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