Remove Session Id from ImsService APIs that do not need it.
[android/platform/frameworks/opt/net/ims.git] / src / java / com / android / ims / internal / ImsCallSession.java
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 }