Home | History | Annotate | Download | only in feature
      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
    239         public MmTelCapabilities() {
    240             super();
    241         }
    242 
    243         public MmTelCapabilities(Capabilities c) {
    244             mCapabilities = c.mCapabilities;
    245         }
    246 
    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
    282         public final void addCapabilities(@MmTelCapability int capabilities) {
    283             super.addCapabilities(capabilities);
    284         }
    285 
    286         @Override
    287         public final void removeCapabilities(@MmTelCapability int capability) {
    288             super.removeCapabilities(capability);
    289         }
    290 
    291         @Override
    292         public final boolean isCapable(@MmTelCapability int capabilities) {
    293             return super.isCapable(capabilities);
    294         }
    295 
    296         @Override
    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
    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
    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      */
    365     private void setListener(IImsMmTelListener listener) {
    366         synchronized (mLock) {
    367             mListener = listener;
    368         }
    369         if (mListener != null) {
    370             onFeatureReady();
    371         }
    372     }
    373 
    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
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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      */
    514     public ImsCallProfile createCallProfile(int callSessionType, int callType) {
    515         // Base Implementation - Should be overridden
    516         return null;
    517     }
    518 
    519     /**
    520      * @hide
    521      */
    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      */
    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      */
    552     public @ProcessCallResult int shouldProcessCall(String[] numbers) {
    553         return PROCESS_CALL_IMS;
    554     }
    555 
    556     /**
    557      *
    558      * @hide
    559      */
    560     protected IImsUt getUtInterface() throws RemoteException {
    561         ImsUtImplBase utImpl = getUt();
    562         return utImpl != null ? utImpl.getInterface() : null;
    563     }
    564 
    565     /**
    566      * @hide
    567      */
    568     protected IImsEcbm getEcbmInterface() throws RemoteException {
    569         ImsEcbmImplBase ecbmImpl = getEcbm();
    570         return ecbmImpl != null ? ecbmImpl.getImsEcbm() : null;
    571     }
    572 
    573     /**
    574      * @hide
    575      */
    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      */
    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      */
    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      */
    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      */
    629     public void setUiTtyMode(int mode, Message onCompleteMessage) {
    630         // Base Implementation - Should be overridden
    631     }
    632 
    633     private void setSmsListener(IImsSmsListener listener) {
    634         getSmsImplementation().registerSmsListener(listener);
    635     }
    636 
    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 
    642     private void acknowledgeSms(int token, int messageRef,
    643             @ImsSmsImplBase.DeliverStatusResult int result) {
    644         getSmsImplementation().acknowledgeSms(token, messageRef, result);
    645     }
    646 
    647     private void acknowledgeSmsReport(int token, int messageRef,
    648             @ImsSmsImplBase.StatusReportResult int result) {
    649         getSmsImplementation().acknowledgeSmsReport(token, messageRef, result);
    650     }
    651 
    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      */
    663     public ImsSmsImplBase getSmsImplementation() {
    664         return new ImsSmsImplBase();
    665     }
    666 
    667     private String getSmsFormat() {
    668         return getSmsImplementation().getSmsFormat();
    669     }
    670 
    671     /**{@inheritDoc}*/
    672     @Override
    673     public void onFeatureRemoved() {
    674         // Base Implementation - Should be overridden
    675     }
    676 
    677     /**{@inheritDoc}*/
    678     @Override
    679     public void onFeatureReady() {
    680         // Base Implementation - Should be overridden
    681     }
    682 
    683     /**
    684      * @hide
    685      */
    686     @Override
    687     public final IImsMmTelFeature getBinder() {
    688         return mImsMMTelBinder;
    689     }
    690 }
    691