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;
18 
19 
20 import android.Manifest;
21 import android.annotation.CallbackExecutor;
22 import android.annotation.FlaggedApi;
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.RequiresFeature;
26 import android.annotation.RequiresPermission;
27 import android.annotation.SuppressAutoDoc;
28 import android.annotation.SuppressLint;
29 import android.annotation.SystemApi;
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.os.Binder;
33 import android.os.RemoteException;
34 import android.os.ServiceSpecificException;
35 import android.telephony.AccessNetworkConstants;
36 import android.telephony.BinderCacheManager;
37 import android.telephony.CarrierConfigManager;
38 import android.telephony.SubscriptionManager;
39 import android.telephony.TelephonyFrameworkInitializer;
40 import android.telephony.ims.aidl.IImsCapabilityCallback;
41 import android.telephony.ims.feature.ImsFeature;
42 import android.telephony.ims.feature.MmTelFeature;
43 import android.telephony.ims.stub.ImsRegistrationImplBase;
44 import android.util.Log;
45 
46 import com.android.internal.annotations.VisibleForTesting;
47 import com.android.internal.telephony.IIntegerConsumer;
48 import com.android.internal.telephony.ITelephony;
49 import com.android.internal.telephony.flags.Flags;
50 
51 import java.lang.annotation.Retention;
52 import java.lang.annotation.RetentionPolicy;
53 import java.util.Objects;
54 import java.util.concurrent.Executor;
55 import java.util.function.Consumer;
56 
57 /**
58  * A manager for the MmTel (Multimedia Telephony) feature of an IMS network, given an associated
59  * subscription.
60  *
61  * Allows a user to query the IMS MmTel feature information for a subscription, register for
62  * registration and MmTel capability status callbacks, as well as query/modify user settings for the
63  * associated subscription.
64  *
65  * Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this
66  * manager.
67  */
68 @RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
69 public class ImsMmTelManager implements RegistrationManager {
70     private static final String TAG = "ImsMmTelManager";
71 
72     /**
73      * @hide
74      */
75     @Retention(RetentionPolicy.SOURCE)
76     @IntDef(prefix = "WIFI_MODE_", value = {
77             WIFI_MODE_UNKNOWN,
78             WIFI_MODE_WIFI_ONLY,
79             WIFI_MODE_CELLULAR_PREFERRED,
80             WIFI_MODE_WIFI_PREFERRED
81             })
82     public @interface WiFiCallingMode {}
83 
84     /**
85      * Wifi calling mode is unknown. This is for initialization only.
86      * @hide
87      */
88     public static final int WIFI_MODE_UNKNOWN = -1;
89 
90     /**
91      * Register for IMS over IWLAN if WiFi signal quality is high enough. Do not hand over to LTE
92      * registration if signal quality degrades.
93      */
94     public static final int WIFI_MODE_WIFI_ONLY = 0;
95 
96     /**
97      * Prefer registering for IMS over LTE if LTE signal quality is high enough.
98      */
99     public static final int WIFI_MODE_CELLULAR_PREFERRED = 1;
100 
101     /**
102      * Prefer registering for IMS over IWLAN if possible if WiFi signal quality is high enough.
103      */
104     public static final int WIFI_MODE_WIFI_PREFERRED = 2;
105 
106     /**
107      * Callback class for receiving IMS network Registration callback events.
108      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
109      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
110      * @deprecated Use {@link RegistrationManager.RegistrationCallback} instead.
111      * @hide
112      */
113     // Do not add to this class, add to RegistrationManager.RegistrationCallback instead.
114     @Deprecated
115     @SystemApi
116     public static class RegistrationCallback extends RegistrationManager.RegistrationCallback {
117 
118         /**
119          * Notifies the framework when the IMS Provider is registered to the IMS network.
120          *
121          * @param imsTransportType the radio access technology.
122          */
123         @Override
onRegistered(@ccessNetworkConstants.TransportType int imsTransportType)124         public void onRegistered(@AccessNetworkConstants.TransportType int imsTransportType) {
125         }
126 
127         /**
128          * Notifies the framework when the IMS Provider is trying to register the IMS network.
129          *
130          * @param imsTransportType the radio access technology.
131          */
132         @Override
onRegistering(@ccessNetworkConstants.TransportType int imsTransportType)133         public void onRegistering(@AccessNetworkConstants.TransportType int imsTransportType) {
134         }
135 
136         /**
137          * Notifies the framework when the IMS Provider is deregistered from the IMS network.
138          *
139          * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
140          */
141         @Override
onUnregistered(@onNull ImsReasonInfo info)142         public void onUnregistered(@NonNull ImsReasonInfo info) {
143         }
144 
145         /**
146          * A failure has occurred when trying to handover registration to another technology type.
147          *
148          * @param imsTransportType The transport type that has failed to handover registration to.
149          * @param info A {@link ImsReasonInfo} that identifies the reason for failure.
150          */
151         @Override
onTechnologyChangeFailed( @ccessNetworkConstants.TransportType int imsTransportType, @NonNull ImsReasonInfo info)152         public void onTechnologyChangeFailed(
153                 @AccessNetworkConstants.TransportType int imsTransportType,
154                 @NonNull ImsReasonInfo info) {
155         }
156     }
157 
158     /**
159      * Receives IMS capability status updates from the ImsService.
160      *
161      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
162      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
163      */
164     public static class CapabilityCallback {
165 
166         private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
167 
168             private final CapabilityCallback mLocalCallback;
169             private Executor mExecutor;
170 
CapabilityBinder(CapabilityCallback c)171             CapabilityBinder(CapabilityCallback c) {
172                 mLocalCallback = c;
173             }
174 
175             @Override
onCapabilitiesStatusChanged(int config)176             public void onCapabilitiesStatusChanged(int config) {
177                 if (mLocalCallback == null) return;
178 
179                 final long callingIdentity = Binder.clearCallingIdentity();
180                 try {
181                     mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged(
182                             new MmTelFeature.MmTelCapabilities(config)));
183                 } finally {
184                     restoreCallingIdentity(callingIdentity);
185                 }
186             }
187 
188             @Override
onQueryCapabilityConfiguration(int capability, int radioTech, boolean isEnabled)189             public void onQueryCapabilityConfiguration(int capability, int radioTech,
190                     boolean isEnabled) {
191                 // This is not used for public interfaces.
192             }
193 
194             @Override
onChangeCapabilityConfigurationError(int capability, int radioTech, @ImsFeature.ImsCapabilityError int reason)195             public void onChangeCapabilityConfigurationError(int capability, int radioTech,
196                     @ImsFeature.ImsCapabilityError int reason) {
197                 // This is not used for public interfaces
198             }
199 
setExecutor(Executor executor)200             private void setExecutor(Executor executor) {
201                 mExecutor = executor;
202             }
203         }
204 
205         private final CapabilityBinder mBinder = new CapabilityBinder(this);
206 
207         /**
208          * The status of the feature's capabilities has changed to either available or unavailable.
209          * If unavailable, the feature is not able to support the unavailable capability at this
210          * time.
211          *
212          * @param capabilities The new availability of the capabilities.
213          */
onCapabilitiesStatusChanged( @onNull MmTelFeature.MmTelCapabilities capabilities)214         public void onCapabilitiesStatusChanged(
215                 @NonNull MmTelFeature.MmTelCapabilities capabilities) {
216         }
217 
218         /**@hide*/
getBinder()219         public final IImsCapabilityCallback getBinder() {
220             return mBinder;
221         }
222 
223         /**@hide*/
224         // Only exposed as public method for compatibility with deprecated ImsManager APIs.
225         // TODO: clean up dependencies and change back to private visibility.
setExecutor(Executor executor)226         public final void setExecutor(Executor executor) {
227             mBinder.setExecutor(executor);
228         }
229     }
230 
231     private final Context mContext;
232     private final int mSubId;
233     private final BinderCacheManager<ITelephony> mBinderCache;
234 
235     // Cache Telephony Binder interfaces, one cache per process.
236     private static final BinderCacheManager<ITelephony> sTelephonyCache =
237             new BinderCacheManager<>(ImsMmTelManager::getITelephonyInterface);
238 
239     /**
240      * Create an instance of {@link ImsMmTelManager} for the subscription id specified.
241      *
242      * @param subId The ID of the subscription that this ImsMmTelManager will use.
243      * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
244      *
245      * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
246      * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
247      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
248      *
249      * @throws IllegalArgumentException if the subscription is invalid.
250      * @deprecated Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an
251      * instance of this class.
252      * @hide
253      */
254     @SystemApi
255     @Deprecated
256     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
257     @RequiresPermission(anyOf = {
258             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
259             android.Manifest.permission.READ_PRECISE_PHONE_STATE
260     })
261     @SuppressLint("ManagerLookup")
createForSubscriptionId(int subId)262     public static @NonNull ImsMmTelManager createForSubscriptionId(int subId) {
263         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
264             throw new IllegalArgumentException("Invalid subscription ID");
265         }
266 
267         return new ImsMmTelManager(subId, sTelephonyCache);
268     }
269 
270     /**
271      * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
272      * @hide
273      */
274     @VisibleForTesting
ImsMmTelManager(int subId, BinderCacheManager<ITelephony> binderCache)275     public ImsMmTelManager(int subId, BinderCacheManager<ITelephony> binderCache) {
276         this(null, subId, binderCache);
277     }
278 
279     /**
280      * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
281      * @hide
282      */
283     @VisibleForTesting
ImsMmTelManager(Context context, int subId, BinderCacheManager<ITelephony> binderCache)284     public ImsMmTelManager(Context context, int subId, BinderCacheManager<ITelephony> binderCache) {
285         mContext = context;
286         mSubId = subId;
287         mBinderCache = binderCache;
288     }
289 
290     /**
291      * Registers a {@link RegistrationCallback} with the system, which will provide registration
292      * updates for the subscription specified in {@link ImsManager#getImsMmTelManager(int)}. Use
293      * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
294      * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
295      *
296      * When the callback is registered, it will initiate the callback c to be called with the
297      * current registration state.
298      *
299      * @param executor The executor the callback events should be run on.
300      * @param c The {@link RegistrationCallback} to be added.
301      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
302      * @throws IllegalArgumentException if the subscription associated with this callback is not
303      * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
304      * {@link CapabilityCallback} callback.
305      * @throws ImsException if the subscription associated with this callback is valid, but
306      * the {@link ImsService} associated with the subscription is not available. This can happen if
307      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
308      * reason.
309      * @deprecated Use {@link RegistrationManager#registerImsRegistrationCallback(Executor,
310      * RegistrationManager.RegistrationCallback)} instead.
311      * @hide
312      */
313     @Deprecated
314     @SystemApi
315     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
registerImsRegistrationCallback(@onNull @allbackExecutor Executor executor, @NonNull RegistrationCallback c)316     public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
317             @NonNull RegistrationCallback c) throws ImsException {
318         if (c == null) {
319             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
320         }
321         if (executor == null) {
322             throw new IllegalArgumentException("Must include a non-null Executor.");
323         }
324         c.setExecutor(executor);
325 
326         ITelephony iTelephony = getITelephony();
327         if (iTelephony == null) {
328             throw new ImsException("Could not find Telephony Service.",
329                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
330         }
331 
332         try {
333             iTelephony.registerImsRegistrationCallback(mSubId, c.getBinder());
334         } catch (ServiceSpecificException e) {
335             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
336                 // Rethrow as runtime error to keep API compatible.
337                 throw new IllegalArgumentException(e.getMessage());
338             } else {
339                 throw new ImsException(e.getMessage(), e.errorCode);
340             }
341         } catch (RemoteException | IllegalStateException e) {
342             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
343         }
344     }
345 
346      /**
347      *
348      * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
349      * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
350      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
351      *
352      * {@inheritDoc}
353      *
354      */
355     @Override
356     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
357     @RequiresPermission(anyOf = {
358             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
359             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
registerImsRegistrationCallback(@onNull @allbackExecutor Executor executor, @NonNull RegistrationManager.RegistrationCallback c)360     public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
361             @NonNull RegistrationManager.RegistrationCallback c) throws ImsException {
362         if (c == null) {
363             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
364         }
365         if (executor == null) {
366             throw new IllegalArgumentException("Must include a non-null Executor.");
367         }
368         c.setExecutor(executor);
369 
370         ITelephony iTelephony = getITelephony();
371         if (iTelephony == null) {
372             throw new ImsException("Could not find Telephony Service.",
373                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
374         }
375 
376         try {
377             iTelephony.registerImsRegistrationCallback(mSubId, c.getBinder());
378         } catch (ServiceSpecificException e) {
379             throw new ImsException(e.getMessage(), e.errorCode);
380         } catch (RemoteException | IllegalStateException e) {
381             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
382         }
383     }
384 
385     /**
386      * Removes an existing {@link RegistrationCallback}.
387      *
388      * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
389      * etc...), this callback will automatically be removed. If this method is called for an
390      * inactive subscription, it will result in a no-op.
391      *
392      * @param c The {@link RegistrationCallback} to be removed.
393      * @see SubscriptionManager.OnSubscriptionsChangedListener
394      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
395      * @deprecated Use {@link #unregisterImsRegistrationCallback(
396      * RegistrationManager.RegistrationCallback)}.
397      * @hide
398      */
399     @Deprecated
400     @SystemApi
401     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
unregisterImsRegistrationCallback(@onNull RegistrationCallback c)402     public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
403         if (c == null) {
404             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
405         }
406 
407         ITelephony iTelephony = getITelephony();
408         if (iTelephony == null) {
409             throw new RuntimeException("Could not find Telephony Service.");
410         }
411 
412         try {
413             iTelephony.unregisterImsRegistrationCallback(mSubId, c.getBinder());
414         } catch (RemoteException e) {
415             throw e.rethrowAsRuntimeException();
416         }
417     }
418 
419      /**
420      *
421      * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
422      * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
423      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
424      * Access by profile owners is deprecated and will be removed in a future release.
425      *
426      *{@inheritDoc}
427      */
428     @Override
429     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
430     @RequiresPermission(anyOf = {
431             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
432             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
unregisterImsRegistrationCallback( @onNull RegistrationManager.RegistrationCallback c)433     public void unregisterImsRegistrationCallback(
434             @NonNull RegistrationManager.RegistrationCallback c) {
435         if (c == null) {
436             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
437         }
438 
439         ITelephony iTelephony = getITelephony();
440         if (iTelephony == null) {
441             throw new RuntimeException("Could not find Telephony Service.");
442         }
443 
444         try {
445             iTelephony.unregisterImsRegistrationCallback(mSubId, c.getBinder());
446         } catch (RemoteException e) {
447             throw e.rethrowAsRuntimeException();
448         }
449     }
450 
451     /**
452      * Registers a {@link RegistrationCallback} with the system, which will provide IMS emergency
453      * registration updates for the subscription specified in
454      * {@link ImsManager#getImsMmTelManager(int)}. Use
455      * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
456      * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
457      *
458      * When the callback is registered, it will initiate the callback c to be called with the
459      * current emergency registration state.
460      * Emergency registration callback is available when there is valid SIM card.
461      * <p>This API requires one of the following:
462      * <ul>
463      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
464      *     <li>If the caller is the device or profile owner, the caller holds the
465      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
466      *     <li>The caller has carrier privileges (see
467      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
468      *     active subscription.</li>
469      * </ul>
470      * <p>The profile owner is an app that owns a managed profile on the device; for more details
471      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
472      * Access by profile owners is deprecated and will be removed in a future release.
473      *
474      * @param executor The executor the callback events should be run on.
475      * @param c The {@link RegistrationCallback} to be added.
476      * @see #unregisterImsEmergencyRegistrationCallback
477      * @throws ImsException if the subscription associated with this callback is valid, but
478      * the {@link ImsService} associated with the subscription is not available. This can happen if
479      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
480      * reason.
481      * @hide
482      */
483     @SystemApi
484     @FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
registerImsEmergencyRegistrationCallback( @onNull @allbackExecutor Executor executor, @NonNull RegistrationManager.RegistrationCallback c)485     public void registerImsEmergencyRegistrationCallback(
486             @NonNull @CallbackExecutor Executor executor,
487             @NonNull RegistrationManager.RegistrationCallback c) throws ImsException {
488         if (c == null) {
489             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
490         }
491         if (executor == null) {
492             throw new IllegalArgumentException("Must include a non-null Executor.");
493         }
494         c.setExecutor(executor);
495 
496         ITelephony iTelephony = getITelephony();
497         if (iTelephony == null) {
498             throw new ImsException("Could not find Telephony Service.",
499                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
500         }
501 
502         try {
503             iTelephony.registerImsEmergencyRegistrationCallback(mSubId, c.getBinder());
504         } catch (ServiceSpecificException e) {
505             throw new ImsException(e.getMessage(), e.errorCode);
506         } catch (RemoteException e) {
507             throw e.rethrowAsRuntimeException();
508         }  catch (IllegalStateException e) {
509             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
510         }
511     }
512 
513     /**
514      * Removes an existing {@link RegistrationCallback} for Emergency IMS registration.
515      *
516      * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
517      * etc...), this callback will automatically be removed. If this method is called for an
518      * inactive subscription, it will result in a no-op.
519      * <p>This API requires one of the following:
520      * <ul>
521      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
522      *     <li>If the caller is the device or profile owner, the caller holds the
523      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
524      *     <li>The caller has carrier privileges (see
525      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
526      *     active subscription.</li>
527      * </ul>
528      * <p>The profile owner is an app that owns a managed profile on the device; for more details
529      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
530      * Access by profile owners is deprecated and will be removed in a future release.
531      *
532      * @param c The {@link RegistrationCallback} to be removed.
533      * @see android.telephony.SubscriptionManager.OnSubscriptionsChangedListener
534      * @see #registerImsEmergencyRegistrationCallback(Executor,
535      *                                 RegistrationManager.RegistrationCallback)
536      * @hide
537      */
538     @SystemApi
539     @FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
unregisterImsEmergencyRegistrationCallback( @onNull RegistrationManager.RegistrationCallback c)540     public void unregisterImsEmergencyRegistrationCallback(
541             @NonNull RegistrationManager.RegistrationCallback c) {
542         if (c == null) {
543             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
544         }
545 
546         ITelephony iTelephony = getITelephony();
547         if (iTelephony == null) {
548             Log.w("ImsMmTelManager", "Could not find Telephony Service.");
549             return;
550         }
551 
552         try {
553             iTelephony.unregisterImsEmergencyRegistrationCallback(mSubId, c.getBinder());
554         } catch (RemoteException e) {
555             throw e.rethrowAsRuntimeException();
556         }
557     }
558 
559     /**
560      * {@inheritDoc}
561      * @hide
562      */
563     @Override
564     @SystemApi
565     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
getRegistrationState(@onNull @allbackExecutor Executor executor, @NonNull @ImsRegistrationState Consumer<Integer> stateCallback)566     public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
567             @NonNull @ImsRegistrationState Consumer<Integer> stateCallback) {
568         if (stateCallback == null) {
569             throw new IllegalArgumentException("Must include a non-null callback.");
570         }
571         if (executor == null) {
572             throw new IllegalArgumentException("Must include a non-null Executor.");
573         }
574 
575         ITelephony iTelephony = getITelephony();
576         if (iTelephony == null) {
577             throw new RuntimeException("Could not find Telephony Service.");
578         }
579 
580         try {
581             iTelephony.getImsMmTelRegistrationState(mSubId, new IIntegerConsumer.Stub() {
582                 @Override
583                 public void accept(int result) {
584                     final long identity = Binder.clearCallingIdentity();
585                     try {
586                         executor.execute(() -> stateCallback.accept(result));
587                     } finally {
588                         Binder.restoreCallingIdentity(identity);
589                     }
590                 }
591             });
592         } catch (ServiceSpecificException | RemoteException e) {
593             Log.w("ImsMmTelManager", "Error getting registration state: " + e);
594             executor.execute(() -> stateCallback.accept(REGISTRATION_STATE_NOT_REGISTERED));
595         }
596     }
597 
598     /**
599      * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
600      * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
601      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
602      * Access by profile owners is deprecated and will be removed in a future release.
603      *
604      *{@inheritDoc}
605      */
606     @Override
607     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
608     @RequiresPermission(anyOf = {
609             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
610             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
getRegistrationTransportType(@onNull @allbackExecutor Executor executor, @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback)611     public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
612             @NonNull @AccessNetworkConstants.TransportType
613                     Consumer<Integer> transportTypeCallback) {
614         if (transportTypeCallback == null) {
615             throw new IllegalArgumentException("Must include a non-null callback.");
616         }
617         if (executor == null) {
618             throw new IllegalArgumentException("Must include a non-null Executor.");
619         }
620 
621         ITelephony iTelephony = getITelephony();
622         if (iTelephony == null) {
623             throw new RuntimeException("Could not find Telephony Service.");
624         }
625 
626         try {
627             iTelephony.getImsMmTelRegistrationTransportType(mSubId,
628                     new IIntegerConsumer.Stub() {
629                         @Override
630                         public void accept(int result) {
631                             final long identity = Binder.clearCallingIdentity();
632                             try {
633                                 executor.execute(() -> transportTypeCallback.accept(result));
634                             } finally {
635                                 Binder.restoreCallingIdentity(identity);
636                             }
637                         }
638                     });
639         } catch (ServiceSpecificException | RemoteException e) {
640             Log.w("ImsMmTelManager", "Error getting transport type: " + e);
641             executor.execute(() -> transportTypeCallback.accept(
642                     AccessNetworkConstants.TRANSPORT_TYPE_INVALID));
643         }
644     }
645 
646     /**
647      * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
648      * availability updates for the subscription specified in
649      * {@link ImsManager#getImsMmTelManager(int)}.
650      *
651      * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
652      * subscription changed events and call
653      * {@link #unregisterMmTelCapabilityCallback(CapabilityCallback)} to clean up.
654      * <p>This API requires one of the following:
655      * <ul>
656      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
657      *     <li>If the caller is the device or profile owner, the caller holds the
658      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
659      *     <li>The caller has carrier privileges (see
660      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
661      *     active subscription.</li>
662      * </ul>
663      * <p>The profile owner is an app that owns a managed profile on the device; for more details
664      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
665      * Access by profile owners is deprecated and will be removed in a future release.
666      *
667      * When the callback is registered, it will initiate the callback c to be called with the
668      * current capabilities.
669      *
670      * @param executor The executor the callback events should be run on.
671      * @param c The MmTel {@link CapabilityCallback} to be registered.
672      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
673      * @throws ImsException if the subscription associated with this callback is valid, but
674      * the {@code ImsService} associated with the subscription is not available. This can happen if
675      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
676      * reason.
677      */
678     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
679     @RequiresPermission(anyOf = {
680             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
681             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
registerMmTelCapabilityCallback(@onNull @allbackExecutor Executor executor, @NonNull CapabilityCallback c)682     public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor,
683             @NonNull CapabilityCallback c) throws ImsException {
684         if (c == null) {
685             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
686         }
687         if (executor == null) {
688             throw new IllegalArgumentException("Must include a non-null Executor.");
689         }
690         c.setExecutor(executor);
691 
692         ITelephony iTelephony = getITelephony();
693         if (iTelephony == null) {
694             throw new ImsException("Could not find Telephony Service.",
695                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
696         }
697 
698         try {
699             iTelephony.registerMmTelCapabilityCallback(mSubId, c.getBinder());
700         } catch (ServiceSpecificException e) {
701             throw new ImsException(e.getMessage(), e.errorCode);
702         } catch (RemoteException e) {
703             throw e.rethrowAsRuntimeException();
704         }  catch (IllegalStateException e) {
705             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
706         }
707     }
708 
709     /**
710      * Removes an existing MmTel {@link CapabilityCallback}.
711      *
712      * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
713      * etc...), this callback will automatically be removed. If this method is called for an
714      * inactive subscription, it will result in a no-op.
715      * <p>This API requires one of the following:
716      * <ul>
717      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
718      *     <li>If the caller is the device or profile owner, the caller holds the
719      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
720      *     <li>The caller has carrier privileges (see
721      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
722      *     active subscription.</li>
723      * </ul>
724      * <p>The profile owner is an app that owns a managed profile on the device; for more details
725      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
726      * Access by profile owners is deprecated and will be removed in a future release.
727      *
728      * @param c The MmTel {@link CapabilityCallback} to be removed.
729      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
730      */
731     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
732     @RequiresPermission(anyOf = {
733             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
734             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
unregisterMmTelCapabilityCallback(@onNull CapabilityCallback c)735     public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
736         if (c == null) {
737             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
738         }
739 
740         ITelephony iTelephony = getITelephony();
741         if (iTelephony == null) {
742             Log.w("ImsMmTelManager", "Could not find Telephony Service.");
743             return;
744         }
745         try {
746             iTelephony.unregisterMmTelCapabilityCallback(mSubId, c.getBinder());
747         } catch (RemoteException e) {
748             throw e.rethrowAsRuntimeException();
749         }
750     }
751 
752     /**
753      * Query the user’s setting for “Advanced Calling” or "Enhanced 4G LTE", which is used to
754      * enable MmTel IMS features, depending on the carrier configuration for the current
755      * subscription. If this setting is enabled, IMS voice and video telephony over IWLAN/LTE will
756      * be enabled as long as the carrier has provisioned these services for the specified
757      * subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
758      * carrier requirements.
759      * <p>
760      * Note: If the carrier configuration for advanced calling is not editable or hidden, this
761      * method will always return the default value.
762      * <p>This API requires one of the following:
763      * <ul>
764      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
765      *     <li>If the caller is the device or profile owner, the caller holds the
766      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
767      *     <li>The caller has carrier privileges (see
768      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
769      *     active subscription.</li>
770      * </ul>
771      * <p>The profile owner is an app that owns a managed profile on the device; for more details
772      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
773      * Access by profile owners is deprecated and will be removed in a future release.
774      *
775      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
776      * @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
777      * @see android.telephony.CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL
778      * @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
779      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
780      * @throws IllegalArgumentException if the subscription associated with this operation is not
781      * active (SIM is not inserted, ESIM inactive) or invalid.
782      * @throws UnsupportedOperationException If the device does not have
783      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
784      * @return true if the user's setting for advanced calling is enabled, false otherwise.
785      */
786     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
787     @RequiresPermission(anyOf = {
788             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
789             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
isAdvancedCallingSettingEnabled()790     public boolean isAdvancedCallingSettingEnabled() {
791         ITelephony iTelephony = getITelephony();
792         if (iTelephony == null) {
793             throw new RuntimeException("Could not find Telephony Service.");
794         }
795 
796         try {
797             return iTelephony.isAdvancedCallingSettingEnabled(mSubId);
798         } catch (ServiceSpecificException e) {
799             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
800                 // Rethrow as runtime error to keep API compatible.
801                 throw new IllegalArgumentException(e.getMessage());
802             } else {
803                 throw new RuntimeException(e.getMessage());
804             }
805         } catch (RemoteException e) {
806             throw e.rethrowAsRuntimeException();
807         }
808     }
809 
810     /**
811      * Modify the user’s setting for “Advanced Calling” or "Enhanced 4G LTE", which is used to
812      * enable MmTel IMS features, depending on the carrier configuration for the current
813      * subscription. If this setting is enabled, IMS voice and video telephony over IWLAN/LTE will
814      * be enabled as long as the carrier has provisioned these services for the specified
815      * subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
816      * carrier requirements.
817      *
818      * Modifying this value may also trigger an IMS registration or deregistration, depending on
819      * whether or not the new value is enabled or disabled.
820      *
821      * Note: If the carrier configuration for advanced calling is not editable or hidden, this
822      * method will do nothing and will instead always use the default value.
823      *
824      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
825      * @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
826      * @see android.telephony.CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL
827      * @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
828      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
829      * @see #isAdvancedCallingSettingEnabled()
830      * @throws IllegalArgumentException if the subscription associated with this operation is not
831      * active (SIM is not inserted, ESIM inactive) or invalid.
832      * @throws UnsupportedOperationException If the device does not have
833      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
834      * @hide
835      */
836     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
837     @SystemApi
setAdvancedCallingSettingEnabled(boolean isEnabled)838     public void setAdvancedCallingSettingEnabled(boolean isEnabled) {
839         ITelephony iTelephony = getITelephony();
840         if (iTelephony == null) {
841             throw new RuntimeException("Could not find Telephony Service.");
842         }
843 
844         try {
845             iTelephony.setAdvancedCallingSettingEnabled(mSubId, isEnabled);
846         } catch (ServiceSpecificException e) {
847             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
848                 // Rethrow as runtime error to keep API compatible.
849                 throw new IllegalArgumentException(e.getMessage());
850             } else {
851                 throw new RuntimeException(e.getMessage());
852             }
853         } catch (RemoteException e) {
854             throw e.rethrowAsRuntimeException();
855         }
856     }
857 
858     /**
859      * Query the IMS MmTel capability for a given registration technology. This does not
860      * necessarily mean that we are registered and the capability is available, but rather the
861      * subscription is capable of this service over IMS.
862      *
863      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
864      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VT_AVAILABLE_BOOL
865      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_IMS_GBA_REQUIRED_BOOL
866      * @see #isAvailable(int, int)
867      *
868      * @param imsRegTech The IMS registration technology.
869      * @param capability The IMS MmTel capability to query.
870      * @return {@code true} if the MmTel IMS capability is capable for this subscription, false
871      *         otherwise.
872      * @throws UnsupportedOperationException If the device does not have
873      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
874      * @hide
875      */
876     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
877     @SystemApi
isCapable(@mTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech)878     public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
879             @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
880         ITelephony iTelephony = getITelephony();
881         if (iTelephony == null) {
882             throw new RuntimeException("Could not find Telephony Service.");
883         }
884 
885         try {
886             return iTelephony.isCapable(mSubId, capability, imsRegTech);
887         } catch (RemoteException e) {
888             throw e.rethrowAsRuntimeException();
889         }
890     }
891 
892     /**
893      * Query the availability of an IMS MmTel capability for a given registration technology. If
894      * a capability is available, IMS is registered and the service is currently available over IMS.
895      *
896      * @see #isCapable(int, int)
897      *
898      * @param imsRegTech The IMS registration technology.
899      * @param capability The IMS MmTel capability to query.
900      * @return {@code true} if the MmTel IMS capability is available for this subscription, false
901      *         otherwise.
902      * @throws UnsupportedOperationException If the device does not have
903      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
904      * @hide
905      */
906     @SystemApi
907     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
isAvailable(@mTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech)908     public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
909             @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
910         ITelephony iTelephony = getITelephony();
911         if (iTelephony == null) {
912             throw new RuntimeException("Could not find Telephony Service.");
913         }
914 
915         try {
916             return iTelephony.isAvailable(mSubId, capability, imsRegTech);
917         } catch (RemoteException e) {
918             throw e.rethrowAsRuntimeException();
919         }
920     }
921 
922     /**
923      * Query whether or not the requested MmTel capability is supported by the carrier on the
924      * specified network transport.
925      * <p>
926      * This is a configuration option and does not change. The only time this may change is if a
927      * new IMS configuration is loaded when there is a
928      * {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} broadcast for this subscription.
929      * @param capability The capability that is being queried for support on the carrier network.
930      * @param transportType The transport type of the capability to check support for.
931      * @param executor The executor that the callback will be called with.
932      * @param callback A consumer containing a Boolean result specifying whether or not the
933      *                 capability is supported on this carrier network for the transport specified.
934      * @throws ImsException if the subscription is no longer valid or the IMS service is not
935      * available.
936      * @hide
937      */
938     @SystemApi
939     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
isSupported(@mTelFeature.MmTelCapabilities.MmTelCapability int capability, @AccessNetworkConstants.TransportType int transportType, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)940     public void isSupported(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
941             @AccessNetworkConstants.TransportType int transportType,
942             @NonNull @CallbackExecutor Executor executor,
943             @NonNull Consumer<Boolean> callback) throws ImsException {
944         if (callback == null) {
945             throw new IllegalArgumentException("Must include a non-null Consumer.");
946         }
947         if (executor == null) {
948             throw new IllegalArgumentException("Must include a non-null Executor.");
949         }
950 
951         ITelephony iTelephony = getITelephony();
952         if (iTelephony == null) {
953             throw new ImsException("Could not find Telephony Service.",
954                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
955         }
956 
957         try {
958             iTelephony.isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() {
959                 @Override
960                 public void accept(int result) {
961                     final long identity = Binder.clearCallingIdentity();
962                     try {
963                         executor.execute(() -> callback.accept(result == 1));
964                     } finally {
965                         Binder.restoreCallingIdentity(identity);
966                     }
967                 }
968             }, capability, transportType);
969         } catch (ServiceSpecificException sse) {
970             throw new ImsException(sse.getMessage(), sse.errorCode);
971         } catch (RemoteException e) {
972             e.rethrowAsRuntimeException();
973         }
974     }
975 
976     /**
977      * The user's setting for whether or not they have enabled the "Video Calling" setting.
978      *
979      * <p>
980      * Note: If the carrier configuration for advanced calling is not editable or hidden, this
981      * method will always return the default value.
982      * <p>This API requires one of the following:
983      * <ul>
984      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
985      *     <li>If the caller is the device or profile owner, the caller holds the
986      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
987      *     <li>The caller has carrier privileges (see
988      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
989      *     active subscription.</li>
990      * </ul>
991      * <p>The profile owner is an app that owns a managed profile on the device; for more details
992      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
993      * Access by profile owners is deprecated and will be removed in a future release.
994      *
995      * @throws IllegalArgumentException if the subscription associated with this operation is not
996      * active (SIM is not inserted, ESIM inactive) or invalid.
997      * @throws UnsupportedOperationException If the device does not have
998      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
999      * @return true if the user’s “Video Calling” setting is currently enabled.
1000      */
1001     @RequiresPermission(anyOf = {
1002             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1003             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
1004     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
isVtSettingEnabled()1005     public boolean isVtSettingEnabled() {
1006         ITelephony iTelephony = getITelephony();
1007         if (iTelephony == null) {
1008             throw new RuntimeException("Could not find Telephony Service.");
1009         }
1010 
1011         try {
1012             return iTelephony.isVtSettingEnabled(mSubId);
1013         } catch (ServiceSpecificException e) {
1014             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1015                 // Rethrow as runtime error to keep API compatible.
1016                 throw new IllegalArgumentException(e.getMessage());
1017             } else {
1018                 throw new RuntimeException(e.getMessage());
1019             }
1020         } catch (RemoteException e) {
1021             throw e.rethrowAsRuntimeException();
1022         }
1023     }
1024 
1025     /**
1026      * Change the user's setting for Video Telephony and enable the Video Telephony capability.
1027      *
1028      * @throws IllegalArgumentException if the subscription associated with this operation is not
1029      * active (SIM is not inserted, ESIM inactive) or invalid.
1030      * @throws UnsupportedOperationException If the device does not have
1031      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1032      * @see #isVtSettingEnabled()
1033      * @hide
1034      */
1035     @SystemApi
1036     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVtSettingEnabled(boolean isEnabled)1037     public void setVtSettingEnabled(boolean isEnabled) {
1038         ITelephony iTelephony = getITelephony();
1039         if (iTelephony == null) {
1040             throw new RuntimeException("Could not find Telephony Service.");
1041         }
1042 
1043         try {
1044             iTelephony.setVtSettingEnabled(mSubId, isEnabled);
1045         } catch (ServiceSpecificException e) {
1046             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1047                 // Rethrow as runtime error to keep API compatible.
1048                 throw new IllegalArgumentException(e.getMessage());
1049             } else {
1050                 throw new RuntimeException(e.getMessage());
1051             }
1052         } catch (RemoteException e) {
1053             throw e.rethrowAsRuntimeException();
1054         }
1055     }
1056 
1057     /**
1058      * @return true if the user's setting for Voice over WiFi is enabled and false if it is not.
1059      *
1060      * <p>This API requires one of the following:
1061      * <ul>
1062      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
1063      *     <li>If the caller is the device or profile owner, the caller holds the
1064      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
1065      *     <li>The caller has carrier privileges (see
1066      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
1067      *     active subscription.</li>
1068      * </ul>
1069      * <p>The profile owner is an app that owns a managed profile on the device; for more details
1070      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
1071      * Access by profile owners is deprecated and will be removed in a future release.
1072      *
1073      * @throws IllegalArgumentException if the subscription associated with this operation is not
1074      * active (SIM is not inserted, ESIM inactive) or invalid.
1075      * @throws UnsupportedOperationException If the device does not have
1076      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1077      */
1078     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
1079     @RequiresPermission(anyOf = {
1080             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1081             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
isVoWiFiSettingEnabled()1082     public boolean isVoWiFiSettingEnabled() {
1083         ITelephony iTelephony = getITelephony();
1084         if (iTelephony == null) {
1085             throw new RuntimeException("Could not find Telephony Service.");
1086         }
1087 
1088         try {
1089             return iTelephony.isVoWiFiSettingEnabled(mSubId);
1090         } catch (ServiceSpecificException e) {
1091             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1092                 // Rethrow as runtime error to keep API compatible.
1093                 throw new IllegalArgumentException(e.getMessage());
1094             } else {
1095                 throw new RuntimeException(e.getMessage());
1096             }
1097         } catch (RemoteException e) {
1098             throw e.rethrowAsRuntimeException();
1099         }
1100     }
1101 
1102     /**
1103      * Sets the user's setting for whether or not Voice over WiFi is enabled.
1104      *
1105      * @throws IllegalArgumentException if the subscription associated with this operation is not
1106      * active (SIM is not inserted, ESIM inactive) or invalid.
1107      * @throws UnsupportedOperationException If the device does not have
1108      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1109      * @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise=
1110      * @see #isVoWiFiSettingEnabled()
1111      * @hide
1112      */
1113     @SystemApi
1114     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVoWiFiSettingEnabled(boolean isEnabled)1115     public void setVoWiFiSettingEnabled(boolean isEnabled) {
1116         ITelephony iTelephony = getITelephony();
1117         if (iTelephony == null) {
1118             throw new RuntimeException("Could not find Telephony Service.");
1119         }
1120 
1121         try {
1122             iTelephony.setVoWiFiSettingEnabled(mSubId, isEnabled);
1123         } catch (ServiceSpecificException e) {
1124             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1125                 // Rethrow as runtime error to keep API compatible.
1126                 throw new IllegalArgumentException(e.getMessage());
1127             } else {
1128                 throw new RuntimeException(e.getMessage());
1129             }
1130         } catch (RemoteException e) {
1131             throw e.rethrowAsRuntimeException();
1132         }
1133     }
1134 
1135     /**
1136      * This configuration is meaningful only on dual sim device.
1137      * If enabled, this will result in the device setting up IMS of all other
1138      * active subscriptions over the INTERNET APN of the primary default data subscription
1139      * when any of those subscriptions are roaming or out of service and if wifi is not available
1140      * for VoWifi. This feature will be disabled if
1141      * {@link CarrierConfigManager#KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL} is set to false.
1142      * <p>Following are the conditions in which system will try to register IMS over
1143      * cross sim
1144      * <ul>
1145      *     <li>Wifi is not available, one SIM is roaming and the default data
1146      *     SIM is in home network. Then roaming SIM IMS will be registered over INTERNET APN of the
1147      *     default data subscription </li>
1148      *     <li>Wifi is not available, one SIM is out of service and the default data
1149      *     SIM is in home network. Then out of service SIM IMS will be registered over INTERNET
1150      *     APN of the default data subscription </li>
1151      * </ul>
1152      * <p>This API requires one of the following:
1153      * <ul>
1154      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
1155      *     <li>If the caller is the device or profile owner, the caller holds the
1156      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
1157      *     <li>The caller has carrier privileges (see
1158      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
1159      *     active subscription.</li>
1160      * </ul>
1161      * <p>The profile owner is an app that owns a managed profile on the device; for more details
1162      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
1163      * Access by profile owners is deprecated and will be removed in a future release.
1164      *
1165      * @throws ImsException if the IMS service associated with this subscription is not available or
1166      * the IMS service is not available.
1167      * @throws UnsupportedOperationException If the device does not have
1168      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1169      * @return true if the user's setting for Voice over Cross SIM is enabled and false if it is not
1170      */
1171     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
1172     @RequiresPermission(anyOf = {
1173             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1174             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
isCrossSimCallingEnabled()1175     public boolean isCrossSimCallingEnabled() throws ImsException {
1176         ITelephony iTelephony = getITelephony();
1177         if (iTelephony == null) {
1178             throw new ImsException("Could not find Telephony Service.",
1179                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
1180         }
1181 
1182         try {
1183             return iTelephony.isCrossSimCallingEnabledByUser(mSubId);
1184         } catch (ServiceSpecificException sse) {
1185             throw new ImsException(sse.getMessage(), sse.errorCode);
1186         } catch (RemoteException e) {
1187             e.rethrowAsRuntimeException();
1188         }
1189         // Not reachable. Adding return to make compiler happy.
1190         return false;
1191     }
1192 
1193     /**
1194      * Sets the user's setting for whether or not Voice over Cross SIM is enabled.
1195      * If enabled, this will result in the device setting up IMS of all other
1196      * active subscriptions over the INTERNET APN of the primary default data subscription
1197      * when any of those subscriptions are roaming or out of service and if wifi is not available
1198      * for VoWifi. This feature will be disabled if
1199      * {@link CarrierConfigManager#KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL} is set to false.
1200      *
1201      * <p>Following are the conditions in which system will try to register IMS over
1202      * cross sim
1203      * <ul>
1204      *     <li>Wifi is not available, one SIM is roaming and the default data
1205      *     SIM is in home network. Then roaming SIM IMS will be registered over INTERNET APN of the
1206      *     default data subscription </li>
1207      *     <li>Wifi is not available, one SIM is out of service and the default data
1208      *     SIM is in home network. Then out of service SIM IMS will be registered over INTERNET
1209      *     APN of the default data subscription </li>
1210      * </ul>
1211      * @throws ImsException if the IMS service associated with this subscription is not available or
1212      * the IMS service is not available.
1213      * @throws UnsupportedOperationException If the device does not have
1214      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1215      * @param isEnabled true if the user's setting for Voice over Cross SIM is enabled,
1216      *                 false otherwise
1217      * @see #isCrossSimCallingEnabled()
1218      * @hide
1219      */
1220     @SystemApi
1221     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setCrossSimCallingEnabled(boolean isEnabled)1222     public void setCrossSimCallingEnabled(boolean isEnabled) throws ImsException {
1223         ITelephony iTelephony = getITelephony();
1224         if (iTelephony == null) {
1225             throw new ImsException("Could not find Telephony Service.",
1226                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
1227         }
1228 
1229         try {
1230             iTelephony.setCrossSimCallingEnabled(mSubId, isEnabled);
1231         } catch (ServiceSpecificException sse) {
1232             throw new ImsException(sse.getMessage(), sse.errorCode);
1233         } catch (RemoteException e) {
1234             e.rethrowAsRuntimeException();
1235         }
1236     }
1237 
1238     /**
1239      * Returns the user's voice over WiFi roaming setting associated with the current subscription.
1240      *
1241      * <p>This API requires one of the following:
1242      * <ul>
1243      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
1244      *     <li>If the caller is the device or profile owner, the caller holds the
1245      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
1246      *     <li>The caller has carrier privileges (see
1247      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
1248      *     active subscription.</li>
1249      * </ul>
1250      * <p>The profile owner is an app that owns a managed profile on the device; for more details
1251      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
1252      * Access by profile owners is deprecated and will be removed in a future release.
1253      *
1254      * @throws IllegalArgumentException if the subscription associated with this operation is not
1255      * active (SIM is not inserted, ESIM inactive) or invalid.
1256      * @throws UnsupportedOperationException If the device does not have
1257      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1258      * @return true if the user's setting for Voice over WiFi while roaming is enabled, false
1259      * if disabled.
1260      */
1261     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
1262     @RequiresPermission(anyOf = {
1263             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1264             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
isVoWiFiRoamingSettingEnabled()1265     public boolean isVoWiFiRoamingSettingEnabled() {
1266         ITelephony iTelephony = getITelephony();
1267         if (iTelephony == null) {
1268             throw new RuntimeException("Could not find Telephony Service.");
1269         }
1270 
1271         try {
1272             return iTelephony.isVoWiFiRoamingSettingEnabled(mSubId);
1273         } catch (ServiceSpecificException e) {
1274             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1275                 // Rethrow as runtime error to keep API compatible.
1276                 throw new IllegalArgumentException(e.getMessage());
1277             } else {
1278                 throw new RuntimeException(e.getMessage());
1279             }
1280         } catch (RemoteException e) {
1281             throw e.rethrowAsRuntimeException();
1282         }
1283     }
1284 
1285     /**
1286      * Change the user's setting for Voice over WiFi while roaming.
1287      *
1288      * @param isEnabled true if the user's setting for Voice over WiFi while roaming is enabled,
1289      *     false otherwise.
1290      * @throws IllegalArgumentException if the subscription associated with this operation is not
1291      * active (SIM is not inserted, ESIM inactive) or invalid.
1292      * @throws UnsupportedOperationException If the device does not have
1293      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1294      * @see #isVoWiFiRoamingSettingEnabled()
1295      * @hide
1296      */
1297     @SystemApi
1298     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVoWiFiRoamingSettingEnabled(boolean isEnabled)1299     public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) {
1300         ITelephony iTelephony = getITelephony();
1301         if (iTelephony == null) {
1302             throw new RuntimeException("Could not find Telephony Service.");
1303         }
1304 
1305         try {
1306             iTelephony.setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
1307         } catch (ServiceSpecificException e) {
1308             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1309                 // Rethrow as runtime error to keep API compatible.
1310                 throw new IllegalArgumentException(e.getMessage());
1311             } else {
1312                 throw new RuntimeException(e.getMessage());
1313             }
1314         } catch (RemoteException e) {
1315             throw e.rethrowAsRuntimeException();
1316         }
1317     }
1318 
1319     /**
1320      * Overrides the Voice over WiFi capability to true for IMS, but do not persist the setting.
1321      * Typically used during the Voice over WiFi registration process for some carriers.
1322      *
1323      * @param isCapable true if the IMS stack should try to register for IMS over IWLAN, false
1324      *     otherwise.
1325      * @param mode the Voice over WiFi mode preference to set, which can be one of the following:
1326      * - {@link #WIFI_MODE_WIFI_ONLY}
1327      * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
1328      * - {@link #WIFI_MODE_WIFI_PREFERRED}
1329      * @throws IllegalArgumentException if the subscription associated with this operation is not
1330      * active (SIM is not inserted, ESIM inactive) or invalid.
1331      * @throws UnsupportedOperationException If the device does not have
1332      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1333      * @see #setVoWiFiSettingEnabled(boolean)
1334      * @hide
1335      */
1336     @SystemApi
1337     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVoWiFiNonPersistent(boolean isCapable, int mode)1338     public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
1339         ITelephony iTelephony = getITelephony();
1340         if (iTelephony == null) {
1341             throw new RuntimeException("Could not find Telephony Service.");
1342         }
1343 
1344         try {
1345             iTelephony.setVoWiFiNonPersistent(mSubId, isCapable, mode);
1346         } catch (ServiceSpecificException e) {
1347             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1348                 // Rethrow as runtime error to keep API compatible.
1349                 throw new IllegalArgumentException(e.getMessage());
1350             } else {
1351                 throw new RuntimeException(e.getMessage());
1352             }
1353         } catch (RemoteException e) {
1354             throw e.rethrowAsRuntimeException();
1355         }
1356     }
1357 
1358     /**
1359      * Returns the user's voice over WiFi Roaming mode setting associated with the device.
1360      *
1361      * <p>This API requires one of the following:
1362      * <ul>
1363      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
1364      *     <li>If the caller is the device or profile owner, the caller holds the
1365      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
1366      *     <li>The caller has carrier privileges (see
1367      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
1368      *     active subscription.</li>
1369      * </ul>
1370      * <p>The profile owner is an app that owns a managed profile on the device; for more details
1371      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
1372      * Access by profile owners is deprecated and will be removed in a future release.
1373      *
1374      * @throws IllegalArgumentException if the subscription associated with this operation is not
1375      * active (SIM is not inserted, ESIM inactive) or invalid.
1376      * @throws UnsupportedOperationException If the device does not have
1377      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1378      * @return The Voice over WiFi Mode preference set by the user, which can be one of the
1379      * following:
1380      * - {@link #WIFI_MODE_WIFI_ONLY}
1381      * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
1382      * - {@link #WIFI_MODE_WIFI_PREFERRED}
1383      */
1384     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
1385     @RequiresPermission(anyOf = {
1386             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1387             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
getVoWiFiModeSetting()1388     public @WiFiCallingMode int getVoWiFiModeSetting() {
1389         ITelephony iTelephony = getITelephony();
1390         if (iTelephony == null) {
1391             throw new RuntimeException("Could not find Telephony Service.");
1392         }
1393 
1394         try {
1395             return iTelephony.getVoWiFiModeSetting(mSubId);
1396         } catch (ServiceSpecificException e) {
1397             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1398                 // Rethrow as runtime error to keep API compatible.
1399                 throw new IllegalArgumentException(e.getMessage());
1400             } else {
1401                 throw new RuntimeException(e.getMessage());
1402             }
1403         } catch (RemoteException e) {
1404             throw e.rethrowAsRuntimeException();
1405         }
1406     }
1407 
1408     /**
1409      * Set the user's preference for Voice over WiFi calling mode.
1410      * @param mode The user's preference for the technology to register for IMS over, can be one of
1411      *    the following:
1412      * - {@link #WIFI_MODE_WIFI_ONLY}
1413      * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
1414      * - {@link #WIFI_MODE_WIFI_PREFERRED}
1415      * @throws IllegalArgumentException if the subscription associated with this operation is not
1416      * active (SIM is not inserted, ESIM inactive) or invalid.
1417      * @throws UnsupportedOperationException If the device does not have
1418      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1419      * @see #getVoWiFiModeSetting()
1420      * @hide
1421      */
1422     @SystemApi
1423     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVoWiFiModeSetting(@iFiCallingMode int mode)1424     public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
1425         ITelephony iTelephony = getITelephony();
1426         if (iTelephony == null) {
1427             throw new RuntimeException("Could not find Telephony Service.");
1428         }
1429 
1430         try {
1431             iTelephony.setVoWiFiModeSetting(mSubId, mode);
1432         } catch (ServiceSpecificException e) {
1433             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1434                 // Rethrow as runtime error to keep API compatible.
1435                 throw new IllegalArgumentException(e.getMessage());
1436             } else {
1437                 throw new RuntimeException(e.getMessage());
1438             }
1439         } catch (RemoteException e) {
1440             throw e.rethrowAsRuntimeException();
1441         }
1442     }
1443 
1444     /**
1445      * Set the user's preference for Voice over WiFi calling mode while the device is roaming on
1446      * another network.
1447      *
1448      * @return The user's preference for the technology to register for IMS over when roaming on
1449      *     another network, can be one of the following:
1450      *     - {@link #WIFI_MODE_WIFI_ONLY}
1451      *     - {@link #WIFI_MODE_CELLULAR_PREFERRED}
1452      *     - {@link #WIFI_MODE_WIFI_PREFERRED}
1453      * @throws IllegalArgumentException if the subscription associated with this operation is not
1454      * active (SIM is not inserted, ESIM inactive) or invalid.
1455      * @throws UnsupportedOperationException If the device does not have
1456      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1457      * @see #setVoWiFiRoamingSettingEnabled(boolean)
1458      * @hide
1459      */
1460     @SystemApi
1461     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
getVoWiFiRoamingModeSetting()1462     public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
1463         ITelephony iTelephony = getITelephony();
1464         if (iTelephony == null) {
1465             throw new RuntimeException("Could not find Telephony Service.");
1466         }
1467 
1468         try {
1469             return iTelephony.getVoWiFiRoamingModeSetting(mSubId);
1470         } catch (ServiceSpecificException e) {
1471             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1472                 // Rethrow as runtime error to keep API compatible.
1473                 throw new IllegalArgumentException(e.getMessage());
1474             } else {
1475                 throw new RuntimeException(e.getMessage());
1476             }
1477         } catch (RemoteException e) {
1478             throw e.rethrowAsRuntimeException();
1479         }
1480     }
1481 
1482     /**
1483      * Set the user's preference for Voice over WiFi mode while the device is roaming on another
1484      * network.
1485      *
1486      * @param mode The user's preference for the technology to register for IMS over when roaming on
1487      *     another network, can be one of the following:
1488      *     - {@link #WIFI_MODE_WIFI_ONLY}
1489      *     - {@link #WIFI_MODE_CELLULAR_PREFERRED}
1490      *     - {@link #WIFI_MODE_WIFI_PREFERRED}
1491      * @throws IllegalArgumentException if the subscription associated with this operation is not
1492      * active (SIM is not inserted, ESIM inactive) or invalid.
1493      * @throws UnsupportedOperationException If the device does not have
1494      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1495      * @see #getVoWiFiRoamingModeSetting()
1496      * @hide
1497      */
1498     @SystemApi
1499     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVoWiFiRoamingModeSetting(@iFiCallingMode int mode)1500     public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
1501         ITelephony iTelephony = getITelephony();
1502         if (iTelephony == null) {
1503             throw new RuntimeException("Could not find Telephony Service.");
1504         }
1505 
1506         try {
1507             iTelephony.setVoWiFiRoamingModeSetting(mSubId, mode);
1508         } catch (ServiceSpecificException e) {
1509             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1510                 // Rethrow as runtime error to keep API compatible.
1511                 throw new IllegalArgumentException(e.getMessage());
1512             } else {
1513                 throw new RuntimeException(e.getMessage());
1514             }
1515         } catch (RemoteException e) {
1516             throw e.rethrowAsRuntimeException();
1517         }
1518     }
1519 
1520     /**
1521      * Sets the capability of RTT for IMS calls placed on this subscription.
1522      *
1523      * Note: This does not affect the value of
1524      * {@link android.provider.Settings.Secure#RTT_CALLING_MODE}, which is the global user setting
1525      * for RTT. That value is enabled/disabled separately by the user through the Accessibility
1526      * settings.
1527      * @throws IllegalArgumentException if the subscription associated with this operation is not
1528      * active (SIM is not inserted, ESIM inactive) or invalid.
1529      * @throws UnsupportedOperationException If the device does not have
1530      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1531      * @param isEnabled if true RTT should be enabled during calls made on this subscription.
1532      * @hide
1533      */
1534     @SystemApi
1535     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setRttCapabilitySetting(boolean isEnabled)1536     public void setRttCapabilitySetting(boolean isEnabled) {
1537         ITelephony iTelephony = getITelephony();
1538         if (iTelephony == null) {
1539             throw new RuntimeException("Could not find Telephony Service.");
1540         }
1541 
1542         try {
1543             iTelephony.setRttCapabilitySetting(mSubId, isEnabled);
1544         } catch (ServiceSpecificException e) {
1545             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1546                 // Rethrow as runtime error to keep API compatible.
1547                 throw new IllegalArgumentException(e.getMessage());
1548             } else {
1549                 throw new RuntimeException(e.getMessage());
1550             }
1551         } catch (RemoteException e) {
1552             throw e.rethrowAsRuntimeException();
1553         }
1554     }
1555 
1556     /**
1557      * @return true if TTY over VoLTE is supported
1558      *
1559      * <p>This API requires one of the following:
1560      * <ul>
1561      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
1562      *     <li>If the caller is the device or profile owner, the caller holds the
1563      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
1564      *     <li>The caller has carrier privileges (see
1565      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
1566      *     active subscription.</li>
1567      * </ul>
1568      * <p>The profile owner is an app that owns a managed profile on the device; for more details
1569      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
1570      * Access by profile owners is deprecated and will be removed in a future release.
1571      *
1572      * @throws IllegalArgumentException if the subscription associated with this operation is not
1573      * active (SIM is not inserted, ESIM inactive) or invalid.
1574      * @throws UnsupportedOperationException If the device does not have
1575      *          {@link PackageManager#FEATURE_TELEPHONY_IMS}.
1576      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
1577      */
1578     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
1579     @RequiresPermission(anyOf = {
1580             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1581             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
isTtyOverVolteEnabled()1582     public boolean isTtyOverVolteEnabled() {
1583         ITelephony iTelephony = getITelephony();
1584         if (iTelephony == null) {
1585             throw new RuntimeException("Could not find Telephony Service.");
1586         }
1587 
1588         try {
1589             return iTelephony.isTtyOverVolteEnabled(mSubId);
1590         } catch (ServiceSpecificException e) {
1591             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1592                 // Rethrow as runtime error to keep API compatible.
1593                 throw new IllegalArgumentException(e.getMessage());
1594             } else {
1595                 throw new RuntimeException(e.getMessage());
1596             }
1597         } catch (RemoteException e) {
1598             throw e.rethrowAsRuntimeException();
1599         }
1600     }
1601 
1602     /**
1603      * Get the status of the MmTel Feature registered on this subscription.
1604      * @param executor The executor that will be used to call the callback.
1605      * @param callback A callback containing an Integer describing the current state of the
1606      *                 MmTel feature, Which will be one of the following:
1607      *                 {@link ImsFeature#STATE_UNAVAILABLE},
1608      *                {@link ImsFeature#STATE_INITIALIZING},
1609      *                {@link ImsFeature#STATE_READY}. Will be called using the executor
1610      *                 specified when the service state has been retrieved from the IMS service.
1611      * @throws ImsException if the IMS service associated with this subscription is not available or
1612      * the IMS service is not available.
1613      * @hide
1614      */
1615     @SystemApi
1616     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
getFeatureState(@onNull @allbackExecutor Executor executor, @NonNull @ImsFeature.ImsState Consumer<Integer> callback)1617     public void getFeatureState(@NonNull @CallbackExecutor Executor executor,
1618             @NonNull @ImsFeature.ImsState Consumer<Integer> callback) throws ImsException {
1619         if (executor == null) {
1620             throw new IllegalArgumentException("Must include a non-null Executor.");
1621         }
1622         if (callback == null) {
1623             throw new IllegalArgumentException("Must include a non-null Consumer.");
1624         }
1625 
1626         ITelephony iTelephony = getITelephony();
1627         if (iTelephony == null) {
1628             throw new ImsException("Could not find Telephony Service.",
1629                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
1630         }
1631 
1632         try {
1633             iTelephony.getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
1634                 @Override
1635                 public void accept(int result) {
1636                     final long identity = Binder.clearCallingIdentity();
1637                     try {
1638                         executor.execute(() -> callback.accept(result));
1639                     } finally {
1640                         Binder.restoreCallingIdentity(identity);
1641                     }
1642                 }
1643             });
1644         } catch (ServiceSpecificException sse) {
1645             throw new ImsException(sse.getMessage(), sse.errorCode);
1646         } catch (RemoteException e) {
1647             e.rethrowAsRuntimeException();
1648         }
1649     }
1650 
1651     /**
1652      * Register a new callback, which is used to notify the registrant of changes to
1653      * the state of the underlying IMS service that is attached to telephony to
1654      * implement IMS functionality. If the manager is created for
1655      * the {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
1656      * this throws an {@link ImsException}.
1657      *
1658      * <p>Requires Permission:
1659      * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
1660      * or that the calling app has carrier privileges
1661      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
1662      *
1663      * @param executor the Executor that will be used to call the {@link ImsStateCallback}.
1664      * @param callback The callback instance being registered.
1665      * @throws ImsException in the case that the callback can not be registered.
1666      * See {@link ImsException#getCode} for more information on when this is called.
1667      */
1668     @RequiresPermission(anyOf = {Manifest.permission.READ_PRECISE_PHONE_STATE,
1669             Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
registerImsStateCallback(@onNull Executor executor, @NonNull ImsStateCallback callback)1670     public void registerImsStateCallback(@NonNull Executor executor,
1671             @NonNull ImsStateCallback callback) throws ImsException {
1672         Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
1673         Objects.requireNonNull(executor, "Must include a non-null Executor.");
1674 
1675         callback.init(executor);
1676         ITelephony telephony = mBinderCache.listenOnBinder(callback, callback::binderDied);
1677         if (telephony == null) {
1678             throw new ImsException("Telephony server is down",
1679                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
1680         }
1681 
1682         try {
1683             telephony.registerImsStateCallback(
1684                     mSubId, ImsFeature.FEATURE_MMTEL,
1685                     callback.getCallbackBinder(), getOpPackageName());
1686         } catch (ServiceSpecificException e) {
1687             throw new ImsException(e.getMessage(), e.errorCode);
1688         } catch (RemoteException | IllegalStateException e) {
1689             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
1690         }
1691     }
1692 
1693     /**
1694      * Unregisters a previously registered callback.
1695      *
1696      * @param callback The callback instance to be unregistered.
1697      */
unregisterImsStateCallback(@onNull ImsStateCallback callback)1698     public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
1699         Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
1700 
1701         ITelephony telephony = mBinderCache.removeRunnable(callback);
1702         try {
1703             if (telephony != null) {
1704                 telephony.unregisterImsStateCallback(callback.getCallbackBinder());
1705             }
1706         } catch (RemoteException ignore) {
1707             // ignore it
1708         }
1709     }
1710 
getOpPackageName()1711     private String getOpPackageName() {
1712         if (mContext != null) {
1713             return mContext.getOpPackageName();
1714         } else {
1715             return null;
1716         }
1717     }
1718 
getITelephony()1719     private ITelephony getITelephony() {
1720         return mBinderCache.getBinder();
1721     }
1722 
getITelephonyInterface()1723     private static ITelephony getITelephonyInterface() {
1724         ITelephony binder = ITelephony.Stub.asInterface(
1725                 TelephonyFrameworkInitializer
1726                         .getTelephonyServiceManager()
1727                         .getTelephonyServiceRegisterer()
1728                         .get());
1729         return binder;
1730     }
1731 
1732     /**
1733      * Convert Wi-Fi calling mode to string.
1734      *
1735      * @param mode Wi-Fi calling mode.
1736      * @return The Wi-Fi calling mode in string format.
1737      *
1738      * @hide
1739      */
1740     @NonNull
wifiCallingModeToString(@msMmTelManager.WiFiCallingMode int mode)1741     public static String wifiCallingModeToString(@ImsMmTelManager.WiFiCallingMode int mode) {
1742         switch (mode) {
1743             case ImsMmTelManager.WIFI_MODE_UNKNOWN: return "UNKNOWN";
1744             case ImsMmTelManager.WIFI_MODE_WIFI_ONLY: return "WIFI_ONLY";
1745             case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED: return "CELLULAR_PREFERRED";
1746             case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED: return "WIFI_PREFERRED";
1747             default:
1748                 return "UNKNOWN(" + mode + ")";
1749         }
1750     }
1751 }
1752