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