1 /* 2 * Copyright (C) 2017 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 import android.annotation.LongDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SuppressLint; 23 import android.annotation.SystemApi; 24 import android.app.Service; 25 import android.content.Intent; 26 import android.os.IBinder; 27 import android.os.RemoteException; 28 import android.telephony.CarrierConfigManager; 29 import android.telephony.ims.aidl.IImsConfig; 30 import android.telephony.ims.aidl.IImsMmTelFeature; 31 import android.telephony.ims.aidl.IImsRcsFeature; 32 import android.telephony.ims.aidl.IImsRegistration; 33 import android.telephony.ims.aidl.IImsServiceController; 34 import android.telephony.ims.aidl.IImsServiceControllerListener; 35 import android.telephony.ims.aidl.ISipTransport; 36 import android.telephony.ims.feature.ImsFeature; 37 import android.telephony.ims.feature.MmTelFeature; 38 import android.telephony.ims.feature.RcsFeature; 39 import android.telephony.ims.stub.ImsConfigImplBase; 40 import android.telephony.ims.stub.ImsFeatureConfiguration; 41 import android.telephony.ims.stub.ImsRegistrationImplBase; 42 import android.telephony.ims.stub.SipTransportImplBase; 43 import android.util.Log; 44 import android.util.SparseArray; 45 import android.util.SparseBooleanArray; 46 47 import com.android.ims.internal.IImsFeatureStatusCallback; 48 import com.android.internal.annotations.VisibleForTesting; 49 import com.android.internal.telephony.util.TelephonyUtils; 50 51 import java.lang.annotation.Retention; 52 import java.lang.annotation.RetentionPolicy; 53 import java.util.HashMap; 54 import java.util.Map; 55 import java.util.concurrent.CancellationException; 56 import java.util.concurrent.CompletableFuture; 57 import java.util.concurrent.CompletionException; 58 import java.util.concurrent.ExecutionException; 59 import java.util.concurrent.Executor; 60 import java.util.function.Supplier; 61 62 /** 63 * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend 64 * ImsService must register the service in their AndroidManifest to be detected by the framework. 65 * First, the application must declare that they use the "android.permission.BIND_IMS_SERVICE" 66 * permission. Then, the ImsService definition in the manifest must follow the following format: 67 * 68 * ... 69 * <service android:name=".EgImsService" 70 * android:permission="android.permission.BIND_IMS_SERVICE" > 71 * ... 72 * <intent-filter> 73 * <action android:name="android.telephony.ims.ImsService" /> 74 * </intent-filter> 75 * </service> 76 * ... 77 * 78 * The telephony framework will then bind to the ImsService you have defined in your manifest 79 * if you are either: 80 * 1) Defined as the default ImsService for the device in the device overlay using 81 * "config_ims_mmtel_package" or "config_ims_rcs_package". 82 * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using 83 * {@link CarrierConfigManager#KEY_CONFIG_IMS_MMTEL_PACKAGE_OVERRIDE_STRING} or 84 * {@link CarrierConfigManager#KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING}. 85 * 86 * There are two ways to define to the platform which {@link ImsFeature}s this {@link ImsService} 87 * supports, dynamic or static definitions. 88 * 89 * In the static definition, the {@link ImsFeature}s that are supported are defined in the service 90 * definition of the AndroidManifest.xml file as metadata: 91 * <!-- Apps must declare which features they support as metadata. The different categories are 92 * defined below. In this example, the MMTEL_FEATURE feature is supported. --> 93 * <meta-data android:name="android.telephony.ims.MMTEL_FEATURE" android:value="true" /> 94 * 95 * The features that are currently supported in an ImsService are: 96 * - RCS_FEATURE: This ImsService implements the RcsFeature class. 97 * - MMTEL_FEATURE: This ImsService implements the MmTelFeature class. 98 * - EMERGENCY_MMTEL_FEATURE: This ImsService supports Emergency Calling for MMTEL, must be 99 * declared along with the MMTEL_FEATURE. If this is not specified, the framework will use 100 * circuit switch for emergency calling. 101 * 102 * In the dynamic definition, the supported features are not specified in the service definition 103 * of the AndroidManifest. Instead, the framework binds to this service and calls 104 * {@link #querySupportedImsFeatures()}. The {@link ImsService} then returns an 105 * {@link ImsFeatureConfiguration}, which the framework uses to initialize the supported 106 * {@link ImsFeature}s. If at any time, the list of supported {@link ImsFeature}s changes, 107 * {@link #onUpdateSupportedImsFeatures(ImsFeatureConfiguration)} can be called to tell the 108 * framework of the changes. 109 * 110 * @hide 111 */ 112 @SystemApi 113 public class ImsService extends Service { 114 115 private static final String LOG_TAG = "ImsService"; 116 117 /** 118 * This ImsService supports the capability to place emergency calls over MMTEL. 119 * <p> 120 * Note: This should never be set by {@link #getImsServiceCapabilities()}, as whether it is 121 * there or not depends on whether or not {@link ImsFeature#FEATURE_EMERGENCY_MMTEL} is defined 122 * for this ImsService. If it is set, it will be removed during sanitization before the final 123 * capabilities bitfield is sent back to the framework. 124 * @hide This is encoded into the {@link ImsFeature#FEATURE_EMERGENCY_MMTEL}, but we will be 125 * adding other capabilities in a central location, so track this capability here as well. 126 */ 127 public static final long CAPABILITY_EMERGENCY_OVER_MMTEL = 1 << 0; 128 129 /** 130 * This ImsService supports the capability to create SIP delegates for other IMS applications 131 * to use to proxy SIP messaging traffic through it. 132 * <p> 133 * In order for the framework to report SipDelegate creation as being available for this 134 * ImsService implementation, this ImsService must report this capability flag in 135 * {@link #getImsServiceCapabilities()}, {@link #getSipTransport(int)} must not return null, and 136 * this ImsService MUST report the ability to create both {@link ImsFeature#FEATURE_MMTEL} and 137 * {@link ImsFeature#FEATURE_RCS} features. 138 */ 139 public static final long CAPABILITY_SIP_DELEGATE_CREATION = 1 << 1; 140 141 /** 142 * Used for internal correctness checks of capabilities set by the ImsService implementation and 143 * tracks the index of the largest defined flag in the capabilities long. 144 * @hide 145 */ 146 public static final long CAPABILITY_MAX_INDEX = 147 Long.numberOfTrailingZeros(CAPABILITY_SIP_DELEGATE_CREATION); 148 149 /** 150 * @hide 151 */ 152 @LongDef(flag = true, 153 prefix = "CAPABILITY_", 154 value = { 155 // CAPABILITY_EMERGENCY_OVER_MMTEL is not included here because it is managed by 156 // whether or not ImsFeature.FEATURE_EMERGENCY_MMTEL feature is set and should 157 // not be set by users of ImsService. 158 CAPABILITY_SIP_DELEGATE_CREATION 159 }) 160 @Retention(RetentionPolicy.SOURCE) 161 public @interface ImsServiceCapability {} 162 163 /** 164 * Used for logging purposes, see {@link #getCapabilitiesString(long)} 165 * @hide 166 */ 167 private static final Map<Long, String> CAPABILITIES_LOG_MAP = new HashMap<Long, String>() {{ 168 put(CAPABILITY_EMERGENCY_OVER_MMTEL, "EMERGENCY_OVER_MMTEL"); 169 put(CAPABILITY_SIP_DELEGATE_CREATION, "SIP_DELEGATE_CREATION"); 170 }}; 171 172 /** 173 * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService. 174 * @hide 175 */ 176 public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService"; 177 178 // A map of slot Id -> map of features (indexed by ImsFeature feature id) corresponding to that 179 // slot. 180 // We keep track of this to facilitate cleanup of the IImsFeatureStatusCallback and 181 // call ImsFeature#onFeatureRemoved. 182 private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>(); 183 184 // A map of slot id -> boolean array, where each entry in the boolean array corresponds to an 185 // ImsFeature that was created for a slot id and not a sub id for backwards compatibility 186 // purposes. 187 private final SparseArray<SparseBooleanArray> mCreateImsFeatureWithSlotIdFlagMap = 188 new SparseArray<>(); 189 190 private IImsServiceControllerListener mListener; 191 private Executor mExecutor; 192 193 /** 194 * Create a new ImsService. 195 * <p> 196 * Method stubs called from the framework will be called asynchronously. Vendor specifies the 197 * {@link Executor} that the methods stubs will be called. If mExecutor is set to null by 198 * vendor use Runnable::run. 199 */ ImsService()200 public ImsService() { 201 mExecutor = ImsService.this.getExecutor(); 202 if (mExecutor == null) { 203 mExecutor = Runnable::run; 204 } 205 } 206 207 /** 208 * Listener that notifies the framework of ImsService changes. 209 * @hide 210 */ 211 public static class Listener extends IImsServiceControllerListener.Stub { 212 /** 213 * The IMS features that this ImsService supports has changed. 214 * @param c a new {@link ImsFeatureConfiguration} containing {@link ImsFeature.FeatureType}s 215 * that this ImsService supports. This may trigger the addition/removal of feature 216 * in this service. 217 */ onUpdateSupportedImsFeatures(ImsFeatureConfiguration c)218 public void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) { 219 } 220 } 221 222 /** 223 * @hide 224 */ 225 protected final IBinder mImsServiceController = new IImsServiceController.Stub() { 226 @Override 227 public void setListener(IImsServiceControllerListener l) { 228 mListener = l; 229 } 230 231 @Override 232 public IImsMmTelFeature createMmTelFeature(int slotId, int subId) { 233 MmTelFeature f = (MmTelFeature) getImsFeature(slotId, ImsFeature.FEATURE_MMTEL); 234 if (f == null) { 235 return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId, subId), 236 "createMmTelFeature"); 237 } else { 238 return f.getBinder(); 239 } 240 } 241 242 @Override 243 public IImsMmTelFeature createEmergencyOnlyMmTelFeature(int slotId) { 244 MmTelFeature f = (MmTelFeature) getImsFeature(slotId, ImsFeature.FEATURE_MMTEL); 245 if (f == null) { 246 return executeMethodAsyncForResult(() -> createEmergencyOnlyMmTelFeatureInternal( 247 slotId), "createEmergencyOnlyMmTelFeature"); 248 } else { 249 return f.getBinder(); 250 } 251 } 252 253 @Override 254 public IImsRcsFeature createRcsFeature(int slotId, int subId) { 255 RcsFeature f = (RcsFeature) getImsFeature(slotId, ImsFeature.FEATURE_RCS); 256 if (f == null) { 257 return executeMethodAsyncForResult(() -> 258 createRcsFeatureInternal(slotId, subId), "createRcsFeature"); 259 } else { 260 return f.getBinder(); 261 } 262 } 263 264 @Override 265 public void addFeatureStatusCallback(int slotId, int featureType, 266 IImsFeatureStatusCallback c) { 267 executeMethodAsync(() -> ImsService.this.addImsFeatureStatusCallback( 268 slotId, featureType, c), "addFeatureStatusCallback"); 269 } 270 271 @Override 272 public void removeFeatureStatusCallback(int slotId, int featureType, 273 IImsFeatureStatusCallback c) { 274 executeMethodAsync(() -> ImsService.this.removeImsFeatureStatusCallback( 275 slotId, featureType, c), "removeFeatureStatusCallback"); 276 } 277 278 @Override 279 public void removeImsFeature(int slotId, int featureType, boolean changeSubId) { 280 if (changeSubId && isImsFeatureCreatedForSlot(slotId, featureType)) { 281 Log.w(LOG_TAG, "Do not remove Ims feature for compatibility"); 282 return; 283 } 284 executeMethodAsync(() -> ImsService.this.removeImsFeature(slotId, featureType), 285 "removeImsFeature"); 286 setImsFeatureCreatedForSlot(slotId, featureType, false); 287 } 288 289 @Override 290 public ImsFeatureConfiguration querySupportedImsFeatures() { 291 return executeMethodAsyncForResult(() -> ImsService.this.querySupportedImsFeatures(), 292 "ImsFeatureConfiguration"); 293 } 294 295 @Override 296 public long getImsServiceCapabilities() { 297 return executeMethodAsyncForResult(() -> { 298 long caps = ImsService.this.getImsServiceCapabilities(); 299 long sanitizedCaps = sanitizeCapabilities(caps); 300 if (caps != sanitizedCaps) { 301 Log.w(LOG_TAG, "removing invalid bits from field: 0x" 302 + Long.toHexString(caps ^ sanitizedCaps)); 303 } 304 return sanitizedCaps; 305 }, "getImsServiceCapabilities"); 306 } 307 308 @Override 309 public void notifyImsServiceReadyForFeatureCreation() { 310 executeMethodAsync(() -> ImsService.this.readyForFeatureCreation(), 311 "notifyImsServiceReadyForFeatureCreation"); 312 } 313 314 @Override 315 public IImsConfig getConfig(int slotId, int subId) { 316 return executeMethodAsyncForResult(() -> { 317 ImsConfigImplBase c = 318 ImsService.this.getConfigForSubscription(slotId, subId); 319 if (c != null) { 320 c.setDefaultExecutor(mExecutor); 321 return c.getIImsConfig(); 322 } else { 323 return null; 324 } 325 }, "getConfig"); 326 } 327 328 @Override 329 public IImsRegistration getRegistration(int slotId, int subId) { 330 return executeMethodAsyncForResult(() -> { 331 ImsRegistrationImplBase r = 332 ImsService.this.getRegistrationForSubscription(slotId, subId); 333 if (r != null) { 334 r.setDefaultExecutor(mExecutor); 335 return r.getBinder(); 336 } else { 337 return null; 338 } 339 }, "getRegistration"); 340 } 341 342 @Override 343 public ISipTransport getSipTransport(int slotId) { 344 return executeMethodAsyncForResult(() -> { 345 SipTransportImplBase s = ImsService.this.getSipTransport(slotId); 346 if (s != null) { 347 s.setDefaultExecutor(mExecutor); 348 return s.getBinder(); 349 } else { 350 return null; 351 } 352 }, "getSipTransport"); 353 } 354 355 @Override 356 public void enableIms(int slotId, int subId) { 357 executeMethodAsync(() -> 358 ImsService.this.enableImsForSubscription(slotId, subId), "enableIms"); 359 } 360 361 @Override 362 public void disableIms(int slotId, int subId) { 363 executeMethodAsync(() -> 364 ImsService.this.disableImsForSubscription(slotId, subId), "disableIms"); 365 } 366 367 // Call the methods with a clean calling identity on the executor and wait indefinitely for 368 // the future to return. 369 private void executeMethodAsync(Runnable r, String errorLogName) { 370 try { 371 CompletableFuture.runAsync( 372 () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); 373 } catch (CancellationException | CompletionException e) { 374 Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: " 375 + e.getMessage()); 376 } 377 } 378 379 private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) { 380 CompletableFuture<T> future = CompletableFuture.supplyAsync( 381 () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); 382 try { 383 return future.get(); 384 } catch (ExecutionException | InterruptedException e) { 385 Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: " 386 + e.getMessage()); 387 return null; 388 } 389 } 390 }; 391 392 /** 393 * @hide 394 */ 395 @Override onBind(Intent intent)396 public IBinder onBind(Intent intent) { 397 if(SERVICE_INTERFACE.equals(intent.getAction())) { 398 Log.i(LOG_TAG, "ImsService Bound."); 399 return mImsServiceController; 400 } 401 return null; 402 } 403 createMmTelFeatureInternal(int slotId, int subscriptionId)404 private IImsMmTelFeature createMmTelFeatureInternal(int slotId, int subscriptionId) { 405 MmTelFeature f = createMmTelFeatureForSubscription(slotId, subscriptionId); 406 if (f != null) { 407 setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL); 408 f.setDefaultExecutor(mExecutor); 409 return f.getBinder(); 410 } else { 411 Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned."); 412 return null; 413 } 414 } 415 createEmergencyOnlyMmTelFeatureInternal(int slotId)416 private IImsMmTelFeature createEmergencyOnlyMmTelFeatureInternal(int slotId) { 417 MmTelFeature f = createEmergencyOnlyMmTelFeature(slotId); 418 if (f != null) { 419 setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL); 420 f.setDefaultExecutor(mExecutor); 421 return f.getBinder(); 422 } else { 423 Log.e(LOG_TAG, "createEmergencyOnlyMmTelFeatureInternal: null feature returned."); 424 return null; 425 } 426 } 427 createRcsFeatureInternal(int slotId, int subI)428 private IImsRcsFeature createRcsFeatureInternal(int slotId, int subI) { 429 RcsFeature f = createRcsFeatureForSubscription(slotId, subI); 430 if (f != null) { 431 f.setDefaultExecutor(mExecutor); 432 setupFeature(f, slotId, ImsFeature.FEATURE_RCS); 433 return f.getBinder(); 434 } else { 435 Log.e(LOG_TAG, "createRcsFeatureInternal: null feature returned."); 436 return null; 437 } 438 } 439 setupFeature(ImsFeature f, int slotId, int featureType)440 private void setupFeature(ImsFeature f, int slotId, int featureType) { 441 f.initialize(this, slotId); 442 addImsFeature(slotId, featureType, f); 443 } 444 addImsFeatureStatusCallback(int slotId, int featureType, IImsFeatureStatusCallback c)445 private void addImsFeatureStatusCallback(int slotId, int featureType, 446 IImsFeatureStatusCallback c) { 447 synchronized (mFeaturesBySlot) { 448 // get ImsFeature associated with the slot/feature 449 SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); 450 if (features == null) { 451 Log.w(LOG_TAG, "Can not add ImsFeatureStatusCallback - no features on slot " 452 + slotId); 453 return; 454 } 455 ImsFeature f = features.get(featureType); 456 if (f != null) { 457 f.addImsFeatureStatusCallback(c); 458 } 459 } 460 } 461 removeImsFeatureStatusCallback(int slotId, int featureType, IImsFeatureStatusCallback c)462 private void removeImsFeatureStatusCallback(int slotId, int featureType, 463 IImsFeatureStatusCallback c) { 464 synchronized (mFeaturesBySlot) { 465 // get ImsFeature associated with the slot/feature 466 SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); 467 if (features == null) { 468 Log.w(LOG_TAG, "Can not remove ImsFeatureStatusCallback - no features on slot " 469 + slotId); 470 return; 471 } 472 ImsFeature f = features.get(featureType); 473 if (f != null) { 474 f.removeImsFeatureStatusCallback(c); 475 } 476 } 477 } 478 addImsFeature(int slotId, int featureType, ImsFeature f)479 private void addImsFeature(int slotId, int featureType, ImsFeature f) { 480 synchronized (mFeaturesBySlot) { 481 // Get SparseArray for Features, by querying slot Id 482 SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); 483 if (features == null) { 484 // Populate new SparseArray of features if it doesn't exist for this slot yet. 485 features = new SparseArray<>(); 486 mFeaturesBySlot.put(slotId, features); 487 } 488 features.put(featureType, f); 489 } 490 } 491 removeImsFeature(int slotId, int featureType)492 private void removeImsFeature(int slotId, int featureType) { 493 synchronized (mFeaturesBySlot) { 494 // get ImsFeature associated with the slot/feature 495 SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); 496 if (features == null) { 497 Log.w(LOG_TAG, "Can not remove ImsFeature. No ImsFeatures exist on slot " 498 + slotId); 499 return; 500 } 501 ImsFeature f = features.get(featureType); 502 if (f == null) { 503 Log.w(LOG_TAG, "Can not remove ImsFeature. No feature with type " 504 + featureType + " exists on slot " + slotId); 505 return; 506 } 507 f.onFeatureRemoved(); 508 features.remove(featureType); 509 } 510 511 } 512 513 /** 514 * @hide 515 */ 516 @VisibleForTesting getImsFeature(int slotId, int featureType)517 public ImsFeature getImsFeature(int slotId, int featureType) { 518 synchronized (mFeaturesBySlot) { 519 // Get SparseArray for Features, by querying slot Id 520 SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); 521 if (features == null) { 522 return null; 523 } 524 return features.get(featureType); 525 } 526 } 527 setImsFeatureCreatedForSlot(int slotId, @ImsFeature.FeatureType int featureType, boolean createdForSlot)528 private void setImsFeatureCreatedForSlot(int slotId, 529 @ImsFeature.FeatureType int featureType, boolean createdForSlot) { 530 synchronized (mCreateImsFeatureWithSlotIdFlagMap) { 531 getImsFeatureCreatedForSlot(slotId).put(featureType, createdForSlot); 532 } 533 } 534 535 /** 536 * @hide 537 */ 538 @VisibleForTesting isImsFeatureCreatedForSlot(int slotId, @ImsFeature.FeatureType int featureType)539 public boolean isImsFeatureCreatedForSlot(int slotId, 540 @ImsFeature.FeatureType int featureType) { 541 synchronized (mCreateImsFeatureWithSlotIdFlagMap) { 542 return getImsFeatureCreatedForSlot(slotId).get(featureType); 543 } 544 } 545 getImsFeatureCreatedForSlot(int slotId)546 private SparseBooleanArray getImsFeatureCreatedForSlot(int slotId) { 547 SparseBooleanArray createFlag = mCreateImsFeatureWithSlotIdFlagMap.get(slotId); 548 if (createFlag == null) { 549 createFlag = new SparseBooleanArray(); 550 mCreateImsFeatureWithSlotIdFlagMap.put(slotId, createFlag); 551 } 552 return createFlag; 553 } 554 555 /** 556 * When called, provide the {@link ImsFeatureConfiguration} that this {@link ImsService} 557 * currently supports. This will trigger the framework to set up the {@link ImsFeature}s that 558 * correspond to the {@link ImsFeature}s configured here. 559 * 560 * Use {@link #onUpdateSupportedImsFeatures(ImsFeatureConfiguration)} to change the supported 561 * {@link ImsFeature}s. 562 * 563 * @return an {@link ImsFeatureConfiguration} containing Features this ImsService supports. 564 */ querySupportedImsFeatures()565 public ImsFeatureConfiguration querySupportedImsFeatures() { 566 // Return empty for base implementation 567 return new ImsFeatureConfiguration(); 568 } 569 570 /** 571 * Updates the framework with a new {@link ImsFeatureConfiguration} containing the updated 572 * features, that this {@link ImsService} supports. This may trigger the framework to add/remove 573 * new ImsFeatures, depending on the configuration. 574 */ onUpdateSupportedImsFeatures(ImsFeatureConfiguration c)575 public final void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) 576 throws RemoteException { 577 if (mListener == null) { 578 throw new IllegalStateException("Framework is not ready"); 579 } 580 mListener.onUpdateSupportedImsFeatures(c); 581 } 582 583 /** 584 * The optional capabilities that this ImsService supports. 585 * <p> 586 * This should be a static configuration and should not change at runtime. 587 * @return The optional static capabilities of this ImsService implementation. 588 */ 589 // ImsService follows a different convention, since it is a stub class. The on* methods are 590 // final and call back into the framework with a state update. 591 @SuppressLint("OnNameExpected") getImsServiceCapabilities()592 public @ImsServiceCapability long getImsServiceCapabilities() { 593 // Stub implementation to be implemented by ImsService. 594 return 0L; 595 } 596 597 /** 598 * The ImsService has been bound and is ready for ImsFeature creation based on the Features that 599 * the ImsService has registered for with the framework, either in the manifest or via 600 * {@link #querySupportedImsFeatures()}. 601 * 602 * The ImsService should use this signal instead of onCreate/onBind or similar to perform 603 * feature initialization because the framework may bind to this service multiple times to 604 * query the ImsService's {@link ImsFeatureConfiguration} via 605 * {@link #querySupportedImsFeatures()}before creating features. 606 */ readyForFeatureCreation()607 public void readyForFeatureCreation() { 608 } 609 610 /** 611 * The framework has enabled IMS for the subscription specified, the ImsService should register 612 * for IMS and perform all appropriate initialization to bring up all ImsFeatures. 613 * 614 * @param slotId The slot ID that IMS will be enabled for. 615 * @param subscriptionId The subscription ID that IMS will be enabled for. 616 */ enableImsForSubscription(int slotId, int subscriptionId)617 public void enableImsForSubscription(int slotId, int subscriptionId) { 618 enableIms(slotId); 619 } 620 621 /** 622 * The framework has disabled IMS for the subscription specified. The ImsService must deregister 623 * for IMS and set capability status to false for all ImsFeatures. 624 * @param slotId The slot ID that IMS will be disabled for. 625 * @param subscriptionId The subscription ID that IMS will be disabled for. 626 */ disableImsForSubscription(int slotId, int subscriptionId)627 public void disableImsForSubscription(int slotId, int subscriptionId) { 628 disableIms(slotId); 629 } 630 631 /** 632 * The framework has enabled IMS for the slot specified, the ImsService should register for IMS 633 * and perform all appropriate initialization to bring up all ImsFeatures. 634 * @deprecated Use {@link #enableImsForSubscription} instead. 635 */ 636 @Deprecated enableIms(int slotId)637 public void enableIms(int slotId) { 638 } 639 640 /** 641 * The framework has disabled IMS for the slot specified. The ImsService must deregister for IMS 642 * and set capability status to false for all ImsFeatures. 643 * @deprecated Use {@link #disableImsForSubscription} instead. 644 */ 645 @Deprecated disableIms(int slotId)646 public void disableIms(int slotId) { 647 } 648 649 /** 650 * When called, the framework is requesting that a new {@link MmTelFeature} is created for the 651 * specified subscription. 652 * 653 * @param subscriptionId The subscription ID that the MMTEL Feature is being created for. 654 * @return The newly created {@link MmTelFeature} associated with the subscription or null if 655 * the feature is not supported. 656 */ createMmTelFeatureForSubscription(int slotId, int subscriptionId)657 public @Nullable MmTelFeature createMmTelFeatureForSubscription(int slotId, 658 int subscriptionId) { 659 setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_MMTEL, true); 660 return createMmTelFeature(slotId); 661 } 662 663 /** 664 * When called, the framework is requesting that a new {@link RcsFeature} is created for the 665 * specified subscription. 666 * 667 * @param subscriptionId The subscription ID that the RCS Feature is being created for. 668 * @return The newly created {@link RcsFeature} associated with the subscription or null if the 669 * feature is not supported. 670 */ createRcsFeatureForSubscription(int slotId, int subscriptionId)671 public @Nullable RcsFeature createRcsFeatureForSubscription(int slotId, int subscriptionId) { 672 setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_RCS, true); 673 return createRcsFeature(slotId); 674 } 675 676 /** 677 * When called, the framework is requesting that a new emergency-only {@link MmTelFeature} is 678 * created for the specified slot. For emergency calls, there is no known Subscription Id. 679 * 680 * @param slotId The slot ID that the MMTEL Feature is being created for. 681 * @return An MmTelFeature instance to be used for the slot ID when there is not 682 * subscription inserted. Only requested when there is no subscription active on 683 * the specified slot. 684 */ createEmergencyOnlyMmTelFeature(int slotId)685 public @Nullable MmTelFeature createEmergencyOnlyMmTelFeature(int slotId) { 686 setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_MMTEL, true); 687 return createMmTelFeature(slotId); 688 } 689 690 /** 691 * When called, the framework is requesting that a new {@link MmTelFeature} is created for the 692 * specified slot. 693 * @deprecated Use {@link #createMmTelFeatureForSubscription} instead 694 * 695 * @param slotId The slot ID that the MMTEL Feature is being created for. 696 * @return The newly created {@link MmTelFeature} associated with the slot or null if the 697 * feature is not supported. 698 */ 699 @Deprecated createMmTelFeature(int slotId)700 public MmTelFeature createMmTelFeature(int slotId) { 701 return null; 702 } 703 704 /** 705 * When called, the framework is requesting that a new {@link RcsFeature} is created for the 706 * specified slot. 707 * @deprecated Use {@link #createRcsFeatureForSubscription} instead 708 * 709 * @param slotId The slot ID that the RCS Feature is being created for. 710 * @return The newly created {@link RcsFeature} associated with the slot or null if the feature 711 * is not supported. 712 */ 713 @Deprecated createRcsFeature(int slotId)714 public RcsFeature createRcsFeature(int slotId) { 715 return null; 716 } 717 718 /** 719 * Return the {@link ImsConfigImplBase} implementation associated with the provided 720 * subscription. This will be used by the platform to get/set specific IMS related 721 * configurations. 722 * 723 * @param subscriptionId The subscription ID that the IMS configuration is associated with. 724 * @return ImsConfig implementation that is associated with the specified subscription. 725 */ getConfigForSubscription(int slotId, int subscriptionId)726 public @NonNull ImsConfigImplBase getConfigForSubscription(int slotId, int subscriptionId) { 727 return getConfig(slotId); 728 } 729 730 /** 731 * Return the {@link ImsRegistrationImplBase} implementation associated with the provided 732 * subscription. 733 * 734 * @param subscriptionId The subscription ID that is associated with the IMS Registration. 735 * @return the ImsRegistration implementation associated with the subscription. 736 */ getRegistrationForSubscription(int slotId, int subscriptionId)737 public @NonNull ImsRegistrationImplBase getRegistrationForSubscription(int slotId, 738 int subscriptionId) { 739 return getRegistration(slotId); 740 } 741 742 /** 743 * Return the {@link ImsConfigImplBase} implementation associated with the provided slot. This 744 * will be used by the platform to get/set specific IMS related configurations. 745 * @deprecated use {@link #getConfigForSubscription} instead. 746 * 747 * @param slotId The slot that the IMS configuration is associated with. 748 * @return ImsConfig implementation that is associated with the specified slot. 749 */ 750 @Deprecated getConfig(int slotId)751 public ImsConfigImplBase getConfig(int slotId) { 752 return new ImsConfigImplBase(); 753 } 754 755 /** 756 * Return the {@link ImsRegistrationImplBase} implementation associated with the provided slot. 757 * @deprecated use {@link #getRegistrationForSubscription} instead. 758 * 759 * @param slotId The slot that is associated with the IMS Registration. 760 * @return the ImsRegistration implementation associated with the slot. 761 */ 762 @Deprecated getRegistration(int slotId)763 public ImsRegistrationImplBase getRegistration(int slotId) { 764 return new ImsRegistrationImplBase(); 765 } 766 767 /** 768 * Return the {@link SipTransportImplBase} implementation associated with the provided slot. 769 * <p> 770 * This is an optional interface used for devices that must support IMS single registration and 771 * proxy SIP traffic to remote IMS applications. If this is not supported for this IMS service, 772 * this method should return {@code null}. If this feature is supported, then this method must 773 * never be {@code null} and the optional ImsService capability flag 774 * {@link #CAPABILITY_SIP_DELEGATE_CREATION} must be set in 775 * {@link #getImsServiceCapabilities()}. Otherwise the framework will assume this feature is not 776 * supported for this ImsService. 777 * @param slotId The slot that is associated with the SipTransport implementation. 778 * @return the SipTransport implementation for the specified slot. 779 */ 780 // ImsService follows a different convention, since it is a stub class. The on* methods are 781 // final and call back into the framework with a state update. 782 @SuppressLint("OnNameExpected") getSipTransport(int slotId)783 public @Nullable SipTransportImplBase getSipTransport(int slotId) { 784 // Stub implementation for ImsServices that do not support SipTransport. 785 return null; 786 } 787 sanitizeCapabilities(@msServiceCapability long caps)788 private static long sanitizeCapabilities(@ImsServiceCapability long caps) { 789 long filter = 0xFFFFFFFFFFFFFFFFL; 790 // pad the "allowed" set with zeros 791 filter <<= CAPABILITY_MAX_INDEX + 1; 792 // remove values above the allowed set. 793 caps &= ~filter; 794 // CAPABILITY_EMERGENCY_OVER_MMTEL should also not be set here, will be set by telephony 795 // internally. 796 caps &= ~CAPABILITY_EMERGENCY_OVER_MMTEL; 797 return caps; 798 } 799 800 /** 801 * @return A string representation of the ImsService capabilities for logging. 802 * @hide 803 */ getCapabilitiesString(@msServiceCapability long caps)804 public static String getCapabilitiesString(@ImsServiceCapability long caps) { 805 StringBuffer result = new StringBuffer(); 806 result.append("capabilities={ "); 807 // filter incrementally fills 0s from left to right. This is used to keep filtering out 808 // more bits in the long until the remaining leftmost bits are all zero. 809 long filter = 0xFFFFFFFFFFFFFFFFL; 810 // position of iterator to potentially print capability. 811 long i = 0; 812 while ((caps & filter) != 0 && i <= 63) { 813 long bitToCheck = (1L << i); 814 if ((caps & bitToCheck) != 0) { 815 result.append(CAPABILITIES_LOG_MAP.getOrDefault(bitToCheck, bitToCheck + "?")); 816 result.append(" "); 817 } 818 // shift left by one and fill in another 1 on the leftmost bit. 819 filter <<= 1; 820 i++; 821 } 822 result.append("}"); 823 return result.toString(); 824 } 825 826 /** 827 * The ImsService will now be able to define an Executor that the ImsService can be used to 828 * execute the methods. By default all ImsService level method calls will use this Executor. 829 * The ImsService has set the default executor as Runnable::run, 830 * Should be override or default executor will be used. 831 * @return an Executor used to execute methods called remotely by the framework. 832 */ getExecutor()833 public @NonNull Executor getExecutor() { 834 return Runnable::run; 835 } 836 } 837