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