1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package android.telephony.ims.stub; 18 19 import android.annotation.IntDef; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 import android.annotation.SystemApi; 23 import android.os.Bundle; 24 import android.os.Message; 25 import android.os.RemoteException; 26 import android.telephony.ims.ImsCallProfile; 27 import android.telephony.ims.ImsCallSession; 28 import android.telephony.ims.ImsCallSessionListener; 29 import android.telephony.ims.ImsReasonInfo; 30 import android.telephony.ims.ImsStreamMediaProfile; 31 import android.telephony.ims.ImsVideoCallProvider; 32 import android.telephony.ims.RtpHeaderExtension; 33 import android.telephony.ims.RtpHeaderExtensionType; 34 import android.telephony.ims.aidl.IImsCallSessionListener; 35 import android.util.ArraySet; 36 import android.util.Log; 37 38 import com.android.ims.internal.IImsCallSession; 39 import com.android.ims.internal.IImsVideoCallProvider; 40 import com.android.internal.telephony.util.TelephonyUtils; 41 42 import java.lang.annotation.Retention; 43 import java.lang.annotation.RetentionPolicy; 44 import java.util.List; 45 import java.util.Set; 46 import java.util.concurrent.CancellationException; 47 import java.util.concurrent.CompletableFuture; 48 import java.util.concurrent.CompletionException; 49 import java.util.concurrent.ExecutionException; 50 import java.util.concurrent.Executor; 51 import java.util.function.Supplier; 52 53 /** 54 * Base implementation of IImsCallSession, which implements stub versions of the methods available. 55 * 56 * Override the methods that your implementation of ImsCallSession supports. 57 * 58 * @hide 59 */ 60 @SystemApi 61 // DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you 62 // will break other implementations of ImsCallSession maintained by other ImsServices. 63 public class ImsCallSessionImplBase implements AutoCloseable { 64 65 private static final String LOG_TAG = "ImsCallSessionImplBase"; 66 /** 67 * Notify USSD Mode. 68 */ 69 public static final int USSD_MODE_NOTIFY = 0; 70 /** 71 * Request USSD Mode 72 */ 73 public static final int USSD_MODE_REQUEST = 1; 74 75 /** @hide */ 76 @IntDef( 77 prefix = "MEDIA_STREAM_TYPE_", 78 value = { 79 MEDIA_STREAM_TYPE_AUDIO, 80 MEDIA_STREAM_TYPE_VIDEO 81 }) 82 @Retention(RetentionPolicy.SOURCE) 83 public @interface MediaStreamType {} 84 85 /** 86 * Media Stream Type - Audio 87 * @hide 88 */ 89 public static final int MEDIA_STREAM_TYPE_AUDIO = 1; 90 /** 91 * Media Stream Type - Video 92 * @hide 93 */ 94 public static final int MEDIA_STREAM_TYPE_VIDEO = 2; 95 96 /** @hide */ 97 @IntDef( 98 prefix = "MEDIA_STREAM_DIRECTION_", 99 value = { 100 MEDIA_STREAM_DIRECTION_UPLINK, 101 MEDIA_STREAM_DIRECTION_DOWNLINK 102 }) 103 @Retention(RetentionPolicy.SOURCE) 104 public @interface MediaStreamDirection {} 105 106 /** 107 * Media Stream Direction - Uplink 108 * @hide 109 */ 110 public static final int MEDIA_STREAM_DIRECTION_UPLINK = 1; 111 /** 112 * Media Stream Direction - Downlink 113 * @hide 114 */ 115 public static final int MEDIA_STREAM_DIRECTION_DOWNLINK = 2; 116 117 /** 118 * Defines IMS call session state. 119 */ 120 public static class State { 121 public static final int IDLE = 0; 122 public static final int INITIATED = 1; 123 public static final int NEGOTIATING = 2; 124 public static final int ESTABLISHING = 3; 125 public static final int ESTABLISHED = 4; 126 127 public static final int RENEGOTIATING = 5; 128 public static final int REESTABLISHING = 6; 129 130 public static final int TERMINATING = 7; 131 public static final int TERMINATED = 8; 132 133 public static final int INVALID = (-1); 134 135 /** 136 * Converts the state to string. 137 */ toString(int state)138 public static String toString(int state) { 139 switch (state) { 140 case IDLE: 141 return "IDLE"; 142 case INITIATED: 143 return "INITIATED"; 144 case NEGOTIATING: 145 return "NEGOTIATING"; 146 case ESTABLISHING: 147 return "ESTABLISHING"; 148 case ESTABLISHED: 149 return "ESTABLISHED"; 150 case RENEGOTIATING: 151 return "RENEGOTIATING"; 152 case REESTABLISHING: 153 return "REESTABLISHING"; 154 case TERMINATING: 155 return "TERMINATING"; 156 case TERMINATED: 157 return "TERMINATED"; 158 default: 159 return "UNKNOWN"; 160 } 161 } 162 163 /** 164 * @hide 165 */ State()166 private State() { 167 } 168 } 169 170 private Executor mExecutor = Runnable::run; 171 172 // Non-final for injection by tests 173 private IImsCallSession mServiceImpl = new IImsCallSession.Stub() { 174 @Override 175 public void close() { 176 executeMethodAsync(() -> ImsCallSessionImplBase.this.close(), "close"); 177 } 178 179 @Override 180 public String getCallId() { 181 return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallId(), 182 "getCallId"); 183 } 184 185 @Override 186 public ImsCallProfile getCallProfile() { 187 return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallProfile(), 188 "getCallProfile"); 189 } 190 191 @Override 192 public ImsCallProfile getLocalCallProfile() { 193 return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this 194 .getLocalCallProfile(), "getLocalCallProfile"); 195 } 196 197 @Override 198 public ImsCallProfile getRemoteCallProfile() { 199 return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this 200 .getRemoteCallProfile(), "getRemoteCallProfile"); 201 } 202 203 @Override 204 public String getProperty(String name) { 205 return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getProperty(name), 206 "getProperty"); 207 } 208 209 @Override 210 public int getState() { 211 return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getState(), 212 "getState"); 213 } 214 215 @Override 216 public boolean isInCall() { 217 return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isInCall(), 218 "isInCall"); 219 } 220 221 @Override 222 public void setListener(IImsCallSessionListener listener) { 223 ImsCallSessionListener iCSL = new ImsCallSessionListener(listener); 224 iCSL.setDefaultExecutor(mExecutor); 225 executeMethodAsync(() -> ImsCallSessionImplBase.this.setListener(iCSL), "setListener"); 226 } 227 228 @Override 229 public void setMute(boolean muted) { 230 executeMethodAsync(() -> ImsCallSessionImplBase.this.setMute(muted), "setMute"); 231 } 232 233 @Override 234 public void start(String callee, ImsCallProfile profile) { 235 executeMethodAsync(() -> ImsCallSessionImplBase.this.start(callee, profile), "start"); 236 } 237 238 @Override 239 public void startConference(String[] participants, ImsCallProfile profile) throws 240 RemoteException { 241 executeMethodAsync(() -> ImsCallSessionImplBase.this.startConference(participants, 242 profile), "startConference"); 243 } 244 245 @Override 246 public void accept(int callType, ImsStreamMediaProfile profile) { 247 executeMethodAsync(() -> ImsCallSessionImplBase.this.accept(callType, profile), 248 "accept"); 249 } 250 251 @Override 252 public void deflect(String deflectNumber) { 253 executeMethodAsync(() -> ImsCallSessionImplBase.this.deflect(deflectNumber), 254 "deflect"); 255 } 256 257 @Override 258 public void reject(int reason) { 259 executeMethodAsync(() -> ImsCallSessionImplBase.this.reject(reason), "reject"); 260 } 261 262 @Override 263 public void transfer(@NonNull String number, boolean isConfirmationRequired) { 264 executeMethodAsync(() -> ImsCallSessionImplBase.this.transfer(number, 265 isConfirmationRequired), "transfer"); 266 } 267 268 @Override 269 public void consultativeTransfer(@NonNull IImsCallSession transferToSession) { 270 executeMethodAsync(() -> { 271 ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase(); 272 otherSession.setServiceImpl(transferToSession); 273 ImsCallSessionImplBase.this.transfer(otherSession); 274 }, "consultativeTransfer"); 275 } 276 277 @Override 278 public void terminate(int reason) { 279 executeMethodAsync(() -> ImsCallSessionImplBase.this.terminate(reason), "terminate"); 280 } 281 282 @Override 283 public void hold(ImsStreamMediaProfile profile) { 284 executeMethodAsync(() -> ImsCallSessionImplBase.this.hold(profile), "hold"); 285 } 286 287 @Override 288 public void resume(ImsStreamMediaProfile profile) { 289 executeMethodAsync(() -> ImsCallSessionImplBase.this.resume(profile), "resume"); 290 } 291 292 @Override 293 public void merge() { 294 executeMethodAsync(() -> ImsCallSessionImplBase.this.merge(), "merge"); 295 } 296 297 @Override 298 public void update(int callType, ImsStreamMediaProfile profile) { 299 executeMethodAsync(() -> ImsCallSessionImplBase.this.update(callType, profile), 300 "update"); 301 } 302 303 @Override 304 public void extendToConference(String[] participants) { 305 executeMethodAsync(() -> ImsCallSessionImplBase.this.extendToConference(participants), 306 "extendToConference"); 307 } 308 309 @Override 310 public void inviteParticipants(String[] participants) { 311 executeMethodAsync(() -> ImsCallSessionImplBase.this.inviteParticipants(participants), 312 "inviteParticipants"); 313 } 314 315 @Override 316 public void removeParticipants(String[] participants) { 317 executeMethodAsync(() -> ImsCallSessionImplBase.this.removeParticipants(participants), 318 "removeParticipants"); 319 } 320 321 @Override 322 public void sendDtmf(char c, Message result) { 323 executeMethodAsync(() -> ImsCallSessionImplBase.this.sendDtmf(c, result), "sendDtmf"); 324 } 325 326 @Override 327 public void startDtmf(char c) { 328 executeMethodAsync(() -> ImsCallSessionImplBase.this.startDtmf(c), "startDtmf"); 329 } 330 331 @Override 332 public void stopDtmf() { 333 executeMethodAsync(() -> ImsCallSessionImplBase.this.stopDtmf(), "stopDtmf"); 334 } 335 336 @Override 337 public void sendUssd(String ussdMessage) { 338 executeMethodAsync(() -> ImsCallSessionImplBase.this.sendUssd(ussdMessage), "sendUssd"); 339 } 340 341 @Override 342 public IImsVideoCallProvider getVideoCallProvider() { 343 return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this 344 .getVideoCallProvider(), "getVideoCallProvider"); 345 } 346 347 @Override 348 public boolean isMultiparty() { 349 return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isMultiparty(), 350 "isMultiparty"); 351 } 352 353 @Override 354 public void sendRttModifyRequest(ImsCallProfile toProfile) { 355 executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile), 356 "sendRttModifyRequest"); 357 } 358 359 @Override 360 public void sendRttModifyResponse(boolean status) { 361 executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyResponse(status), 362 "sendRttModifyResponse"); 363 } 364 365 @Override 366 public void sendRttMessage(String rttMessage) { 367 executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttMessage(rttMessage), 368 "sendRttMessage"); 369 } 370 371 @Override 372 public void sendRtpHeaderExtensions(@NonNull List<RtpHeaderExtension> extensions) { 373 executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRtpHeaderExtensions( 374 new ArraySet<RtpHeaderExtension>(extensions)), "sendRtpHeaderExtensions"); 375 } 376 377 @Override 378 public void callSessionNotifyAnbr(int mediaType, int direction, int bitsPerSecond) { 379 executeMethodAsync(() -> ImsCallSessionImplBase.this.callSessionNotifyAnbr( 380 mediaType, direction, bitsPerSecond), "callSessionNotifyAnbr"); 381 } 382 383 // Call the methods with a clean calling identity on the executor and wait indefinitely for 384 // the future to return. 385 private void executeMethodAsync(Runnable r, String errorLogName) { 386 try { 387 CompletableFuture.runAsync( 388 () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); 389 } catch (CancellationException | CompletionException e) { 390 Log.w(LOG_TAG, "ImsCallSessionImplBase Binder - " + errorLogName + " exception: " 391 + e.getMessage()); 392 } 393 } 394 395 private <T> T executeMethodAsyncForResult(Supplier<T> r, 396 String errorLogName) { 397 CompletableFuture<T> future = CompletableFuture.supplyAsync( 398 () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); 399 try { 400 return future.get(); 401 } catch (ExecutionException | InterruptedException e) { 402 Log.w(LOG_TAG, "ImsCallSessionImplBase Binder - " + errorLogName + " exception: " 403 + e.getMessage()); 404 return null; 405 } 406 } 407 }; 408 409 /** 410 * @hide 411 */ setListener(IImsCallSessionListener listener)412 public final void setListener(IImsCallSessionListener listener) throws RemoteException { 413 setListener(new ImsCallSessionListener(listener)); 414 } 415 416 /** 417 * Sets the listener to listen to the session events. An {@link ImsCallSession} 418 * can only hold one listener at a time. Subsequent calls to this method 419 * override the previous listener. 420 * 421 * @param listener {@link ImsCallSessionListener} used to notify the framework of updates 422 * to the ImsCallSession 423 424 * @deprecated use {@link android.telephony.ims.feature.MmTelFeature#notifyIncomingCall( 425 * ImsCallSessionImplBase, String, Bundle)} to get the listener instead 426 */ 427 @Deprecated setListener(ImsCallSessionListener listener)428 public void setListener(ImsCallSessionListener listener) { 429 } 430 431 /** 432 * Closes the object. This {@link ImsCallSessionImplBase} is not usable after being closed. 433 */ 434 @Override close()435 public void close() { 436 437 } 438 439 /** 440 * @return A String containing the unique call ID of this {@link ImsCallSessionImplBase}. 441 */ getCallId()442 public String getCallId() { 443 return null; 444 } 445 446 /** 447 * @return The {@link ImsCallProfile} that this {@link ImsCallSessionImplBase} is associated 448 * with. 449 */ getCallProfile()450 public ImsCallProfile getCallProfile() { 451 return null; 452 } 453 454 /** 455 * @return The local {@link ImsCallProfile} that this {@link ImsCallSessionImplBase} is 456 * associated with. 457 */ getLocalCallProfile()458 public ImsCallProfile getLocalCallProfile() { 459 return null; 460 } 461 462 /** 463 * @return The remote {@link ImsCallProfile} that this {@link ImsCallSessionImplBase} is 464 * associated with. 465 */ getRemoteCallProfile()466 public ImsCallProfile getRemoteCallProfile() { 467 return null; 468 } 469 470 /** 471 * @param name The String extra key. 472 * @return The string extra value associated with the specified property. 473 */ getProperty(String name)474 public String getProperty(String name) { 475 return null; 476 } 477 478 /** 479 * @return The {@link ImsCallSessionImplBase} state, defined in 480 * {@link ImsCallSessionImplBase.State}. 481 */ getState()482 public int getState() { 483 return ImsCallSessionImplBase.State.INVALID; 484 } 485 486 /** 487 * @return true if the {@link ImsCallSessionImplBase} is in a call, false otherwise. 488 */ isInCall()489 public boolean isInCall() { 490 return false; 491 } 492 493 /** 494 * Mutes or unmutes the mic for the active call. 495 * 496 * @param muted true if the call should be muted, false otherwise. 497 */ setMute(boolean muted)498 public void setMute(boolean muted) { 499 } 500 501 /** 502 * Initiates an IMS call with the specified number and call profile. 503 * The session listener set in {@link #setListener(ImsCallSessionListener)} is called back upon 504 * defined session events. 505 * Only valid to call when the session state is in 506 * {@link ImsCallSession.State#IDLE}. 507 * 508 * @param callee dialed string to make the call to 509 * @param profile call profile to make the call with the specified service type, 510 * call type and media information 511 * @see {@link ImsCallSession.Listener#callSessionStarted}, 512 * {@link ImsCallSession.Listener#callSessionStartFailed} 513 */ start(String callee, ImsCallProfile profile)514 public void start(String callee, ImsCallProfile profile) { 515 } 516 517 /** 518 * Initiates an IMS call with the specified participants and call profile. 519 * The session listener set in {@link #setListener(ImsCallSessionListener)} is called back upon 520 * defined session events. 521 * The method is only valid to call when the session state is in 522 * {@link ImsCallSession.State#IDLE}. 523 * 524 * @param participants participant list to initiate an IMS conference call 525 * @param profile call profile to make the call with the specified service type, 526 * call type and media information 527 * @see {@link ImsCallSession.Listener#callSessionStarted}, 528 * {@link ImsCallSession.Listener#callSessionStartFailed} 529 */ startConference(String[] participants, ImsCallProfile profile)530 public void startConference(String[] participants, ImsCallProfile profile) { 531 } 532 533 /** 534 * Accepts an incoming call or session update. 535 * 536 * @param callType call type specified in {@link ImsCallProfile} to be answered 537 * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered 538 * @see {@link ImsCallSession.Listener#callSessionStarted} 539 */ accept(int callType, ImsStreamMediaProfile profile)540 public void accept(int callType, ImsStreamMediaProfile profile) { 541 } 542 543 /** 544 * Deflects an incoming call. 545 * 546 * @param deflectNumber number to deflect the call 547 */ deflect(String deflectNumber)548 public void deflect(String deflectNumber) { 549 } 550 551 /** 552 * Rejects an incoming call or session update. 553 * 554 * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}. 555 * The {@link android.telecom.InCallService} (dialer app) can use the 556 * {@link android.telecom.Call#reject(int)} API to reject a call while specifying 557 * a user-indicated reason for rejecting the call. 558 * Normal call declines ({@link android.telecom.Call#REJECT_REASON_DECLINED}) will 559 * map to {@link ImsReasonInfo#CODE_USER_DECLINE}. 560 * Unwanted calls ({@link android.telecom.Call#REJECT_REASON_UNWANTED}) will map 561 * to {@link ImsReasonInfo#CODE_SIP_USER_MARKED_UNWANTED}. 562 * {@link ImsCallSession.Listener#callSessionStartFailed} 563 */ reject(int reason)564 public void reject(int reason) { 565 } 566 567 /** 568 * Transfer an established call to given number 569 * 570 * @param number number to transfer the call 571 * @param isConfirmationRequired if {@code True}, indicates a confirmed transfer, 572 * if {@code False} it indicates an unconfirmed transfer. 573 * @hide 574 */ transfer(@onNull String number, boolean isConfirmationRequired)575 public void transfer(@NonNull String number, boolean isConfirmationRequired) { 576 } 577 578 /** 579 * Transfer an established call to another call session 580 * 581 * @param otherSession The other ImsCallSession to transfer the ongoing session to. 582 * @hide 583 */ transfer(@onNull ImsCallSessionImplBase otherSession)584 public void transfer(@NonNull ImsCallSessionImplBase otherSession) { 585 } 586 587 /** 588 * Terminates a call. 589 * 590 * @param reason reason code to terminate a call, defined in {@link ImsReasonInfo}. 591 * 592 * @see {@link ImsCallSession.Listener#callSessionTerminated} 593 */ terminate(int reason)594 public void terminate(int reason) { 595 } 596 597 /** 598 * Puts a call on hold. When it succeeds, {@link ImsCallSession.Listener#callSessionHeld} is 599 * called. 600 * 601 * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call 602 * @see {@link ImsCallSession.Listener#callSessionHeld}, 603 * {@link ImsCallSession.Listener#callSessionHoldFailed} 604 */ hold(ImsStreamMediaProfile profile)605 public void hold(ImsStreamMediaProfile profile) { 606 } 607 608 /** 609 * Continues a call that's on hold. When it succeeds, 610 * {@link ImsCallSession.Listener#callSessionResumed} is called. 611 * 612 * @param profile stream media profile with {@link ImsStreamMediaProfile} to resume the call 613 * @see {@link ImsCallSession.Listener#callSessionResumed}, 614 * {@link ImsCallSession.Listener#callSessionResumeFailed} 615 */ resume(ImsStreamMediaProfile profile)616 public void resume(ImsStreamMediaProfile profile) { 617 } 618 619 /** 620 * Merges the active and held call. When the merge starts, 621 * {@link ImsCallSession.Listener#callSessionMergeStarted} is called. 622 * {@link ImsCallSession.Listener#callSessionMergeComplete} is called if the merge is 623 * successful, and {@link ImsCallSession.Listener#callSessionMergeFailed} is called if the merge 624 * fails. 625 * 626 * @see {@link ImsCallSession.Listener#callSessionMergeStarted}, 627 * {@link ImsCallSession.Listener#callSessionMergeComplete}, 628 * {@link ImsCallSession.Listener#callSessionMergeFailed} 629 */ merge()630 public void merge() { 631 } 632 633 /** 634 * Updates the current call's properties (ex. call mode change: video upgrade / downgrade). 635 * 636 * @param callType call type specified in {@link ImsCallProfile} to be updated 637 * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated 638 * @see {@link ImsCallSession.Listener#callSessionUpdated}, 639 * {@link ImsCallSession.Listener#callSessionUpdateFailed} 640 */ update(int callType, ImsStreamMediaProfile profile)641 public void update(int callType, ImsStreamMediaProfile profile) { 642 } 643 644 /** 645 * Extends this call to the conference call with the specified recipients. 646 * 647 * @param participants participant list to be invited to the conference call after extending the 648 * call 649 * @see {@link ImsCallSession.Listener#callSessionConferenceExtended}, 650 * {@link ImsCallSession.Listener#callSessionConferenceExtendFailed} 651 */ extendToConference(String[] participants)652 public void extendToConference(String[] participants) { 653 } 654 655 /** 656 * Requests the conference server to invite an additional participants to the conference. 657 * 658 * @param participants participant list to be invited to the conference call 659 * @see {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestDelivered}, 660 * {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestFailed} 661 */ inviteParticipants(String[] participants)662 public void inviteParticipants(String[] participants) { 663 } 664 665 /** 666 * Requests the conference server to remove the specified participants from the conference. 667 * 668 * @param participants participant list to be removed from the conference call 669 * @see {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestDelivered}, 670 * {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestFailed} 671 */ removeParticipants(String[] participants)672 public void removeParticipants(String[] participants) { 673 } 674 675 /** 676 * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>, 677 * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15, 678 * and event flash to 16. Currently, event flash is not supported. 679 * 680 * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs. 681 * @param result If non-null, the {@link Message} to send when the operation is complete. This 682 * is done by using the associated {@link android.os.Messenger} in 683 * {@link Message#replyTo}. For example: 684 * {@code 685 * // Send DTMF and other operations... 686 * try { 687 * // Notify framework that the DTMF was sent. 688 * Messenger dtmfMessenger = result.replyTo; 689 * if (dtmfMessenger != null) { 690 * dtmfMessenger.send(result); 691 * } 692 * } catch (RemoteException e) { 693 * // Remote side is dead 694 * } 695 * } 696 */ sendDtmf(char c, Message result)697 public void sendDtmf(char c, Message result) { 698 } 699 700 /** 701 * Start a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>, 702 * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15, 703 * and event flash to 16. Currently, event flash is not supported. 704 * 705 * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs. 706 */ startDtmf(char c)707 public void startDtmf(char c) { 708 } 709 710 /** 711 * Stop a DTMF code. 712 */ stopDtmf()713 public void stopDtmf() { 714 } 715 716 /** 717 * Sends an USSD message. 718 * 719 * @param ussdMessage USSD message to send 720 */ sendUssd(String ussdMessage)721 public void sendUssd(String ussdMessage) { 722 } 723 724 /** 725 * See {@link #getImsVideoCallProvider()}, used directly in older ImsService implementations. 726 * @hide 727 */ getVideoCallProvider()728 public IImsVideoCallProvider getVideoCallProvider() { 729 ImsVideoCallProvider provider = getImsVideoCallProvider(); 730 return provider != null ? provider.getInterface() : null; 731 } 732 733 /** 734 * @return The {@link ImsVideoCallProvider} implementation contained within the IMS service 735 * process. 736 */ getImsVideoCallProvider()737 public ImsVideoCallProvider getImsVideoCallProvider() { 738 return null; 739 } 740 741 /** 742 * Determines if the current session is multiparty. 743 * @return {@code True} if the session is multiparty. 744 */ isMultiparty()745 public boolean isMultiparty() { 746 return false; 747 } 748 749 /** 750 * Device issues RTT modify request 751 * @param toProfile The profile with requested changes made 752 */ sendRttModifyRequest(ImsCallProfile toProfile)753 public void sendRttModifyRequest(ImsCallProfile toProfile) { 754 } 755 756 /** 757 * Device responds to Remote RTT modify request 758 * @param status true if the the request was accepted or false of the request is defined. 759 */ sendRttModifyResponse(boolean status)760 public void sendRttModifyResponse(boolean status) { 761 } 762 763 /** 764 * Device sends RTT message 765 * @param rttMessage RTT message to be sent 766 */ sendRttMessage(String rttMessage)767 public void sendRttMessage(String rttMessage) { 768 } 769 770 /** 771 * Device requests that {@code rtpHeaderExtensions} are sent as a header extension with the next 772 * RTP packet sent by the IMS stack. 773 * <p> 774 * The {@link RtpHeaderExtensionType}s negotiated during SDP (Session Description Protocol) 775 * signalling determine the {@link RtpHeaderExtension}s which can be sent using this method. 776 * See RFC8285 for more information. 777 * <p> 778 * By specification, the RTP header extension is an unacknowledged transmission and there is no 779 * guarantee that the header extension will be delivered by the network to the other end of the 780 * call. 781 * @param rtpHeaderExtensions The RTP header extensions to be included in the next RTP header. 782 */ sendRtpHeaderExtensions(@onNull Set<RtpHeaderExtension> rtpHeaderExtensions)783 public void sendRtpHeaderExtensions(@NonNull Set<RtpHeaderExtension> rtpHeaderExtensions) { 784 } 785 786 /** 787 * Deliver the bitrate for the indicated media type, direction and bitrate to the upper layer. 788 * 789 * @param mediaType MediaType is used to identify media stream such as audio or video. 790 * @param direction Direction of this packet stream (e.g. uplink or downlink). 791 * @param bitsPerSecond This value is the bitrate received from the NW through the Recommended 792 * bitrate MAC Control Element message and ImsStack converts this value from MAC bitrate 793 * to audio/video codec bitrate (defined in TS26.114). 794 * @hide 795 */ callSessionNotifyAnbr(@ediaStreamType int mediaType, @MediaStreamDirection int direction, @IntRange(from = 0) int bitsPerSecond)796 public void callSessionNotifyAnbr(@MediaStreamType int mediaType, 797 @MediaStreamDirection int direction, @IntRange(from = 0) int bitsPerSecond) { 798 // Base Implementation - Should be overridden by IMS service 799 Log.i(LOG_TAG, "ImsCallSessionImplBase callSessionNotifyAnbr - mediaType: " + mediaType); 800 } 801 802 /** @hide */ getServiceImpl()803 public IImsCallSession getServiceImpl() { 804 return mServiceImpl; 805 } 806 807 /** @hide */ setServiceImpl(IImsCallSession serviceImpl)808 public void setServiceImpl(IImsCallSession serviceImpl) { 809 mServiceImpl = serviceImpl; 810 } 811 812 /** 813 * Set default Executor from MmTelFeature. 814 * @param executor The default executor for the framework to use when executing the methods 815 * overridden by the implementation of ImsCallSession. 816 * @hide 817 */ setDefaultExecutor(@onNull Executor executor)818 public final void setDefaultExecutor(@NonNull Executor executor) { 819 mExecutor = executor; 820 } 821 } 822