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