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.feature; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.FlaggedApi; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.SystemApi; 25 import android.os.Binder; 26 import android.os.Bundle; 27 import android.os.Message; 28 import android.os.RemoteException; 29 import android.os.ServiceSpecificException; 30 import android.telecom.TelecomManager; 31 import android.telephony.AccessNetworkConstants; 32 import android.telephony.ims.ImsCallProfile; 33 import android.telephony.ims.ImsCallSession; 34 import android.telephony.ims.ImsCallSessionListener; 35 import android.telephony.ims.ImsException; 36 import android.telephony.ims.ImsReasonInfo; 37 import android.telephony.ims.ImsService; 38 import android.telephony.ims.MediaQualityStatus; 39 import android.telephony.ims.MediaThreshold; 40 import android.telephony.ims.RtpHeaderExtensionType; 41 import android.telephony.ims.SrvccCall; 42 import android.telephony.ims.aidl.IImsCallSessionListener; 43 import android.telephony.ims.aidl.IImsCapabilityCallback; 44 import android.telephony.ims.aidl.IImsMmTelFeature; 45 import android.telephony.ims.aidl.IImsMmTelListener; 46 import android.telephony.ims.aidl.IImsSmsListener; 47 import android.telephony.ims.aidl.IImsTrafficSessionCallback; 48 import android.telephony.ims.aidl.ISrvccStartedCallback; 49 import android.telephony.ims.stub.ImsCallSessionImplBase; 50 import android.telephony.ims.stub.ImsEcbmImplBase; 51 import android.telephony.ims.stub.ImsMultiEndpointImplBase; 52 import android.telephony.ims.stub.ImsRegistrationImplBase; 53 import android.telephony.ims.stub.ImsSmsImplBase; 54 import android.telephony.ims.stub.ImsUtImplBase; 55 import android.util.ArraySet; 56 import android.util.Log; 57 58 import com.android.ims.internal.IImsCallSession; 59 import com.android.ims.internal.IImsEcbm; 60 import com.android.ims.internal.IImsMultiEndpoint; 61 import com.android.ims.internal.IImsUt; 62 import com.android.internal.telephony.util.TelephonyUtils; 63 import com.android.server.telecom.flags.Flags; 64 65 import java.lang.annotation.Retention; 66 import java.lang.annotation.RetentionPolicy; 67 import java.lang.ref.WeakReference; 68 import java.util.HashMap; 69 import java.util.List; 70 import java.util.Set; 71 import java.util.concurrent.CancellationException; 72 import java.util.concurrent.CompletableFuture; 73 import java.util.concurrent.CompletionException; 74 import java.util.concurrent.ExecutionException; 75 import java.util.concurrent.Executor; 76 import java.util.concurrent.atomic.AtomicInteger; 77 import java.util.concurrent.atomic.AtomicReference; 78 import java.util.function.Consumer; 79 import java.util.function.Supplier; 80 81 /** 82 * Base implementation for Voice and SMS (IR-92) and Video (IR-94) IMS support. 83 * 84 * Any class wishing to use MmTelFeature should extend this class and implement all methods that the 85 * service supports. 86 */ 87 public class MmTelFeature extends ImsFeature { 88 89 private static final String LOG_TAG = "MmTelFeature"; 90 private Executor mExecutor; 91 private ImsSmsImplBase mSmsImpl; 92 93 private HashMap<ImsTrafficSessionCallback, ImsTrafficSessionCallbackWrapper> mTrafficCallbacks = 94 new HashMap<>(); 95 /** 96 * Creates a new MmTelFeature using the Executor set in {@link ImsService#getExecutor} 97 * @hide 98 */ 99 @SystemApi MmTelFeature()100 public MmTelFeature() { 101 } 102 103 /** 104 * Create a new MmTelFeature using the Executor specified for methods being called by the 105 * framework. 106 * @param executor The executor for the framework to use when executing the methods overridden 107 * by the implementation of MmTelFeature. 108 * @hide 109 */ 110 @SystemApi MmTelFeature(@onNull Executor executor)111 public MmTelFeature(@NonNull Executor executor) { 112 super(); 113 mExecutor = executor; 114 } 115 116 private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() { 117 118 @Override 119 public void setListener(IImsMmTelListener l) { 120 executeMethodAsyncNoException(() -> MmTelFeature.this.setListener(l), "setListener"); 121 } 122 123 @Override 124 public int getFeatureState() throws RemoteException { 125 return executeMethodAsyncForResult(() -> MmTelFeature.this.getFeatureState(), 126 "getFeatureState"); 127 } 128 129 @Override 130 public ImsCallProfile createCallProfile(int callSessionType, int callType) 131 throws RemoteException { 132 return executeMethodAsyncForResult(() -> MmTelFeature.this.createCallProfile( 133 callSessionType, callType), "createCallProfile"); 134 } 135 136 @Override 137 public void changeOfferedRtpHeaderExtensionTypes(List<RtpHeaderExtensionType> types) 138 throws RemoteException { 139 executeMethodAsync(() -> MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes( 140 new ArraySet<>(types)), "changeOfferedRtpHeaderExtensionTypes"); 141 } 142 143 @Override 144 public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException { 145 AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); 146 IImsCallSession result = executeMethodAsyncForResult(() -> { 147 try { 148 return createCallSessionInterface(profile); 149 } catch (RemoteException e) { 150 exceptionRef.set(e); 151 return null; 152 } 153 }, "createCallSession"); 154 155 if (exceptionRef.get() != null) { 156 throw exceptionRef.get(); 157 } 158 159 return result; 160 } 161 162 @Override 163 public int shouldProcessCall(String[] numbers) { 164 Integer result = executeMethodAsyncForResultNoException(() -> 165 MmTelFeature.this.shouldProcessCall(numbers), "shouldProcessCall"); 166 if (result != null) { 167 return result.intValue(); 168 } else { 169 return PROCESS_CALL_CSFB; 170 } 171 } 172 173 @Override 174 public IImsUt getUtInterface() throws RemoteException { 175 AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); 176 IImsUt result = executeMethodAsyncForResult(() -> { 177 try { 178 return MmTelFeature.this.getUtInterface(); 179 } catch (RemoteException e) { 180 exceptionRef.set(e); 181 return null; 182 } 183 }, "getUtInterface"); 184 185 if (exceptionRef.get() != null) { 186 throw exceptionRef.get(); 187 } 188 189 return result; 190 } 191 192 @Override 193 public IImsEcbm getEcbmInterface() throws RemoteException { 194 AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); 195 IImsEcbm result = executeMethodAsyncForResult(() -> { 196 try { 197 return MmTelFeature.this.getEcbmInterface(); 198 } catch (RemoteException e) { 199 exceptionRef.set(e); 200 return null; 201 } 202 }, "getEcbmInterface"); 203 204 if (exceptionRef.get() != null) { 205 throw exceptionRef.get(); 206 } 207 208 return result; 209 } 210 211 @Override 212 public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException { 213 executeMethodAsync(() -> MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage), 214 "setUiTtyMode"); 215 } 216 217 @Override 218 public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException { 219 AtomicReference<RemoteException> exceptionRef = new AtomicReference<>(); 220 IImsMultiEndpoint result = executeMethodAsyncForResult(() -> { 221 try { 222 return MmTelFeature.this.getMultiEndpointInterface(); 223 } catch (RemoteException e) { 224 exceptionRef.set(e); 225 return null; 226 } 227 }, "getMultiEndpointInterface"); 228 229 if (exceptionRef.get() != null) { 230 throw exceptionRef.get(); 231 } 232 233 return result; 234 } 235 236 @Override 237 public int queryCapabilityStatus() { 238 Integer result = executeMethodAsyncForResultNoException(() -> MmTelFeature.this 239 .queryCapabilityStatus().mCapabilities, "queryCapabilityStatus"); 240 241 if (result != null) { 242 return result.intValue(); 243 } else { 244 return 0; 245 } 246 } 247 248 @Override 249 public void addCapabilityCallback(IImsCapabilityCallback c) { 250 executeMethodAsyncNoException(() -> MmTelFeature.this 251 .addCapabilityCallback(c), "addCapabilityCallback"); 252 } 253 254 @Override 255 public void removeCapabilityCallback(IImsCapabilityCallback c) { 256 executeMethodAsyncNoException(() -> MmTelFeature.this 257 .removeCapabilityCallback(c), "removeCapabilityCallback"); 258 } 259 260 @Override 261 public void changeCapabilitiesConfiguration(CapabilityChangeRequest request, 262 IImsCapabilityCallback c) { 263 executeMethodAsyncNoException(() -> MmTelFeature.this 264 .requestChangeEnabledCapabilities(request, c), 265 "changeCapabilitiesConfiguration"); 266 } 267 268 @Override 269 public void queryCapabilityConfiguration(int capability, int radioTech, 270 IImsCapabilityCallback c) { 271 executeMethodAsyncNoException(() -> queryCapabilityConfigurationInternal( 272 capability, radioTech, c), "queryCapabilityConfiguration"); 273 } 274 275 @Override 276 public void setMediaQualityThreshold(@MediaQualityStatus.MediaSessionType int sessionType, 277 MediaThreshold mediaThreshold) { 278 if (mediaThreshold != null) { 279 executeMethodAsyncNoException(() -> setMediaThreshold(sessionType, mediaThreshold), 280 "setMediaQualityThreshold"); 281 } else { 282 executeMethodAsyncNoException(() -> clearMediaThreshold(sessionType), 283 "clearMediaQualityThreshold"); 284 } 285 } 286 287 @Override 288 public MediaQualityStatus queryMediaQualityStatus( 289 @MediaQualityStatus.MediaSessionType int sessionType) 290 throws RemoteException { 291 return executeMethodAsyncForResult(() -> MmTelFeature.this.queryMediaQualityStatus( 292 sessionType), "queryMediaQualityStatus"); 293 } 294 295 @Override 296 public void setSmsListener(IImsSmsListener l) { 297 executeMethodAsyncNoException(() -> MmTelFeature.this.setSmsListener(l), 298 "setSmsListener", getImsSmsImpl().getExecutor()); 299 } 300 301 @Override 302 public void sendSms(int token, int messageRef, String format, String smsc, boolean retry, 303 byte[] pdu) { 304 executeMethodAsyncNoException(() -> MmTelFeature.this 305 .sendSms(token, messageRef, format, smsc, retry, pdu), "sendSms", 306 getImsSmsImpl().getExecutor()); 307 } 308 309 @Override 310 public void onMemoryAvailable(int token) { 311 executeMethodAsyncNoException(() -> MmTelFeature.this 312 .onMemoryAvailable(token), "onMemoryAvailable", getImsSmsImpl().getExecutor()); 313 } 314 315 @Override 316 public void acknowledgeSms(int token, int messageRef, int result) { 317 executeMethodAsyncNoException(() -> MmTelFeature.this 318 .acknowledgeSms(token, messageRef, result), "acknowledgeSms", 319 getImsSmsImpl().getExecutor()); 320 } 321 322 @Override 323 public void acknowledgeSmsWithPdu(int token, int messageRef, int result, byte[] pdu) { 324 executeMethodAsyncNoException(() -> MmTelFeature.this 325 .acknowledgeSms(token, messageRef, result, pdu), "acknowledgeSms", 326 getImsSmsImpl().getExecutor()); 327 } 328 329 @Override 330 public void acknowledgeSmsReport(int token, int messageRef, int result) { 331 executeMethodAsyncNoException(() -> MmTelFeature.this 332 .acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport", 333 getImsSmsImpl().getExecutor()); 334 } 335 336 @Override 337 public String getSmsFormat() { 338 return executeMethodAsyncForResultNoException(() -> MmTelFeature.this 339 .getSmsFormat(), "getSmsFormat", getImsSmsImpl().getExecutor()); 340 } 341 342 @Override 343 public void onSmsReady() { 344 executeMethodAsyncNoException(() -> MmTelFeature.this.onSmsReady(), 345 "onSmsReady", getImsSmsImpl().getExecutor()); 346 } 347 348 @Override 349 public void notifySrvccStarted(final ISrvccStartedCallback cb) { 350 executeMethodAsyncNoException( 351 () -> MmTelFeature.this.notifySrvccStarted( 352 (profiles) -> { 353 try { 354 cb.onSrvccCallNotified(profiles); 355 } catch (Exception e) { 356 Log.e(LOG_TAG, "onSrvccCallNotified e=" + e); 357 } 358 }), 359 "notifySrvccStarted"); 360 } 361 362 @Override 363 public void notifySrvccCompleted() { 364 executeMethodAsyncNoException( 365 () -> MmTelFeature.this.notifySrvccCompleted(), "notifySrvccCompleted"); 366 } 367 368 @Override 369 public void notifySrvccFailed() { 370 executeMethodAsyncNoException( 371 () -> MmTelFeature.this.notifySrvccFailed(), "notifySrvccFailed"); 372 } 373 374 @Override 375 public void notifySrvccCanceled() { 376 executeMethodAsyncNoException( 377 () -> MmTelFeature.this.notifySrvccCanceled(), "notifySrvccCanceled"); 378 } 379 380 @Override 381 public void setTerminalBasedCallWaitingStatus(boolean enabled) throws RemoteException { 382 synchronized (mLock) { 383 try { 384 MmTelFeature.this.setTerminalBasedCallWaitingStatus(enabled); 385 } catch (ServiceSpecificException se) { 386 throw new ServiceSpecificException(se.errorCode, se.getMessage()); 387 } catch (Exception e) { 388 throw new RemoteException(e.getMessage()); 389 } 390 } 391 } 392 393 // Call the methods with a clean calling identity on the executor and wait indefinitely for 394 // the future to return. 395 private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException { 396 try { 397 CompletableFuture.runAsync( 398 () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); 399 } catch (CancellationException | CompletionException e) { 400 Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " 401 + e.getMessage()); 402 throw new RemoteException(e.getMessage()); 403 } 404 } 405 406 private void executeMethodAsyncNoException(Runnable r, String errorLogName) { 407 try { 408 CompletableFuture.runAsync( 409 () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); 410 } catch (CancellationException | CompletionException e) { 411 Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " 412 + e.getMessage()); 413 } 414 } 415 416 private void executeMethodAsyncNoException(Runnable r, String errorLogName, 417 Executor executor) { 418 try { 419 CompletableFuture.runAsync( 420 () -> TelephonyUtils.runWithCleanCallingIdentity(r), executor).join(); 421 } catch (CancellationException | CompletionException e) { 422 Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " 423 + e.getMessage()); 424 } 425 } 426 427 private <T> T executeMethodAsyncForResult(Supplier<T> r, 428 String errorLogName) throws RemoteException { 429 CompletableFuture<T> future = CompletableFuture.supplyAsync( 430 () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); 431 try { 432 return future.get(); 433 } catch (ExecutionException | InterruptedException e) { 434 Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " 435 + e.getMessage()); 436 throw new RemoteException(e.getMessage()); 437 } 438 } 439 440 private <T> T executeMethodAsyncForResultNoException(Supplier<T> r, 441 String errorLogName) { 442 CompletableFuture<T> future = CompletableFuture.supplyAsync( 443 () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); 444 try { 445 return future.get(); 446 } catch (ExecutionException | InterruptedException e) { 447 Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " 448 + e.getMessage()); 449 return null; 450 } 451 } 452 453 private <T> T executeMethodAsyncForResultNoException(Supplier<T> r, 454 String errorLogName, Executor executor) { 455 CompletableFuture<T> future = CompletableFuture.supplyAsync( 456 () -> TelephonyUtils.runWithCleanCallingIdentity(r), executor); 457 try { 458 return future.get(); 459 } catch (ExecutionException | InterruptedException e) { 460 Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " 461 + e.getMessage()); 462 return null; 463 } 464 } 465 }; 466 467 /** 468 * Contains the capabilities defined and supported by a MmTelFeature in the form of a Bitmask. 469 * The capabilities that are used in MmTelFeature are defined as 470 * {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE}, 471 * {@link MmTelCapabilities#CAPABILITY_TYPE_VIDEO}, 472 * {@link MmTelCapabilities#CAPABILITY_TYPE_UT}, 473 * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}, and 474 * {@link MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER}. 475 * 476 * The capabilities of this MmTelFeature will be set by the framework. 477 */ 478 public static class MmTelCapabilities extends Capabilities { 479 480 /** 481 * Create a new empty {@link MmTelCapabilities} instance. 482 * @see #addCapabilities(int) 483 * @see #removeCapabilities(int) 484 * @hide 485 */ 486 @SystemApi MmTelCapabilities()487 public MmTelCapabilities() { 488 super(); 489 } 490 491 /**@deprecated Use {@link MmTelCapabilities} to construct a new instance instead. 492 * @hide 493 */ 494 @Deprecated 495 @SystemApi MmTelCapabilities(Capabilities c)496 public MmTelCapabilities(Capabilities c) { 497 mCapabilities = c.mCapabilities; 498 } 499 500 /** 501 * Create a new {link @MmTelCapabilities} instance with the provided capabilities. 502 * @param capabilities The capabilities that are supported for MmTel in the form of a 503 * bitfield. 504 * @hide 505 */ 506 @SystemApi MmTelCapabilities(@mTelCapability int capabilities)507 public MmTelCapabilities(@MmTelCapability int capabilities) { 508 super(capabilities); 509 } 510 511 /** @hide */ 512 @IntDef(flag = true, 513 value = { 514 CAPABILITY_TYPE_VOICE, 515 CAPABILITY_TYPE_VIDEO, 516 CAPABILITY_TYPE_UT, 517 CAPABILITY_TYPE_SMS, 518 CAPABILITY_TYPE_CALL_COMPOSER, 519 CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY 520 }) 521 @Retention(RetentionPolicy.SOURCE) 522 public @interface MmTelCapability {} 523 524 /** 525 * Undefined capability type for initialization 526 * This is used to check the upper range of MmTel capability 527 * @hide 528 */ 529 public static final int CAPABILITY_TYPE_NONE = 0; 530 531 /** 532 * This MmTelFeature supports Voice calling (IR.92) 533 */ 534 public static final int CAPABILITY_TYPE_VOICE = 1 << 0; 535 536 /** 537 * This MmTelFeature supports Video (IR.94) 538 */ 539 public static final int CAPABILITY_TYPE_VIDEO = 1 << 1; 540 541 /** 542 * This MmTelFeature supports XCAP over Ut for supplementary services. (IR.92) 543 */ 544 public static final int CAPABILITY_TYPE_UT = 1 << 2; 545 546 /** 547 * This MmTelFeature supports SMS (IR.92) 548 */ 549 public static final int CAPABILITY_TYPE_SMS = 1 << 3; 550 551 /** 552 * This MmTelFeature supports Call Composer (section 2.4 of RC.20). This is the superset 553 * Call Composer, meaning that all subset types of Call Composers must be enabled when this 554 * capability is enabled 555 */ 556 public static final int CAPABILITY_TYPE_CALL_COMPOSER = 1 << 4; 557 558 559 /** 560 * This MmTelFeature supports Business-only Call Composer. This is a subset of 561 * {@code CAPABILITY_TYPE_CALL_COMPOSER} that only supports business related 562 * information for calling (e.g. information to signal if the call is a business call) in 563 * the SIP header. When enabling {@code CAPABILITY_TYPE_CALL_COMPOSER}, the 564 * {@code CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY} capability must also be enabled. 565 */ 566 @FlaggedApi(Flags.FLAG_BUSINESS_CALL_COMPOSER) 567 public static final int CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY = 1 << 5; 568 569 /** 570 * This is used to check the upper range of MmTel capability 571 * @hide 572 */ 573 public static final int CAPABILITY_TYPE_MAX = 574 CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY + 1; 575 576 /** 577 * @hide 578 */ 579 @Override 580 @SystemApi addCapabilities(@mTelCapability int capabilities)581 public final void addCapabilities(@MmTelCapability int capabilities) { 582 super.addCapabilities(capabilities); 583 } 584 585 /** 586 * @hide 587 */ 588 @Override 589 @SystemApi removeCapabilities(@mTelCapability int capability)590 public final void removeCapabilities(@MmTelCapability int capability) { 591 super.removeCapabilities(capability); 592 } 593 594 /** 595 * @param capabilities a bitmask of one or more capabilities. 596 * 597 * @return true if all queried capabilities are true, otherwise false. 598 */ 599 @Override isCapable(@mTelCapability int capabilities)600 public final boolean isCapable(@MmTelCapability int capabilities) { 601 return super.isCapable(capabilities); 602 } 603 604 /** 605 * @hide 606 */ 607 @NonNull 608 @Override toString()609 public String toString() { 610 StringBuilder builder = new StringBuilder("MmTel Capabilities - ["); 611 builder.append("Voice: "); 612 builder.append(isCapable(CAPABILITY_TYPE_VOICE)); 613 builder.append(" Video: "); 614 builder.append(isCapable(CAPABILITY_TYPE_VIDEO)); 615 builder.append(" UT: "); 616 builder.append(isCapable(CAPABILITY_TYPE_UT)); 617 builder.append(" SMS: "); 618 builder.append(isCapable(CAPABILITY_TYPE_SMS)); 619 builder.append(" CALL_COMPOSER: "); 620 builder.append(isCapable(CAPABILITY_TYPE_CALL_COMPOSER)); 621 builder.append(" BUSINESS_COMPOSER_ONLY: "); 622 builder.append(isCapable(CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY)); 623 builder.append("]"); 624 return builder.toString(); 625 } 626 } 627 628 /** 629 * Listener that the framework implements for communication from the MmTelFeature. 630 * @hide 631 */ 632 public static class Listener extends IImsMmTelListener.Stub { 633 634 /** 635 * Called when the IMS provider receives an incoming call. 636 * @param c The {@link ImsCallSession} associated with the new call. 637 * @param callId The call ID of the session of the new incoming call. 638 * @param extras A bundle containing extra parameters related to the call. See 639 * {@link #EXTRA_IS_UNKNOWN_CALL} and {@link #EXTRA_IS_USSD} above. 640 * @return the listener to listen to the session events. An {@link ImsCallSession} can only 641 * hold one listener at a time. see {@link ImsCallSessionListener}. 642 * If this method returns {@code null}, then the call could not be placed. 643 * @hide 644 */ 645 @Override 646 @Nullable onIncomingCall(IImsCallSession c, String callId, Bundle extras)647 public IImsCallSessionListener onIncomingCall(IImsCallSession c, 648 String callId, Bundle extras) { 649 return null; 650 } 651 652 /** 653 * Called when the IMS provider implicitly rejects an incoming call during setup. 654 * @param callProfile An {@link ImsCallProfile} with the call details. 655 * @param reason The {@link ImsReasonInfo} reason for call rejection. 656 * @hide 657 */ 658 @Override onRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason)659 public void onRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) { 660 661 } 662 663 /** 664 * Updates the Listener when the voice message count for IMS has changed. 665 * @param count an integer representing the new message count. 666 * @hide 667 */ 668 @Override onVoiceMessageCountUpdate(int count)669 public void onVoiceMessageCountUpdate(int count) { 670 671 } 672 673 /** 674 * Called to set the audio handler for this connection. 675 * @param imsAudioHandler an {@link ImsAudioHandler} used to handle the audio 676 * for this IMS call. 677 * @hide 678 */ 679 @Override onAudioModeIsVoipChanged(int imsAudioHandler)680 public void onAudioModeIsVoipChanged(int imsAudioHandler) { 681 682 } 683 684 /** 685 * Called when the IMS triggers EPS fallback procedure. 686 * 687 * @param reason specifies the reason that causes EPS fallback. 688 * @hide 689 */ 690 @Override onTriggerEpsFallback(@psFallbackReason int reason)691 public void onTriggerEpsFallback(@EpsFallbackReason int reason) { 692 693 } 694 695 /** 696 * Called when the IMS notifies the upcoming traffic type to the radio. 697 * 698 * @param token A nonce to identify the request 699 * @param trafficType The {@link ImsTrafficType} type for IMS traffic. 700 * @param accessNetworkType The {@link AccessNetworkConstants#RadioAccessNetworkType} 701 * type of the radio access network. 702 * @param trafficDirection Indicates whether traffic is originated by mobile originated or 703 * mobile terminated use case eg. MO/MT call/SMS etc. 704 * @param callback The callback to receive the result. 705 * @hide 706 */ 707 @Override onStartImsTrafficSession(int token, @ImsTrafficType int trafficType, @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, @ImsTrafficDirection int trafficDirection, IImsTrafficSessionCallback callback)708 public void onStartImsTrafficSession(int token, 709 @ImsTrafficType int trafficType, 710 @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, 711 @ImsTrafficDirection int trafficDirection, 712 IImsTrafficSessionCallback callback) { 713 714 } 715 716 /** 717 * Called when the IMS notifies the traffic type has been stopped. 718 * 719 * @param token A nonce registered with {@link #onStartImsTrafficSession}. 720 * @param accessNetworkType The {@link AccessNetworkConstants#RadioAccessNetworkType} 721 * type of the radio access network. 722 * @hide 723 */ 724 @Override onModifyImsTrafficSession(int token, @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType)725 public void onModifyImsTrafficSession(int token, 726 @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType) { 727 728 } 729 730 /** 731 * Called when the IMS notifies the traffic type has been stopped. 732 * 733 * @param token A nonce registered with {@link #onStartImsTrafficSession}. 734 * @hide 735 */ 736 @Override onStopImsTrafficSession(int token)737 public void onStopImsTrafficSession(int token) { 738 739 } 740 741 /** 742 * Called when the IMS provider notifies {@link MediaQualityStatus}. 743 * 744 * @param status media quality status currently measured. 745 * @hide 746 */ 747 @Override onMediaQualityStatusChanged(MediaQualityStatus status)748 public void onMediaQualityStatusChanged(MediaQualityStatus status) { 749 750 } 751 } 752 753 /** 754 * A wrapper class of {@link ImsTrafficSessionCallback}. 755 * @hide 756 */ 757 public static class ImsTrafficSessionCallbackWrapper { 758 public static final int INVALID_TOKEN = -1; 759 760 private static final int MAX_TOKEN = 0x10000; 761 762 private static final AtomicInteger sTokenGenerator = new AtomicInteger(); 763 764 /** Callback to receive the response */ 765 private IImsTrafficSessionCallbackStub mCallback = null; 766 /** Identifier to distinguish each IMS traffic request */ 767 private int mToken = INVALID_TOKEN; 768 769 private ImsTrafficSessionCallback mImsTrafficSessionCallback; 770 ImsTrafficSessionCallbackWrapper(ImsTrafficSessionCallback callback)771 private ImsTrafficSessionCallbackWrapper(ImsTrafficSessionCallback callback) { 772 mImsTrafficSessionCallback = callback; 773 } 774 775 /** 776 * Updates the callback. 777 * 778 * The mToken should be kept since it is used to identify the traffic notified to the modem 779 * until calling {@link MmtelFEature#stopImsTrafficSession}. 780 */ update(@onNull @allbackExecutor Executor executor)781 final void update(@NonNull @CallbackExecutor Executor executor) { 782 if (executor == null) { 783 throw new IllegalArgumentException( 784 "ImsTrafficSessionCallback Executor must be non-null"); 785 } 786 787 if (mCallback == null) { 788 // initial start of Ims traffic. 789 mCallback = new IImsTrafficSessionCallbackStub( 790 mImsTrafficSessionCallback, executor); 791 mToken = generateToken(); 792 } else { 793 // handover between cellular and Wi-Fi 794 mCallback.update(executor); 795 } 796 } 797 798 /** 799 * Using a static class and weak reference here to avoid memory leak caused by the 800 * {@link IImsTrafficSessionCallback.Stub} callback retaining references to the outside 801 * {@link ImsTrafficSessionCallback}. 802 */ 803 private static class IImsTrafficSessionCallbackStub 804 extends IImsTrafficSessionCallback.Stub { 805 private WeakReference<ImsTrafficSessionCallback> mImsTrafficSessionCallbackWeakRef; 806 private Executor mExecutor; 807 IImsTrafficSessionCallbackStub(ImsTrafficSessionCallback imsTrafficCallback, Executor executor)808 IImsTrafficSessionCallbackStub(ImsTrafficSessionCallback imsTrafficCallback, 809 Executor executor) { 810 mImsTrafficSessionCallbackWeakRef = 811 new WeakReference<ImsTrafficSessionCallback>(imsTrafficCallback); 812 mExecutor = executor; 813 } 814 update(Executor executor)815 void update(Executor executor) { 816 mExecutor = executor; 817 } 818 819 @Override onReady()820 public void onReady() { 821 ImsTrafficSessionCallback callback = mImsTrafficSessionCallbackWeakRef.get(); 822 if (callback == null) return; 823 824 Binder.withCleanCallingIdentity( 825 () -> mExecutor.execute(() -> callback.onReady())); 826 } 827 828 @Override onError(ConnectionFailureInfo info)829 public void onError(ConnectionFailureInfo info) { 830 ImsTrafficSessionCallback callback = mImsTrafficSessionCallbackWeakRef.get(); 831 if (callback == null) return; 832 833 Binder.withCleanCallingIdentity( 834 () -> mExecutor.execute(() -> callback.onError(info))); 835 } 836 } 837 838 /** 839 * Returns the callback binder. 840 */ getCallbackBinder()841 final IImsTrafficSessionCallbackStub getCallbackBinder() { 842 return mCallback; 843 } 844 845 /** 846 * Returns the token. 847 */ getToken()848 final int getToken() { 849 return mToken; 850 } 851 852 /** 853 * Resets the members. 854 * It's called by {@link MmTelFeature#stopImsTrafficSession}. 855 */ reset()856 final void reset() { 857 mCallback = null; 858 mToken = INVALID_TOKEN; 859 } 860 generateToken()861 private static int generateToken() { 862 int token = sTokenGenerator.incrementAndGet(); 863 if (token == MAX_TOKEN) sTokenGenerator.set(0); 864 return token; 865 } 866 } 867 868 /** 869 * To be returned by {@link #shouldProcessCall(String[])} when the ImsService should process the 870 * outgoing call as IMS. 871 * @hide 872 */ 873 @SystemApi 874 public static final int PROCESS_CALL_IMS = 0; 875 /** 876 * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should 877 * not process the outgoing call as IMS and should instead use circuit switch. 878 * @hide 879 */ 880 @SystemApi 881 public static final int PROCESS_CALL_CSFB = 1; 882 883 /** @hide */ 884 @IntDef(flag = true, 885 value = { 886 PROCESS_CALL_IMS, 887 PROCESS_CALL_CSFB 888 }) 889 @Retention(RetentionPolicy.SOURCE) 890 public @interface ProcessCallResult {} 891 892 /** 893 * If the flag is present and true, it indicates that the incoming call is for USSD. 894 * <p> 895 * This is an optional boolean flag. 896 * @hide 897 */ 898 @SystemApi 899 public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD"; 900 901 /** 902 * If this flag is present and true, this call is marked as an unknown dialing call instead 903 * of an incoming call. An example of such a call is a call that is originated by sending 904 * commands (like AT commands) directly to the modem without Android involvement or dialing 905 * calls appearing over IMS when the modem does a silent redial from circuit-switched to IMS in 906 * certain situations. 907 * <p> 908 * This is an optional boolean flag. 909 * @hide 910 */ 911 @SystemApi 912 public static final String EXTRA_IS_UNKNOWN_CALL = 913 "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL"; 914 915 /** @hide */ 916 @IntDef( 917 prefix = "AUDIO_HANDLER_", 918 value = { 919 AUDIO_HANDLER_ANDROID, 920 AUDIO_HANDLER_BASEBAND 921 }) 922 @Retention(RetentionPolicy.SOURCE) 923 public @interface ImsAudioHandler {} 924 925 /** 926 * Audio Handler - Android 927 * @hide 928 */ 929 @SystemApi 930 public static final int AUDIO_HANDLER_ANDROID = 0; 931 932 /** 933 * Audio Handler - Baseband 934 * @hide 935 */ 936 @SystemApi 937 public static final int AUDIO_HANDLER_BASEBAND = 1; 938 939 /** @hide */ 940 @Retention(RetentionPolicy.SOURCE) 941 @IntDef( 942 prefix = "EPS_FALLBACK_REASON_", 943 value = { 944 EPS_FALLBACK_REASON_INVALID, 945 EPS_FALLBACK_REASON_NO_NETWORK_TRIGGER, 946 EPS_FALLBACK_REASON_NO_NETWORK_RESPONSE, 947 }) 948 public @interface EpsFallbackReason {} 949 950 /** 951 * Default value. Internal use only. 952 * This value should not be used to trigger EPS fallback. 953 * @hide 954 */ 955 public static final int EPS_FALLBACK_REASON_INVALID = -1; 956 957 /** 958 * If the network only supports the EPS fallback in 5G NR SA for voice calling and the EPS 959 * Fallback procedure by the network during the call setup is not triggered, UE initiated 960 * fallback will be triggered with this reason. The modem shall locally release the 5G NR 961 * SA RRC connection and acquire the LTE network and perform a tracking area update 962 * procedure. After the EPS fallback procedure is completed, the call setup for voice will 963 * be established if there is no problem. 964 * 965 * @hide 966 */ 967 public static final int EPS_FALLBACK_REASON_NO_NETWORK_TRIGGER = 1; 968 969 /** 970 * If the UE doesn't receive any response for SIP INVITE within a certain timeout in 5G NR 971 * SA for MO voice calling, the device determines that voice call is not available in 5G and 972 * terminates all active SIP dialogs and SIP requests and enters IMS non-registered state. 973 * In that case, UE initiated fallback will be triggered with this reason. The modem shall 974 * reset modem's data buffer of IMS PDU to prevent the ghost call. After the EPS fallback 975 * procedure is completed, VoLTE call could be tried if there is no problem. 976 * 977 * @hide 978 */ 979 public static final int EPS_FALLBACK_REASON_NO_NETWORK_RESPONSE = 2; 980 981 /** @hide */ 982 @Retention(RetentionPolicy.SOURCE) 983 @IntDef( 984 prefix = "IMS_TRAFFIC_TYPE_", 985 value = { 986 IMS_TRAFFIC_TYPE_NONE, 987 IMS_TRAFFIC_TYPE_EMERGENCY, 988 IMS_TRAFFIC_TYPE_EMERGENCY_SMS, 989 IMS_TRAFFIC_TYPE_VOICE, 990 IMS_TRAFFIC_TYPE_VIDEO, 991 IMS_TRAFFIC_TYPE_SMS, 992 IMS_TRAFFIC_TYPE_REGISTRATION, 993 IMS_TRAFFIC_TYPE_UT_XCAP 994 }) 995 public @interface ImsTrafficType {} 996 997 /** 998 * Default value for initialization. Internal use only. 999 * @hide 1000 */ 1001 public static final int IMS_TRAFFIC_TYPE_NONE = -1; 1002 /** 1003 * Emergency call 1004 * @hide 1005 */ 1006 public static final int IMS_TRAFFIC_TYPE_EMERGENCY = 0; 1007 /** 1008 * Emergency SMS 1009 * @hide 1010 */ 1011 public static final int IMS_TRAFFIC_TYPE_EMERGENCY_SMS = 1; 1012 /** 1013 * Voice call 1014 * @hide 1015 */ 1016 public static final int IMS_TRAFFIC_TYPE_VOICE = 2; 1017 /** 1018 * Video call 1019 * @hide 1020 */ 1021 public static final int IMS_TRAFFIC_TYPE_VIDEO = 3; 1022 /** 1023 * SMS over IMS 1024 * @hide 1025 */ 1026 public static final int IMS_TRAFFIC_TYPE_SMS = 4; 1027 /** 1028 * IMS registration and subscription for reg event package (signaling) 1029 * @hide 1030 */ 1031 public static final int IMS_TRAFFIC_TYPE_REGISTRATION = 5; 1032 /** 1033 * Ut/XCAP (XML Configuration Access Protocol) 1034 * @hide 1035 */ 1036 public static final int IMS_TRAFFIC_TYPE_UT_XCAP = 6; 1037 1038 /** @hide */ 1039 @Retention(RetentionPolicy.SOURCE) 1040 @IntDef( 1041 prefix = { "IMS_TRAFFIC_DIRECTION_" }, 1042 value = {IMS_TRAFFIC_DIRECTION_INCOMING, IMS_TRAFFIC_DIRECTION_OUTGOING}) 1043 public @interface ImsTrafficDirection {} 1044 1045 /** 1046 * Indicates that the traffic is an incoming traffic. 1047 * @hide 1048 */ 1049 public static final int IMS_TRAFFIC_DIRECTION_INCOMING = 0; 1050 /** 1051 * Indicates that the traffic is an outgoing traffic. 1052 * @hide 1053 */ 1054 public static final int IMS_TRAFFIC_DIRECTION_OUTGOING = 1; 1055 1056 private IImsMmTelListener mListener; 1057 1058 /** 1059 * @param listener A {@link Listener} used when the MmTelFeature receives an incoming call and 1060 * notifies the framework. 1061 */ setListener(IImsMmTelListener listener)1062 private void setListener(IImsMmTelListener listener) { 1063 synchronized (mLock) { 1064 mListener = listener; 1065 if (mListener != null) { 1066 onFeatureReady(); 1067 } 1068 } 1069 } 1070 1071 /** 1072 * @return the listener associated with this MmTelFeature. May be null if it has not been set 1073 * by the framework yet. 1074 */ getListener()1075 private IImsMmTelListener getListener() { 1076 synchronized (mLock) { 1077 return mListener; 1078 } 1079 } 1080 1081 /** 1082 * The current capability status that this MmTelFeature has defined is available. This 1083 * configuration will be used by the platform to figure out which capabilities are CURRENTLY 1084 * available to be used. 1085 * 1086 * Should be a subset of the capabilities that are enabled by the framework in 1087 * {@link #changeEnabledCapabilities}. 1088 * @return A copy of the current MmTelFeature capability status. 1089 * @hide 1090 */ 1091 @Override 1092 @SystemApi queryCapabilityStatus()1093 public @NonNull final MmTelCapabilities queryCapabilityStatus() { 1094 return new MmTelCapabilities(super.queryCapabilityStatus()); 1095 } 1096 1097 /** 1098 * Notify the framework that the status of the Capabilities has changed. Even though the 1099 * MmTelFeature capability may be enabled by the framework, the status may be disabled due to 1100 * the feature being unavailable from the network. 1101 * @param c The current capability status of the MmTelFeature. If a capability is disabled, then 1102 * the status of that capability is disabled. This can happen if the network does not currently 1103 * support the capability that is enabled. A capability that is disabled by the framework (via 1104 * {@link #changeEnabledCapabilities}) should also show the status as disabled. 1105 * @hide 1106 */ 1107 @SystemApi notifyCapabilitiesStatusChanged(@onNull MmTelCapabilities c)1108 public final void notifyCapabilitiesStatusChanged(@NonNull MmTelCapabilities c) { 1109 if (c == null) { 1110 throw new IllegalArgumentException("MmTelCapabilities must be non-null!"); 1111 } 1112 super.notifyCapabilitiesStatusChanged(c); 1113 } 1114 1115 /** 1116 * Notify the framework that the measured media quality has crossed a threshold set by {@link 1117 * MmTelFeature#setMediaThreshold} 1118 * 1119 * @param status current media quality status measured. 1120 * @hide 1121 */ 1122 @SystemApi notifyMediaQualityStatusChanged( @onNull MediaQualityStatus status)1123 public final void notifyMediaQualityStatusChanged( 1124 @NonNull MediaQualityStatus status) { 1125 if (status == null) { 1126 throw new IllegalArgumentException( 1127 "MediaQualityStatus must be non-null!"); 1128 } 1129 Log.i(LOG_TAG, "notifyMediaQualityStatusChanged " + status); 1130 IImsMmTelListener listener = getListener(); 1131 if (listener == null) { 1132 throw new IllegalStateException("Session is not available."); 1133 } 1134 try { 1135 listener.onMediaQualityStatusChanged(status); 1136 } catch (RemoteException e) { 1137 throw new RuntimeException(e); 1138 } 1139 } 1140 1141 /** 1142 * Notify the framework of an incoming call. 1143 * @param c The {@link ImsCallSessionImplBase} of the new incoming call. 1144 * @param extras A bundle containing extra parameters related to the call. See 1145 * {@link #EXTRA_IS_UNKNOWN_CALL} and {@link #EXTRA_IS_USSD} above. 1146 * @hide 1147 * 1148 * @deprecated use {@link #notifyIncomingCall(ImsCallSessionImplBase, String, Bundle)} instead 1149 */ 1150 @Deprecated 1151 @SystemApi notifyIncomingCall(@onNull ImsCallSessionImplBase c, @NonNull Bundle extras)1152 public final void notifyIncomingCall(@NonNull ImsCallSessionImplBase c, 1153 @NonNull Bundle extras) { 1154 if (c == null || extras == null) { 1155 throw new IllegalArgumentException("ImsCallSessionImplBase and Bundle can not be " 1156 + "null."); 1157 } 1158 IImsMmTelListener listener = getListener(); 1159 if (listener == null) { 1160 throw new IllegalStateException("Session is not available."); 1161 } 1162 try { 1163 c.setDefaultExecutor(MmTelFeature.this.mExecutor); 1164 listener.onIncomingCall(c.getServiceImpl(), null, extras); 1165 } catch (RemoteException e) { 1166 throw new RuntimeException(e); 1167 } 1168 } 1169 1170 /** 1171 * Notify the framework of an incoming call. 1172 * @param c The {@link ImsCallSessionImplBase} of the new incoming call. 1173 * @param callId The call ID of the session of the new incoming call. 1174 * @param extras A bundle containing extra parameters related to the call. See 1175 * {@link #EXTRA_IS_UNKNOWN_CALL} and {@link #EXTRA_IS_USSD} above. 1176 * @return The listener used by the framework to listen to call session events created 1177 * from the ImsService. 1178 * If this method returns {@code null}, then the call could not be placed. 1179 * @hide 1180 */ 1181 @SystemApi 1182 @Nullable notifyIncomingCall( @onNull ImsCallSessionImplBase c, @NonNull String callId, @NonNull Bundle extras)1183 public final ImsCallSessionListener notifyIncomingCall( 1184 @NonNull ImsCallSessionImplBase c, @NonNull String callId, @NonNull Bundle extras) { 1185 if (c == null || callId == null || extras == null) { 1186 throw new IllegalArgumentException("ImsCallSessionImplBase, callId, and Bundle can " 1187 + "not be null."); 1188 } 1189 IImsMmTelListener listener = getListener(); 1190 if (listener == null) { 1191 throw new IllegalStateException("Session is not available."); 1192 } 1193 try { 1194 c.setDefaultExecutor(MmTelFeature.this.mExecutor); 1195 IImsCallSessionListener isl = 1196 listener.onIncomingCall(c.getServiceImpl(), callId, extras); 1197 if (isl != null) { 1198 ImsCallSessionListener iCSL = new ImsCallSessionListener(isl); 1199 iCSL.setDefaultExecutor(MmTelFeature.this.mExecutor); 1200 return iCSL; 1201 } else { 1202 return null; 1203 } 1204 } catch (RemoteException e) { 1205 throw new RuntimeException(e); 1206 } 1207 } 1208 1209 /** 1210 * Notify the framework that a call has been implicitly rejected by this MmTelFeature 1211 * during call setup. 1212 * @param callProfile The {@link ImsCallProfile} IMS call profile with details. 1213 * This can be null if no call information is available for the rejected call. 1214 * @param reason The {@link ImsReasonInfo} call rejection reason. 1215 * @hide 1216 */ 1217 @SystemApi notifyRejectedCall(@onNull ImsCallProfile callProfile, @NonNull ImsReasonInfo reason)1218 public final void notifyRejectedCall(@NonNull ImsCallProfile callProfile, 1219 @NonNull ImsReasonInfo reason) { 1220 if (callProfile == null || reason == null) { 1221 throw new IllegalArgumentException("ImsCallProfile and ImsReasonInfo must not be " 1222 + "null."); 1223 } 1224 IImsMmTelListener listener = getListener(); 1225 if (listener == null) { 1226 throw new IllegalStateException("Session is not available."); 1227 } 1228 try { 1229 listener.onRejectedCall(callProfile, reason); 1230 } catch (RemoteException e) { 1231 throw new RuntimeException(e); 1232 } 1233 } 1234 1235 /** 1236 * 1237 * @hide 1238 */ notifyIncomingCallSession(IImsCallSession c, Bundle extras)1239 public final void notifyIncomingCallSession(IImsCallSession c, Bundle extras) { 1240 IImsMmTelListener listener = getListener(); 1241 if (listener == null) { 1242 throw new IllegalStateException("Session is not available."); 1243 } 1244 try { 1245 listener.onIncomingCall(c, null, extras); 1246 } catch (RemoteException e) { 1247 throw new RuntimeException(e); 1248 } 1249 } 1250 1251 /** 1252 * Notify the framework of a change in the Voice Message count. 1253 * @link count the new Voice Message count. 1254 * @hide 1255 */ 1256 @SystemApi notifyVoiceMessageCountUpdate(int count)1257 public final void notifyVoiceMessageCountUpdate(int count) { 1258 IImsMmTelListener listener = getListener(); 1259 if (listener == null) { 1260 throw new IllegalStateException("Session is not available."); 1261 } 1262 try { 1263 listener.onVoiceMessageCountUpdate(count); 1264 } catch (RemoteException e) { 1265 throw new RuntimeException(e); 1266 } 1267 } 1268 1269 /** 1270 * Sets the audio handler for this connection. The vendor IMS stack will invoke this API 1271 * to inform Telephony/Telecom layers about which audio handlers i.e. either Android or Modem 1272 * shall be used for handling the IMS call audio. 1273 * 1274 * @param imsAudioHandler {@link MmTelFeature#ImsAudioHandler} used to handle the audio 1275 * for this IMS call. 1276 * @hide 1277 */ 1278 @SystemApi setCallAudioHandler(@msAudioHandler int imsAudioHandler)1279 public final void setCallAudioHandler(@ImsAudioHandler int imsAudioHandler) { 1280 IImsMmTelListener listener = getListener(); 1281 if (listener == null) { 1282 throw new IllegalStateException("Session is not available."); 1283 } 1284 try { 1285 listener.onAudioModeIsVoipChanged(imsAudioHandler); 1286 } catch (RemoteException e) { 1287 throw new RuntimeException(e); 1288 } 1289 } 1290 1291 /** 1292 * Triggers the EPS fallback procedure. 1293 * 1294 * @param reason specifies the reason that causes EPS fallback. 1295 * @hide 1296 */ triggerEpsFallback(@psFallbackReason int reason)1297 public final void triggerEpsFallback(@EpsFallbackReason int reason) { 1298 IImsMmTelListener listener = getListener(); 1299 if (listener == null) { 1300 throw new IllegalStateException("Session is not available."); 1301 } 1302 try { 1303 listener.onTriggerEpsFallback(reason); 1304 } catch (RemoteException e) { 1305 throw new RuntimeException(e); 1306 } 1307 } 1308 1309 /** 1310 * Starts a new IMS traffic session with the framework. 1311 * 1312 * This API notifies the NAS and RRC layers of the modem that IMS traffic of type 1313 * {@link ImsTrafficType} is starting for the IMS session represented by a 1314 * {@link ImsTrafficSessionCallback}. The {@link ImsTrafficSessionCallback} 1315 * will notify the caller when IMS traffic is ready to start via the 1316 * {@link ImsTrafficSessionCallback#onReady()} callback. If there was an error starting 1317 * IMS traffic for the specified traffic type, {@link ImsTrafficSessionCallback#onError()} will 1318 * be called, which will also notify the caller of the reason of the failure. 1319 * 1320 * If there is a handover that changes the {@link AccessNetworkConstants#RadioAccessNetworkType} 1321 * of this IMS traffic session, then {@link #modifyImsTrafficSession} should be called. This is 1322 * used, for example, when a WiFi <-> cellular handover occurs. 1323 * 1324 * Once the IMS traffic session is finished, {@link #stopImsTrafficSession} must be called. 1325 * 1326 * Note: This API will be used to prioritize RF resources in case of DSDS. The service priority 1327 * is EMERGENCY > EMERGENCY SMS > VOICE > VIDEO > SMS > REGISTRATION > Ut/XCAP. RF 1328 * shall be prioritized to the subscription which handles the higher priority service. 1329 * When both subscriptions are handling the same type of service, then RF shall be 1330 * prioritized to the voice preferred sub. 1331 * 1332 * @param trafficType The {@link ImsTrafficType} type for IMS traffic. 1333 * @param accessNetworkType The {@link AccessNetworkConstants#RadioAccessNetworkType} type of 1334 * the radio access network. 1335 * @param trafficDirection Indicates whether traffic is originated by mobile originated or 1336 * mobile terminated use case eg. MO/MT call/SMS etc. 1337 * @param executor The Executor that will be used to call the {@link ImsTrafficSessionCallback}. 1338 * @param callback The session representing the IMS Session associated with a specific 1339 * trafficType. This callback instance should only be used for the specified traffic type 1340 * until {@link #stopImsTrafficSession} is called. 1341 * 1342 * @see modifyImsTrafficSession 1343 * @see stopImsTrafficSession 1344 * 1345 * @hide 1346 */ startImsTrafficSession(@msTrafficType int trafficType, @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, @ImsTrafficDirection int trafficDirection, @NonNull Executor executor, @NonNull ImsTrafficSessionCallback callback)1347 public final void startImsTrafficSession(@ImsTrafficType int trafficType, 1348 @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, 1349 @ImsTrafficDirection int trafficDirection, 1350 @NonNull Executor executor, @NonNull ImsTrafficSessionCallback callback) { 1351 IImsMmTelListener listener = getListener(); 1352 if (listener == null) { 1353 throw new IllegalStateException("Session is not available."); 1354 } 1355 // TODO: retrieve from the callback list 1356 ImsTrafficSessionCallbackWrapper callbackWrapper = mTrafficCallbacks.get(callback); 1357 if (callbackWrapper == null) { 1358 callbackWrapper = new ImsTrafficSessionCallbackWrapper(callback); 1359 mTrafficCallbacks.put(callback, callbackWrapper); 1360 } 1361 try { 1362 callbackWrapper.update(executor); 1363 listener.onStartImsTrafficSession(callbackWrapper.getToken(), 1364 trafficType, accessNetworkType, trafficDirection, 1365 callbackWrapper.getCallbackBinder()); 1366 } catch (RemoteException e) { 1367 throw new RuntimeException(e); 1368 } 1369 } 1370 1371 /** 1372 * Modifies an existing IMS traffic session represented by the associated 1373 * {@link ImsTrafficSessionCallback}. 1374 * 1375 * The {@link ImsTrafficSessionCallback} will notify the caller when IMS traffic is ready to 1376 * start after modification using the {@link ImsTrafficSessionCallback#onReady()} callback. 1377 * If there was an error modifying IMS traffic for the new radio access network type type, 1378 * {@link ImsTrafficSessionCallback#onError()} will be called, which will also notify the 1379 * caller of the reason of the failure. 1380 * 1381 * @param accessNetworkType The {@link AccessNetworkConstants#RadioAccessNetworkType} type of 1382 * the radio access network. 1383 * @param callback The callback registered with {@link #startImsTrafficSession}. 1384 * 1385 * @see startImsTrafficSession 1386 * @see stopImsTrafficSession 1387 * 1388 * @hide 1389 */ modifyImsTrafficSession( @ccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, @NonNull ImsTrafficSessionCallback callback)1390 public final void modifyImsTrafficSession( 1391 @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, 1392 @NonNull ImsTrafficSessionCallback callback) { 1393 IImsMmTelListener listener = getListener(); 1394 if (listener == null) { 1395 throw new IllegalStateException("Session is not available."); 1396 } 1397 ImsTrafficSessionCallbackWrapper callbackWrapper = mTrafficCallbacks.get(callback); 1398 if (callbackWrapper == null) { 1399 // should not reach here. 1400 throw new IllegalStateException("Unknown ImsTrafficSessionCallback instance."); 1401 } 1402 try { 1403 listener.onModifyImsTrafficSession(callbackWrapper.getToken(), accessNetworkType); 1404 } catch (RemoteException e) { 1405 throw new RuntimeException(e); 1406 } 1407 } 1408 1409 /** 1410 * Notifies the framework that the IMS traffic session represented by the associated 1411 * {@link ImsTrafficSessionCallback} has ended. 1412 * 1413 * @param callback The callback registered with {@link #startImsTrafficSession}. 1414 * 1415 * @see startImsTrafficSession 1416 * @see modifyImsTrafficSession 1417 * 1418 * @hide 1419 */ stopImsTrafficSession(@onNull ImsTrafficSessionCallback callback)1420 public final void stopImsTrafficSession(@NonNull ImsTrafficSessionCallback callback) { 1421 IImsMmTelListener listener = getListener(); 1422 if (listener == null) { 1423 throw new IllegalStateException("Session is not available."); 1424 } 1425 ImsTrafficSessionCallbackWrapper callbackWrapper = mTrafficCallbacks.get(callback); 1426 if (callbackWrapper == null) { 1427 // should not reach here. 1428 throw new IllegalStateException("Unknown ImsTrafficSessionCallback instance."); 1429 } 1430 try { 1431 listener.onStopImsTrafficSession(callbackWrapper.getToken()); 1432 callbackWrapper.reset(); 1433 mTrafficCallbacks.remove(callback); 1434 } catch (RemoteException e) { 1435 throw new RuntimeException(e); 1436 } 1437 } 1438 1439 /** 1440 * Provides the MmTelFeature with the ability to return the framework Capability Configuration 1441 * for a provided Capability. If the framework calls {@link #changeEnabledCapabilities} and 1442 * includes a capability A to enable or disable, this method should return the correct enabled 1443 * status for capability A. 1444 * @param capability The capability that we are querying the configuration for. 1445 * @return true if the capability is enabled, false otherwise. 1446 * @hide 1447 */ 1448 @Override 1449 @SystemApi queryCapabilityConfiguration(@mTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)1450 public boolean queryCapabilityConfiguration(@MmTelCapabilities.MmTelCapability int capability, 1451 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { 1452 // Base implementation - Override to provide functionality 1453 return false; 1454 } 1455 1456 /** 1457 * The MmTelFeature should override this method to handle the enabling/disabling of 1458 * MmTel Features, defined in {@link MmTelCapabilities.MmTelCapability}. The framework assumes 1459 * the {@link CapabilityChangeRequest} was processed successfully. If a subset of capabilities 1460 * could not be set to their new values, 1461 * {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError} must be called 1462 * individually for each capability whose processing resulted in an error. 1463 * 1464 * Enabling/Disabling a capability here indicates that the capability should be registered or 1465 * deregistered (depending on the capability change) and become available or unavailable to 1466 * the framework. 1467 * @hide 1468 */ 1469 @Override 1470 @SystemApi changeEnabledCapabilities(@onNull CapabilityChangeRequest request, @NonNull CapabilityCallbackProxy c)1471 public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request, 1472 @NonNull CapabilityCallbackProxy c) { 1473 // Base implementation, no-op 1474 } 1475 1476 /** 1477 * Called by the framework to pass {@link MediaThreshold}. The MmTelFeature should override this 1478 * method to get Media quality threshold. This will pass the consolidated threshold values from 1479 * Telephony framework. IMS provider needs to monitor media quality of active call and notify 1480 * media quality {@link #notifyMediaQualityStatusChanged(MediaQualityStatus)} when the measured 1481 * media quality crosses at least one of {@link MediaThreshold} set by this. 1482 * 1483 * @param mediaSessionType media session type for this Threshold info. 1484 * @param mediaThreshold media threshold information 1485 * @hide 1486 */ 1487 @SystemApi setMediaThreshold( @ediaQualityStatus.MediaSessionType int mediaSessionType, @NonNull MediaThreshold mediaThreshold)1488 public void setMediaThreshold( 1489 @MediaQualityStatus.MediaSessionType int mediaSessionType, 1490 @NonNull MediaThreshold mediaThreshold) { 1491 // Base Implementation - Should be overridden. 1492 Log.d(LOG_TAG, "setMediaThreshold is not supported." + mediaThreshold); 1493 } 1494 1495 /** 1496 * The MmTelFeature should override this method to clear Media quality thresholds that were 1497 * registered and stop media quality status updates. 1498 * 1499 * @param mediaSessionType media session type 1500 * @hide 1501 */ 1502 @SystemApi clearMediaThreshold(@ediaQualityStatus.MediaSessionType int mediaSessionType)1503 public void clearMediaThreshold(@MediaQualityStatus.MediaSessionType int mediaSessionType) { 1504 // Base Implementation - Should be overridden. 1505 Log.d(LOG_TAG, "clearMediaThreshold is not supported." + mediaSessionType); 1506 } 1507 1508 /** 1509 * IMS provider should override this method to return currently measured media quality status. 1510 * 1511 * <p/> 1512 * If media quality status is not yet measured after call is active, it needs to notify media 1513 * quality status {@link #notifyMediaQualityStatusChanged(MediaQualityStatus)} when the first 1514 * measurement is done. 1515 * 1516 * @param mediaSessionType media session type 1517 * @return Current media quality status. It could be null if media quality status is not 1518 * measured yet or {@link MediaThreshold} was not set corresponding to the media session 1519 * type. 1520 * 1521 * @hide 1522 */ 1523 @SystemApi 1524 @Nullable queryMediaQualityStatus( @ediaQualityStatus.MediaSessionType int mediaSessionType)1525 public MediaQualityStatus queryMediaQualityStatus( 1526 @MediaQualityStatus.MediaSessionType int mediaSessionType) { 1527 // Base Implementation - Should be overridden. 1528 Log.d(LOG_TAG, "queryMediaQualityStatus is not supported." + mediaSessionType); 1529 return null; 1530 } 1531 1532 /** 1533 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. 1534 * 1535 * @param callSessionType a service type that is specified in {@link ImsCallProfile} 1536 * {@link ImsCallProfile#SERVICE_TYPE_NONE} 1537 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 1538 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 1539 * @param callType a call type that is specified in {@link ImsCallProfile} 1540 * {@link ImsCallProfile#CALL_TYPE_VOICE} 1541 * {@link ImsCallProfile#CALL_TYPE_VT} 1542 * {@link ImsCallProfile#CALL_TYPE_VT_TX} 1543 * {@link ImsCallProfile#CALL_TYPE_VT_RX} 1544 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR} 1545 * {@link ImsCallProfile#CALL_TYPE_VS} 1546 * {@link ImsCallProfile#CALL_TYPE_VS_TX} 1547 * {@link ImsCallProfile#CALL_TYPE_VS_RX} 1548 * @return a {@link ImsCallProfile} object 1549 * @hide 1550 */ 1551 @SystemApi createCallProfile(int callSessionType, int callType)1552 public @Nullable ImsCallProfile createCallProfile(int callSessionType, int callType) { 1553 // Base Implementation - Should be overridden 1554 return null; 1555 } 1556 1557 /** 1558 * Called by the framework to report a change to the RTP header extension types which should be 1559 * offered during SDP negotiation (see RFC8285 for more information). 1560 * <p> 1561 * The {@link ImsService} should report the RTP header extensions which were accepted during 1562 * SDP negotiation using {@link ImsCallProfile#setAcceptedRtpHeaderExtensionTypes(Set)}. 1563 * 1564 * @param extensionTypes The RTP header extensions the framework wishes to offer during 1565 * outgoing and incoming call setup. An empty list indicates that there 1566 * are no framework defined RTP header extension types to offer. 1567 * @hide 1568 */ 1569 @SystemApi changeOfferedRtpHeaderExtensionTypes( @onNull Set<RtpHeaderExtensionType> extensionTypes)1570 public void changeOfferedRtpHeaderExtensionTypes( 1571 @NonNull Set<RtpHeaderExtensionType> extensionTypes) { 1572 // Base implementation - should be overridden if RTP header extension handling is supported. 1573 } 1574 1575 /** 1576 * @hide 1577 */ createCallSessionInterface(ImsCallProfile profile)1578 public IImsCallSession createCallSessionInterface(ImsCallProfile profile) 1579 throws RemoteException { 1580 ImsCallSessionImplBase s = MmTelFeature.this.createCallSession(profile); 1581 if (s != null) { 1582 s.setDefaultExecutor(mExecutor); 1583 return s.getServiceImpl(); 1584 } else { 1585 return null; 1586 } 1587 } 1588 1589 /** 1590 * Creates an {@link ImsCallSession} with the specified call profile. 1591 * Use other methods, if applicable, instead of interacting with 1592 * {@link ImsCallSession} directly. 1593 * 1594 * @param profile a call profile to make the call 1595 * @hide 1596 */ 1597 @SystemApi createCallSession(@onNull ImsCallProfile profile)1598 public @Nullable ImsCallSessionImplBase createCallSession(@NonNull ImsCallProfile profile) { 1599 // Base Implementation - Should be overridden 1600 return null; 1601 } 1602 1603 /** 1604 * Called by the framework to determine if the outgoing call, designated by the outgoing 1605 * {@link String}s, should be processed as an IMS call or CSFB call. If this method's 1606 * functionality is not overridden, the platform will process every call as IMS as long as the 1607 * MmTelFeature reports that the {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE} capability is 1608 * available. 1609 * @param numbers An array of {@link String}s that will be used for placing the call. There can 1610 * be multiple {@link String}s listed in the case when we want to place an outgoing 1611 * call as a conference. 1612 * @return a {@link ProcessCallResult} to the framework, which will be used to determine if the 1613 * call will be placed over IMS or via CSFB. 1614 * @hide 1615 */ 1616 @SystemApi shouldProcessCall(@onNull String[] numbers)1617 public @ProcessCallResult int shouldProcessCall(@NonNull String[] numbers) { 1618 return PROCESS_CALL_IMS; 1619 } 1620 1621 /** 1622 * 1623 * @hide 1624 */ getUtInterface()1625 protected IImsUt getUtInterface() throws RemoteException { 1626 ImsUtImplBase utImpl = getUt(); 1627 if (utImpl != null) { 1628 utImpl.setDefaultExecutor(mExecutor); 1629 return utImpl.getInterface(); 1630 } else { 1631 return null; 1632 } 1633 } 1634 1635 /** 1636 * @hide 1637 */ getEcbmInterface()1638 protected IImsEcbm getEcbmInterface() throws RemoteException { 1639 ImsEcbmImplBase ecbmImpl = getEcbm(); 1640 if (ecbmImpl != null) { 1641 ecbmImpl.setDefaultExecutor(mExecutor); 1642 return ecbmImpl.getImsEcbm(); 1643 } else { 1644 return null; 1645 } 1646 } 1647 1648 /** 1649 * @hide 1650 */ getMultiEndpointInterface()1651 public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException { 1652 ImsMultiEndpointImplBase multiendpointImpl = getMultiEndpoint(); 1653 if (multiendpointImpl != null) { 1654 multiendpointImpl.setDefaultExecutor(mExecutor); 1655 return multiendpointImpl.getIImsMultiEndpoint(); 1656 } else { 1657 return null; 1658 } 1659 } 1660 1661 /** 1662 * @hide 1663 */ getImsSmsImpl()1664 public @NonNull ImsSmsImplBase getImsSmsImpl() { 1665 synchronized (mLock) { 1666 if (mSmsImpl == null) { 1667 mSmsImpl = getSmsImplementation(); 1668 mSmsImpl.setDefaultExecutor(mExecutor); 1669 } 1670 return mSmsImpl; 1671 } 1672 } 1673 1674 /** 1675 * @return The {@link ImsUtImplBase} Ut interface implementation for the supplementary service 1676 * configuration. 1677 * @hide 1678 */ 1679 @SystemApi getUt()1680 public @NonNull ImsUtImplBase getUt() { 1681 // Base Implementation - Should be overridden 1682 return new ImsUtImplBase(); 1683 } 1684 1685 /** 1686 * @return The {@link ImsEcbmImplBase} Emergency call-back mode interface for emergency VoLTE 1687 * calls that support it. 1688 * @hide 1689 */ 1690 @SystemApi getEcbm()1691 public @NonNull ImsEcbmImplBase getEcbm() { 1692 // Base Implementation - Should be overridden 1693 return new ImsEcbmImplBase(); 1694 } 1695 1696 /** 1697 * @return The {@link ImsMultiEndpointImplBase} implementation for implementing Dialog event 1698 * package processing for multi-endpoint. 1699 * @hide 1700 */ 1701 @SystemApi getMultiEndpoint()1702 public @NonNull ImsMultiEndpointImplBase getMultiEndpoint() { 1703 // Base Implementation - Should be overridden 1704 return new ImsMultiEndpointImplBase(); 1705 } 1706 1707 /** 1708 * Sets the current UI TTY mode for the MmTelFeature. 1709 * @param mode An integer containing the new UI TTY Mode, can consist of 1710 * {@link TelecomManager#TTY_MODE_OFF}, 1711 * {@link TelecomManager#TTY_MODE_FULL}, 1712 * {@link TelecomManager#TTY_MODE_HCO}, 1713 * {@link TelecomManager#TTY_MODE_VCO} 1714 * @param onCompleteMessage If non-null, this MmTelFeature should call this {@link Message} when 1715 * the operation is complete by using the associated {@link android.os.Messenger} in 1716 * {@link Message#replyTo}. For example: 1717 * {@code 1718 * // Set UI TTY Mode and other operations... 1719 * try { 1720 * // Notify framework that the mode was changed. 1721 * Messenger uiMessenger = onCompleteMessage.replyTo; 1722 * uiMessenger.send(onCompleteMessage); 1723 * } catch (RemoteException e) { 1724 * // Remote side is dead 1725 * } 1726 * } 1727 * @hide 1728 */ 1729 @SystemApi setUiTtyMode(int mode, @Nullable Message onCompleteMessage)1730 public void setUiTtyMode(int mode, @Nullable Message onCompleteMessage) { 1731 // Base Implementation - Should be overridden 1732 } 1733 1734 /** 1735 * Notifies the MmTelFeature of the enablement status of terminal based call waiting 1736 * 1737 * If the terminal based call waiting is provisioned, 1738 * IMS controls the enablement of terminal based call waiting which is defined 1739 * in 3GPP TS 24.615. 1740 * 1741 * @param enabled user setting controlling whether or not call waiting is enabled. 1742 * 1743 * @hide 1744 */ 1745 @SystemApi setTerminalBasedCallWaitingStatus(boolean enabled)1746 public void setTerminalBasedCallWaitingStatus(boolean enabled) { 1747 // Base Implementation - Should be overridden by IMS service 1748 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, 1749 "Not implemented on device."); 1750 } 1751 1752 /** 1753 * Notifies the MmTelFeature that the network has initiated an SRVCC (Single radio voice 1754 * call continuity) for all IMS calls. When the network initiates an SRVCC, calls from 1755 * the LTE domain are handed over to the legacy circuit switched domain. The modem requires 1756 * knowledge of ongoing calls in the IMS domain in order to complete the SRVCC operation. 1757 * <p> 1758 * @param consumer The callback used to notify the framework of the list of IMS calls and their 1759 * state at the time of the SRVCC. 1760 * 1761 * @hide 1762 */ 1763 @SystemApi notifySrvccStarted(@onNull Consumer<List<SrvccCall>> consumer)1764 public void notifySrvccStarted(@NonNull Consumer<List<SrvccCall>> consumer) { 1765 // Base Implementation - Should be overridden by IMS service 1766 } 1767 1768 /** 1769 * Notifies the MmTelFeature that the SRVCC is completed and the calls have been moved 1770 * over to the circuit-switched domain. 1771 * {@link android.telephony.CarrierConfigManager.ImsVoice#KEY_SRVCC_TYPE_INT_ARRAY} 1772 * specifies the calls can be moved. Other calls will be disconnected. 1773 * <p> 1774 * The MmTelFeature may now release all resources related to the IMS calls. 1775 * 1776 * @hide 1777 */ 1778 @SystemApi notifySrvccCompleted()1779 public void notifySrvccCompleted() { 1780 // Base Implementation - Should be overridden by IMS service 1781 } 1782 1783 /** 1784 * Notifies the MmTelFeature that the SRVCC has failed. 1785 * 1786 * The handover can fail by encountering a failure at the radio level 1787 * or temporary MSC server internal errors in handover procedure. 1788 * Refer to 3GPP TS 23.216 section 8 Handover Failure. 1789 * <p> 1790 * IMS service will recover and continue calls over IMS. 1791 * Per TS 24.237 12.2.4.2, UE shall send SIP UPDATE request containing the reason-text 1792 * set to "failure to transition to CS domain". 1793 * 1794 * @hide 1795 */ 1796 @SystemApi notifySrvccFailed()1797 public void notifySrvccFailed() { 1798 // Base Implementation - Should be overridden by IMS service 1799 } 1800 1801 /** 1802 * Notifies the MmTelFeature that the SRVCC has been canceled. 1803 * 1804 * Since the state of network can be changed, the network can decide to terminate 1805 * the handover procedure before its completion and to return to its state before the handover 1806 * procedure was triggered. 1807 * Refer to 3GPP TS 23.216 section 8.1.3 Handover Cancellation. 1808 * 1809 * <p> 1810 * IMS service will recover and continue calls over IMS. 1811 * Per TS 24.237 12.2.4.2, UE shall send SIP UPDATE request containing the reason-text 1812 * set to "handover canceled". 1813 * 1814 * @hide 1815 */ 1816 @SystemApi notifySrvccCanceled()1817 public void notifySrvccCanceled() { 1818 // Base Implementation - Should be overridden by IMS service 1819 } 1820 setSmsListener(IImsSmsListener listener)1821 private void setSmsListener(IImsSmsListener listener) { 1822 getImsSmsImpl().registerSmsListener(listener); 1823 } 1824 sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, byte[] pdu)1825 private void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, 1826 byte[] pdu) { 1827 getImsSmsImpl().sendSms(token, messageRef, format, smsc, isRetry, pdu); 1828 } 1829 onMemoryAvailable(int token)1830 private void onMemoryAvailable(int token) { 1831 getImsSmsImpl().onMemoryAvailable(token); 1832 } 1833 acknowledgeSms(int token, int messageRef, @ImsSmsImplBase.DeliverStatusResult int result)1834 private void acknowledgeSms(int token, int messageRef, 1835 @ImsSmsImplBase.DeliverStatusResult int result) { 1836 getImsSmsImpl().acknowledgeSms(token, messageRef, result); 1837 } 1838 acknowledgeSms(int token, int messageRef, @ImsSmsImplBase.DeliverStatusResult int result, byte[] pdu)1839 private void acknowledgeSms(int token, int messageRef, 1840 @ImsSmsImplBase.DeliverStatusResult int result, byte[] pdu) { 1841 getImsSmsImpl().acknowledgeSms(token, messageRef, result, pdu); 1842 } 1843 acknowledgeSmsReport(int token, int messageRef, @ImsSmsImplBase.StatusReportResult int result)1844 private void acknowledgeSmsReport(int token, int messageRef, 1845 @ImsSmsImplBase.StatusReportResult int result) { 1846 getImsSmsImpl().acknowledgeSmsReport(token, messageRef, result); 1847 } 1848 onSmsReady()1849 private void onSmsReady() { 1850 getImsSmsImpl().onReady(); 1851 } 1852 1853 /** 1854 * Must be overridden by IMS Provider to be able to support SMS over IMS. Otherwise a default 1855 * non-functional implementation is returned. 1856 * 1857 * @return an instance of {@link ImsSmsImplBase} which should be implemented by the IMS 1858 * Provider. 1859 * @hide 1860 */ 1861 @SystemApi getSmsImplementation()1862 public @NonNull ImsSmsImplBase getSmsImplementation() { 1863 return new ImsSmsImplBase(); 1864 } 1865 getSmsFormat()1866 private String getSmsFormat() { 1867 return getImsSmsImpl().getSmsFormat(); 1868 } 1869 1870 /** 1871 * {@inheritDoc} 1872 * @hide 1873 */ 1874 @Override 1875 @SystemApi onFeatureRemoved()1876 public void onFeatureRemoved() { 1877 // Base Implementation - Should be overridden 1878 } 1879 1880 /** 1881 * {@inheritDoc} 1882 * @hide 1883 */ 1884 @Override 1885 @SystemApi onFeatureReady()1886 public void onFeatureReady() { 1887 // Base Implementation - Should be overridden 1888 } 1889 1890 /** 1891 * @hide 1892 */ 1893 @Override getBinder()1894 public final IImsMmTelFeature getBinder() { 1895 return mImsMMTelBinder; 1896 } 1897 1898 /** 1899 * Set default Executor from ImsService. 1900 * @param executor The default executor for the framework to use when executing the methods 1901 * overridden by the implementation of MmTelFeature. 1902 * @hide 1903 */ setDefaultExecutor(@onNull Executor executor)1904 public final void setDefaultExecutor(@NonNull Executor executor) { 1905 if (mExecutor == null) { 1906 mExecutor = executor; 1907 } 1908 } 1909 } 1910