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