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