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