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