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.IntDef; 20 import android.annotation.SystemApi; 21 import android.os.Bundle; 22 import android.os.Message; 23 import android.os.RemoteException; 24 import android.telecom.TelecomManager; 25 import android.telephony.ims.stub.ImsRegistrationImplBase; 26 import android.telephony.ims.stub.ImsCallSessionImplBase; 27 import android.telephony.ims.stub.ImsSmsImplBase; 28 import android.telephony.ims.aidl.IImsCapabilityCallback; 29 import android.telephony.ims.aidl.IImsMmTelFeature; 30 import android.telephony.ims.aidl.IImsMmTelListener; 31 import android.telephony.ims.aidl.IImsSmsListener; 32 import android.telephony.ims.stub.ImsEcbmImplBase; 33 import android.telephony.ims.stub.ImsMultiEndpointImplBase; 34 import android.telephony.ims.stub.ImsUtImplBase; 35 import android.util.Log; 36 37 import android.telephony.ims.ImsCallProfile; 38 import com.android.ims.internal.IImsCallSession; 39 import com.android.ims.internal.IImsEcbm; 40 import com.android.ims.internal.IImsMultiEndpoint; 41 import com.android.ims.internal.IImsUt; 42 import android.telephony.ims.ImsCallSession; 43 import com.android.internal.annotations.VisibleForTesting; 44 45 import java.lang.annotation.Retention; 46 import java.lang.annotation.RetentionPolicy; 47 48 /** 49 * Base implementation for Voice and SMS (IR-92) and Video (IR-94) IMS support. 50 * 51 * Any class wishing to use MmTelFeature should extend this class and implement all methods that the 52 * service supports. 53 * @hide 54 */ 55 @SystemApi 56 public class MmTelFeature extends ImsFeature { 57 58 private static final String LOG_TAG = "MmTelFeature"; 59 60 private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() { 61 62 @Override 63 public void setListener(IImsMmTelListener l) throws RemoteException { 64 synchronized (mLock) { 65 MmTelFeature.this.setListener(l); 66 } 67 } 68 69 @Override 70 public int getFeatureState() throws RemoteException { 71 synchronized (mLock) { 72 try { 73 return MmTelFeature.this.getFeatureState(); 74 } catch (Exception e) { 75 throw new RemoteException(e.getMessage()); 76 } 77 } 78 } 79 80 81 @Override 82 public ImsCallProfile createCallProfile(int callSessionType, int callType) 83 throws RemoteException { 84 synchronized (mLock) { 85 try { 86 return MmTelFeature.this.createCallProfile(callSessionType, callType); 87 } catch (Exception e) { 88 throw new RemoteException(e.getMessage()); 89 } 90 } 91 } 92 93 @Override 94 public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException { 95 synchronized (mLock) { 96 return createCallSessionInterface(profile); 97 } 98 } 99 100 @Override 101 public int shouldProcessCall(String[] numbers) { 102 synchronized (mLock) { 103 return MmTelFeature.this.shouldProcessCall(numbers); 104 } 105 } 106 107 @Override 108 public IImsUt getUtInterface() throws RemoteException { 109 synchronized (mLock) { 110 return MmTelFeature.this.getUtInterface(); 111 } 112 } 113 114 @Override 115 public IImsEcbm getEcbmInterface() throws RemoteException { 116 synchronized (mLock) { 117 return MmTelFeature.this.getEcbmInterface(); 118 } 119 } 120 121 @Override 122 public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException { 123 synchronized (mLock) { 124 try { 125 MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage); 126 } catch (Exception e) { 127 throw new RemoteException(e.getMessage()); 128 } 129 } 130 } 131 132 @Override 133 public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException { 134 synchronized (mLock) { 135 return MmTelFeature.this.getMultiEndpointInterface(); 136 } 137 } 138 139 @Override 140 public int queryCapabilityStatus() throws RemoteException { 141 synchronized (mLock) { 142 return MmTelFeature.this.queryCapabilityStatus().mCapabilities; 143 } 144 } 145 146 @Override 147 public void addCapabilityCallback(IImsCapabilityCallback c) { 148 // no need to lock, structure already handles multithreading. 149 MmTelFeature.this.addCapabilityCallback(c); 150 } 151 152 @Override 153 public void removeCapabilityCallback(IImsCapabilityCallback c) { 154 // no need to lock, structure already handles multithreading. 155 MmTelFeature.this.removeCapabilityCallback(c); 156 } 157 158 @Override 159 public void changeCapabilitiesConfiguration(CapabilityChangeRequest request, 160 IImsCapabilityCallback c) throws RemoteException { 161 synchronized (mLock) { 162 MmTelFeature.this.requestChangeEnabledCapabilities(request, c); 163 } 164 } 165 166 @Override 167 public void queryCapabilityConfiguration(int capability, int radioTech, 168 IImsCapabilityCallback c) { 169 synchronized (mLock) { 170 queryCapabilityConfigurationInternal(capability, radioTech, c); 171 } 172 } 173 174 @Override 175 public void setSmsListener(IImsSmsListener l) throws RemoteException { 176 synchronized (mLock) { 177 MmTelFeature.this.setSmsListener(l); 178 } 179 } 180 181 @Override 182 public void sendSms(int token, int messageRef, String format, String smsc, boolean retry, 183 byte[] pdu) { 184 synchronized (mLock) { 185 MmTelFeature.this.sendSms(token, messageRef, format, smsc, retry, pdu); 186 } 187 } 188 189 @Override 190 public void acknowledgeSms(int token, int messageRef, int result) { 191 synchronized (mLock) { 192 MmTelFeature.this.acknowledgeSms(token, messageRef, result); 193 } 194 } 195 196 @Override 197 public void acknowledgeSmsReport(int token, int messageRef, int result) { 198 synchronized (mLock) { 199 MmTelFeature.this.acknowledgeSmsReport(token, messageRef, result); 200 } 201 } 202 203 @Override 204 public String getSmsFormat() { 205 synchronized (mLock) { 206 return MmTelFeature.this.getSmsFormat(); 207 } 208 } 209 210 @Override 211 public void onSmsReady() { 212 synchronized (mLock) { 213 MmTelFeature.this.onSmsReady(); 214 } 215 } 216 }; 217 218 /** 219 * Contains the capabilities defined and supported by a MmTelFeature in the form of a Bitmask. 220 * The capabilities that are used in MmTelFeature are defined as 221 * {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE}, 222 * {@link MmTelCapabilities#CAPABILITY_TYPE_VIDEO}, 223 * {@link MmTelCapabilities#CAPABILITY_TYPE_UT}, and 224 * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}. 225 * 226 * The capabilities of this MmTelFeature will be set by the framework and can be queried with 227 * {@link #queryCapabilityStatus()}. 228 * 229 * This MmTelFeature can then return the status of each of these capabilities (enabled or not) 230 * by sending a {@link #notifyCapabilitiesStatusChanged} callback to the framework. The current 231 * status can also be queried using {@link #queryCapabilityStatus()}. 232 */ 233 public static class MmTelCapabilities extends Capabilities { 234 235 /** 236 * @hide 237 */ 238 @VisibleForTesting MmTelCapabilities()239 public MmTelCapabilities() { 240 super(); 241 } 242 MmTelCapabilities(Capabilities c)243 public MmTelCapabilities(Capabilities c) { 244 mCapabilities = c.mCapabilities; 245 } 246 MmTelCapabilities(int capabilities)247 public MmTelCapabilities(int capabilities) { 248 mCapabilities = capabilities; 249 } 250 251 @IntDef(flag = true, 252 value = { 253 CAPABILITY_TYPE_VOICE, 254 CAPABILITY_TYPE_VIDEO, 255 CAPABILITY_TYPE_UT, 256 CAPABILITY_TYPE_SMS 257 }) 258 @Retention(RetentionPolicy.SOURCE) 259 public @interface MmTelCapability {} 260 261 /** 262 * This MmTelFeature supports Voice calling (IR.92) 263 */ 264 public static final int CAPABILITY_TYPE_VOICE = 1 << 0; 265 266 /** 267 * This MmTelFeature supports Video (IR.94) 268 */ 269 public static final int CAPABILITY_TYPE_VIDEO = 1 << 1; 270 271 /** 272 * This MmTelFeature supports XCAP over Ut for supplementary services. (IR.92) 273 */ 274 public static final int CAPABILITY_TYPE_UT = 1 << 2; 275 276 /** 277 * This MmTelFeature supports SMS (IR.92) 278 */ 279 public static final int CAPABILITY_TYPE_SMS = 1 << 3; 280 281 @Override addCapabilities(@mTelCapability int capabilities)282 public final void addCapabilities(@MmTelCapability int capabilities) { 283 super.addCapabilities(capabilities); 284 } 285 286 @Override removeCapabilities(@mTelCapability int capability)287 public final void removeCapabilities(@MmTelCapability int capability) { 288 super.removeCapabilities(capability); 289 } 290 291 @Override isCapable(@mTelCapability int capabilities)292 public final boolean isCapable(@MmTelCapability int capabilities) { 293 return super.isCapable(capabilities); 294 } 295 296 @Override toString()297 public String toString() { 298 StringBuilder builder = new StringBuilder("MmTel Capabilities - ["); 299 builder.append("Voice: "); 300 builder.append(isCapable(CAPABILITY_TYPE_VOICE)); 301 builder.append(" Video: "); 302 builder.append(isCapable(CAPABILITY_TYPE_VIDEO)); 303 builder.append(" UT: "); 304 builder.append(isCapable(CAPABILITY_TYPE_UT)); 305 builder.append(" SMS: "); 306 builder.append(isCapable(CAPABILITY_TYPE_SMS)); 307 builder.append("]"); 308 return builder.toString(); 309 } 310 } 311 312 /** 313 * Listener that the framework implements for communication from the MmTelFeature. 314 * @hide 315 */ 316 public static class Listener extends IImsMmTelListener.Stub { 317 318 /** 319 * Called when the IMS provider receives an incoming call. 320 * @param c The {@link ImsCallSession} associated with the new call. 321 */ 322 @Override onIncomingCall(IImsCallSession c, Bundle extras)323 public void onIncomingCall(IImsCallSession c, Bundle extras) { 324 325 } 326 327 /** 328 * Updates the Listener when the voice message count for IMS has changed. 329 * @param count an integer representing the new message count. 330 */ 331 @Override onVoiceMessageCountUpdate(int count)332 public void onVoiceMessageCountUpdate(int count) { 333 334 } 335 } 336 337 /** 338 * To be returned by {@link #shouldProcessCall(String[])} when the ImsService should process the 339 * outgoing call as IMS. 340 */ 341 public static final int PROCESS_CALL_IMS = 0; 342 /** 343 * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should 344 * not process the outgoing call as IMS and should instead use circuit switch. 345 */ 346 public static final int PROCESS_CALL_CSFB = 1; 347 348 @IntDef(flag = true, 349 value = { 350 PROCESS_CALL_IMS, 351 PROCESS_CALL_CSFB 352 }) 353 @Retention(RetentionPolicy.SOURCE) 354 public @interface ProcessCallResult {} 355 356 357 // Lock for feature synchronization 358 private final Object mLock = new Object(); 359 private IImsMmTelListener mListener; 360 361 /** 362 * @param listener A {@link Listener} used when the MmTelFeature receives an incoming call and 363 * notifies the framework. 364 */ setListener(IImsMmTelListener listener)365 private void setListener(IImsMmTelListener listener) { 366 synchronized (mLock) { 367 mListener = listener; 368 } 369 if (mListener != null) { 370 onFeatureReady(); 371 } 372 } 373 queryCapabilityConfigurationInternal(int capability, int radioTech, IImsCapabilityCallback c)374 private void queryCapabilityConfigurationInternal(int capability, int radioTech, 375 IImsCapabilityCallback c) { 376 boolean enabled = queryCapabilityConfiguration(capability, radioTech); 377 try { 378 if (c != null) { 379 c.onQueryCapabilityConfiguration(capability, radioTech, enabled); 380 } 381 } catch (RemoteException e) { 382 Log.e(LOG_TAG, "queryCapabilityConfigurationInternal called on dead binder!"); 383 } 384 } 385 386 /** 387 * The current capability status that this MmTelFeature has defined is available. This 388 * configuration will be used by the platform to figure out which capabilities are CURRENTLY 389 * available to be used. 390 * 391 * Should be a subset of the capabilities that are enabled by the framework in 392 * {@link #changeEnabledCapabilities}. 393 * @return A copy of the current MmTelFeature capability status. 394 */ 395 @Override queryCapabilityStatus()396 public final MmTelCapabilities queryCapabilityStatus() { 397 return new MmTelCapabilities(super.queryCapabilityStatus()); 398 } 399 400 /** 401 * Notify the framework that the status of the Capabilities has changed. Even though the 402 * MmTelFeature capability may be enabled by the framework, the status may be disabled due to 403 * the feature being unavailable from the network. 404 * @param c The current capability status of the MmTelFeature. If a capability is disabled, then 405 * the status of that capability is disabled. This can happen if the network does not currently 406 * support the capability that is enabled. A capability that is disabled by the framework (via 407 * {@link #changeEnabledCapabilities}) should also show the status as disabled. 408 */ notifyCapabilitiesStatusChanged(MmTelCapabilities c)409 public final void notifyCapabilitiesStatusChanged(MmTelCapabilities c) { 410 super.notifyCapabilitiesStatusChanged(c); 411 } 412 413 /** 414 * Notify the framework of an incoming call. 415 * @param c The {@link ImsCallSessionImplBase} of the new incoming call. 416 */ notifyIncomingCall(ImsCallSessionImplBase c, Bundle extras)417 public final void notifyIncomingCall(ImsCallSessionImplBase c, Bundle extras) { 418 synchronized (mLock) { 419 if (mListener == null) { 420 throw new IllegalStateException("Session is not available."); 421 } 422 try { 423 mListener.onIncomingCall(c.getServiceImpl(), extras); 424 } catch (RemoteException e) { 425 throw new RuntimeException(e); 426 } 427 } 428 } 429 430 /** 431 * 432 * @hide 433 */ notifyIncomingCallSession(IImsCallSession c, Bundle extras)434 public final void notifyIncomingCallSession(IImsCallSession c, Bundle extras) { 435 synchronized (mLock) { 436 if (mListener == null) { 437 throw new IllegalStateException("Session is not available."); 438 } 439 try { 440 mListener.onIncomingCall(c, extras); 441 } catch (RemoteException e) { 442 throw new RuntimeException(e); 443 } 444 } 445 } 446 447 /** 448 * Notify the framework of a change in the Voice Message count. 449 * @link count the new Voice Message count. 450 */ notifyVoiceMessageCountUpdate(int count)451 public final void notifyVoiceMessageCountUpdate(int count) { 452 synchronized (mLock) { 453 if (mListener == null) { 454 throw new IllegalStateException("Session is not available."); 455 } 456 try { 457 mListener.onVoiceMessageCountUpdate(count); 458 } catch (RemoteException e) { 459 throw new RuntimeException(e); 460 } 461 } 462 } 463 464 /** 465 * Provides the MmTelFeature with the ability to return the framework Capability Configuration 466 * for a provided Capability. If the framework calls {@link #changeEnabledCapabilities} and 467 * includes a capability A to enable or disable, this method should return the correct enabled 468 * status for capability A. 469 * @param capability The capability that we are querying the configuration for. 470 * @return true if the capability is enabled, false otherwise. 471 */ queryCapabilityConfiguration(@mTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)472 public boolean queryCapabilityConfiguration(@MmTelCapabilities.MmTelCapability int capability, 473 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { 474 // Base implementation - Override to provide functionality 475 return false; 476 } 477 478 /** 479 * The MmTelFeature should override this method to handle the enabling/disabling of 480 * MmTel Features, defined in {@link MmTelCapabilities.MmTelCapability}. The framework assumes 481 * the {@link CapabilityChangeRequest} was processed successfully. If a subset of capabilities 482 * could not be set to their new values, 483 * {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError} must be called 484 * individually for each capability whose processing resulted in an error. 485 * 486 * Enabling/Disabling a capability here indicates that the capability should be registered or 487 * deregistered (depending on the capability change) and become available or unavailable to 488 * the framework. 489 */ 490 @Override changeEnabledCapabilities(CapabilityChangeRequest request, CapabilityCallbackProxy c)491 public void changeEnabledCapabilities(CapabilityChangeRequest request, 492 CapabilityCallbackProxy c) { 493 // Base implementation, no-op 494 } 495 496 /** 497 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. 498 * 499 * @param callSessionType a service type that is specified in {@link ImsCallProfile} 500 * {@link ImsCallProfile#SERVICE_TYPE_NONE} 501 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 502 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 503 * @param callType a call type that is specified in {@link ImsCallProfile} 504 * {@link ImsCallProfile#CALL_TYPE_VOICE} 505 * {@link ImsCallProfile#CALL_TYPE_VT} 506 * {@link ImsCallProfile#CALL_TYPE_VT_TX} 507 * {@link ImsCallProfile#CALL_TYPE_VT_RX} 508 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR} 509 * {@link ImsCallProfile#CALL_TYPE_VS} 510 * {@link ImsCallProfile#CALL_TYPE_VS_TX} 511 * {@link ImsCallProfile#CALL_TYPE_VS_RX} 512 * @return a {@link ImsCallProfile} object 513 */ createCallProfile(int callSessionType, int callType)514 public ImsCallProfile createCallProfile(int callSessionType, int callType) { 515 // Base Implementation - Should be overridden 516 return null; 517 } 518 519 /** 520 * @hide 521 */ createCallSessionInterface(ImsCallProfile profile)522 public IImsCallSession createCallSessionInterface(ImsCallProfile profile) 523 throws RemoteException { 524 ImsCallSessionImplBase s = MmTelFeature.this.createCallSession(profile); 525 return s != null ? s.getServiceImpl() : null; 526 } 527 528 /** 529 * Creates an {@link ImsCallSession} with the specified call profile. 530 * Use other methods, if applicable, instead of interacting with 531 * {@link ImsCallSession} directly. 532 * 533 * @param profile a call profile to make the call 534 */ createCallSession(ImsCallProfile profile)535 public ImsCallSessionImplBase createCallSession(ImsCallProfile profile) { 536 // Base Implementation - Should be overridden 537 return null; 538 } 539 540 /** 541 * Called by the framework to determine if the outgoing call, designated by the outgoing 542 * {@link String}s, should be processed as an IMS call or CSFB call. If this method's 543 * functionality is not overridden, the platform will process every call as IMS as long as the 544 * MmTelFeature reports that the {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE} capability is 545 * available. 546 * @param numbers An array of {@link String}s that will be used for placing the call. There can 547 * be multiple {@link String}s listed in the case when we want to place an outgoing 548 * call as a conference. 549 * @return a {@link ProcessCallResult} to the framework, which will be used to determine if the 550 * call will be placed over IMS or via CSFB. 551 */ shouldProcessCall(String[] numbers)552 public @ProcessCallResult int shouldProcessCall(String[] numbers) { 553 return PROCESS_CALL_IMS; 554 } 555 556 /** 557 * 558 * @hide 559 */ getUtInterface()560 protected IImsUt getUtInterface() throws RemoteException { 561 ImsUtImplBase utImpl = getUt(); 562 return utImpl != null ? utImpl.getInterface() : null; 563 } 564 565 /** 566 * @hide 567 */ getEcbmInterface()568 protected IImsEcbm getEcbmInterface() throws RemoteException { 569 ImsEcbmImplBase ecbmImpl = getEcbm(); 570 return ecbmImpl != null ? ecbmImpl.getImsEcbm() : null; 571 } 572 573 /** 574 * @hide 575 */ getMultiEndpointInterface()576 public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException { 577 ImsMultiEndpointImplBase multiendpointImpl = getMultiEndpoint(); 578 return multiendpointImpl != null ? multiendpointImpl.getIImsMultiEndpoint() : null; 579 } 580 581 /** 582 * @return The {@link ImsUtImplBase} Ut interface implementation for the supplementary service 583 * configuration. 584 */ getUt()585 public ImsUtImplBase getUt() { 586 // Base Implementation - Should be overridden 587 return new ImsUtImplBase(); 588 } 589 590 /** 591 * @return The {@link ImsEcbmImplBase} Emergency call-back mode interface for emergency VoLTE 592 * calls that support it. 593 */ getEcbm()594 public ImsEcbmImplBase getEcbm() { 595 // Base Implementation - Should be overridden 596 return new ImsEcbmImplBase(); 597 } 598 599 /** 600 * @return The {@link ImsMultiEndpointImplBase} implementation for implementing Dialog event 601 * package processing for multi-endpoint. 602 */ getMultiEndpoint()603 public ImsMultiEndpointImplBase getMultiEndpoint() { 604 // Base Implementation - Should be overridden 605 return new ImsMultiEndpointImplBase(); 606 } 607 608 /** 609 * Sets the current UI TTY mode for the MmTelFeature. 610 * @param mode An integer containing the new UI TTY Mode, can consist of 611 * {@link TelecomManager#TTY_MODE_OFF}, 612 * {@link TelecomManager#TTY_MODE_FULL}, 613 * {@link TelecomManager#TTY_MODE_HCO}, 614 * {@link TelecomManager#TTY_MODE_VCO} 615 * @param onCompleteMessage If non-null, this MmTelFeature should call this {@link Message} when 616 * the operation is complete by using the associated {@link android.os.Messenger} in 617 * {@link Message#replyTo}. For example: 618 * {@code 619 * // Set UI TTY Mode and other operations... 620 * try { 621 * // Notify framework that the mode was changed. 622 * Messenger uiMessenger = onCompleteMessage.replyTo; 623 * uiMessenger.send(onCompleteMessage); 624 * } catch (RemoteException e) { 625 * // Remote side is dead 626 * } 627 * } 628 */ setUiTtyMode(int mode, Message onCompleteMessage)629 public void setUiTtyMode(int mode, Message onCompleteMessage) { 630 // Base Implementation - Should be overridden 631 } 632 setSmsListener(IImsSmsListener listener)633 private void setSmsListener(IImsSmsListener listener) { 634 getSmsImplementation().registerSmsListener(listener); 635 } 636 sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, byte[] pdu)637 private void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, 638 byte[] pdu) { 639 getSmsImplementation().sendSms(token, messageRef, format, smsc, isRetry, pdu); 640 } 641 acknowledgeSms(int token, int messageRef, @ImsSmsImplBase.DeliverStatusResult int result)642 private void acknowledgeSms(int token, int messageRef, 643 @ImsSmsImplBase.DeliverStatusResult int result) { 644 getSmsImplementation().acknowledgeSms(token, messageRef, result); 645 } 646 acknowledgeSmsReport(int token, int messageRef, @ImsSmsImplBase.StatusReportResult int result)647 private void acknowledgeSmsReport(int token, int messageRef, 648 @ImsSmsImplBase.StatusReportResult int result) { 649 getSmsImplementation().acknowledgeSmsReport(token, messageRef, result); 650 } 651 onSmsReady()652 private void onSmsReady() { 653 getSmsImplementation().onReady(); 654 } 655 656 /** 657 * Must be overridden by IMS Provider to be able to support SMS over IMS. Otherwise a default 658 * non-functional implementation is returned. 659 * 660 * @return an instance of {@link ImsSmsImplBase} which should be implemented by the IMS 661 * Provider. 662 */ getSmsImplementation()663 public ImsSmsImplBase getSmsImplementation() { 664 return new ImsSmsImplBase(); 665 } 666 getSmsFormat()667 private String getSmsFormat() { 668 return getSmsImplementation().getSmsFormat(); 669 } 670 671 /**{@inheritDoc}*/ 672 @Override onFeatureRemoved()673 public void onFeatureRemoved() { 674 // Base Implementation - Should be overridden 675 } 676 677 /**{@inheritDoc}*/ 678 @Override onFeatureReady()679 public void onFeatureReady() { 680 // Base Implementation - Should be overridden 681 } 682 683 /** 684 * @hide 685 */ 686 @Override getBinder()687 public final IImsMmTelFeature getBinder() { 688 return mImsMMTelBinder; 689 } 690 } 691