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