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