1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package android.telephony.ims.feature;
18 
19 import android.annotation.IntDef;
20 import android.annotation.SystemApi;
21 import android.os.Bundle;
22 import android.os.Message;
23 import android.os.RemoteException;
24 import android.telecom.TelecomManager;
25 import android.telephony.ims.stub.ImsRegistrationImplBase;
26 import android.telephony.ims.stub.ImsCallSessionImplBase;
27 import android.telephony.ims.stub.ImsSmsImplBase;
28 import android.telephony.ims.aidl.IImsCapabilityCallback;
29 import android.telephony.ims.aidl.IImsMmTelFeature;
30 import android.telephony.ims.aidl.IImsMmTelListener;
31 import android.telephony.ims.aidl.IImsSmsListener;
32 import android.telephony.ims.stub.ImsEcbmImplBase;
33 import android.telephony.ims.stub.ImsMultiEndpointImplBase;
34 import android.telephony.ims.stub.ImsUtImplBase;
35 import android.util.Log;
36 
37 import android.telephony.ims.ImsCallProfile;
38 import com.android.ims.internal.IImsCallSession;
39 import com.android.ims.internal.IImsEcbm;
40 import com.android.ims.internal.IImsMultiEndpoint;
41 import com.android.ims.internal.IImsUt;
42 import android.telephony.ims.ImsCallSession;
43 import com.android.internal.annotations.VisibleForTesting;
44 
45 import java.lang.annotation.Retention;
46 import java.lang.annotation.RetentionPolicy;
47 
48 /**
49  * Base implementation for Voice and SMS (IR-92) and Video (IR-94) IMS support.
50  *
51  * Any class wishing to use MmTelFeature should extend this class and implement all methods that the
52  * service supports.
53  * @hide
54  */
55 @SystemApi
56 public class MmTelFeature extends ImsFeature {
57 
58     private static final String LOG_TAG = "MmTelFeature";
59 
60     private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() {
61 
62         @Override
63         public void setListener(IImsMmTelListener l) throws RemoteException {
64             synchronized (mLock) {
65                 MmTelFeature.this.setListener(l);
66             }
67         }
68 
69         @Override
70         public int getFeatureState() throws RemoteException {
71             synchronized (mLock) {
72                 try {
73                     return MmTelFeature.this.getFeatureState();
74                 } catch (Exception e) {
75                     throw new RemoteException(e.getMessage());
76                 }
77             }
78         }
79 
80 
81         @Override
82         public ImsCallProfile createCallProfile(int callSessionType, int callType)
83                 throws RemoteException {
84             synchronized (mLock) {
85                 try {
86                     return MmTelFeature.this.createCallProfile(callSessionType, callType);
87                 } catch (Exception e) {
88                     throw new RemoteException(e.getMessage());
89                 }
90             }
91         }
92 
93         @Override
94         public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException {
95             synchronized (mLock) {
96                 return createCallSessionInterface(profile);
97             }
98         }
99 
100         @Override
101         public int shouldProcessCall(String[] numbers) {
102             synchronized (mLock) {
103                 return MmTelFeature.this.shouldProcessCall(numbers);
104             }
105         }
106 
107         @Override
108         public IImsUt getUtInterface() throws RemoteException {
109             synchronized (mLock) {
110                 return MmTelFeature.this.getUtInterface();
111             }
112         }
113 
114         @Override
115         public IImsEcbm getEcbmInterface() throws RemoteException {
116             synchronized (mLock) {
117                 return MmTelFeature.this.getEcbmInterface();
118             }
119         }
120 
121         @Override
122         public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException {
123             synchronized (mLock) {
124                 try {
125                     MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage);
126                 } catch (Exception e) {
127                     throw new RemoteException(e.getMessage());
128                 }
129             }
130         }
131 
132         @Override
133         public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
134             synchronized (mLock) {
135                 return MmTelFeature.this.getMultiEndpointInterface();
136             }
137         }
138 
139         @Override
140         public int queryCapabilityStatus() throws RemoteException {
141             synchronized (mLock) {
142                 return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
143             }
144         }
145 
146         @Override
147         public void addCapabilityCallback(IImsCapabilityCallback c) {
148             // no need to lock, structure already handles multithreading.
149             MmTelFeature.this.addCapabilityCallback(c);
150         }
151 
152         @Override
153         public void removeCapabilityCallback(IImsCapabilityCallback c) {
154             // no need to lock, structure already handles multithreading.
155             MmTelFeature.this.removeCapabilityCallback(c);
156         }
157 
158         @Override
159         public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
160                 IImsCapabilityCallback c) throws RemoteException {
161             synchronized (mLock) {
162                 MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
163             }
164         }
165 
166         @Override
167         public void queryCapabilityConfiguration(int capability, int radioTech,
168                 IImsCapabilityCallback c) {
169             synchronized (mLock) {
170                 queryCapabilityConfigurationInternal(capability, radioTech, c);
171             }
172         }
173 
174         @Override
175         public void setSmsListener(IImsSmsListener l) throws RemoteException {
176             synchronized (mLock) {
177                 MmTelFeature.this.setSmsListener(l);
178             }
179         }
180 
181         @Override
182         public void sendSms(int token, int messageRef, String format, String smsc, boolean retry,
183                 byte[] pdu) {
184             synchronized (mLock) {
185                 MmTelFeature.this.sendSms(token, messageRef, format, smsc, retry, pdu);
186             }
187         }
188 
189         @Override
190         public void acknowledgeSms(int token, int messageRef, int result) {
191             synchronized (mLock) {
192                 MmTelFeature.this.acknowledgeSms(token, messageRef, result);
193             }
194         }
195 
196         @Override
197         public void acknowledgeSmsReport(int token, int messageRef, int result) {
198             synchronized (mLock) {
199                 MmTelFeature.this.acknowledgeSmsReport(token, messageRef, result);
200             }
201         }
202 
203         @Override
204         public String getSmsFormat() {
205             synchronized (mLock) {
206                 return MmTelFeature.this.getSmsFormat();
207             }
208         }
209 
210         @Override
211         public void onSmsReady() {
212             synchronized (mLock) {
213                 MmTelFeature.this.onSmsReady();
214             }
215         }
216     };
217 
218     /**
219      * Contains the capabilities defined and supported by a MmTelFeature in the form of a Bitmask.
220      * The capabilities that are used in MmTelFeature are defined as
221      * {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE},
222      * {@link MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
223      * {@link MmTelCapabilities#CAPABILITY_TYPE_UT}, and
224      * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}.
225      *
226      * The capabilities of this MmTelFeature will be set by the framework and can be queried with
227      * {@link #queryCapabilityStatus()}.
228      *
229      * This MmTelFeature can then return the status of each of these capabilities (enabled or not)
230      * by sending a {@link #notifyCapabilitiesStatusChanged} callback to the framework. The current
231      * status can also be queried using {@link #queryCapabilityStatus()}.
232      */
233     public static class MmTelCapabilities extends Capabilities {
234 
235         /**
236          * @hide
237          */
238         @VisibleForTesting
MmTelCapabilities()239         public MmTelCapabilities() {
240             super();
241         }
242 
MmTelCapabilities(Capabilities c)243         public MmTelCapabilities(Capabilities c) {
244             mCapabilities = c.mCapabilities;
245         }
246 
MmTelCapabilities(int capabilities)247         public MmTelCapabilities(int capabilities) {
248             mCapabilities = capabilities;
249         }
250 
251         @IntDef(flag = true,
252                 value = {
253                         CAPABILITY_TYPE_VOICE,
254                         CAPABILITY_TYPE_VIDEO,
255                         CAPABILITY_TYPE_UT,
256                         CAPABILITY_TYPE_SMS
257                 })
258         @Retention(RetentionPolicy.SOURCE)
259         public @interface MmTelCapability {}
260 
261         /**
262          * This MmTelFeature supports Voice calling (IR.92)
263          */
264         public static final int CAPABILITY_TYPE_VOICE = 1 << 0;
265 
266         /**
267          * This MmTelFeature supports Video (IR.94)
268          */
269         public static final int CAPABILITY_TYPE_VIDEO = 1 << 1;
270 
271         /**
272          * This MmTelFeature supports XCAP over Ut for supplementary services. (IR.92)
273          */
274         public static final int CAPABILITY_TYPE_UT = 1 << 2;
275 
276         /**
277          * This MmTelFeature supports SMS (IR.92)
278          */
279         public static final int CAPABILITY_TYPE_SMS = 1 << 3;
280 
281         @Override
addCapabilities(@mTelCapability int capabilities)282         public final void addCapabilities(@MmTelCapability int capabilities) {
283             super.addCapabilities(capabilities);
284         }
285 
286         @Override
removeCapabilities(@mTelCapability int capability)287         public final void removeCapabilities(@MmTelCapability int capability) {
288             super.removeCapabilities(capability);
289         }
290 
291         @Override
isCapable(@mTelCapability int capabilities)292         public final boolean isCapable(@MmTelCapability int capabilities) {
293             return super.isCapable(capabilities);
294         }
295 
296         @Override
toString()297         public String toString() {
298             StringBuilder builder = new StringBuilder("MmTel Capabilities - [");
299             builder.append("Voice: ");
300             builder.append(isCapable(CAPABILITY_TYPE_VOICE));
301             builder.append(" Video: ");
302             builder.append(isCapable(CAPABILITY_TYPE_VIDEO));
303             builder.append(" UT: ");
304             builder.append(isCapable(CAPABILITY_TYPE_UT));
305             builder.append(" SMS: ");
306             builder.append(isCapable(CAPABILITY_TYPE_SMS));
307             builder.append("]");
308             return builder.toString();
309         }
310     }
311 
312     /**
313      * Listener that the framework implements for communication from the MmTelFeature.
314      * @hide
315      */
316     public static class Listener extends IImsMmTelListener.Stub {
317 
318         /**
319          * Called when the IMS provider receives an incoming call.
320          * @param c The {@link ImsCallSession} associated with the new call.
321          */
322         @Override
onIncomingCall(IImsCallSession c, Bundle extras)323         public void onIncomingCall(IImsCallSession c, Bundle extras) {
324 
325         }
326 
327         /**
328          * Updates the Listener when the voice message count for IMS has changed.
329          * @param count an integer representing the new message count.
330          */
331         @Override
onVoiceMessageCountUpdate(int count)332         public void onVoiceMessageCountUpdate(int count) {
333 
334         }
335     }
336 
337     /**
338      * To be returned by {@link #shouldProcessCall(String[])} when the ImsService should process the
339      * outgoing call as IMS.
340      */
341     public static final int PROCESS_CALL_IMS = 0;
342     /**
343      * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should
344      * not process the outgoing call as IMS and should instead use circuit switch.
345      */
346     public static final int PROCESS_CALL_CSFB = 1;
347 
348     @IntDef(flag = true,
349             value = {
350                     PROCESS_CALL_IMS,
351                     PROCESS_CALL_CSFB
352             })
353     @Retention(RetentionPolicy.SOURCE)
354     public @interface ProcessCallResult {}
355 
356 
357     // Lock for feature synchronization
358     private final Object mLock = new Object();
359     private IImsMmTelListener mListener;
360 
361     /**
362      * @param listener A {@link Listener} used when the MmTelFeature receives an incoming call and
363      *     notifies the framework.
364      */
setListener(IImsMmTelListener listener)365     private void setListener(IImsMmTelListener listener) {
366         synchronized (mLock) {
367             mListener = listener;
368         }
369         if (mListener != null) {
370             onFeatureReady();
371         }
372     }
373 
queryCapabilityConfigurationInternal(int capability, int radioTech, IImsCapabilityCallback c)374     private void queryCapabilityConfigurationInternal(int capability, int radioTech,
375             IImsCapabilityCallback c) {
376         boolean enabled = queryCapabilityConfiguration(capability, radioTech);
377         try {
378             if (c != null) {
379                 c.onQueryCapabilityConfiguration(capability, radioTech, enabled);
380             }
381         } catch (RemoteException e) {
382             Log.e(LOG_TAG, "queryCapabilityConfigurationInternal called on dead binder!");
383         }
384     }
385 
386     /**
387      * The current capability status that this MmTelFeature has defined is available. This
388      * configuration will be used by the platform to figure out which capabilities are CURRENTLY
389      * available to be used.
390      *
391      * Should be a subset of the capabilities that are enabled by the framework in
392      * {@link #changeEnabledCapabilities}.
393      * @return A copy of the current MmTelFeature capability status.
394      */
395     @Override
queryCapabilityStatus()396     public final MmTelCapabilities queryCapabilityStatus() {
397         return new MmTelCapabilities(super.queryCapabilityStatus());
398     }
399 
400     /**
401      * Notify the framework that the status of the Capabilities has changed. Even though the
402      * MmTelFeature capability may be enabled by the framework, the status may be disabled due to
403      * the feature being unavailable from the network.
404      * @param c The current capability status of the MmTelFeature. If a capability is disabled, then
405      * the status of that capability is disabled. This can happen if the network does not currently
406      * support the capability that is enabled. A capability that is disabled by the framework (via
407      * {@link #changeEnabledCapabilities}) should also show the status as disabled.
408      */
notifyCapabilitiesStatusChanged(MmTelCapabilities c)409     public final void notifyCapabilitiesStatusChanged(MmTelCapabilities c) {
410         super.notifyCapabilitiesStatusChanged(c);
411     }
412 
413     /**
414      * Notify the framework of an incoming call.
415      * @param c The {@link ImsCallSessionImplBase} of the new incoming call.
416      */
notifyIncomingCall(ImsCallSessionImplBase c, Bundle extras)417     public final void notifyIncomingCall(ImsCallSessionImplBase c, Bundle extras) {
418         synchronized (mLock) {
419             if (mListener == null) {
420                 throw new IllegalStateException("Session is not available.");
421             }
422             try {
423                 mListener.onIncomingCall(c.getServiceImpl(), extras);
424             } catch (RemoteException e) {
425                 throw new RuntimeException(e);
426             }
427         }
428     }
429 
430     /**
431      *
432      * @hide
433      */
notifyIncomingCallSession(IImsCallSession c, Bundle extras)434     public final void notifyIncomingCallSession(IImsCallSession c, Bundle extras) {
435         synchronized (mLock) {
436             if (mListener == null) {
437                 throw new IllegalStateException("Session is not available.");
438             }
439             try {
440                 mListener.onIncomingCall(c, extras);
441             } catch (RemoteException e) {
442                 throw new RuntimeException(e);
443             }
444         }
445     }
446 
447     /**
448      * Notify the framework of a change in the Voice Message count.
449      * @link count the new Voice Message count.
450      */
notifyVoiceMessageCountUpdate(int count)451     public final void notifyVoiceMessageCountUpdate(int count) {
452         synchronized (mLock) {
453             if (mListener == null) {
454                 throw new IllegalStateException("Session is not available.");
455             }
456             try {
457                 mListener.onVoiceMessageCountUpdate(count);
458             } catch (RemoteException e) {
459                 throw new RuntimeException(e);
460             }
461         }
462     }
463 
464     /**
465      * Provides the MmTelFeature with the ability to return the framework Capability Configuration
466      * for a provided Capability. If the framework calls {@link #changeEnabledCapabilities} and
467      * includes a capability A to enable or disable, this method should return the correct enabled
468      * status for capability A.
469      * @param capability The capability that we are querying the configuration for.
470      * @return true if the capability is enabled, false otherwise.
471      */
queryCapabilityConfiguration(@mTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)472     public boolean queryCapabilityConfiguration(@MmTelCapabilities.MmTelCapability int capability,
473             @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
474         // Base implementation - Override to provide functionality
475         return false;
476     }
477 
478     /**
479      * The MmTelFeature should override this method to handle the enabling/disabling of
480      * MmTel Features, defined in {@link MmTelCapabilities.MmTelCapability}. The framework assumes
481      * the {@link CapabilityChangeRequest} was processed successfully. If a subset of capabilities
482      * could not be set to their new values,
483      * {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError} must be called
484      * individually for each capability whose processing resulted in an error.
485      *
486      * Enabling/Disabling a capability here indicates that the capability should be registered or
487      * deregistered (depending on the capability change) and become available or unavailable to
488      * the framework.
489      */
490     @Override
changeEnabledCapabilities(CapabilityChangeRequest request, CapabilityCallbackProxy c)491     public void changeEnabledCapabilities(CapabilityChangeRequest request,
492             CapabilityCallbackProxy c) {
493         // Base implementation, no-op
494     }
495 
496     /**
497      * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
498      *
499      * @param callSessionType a service type that is specified in {@link ImsCallProfile}
500      *        {@link ImsCallProfile#SERVICE_TYPE_NONE}
501      *        {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
502      *        {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
503      * @param callType a call type that is specified in {@link ImsCallProfile}
504      *        {@link ImsCallProfile#CALL_TYPE_VOICE}
505      *        {@link ImsCallProfile#CALL_TYPE_VT}
506      *        {@link ImsCallProfile#CALL_TYPE_VT_TX}
507      *        {@link ImsCallProfile#CALL_TYPE_VT_RX}
508      *        {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
509      *        {@link ImsCallProfile#CALL_TYPE_VS}
510      *        {@link ImsCallProfile#CALL_TYPE_VS_TX}
511      *        {@link ImsCallProfile#CALL_TYPE_VS_RX}
512      * @return a {@link ImsCallProfile} object
513      */
createCallProfile(int callSessionType, int callType)514     public ImsCallProfile createCallProfile(int callSessionType, int callType) {
515         // Base Implementation - Should be overridden
516         return null;
517     }
518 
519     /**
520      * @hide
521      */
createCallSessionInterface(ImsCallProfile profile)522     public IImsCallSession createCallSessionInterface(ImsCallProfile profile)
523             throws RemoteException {
524         ImsCallSessionImplBase s = MmTelFeature.this.createCallSession(profile);
525         return s != null ? s.getServiceImpl() : null;
526     }
527 
528     /**
529      * Creates an {@link ImsCallSession} with the specified call profile.
530      * Use other methods, if applicable, instead of interacting with
531      * {@link ImsCallSession} directly.
532      *
533      * @param profile a call profile to make the call
534      */
createCallSession(ImsCallProfile profile)535     public ImsCallSessionImplBase createCallSession(ImsCallProfile profile) {
536         // Base Implementation - Should be overridden
537         return null;
538     }
539 
540     /**
541      * Called by the framework to determine if the outgoing call, designated by the outgoing
542      * {@link String}s, should be processed as an IMS call or CSFB call. If this method's
543      * functionality is not overridden, the platform will process every call as IMS as long as the
544      * MmTelFeature reports that the {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE} capability is
545      * available.
546      * @param numbers An array of {@link String}s that will be used for placing the call. There can
547      *         be multiple {@link String}s listed in the case when we want to place an outgoing
548      *         call as a conference.
549      * @return a {@link ProcessCallResult} to the framework, which will be used to determine if the
550      *        call will be placed over IMS or via CSFB.
551      */
shouldProcessCall(String[] numbers)552     public @ProcessCallResult int shouldProcessCall(String[] numbers) {
553         return PROCESS_CALL_IMS;
554     }
555 
556     /**
557      *
558      * @hide
559      */
getUtInterface()560     protected IImsUt getUtInterface() throws RemoteException {
561         ImsUtImplBase utImpl = getUt();
562         return utImpl != null ? utImpl.getInterface() : null;
563     }
564 
565     /**
566      * @hide
567      */
getEcbmInterface()568     protected IImsEcbm getEcbmInterface() throws RemoteException {
569         ImsEcbmImplBase ecbmImpl = getEcbm();
570         return ecbmImpl != null ? ecbmImpl.getImsEcbm() : null;
571     }
572 
573     /**
574      * @hide
575      */
getMultiEndpointInterface()576     public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
577         ImsMultiEndpointImplBase multiendpointImpl = getMultiEndpoint();
578         return multiendpointImpl != null ? multiendpointImpl.getIImsMultiEndpoint() : null;
579     }
580 
581     /**
582      * @return The {@link ImsUtImplBase} Ut interface implementation for the supplementary service
583      * configuration.
584      */
getUt()585     public ImsUtImplBase getUt() {
586         // Base Implementation - Should be overridden
587         return new ImsUtImplBase();
588     }
589 
590     /**
591      * @return The {@link ImsEcbmImplBase} Emergency call-back mode interface for emergency VoLTE
592      * calls that support it.
593      */
getEcbm()594     public ImsEcbmImplBase getEcbm() {
595         // Base Implementation - Should be overridden
596         return new ImsEcbmImplBase();
597     }
598 
599     /**
600      * @return The {@link ImsMultiEndpointImplBase} implementation for implementing Dialog event
601      * package processing for multi-endpoint.
602      */
getMultiEndpoint()603     public ImsMultiEndpointImplBase getMultiEndpoint() {
604         // Base Implementation - Should be overridden
605         return new ImsMultiEndpointImplBase();
606     }
607 
608     /**
609      * Sets the current UI TTY mode for the MmTelFeature.
610      * @param mode An integer containing the new UI TTY Mode, can consist of
611      *         {@link TelecomManager#TTY_MODE_OFF},
612      *         {@link TelecomManager#TTY_MODE_FULL},
613      *         {@link TelecomManager#TTY_MODE_HCO},
614      *         {@link TelecomManager#TTY_MODE_VCO}
615      * @param onCompleteMessage If non-null, this MmTelFeature should call this {@link Message} when
616      *         the operation is complete by using the associated {@link android.os.Messenger} in
617      *         {@link Message#replyTo}. For example:
618      * {@code
619      *     // Set UI TTY Mode and other operations...
620      *     try {
621      *         // Notify framework that the mode was changed.
622      *         Messenger uiMessenger = onCompleteMessage.replyTo;
623      *         uiMessenger.send(onCompleteMessage);
624      *     } catch (RemoteException e) {
625      *         // Remote side is dead
626      *     }
627      * }
628      */
setUiTtyMode(int mode, Message onCompleteMessage)629     public void setUiTtyMode(int mode, Message onCompleteMessage) {
630         // Base Implementation - Should be overridden
631     }
632 
setSmsListener(IImsSmsListener listener)633     private void setSmsListener(IImsSmsListener listener) {
634         getSmsImplementation().registerSmsListener(listener);
635     }
636 
sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, byte[] pdu)637     private void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry,
638             byte[] pdu) {
639         getSmsImplementation().sendSms(token, messageRef, format, smsc, isRetry, pdu);
640     }
641 
acknowledgeSms(int token, int messageRef, @ImsSmsImplBase.DeliverStatusResult int result)642     private void acknowledgeSms(int token, int messageRef,
643             @ImsSmsImplBase.DeliverStatusResult int result) {
644         getSmsImplementation().acknowledgeSms(token, messageRef, result);
645     }
646 
acknowledgeSmsReport(int token, int messageRef, @ImsSmsImplBase.StatusReportResult int result)647     private void acknowledgeSmsReport(int token, int messageRef,
648             @ImsSmsImplBase.StatusReportResult int result) {
649         getSmsImplementation().acknowledgeSmsReport(token, messageRef, result);
650     }
651 
onSmsReady()652     private void onSmsReady() {
653         getSmsImplementation().onReady();
654     }
655 
656     /**
657      * Must be overridden by IMS Provider to be able to support SMS over IMS. Otherwise a default
658      * non-functional implementation is returned.
659      *
660      * @return an instance of {@link ImsSmsImplBase} which should be implemented by the IMS
661      * Provider.
662      */
getSmsImplementation()663     public ImsSmsImplBase getSmsImplementation() {
664         return new ImsSmsImplBase();
665     }
666 
getSmsFormat()667     private String getSmsFormat() {
668         return getSmsImplementation().getSmsFormat();
669     }
670 
671     /**{@inheritDoc}*/
672     @Override
onFeatureRemoved()673     public void onFeatureRemoved() {
674         // Base Implementation - Should be overridden
675     }
676 
677     /**{@inheritDoc}*/
678     @Override
onFeatureReady()679     public void onFeatureReady() {
680         // Base Implementation - Should be overridden
681     }
682 
683     /**
684      * @hide
685      */
686     @Override
getBinder()687     public final IImsMmTelFeature getBinder() {
688         return mImsMMTelBinder;
689     }
690 }
691