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.IntDef;
23 import android.annotation.NonNull;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SuppressAutoDoc;
26 import android.annotation.SuppressLint;
27 import android.annotation.SystemApi;
28 import android.annotation.TestApi;
29 import android.os.Binder;
30 import android.os.RemoteException;
31 import android.os.ServiceSpecificException;
32 import android.telephony.AccessNetworkConstants;
33 import android.telephony.CarrierConfigManager;
34 import android.telephony.SubscriptionManager;
35 import android.telephony.TelephonyFrameworkInitializer;
36 import android.telephony.ims.aidl.IImsCapabilityCallback;
37 import android.telephony.ims.feature.ImsFeature;
38 import android.telephony.ims.feature.MmTelFeature;
39 import android.telephony.ims.stub.ImsRegistrationImplBase;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.internal.telephony.IIntegerConsumer;
43 import com.android.internal.telephony.ITelephony;
44 
45 import java.lang.annotation.Retention;
46 import java.lang.annotation.RetentionPolicy;
47 import java.util.concurrent.Executor;
48 import java.util.function.Consumer;
49 
50 /**
51  * A manager for the MmTel (Multimedia Telephony) feature of an IMS network, given an associated
52  * subscription.
53  *
54  * Allows a user to query the IMS MmTel feature information for a subscription, register for
55  * registration and MmTel capability status callbacks, as well as query/modify user settings for the
56  * associated subscription.
57  *
58  * Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this
59  * manager.
60  */
61 public class ImsMmTelManager implements RegistrationManager {
62 
63     /**
64      * @hide
65      */
66     @Retention(RetentionPolicy.SOURCE)
67     @IntDef(prefix = "WIFI_MODE_", value = {
68             WIFI_MODE_WIFI_ONLY,
69             WIFI_MODE_CELLULAR_PREFERRED,
70             WIFI_MODE_WIFI_PREFERRED
71             })
72     public @interface WiFiCallingMode {}
73 
74     /**
75      * Register for IMS over IWLAN if WiFi signal quality is high enough. Do not hand over to LTE
76      * registration if signal quality degrades.
77      */
78     public static final int WIFI_MODE_WIFI_ONLY = 0;
79 
80     /**
81      * Prefer registering for IMS over LTE if LTE signal quality is high enough.
82      */
83     public static final int WIFI_MODE_CELLULAR_PREFERRED = 1;
84 
85     /**
86      * Prefer registering for IMS over IWLAN if possible if WiFi signal quality is high enough.
87      */
88     public static final int WIFI_MODE_WIFI_PREFERRED = 2;
89 
90     /**
91      * Callback class for receiving IMS network Registration callback events.
92      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
93      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
94      * @deprecated Use {@link RegistrationManager.RegistrationCallback} instead.
95      * @hide
96      */
97     // Do not add to this class, add to RegistrationManager.RegistrationCallback instead.
98     @Deprecated
99     @SystemApi @TestApi
100     public static class RegistrationCallback extends RegistrationManager.RegistrationCallback {
101 
102         /**
103          * Notifies the framework when the IMS Provider is registered to the IMS network.
104          *
105          * @param imsTransportType the radio access technology.
106          */
107         @Override
onRegistered(@ccessNetworkConstants.TransportType int imsTransportType)108         public void onRegistered(@AccessNetworkConstants.TransportType int imsTransportType) {
109         }
110 
111         /**
112          * Notifies the framework when the IMS Provider is trying to register the IMS network.
113          *
114          * @param imsTransportType the radio access technology.
115          */
116         @Override
onRegistering(@ccessNetworkConstants.TransportType int imsTransportType)117         public void onRegistering(@AccessNetworkConstants.TransportType int imsTransportType) {
118         }
119 
120         /**
121          * Notifies the framework when the IMS Provider is deregistered from the IMS network.
122          *
123          * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
124          */
125         @Override
onUnregistered(@onNull ImsReasonInfo info)126         public void onUnregistered(@NonNull ImsReasonInfo info) {
127         }
128 
129         /**
130          * A failure has occurred when trying to handover registration to another technology type.
131          *
132          * @param imsTransportType The transport type that has failed to handover registration to.
133          * @param info A {@link ImsReasonInfo} that identifies the reason for failure.
134          */
135         @Override
onTechnologyChangeFailed( @ccessNetworkConstants.TransportType int imsTransportType, @NonNull ImsReasonInfo info)136         public void onTechnologyChangeFailed(
137                 @AccessNetworkConstants.TransportType int imsTransportType,
138                 @NonNull ImsReasonInfo info) {
139         }
140     }
141 
142     /**
143      * Receives IMS capability status updates from the ImsService.
144      *
145      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
146      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
147      */
148     public static class CapabilityCallback {
149 
150         private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
151 
152             private final CapabilityCallback mLocalCallback;
153             private Executor mExecutor;
154 
CapabilityBinder(CapabilityCallback c)155             CapabilityBinder(CapabilityCallback c) {
156                 mLocalCallback = c;
157             }
158 
159             @Override
onCapabilitiesStatusChanged(int config)160             public void onCapabilitiesStatusChanged(int config) {
161                 if (mLocalCallback == null) return;
162 
163                 long callingIdentity = Binder.clearCallingIdentity();
164                 try {
165                     mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged(
166                             new MmTelFeature.MmTelCapabilities(config)));
167                 } finally {
168                     restoreCallingIdentity(callingIdentity);
169                 }
170             }
171 
172             @Override
onQueryCapabilityConfiguration(int capability, int radioTech, boolean isEnabled)173             public void onQueryCapabilityConfiguration(int capability, int radioTech,
174                     boolean isEnabled) {
175                 // This is not used for public interfaces.
176             }
177 
178             @Override
onChangeCapabilityConfigurationError(int capability, int radioTech, @ImsFeature.ImsCapabilityError int reason)179             public void onChangeCapabilityConfigurationError(int capability, int radioTech,
180                     @ImsFeature.ImsCapabilityError int reason) {
181                 // This is not used for public interfaces
182             }
183 
setExecutor(Executor executor)184             private void setExecutor(Executor executor) {
185                 mExecutor = executor;
186             }
187         }
188 
189         private final CapabilityBinder mBinder = new CapabilityBinder(this);
190 
191         /**
192          * The status of the feature's capabilities has changed to either available or unavailable.
193          * If unavailable, the feature is not able to support the unavailable capability at this
194          * time.
195          *
196          * @param capabilities The new availability of the capabilities.
197          */
onCapabilitiesStatusChanged( @onNull MmTelFeature.MmTelCapabilities capabilities)198         public void onCapabilitiesStatusChanged(
199                 @NonNull MmTelFeature.MmTelCapabilities capabilities) {
200         }
201 
202         /**@hide*/
getBinder()203         public final IImsCapabilityCallback getBinder() {
204             return mBinder;
205         }
206 
207         /**@hide*/
208         // Only exposed as public method for compatibility with deprecated ImsManager APIs.
209         // TODO: clean up dependencies and change back to private visibility.
setExecutor(Executor executor)210         public final void setExecutor(Executor executor) {
211             mBinder.setExecutor(executor);
212         }
213     }
214 
215     private final int mSubId;
216 
217     /**
218      * Create an instance of {@link ImsMmTelManager} for the subscription id specified.
219      *
220      * @param subId The ID of the subscription that this ImsMmTelManager will use.
221      * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
222      *
223      * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
224      * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
225      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
226      *
227      * @throws IllegalArgumentException if the subscription is invalid.
228      * @deprecated Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an
229      * instance of this class.
230      * @hide
231      */
232     @SystemApi
233     @TestApi
234     @Deprecated
235     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
236     @RequiresPermission(anyOf = {
237             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
238             android.Manifest.permission.READ_PRECISE_PHONE_STATE
239     })
240     @SuppressLint("ManagerLookup")
createForSubscriptionId(int subId)241     public static @NonNull ImsMmTelManager createForSubscriptionId(int subId) {
242         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
243             throw new IllegalArgumentException("Invalid subscription ID");
244         }
245 
246         return new ImsMmTelManager(subId);
247     }
248 
249     /**
250      * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
251      * @hide
252      */
253     @VisibleForTesting
ImsMmTelManager(int subId)254     public ImsMmTelManager(int subId) {
255         mSubId = subId;
256     }
257 
258     /**
259      * Registers a {@link RegistrationCallback} with the system, which will provide registration
260      * updates for the subscription specified in {@link ImsManager#getImsMmTelManager(int)}. Use
261      * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
262      * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
263      *
264      * When the callback is registered, it will initiate the callback c to be called with the
265      * current registration state.
266      *
267      * @param executor The executor the callback events should be run on.
268      * @param c The {@link RegistrationCallback} to be added.
269      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
270      * @throws IllegalArgumentException if the subscription associated with this callback is not
271      * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
272      * {@link CapabilityCallback} callback.
273      * @throws ImsException if the subscription associated with this callback is valid, but
274      * the {@link ImsService} associated with the subscription is not available. This can happen if
275      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
276      * reason.
277      * @deprecated Use {@link RegistrationManager#registerImsRegistrationCallback(Executor,
278      * RegistrationManager.RegistrationCallback)} instead.
279      * @hide
280      */
281     @Deprecated
282     @SystemApi @TestApi
283     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
registerImsRegistrationCallback(@onNull @allbackExecutor Executor executor, @NonNull RegistrationCallback c)284     public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
285             @NonNull RegistrationCallback c) throws ImsException {
286         if (c == null) {
287             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
288         }
289         if (executor == null) {
290             throw new IllegalArgumentException("Must include a non-null Executor.");
291         }
292         c.setExecutor(executor);
293 
294         ITelephony iTelephony = getITelephony();
295         if (iTelephony == null) {
296             throw new ImsException("Could not find Telephony Service.",
297                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
298         }
299 
300         try {
301             iTelephony.registerImsRegistrationCallback(mSubId, c.getBinder());
302         } catch (ServiceSpecificException e) {
303             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
304                 // Rethrow as runtime error to keep API compatible.
305                 throw new IllegalArgumentException(e.getMessage());
306             } else {
307                 throw new ImsException(e.getMessage(), e.errorCode);
308             }
309         } catch (RemoteException | IllegalStateException e) {
310             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
311         }
312     }
313 
314      /**
315      *
316      * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
317      * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
318      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
319      *
320      * {@inheritDoc}
321      *
322      */
323     @Override
324     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
325     @RequiresPermission(anyOf = {
326             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
327             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
registerImsRegistrationCallback(@onNull @allbackExecutor Executor executor, @NonNull RegistrationManager.RegistrationCallback c)328     public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
329             @NonNull RegistrationManager.RegistrationCallback c) throws ImsException {
330         if (c == null) {
331             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
332         }
333         if (executor == null) {
334             throw new IllegalArgumentException("Must include a non-null Executor.");
335         }
336         c.setExecutor(executor);
337 
338         ITelephony iTelephony = getITelephony();
339         if (iTelephony == null) {
340             throw new ImsException("Could not find Telephony Service.",
341                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
342         }
343 
344         try {
345             iTelephony.registerImsRegistrationCallback(mSubId, c.getBinder());
346         } catch (ServiceSpecificException e) {
347             throw new ImsException(e.getMessage(), e.errorCode);
348         } catch (RemoteException | IllegalStateException e) {
349             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
350         }
351     }
352 
353     /**
354      * Removes an existing {@link RegistrationCallback}.
355      *
356      * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
357      * etc...), this callback will automatically be removed. If this method is called for an
358      * inactive subscription, it will result in a no-op.
359      *
360      * @param c The {@link RegistrationCallback} to be removed.
361      * @see SubscriptionManager.OnSubscriptionsChangedListener
362      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
363      * @deprecated Use {@link #unregisterImsRegistrationCallback(
364      * RegistrationManager.RegistrationCallback)}.
365      * @hide
366      */
367     @Deprecated
368     @SystemApi @TestApi
369     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
unregisterImsRegistrationCallback(@onNull RegistrationCallback c)370     public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
371         if (c == null) {
372             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
373         }
374 
375         ITelephony iTelephony = getITelephony();
376         if (iTelephony == null) {
377             throw new RuntimeException("Could not find Telephony Service.");
378         }
379 
380         try {
381             iTelephony.unregisterImsRegistrationCallback(mSubId, c.getBinder());
382         } catch (RemoteException e) {
383             throw e.rethrowAsRuntimeException();
384         }
385     }
386 
387      /**
388      *
389      * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
390      * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
391      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
392      * Access by profile owners is deprecated and will be removed in a future release.
393      *
394      *{@inheritDoc}
395      */
396     @Override
397     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
398     @RequiresPermission(anyOf = {
399             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
400             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
unregisterImsRegistrationCallback( @onNull RegistrationManager.RegistrationCallback c)401     public void unregisterImsRegistrationCallback(
402             @NonNull RegistrationManager.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      * {@inheritDoc}
421      * @hide
422      */
423     @Override
424     @SystemApi @TestApi
425     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
getRegistrationState(@onNull @allbackExecutor Executor executor, @NonNull @ImsRegistrationState Consumer<Integer> stateCallback)426     public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
427             @NonNull @ImsRegistrationState Consumer<Integer> stateCallback) {
428         if (stateCallback == null) {
429             throw new IllegalArgumentException("Must include a non-null callback.");
430         }
431         if (executor == null) {
432             throw new IllegalArgumentException("Must include a non-null Executor.");
433         }
434 
435         ITelephony iTelephony = getITelephony();
436         if (iTelephony == null) {
437             throw new RuntimeException("Could not find Telephony Service.");
438         }
439 
440         try {
441             iTelephony.getImsMmTelRegistrationState(mSubId, new IIntegerConsumer.Stub() {
442                 @Override
443                 public void accept(int result) {
444                     executor.execute(() -> stateCallback.accept(result));
445                 }
446             });
447         } catch (RemoteException e) {
448             throw e.rethrowAsRuntimeException();
449         }
450     }
451 
452     /**
453      * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
454      * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
455      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
456      * Access by profile owners is deprecated and will be removed in a future release.
457      *
458      *{@inheritDoc}
459      */
460     @Override
461     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
462     @RequiresPermission(anyOf = {
463             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
464             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
getRegistrationTransportType(@onNull @allbackExecutor Executor executor, @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback)465     public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
466             @NonNull @AccessNetworkConstants.TransportType
467                     Consumer<Integer> transportTypeCallback) {
468         if (transportTypeCallback == null) {
469             throw new IllegalArgumentException("Must include a non-null callback.");
470         }
471         if (executor == null) {
472             throw new IllegalArgumentException("Must include a non-null Executor.");
473         }
474 
475         ITelephony iTelephony = getITelephony();
476         if (iTelephony == null) {
477             throw new RuntimeException("Could not find Telephony Service.");
478         }
479 
480         try {
481             iTelephony.getImsMmTelRegistrationTransportType(mSubId,
482                     new IIntegerConsumer.Stub() {
483                         @Override
484                         public void accept(int result) {
485                             executor.execute(() -> transportTypeCallback.accept(result));
486                         }
487                     });
488         } catch (RemoteException e) {
489             throw e.rethrowAsRuntimeException();
490         }
491     }
492 
493     /**
494      * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
495      * availability updates for the subscription specified in
496      * {@link ImsManager#getImsMmTelManager(int)}.
497      *
498      * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
499      * subscription changed events and call
500      * {@link #unregisterMmTelCapabilityCallback(CapabilityCallback)} to clean up.
501      * <p>This API requires one of the following:
502      * <ul>
503      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
504      *     <li>If the caller is the device or profile owner, the caller holds the
505      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
506      *     <li>The caller has carrier privileges (see
507      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
508      *     active subscription.</li>
509      *     <li>The caller is the default SMS app for the device.</li>
510      * </ul>
511      * <p>The profile owner is an app that owns a managed profile on the device; for more details
512      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
513      * Access by profile owners is deprecated and will be removed in a future release.
514      *
515      * When the callback is registered, it will initiate the callback c to be called with the
516      * current capabilities.
517      *
518      * @param executor The executor the callback events should be run on.
519      * @param c The MmTel {@link CapabilityCallback} to be registered.
520      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
521      * @throws ImsException if the subscription associated with this callback is valid, but
522      * the {@link ImsService} associated with the subscription is not available. This can happen if
523      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
524      * reason.
525      */
526     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
527     @RequiresPermission(anyOf = {
528             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
529             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
registerMmTelCapabilityCallback(@onNull @allbackExecutor Executor executor, @NonNull CapabilityCallback c)530     public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor,
531             @NonNull CapabilityCallback c) throws ImsException {
532         if (c == null) {
533             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
534         }
535         if (executor == null) {
536             throw new IllegalArgumentException("Must include a non-null Executor.");
537         }
538         c.setExecutor(executor);
539 
540         ITelephony iTelephony = getITelephony();
541         if (iTelephony == null) {
542             throw new ImsException("Could not find Telephony Service.",
543                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
544         }
545 
546         try {
547             iTelephony.registerMmTelCapabilityCallback(mSubId, c.getBinder());
548         } catch (ServiceSpecificException e) {
549             throw new ImsException(e.getMessage(), e.errorCode);
550         } catch (RemoteException e) {
551             throw e.rethrowAsRuntimeException();
552         }  catch (IllegalStateException e) {
553             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
554         }
555     }
556 
557     /**
558      * Removes an existing MmTel {@link CapabilityCallback}.
559      *
560      * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
561      * etc...), this callback will automatically be removed. If this method is called for an
562      * inactive subscription, it will result in a no-op.
563      * <p>This API requires one of the following:
564      * <ul>
565      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
566      *     <li>If the caller is the device or profile owner, the caller holds the
567      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
568      *     <li>The caller has carrier privileges (see
569      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
570      *     active subscription.</li>
571      *     <li>The caller is the default SMS app for the device.</li>
572      * </ul>
573      * <p>The profile owner is an app that owns a managed profile on the device; for more details
574      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
575      * Access by profile owners is deprecated and will be removed in a future release.
576      *
577      * @param c The MmTel {@link CapabilityCallback} to be removed.
578      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
579      */
580     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
581     @RequiresPermission(anyOf = {
582             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
583             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
unregisterMmTelCapabilityCallback(@onNull CapabilityCallback c)584     public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
585         if (c == null) {
586             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
587         }
588 
589         ITelephony iTelephony = getITelephony();
590         if (iTelephony == null) {
591             throw new RuntimeException("Could not find Telephony Service.");
592         }
593 
594         try {
595             iTelephony.unregisterMmTelCapabilityCallback(mSubId, c.getBinder());
596         } catch (RemoteException e) {
597             throw e.rethrowAsRuntimeException();
598         }
599     }
600 
601     /**
602      * Query the user’s setting for “Advanced Calling” or "Enhanced 4G LTE", which is used to
603      * enable MmTel IMS features, depending on the carrier configuration for the current
604      * subscription. If this setting is enabled, IMS voice and video telephony over IWLAN/LTE will
605      * be enabled as long as the carrier has provisioned these services for the specified
606      * subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
607      * carrier requirements.
608      * <p>
609      * Note: If the carrier configuration for advanced calling is not editable or hidden, this
610      * method will always return the default value.
611      * <p>This API requires one of the following:
612      * <ul>
613      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
614      *     <li>If the caller is the device or profile owner, the caller holds the
615      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
616      *     <li>The caller has carrier privileges (see
617      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
618      *     active subscription.</li>
619      *     <li>The caller is the default SMS app for the device.</li>
620      * </ul>
621      * <p>The profile owner is an app that owns a managed profile on the device; for more details
622      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
623      * Access by profile owners is deprecated and will be removed in a future release.
624      *
625      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
626      * @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
627      * @see android.telephony.CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL
628      * @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
629      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
630      * @throws IllegalArgumentException if the subscription associated with this operation is not
631      * active (SIM is not inserted, ESIM inactive) or invalid.
632      * @return true if the user's setting for advanced calling is enabled, false otherwise.
633      */
634     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
635     @RequiresPermission(anyOf = {
636             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
637             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
isAdvancedCallingSettingEnabled()638     public boolean isAdvancedCallingSettingEnabled() {
639         ITelephony iTelephony = getITelephony();
640         if (iTelephony == null) {
641             throw new RuntimeException("Could not find Telephony Service.");
642         }
643 
644         try {
645             return iTelephony.isAdvancedCallingSettingEnabled(mSubId);
646         } catch (ServiceSpecificException e) {
647             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
648                 // Rethrow as runtime error to keep API compatible.
649                 throw new IllegalArgumentException(e.getMessage());
650             } else {
651                 throw new RuntimeException(e.getMessage());
652             }
653         } catch (RemoteException e) {
654             throw e.rethrowAsRuntimeException();
655         }
656     }
657 
658     /**
659      * Modify the user’s setting for “Advanced Calling” or "Enhanced 4G LTE", which is used to
660      * enable MmTel IMS features, depending on the carrier configuration for the current
661      * subscription. If this setting is enabled, IMS voice and video telephony over IWLAN/LTE will
662      * be enabled as long as the carrier has provisioned these services for the specified
663      * subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
664      * carrier requirements.
665      *
666      * Modifying this value may also trigger an IMS registration or deregistration, depending on
667      * whether or not the new value is enabled or disabled.
668      *
669      * Note: If the carrier configuration for advanced calling is not editable or hidden, this
670      * method will do nothing and will instead always use the default value.
671      *
672      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
673      * @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
674      * @see android.telephony.CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL
675      * @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
676      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
677      * @see #isAdvancedCallingSettingEnabled()
678      * @throws IllegalArgumentException if the subscription associated with this operation is not
679      * active (SIM is not inserted, ESIM inactive) or invalid.
680      * @hide
681      */
682     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
683     @SystemApi @TestApi
setAdvancedCallingSettingEnabled(boolean isEnabled)684     public void setAdvancedCallingSettingEnabled(boolean isEnabled) {
685         ITelephony iTelephony = getITelephony();
686         if (iTelephony == null) {
687             throw new RuntimeException("Could not find Telephony Service.");
688         }
689 
690         try {
691             iTelephony.setAdvancedCallingSettingEnabled(mSubId, isEnabled);
692         } catch (ServiceSpecificException e) {
693             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
694                 // Rethrow as runtime error to keep API compatible.
695                 throw new IllegalArgumentException(e.getMessage());
696             } else {
697                 throw new RuntimeException(e.getMessage());
698             }
699         } catch (RemoteException e) {
700             throw e.rethrowAsRuntimeException();
701         }
702     }
703 
704     /**
705      * Query the IMS MmTel capability for a given registration technology. This does not
706      * necessarily mean that we are registered and the capability is available, but rather the
707      * subscription is capable of this service over IMS.
708      *
709      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
710      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VT_AVAILABLE_BOOL
711      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_IMS_GBA_REQUIRED_BOOL
712      * @see #isAvailable(int, int)
713      *
714      * @param imsRegTech The IMS registration technology, can be one of the following:
715      *         {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE},
716      *         {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
717      * @param capability The IMS MmTel capability to query, can be one of the following:
718      *         {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
719      *         {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
720      *         {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT},
721      *         {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
722      * @return {@code true} if the MmTel IMS capability is capable for this subscription, false
723      *         otherwise.
724      * @hide
725      */
726     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
727     @SystemApi @TestApi
isCapable(@mTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech)728     public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
729             @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
730         ITelephony iTelephony = getITelephony();
731         if (iTelephony == null) {
732             throw new RuntimeException("Could not find Telephony Service.");
733         }
734 
735         try {
736             return iTelephony.isCapable(mSubId, capability, imsRegTech);
737         } catch (RemoteException e) {
738             throw e.rethrowAsRuntimeException();
739         }
740     }
741 
742     /**
743      * Query the availability of an IMS MmTel capability for a given registration technology. If
744      * a capability is available, IMS is registered and the service is currently available over IMS.
745      *
746      * @see #isCapable(int, int)
747      *
748      * @param imsRegTech The IMS registration technology, can be one of the following:
749      *         {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE},
750      *         {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
751      * @param capability The IMS MmTel capability to query, can be one of the following:
752      *         {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
753      *         {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
754      *         {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT},
755      *         {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
756      * @return {@code true} if the MmTel IMS capability is available for this subscription, false
757      *         otherwise.
758      * @hide
759      */
760     @SystemApi @TestApi
761     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
isAvailable(@mTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech)762     public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
763             @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
764         ITelephony iTelephony = getITelephony();
765         if (iTelephony == null) {
766             throw new RuntimeException("Could not find Telephony Service.");
767         }
768 
769         try {
770             return iTelephony.isAvailable(mSubId, capability, imsRegTech);
771         } catch (RemoteException e) {
772             throw e.rethrowAsRuntimeException();
773         }
774     }
775 
776     /**
777      * Query whether or not the requested MmTel capability is supported by the carrier on the
778      * specified network transport.
779      * <p>
780      * This is a configuration option and does not change. The only time this may change is if a
781      * new IMS configuration is loaded when there is a
782      * {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} broadcast for this subscription.
783      * @param capability The capability that is being queried for support on the carrier network.
784      * @param transportType The transport type of the capability to check support for.
785      * @param executor The executor that the callback will be called with.
786      * @param callback A consumer containing a Boolean result specifying whether or not the
787      *                 capability is supported on this carrier network for the transport specified.
788      * @throws ImsException if the subscription is no longer valid or the IMS service is not
789      * available.
790      * @hide
791      */
792     @SystemApi @TestApi
793     @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)794     public void isSupported(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
795             @AccessNetworkConstants.TransportType int transportType,
796             @NonNull @CallbackExecutor Executor executor,
797             @NonNull Consumer<Boolean> callback) throws ImsException {
798         if (callback == null) {
799             throw new IllegalArgumentException("Must include a non-null Consumer.");
800         }
801         if (executor == null) {
802             throw new IllegalArgumentException("Must include a non-null Executor.");
803         }
804 
805         ITelephony iTelephony = getITelephony();
806         if (iTelephony == null) {
807             throw new ImsException("Could not find Telephony Service.",
808                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
809         }
810 
811         try {
812             getITelephony().isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() {
813                 @Override
814                 public void accept(int result) {
815                     executor.execute(() -> callback.accept(result == 1));
816                 }
817             }, capability, transportType);
818         } catch (ServiceSpecificException sse) {
819             throw new ImsException(sse.getMessage(), sse.errorCode);
820         } catch (RemoteException e) {
821             e.rethrowAsRuntimeException();
822         }
823     }
824 
825     /**
826      * The user's setting for whether or not they have enabled the "Video Calling" setting.
827      *
828      * <p>
829      * Note: If the carrier configuration for advanced calling is not editable or hidden, this
830      * method will always return the default value.
831      * <p>This API requires one of the following:
832      * <ul>
833      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
834      *     <li>If the caller is the device or profile owner, the caller holds the
835      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
836      *     <li>The caller has carrier privileges (see
837      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
838      *     active subscription.</li>
839      *     <li>The caller is the default SMS app for the device.</li>
840      * </ul>
841      * <p>The profile owner is an app that owns a managed profile on the device; for more details
842      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
843      * Access by profile owners is deprecated and will be removed in a future release.
844      *
845      * @throws IllegalArgumentException if the subscription associated with this operation is not
846      * active (SIM is not inserted, ESIM inactive) or invalid.
847      * @return true if the user’s “Video Calling” setting is currently enabled.
848      */
849     @RequiresPermission(anyOf = {
850             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
851             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
852     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
isVtSettingEnabled()853     public boolean isVtSettingEnabled() {
854         ITelephony iTelephony = getITelephony();
855         if (iTelephony == null) {
856             throw new RuntimeException("Could not find Telephony Service.");
857         }
858 
859         try {
860             return iTelephony.isVtSettingEnabled(mSubId);
861         } catch (ServiceSpecificException e) {
862             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
863                 // Rethrow as runtime error to keep API compatible.
864                 throw new IllegalArgumentException(e.getMessage());
865             } else {
866                 throw new RuntimeException(e.getMessage());
867             }
868         } catch (RemoteException e) {
869             throw e.rethrowAsRuntimeException();
870         }
871     }
872 
873     /**
874      * Change the user's setting for Video Telephony and enable the Video Telephony capability.
875      *
876      * @throws IllegalArgumentException if the subscription associated with this operation is not
877      * active (SIM is not inserted, ESIM inactive) or invalid.
878      * @see #isVtSettingEnabled()
879      * @hide
880      */
881     @SystemApi @TestApi
882     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVtSettingEnabled(boolean isEnabled)883     public void setVtSettingEnabled(boolean isEnabled) {
884         ITelephony iTelephony = getITelephony();
885         if (iTelephony == null) {
886             throw new RuntimeException("Could not find Telephony Service.");
887         }
888 
889         try {
890             iTelephony.setVtSettingEnabled(mSubId, isEnabled);
891         } catch (ServiceSpecificException e) {
892             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
893                 // Rethrow as runtime error to keep API compatible.
894                 throw new IllegalArgumentException(e.getMessage());
895             } else {
896                 throw new RuntimeException(e.getMessage());
897             }
898         } catch (RemoteException e) {
899             throw e.rethrowAsRuntimeException();
900         }
901     }
902 
903     /**
904      * @return true if the user's setting for Voice over WiFi is enabled and false if it is not.
905      *
906      * <p>This API requires one of the following:
907      * <ul>
908      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
909      *     <li>If the caller is the device or profile owner, the caller holds the
910      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
911      *     <li>The caller has carrier privileges (see
912      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
913      *     active subscription.</li>
914      *     <li>The caller is the default SMS app for the device.</li>
915      * </ul>
916      * <p>The profile owner is an app that owns a managed profile on the device; for more details
917      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
918      * Access by profile owners is deprecated and will be removed in a future release.
919      *
920      * @throws IllegalArgumentException if the subscription associated with this operation is not
921      * active (SIM is not inserted, ESIM inactive) or invalid.
922      */
923     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
924     @RequiresPermission(anyOf = {
925             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
926             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
isVoWiFiSettingEnabled()927     public boolean isVoWiFiSettingEnabled() {
928         ITelephony iTelephony = getITelephony();
929         if (iTelephony == null) {
930             throw new RuntimeException("Could not find Telephony Service.");
931         }
932 
933         try {
934             return iTelephony.isVoWiFiSettingEnabled(mSubId);
935         } catch (ServiceSpecificException e) {
936             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
937                 // Rethrow as runtime error to keep API compatible.
938                 throw new IllegalArgumentException(e.getMessage());
939             } else {
940                 throw new RuntimeException(e.getMessage());
941             }
942         } catch (RemoteException e) {
943             throw e.rethrowAsRuntimeException();
944         }
945     }
946 
947     /**
948      * Sets the user's setting for whether or not Voice over WiFi is enabled.
949      *
950      * @throws IllegalArgumentException if the subscription associated with this operation is not
951      * active (SIM is not inserted, ESIM inactive) or invalid.
952      * @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise=
953      * @see #isVoWiFiSettingEnabled()
954      * @hide
955      */
956     @SystemApi @TestApi
957     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVoWiFiSettingEnabled(boolean isEnabled)958     public void setVoWiFiSettingEnabled(boolean isEnabled) {
959         ITelephony iTelephony = getITelephony();
960         if (iTelephony == null) {
961             throw new RuntimeException("Could not find Telephony Service.");
962         }
963 
964         try {
965             iTelephony.setVoWiFiSettingEnabled(mSubId, isEnabled);
966         } catch (ServiceSpecificException e) {
967             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
968                 // Rethrow as runtime error to keep API compatible.
969                 throw new IllegalArgumentException(e.getMessage());
970             } else {
971                 throw new RuntimeException(e.getMessage());
972             }
973         } catch (RemoteException e) {
974             throw e.rethrowAsRuntimeException();
975         }
976     }
977 
978     /**
979      * Returns the user's voice over WiFi roaming setting associated with the current subscription.
980      *
981      * <p>This API requires one of the following:
982      * <ul>
983      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
984      *     <li>If the caller is the device or profile owner, the caller holds the
985      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
986      *     <li>The caller has carrier privileges (see
987      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
988      *     active subscription.</li>
989      *     <li>The caller is the default SMS app for the device.</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      * @return true if the user's setting for Voice over WiFi while roaming is enabled, false
998      * if disabled.
999      */
1000     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
1001     @RequiresPermission(anyOf = {
1002             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1003             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
isVoWiFiRoamingSettingEnabled()1004     public boolean isVoWiFiRoamingSettingEnabled() {
1005         ITelephony iTelephony = getITelephony();
1006         if (iTelephony == null) {
1007             throw new RuntimeException("Could not find Telephony Service.");
1008         }
1009 
1010         try {
1011             return iTelephony.isVoWiFiRoamingSettingEnabled(mSubId);
1012         } catch (ServiceSpecificException e) {
1013             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1014                 // Rethrow as runtime error to keep API compatible.
1015                 throw new IllegalArgumentException(e.getMessage());
1016             } else {
1017                 throw new RuntimeException(e.getMessage());
1018             }
1019         } catch (RemoteException e) {
1020             throw e.rethrowAsRuntimeException();
1021         }
1022     }
1023 
1024     /**
1025      * Change the user's setting for Voice over WiFi while roaming.
1026      *
1027      * @param isEnabled true if the user's setting for Voice over WiFi while roaming is enabled,
1028      *     false otherwise.
1029      * @throws IllegalArgumentException if the subscription associated with this operation is not
1030      * active (SIM is not inserted, ESIM inactive) or invalid.
1031      * @see #isVoWiFiRoamingSettingEnabled()
1032      * @hide
1033      */
1034     @SystemApi @TestApi
1035     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVoWiFiRoamingSettingEnabled(boolean isEnabled)1036     public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) {
1037         ITelephony iTelephony = getITelephony();
1038         if (iTelephony == null) {
1039             throw new RuntimeException("Could not find Telephony Service.");
1040         }
1041 
1042         try {
1043             iTelephony.setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
1044         } catch (ServiceSpecificException e) {
1045             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1046                 // Rethrow as runtime error to keep API compatible.
1047                 throw new IllegalArgumentException(e.getMessage());
1048             } else {
1049                 throw new RuntimeException(e.getMessage());
1050             }
1051         } catch (RemoteException e) {
1052             throw e.rethrowAsRuntimeException();
1053         }
1054     }
1055 
1056     /**
1057      * Overrides the Voice over WiFi capability to true for IMS, but do not persist the setting.
1058      * Typically used during the Voice over WiFi registration process for some carriers.
1059      *
1060      * @param isCapable true if the IMS stack should try to register for IMS over IWLAN, false
1061      *     otherwise.
1062      * @param mode the Voice over WiFi mode preference to set, which can be one of the following:
1063      * - {@link #WIFI_MODE_WIFI_ONLY}
1064      * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
1065      * - {@link #WIFI_MODE_WIFI_PREFERRED}
1066      * @throws IllegalArgumentException if the subscription associated with this operation is not
1067      * active (SIM is not inserted, ESIM inactive) or invalid.
1068      * @see #setVoWiFiSettingEnabled(boolean)
1069      * @hide
1070      */
1071     @SystemApi @TestApi
1072     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVoWiFiNonPersistent(boolean isCapable, int mode)1073     public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
1074         ITelephony iTelephony = getITelephony();
1075         if (iTelephony == null) {
1076             throw new RuntimeException("Could not find Telephony Service.");
1077         }
1078 
1079         try {
1080             iTelephony.setVoWiFiNonPersistent(mSubId, isCapable, mode);
1081         } catch (ServiceSpecificException e) {
1082             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1083                 // Rethrow as runtime error to keep API compatible.
1084                 throw new IllegalArgumentException(e.getMessage());
1085             } else {
1086                 throw new RuntimeException(e.getMessage());
1087             }
1088         } catch (RemoteException e) {
1089             throw e.rethrowAsRuntimeException();
1090         }
1091     }
1092 
1093     /**
1094      * Returns the user's voice over WiFi Roaming mode setting associated with the device.
1095      *
1096      * <p>This API requires one of the following:
1097      * <ul>
1098      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
1099      *     <li>If the caller is the device or profile owner, the caller holds the
1100      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
1101      *     <li>The caller has carrier privileges (see
1102      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
1103      *     active subscription.</li>
1104      *     <li>The caller is the default SMS app for the device.</li>
1105      * </ul>
1106      * <p>The profile owner is an app that owns a managed profile on the device; for more details
1107      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
1108      * Access by profile owners is deprecated and will be removed in a future release.
1109      *
1110      * @throws IllegalArgumentException if the subscription associated with this operation is not
1111      * active (SIM is not inserted, ESIM inactive) or invalid.
1112      * @return The Voice over WiFi Mode preference set by the user, which can be one of the
1113      * following:
1114      * - {@link #WIFI_MODE_WIFI_ONLY}
1115      * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
1116      * - {@link #WIFI_MODE_WIFI_PREFERRED}
1117      */
1118     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
1119     @RequiresPermission(anyOf = {
1120             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1121             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
getVoWiFiModeSetting()1122     public @WiFiCallingMode int getVoWiFiModeSetting() {
1123         ITelephony iTelephony = getITelephony();
1124         if (iTelephony == null) {
1125             throw new RuntimeException("Could not find Telephony Service.");
1126         }
1127 
1128         try {
1129             return iTelephony.getVoWiFiModeSetting(mSubId);
1130         } catch (ServiceSpecificException e) {
1131             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1132                 // Rethrow as runtime error to keep API compatible.
1133                 throw new IllegalArgumentException(e.getMessage());
1134             } else {
1135                 throw new RuntimeException(e.getMessage());
1136             }
1137         } catch (RemoteException e) {
1138             throw e.rethrowAsRuntimeException();
1139         }
1140     }
1141 
1142     /**
1143      * Set the user's preference for Voice over WiFi calling mode.
1144      * @param mode The user's preference for the technology to register for IMS over, can be one of
1145      *    the following:
1146      * - {@link #WIFI_MODE_WIFI_ONLY}
1147      * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
1148      * - {@link #WIFI_MODE_WIFI_PREFERRED}
1149      * @throws IllegalArgumentException if the subscription associated with this operation is not
1150      * active (SIM is not inserted, ESIM inactive) or invalid.
1151      * @see #getVoWiFiModeSetting()
1152      * @hide
1153      */
1154     @SystemApi @TestApi
1155     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVoWiFiModeSetting(@iFiCallingMode int mode)1156     public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
1157         ITelephony iTelephony = getITelephony();
1158         if (iTelephony == null) {
1159             throw new RuntimeException("Could not find Telephony Service.");
1160         }
1161 
1162         try {
1163             iTelephony.setVoWiFiModeSetting(mSubId, mode);
1164         } catch (ServiceSpecificException e) {
1165             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1166                 // Rethrow as runtime error to keep API compatible.
1167                 throw new IllegalArgumentException(e.getMessage());
1168             } else {
1169                 throw new RuntimeException(e.getMessage());
1170             }
1171         } catch (RemoteException e) {
1172             throw e.rethrowAsRuntimeException();
1173         }
1174     }
1175 
1176     /**
1177      * Set the user's preference for Voice over WiFi calling mode while the device is roaming on
1178      * another network.
1179      *
1180      * @return The user's preference for the technology to register for IMS over when roaming on
1181      *     another network, can be one of the following:
1182      *     - {@link #WIFI_MODE_WIFI_ONLY}
1183      *     - {@link #WIFI_MODE_CELLULAR_PREFERRED}
1184      *     - {@link #WIFI_MODE_WIFI_PREFERRED}
1185      * @throws IllegalArgumentException if the subscription associated with this operation is not
1186      * active (SIM is not inserted, ESIM inactive) or invalid.
1187      * @see #setVoWiFiRoamingSettingEnabled(boolean)
1188      * @hide
1189      */
1190     @SystemApi @TestApi
1191     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
getVoWiFiRoamingModeSetting()1192     public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
1193         ITelephony iTelephony = getITelephony();
1194         if (iTelephony == null) {
1195             throw new RuntimeException("Could not find Telephony Service.");
1196         }
1197 
1198         try {
1199             return iTelephony.getVoWiFiRoamingModeSetting(mSubId);
1200         } catch (ServiceSpecificException e) {
1201             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1202                 // Rethrow as runtime error to keep API compatible.
1203                 throw new IllegalArgumentException(e.getMessage());
1204             } else {
1205                 throw new RuntimeException(e.getMessage());
1206             }
1207         } catch (RemoteException e) {
1208             throw e.rethrowAsRuntimeException();
1209         }
1210     }
1211 
1212     /**
1213      * Set the user's preference for Voice over WiFi mode while the device is roaming on another
1214      * network.
1215      *
1216      * @param mode The user's preference for the technology to register for IMS over when roaming on
1217      *     another network, can be one of the following:
1218      *     - {@link #WIFI_MODE_WIFI_ONLY}
1219      *     - {@link #WIFI_MODE_CELLULAR_PREFERRED}
1220      *     - {@link #WIFI_MODE_WIFI_PREFERRED}
1221      * @throws IllegalArgumentException if the subscription associated with this operation is not
1222      * active (SIM is not inserted, ESIM inactive) or invalid.
1223      * @see #getVoWiFiRoamingModeSetting()
1224      * @hide
1225      */
1226     @SystemApi @TestApi
1227     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setVoWiFiRoamingModeSetting(@iFiCallingMode int mode)1228     public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
1229         ITelephony iTelephony = getITelephony();
1230         if (iTelephony == null) {
1231             throw new RuntimeException("Could not find Telephony Service.");
1232         }
1233 
1234         try {
1235             iTelephony.setVoWiFiRoamingModeSetting(mSubId, mode);
1236         } catch (ServiceSpecificException e) {
1237             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1238                 // Rethrow as runtime error to keep API compatible.
1239                 throw new IllegalArgumentException(e.getMessage());
1240             } else {
1241                 throw new RuntimeException(e.getMessage());
1242             }
1243         } catch (RemoteException e) {
1244             throw e.rethrowAsRuntimeException();
1245         }
1246     }
1247 
1248     /**
1249      * Sets the capability of RTT for IMS calls placed on this subscription.
1250      *
1251      * Note: This does not affect the value of
1252      * {@link android.provider.Settings.Secure#RTT_CALLING_MODE}, which is the global user setting
1253      * for RTT. That value is enabled/disabled separately by the user through the Accessibility
1254      * settings.
1255      * @throws IllegalArgumentException if the subscription associated with this operation is not
1256      * active (SIM is not inserted, ESIM inactive) or invalid.
1257      * @param isEnabled if true RTT should be enabled during calls made on this subscription.
1258      * @hide
1259      */
1260     @SystemApi @TestApi
1261     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setRttCapabilitySetting(boolean isEnabled)1262     public void setRttCapabilitySetting(boolean isEnabled) {
1263         ITelephony iTelephony = getITelephony();
1264         if (iTelephony == null) {
1265             throw new RuntimeException("Could not find Telephony Service.");
1266         }
1267 
1268         try {
1269             iTelephony.setRttCapabilitySetting(mSubId, isEnabled);
1270         } catch (ServiceSpecificException e) {
1271             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1272                 // Rethrow as runtime error to keep API compatible.
1273                 throw new IllegalArgumentException(e.getMessage());
1274             } else {
1275                 throw new RuntimeException(e.getMessage());
1276             }
1277         } catch (RemoteException e) {
1278             throw e.rethrowAsRuntimeException();
1279         }
1280     }
1281 
1282     /**
1283      * @return true if TTY over VoLTE is supported
1284      *
1285      * <p>This API requires one of the following:
1286      * <ul>
1287      *     <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
1288      *     <li>If the caller is the device or profile owner, the caller holds the
1289      *     {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
1290      *     <li>The caller has carrier privileges (see
1291      *     {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
1292      *     active subscription.</li>
1293      *     <li>The caller is the default SMS app for the device.</li>
1294      * </ul>
1295      * <p>The profile owner is an app that owns a managed profile on the device; for more details
1296      * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
1297      * Access by profile owners is deprecated and will be removed in a future release.
1298      *
1299      * @throws IllegalArgumentException if the subscription associated with this operation is not
1300      * active (SIM is not inserted, ESIM inactive) or invalid.
1301      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
1302      */
1303     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
1304     @RequiresPermission(anyOf = {
1305             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1306             android.Manifest.permission.READ_PRECISE_PHONE_STATE})
isTtyOverVolteEnabled()1307     public boolean isTtyOverVolteEnabled() {
1308         ITelephony iTelephony = getITelephony();
1309         if (iTelephony == null) {
1310             throw new RuntimeException("Could not find Telephony Service.");
1311         }
1312 
1313         try {
1314             return iTelephony.isTtyOverVolteEnabled(mSubId);
1315         } catch (ServiceSpecificException e) {
1316             if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
1317                 // Rethrow as runtime error to keep API compatible.
1318                 throw new IllegalArgumentException(e.getMessage());
1319             } else {
1320                 throw new RuntimeException(e.getMessage());
1321             }
1322         } catch (RemoteException e) {
1323             throw e.rethrowAsRuntimeException();
1324         }
1325     }
1326 
1327     /**
1328      * Get the status of the MmTel Feature registered on this subscription.
1329      * @param executor The executor that will be used to call the callback.
1330      * @param callback A callback containing an Integer describing the current state of the
1331      *                 MmTel feature, Which will be one of the following:
1332      *                 {@link ImsFeature#STATE_UNAVAILABLE},
1333      *                {@link ImsFeature#STATE_INITIALIZING},
1334      *                {@link ImsFeature#STATE_READY}. Will be called using the executor
1335      *                 specified when the service state has been retrieved from the IMS service.
1336      * @throws ImsException if the IMS service associated with this subscription is not available or
1337      * the IMS service is not available.
1338      * @hide
1339      */
1340     @SystemApi @TestApi
1341     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
getFeatureState(@onNull @allbackExecutor Executor executor, @NonNull @ImsFeature.ImsState Consumer<Integer> callback)1342     public void getFeatureState(@NonNull @CallbackExecutor Executor executor,
1343             @NonNull @ImsFeature.ImsState Consumer<Integer> callback) throws ImsException {
1344         if (executor == null) {
1345             throw new IllegalArgumentException("Must include a non-null Executor.");
1346         }
1347         if (callback == null) {
1348             throw new IllegalArgumentException("Must include a non-null Consumer.");
1349         }
1350 
1351         ITelephony iTelephony = getITelephony();
1352         if (iTelephony == null) {
1353             throw new ImsException("Could not find Telephony Service.",
1354                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
1355         }
1356 
1357         try {
1358             iTelephony.getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
1359                 @Override
1360                 public void accept(int result) {
1361                     executor.execute(() -> callback.accept(result));
1362                 }
1363             });
1364         } catch (ServiceSpecificException sse) {
1365             throw new ImsException(sse.getMessage(), sse.errorCode);
1366         } catch (RemoteException e) {
1367             e.rethrowAsRuntimeException();
1368         }
1369     }
1370 
getITelephony()1371     private static ITelephony getITelephony() {
1372         ITelephony binder = ITelephony.Stub.asInterface(
1373                 TelephonyFrameworkInitializer
1374                         .getTelephonyServiceManager()
1375                         .getTelephonyServiceRegisterer()
1376                         .get());
1377         return binder;
1378     }
1379 }
1380