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