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