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; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.os.Message; 22 import android.os.RemoteException; 23 import android.telephony.CallQuality; 24 import android.telephony.ims.aidl.IImsCallSessionListener; 25 import android.util.ArraySet; 26 import android.util.Log; 27 28 import com.android.ims.internal.IImsCallSession; 29 import com.android.ims.internal.IImsVideoCallProvider; 30 import com.android.internal.telephony.util.TelephonyUtils; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.Set; 35 import java.util.concurrent.Executor; 36 37 /** 38 * Provides the call initiation/termination, and media exchange between two IMS endpoints. 39 * It directly communicates with IMS service which implements the IMS protocol behavior. 40 * 41 * @hide 42 */ 43 public class ImsCallSession { 44 private static final String TAG = "ImsCallSession"; 45 46 /** 47 * Defines IMS call session state. Please use 48 * {@link android.telephony.ims.stub.ImsCallSessionImplBase.State} definition. 49 * This is kept around for capability reasons. 50 */ 51 public static class State { 52 public static final int IDLE = 0; 53 public static final int INITIATED = 1; 54 public static final int NEGOTIATING = 2; 55 public static final int ESTABLISHING = 3; 56 public static final int ESTABLISHED = 4; 57 58 public static final int RENEGOTIATING = 5; 59 public static final int REESTABLISHING = 6; 60 61 public static final int TERMINATING = 7; 62 public static final int TERMINATED = 8; 63 64 public static final int INVALID = (-1); 65 66 /** 67 * Converts the state to string. 68 */ toString(int state)69 public static String toString(int state) { 70 switch (state) { 71 case IDLE: 72 return "IDLE"; 73 case INITIATED: 74 return "INITIATED"; 75 case NEGOTIATING: 76 return "NEGOTIATING"; 77 case ESTABLISHING: 78 return "ESTABLISHING"; 79 case ESTABLISHED: 80 return "ESTABLISHED"; 81 case RENEGOTIATING: 82 return "RENEGOTIATING"; 83 case REESTABLISHING: 84 return "REESTABLISHING"; 85 case TERMINATING: 86 return "TERMINATING"; 87 case TERMINATED: 88 return "TERMINATED"; 89 default: 90 return "UNKNOWN"; 91 } 92 } 93 State()94 private State() { 95 } 96 } 97 98 /** 99 * Listener for events relating to an IMS session, such as when a session is being 100 * recieved ("on ringing") or a call is outgoing ("on calling"). 101 * <p>Many of these events are also received by {@link ImsCall.Listener}.</p> 102 * @hide 103 */ 104 public static class Listener { 105 /** 106 * Called when the session is initiating. 107 * 108 * see: {@link ImsCallSessionListener#callSessionInitiating(ImsCallProfile)} 109 */ callSessionInitiating(ImsCallSession session, ImsCallProfile profile)110 public void callSessionInitiating(ImsCallSession session, 111 ImsCallProfile profile) { 112 // no-op 113 } 114 115 /** 116 * Called when the session failed before initiating was called. 117 * 118 * see: {@link ImsCallSessionListener#callSessionInitiatingFailed(ImsReasonInfo)} 119 */ callSessionInitiatingFailed(ImsCallSession session, ImsReasonInfo reasonInfo)120 public void callSessionInitiatingFailed(ImsCallSession session, 121 ImsReasonInfo reasonInfo) { 122 // no-op 123 } 124 125 /** 126 * Called when the session is progressing. 127 * 128 * see: {@link ImsCallSessionListener#callSessionProgressing(ImsStreamMediaProfile)} 129 */ callSessionProgressing(ImsCallSession session, ImsStreamMediaProfile profile)130 public void callSessionProgressing(ImsCallSession session, 131 ImsStreamMediaProfile profile) { 132 // no-op 133 } 134 135 /** 136 * Called when the session is established. 137 * 138 * @param session the session object that carries out the IMS session 139 */ callSessionStarted(ImsCallSession session, ImsCallProfile profile)140 public void callSessionStarted(ImsCallSession session, 141 ImsCallProfile profile) { 142 // no-op 143 } 144 145 /** 146 * Called when the session establishment is failed. 147 * 148 * @param session the session object that carries out the IMS session 149 * @param reasonInfo detailed reason of the session establishment failure 150 */ callSessionStartFailed(ImsCallSession session, ImsReasonInfo reasonInfo)151 public void callSessionStartFailed(ImsCallSession session, 152 ImsReasonInfo reasonInfo) { 153 } 154 155 /** 156 * Called when the session is terminated. 157 * 158 * @param session the session object that carries out the IMS session 159 * @param reasonInfo detailed reason of the session termination 160 */ callSessionTerminated(ImsCallSession session, ImsReasonInfo reasonInfo)161 public void callSessionTerminated(ImsCallSession session, 162 ImsReasonInfo reasonInfo) { 163 } 164 165 /** 166 * Called when the session is in hold. 167 * 168 * @param session the session object that carries out the IMS session 169 */ callSessionHeld(ImsCallSession session, ImsCallProfile profile)170 public void callSessionHeld(ImsCallSession session, 171 ImsCallProfile profile) { 172 } 173 174 /** 175 * Called when the session hold is failed. 176 * 177 * @param session the session object that carries out the IMS session 178 * @param reasonInfo detailed reason of the session hold failure 179 */ callSessionHoldFailed(ImsCallSession session, ImsReasonInfo reasonInfo)180 public void callSessionHoldFailed(ImsCallSession session, 181 ImsReasonInfo reasonInfo) { 182 } 183 184 /** 185 * Called when the session hold is received from the remote user. 186 * 187 * @param session the session object that carries out the IMS session 188 */ callSessionHoldReceived(ImsCallSession session, ImsCallProfile profile)189 public void callSessionHoldReceived(ImsCallSession session, 190 ImsCallProfile profile) { 191 } 192 193 /** 194 * Called when the session resume is done. 195 * 196 * @param session the session object that carries out the IMS session 197 */ callSessionResumed(ImsCallSession session, ImsCallProfile profile)198 public void callSessionResumed(ImsCallSession session, 199 ImsCallProfile profile) { 200 } 201 202 /** 203 * Called when the session resume is failed. 204 * 205 * @param session the session object that carries out the IMS session 206 * @param reasonInfo detailed reason of the session resume failure 207 */ callSessionResumeFailed(ImsCallSession session, ImsReasonInfo reasonInfo)208 public void callSessionResumeFailed(ImsCallSession session, 209 ImsReasonInfo reasonInfo) { 210 } 211 212 /** 213 * Called when the session resume is received from the remote user. 214 * 215 * @param session the session object that carries out the IMS session 216 */ callSessionResumeReceived(ImsCallSession session, ImsCallProfile profile)217 public void callSessionResumeReceived(ImsCallSession session, 218 ImsCallProfile profile) { 219 } 220 221 /** 222 * Called when the session merge has been started. At this point, the {@code newSession} 223 * represents the session which has been initiated to the IMS conference server for the 224 * new merged conference. 225 * 226 * @param session the session object that carries out the IMS session 227 * @param newSession the session object that is merged with an active & hold session 228 */ callSessionMergeStarted(ImsCallSession session, ImsCallSession newSession, ImsCallProfile profile)229 public void callSessionMergeStarted(ImsCallSession session, 230 ImsCallSession newSession, ImsCallProfile profile) { 231 } 232 233 /** 234 * Called when the session merge is successful and the merged session is active. 235 * 236 * @param session the session object that carries out the IMS session 237 */ callSessionMergeComplete(ImsCallSession session)238 public void callSessionMergeComplete(ImsCallSession session) { 239 } 240 241 /** 242 * Called when the session merge has failed. 243 * 244 * @param session the session object that carries out the IMS session 245 * @param reasonInfo detailed reason of the call merge failure 246 */ callSessionMergeFailed(ImsCallSession session, ImsReasonInfo reasonInfo)247 public void callSessionMergeFailed(ImsCallSession session, 248 ImsReasonInfo reasonInfo) { 249 } 250 251 /** 252 * Called when the session is updated (except for hold/unhold). 253 * 254 * @param session the session object that carries out the IMS session 255 */ callSessionUpdated(ImsCallSession session, ImsCallProfile profile)256 public void callSessionUpdated(ImsCallSession session, 257 ImsCallProfile profile) { 258 } 259 260 /** 261 * Called when the session update is failed. 262 * 263 * @param session the session object that carries out the IMS session 264 * @param reasonInfo detailed reason of the session update failure 265 */ callSessionUpdateFailed(ImsCallSession session, ImsReasonInfo reasonInfo)266 public void callSessionUpdateFailed(ImsCallSession session, 267 ImsReasonInfo reasonInfo) { 268 } 269 270 /** 271 * Called when the session update is received from the remote user. 272 * 273 * @param session the session object that carries out the IMS session 274 */ callSessionUpdateReceived(ImsCallSession session, ImsCallProfile profile)275 public void callSessionUpdateReceived(ImsCallSession session, 276 ImsCallProfile profile) { 277 // no-op 278 } 279 280 /** 281 * Called when the session is extended to the conference session. 282 * 283 * @param session the session object that carries out the IMS session 284 * @param newSession the session object that is extended to the conference 285 * from the active session 286 */ callSessionConferenceExtended(ImsCallSession session, ImsCallSession newSession, ImsCallProfile profile)287 public void callSessionConferenceExtended(ImsCallSession session, 288 ImsCallSession newSession, ImsCallProfile profile) { 289 } 290 291 /** 292 * Called when the conference extension is failed. 293 * 294 * @param session the session object that carries out the IMS session 295 * @param reasonInfo detailed reason of the conference extension failure 296 */ callSessionConferenceExtendFailed(ImsCallSession session, ImsReasonInfo reasonInfo)297 public void callSessionConferenceExtendFailed(ImsCallSession session, 298 ImsReasonInfo reasonInfo) { 299 } 300 301 /** 302 * Called when the conference extension is received from the remote user. 303 * 304 * @param session the session object that carries out the IMS session 305 */ callSessionConferenceExtendReceived(ImsCallSession session, ImsCallSession newSession, ImsCallProfile profile)306 public void callSessionConferenceExtendReceived(ImsCallSession session, 307 ImsCallSession newSession, ImsCallProfile profile) { 308 // no-op 309 } 310 311 /** 312 * Called when the invitation request of the participants is delivered to the conference 313 * server. 314 * 315 * @param session the session object that carries out the IMS session 316 */ callSessionInviteParticipantsRequestDelivered(ImsCallSession session)317 public void callSessionInviteParticipantsRequestDelivered(ImsCallSession session) { 318 // no-op 319 } 320 321 /** 322 * Called when the invitation request of the participants is failed. 323 * 324 * @param session the session object that carries out the IMS session 325 * @param reasonInfo detailed reason of the conference invitation failure 326 */ callSessionInviteParticipantsRequestFailed(ImsCallSession session, ImsReasonInfo reasonInfo)327 public void callSessionInviteParticipantsRequestFailed(ImsCallSession session, 328 ImsReasonInfo reasonInfo) { 329 // no-op 330 } 331 332 /** 333 * Called when the removal request of the participants is delivered to the conference 334 * server. 335 * 336 * @param session the session object that carries out the IMS session 337 */ callSessionRemoveParticipantsRequestDelivered(ImsCallSession session)338 public void callSessionRemoveParticipantsRequestDelivered(ImsCallSession session) { 339 // no-op 340 } 341 342 /** 343 * Called when the removal request of the participants is failed. 344 * 345 * @param session the session object that carries out the IMS session 346 * @param reasonInfo detailed reason of the conference removal failure 347 */ callSessionRemoveParticipantsRequestFailed(ImsCallSession session, ImsReasonInfo reasonInfo)348 public void callSessionRemoveParticipantsRequestFailed(ImsCallSession session, 349 ImsReasonInfo reasonInfo) { 350 // no-op 351 } 352 353 /** 354 * Called when the conference state is updated. 355 * 356 * @param session the session object that carries out the IMS session 357 */ callSessionConferenceStateUpdated(ImsCallSession session, ImsConferenceState state)358 public void callSessionConferenceStateUpdated(ImsCallSession session, 359 ImsConferenceState state) { 360 // no-op 361 } 362 363 /** 364 * Called when the USSD message is received from the network. 365 * 366 * @param mode mode of the USSD message (REQUEST / NOTIFY) 367 * @param ussdMessage USSD message 368 */ callSessionUssdMessageReceived(ImsCallSession session, int mode, String ussdMessage)369 public void callSessionUssdMessageReceived(ImsCallSession session, 370 int mode, String ussdMessage) { 371 // no-op 372 } 373 374 /** 375 * Called when an {@link ImsCallSession} may handover from one network type to another. 376 * For example, the session may handover from WIFI to LTE if conditions are right. 377 * <p> 378 * If handover is attempted, 379 * {@link #callSessionHandover(ImsCallSession, int, int, ImsReasonInfo)} or 380 * {@link #callSessionHandoverFailed(ImsCallSession, int, int, ImsReasonInfo)} will be 381 * called to indicate the success or failure of the handover. 382 * 383 * @param session IMS session object 384 * @param srcNetworkType original network type 385 * @param targetNetworkType new network type 386 */ callSessionMayHandover(ImsCallSession session, int srcNetworkType, int targetNetworkType)387 public void callSessionMayHandover(ImsCallSession session, int srcNetworkType, 388 int targetNetworkType) { 389 // no-op 390 } 391 392 /** 393 * Called when session network type changes 394 * 395 * @param session IMS session object 396 * @param srcNetworkType original network type 397 * @param targetNetworkType new network type 398 * @param reasonInfo 399 */ callSessionHandover(ImsCallSession session, int srcNetworkType, int targetNetworkType, ImsReasonInfo reasonInfo)400 public void callSessionHandover(ImsCallSession session, 401 int srcNetworkType, int targetNetworkType, 402 ImsReasonInfo reasonInfo) { 403 // no-op 404 } 405 406 /** 407 * Called when session access technology change fails 408 * 409 * @param session IMS session object 410 * @param srcNetworkType original access technology 411 * @param targetNetworkType new access technology 412 * @param reasonInfo handover failure reason 413 */ callSessionHandoverFailed(ImsCallSession session, int srcNetworkType, int targetNetworkType, ImsReasonInfo reasonInfo)414 public void callSessionHandoverFailed(ImsCallSession session, 415 int srcNetworkType, int targetNetworkType, 416 ImsReasonInfo reasonInfo) { 417 // no-op 418 } 419 420 /** 421 * Called when TTY mode of remote party changed 422 * 423 * @param session IMS session object 424 * @param mode TTY mode of remote party 425 */ callSessionTtyModeReceived(ImsCallSession session, int mode)426 public void callSessionTtyModeReceived(ImsCallSession session, 427 int mode) { 428 // no-op 429 } 430 431 /** 432 * Notifies of a change to the multiparty state for this {@code ImsCallSession}. 433 * 434 * @param session The call session. 435 * @param isMultiParty {@code true} if the session became multiparty, {@code false} 436 * otherwise. 437 */ callSessionMultipartyStateChanged(ImsCallSession session, boolean isMultiParty)438 public void callSessionMultipartyStateChanged(ImsCallSession session, 439 boolean isMultiParty) { 440 // no-op 441 } 442 443 /** 444 * Called when the session supplementary service is received 445 * 446 * @param session the session object that carries out the IMS session 447 */ callSessionSuppServiceReceived(ImsCallSession session, ImsSuppServiceNotification suppServiceInfo)448 public void callSessionSuppServiceReceived(ImsCallSession session, 449 ImsSuppServiceNotification suppServiceInfo) { 450 } 451 452 /** 453 * Received RTT modify request from Remote Party 454 */ callSessionRttModifyRequestReceived(ImsCallSession session, ImsCallProfile callProfile)455 public void callSessionRttModifyRequestReceived(ImsCallSession session, 456 ImsCallProfile callProfile) { 457 // no-op 458 } 459 460 /** 461 * Received response for RTT modify request 462 */ callSessionRttModifyResponseReceived(int status)463 public void callSessionRttModifyResponseReceived(int status) { 464 // no -op 465 } 466 467 /** 468 * Device received RTT message from Remote UE 469 */ callSessionRttMessageReceived(String rttMessage)470 public void callSessionRttMessageReceived(String rttMessage) { 471 // no-op 472 } 473 474 /** 475 * While in call, there has been a change in RTT audio indicator. 476 */ callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile)477 public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile) { 478 // no-op 479 } 480 481 /** 482 * Received success response for call transfer request. 483 */ callSessionTransferred(@onNull ImsCallSession session)484 public void callSessionTransferred(@NonNull ImsCallSession session) { 485 // no-op 486 } 487 488 /** 489 * Received failure response for call transfer request. 490 */ callSessionTransferFailed(@onNull ImsCallSession session, @Nullable ImsReasonInfo reasonInfo)491 public void callSessionTransferFailed(@NonNull ImsCallSession session, 492 @Nullable ImsReasonInfo reasonInfo) { 493 // no-op 494 } 495 496 /** 497 * Informs the framework of a DTMF digit which was received from the network. 498 * <p> 499 * According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833 sec 3.10</a>, 500 * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 501 * 12 ~ 15. 502 * @param digit the DTMF digit 503 */ callSessionDtmfReceived(char digit)504 public void callSessionDtmfReceived(char digit) { 505 // no-op 506 } 507 508 /** 509 * Called when the IMS service reports a change to the call quality. 510 */ callQualityChanged(CallQuality callQuality)511 public void callQualityChanged(CallQuality callQuality) { 512 // no-op 513 } 514 515 /** 516 * Called when the IMS service reports incoming RTP header extension data. 517 */ callSessionRtpHeaderExtensionsReceived( @onNull Set<RtpHeaderExtension> extensions)518 public void callSessionRtpHeaderExtensionsReceived( 519 @NonNull Set<RtpHeaderExtension> extensions) { 520 // no-op 521 } 522 } 523 524 private final IImsCallSession miSession; 525 private boolean mClosed = false; 526 private Listener mListener; 527 private Executor mListenerExecutor = Runnable::run; 528 529 /** @hide */ ImsCallSession(IImsCallSession iSession)530 public ImsCallSession(IImsCallSession iSession) { 531 miSession = iSession; 532 533 if (iSession != null) { 534 try { 535 iSession.setListener(new IImsCallSessionListenerProxy()); 536 } catch (RemoteException e) { 537 } 538 } else { 539 mClosed = true; 540 } 541 } 542 543 /** @hide */ ImsCallSession(IImsCallSession iSession, Listener listener, Executor executor)544 public ImsCallSession(IImsCallSession iSession, Listener listener, Executor executor) { 545 this(iSession); 546 setListener(listener, executor); 547 } 548 549 /** 550 * Closes this object. This object is not usable after being closed. 551 */ close()552 public void close() { 553 synchronized (this) { 554 if (mClosed) { 555 return; 556 } 557 558 try { 559 miSession.close(); 560 mClosed = true; 561 } catch (RemoteException e) { 562 } 563 } 564 } 565 566 /** 567 * Gets the call ID of the session. 568 * 569 * @return the call ID 570 */ getCallId()571 public String getCallId() { 572 if (mClosed) { 573 return null; 574 } 575 576 try { 577 return miSession.getCallId(); 578 } catch (RemoteException e) { 579 return null; 580 } 581 } 582 583 /** 584 * Gets the call profile that this session is associated with 585 * 586 * @return the call profile that this session is associated with 587 */ getCallProfile()588 public ImsCallProfile getCallProfile() { 589 if (mClosed) { 590 return null; 591 } 592 593 try { 594 return miSession.getCallProfile(); 595 } catch (RemoteException e) { 596 return null; 597 } 598 } 599 600 /** 601 * Gets the local call profile that this session is associated with 602 * 603 * @return the local call profile that this session is associated with 604 */ getLocalCallProfile()605 public ImsCallProfile getLocalCallProfile() { 606 if (mClosed) { 607 return null; 608 } 609 610 try { 611 return miSession.getLocalCallProfile(); 612 } catch (RemoteException e) { 613 return null; 614 } 615 } 616 617 /** 618 * Gets the remote call profile that this session is associated with 619 * 620 * @return the remote call profile that this session is associated with 621 */ getRemoteCallProfile()622 public ImsCallProfile getRemoteCallProfile() { 623 if (mClosed) { 624 return null; 625 } 626 627 try { 628 return miSession.getRemoteCallProfile(); 629 } catch (RemoteException e) { 630 return null; 631 } 632 } 633 634 /** 635 * Gets the video call provider for the session. 636 * 637 * @return The video call provider. 638 * @hide 639 */ getVideoCallProvider()640 public IImsVideoCallProvider getVideoCallProvider() { 641 if (mClosed) { 642 return null; 643 } 644 645 try { 646 return miSession.getVideoCallProvider(); 647 } catch (RemoteException e) { 648 return null; 649 } 650 } 651 652 /** 653 * Gets the value associated with the specified property of this session. 654 * 655 * @return the string value associated with the specified property 656 */ getProperty(String name)657 public String getProperty(String name) { 658 if (mClosed) { 659 return null; 660 } 661 662 try { 663 return miSession.getProperty(name); 664 } catch (RemoteException e) { 665 return null; 666 } 667 } 668 669 /** 670 * Gets the session state. 671 * The value returned must be one of the states in {@link State}. 672 * 673 * @return the session state 674 */ getState()675 public int getState() { 676 if (mClosed) { 677 return State.INVALID; 678 } 679 680 try { 681 return miSession.getState(); 682 } catch (RemoteException e) { 683 return State.INVALID; 684 } 685 } 686 687 /** 688 * Determines if the {@link ImsCallSession} is currently alive (e.g. not in a terminated or 689 * closed state). 690 * 691 * @return {@code True} if the session is alive. 692 */ isAlive()693 public boolean isAlive() { 694 if (mClosed) { 695 return false; 696 } 697 698 int state = getState(); 699 switch (state) { 700 case State.IDLE: 701 case State.INITIATED: 702 case State.NEGOTIATING: 703 case State.ESTABLISHING: 704 case State.ESTABLISHED: 705 case State.RENEGOTIATING: 706 case State.REESTABLISHING: 707 return true; 708 default: 709 return false; 710 } 711 } 712 713 /** 714 * Gets the native IMS call session. 715 * @hide 716 */ getSession()717 public IImsCallSession getSession() { 718 return miSession; 719 } 720 721 /** 722 * Checks if the session is in call. 723 * 724 * @return true if the session is in call 725 */ isInCall()726 public boolean isInCall() { 727 if (mClosed) { 728 return false; 729 } 730 731 try { 732 return miSession.isInCall(); 733 } catch (RemoteException e) { 734 return false; 735 } 736 } 737 738 /** 739 * Sets the listener to listen to the session events. A {@link ImsCallSession} 740 * can only hold one listener at a time. Subsequent calls to this method 741 * override the previous listener. 742 * 743 * @param listener to listen to the session events of this object 744 * @param executor an Executor that will execute callbacks 745 * @hide 746 */ setListener(Listener listener, Executor executor)747 public void setListener(Listener listener, Executor executor) { 748 mListener = listener; 749 if (executor != null) { 750 mListenerExecutor = executor; 751 } 752 } 753 754 /** 755 * Mutes or unmutes the mic for the active call. 756 * 757 * @param muted true if the call is muted, false otherwise 758 */ setMute(boolean muted)759 public void setMute(boolean muted) { 760 if (mClosed) { 761 return; 762 } 763 764 try { 765 miSession.setMute(muted); 766 } catch (RemoteException e) { 767 } 768 } 769 770 /** 771 * Initiates an IMS call with the specified target and call profile. 772 * The session listener is called back upon defined session events. 773 * The method is only valid to call when the session state is in 774 * {@link ImsCallSession.State#IDLE}. 775 * 776 * @param callee dial string to make the call to. The platform passes the dialed number 777 * entered by the user as-is. The {@link ImsService} should ensure that the 778 * number is formatted in SIP messages appropriately (e.g. using 779 * {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}). 780 * @param profile call profile to make the call with the specified service type, 781 * call type and media information 782 * @see Listener#callSessionStarted, Listener#callSessionStartFailed 783 */ start(String callee, ImsCallProfile profile)784 public void start(String callee, ImsCallProfile profile) { 785 if (mClosed) { 786 return; 787 } 788 789 try { 790 miSession.start(callee, profile); 791 } catch (RemoteException e) { 792 } 793 } 794 795 /** 796 * Initiates an IMS conference call with the specified target and call profile. 797 * The session listener is called back upon defined session events. 798 * The method is only valid to call when the session state is in 799 * {@link ImsCallSession.State#IDLE}. 800 * 801 * @param participants participant list to initiate an IMS conference call. The platform passes 802 * the dialed numbers entered by the user as-is. The {@link ImsService} should 803 * ensure that the number is formatted in SIP messages appropriately (e.g. using 804 * {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}). 805 * @param profile call profile to make the call with the specified service type, 806 * call type and media information 807 * @see Listener#callSessionStarted, Listener#callSessionStartFailed 808 */ start(String[] participants, ImsCallProfile profile)809 public void start(String[] participants, ImsCallProfile profile) { 810 if (mClosed) { 811 return; 812 } 813 814 try { 815 miSession.startConference(participants, profile); 816 } catch (RemoteException e) { 817 } 818 } 819 820 /** 821 * Accepts an incoming call or session update. 822 * 823 * @param callType call type specified in {@link ImsCallProfile} to be answered 824 * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered 825 * @see Listener#callSessionStarted 826 */ accept(int callType, ImsStreamMediaProfile profile)827 public void accept(int callType, ImsStreamMediaProfile profile) { 828 if (mClosed) { 829 return; 830 } 831 832 try { 833 miSession.accept(callType, profile); 834 } catch (RemoteException e) { 835 } 836 } 837 838 /** 839 * Deflects an incoming call. 840 * 841 * @param number number to be deflected to 842 */ deflect(String number)843 public void deflect(String number) { 844 if (mClosed) { 845 return; 846 } 847 848 try { 849 miSession.deflect(number); 850 } catch (RemoteException e) { 851 } 852 } 853 854 /** 855 * Rejects an incoming call or session update. 856 * 857 * @param reason reason code to reject an incoming call 858 * @see Listener#callSessionStartFailed 859 */ reject(int reason)860 public void reject(int reason) { 861 if (mClosed) { 862 return; 863 } 864 865 try { 866 miSession.reject(reason); 867 } catch (RemoteException e) { 868 } 869 } 870 871 /** 872 * Transfers an ongoing call. 873 * 874 * @param number number to be transferred to. 875 * @param isConfirmationRequired indicates whether confirmation of the transfer is required. 876 */ transfer(@onNull String number, boolean isConfirmationRequired)877 public void transfer(@NonNull String number, boolean isConfirmationRequired) { 878 if (mClosed) { 879 return; 880 } 881 882 try { 883 miSession.transfer(number, isConfirmationRequired); 884 } catch (RemoteException e) { 885 } 886 } 887 888 /** 889 * Transfers a call to another ongoing call. 890 * 891 * @param transferToSession the other ImsCallSession to which this session will be transferred. 892 */ transfer(@onNull ImsCallSession transferToSession)893 public void transfer(@NonNull ImsCallSession transferToSession) { 894 if (mClosed) { 895 return; 896 } 897 898 try { 899 if (transferToSession != null) { 900 miSession.consultativeTransfer(transferToSession.getSession()); 901 } 902 } catch (RemoteException e) { 903 } 904 } 905 906 /** 907 * Terminates a call. 908 * 909 * @see Listener#callSessionTerminated 910 */ terminate(int reason)911 public void terminate(int reason) { 912 if (mClosed) { 913 return; 914 } 915 916 try { 917 miSession.terminate(reason); 918 } catch (RemoteException e) { 919 } 920 } 921 922 /** 923 * Puts a call on hold. When it succeeds, {@link Listener#callSessionHeld} is called. 924 * 925 * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call 926 * @see Listener#callSessionHeld, Listener#callSessionHoldFailed 927 */ hold(ImsStreamMediaProfile profile)928 public void hold(ImsStreamMediaProfile profile) { 929 if (mClosed) { 930 return; 931 } 932 933 try { 934 miSession.hold(profile); 935 } catch (RemoteException e) { 936 } 937 } 938 939 /** 940 * Continues a call that's on hold. When it succeeds, 941 * {@link Listener#callSessionResumed} is called. 942 * 943 * @param profile stream media profile {@link ImsStreamMediaProfile} to resume the call 944 * @see Listener#callSessionResumed, Listener#callSessionResumeFailed 945 */ resume(ImsStreamMediaProfile profile)946 public void resume(ImsStreamMediaProfile profile) { 947 if (mClosed) { 948 return; 949 } 950 951 try { 952 miSession.resume(profile); 953 } catch (RemoteException e) { 954 } 955 } 956 957 /** 958 * Merges the active & hold call. When it succeeds, 959 * {@link Listener#callSessionMergeStarted} is called. 960 * 961 * @see Listener#callSessionMergeStarted , Listener#callSessionMergeFailed 962 */ merge()963 public void merge() { 964 if (mClosed) { 965 return; 966 } 967 968 try { 969 miSession.merge(); 970 } catch (RemoteException e) { 971 } 972 } 973 974 /** 975 * Updates the current call's properties (ex. call mode change: video upgrade / downgrade). 976 * 977 * @param callType call type specified in {@link ImsCallProfile} to be updated 978 * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated 979 * @see Listener#callSessionUpdated, Listener#callSessionUpdateFailed 980 */ update(int callType, ImsStreamMediaProfile profile)981 public void update(int callType, ImsStreamMediaProfile profile) { 982 if (mClosed) { 983 return; 984 } 985 986 try { 987 miSession.update(callType, profile); 988 } catch (RemoteException e) { 989 } 990 } 991 992 /** 993 * Extends this call to the conference call with the specified recipients. 994 * 995 * @param participants list to be invited to the conference call after extending the call 996 * @see Listener#callSessionConferenceExtended 997 * @see Listener#callSessionConferenceExtendFailed 998 */ extendToConference(String[] participants)999 public void extendToConference(String[] participants) { 1000 if (mClosed) { 1001 return; 1002 } 1003 1004 try { 1005 miSession.extendToConference(participants); 1006 } catch (RemoteException e) { 1007 } 1008 } 1009 1010 /** 1011 * Requests the conference server to invite an additional participants to the conference. 1012 * 1013 * @param participants list to be invited to the conference call 1014 * @see Listener#callSessionInviteParticipantsRequestDelivered 1015 * @see Listener#callSessionInviteParticipantsRequestFailed 1016 */ inviteParticipants(String[] participants)1017 public void inviteParticipants(String[] participants) { 1018 if (mClosed) { 1019 return; 1020 } 1021 1022 try { 1023 miSession.inviteParticipants(participants); 1024 } catch (RemoteException e) { 1025 } 1026 } 1027 1028 /** 1029 * Requests the conference server to remove the specified participants from the conference. 1030 * 1031 * @param participants participant list to be removed from the conference call 1032 * @see Listener#callSessionRemoveParticipantsRequestDelivered 1033 * @see Listener#callSessionRemoveParticipantsRequestFailed 1034 */ removeParticipants(String[] participants)1035 public void removeParticipants(String[] participants) { 1036 if (mClosed) { 1037 return; 1038 } 1039 1040 try { 1041 miSession.removeParticipants(participants); 1042 } catch (RemoteException e) { 1043 } 1044 } 1045 1046 1047 /** 1048 * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>, 1049 * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15, 1050 * and event flash to 16. Currently, event flash is not supported. 1051 * 1052 * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs. 1053 */ sendDtmf(char c, Message result)1054 public void sendDtmf(char c, Message result) { 1055 if (mClosed) { 1056 return; 1057 } 1058 1059 try { 1060 miSession.sendDtmf(c, result); 1061 } catch (RemoteException e) { 1062 } 1063 } 1064 1065 /** 1066 * Starts a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>, 1067 * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15, 1068 * and event flash to 16. Currently, event flash is not supported. 1069 * 1070 * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs. 1071 */ startDtmf(char c)1072 public void startDtmf(char c) { 1073 if (mClosed) { 1074 return; 1075 } 1076 1077 try { 1078 miSession.startDtmf(c); 1079 } catch (RemoteException e) { 1080 } 1081 } 1082 1083 /** 1084 * Stops a DTMF code. 1085 */ stopDtmf()1086 public void stopDtmf() { 1087 if (mClosed) { 1088 return; 1089 } 1090 1091 try { 1092 miSession.stopDtmf(); 1093 } catch (RemoteException e) { 1094 } 1095 } 1096 1097 /** 1098 * Sends an USSD message. 1099 * 1100 * @param ussdMessage USSD message to send 1101 */ sendUssd(String ussdMessage)1102 public void sendUssd(String ussdMessage) { 1103 if (mClosed) { 1104 return; 1105 } 1106 1107 try { 1108 miSession.sendUssd(ussdMessage); 1109 } catch (RemoteException e) { 1110 } 1111 } 1112 1113 /** 1114 * Determines if the session is multiparty. 1115 * 1116 * @return {@code True} if the session is multiparty. 1117 */ isMultiparty()1118 public boolean isMultiparty() { 1119 if (mClosed) { 1120 return false; 1121 } 1122 1123 try { 1124 return miSession.isMultiparty(); 1125 } catch (RemoteException e) { 1126 return false; 1127 } 1128 } 1129 1130 /** 1131 * Sends Rtt Message 1132 * 1133 * @param rttMessage rtt text to be sent 1134 */ sendRttMessage(String rttMessage)1135 public void sendRttMessage(String rttMessage) { 1136 if (mClosed) { 1137 return; 1138 } 1139 1140 try { 1141 miSession.sendRttMessage(rttMessage); 1142 } catch (RemoteException e) { 1143 } 1144 } 1145 1146 /** 1147 * Sends RTT Upgrade or downgrade request 1148 * 1149 * @param to Profile with the RTT flag set to the desired value 1150 */ sendRttModifyRequest(ImsCallProfile to)1151 public void sendRttModifyRequest(ImsCallProfile to) { 1152 if (mClosed) { 1153 return; 1154 } 1155 1156 try { 1157 miSession.sendRttModifyRequest(to); 1158 } catch (RemoteException e) { 1159 } 1160 } 1161 1162 /** 1163 * Sends RTT Upgrade response 1164 * 1165 * @param response : response for upgrade 1166 */ sendRttModifyResponse(boolean response)1167 public void sendRttModifyResponse(boolean response) { 1168 if (mClosed) { 1169 return; 1170 } 1171 1172 try { 1173 miSession.sendRttModifyResponse(response); 1174 } catch (RemoteException e) { 1175 } 1176 } 1177 1178 /** 1179 * Requests that {@code rtpHeaderExtensions} are sent as a header extension with the next 1180 * RTP packet sent by the IMS stack. 1181 * <p> 1182 * The {@link RtpHeaderExtensionType}s negotiated during SDP (Session Description Protocol) 1183 * signalling determine the {@link RtpHeaderExtension}s which can be sent using this method. 1184 * See RFC8285 for more information. 1185 * <p> 1186 * By specification, the RTP header extension is an unacknowledged transmission and there is no 1187 * guarantee that the header extension will be delivered by the network to the other end of the 1188 * call. 1189 * @param rtpHeaderExtensions The header extensions to be included in the next RTP header. 1190 */ sendRtpHeaderExtensions(@onNull Set<RtpHeaderExtension> rtpHeaderExtensions)1191 public void sendRtpHeaderExtensions(@NonNull Set<RtpHeaderExtension> rtpHeaderExtensions) { 1192 if (mClosed) { 1193 return; 1194 } 1195 1196 try { 1197 miSession.sendRtpHeaderExtensions( 1198 new ArrayList<RtpHeaderExtension>(rtpHeaderExtensions)); 1199 } catch (RemoteException e) { 1200 } 1201 } 1202 1203 /** 1204 * A listener type for receiving notification on IMS call session events. 1205 * When an event is generated for an {@link IImsCallSession}, 1206 * the application is notified by having one of the methods called on 1207 * the {@link IImsCallSessionListener}. 1208 */ 1209 private class IImsCallSessionListenerProxy extends IImsCallSessionListener.Stub { 1210 /** 1211 * Notifies the result of the basic session operation (setup / terminate). 1212 */ 1213 @Override callSessionInitiating(ImsCallProfile profile)1214 public void callSessionInitiating(ImsCallProfile profile) { 1215 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1216 if (mListener != null) { 1217 mListener.callSessionInitiating(ImsCallSession.this, profile); 1218 } 1219 }, mListenerExecutor); 1220 } 1221 1222 @Override callSessionProgressing(ImsStreamMediaProfile profile)1223 public void callSessionProgressing(ImsStreamMediaProfile profile) { 1224 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1225 if (mListener != null) { 1226 mListener.callSessionProgressing(ImsCallSession.this, profile); 1227 } 1228 }, mListenerExecutor); 1229 } 1230 1231 @Override callSessionInitiated(ImsCallProfile profile)1232 public void callSessionInitiated(ImsCallProfile profile) { 1233 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1234 if (mListener != null) { 1235 mListener.callSessionStarted(ImsCallSession.this, profile); 1236 } 1237 }, mListenerExecutor); 1238 } 1239 1240 @Override callSessionInitiatingFailed(ImsReasonInfo reasonInfo)1241 public void callSessionInitiatingFailed(ImsReasonInfo reasonInfo) { 1242 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1243 if (mListener != null) { 1244 mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo); 1245 } 1246 }, mListenerExecutor); 1247 } 1248 1249 @Override callSessionInitiatedFailed(ImsReasonInfo reasonInfo)1250 public void callSessionInitiatedFailed(ImsReasonInfo reasonInfo) { 1251 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1252 if (mListener != null) { 1253 mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo); 1254 } 1255 }, mListenerExecutor); 1256 } 1257 1258 @Override callSessionTerminated(ImsReasonInfo reasonInfo)1259 public void callSessionTerminated(ImsReasonInfo reasonInfo) { 1260 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1261 if (mListener != null) { 1262 mListener.callSessionTerminated(ImsCallSession.this, reasonInfo); 1263 } 1264 }, mListenerExecutor); 1265 } 1266 1267 /** 1268 * Notifies the result of the call hold/resume operation. 1269 */ 1270 @Override callSessionHeld(ImsCallProfile profile)1271 public void callSessionHeld(ImsCallProfile profile) { 1272 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1273 if (mListener != null) { 1274 mListener.callSessionHeld(ImsCallSession.this, profile); 1275 } 1276 }, mListenerExecutor); 1277 } 1278 1279 @Override callSessionHoldFailed(ImsReasonInfo reasonInfo)1280 public void callSessionHoldFailed(ImsReasonInfo reasonInfo) { 1281 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1282 if (mListener != null) { 1283 mListener.callSessionHoldFailed(ImsCallSession.this, reasonInfo); 1284 } 1285 }, mListenerExecutor); 1286 } 1287 1288 @Override callSessionHoldReceived(ImsCallProfile profile)1289 public void callSessionHoldReceived(ImsCallProfile profile) { 1290 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1291 if (mListener != null) { 1292 mListener.callSessionHoldReceived(ImsCallSession.this, profile); 1293 } 1294 }, mListenerExecutor); 1295 } 1296 1297 @Override callSessionResumed(ImsCallProfile profile)1298 public void callSessionResumed(ImsCallProfile profile) { 1299 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1300 if (mListener != null) { 1301 mListener.callSessionResumed(ImsCallSession.this, profile); 1302 } 1303 }, mListenerExecutor); 1304 } 1305 1306 @Override callSessionResumeFailed(ImsReasonInfo reasonInfo)1307 public void callSessionResumeFailed(ImsReasonInfo reasonInfo) { 1308 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1309 if (mListener != null) { 1310 mListener.callSessionResumeFailed(ImsCallSession.this, reasonInfo); 1311 } 1312 }, mListenerExecutor); 1313 } 1314 1315 @Override callSessionResumeReceived(ImsCallProfile profile)1316 public void callSessionResumeReceived(ImsCallProfile profile) { 1317 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1318 if (mListener != null) { 1319 mListener.callSessionResumeReceived(ImsCallSession.this, profile); 1320 } 1321 }, mListenerExecutor); 1322 } 1323 1324 /** 1325 * Notifies the start of a call merge operation. 1326 * 1327 * @param newSession The merged call session. 1328 * @param profile The call profile. 1329 */ 1330 @Override callSessionMergeStarted(IImsCallSession newSession, ImsCallProfile profile)1331 public void callSessionMergeStarted(IImsCallSession newSession, ImsCallProfile profile) { 1332 // This callback can be used for future use to add additional 1333 // functionality that may be needed between conference start and complete 1334 Log.d(TAG, "callSessionMergeStarted"); 1335 } 1336 1337 /** 1338 * Notifies the successful completion of a call merge operation. 1339 * 1340 * @param newSession The call session. 1341 */ 1342 @Override callSessionMergeComplete(IImsCallSession newSession)1343 public void callSessionMergeComplete(IImsCallSession newSession) { 1344 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1345 if (mListener != null) { 1346 if (newSession != null) { 1347 // New session created after conference 1348 mListener.callSessionMergeComplete(new ImsCallSession(newSession)); 1349 } else { 1350 // Session already exists. Hence no need to pass 1351 mListener.callSessionMergeComplete(null); 1352 } 1353 } 1354 }, mListenerExecutor); 1355 } 1356 1357 /** 1358 * Notifies of a failure to perform a call merge operation. 1359 * 1360 * @param reasonInfo The merge failure reason. 1361 */ 1362 @Override callSessionMergeFailed(ImsReasonInfo reasonInfo)1363 public void callSessionMergeFailed(ImsReasonInfo reasonInfo) { 1364 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1365 if (mListener != null) { 1366 mListener.callSessionMergeFailed(ImsCallSession.this, reasonInfo); 1367 } 1368 }, mListenerExecutor); 1369 } 1370 1371 /** 1372 * Notifies the result of call upgrade / downgrade or any other call updates. 1373 */ 1374 @Override callSessionUpdated(ImsCallProfile profile)1375 public void callSessionUpdated(ImsCallProfile profile) { 1376 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1377 if (mListener != null) { 1378 mListener.callSessionUpdated(ImsCallSession.this, profile); 1379 } 1380 }, mListenerExecutor); 1381 } 1382 1383 @Override callSessionUpdateFailed(ImsReasonInfo reasonInfo)1384 public void callSessionUpdateFailed(ImsReasonInfo reasonInfo) { 1385 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1386 if (mListener != null) { 1387 mListener.callSessionUpdateFailed(ImsCallSession.this, reasonInfo); 1388 } 1389 }, mListenerExecutor); 1390 } 1391 1392 @Override callSessionUpdateReceived(ImsCallProfile profile)1393 public void callSessionUpdateReceived(ImsCallProfile profile) { 1394 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1395 if (mListener != null) { 1396 mListener.callSessionUpdateReceived(ImsCallSession.this, profile); 1397 } 1398 }, mListenerExecutor); 1399 } 1400 1401 /** 1402 * Notifies the result of conference extension. 1403 */ 1404 @Override callSessionConferenceExtended(IImsCallSession newSession, ImsCallProfile profile)1405 public void callSessionConferenceExtended(IImsCallSession newSession, 1406 ImsCallProfile profile) { 1407 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1408 if (mListener != null) { 1409 mListener.callSessionConferenceExtended(ImsCallSession.this, 1410 new ImsCallSession(newSession), profile); 1411 } 1412 }, mListenerExecutor); 1413 } 1414 1415 @Override callSessionConferenceExtendFailed(ImsReasonInfo reasonInfo)1416 public void callSessionConferenceExtendFailed(ImsReasonInfo reasonInfo) { 1417 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1418 if (mListener != null) { 1419 mListener.callSessionConferenceExtendFailed( 1420 ImsCallSession.this, reasonInfo); 1421 } 1422 }, mListenerExecutor); 1423 } 1424 1425 @Override callSessionConferenceExtendReceived(IImsCallSession newSession, ImsCallProfile profile)1426 public void callSessionConferenceExtendReceived(IImsCallSession newSession, 1427 ImsCallProfile profile) { 1428 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1429 if (mListener != null) { 1430 mListener.callSessionConferenceExtendReceived(ImsCallSession.this, 1431 new ImsCallSession(newSession), profile); 1432 } 1433 }, mListenerExecutor); 1434 } 1435 1436 /** 1437 * Notifies the result of the participant invitation / removal to/from 1438 * the conference session. 1439 */ 1440 @Override callSessionInviteParticipantsRequestDelivered()1441 public void callSessionInviteParticipantsRequestDelivered() { 1442 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1443 if (mListener != null) { 1444 mListener.callSessionInviteParticipantsRequestDelivered( 1445 ImsCallSession.this); 1446 } 1447 }, mListenerExecutor); 1448 } 1449 1450 @Override callSessionInviteParticipantsRequestFailed(ImsReasonInfo reasonInfo)1451 public void callSessionInviteParticipantsRequestFailed(ImsReasonInfo reasonInfo) { 1452 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1453 if (mListener != null) { 1454 mListener.callSessionInviteParticipantsRequestFailed(ImsCallSession.this, 1455 reasonInfo); 1456 } 1457 }, mListenerExecutor); 1458 } 1459 1460 @Override callSessionRemoveParticipantsRequestDelivered()1461 public void callSessionRemoveParticipantsRequestDelivered() { 1462 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1463 if (mListener != null) { 1464 mListener.callSessionRemoveParticipantsRequestDelivered(ImsCallSession.this); 1465 } 1466 }, mListenerExecutor); 1467 } 1468 1469 @Override callSessionRemoveParticipantsRequestFailed(ImsReasonInfo reasonInfo)1470 public void callSessionRemoveParticipantsRequestFailed(ImsReasonInfo reasonInfo) { 1471 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1472 if (mListener != null) { 1473 mListener.callSessionRemoveParticipantsRequestFailed(ImsCallSession.this, 1474 reasonInfo); 1475 } 1476 }, mListenerExecutor); 1477 } 1478 1479 /** 1480 * Notifies the changes of the conference info. in the conference session. 1481 */ 1482 @Override callSessionConferenceStateUpdated(ImsConferenceState state)1483 public void callSessionConferenceStateUpdated(ImsConferenceState state) { 1484 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1485 if (mListener != null) { 1486 mListener.callSessionConferenceStateUpdated(ImsCallSession.this, state); 1487 } 1488 }, mListenerExecutor); 1489 } 1490 1491 /** 1492 * Notifies the incoming USSD message. 1493 */ 1494 @Override callSessionUssdMessageReceived(int mode, String ussdMessage)1495 public void callSessionUssdMessageReceived(int mode, String ussdMessage) { 1496 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1497 if (mListener != null) { 1498 mListener.callSessionUssdMessageReceived(ImsCallSession.this, mode, 1499 ussdMessage); 1500 } 1501 }, mListenerExecutor); 1502 } 1503 1504 /** 1505 * Notifies of a case where a {@link ImsCallSession} may 1506 * potentially handover from one radio technology to another. 1507 * @param srcNetworkType The source network type; one of the network type constants defined 1508 * in {@link android.telephony.TelephonyManager}. For example 1509 * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}. 1510 * @param targetNetworkType The target radio access technology; one of the network type 1511 * constants defined in {@link android.telephony.TelephonyManager}. 1512 * For example 1513 * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}. 1514 */ 1515 @Override callSessionMayHandover(int srcNetworkType, int targetNetworkType)1516 public void callSessionMayHandover(int srcNetworkType, int targetNetworkType) { 1517 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1518 if (mListener != null) { 1519 mListener.callSessionMayHandover(ImsCallSession.this, srcNetworkType, 1520 targetNetworkType); 1521 } 1522 }, mListenerExecutor); 1523 } 1524 1525 /** 1526 * Notifies of handover information for this call 1527 */ 1528 @Override callSessionHandover(int srcNetworkType, int targetNetworkType, ImsReasonInfo reasonInfo)1529 public void callSessionHandover(int srcNetworkType, int targetNetworkType, 1530 ImsReasonInfo reasonInfo) { 1531 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1532 if (mListener != null) { 1533 mListener.callSessionHandover(ImsCallSession.this, srcNetworkType, 1534 targetNetworkType, reasonInfo); 1535 } 1536 }, mListenerExecutor); 1537 } 1538 1539 /** 1540 * Notifies of handover failure info for this call 1541 */ 1542 @Override callSessionHandoverFailed(int srcNetworkType, int targetNetworkType, ImsReasonInfo reasonInfo)1543 public void callSessionHandoverFailed(int srcNetworkType, int targetNetworkType, 1544 ImsReasonInfo reasonInfo) { 1545 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1546 if (mListener != null) { 1547 mListener.callSessionHandoverFailed(ImsCallSession.this, srcNetworkType, 1548 targetNetworkType, reasonInfo); 1549 } 1550 }, mListenerExecutor); 1551 } 1552 1553 /** 1554 * Notifies the TTY mode received from remote party. 1555 */ 1556 @Override callSessionTtyModeReceived(int mode)1557 public void callSessionTtyModeReceived(int mode) { 1558 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1559 if (mListener != null) { 1560 mListener.callSessionTtyModeReceived(ImsCallSession.this, mode); 1561 } 1562 }, mListenerExecutor); 1563 } 1564 1565 /** 1566 * Notifies of a change to the multiparty state for this {@code ImsCallSession}. 1567 * 1568 * @param isMultiParty {@code true} if the session became multiparty, {@code false} 1569 * otherwise. 1570 */ callSessionMultipartyStateChanged(boolean isMultiParty)1571 public void callSessionMultipartyStateChanged(boolean isMultiParty) { 1572 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1573 if (mListener != null) { 1574 mListener.callSessionMultipartyStateChanged(ImsCallSession.this, 1575 isMultiParty); 1576 } 1577 }, mListenerExecutor); 1578 } 1579 1580 @Override callSessionSuppServiceReceived(ImsSuppServiceNotification suppServiceInfo )1581 public void callSessionSuppServiceReceived(ImsSuppServiceNotification suppServiceInfo ) { 1582 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1583 if (mListener != null) { 1584 mListener.callSessionSuppServiceReceived(ImsCallSession.this, 1585 suppServiceInfo); 1586 } 1587 }, mListenerExecutor); 1588 } 1589 1590 /** 1591 * Received RTT modify request from remote party 1592 */ 1593 @Override callSessionRttModifyRequestReceived(ImsCallProfile callProfile)1594 public void callSessionRttModifyRequestReceived(ImsCallProfile callProfile) { 1595 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1596 if (mListener != null) { 1597 mListener.callSessionRttModifyRequestReceived(ImsCallSession.this, 1598 callProfile); 1599 } 1600 }, mListenerExecutor); 1601 } 1602 1603 /** 1604 * Received response for RTT modify request 1605 */ 1606 @Override callSessionRttModifyResponseReceived(int status)1607 public void callSessionRttModifyResponseReceived(int status) { 1608 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1609 if (mListener != null) { 1610 mListener.callSessionRttModifyResponseReceived(status); 1611 } 1612 }, mListenerExecutor); 1613 } 1614 1615 /** 1616 * RTT Message received 1617 */ 1618 @Override callSessionRttMessageReceived(String rttMessage)1619 public void callSessionRttMessageReceived(String rttMessage) { 1620 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1621 if (mListener != null) { 1622 mListener.callSessionRttMessageReceived(rttMessage); 1623 } 1624 }, mListenerExecutor); 1625 } 1626 1627 /** 1628 * While in call, there has been a change in RTT audio indicator. 1629 */ 1630 @Override callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile)1631 public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile) { 1632 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1633 if (mListener != null) { 1634 mListener.callSessionRttAudioIndicatorChanged(profile); 1635 } 1636 }, mListenerExecutor); 1637 } 1638 1639 @Override callSessionTransferred()1640 public void callSessionTransferred() { 1641 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1642 if (mListener != null) { 1643 mListener.callSessionTransferred(ImsCallSession.this); 1644 } 1645 }, mListenerExecutor); 1646 } 1647 1648 @Override callSessionTransferFailed(@ullable ImsReasonInfo reasonInfo)1649 public void callSessionTransferFailed(@Nullable ImsReasonInfo reasonInfo) { 1650 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1651 if (mListener != null) { 1652 mListener.callSessionTransferFailed(ImsCallSession.this, reasonInfo); 1653 } 1654 }, mListenerExecutor); 1655 } 1656 1657 /** 1658 * DTMF digit received. 1659 * @param dtmf The DTMF digit. 1660 */ 1661 @Override callSessionDtmfReceived(char dtmf)1662 public void callSessionDtmfReceived(char dtmf) { 1663 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1664 if (mListener != null) { 1665 mListener.callSessionDtmfReceived(dtmf); 1666 } 1667 }, mListenerExecutor); 1668 } 1669 1670 /** 1671 * Call quality updated 1672 */ 1673 @Override callQualityChanged(CallQuality callQuality)1674 public void callQualityChanged(CallQuality callQuality) { 1675 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1676 if (mListener != null) { 1677 mListener.callQualityChanged(callQuality); 1678 } 1679 }, mListenerExecutor); 1680 } 1681 1682 /** 1683 * RTP header extension data received. 1684 * @param extensions The header extension data. 1685 */ 1686 @Override callSessionRtpHeaderExtensionsReceived( @onNull List<RtpHeaderExtension> extensions)1687 public void callSessionRtpHeaderExtensionsReceived( 1688 @NonNull List<RtpHeaderExtension> extensions) { 1689 TelephonyUtils.runWithCleanCallingIdentity(()-> { 1690 if (mListener != null) { 1691 mListener.callSessionRtpHeaderExtensionsReceived( 1692 new ArraySet<RtpHeaderExtension>(extensions)); 1693 } 1694 }, mListenerExecutor); 1695 } 1696 } 1697 1698 /** 1699 * Provides a string representation of the {@link ImsCallSession}. Primarily intended for 1700 * use in log statements. 1701 * 1702 * @return String representation of session. 1703 */ 1704 @Override toString()1705 public String toString() { 1706 StringBuilder sb = new StringBuilder(); 1707 sb.append("[ImsCallSession objId:"); 1708 sb.append(System.identityHashCode(this)); 1709 sb.append(" state:"); 1710 sb.append(State.toString(getState())); 1711 sb.append(" callId:"); 1712 sb.append(getCallId()); 1713 sb.append("]"); 1714 return sb.toString(); 1715 } 1716 } 1717