1 /*
2  * Copyright (C) 2014 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.telecom;
18 
19 import com.android.internal.os.SomeArgs;
20 import com.android.internal.telecom.IVideoCallback;
21 import com.android.internal.telecom.IVideoProvider;
22 
23 import android.annotation.Nullable;
24 import android.annotation.SystemApi;
25 import android.hardware.camera2.CameraManager;
26 import android.net.Uri;
27 import android.os.Bundle;
28 import android.os.Handler;
29 import android.os.IBinder;
30 import android.os.Looper;
31 import android.os.Message;
32 import android.os.RemoteException;
33 import android.view.Surface;
34 
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
38 import java.util.Set;
39 import java.util.concurrent.ConcurrentHashMap;
40 
41 /**
42  * Represents a phone call or connection to a remote endpoint that carries voice and/or video
43  * traffic.
44  * <p>
45  * Implementations create a custom subclass of {@code Connection} and return it to the framework
46  * as the return value of
47  * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}
48  * or
49  * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
50  * Implementations are then responsible for updating the state of the {@code Connection}, and
51  * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no
52  * longer used and associated resources may be recovered.
53  */
54 public abstract class Connection extends Conferenceable {
55 
56     /**
57      * The connection is initializing. This is generally the first state for a {@code Connection}
58      * returned by a {@link ConnectionService}.
59      */
60     public static final int STATE_INITIALIZING = 0;
61 
62     /**
63      * The connection is new and not connected.
64      */
65     public static final int STATE_NEW = 1;
66 
67     /**
68      * An incoming connection is in the ringing state. During this state, the user's ringer or
69      * vibration feature will be activated.
70      */
71     public static final int STATE_RINGING = 2;
72 
73     /**
74      * An outgoing connection is in the dialing state. In this state the other party has not yet
75      * answered the call and the user traditionally hears a ringback tone.
76      */
77     public static final int STATE_DIALING = 3;
78 
79     /**
80      * A connection is active. Both parties are connected to the call and can actively communicate.
81      */
82     public static final int STATE_ACTIVE = 4;
83 
84     /**
85      * A connection is on hold.
86      */
87     public static final int STATE_HOLDING = 5;
88 
89     /**
90      * A connection has been disconnected. This is the final state once the user has been
91      * disconnected from a call either locally, remotely or by an error in the service.
92      */
93     public static final int STATE_DISCONNECTED = 6;
94 
95     /**
96      * Connection can currently be put on hold or unheld. This is distinct from
97      * {@link #CAPABILITY_SUPPORT_HOLD} in that although a connection may support 'hold' most times,
98      * it does not at the moment support the function. This can be true while the call is in the
99      * state {@link #STATE_DIALING}, for example. During this condition, an in-call UI may
100      * display a disabled 'hold' button.
101      */
102     public static final int CAPABILITY_HOLD = 0x00000001;
103 
104     /** Connection supports the hold feature. */
105     public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
106 
107     /**
108      * Connections within a conference can be merged. A {@link ConnectionService} has the option to
109      * add a {@link Conference} before the child {@link Connection}s are merged. This is how
110      * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
111      * capability allows a merge button to be shown while the conference is in the foreground
112      * of the in-call UI.
113      * <p>
114      * This is only intended for use by a {@link Conference}.
115      */
116     public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
117 
118     /**
119      * Connections within a conference can be swapped between foreground and background.
120      * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
121      * <p>
122      * This is only intended for use by a {@link Conference}.
123      */
124     public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
125 
126     /**
127      * @hide
128      */
129     public static final int CAPABILITY_UNUSED = 0x00000010;
130 
131     /** Connection supports responding via text option. */
132     public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
133 
134     /** Connection can be muted. */
135     public static final int CAPABILITY_MUTE = 0x00000040;
136 
137     /**
138      * Connection supports conference management. This capability only applies to
139      * {@link Conference}s which can have {@link Connection}s as children.
140      */
141     public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
142 
143     /**
144      * Local device supports receiving video.
145      */
146     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
147 
148     /**
149      * Local device supports transmitting video.
150      */
151     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
152 
153     /**
154      * Local device supports bidirectional video calling.
155      */
156     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
157             CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
158 
159     /**
160      * Remote device supports receiving video.
161      */
162     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
163 
164     /**
165      * Remote device supports transmitting video.
166      */
167     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
168 
169     /**
170      * Remote device supports bidirectional video calling.
171      */
172     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
173             CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
174 
175     /**
176      * Connection is able to be separated from its parent {@code Conference}, if any.
177      */
178     public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
179 
180     /**
181      * Connection is able to be individually disconnected when in a {@code Conference}.
182      */
183     public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
184 
185     /**
186      * Whether the call is a generic conference, where we do not know the precise state of
187      * participants in the conference (eg. on CDMA).
188      *
189      * @hide
190      */
191     public static final int CAPABILITY_GENERIC_CONFERENCE = 0x00004000;
192 
193     /**
194      * Connection is using high definition audio.
195      * @hide
196      */
197     public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00008000;
198 
199     /**
200      * Connection is using WIFI.
201      * @hide
202      */
203     public static final int CAPABILITY_WIFI = 0x00010000;
204 
205     /**
206      * Indicates that the current device callback number should be shown.
207      *
208      * @hide
209      */
210     public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 0x00020000;
211 
212     /**
213      * Speed up audio setup for MT call.
214      * @hide
215      */
216     public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
217 
218     /**
219      * Call can be upgraded to a video call.
220      */
221     public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
222 
223     /**
224      * For video calls, indicates whether the outgoing video for the call can be paused using
225      * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
226      */
227     public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
228 
229     /**
230      * For a conference, indicates the conference will not have child connections.
231      * <p>
232      * An example of a conference with child connections is a GSM conference call, where the radio
233      * retains connections to the individual participants of the conference.  Another example is an
234      * IMS conference call where conference event package functionality is supported; in this case
235      * the conference server ensures the radio is aware of the participants in the conference, which
236      * are represented by child connections.
237      * <p>
238      * An example of a conference with no child connections is an IMS conference call with no
239      * conference event package support.  Such a conference is represented by the radio as a single
240      * connection to the IMS conference server.
241      * <p>
242      * Indicating whether a conference has children or not is important to help user interfaces
243      * visually represent a conference.  A conference with no children, for example, will have the
244      * conference connection shown in the list of calls on a Bluetooth device, where if the
245      * conference has children, only the children will be shown in the list of calls on a Bluetooth
246      * device.
247      * @hide
248      */
249     public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
250 
251     //**********************************************************************************************
252     // Next CAPABILITY value: 0x00400000
253     //**********************************************************************************************
254 
255     /**
256      * Connection extra key used to store the last forwarded number associated with the current
257      * connection.  Used to communicate to the user interface that the connection was forwarded via
258      * the specified number.
259      */
260     public static final String EXTRA_LAST_FORWARDED_NUMBER =
261             "android.telecom.extra.LAST_FORWARDED_NUMBER";
262 
263     /**
264      * Connection extra key used to store a child number associated with the current connection.
265      * Used to communicate to the user interface that the connection was received via
266      * a child address (i.e. phone number) associated with the {@link PhoneAccount}'s primary
267      * address.
268      */
269     public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
270 
271     /**
272      * Connection extra key used to store the subject for an incoming call.  The user interface can
273      * query this extra and display its contents for incoming calls.  Will only be used if the
274      * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}.
275      */
276     public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
277 
278     // Flag controlling whether PII is emitted into the logs
279     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
280 
281     /**
282      * Whether the given capabilities support the specified capability.
283      *
284      * @param capabilities A capability bit field.
285      * @param capability The capability to check capabilities for.
286      * @return Whether the specified capability is supported.
287      * @hide
288      */
can(int capabilities, int capability)289     public static boolean can(int capabilities, int capability) {
290         return (capabilities & capability) != 0;
291     }
292 
293     /**
294      * Whether the capabilities of this {@code Connection} supports the specified capability.
295      *
296      * @param capability The capability to check capabilities for.
297      * @return Whether the specified capability is supported.
298      * @hide
299      */
can(int capability)300     public boolean can(int capability) {
301         return can(mConnectionCapabilities, capability);
302     }
303 
304     /**
305      * Removes the specified capability from the set of capabilities of this {@code Connection}.
306      *
307      * @param capability The capability to remove from the set.
308      * @hide
309      */
removeCapability(int capability)310     public void removeCapability(int capability) {
311         mConnectionCapabilities &= ~capability;
312     }
313 
314     /**
315      * Adds the specified capability to the set of capabilities of this {@code Connection}.
316      *
317      * @param capability The capability to add to the set.
318      * @hide
319      */
addCapability(int capability)320     public void addCapability(int capability) {
321         mConnectionCapabilities |= capability;
322     }
323 
324 
capabilitiesToString(int capabilities)325     public static String capabilitiesToString(int capabilities) {
326         StringBuilder builder = new StringBuilder();
327         builder.append("[Capabilities:");
328         if (can(capabilities, CAPABILITY_HOLD)) {
329             builder.append(" CAPABILITY_HOLD");
330         }
331         if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
332             builder.append(" CAPABILITY_SUPPORT_HOLD");
333         }
334         if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
335             builder.append(" CAPABILITY_MERGE_CONFERENCE");
336         }
337         if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
338             builder.append(" CAPABILITY_SWAP_CONFERENCE");
339         }
340         if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
341             builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
342         }
343         if (can(capabilities, CAPABILITY_MUTE)) {
344             builder.append(" CAPABILITY_MUTE");
345         }
346         if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
347             builder.append(" CAPABILITY_MANAGE_CONFERENCE");
348         }
349         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
350             builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
351         }
352         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
353             builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
354         }
355         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
356             builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
357         }
358         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
359             builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
360         }
361         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
362             builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
363         }
364         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
365             builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
366         }
367         if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
368             builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
369         }
370         if (can(capabilities, CAPABILITY_WIFI)) {
371             builder.append(" CAPABILITY_WIFI");
372         }
373         if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) {
374             builder.append(" CAPABILITY_GENERIC_CONFERENCE");
375         }
376         if (can(capabilities, CAPABILITY_SHOW_CALLBACK_NUMBER)) {
377             builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
378         }
379         if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
380             builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
381         }
382         if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
383             builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
384         }
385         if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
386             builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
387         }
388         if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
389             builder.append(" CAPABILITY_SINGLE_PARTY_CONFERENCE");
390         }
391         builder.append("]");
392         return builder.toString();
393     }
394 
395     /** @hide */
396     public abstract static class Listener {
onStateChanged(Connection c, int state)397         public void onStateChanged(Connection c, int state) {}
onAddressChanged(Connection c, Uri newAddress, int presentation)398         public void onAddressChanged(Connection c, Uri newAddress, int presentation) {}
onCallerDisplayNameChanged( Connection c, String callerDisplayName, int presentation)399         public void onCallerDisplayNameChanged(
400                 Connection c, String callerDisplayName, int presentation) {}
onVideoStateChanged(Connection c, int videoState)401         public void onVideoStateChanged(Connection c, int videoState) {}
onDisconnected(Connection c, DisconnectCause disconnectCause)402         public void onDisconnected(Connection c, DisconnectCause disconnectCause) {}
onPostDialWait(Connection c, String remaining)403         public void onPostDialWait(Connection c, String remaining) {}
onPostDialChar(Connection c, char nextChar)404         public void onPostDialChar(Connection c, char nextChar) {}
onRingbackRequested(Connection c, boolean ringback)405         public void onRingbackRequested(Connection c, boolean ringback) {}
onDestroyed(Connection c)406         public void onDestroyed(Connection c) {}
onConnectionCapabilitiesChanged(Connection c, int capabilities)407         public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {}
onVideoProviderChanged( Connection c, VideoProvider videoProvider)408         public void onVideoProviderChanged(
409                 Connection c, VideoProvider videoProvider) {}
onAudioModeIsVoipChanged(Connection c, boolean isVoip)410         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
onStatusHintsChanged(Connection c, StatusHints statusHints)411         public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
onConferenceablesChanged( Connection c, List<Conferenceable> conferenceables)412         public void onConferenceablesChanged(
413                 Connection c, List<Conferenceable> conferenceables) {}
onConferenceChanged(Connection c, Conference conference)414         public void onConferenceChanged(Connection c, Conference conference) {}
415         /** @hide */
onConferenceParticipantsChanged(Connection c, List<ConferenceParticipant> participants)416         public void onConferenceParticipantsChanged(Connection c,
417                 List<ConferenceParticipant> participants) {}
onConferenceStarted()418         public void onConferenceStarted() {}
onConferenceMergeFailed(Connection c)419         public void onConferenceMergeFailed(Connection c) {}
onExtrasChanged(Connection c, Bundle extras)420         public void onExtrasChanged(Connection c, Bundle extras) {}
421     }
422 
423     /**
424      * Provides a means of controlling the video session associated with a {@link Connection}.
425      * <p>
426      * Implementations create a custom subclass of {@link VideoProvider} and the
427      * {@link ConnectionService} creates an instance sets it on the {@link Connection} using
428      * {@link Connection#setVideoProvider(VideoProvider)}.  Any connection which supports video
429      * should set the {@link VideoProvider}.
430      * <p>
431      * The {@link VideoProvider} serves two primary purposes: it provides a means for Telecom and
432      * {@link InCallService} implementations to issue requests related to the video session;
433      * it provides a means for the {@link ConnectionService} to report events and information
434      * related to the video session to Telecom and the {@link InCallService} implementations.
435      * <p>
436      * {@link InCallService} implementations interact with the {@link VideoProvider} via
437      * {@link android.telecom.InCallService.VideoCall}.
438      */
439     public static abstract class VideoProvider {
440 
441         /**
442          * Video is not being received (no protocol pause was issued).
443          * @see #handleCallSessionEvent(int)
444          */
445         public static final int SESSION_EVENT_RX_PAUSE = 1;
446 
447         /**
448          * Video reception has resumed after a {@link #SESSION_EVENT_RX_PAUSE}.
449          * @see #handleCallSessionEvent(int)
450          */
451         public static final int SESSION_EVENT_RX_RESUME = 2;
452 
453         /**
454          * Video transmission has begun. This occurs after a negotiated start of video transmission
455          * when the underlying protocol has actually begun transmitting video to the remote party.
456          * @see #handleCallSessionEvent(int)
457          */
458         public static final int SESSION_EVENT_TX_START = 3;
459 
460         /**
461          * Video transmission has stopped. This occurs after a negotiated stop of video transmission
462          * when the underlying protocol has actually stopped transmitting video to the remote party.
463          * @see #handleCallSessionEvent(int)
464          */
465         public static final int SESSION_EVENT_TX_STOP = 4;
466 
467         /**
468          * A camera failure has occurred for the selected camera.  The {@link InCallService} can use
469          * this as a cue to inform the user the camera is not available.
470          * @see #handleCallSessionEvent(int)
471          */
472         public static final int SESSION_EVENT_CAMERA_FAILURE = 5;
473 
474         /**
475          * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready
476          * for operation.  The {@link InCallService} can use this as a cue to inform the user that
477          * the camera has become available again.
478          * @see #handleCallSessionEvent(int)
479          */
480         public static final int SESSION_EVENT_CAMERA_READY = 6;
481 
482         /**
483          * Session modify request was successful.
484          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
485          */
486         public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1;
487 
488         /**
489          * Session modify request failed.
490          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
491          */
492         public static final int SESSION_MODIFY_REQUEST_FAIL = 2;
493 
494         /**
495          * Session modify request ignored due to invalid parameters.
496          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
497          */
498         public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
499 
500         /**
501          * Session modify request timed out.
502          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
503          */
504         public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4;
505 
506         /**
507          * Session modify request rejected by remote user.
508          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
509          */
510         public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5;
511 
512         private static final int MSG_ADD_VIDEO_CALLBACK = 1;
513         private static final int MSG_SET_CAMERA = 2;
514         private static final int MSG_SET_PREVIEW_SURFACE = 3;
515         private static final int MSG_SET_DISPLAY_SURFACE = 4;
516         private static final int MSG_SET_DEVICE_ORIENTATION = 5;
517         private static final int MSG_SET_ZOOM = 6;
518         private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
519         private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
520         private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
521         private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10;
522         private static final int MSG_SET_PAUSE_IMAGE = 11;
523         private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
524 
525         private VideoProvider.VideoProviderHandler mMessageHandler;
526         private final VideoProvider.VideoProviderBinder mBinder;
527 
528         /**
529          * Stores a list of the video callbacks, keyed by IBinder.
530          *
531          * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
532          * load factor before resizing, 1 means we only expect a single thread to
533          * access the map so make only a single shard
534          */
535         private ConcurrentHashMap<IBinder, IVideoCallback> mVideoCallbacks =
536                 new ConcurrentHashMap<IBinder, IVideoCallback>(8, 0.9f, 1);
537 
538         /**
539          * Default handler used to consolidate binder method calls onto a single thread.
540          */
541         private final class VideoProviderHandler extends Handler {
VideoProviderHandler()542             public VideoProviderHandler() {
543                 super();
544             }
545 
VideoProviderHandler(Looper looper)546             public VideoProviderHandler(Looper looper) {
547                 super(looper);
548             }
549 
550             @Override
handleMessage(Message msg)551             public void handleMessage(Message msg) {
552                 switch (msg.what) {
553                     case MSG_ADD_VIDEO_CALLBACK: {
554                         IBinder binder = (IBinder) msg.obj;
555                         IVideoCallback callback = IVideoCallback.Stub
556                                 .asInterface((IBinder) msg.obj);
557                         if (callback == null) {
558                             Log.w(this, "addVideoProvider - skipped; callback is null.");
559                             break;
560                         }
561 
562                         if (mVideoCallbacks.containsKey(binder)) {
563                             Log.i(this, "addVideoProvider - skipped; already present.");
564                             break;
565                         }
566                         mVideoCallbacks.put(binder, callback);
567                         break;
568                     }
569                     case MSG_REMOVE_VIDEO_CALLBACK: {
570                         IBinder binder = (IBinder) msg.obj;
571                         IVideoCallback callback = IVideoCallback.Stub
572                                 .asInterface((IBinder) msg.obj);
573                         if (!mVideoCallbacks.containsKey(binder)) {
574                             Log.i(this, "removeVideoProvider - skipped; not present.");
575                             break;
576                         }
577                         mVideoCallbacks.remove(binder);
578                         break;
579                     }
580                     case MSG_SET_CAMERA:
581                         onSetCamera((String) msg.obj);
582                         break;
583                     case MSG_SET_PREVIEW_SURFACE:
584                         onSetPreviewSurface((Surface) msg.obj);
585                         break;
586                     case MSG_SET_DISPLAY_SURFACE:
587                         onSetDisplaySurface((Surface) msg.obj);
588                         break;
589                     case MSG_SET_DEVICE_ORIENTATION:
590                         onSetDeviceOrientation(msg.arg1);
591                         break;
592                     case MSG_SET_ZOOM:
593                         onSetZoom((Float) msg.obj);
594                         break;
595                     case MSG_SEND_SESSION_MODIFY_REQUEST: {
596                         SomeArgs args = (SomeArgs) msg.obj;
597                         try {
598                             onSendSessionModifyRequest((VideoProfile) args.arg1,
599                                     (VideoProfile) args.arg2);
600                         } finally {
601                             args.recycle();
602                         }
603                         break;
604                     }
605                     case MSG_SEND_SESSION_MODIFY_RESPONSE:
606                         onSendSessionModifyResponse((VideoProfile) msg.obj);
607                         break;
608                     case MSG_REQUEST_CAMERA_CAPABILITIES:
609                         onRequestCameraCapabilities();
610                         break;
611                     case MSG_REQUEST_CONNECTION_DATA_USAGE:
612                         onRequestConnectionDataUsage();
613                         break;
614                     case MSG_SET_PAUSE_IMAGE:
615                         onSetPauseImage((Uri) msg.obj);
616                         break;
617                     default:
618                         break;
619                 }
620             }
621         }
622 
623         /**
624          * IVideoProvider stub implementation.
625          */
626         private final class VideoProviderBinder extends IVideoProvider.Stub {
addVideoCallback(IBinder videoCallbackBinder)627             public void addVideoCallback(IBinder videoCallbackBinder) {
628                 mMessageHandler.obtainMessage(
629                         MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
630             }
631 
removeVideoCallback(IBinder videoCallbackBinder)632             public void removeVideoCallback(IBinder videoCallbackBinder) {
633                 mMessageHandler.obtainMessage(
634                         MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
635             }
636 
setCamera(String cameraId)637             public void setCamera(String cameraId) {
638                 mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
639             }
640 
setPreviewSurface(Surface surface)641             public void setPreviewSurface(Surface surface) {
642                 mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
643             }
644 
setDisplaySurface(Surface surface)645             public void setDisplaySurface(Surface surface) {
646                 mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
647             }
648 
setDeviceOrientation(int rotation)649             public void setDeviceOrientation(int rotation) {
650                 mMessageHandler.obtainMessage(
651                         MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget();
652             }
653 
setZoom(float value)654             public void setZoom(float value) {
655                 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
656             }
657 
sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)658             public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
659                 SomeArgs args = SomeArgs.obtain();
660                 args.arg1 = fromProfile;
661                 args.arg2 = toProfile;
662                 mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
663             }
664 
sendSessionModifyResponse(VideoProfile responseProfile)665             public void sendSessionModifyResponse(VideoProfile responseProfile) {
666                 mMessageHandler.obtainMessage(
667                         MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
668             }
669 
requestCameraCapabilities()670             public void requestCameraCapabilities() {
671                 mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
672             }
673 
requestCallDataUsage()674             public void requestCallDataUsage() {
675                 mMessageHandler.obtainMessage(MSG_REQUEST_CONNECTION_DATA_USAGE).sendToTarget();
676             }
677 
setPauseImage(Uri uri)678             public void setPauseImage(Uri uri) {
679                 mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
680             }
681         }
682 
VideoProvider()683         public VideoProvider() {
684             mBinder = new VideoProvider.VideoProviderBinder();
685             mMessageHandler = new VideoProvider.VideoProviderHandler(Looper.getMainLooper());
686         }
687 
688         /**
689          * Creates an instance of the {@link VideoProvider}, specifying the looper to use.
690          *
691          * @param looper The looper.
692          * @hide
693          */
VideoProvider(Looper looper)694         public VideoProvider(Looper looper) {
695             mBinder = new VideoProvider.VideoProviderBinder();
696             mMessageHandler = new VideoProvider.VideoProviderHandler(looper);
697         }
698 
699         /**
700          * Returns binder object which can be used across IPC methods.
701          * @hide
702          */
getInterface()703         public final IVideoProvider getInterface() {
704             return mBinder;
705         }
706 
707         /**
708          * Sets the camera to be used for the outgoing video.
709          * <p>
710          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
711          * camera via
712          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
713          * <p>
714          * Sent from the {@link InCallService} via
715          * {@link InCallService.VideoCall#setCamera(String)}.
716          *
717          * @param cameraId The id of the camera (use ids as reported by
718          * {@link CameraManager#getCameraIdList()}).
719          */
onSetCamera(String cameraId)720         public abstract void onSetCamera(String cameraId);
721 
722         /**
723          * Sets the surface to be used for displaying a preview of what the user's camera is
724          * currently capturing.  When video transmission is enabled, this is the video signal which
725          * is sent to the remote device.
726          * <p>
727          * Sent from the {@link InCallService} via
728          * {@link InCallService.VideoCall#setPreviewSurface(Surface)}.
729          *
730          * @param surface The {@link Surface}.
731          */
onSetPreviewSurface(Surface surface)732         public abstract void onSetPreviewSurface(Surface surface);
733 
734         /**
735          * Sets the surface to be used for displaying the video received from the remote device.
736          * <p>
737          * Sent from the {@link InCallService} via
738          * {@link InCallService.VideoCall#setDisplaySurface(Surface)}.
739          *
740          * @param surface The {@link Surface}.
741          */
onSetDisplaySurface(Surface surface)742         public abstract void onSetDisplaySurface(Surface surface);
743 
744         /**
745          * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of
746          * the device is 0 degrees.
747          * <p>
748          * Sent from the {@link InCallService} via
749          * {@link InCallService.VideoCall#setDeviceOrientation(int)}.
750          *
751          * @param rotation The device orientation, in degrees.
752          */
onSetDeviceOrientation(int rotation)753         public abstract void onSetDeviceOrientation(int rotation);
754 
755         /**
756          * Sets camera zoom ratio.
757          * <p>
758          * Sent from the {@link InCallService} via {@link InCallService.VideoCall#setZoom(float)}.
759          *
760          * @param value The camera zoom ratio.
761          */
onSetZoom(float value)762         public abstract void onSetZoom(float value);
763 
764         /**
765          * Issues a request to modify the properties of the current video session.
766          * <p>
767          * Example scenarios include: requesting an audio-only call to be upgraded to a
768          * bi-directional video call, turning on or off the user's camera, sending a pause signal
769          * when the {@link InCallService} is no longer the foreground application.
770          * <p>
771          * If the {@link VideoProvider} determines a request to be invalid, it should call
772          * {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} to report the
773          * invalid request back to the {@link InCallService}.
774          * <p>
775          * Where a request requires confirmation from the user of the peer device, the
776          * {@link VideoProvider} must communicate the request to the peer device and handle the
777          * user's response.  {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)}
778          * is used to inform the {@link InCallService} of the result of the request.
779          * <p>
780          * Sent from the {@link InCallService} via
781          * {@link InCallService.VideoCall#sendSessionModifyRequest(VideoProfile)}.
782          *
783          * @param fromProfile The video profile prior to the request.
784          * @param toProfile The video profile with the requested changes made.
785          */
onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)786         public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
787                 VideoProfile toProfile);
788 
789         /**
790          * Provides a response to a request to change the current video session properties.
791          * <p>
792          * For example, if the peer requests and upgrade from an audio-only call to a bi-directional
793          * video call, could decline the request and keep the call as audio-only.
794          * In such a scenario, the {@code responseProfile} would have a video state of
795          * {@link VideoProfile#STATE_AUDIO_ONLY}.  If the user had decided to accept the request,
796          * the video state would be {@link VideoProfile#STATE_BIDIRECTIONAL}.
797          * <p>
798          * Sent from the {@link InCallService} via
799          * {@link InCallService.VideoCall#sendSessionModifyResponse(VideoProfile)} in response to
800          * a {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)}
801          * callback.
802          *
803          * @param responseProfile The response video profile.
804          */
onSendSessionModifyResponse(VideoProfile responseProfile)805         public abstract void onSendSessionModifyResponse(VideoProfile responseProfile);
806 
807         /**
808          * Issues a request to the {@link VideoProvider} to retrieve the camera capabilities.
809          * <p>
810          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
811          * camera via
812          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
813          * <p>
814          * Sent from the {@link InCallService} via
815          * {@link InCallService.VideoCall#requestCameraCapabilities()}.
816          */
onRequestCameraCapabilities()817         public abstract void onRequestCameraCapabilities();
818 
819         /**
820          * Issues a request to the {@link VideoProvider} to retrieve the current data usage for the
821          * video component of the current {@link Connection}.
822          * <p>
823          * The {@link VideoProvider} should respond by communicating current data usage, in bytes,
824          * via {@link VideoProvider#setCallDataUsage(long)}.
825          * <p>
826          * Sent from the {@link InCallService} via
827          * {@link InCallService.VideoCall#requestCallDataUsage()}.
828          */
onRequestConnectionDataUsage()829         public abstract void onRequestConnectionDataUsage();
830 
831         /**
832          * Provides the {@link VideoProvider} with the {@link Uri} of an image to be displayed to
833          * the peer device when the video signal is paused.
834          * <p>
835          * Sent from the {@link InCallService} via
836          * {@link InCallService.VideoCall#setPauseImage(Uri)}.
837          *
838          * @param uri URI of image to display.
839          */
onSetPauseImage(Uri uri)840         public abstract void onSetPauseImage(Uri uri);
841 
842         /**
843          * Used to inform listening {@link InCallService} implementations when the
844          * {@link VideoProvider} receives a session modification request.
845          * <p>
846          * Received by the {@link InCallService} via
847          * {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)},
848          *
849          * @param videoProfile The requested video profile.
850          * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)
851          */
receiveSessionModifyRequest(VideoProfile videoProfile)852         public void receiveSessionModifyRequest(VideoProfile videoProfile) {
853             if (mVideoCallbacks != null) {
854                 for (IVideoCallback callback : mVideoCallbacks.values()) {
855                     try {
856                         callback.receiveSessionModifyRequest(videoProfile);
857                     } catch (RemoteException ignored) {
858                         Log.w(this, "receiveSessionModifyRequest callback failed", ignored);
859                     }
860                 }
861             }
862         }
863 
864         /**
865          * Used to inform listening {@link InCallService} implementations when the
866          * {@link VideoProvider} receives a response to a session modification request.
867          * <p>
868          * Received by the {@link InCallService} via
869          * {@link InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int,
870          * VideoProfile, VideoProfile)}.
871          *
872          * @param status Status of the session modify request.  Valid values are
873          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS},
874          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_FAIL},
875          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_INVALID},
876          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_TIMED_OUT},
877          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE}
878          * @param requestedProfile The original request which was sent to the peer device.
879          * @param responseProfile The actual profile changes agreed to by the peer device.
880          * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)
881          */
receiveSessionModifyResponse(int status, VideoProfile requestedProfile, VideoProfile responseProfile)882         public void receiveSessionModifyResponse(int status,
883                 VideoProfile requestedProfile, VideoProfile responseProfile) {
884             if (mVideoCallbacks != null) {
885                 for (IVideoCallback callback : mVideoCallbacks.values()) {
886                     try {
887                         callback.receiveSessionModifyResponse(status, requestedProfile,
888                                 responseProfile);
889                     } catch (RemoteException ignored) {
890                         Log.w(this, "receiveSessionModifyResponse callback failed", ignored);
891                     }
892                 }
893             }
894         }
895 
896         /**
897          * Used to inform listening {@link InCallService} implementations when the
898          * {@link VideoProvider} reports a call session event.
899          * <p>
900          * Received by the {@link InCallService} via
901          * {@link InCallService.VideoCall.Callback#onCallSessionEvent(int)}.
902          *
903          * @param event The event.  Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE},
904          *      {@link VideoProvider#SESSION_EVENT_RX_RESUME},
905          *      {@link VideoProvider#SESSION_EVENT_TX_START},
906          *      {@link VideoProvider#SESSION_EVENT_TX_STOP},
907          *      {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
908          *      {@link VideoProvider#SESSION_EVENT_CAMERA_READY}.
909          */
handleCallSessionEvent(int event)910         public void handleCallSessionEvent(int event) {
911             if (mVideoCallbacks != null) {
912                 for (IVideoCallback callback : mVideoCallbacks.values()) {
913                     try {
914                         callback.handleCallSessionEvent(event);
915                     } catch (RemoteException ignored) {
916                         Log.w(this, "handleCallSessionEvent callback failed", ignored);
917                     }
918                 }
919             }
920         }
921 
922         /**
923          * Used to inform listening {@link InCallService} implementations when the dimensions of the
924          * peer's video have changed.
925          * <p>
926          * This could occur if, for example, the peer rotates their device, changing the aspect
927          * ratio of the video, or if the user switches between the back and front cameras.
928          * <p>
929          * Received by the {@link InCallService} via
930          * {@link InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int)}.
931          *
932          * @param width  The updated peer video width.
933          * @param height The updated peer video height.
934          */
changePeerDimensions(int width, int height)935         public void changePeerDimensions(int width, int height) {
936             if (mVideoCallbacks != null) {
937                 for (IVideoCallback callback : mVideoCallbacks.values()) {
938                     try {
939                         callback.changePeerDimensions(width, height);
940                     } catch (RemoteException ignored) {
941                         Log.w(this, "changePeerDimensions callback failed", ignored);
942                     }
943                 }
944             }
945         }
946 
947         /**
948          * Used to inform listening {@link InCallService} implementations when the data usage of the
949          * video associated with the current {@link Connection} has changed.
950          * <p>
951          * This could be in response to a preview request via
952          * {@link #onRequestConnectionDataUsage()}, or as a periodic update by the
953          * {@link VideoProvider}.  Where periodic updates of data usage are provided, they should be
954          * provided at most for every 1 MB of data transferred and no more than once every 10 sec.
955          * <p>
956          * Received by the {@link InCallService} via
957          * {@link InCallService.VideoCall.Callback#onCallDataUsageChanged(long)}.
958          *
959          * @param dataUsage The updated data usage (in bytes).  Reported as the cumulative bytes
960          *                  used since the start of the call.
961          */
setCallDataUsage(long dataUsage)962         public void setCallDataUsage(long dataUsage) {
963             if (mVideoCallbacks != null) {
964                 for (IVideoCallback callback : mVideoCallbacks.values()) {
965                     try {
966                         callback.changeCallDataUsage(dataUsage);
967                     } catch (RemoteException ignored) {
968                         Log.w(this, "setCallDataUsage callback failed", ignored);
969                     }
970                 }
971             }
972         }
973 
974         /**
975          * @see #setCallDataUsage(long)
976          *
977          * @param dataUsage The updated data usage (in byes).
978          * @deprecated - Use {@link #setCallDataUsage(long)} instead.
979          * @hide
980          */
changeCallDataUsage(long dataUsage)981         public void changeCallDataUsage(long dataUsage) {
982             setCallDataUsage(dataUsage);
983         }
984 
985         /**
986          * Used to inform listening {@link InCallService} implementations when the capabilities of
987          * the current camera have changed.
988          * <p>
989          * The {@link VideoProvider} should call this in response to
990          * {@link VideoProvider#onRequestCameraCapabilities()}, or when the current camera is
991          * changed via {@link VideoProvider#onSetCamera(String)}.
992          * <p>
993          * Received by the {@link InCallService} via
994          * {@link InCallService.VideoCall.Callback#onCameraCapabilitiesChanged(
995          * VideoProfile.CameraCapabilities)}.
996          *
997          * @param cameraCapabilities The new camera capabilities.
998          */
changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities)999         public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
1000             if (mVideoCallbacks != null) {
1001                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1002                     try {
1003                         callback.changeCameraCapabilities(cameraCapabilities);
1004                     } catch (RemoteException ignored) {
1005                         Log.w(this, "changeCameraCapabilities callback failed", ignored);
1006                     }
1007                 }
1008             }
1009         }
1010 
1011         /**
1012          * Used to inform listening {@link InCallService} implementations when the video quality
1013          * of the call has changed.
1014          * <p>
1015          * Received by the {@link InCallService} via
1016          * {@link InCallService.VideoCall.Callback#onVideoQualityChanged(int)}.
1017          *
1018          * @param videoQuality The updated video quality.  Valid values:
1019          *      {@link VideoProfile#QUALITY_HIGH},
1020          *      {@link VideoProfile#QUALITY_MEDIUM},
1021          *      {@link VideoProfile#QUALITY_LOW},
1022          *      {@link VideoProfile#QUALITY_DEFAULT}.
1023          */
changeVideoQuality(int videoQuality)1024         public void changeVideoQuality(int videoQuality) {
1025             if (mVideoCallbacks != null) {
1026                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1027                     try {
1028                         callback.changeVideoQuality(videoQuality);
1029                     } catch (RemoteException ignored) {
1030                         Log.w(this, "changeVideoQuality callback failed", ignored);
1031                     }
1032                 }
1033             }
1034         }
1035     }
1036 
1037     private final Listener mConnectionDeathListener = new Listener() {
1038         @Override
1039         public void onDestroyed(Connection c) {
1040             if (mConferenceables.remove(c)) {
1041                 fireOnConferenceableConnectionsChanged();
1042             }
1043         }
1044     };
1045 
1046     private final Conference.Listener mConferenceDeathListener = new Conference.Listener() {
1047         @Override
1048         public void onDestroyed(Conference c) {
1049             if (mConferenceables.remove(c)) {
1050                 fireOnConferenceableConnectionsChanged();
1051             }
1052         }
1053     };
1054 
1055     /**
1056      * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
1057      * load factor before resizing, 1 means we only expect a single thread to
1058      * access the map so make only a single shard
1059      */
1060     private final Set<Listener> mListeners = Collections.newSetFromMap(
1061             new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
1062     private final List<Conferenceable> mConferenceables = new ArrayList<>();
1063     private final List<Conferenceable> mUnmodifiableConferenceables =
1064             Collections.unmodifiableList(mConferenceables);
1065 
1066     private int mState = STATE_NEW;
1067     private CallAudioState mCallAudioState;
1068     private Uri mAddress;
1069     private int mAddressPresentation;
1070     private String mCallerDisplayName;
1071     private int mCallerDisplayNamePresentation;
1072     private boolean mRingbackRequested = false;
1073     private int mConnectionCapabilities;
1074     private VideoProvider mVideoProvider;
1075     private boolean mAudioModeIsVoip;
1076     private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
1077     private StatusHints mStatusHints;
1078     private int mVideoState;
1079     private DisconnectCause mDisconnectCause;
1080     private Conference mConference;
1081     private ConnectionService mConnectionService;
1082     private Bundle mExtras;
1083 
1084     /**
1085      * Create a new Connection.
1086      */
Connection()1087     public Connection() {}
1088 
1089     /**
1090      * @return The address (e.g., phone number) to which this Connection is currently communicating.
1091      */
getAddress()1092     public final Uri getAddress() {
1093         return mAddress;
1094     }
1095 
1096     /**
1097      * @return The presentation requirements for the address.
1098      *         See {@link TelecomManager} for valid values.
1099      */
getAddressPresentation()1100     public final int getAddressPresentation() {
1101         return mAddressPresentation;
1102     }
1103 
1104     /**
1105      * @return The caller display name (CNAP).
1106      */
getCallerDisplayName()1107     public final String getCallerDisplayName() {
1108         return mCallerDisplayName;
1109     }
1110 
1111     /**
1112      * @return The presentation requirements for the handle.
1113      *         See {@link TelecomManager} for valid values.
1114      */
getCallerDisplayNamePresentation()1115     public final int getCallerDisplayNamePresentation() {
1116         return mCallerDisplayNamePresentation;
1117     }
1118 
1119     /**
1120      * @return The state of this Connection.
1121      */
getState()1122     public final int getState() {
1123         return mState;
1124     }
1125 
1126     /**
1127      * Returns the video state of the connection.
1128      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
1129      * {@link VideoProfile#STATE_BIDIRECTIONAL},
1130      * {@link VideoProfile#STATE_TX_ENABLED},
1131      * {@link VideoProfile#STATE_RX_ENABLED}.
1132      *
1133      * @return The video state of the connection.
1134      * @hide
1135      */
getVideoState()1136     public final int getVideoState() {
1137         return mVideoState;
1138     }
1139 
1140     /**
1141      * @return The audio state of the connection, describing how its audio is currently
1142      *         being routed by the system. This is {@code null} if this Connection
1143      *         does not directly know about its audio state.
1144      * @deprecated Use {@link #getCallAudioState()} instead.
1145      * @hide
1146      */
1147     @SystemApi
1148     @Deprecated
getAudioState()1149     public final AudioState getAudioState() {
1150         if (mCallAudioState == null) {
1151           return null;
1152         }
1153         return new AudioState(mCallAudioState);
1154     }
1155 
1156     /**
1157      * @return The audio state of the connection, describing how its audio is currently
1158      *         being routed by the system. This is {@code null} if this Connection
1159      *         does not directly know about its audio state.
1160      */
getCallAudioState()1161     public final CallAudioState getCallAudioState() {
1162         return mCallAudioState;
1163     }
1164 
1165     /**
1166      * @return The conference that this connection is a part of.  Null if it is not part of any
1167      *         conference.
1168      */
getConference()1169     public final Conference getConference() {
1170         return mConference;
1171     }
1172 
1173     /**
1174      * Returns whether this connection is requesting that the system play a ringback tone
1175      * on its behalf.
1176      */
isRingbackRequested()1177     public final boolean isRingbackRequested() {
1178         return mRingbackRequested;
1179     }
1180 
1181     /**
1182      * @return True if the connection's audio mode is VOIP.
1183      */
getAudioModeIsVoip()1184     public final boolean getAudioModeIsVoip() {
1185         return mAudioModeIsVoip;
1186     }
1187 
1188     /**
1189      * Retrieves the connection start time of the {@code Connnection}, if specified.  A value of
1190      * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the
1191      * start time of the conference.
1192      *
1193      * @return The time at which the {@code Connnection} was connected.
1194      *
1195      * @hide
1196      */
getConnectTimeMillis()1197     public final long getConnectTimeMillis() {
1198         return mConnectTimeMillis;
1199     }
1200 
1201     /**
1202      * @return The status hints for this connection.
1203      */
getStatusHints()1204     public final StatusHints getStatusHints() {
1205         return mStatusHints;
1206     }
1207 
1208     /**
1209      * @return The extras associated with this connection.
1210      */
getExtras()1211     public final Bundle getExtras() {
1212         return mExtras;
1213     }
1214 
1215     /**
1216      * Assign a listener to be notified of state changes.
1217      *
1218      * @param l A listener.
1219      * @return This Connection.
1220      *
1221      * @hide
1222      */
addConnectionListener(Listener l)1223     public final Connection addConnectionListener(Listener l) {
1224         mListeners.add(l);
1225         return this;
1226     }
1227 
1228     /**
1229      * Remove a previously assigned listener that was being notified of state changes.
1230      *
1231      * @param l A Listener.
1232      * @return This Connection.
1233      *
1234      * @hide
1235      */
removeConnectionListener(Listener l)1236     public final Connection removeConnectionListener(Listener l) {
1237         if (l != null) {
1238             mListeners.remove(l);
1239         }
1240         return this;
1241     }
1242 
1243     /**
1244      * @return The {@link DisconnectCause} for this connection.
1245      */
getDisconnectCause()1246     public final DisconnectCause getDisconnectCause() {
1247         return mDisconnectCause;
1248     }
1249 
1250     /**
1251      * Inform this Connection that the state of its audio output has been changed externally.
1252      *
1253      * @param state The new audio state.
1254      * @hide
1255      */
setCallAudioState(CallAudioState state)1256     final void setCallAudioState(CallAudioState state) {
1257         checkImmutable();
1258         Log.d(this, "setAudioState %s", state);
1259         mCallAudioState = state;
1260         onAudioStateChanged(getAudioState());
1261         onCallAudioStateChanged(state);
1262     }
1263 
1264     /**
1265      * @param state An integer value of a {@code STATE_*} constant.
1266      * @return A string representation of the value.
1267      */
stateToString(int state)1268     public static String stateToString(int state) {
1269         switch (state) {
1270             case STATE_INITIALIZING:
1271                 return "INITIALIZING";
1272             case STATE_NEW:
1273                 return "NEW";
1274             case STATE_RINGING:
1275                 return "RINGING";
1276             case STATE_DIALING:
1277                 return "DIALING";
1278             case STATE_ACTIVE:
1279                 return "ACTIVE";
1280             case STATE_HOLDING:
1281                 return "HOLDING";
1282             case STATE_DISCONNECTED:
1283                 return "DISCONNECTED";
1284             default:
1285                 Log.wtf(Connection.class, "Unknown state %d", state);
1286                 return "UNKNOWN";
1287         }
1288     }
1289 
1290     /**
1291      * Returns the connection's capabilities, as a bit mask of the {@code CAPABILITY_*} constants.
1292      */
getConnectionCapabilities()1293     public final int getConnectionCapabilities() {
1294         return mConnectionCapabilities;
1295     }
1296 
1297     /**
1298      * Sets the value of the {@link #getAddress()} property.
1299      *
1300      * @param address The new address.
1301      * @param presentation The presentation requirements for the address.
1302      *        See {@link TelecomManager} for valid values.
1303      */
setAddress(Uri address, int presentation)1304     public final void setAddress(Uri address, int presentation) {
1305         checkImmutable();
1306         Log.d(this, "setAddress %s", address);
1307         mAddress = address;
1308         mAddressPresentation = presentation;
1309         for (Listener l : mListeners) {
1310             l.onAddressChanged(this, address, presentation);
1311         }
1312     }
1313 
1314     /**
1315      * Sets the caller display name (CNAP).
1316      *
1317      * @param callerDisplayName The new display name.
1318      * @param presentation The presentation requirements for the handle.
1319      *        See {@link TelecomManager} for valid values.
1320      */
setCallerDisplayName(String callerDisplayName, int presentation)1321     public final void setCallerDisplayName(String callerDisplayName, int presentation) {
1322         checkImmutable();
1323         Log.d(this, "setCallerDisplayName %s", callerDisplayName);
1324         mCallerDisplayName = callerDisplayName;
1325         mCallerDisplayNamePresentation = presentation;
1326         for (Listener l : mListeners) {
1327             l.onCallerDisplayNameChanged(this, callerDisplayName, presentation);
1328         }
1329     }
1330 
1331     /**
1332      * Set the video state for the connection.
1333      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
1334      * {@link VideoProfile#STATE_BIDIRECTIONAL},
1335      * {@link VideoProfile#STATE_TX_ENABLED},
1336      * {@link VideoProfile#STATE_RX_ENABLED}.
1337      *
1338      * @param videoState The new video state.
1339      */
setVideoState(int videoState)1340     public final void setVideoState(int videoState) {
1341         checkImmutable();
1342         Log.d(this, "setVideoState %d", videoState);
1343         mVideoState = videoState;
1344         for (Listener l : mListeners) {
1345             l.onVideoStateChanged(this, mVideoState);
1346         }
1347     }
1348 
1349     /**
1350      * Sets state to active (e.g., an ongoing connection where two or more parties can actively
1351      * communicate).
1352      */
setActive()1353     public final void setActive() {
1354         checkImmutable();
1355         setRingbackRequested(false);
1356         setState(STATE_ACTIVE);
1357     }
1358 
1359     /**
1360      * Sets state to ringing (e.g., an inbound ringing connection).
1361      */
setRinging()1362     public final void setRinging() {
1363         checkImmutable();
1364         setState(STATE_RINGING);
1365     }
1366 
1367     /**
1368      * Sets state to initializing (this Connection is not yet ready to be used).
1369      */
setInitializing()1370     public final void setInitializing() {
1371         checkImmutable();
1372         setState(STATE_INITIALIZING);
1373     }
1374 
1375     /**
1376      * Sets state to initialized (the Connection has been set up and is now ready to be used).
1377      */
setInitialized()1378     public final void setInitialized() {
1379         checkImmutable();
1380         setState(STATE_NEW);
1381     }
1382 
1383     /**
1384      * Sets state to dialing (e.g., dialing an outbound connection).
1385      */
setDialing()1386     public final void setDialing() {
1387         checkImmutable();
1388         setState(STATE_DIALING);
1389     }
1390 
1391     /**
1392      * Sets state to be on hold.
1393      */
setOnHold()1394     public final void setOnHold() {
1395         checkImmutable();
1396         setState(STATE_HOLDING);
1397     }
1398 
1399     /**
1400      * Sets the video connection provider.
1401      * @param videoProvider The video provider.
1402      */
setVideoProvider(VideoProvider videoProvider)1403     public final void setVideoProvider(VideoProvider videoProvider) {
1404         checkImmutable();
1405         mVideoProvider = videoProvider;
1406         for (Listener l : mListeners) {
1407             l.onVideoProviderChanged(this, videoProvider);
1408         }
1409     }
1410 
getVideoProvider()1411     public final VideoProvider getVideoProvider() {
1412         return mVideoProvider;
1413     }
1414 
1415     /**
1416      * Sets state to disconnected.
1417      *
1418      * @param disconnectCause The reason for the disconnection, as specified by
1419      *         {@link DisconnectCause}.
1420      */
setDisconnected(DisconnectCause disconnectCause)1421     public final void setDisconnected(DisconnectCause disconnectCause) {
1422         checkImmutable();
1423         mDisconnectCause = disconnectCause;
1424         setState(STATE_DISCONNECTED);
1425         Log.d(this, "Disconnected with cause %s", disconnectCause);
1426         for (Listener l : mListeners) {
1427             l.onDisconnected(this, disconnectCause);
1428         }
1429     }
1430 
1431     /**
1432      * Informs listeners that this {@code Connection} is in a post-dial wait state. This is done
1433      * when (a) the {@code Connection} is issuing a DTMF sequence; (b) it has encountered a "wait"
1434      * character; and (c) it wishes to inform the In-Call app that it is waiting for the end-user
1435      * to send an {@link #onPostDialContinue(boolean)} signal.
1436      *
1437      * @param remaining The DTMF character sequence remaining to be emitted once the
1438      *         {@link #onPostDialContinue(boolean)} is received, including any "wait" characters
1439      *         that remaining sequence may contain.
1440      */
setPostDialWait(String remaining)1441     public final void setPostDialWait(String remaining) {
1442         checkImmutable();
1443         for (Listener l : mListeners) {
1444             l.onPostDialWait(this, remaining);
1445         }
1446     }
1447 
1448     /**
1449      * Informs listeners that this {@code Connection} has processed a character in the post-dial
1450      * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence;
1451      * and (b) it wishes to signal Telecom to play the corresponding DTMF tone locally.
1452      *
1453      * @param nextChar The DTMF character that was just processed by the {@code Connection}.
1454      */
setNextPostDialChar(char nextChar)1455     public final void setNextPostDialChar(char nextChar) {
1456         checkImmutable();
1457         for (Listener l : mListeners) {
1458             l.onPostDialChar(this, nextChar);
1459         }
1460     }
1461 
1462     /**
1463      * Requests that the framework play a ringback tone. This is to be invoked by implementations
1464      * that do not play a ringback tone themselves in the connection's audio stream.
1465      *
1466      * @param ringback Whether the ringback tone is to be played.
1467      */
setRingbackRequested(boolean ringback)1468     public final void setRingbackRequested(boolean ringback) {
1469         checkImmutable();
1470         if (mRingbackRequested != ringback) {
1471             mRingbackRequested = ringback;
1472             for (Listener l : mListeners) {
1473                 l.onRingbackRequested(this, ringback);
1474             }
1475         }
1476     }
1477 
1478     /**
1479      * Sets the connection's capabilities as a bit mask of the {@code CAPABILITY_*} constants.
1480      *
1481      * @param connectionCapabilities The new connection capabilities.
1482      */
setConnectionCapabilities(int connectionCapabilities)1483     public final void setConnectionCapabilities(int connectionCapabilities) {
1484         checkImmutable();
1485         if (mConnectionCapabilities != connectionCapabilities) {
1486             mConnectionCapabilities = connectionCapabilities;
1487             for (Listener l : mListeners) {
1488                 l.onConnectionCapabilitiesChanged(this, mConnectionCapabilities);
1489             }
1490         }
1491     }
1492 
1493     /**
1494      * Tears down the Connection object.
1495      */
destroy()1496     public final void destroy() {
1497         for (Listener l : mListeners) {
1498             l.onDestroyed(this);
1499         }
1500     }
1501 
1502     /**
1503      * Requests that the framework use VOIP audio mode for this connection.
1504      *
1505      * @param isVoip True if the audio mode is VOIP.
1506      */
setAudioModeIsVoip(boolean isVoip)1507     public final void setAudioModeIsVoip(boolean isVoip) {
1508         checkImmutable();
1509         mAudioModeIsVoip = isVoip;
1510         for (Listener l : mListeners) {
1511             l.onAudioModeIsVoipChanged(this, isVoip);
1512         }
1513     }
1514 
1515     /**
1516      * Sets the time at which a call became active on this Connection. This is set only
1517      * when a conference call becomes active on this connection.
1518      *
1519      * @param connectionTimeMillis The connection time, in milliseconds.
1520      *
1521      * @hide
1522      */
setConnectTimeMillis(long connectTimeMillis)1523     public final void setConnectTimeMillis(long connectTimeMillis) {
1524         mConnectTimeMillis = connectTimeMillis;
1525     }
1526 
1527     /**
1528      * Sets the label and icon status to display in the in-call UI.
1529      *
1530      * @param statusHints The status label and icon to set.
1531      */
setStatusHints(StatusHints statusHints)1532     public final void setStatusHints(StatusHints statusHints) {
1533         checkImmutable();
1534         mStatusHints = statusHints;
1535         for (Listener l : mListeners) {
1536             l.onStatusHintsChanged(this, statusHints);
1537         }
1538     }
1539 
1540     /**
1541      * Sets the connections with which this connection can be conferenced.
1542      *
1543      * @param conferenceableConnections The set of connections this connection can conference with.
1544      */
setConferenceableConnections(List<Connection> conferenceableConnections)1545     public final void setConferenceableConnections(List<Connection> conferenceableConnections) {
1546         checkImmutable();
1547         clearConferenceableList();
1548         for (Connection c : conferenceableConnections) {
1549             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
1550             // small amount of items here.
1551             if (!mConferenceables.contains(c)) {
1552                 c.addConnectionListener(mConnectionDeathListener);
1553                 mConferenceables.add(c);
1554             }
1555         }
1556         fireOnConferenceableConnectionsChanged();
1557     }
1558 
1559     /**
1560      * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections
1561      * or conferences with which this connection can be conferenced.
1562      *
1563      * @param conferenceables The conferenceables.
1564      */
setConferenceables(List<Conferenceable> conferenceables)1565     public final void setConferenceables(List<Conferenceable> conferenceables) {
1566         clearConferenceableList();
1567         for (Conferenceable c : conferenceables) {
1568             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
1569             // small amount of items here.
1570             if (!mConferenceables.contains(c)) {
1571                 if (c instanceof Connection) {
1572                     Connection connection = (Connection) c;
1573                     connection.addConnectionListener(mConnectionDeathListener);
1574                 } else if (c instanceof Conference) {
1575                     Conference conference = (Conference) c;
1576                     conference.addListener(mConferenceDeathListener);
1577                 }
1578                 mConferenceables.add(c);
1579             }
1580         }
1581         fireOnConferenceableConnectionsChanged();
1582     }
1583 
1584     /**
1585      * Returns the connections or conferences with which this connection can be conferenced.
1586      */
getConferenceables()1587     public final List<Conferenceable> getConferenceables() {
1588         return mUnmodifiableConferenceables;
1589     }
1590 
1591     /**
1592      * @hide
1593      */
setConnectionService(ConnectionService connectionService)1594     public final void setConnectionService(ConnectionService connectionService) {
1595         checkImmutable();
1596         if (mConnectionService != null) {
1597             Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " +
1598                     "which is already associated with another ConnectionService.");
1599         } else {
1600             mConnectionService = connectionService;
1601         }
1602     }
1603 
1604     /**
1605      * @hide
1606      */
unsetConnectionService(ConnectionService connectionService)1607     public final void unsetConnectionService(ConnectionService connectionService) {
1608         if (mConnectionService != connectionService) {
1609             Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " +
1610                     "that does not belong to the ConnectionService.");
1611         } else {
1612             mConnectionService = null;
1613         }
1614     }
1615 
1616     /**
1617      * @hide
1618      */
getConnectionService()1619     public final ConnectionService getConnectionService() {
1620         return mConnectionService;
1621     }
1622 
1623     /**
1624      * Sets the conference that this connection is a part of. This will fail if the connection is
1625      * already part of a conference. {@link #resetConference} to un-set the conference first.
1626      *
1627      * @param conference The conference.
1628      * @return {@code true} if the conference was successfully set.
1629      * @hide
1630      */
setConference(Conference conference)1631     public final boolean setConference(Conference conference) {
1632         checkImmutable();
1633         // We check to see if it is already part of another conference.
1634         if (mConference == null) {
1635             mConference = conference;
1636             if (mConnectionService != null && mConnectionService.containsConference(conference)) {
1637                 fireConferenceChanged();
1638             }
1639             return true;
1640         }
1641         return false;
1642     }
1643 
1644     /**
1645      * Resets the conference that this connection is a part of.
1646      * @hide
1647      */
resetConference()1648     public final void resetConference() {
1649         if (mConference != null) {
1650             Log.d(this, "Conference reset");
1651             mConference = null;
1652             fireConferenceChanged();
1653         }
1654     }
1655 
1656     /**
1657      * Set some extras that can be associated with this {@code Connection}. No assumptions should
1658      * be made as to how an In-Call UI or service will handle these extras.
1659      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
1660      *
1661      * @param extras The extras associated with this {@code Connection}.
1662      */
setExtras(@ullable Bundle extras)1663     public final void setExtras(@Nullable Bundle extras) {
1664         checkImmutable();
1665         mExtras = extras;
1666         for (Listener l : mListeners) {
1667             l.onExtrasChanged(this, extras);
1668         }
1669     }
1670 
1671     /**
1672      * Notifies this Connection that the {@link #getAudioState()} property has a new value.
1673      *
1674      * @param state The new connection audio state.
1675      * @deprecated Use {@link #onCallAudioStateChanged(CallAudioState)} instead.
1676      * @hide
1677      */
1678     @SystemApi
1679     @Deprecated
onAudioStateChanged(AudioState state)1680     public void onAudioStateChanged(AudioState state) {}
1681 
1682     /**
1683      * Notifies this Connection that the {@link #getCallAudioState()} property has a new value.
1684      *
1685      * @param state The new connection audio state.
1686      */
onCallAudioStateChanged(CallAudioState state)1687     public void onCallAudioStateChanged(CallAudioState state) {}
1688 
1689     /**
1690      * Notifies this Connection of an internal state change. This method is called after the
1691      * state is changed.
1692      *
1693      * @param state The new state, one of the {@code STATE_*} constants.
1694      */
onStateChanged(int state)1695     public void onStateChanged(int state) {}
1696 
1697     /**
1698      * Notifies this Connection of a request to play a DTMF tone.
1699      *
1700      * @param c A DTMF character.
1701      */
onPlayDtmfTone(char c)1702     public void onPlayDtmfTone(char c) {}
1703 
1704     /**
1705      * Notifies this Connection of a request to stop any currently playing DTMF tones.
1706      */
onStopDtmfTone()1707     public void onStopDtmfTone() {}
1708 
1709     /**
1710      * Notifies this Connection of a request to disconnect.
1711      */
onDisconnect()1712     public void onDisconnect() {}
1713 
1714     /**
1715      * Notifies this Connection of a request to disconnect a participant of the conference managed
1716      * by the connection.
1717      *
1718      * @param endpoint the {@link Uri} of the participant to disconnect.
1719      * @hide
1720      */
onDisconnectConferenceParticipant(Uri endpoint)1721     public void onDisconnectConferenceParticipant(Uri endpoint) {}
1722 
1723     /**
1724      * Notifies this Connection of a request to separate from its parent conference.
1725      */
onSeparate()1726     public void onSeparate() {}
1727 
1728     /**
1729      * Notifies this Connection of a request to abort.
1730      */
onAbort()1731     public void onAbort() {}
1732 
1733     /**
1734      * Notifies this Connection of a request to hold.
1735      */
onHold()1736     public void onHold() {}
1737 
1738     /**
1739      * Notifies this Connection of a request to exit a hold state.
1740      */
onUnhold()1741     public void onUnhold() {}
1742 
1743     /**
1744      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
1745      * a request to accept.
1746      *
1747      * @param videoState The video state in which to answer the connection.
1748      */
onAnswer(int videoState)1749     public void onAnswer(int videoState) {}
1750 
1751     /**
1752      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
1753      * a request to accept.
1754      */
onAnswer()1755     public void onAnswer() {
1756         onAnswer(VideoProfile.STATE_AUDIO_ONLY);
1757     }
1758 
1759     /**
1760      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
1761      * a request to reject.
1762      */
onReject()1763     public void onReject() {}
1764 
1765     /**
1766      * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
1767      */
onPostDialContinue(boolean proceed)1768     public void onPostDialContinue(boolean proceed) {}
1769 
toLogSafePhoneNumber(String number)1770     static String toLogSafePhoneNumber(String number) {
1771         // For unknown number, log empty string.
1772         if (number == null) {
1773             return "";
1774         }
1775 
1776         if (PII_DEBUG) {
1777             // When PII_DEBUG is true we emit PII.
1778             return number;
1779         }
1780 
1781         // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
1782         // sanitized phone numbers.
1783         StringBuilder builder = new StringBuilder();
1784         for (int i = 0; i < number.length(); i++) {
1785             char c = number.charAt(i);
1786             if (c == '-' || c == '@' || c == '.') {
1787                 builder.append(c);
1788             } else {
1789                 builder.append('x');
1790             }
1791         }
1792         return builder.toString();
1793     }
1794 
setState(int state)1795     private void setState(int state) {
1796         checkImmutable();
1797         if (mState == STATE_DISCONNECTED && mState != state) {
1798             Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state.");
1799             return;
1800         }
1801         if (mState != state) {
1802             Log.d(this, "setState: %s", stateToString(state));
1803             mState = state;
1804             onStateChanged(state);
1805             for (Listener l : mListeners) {
1806                 l.onStateChanged(this, state);
1807             }
1808         }
1809     }
1810 
1811     private static class FailureSignalingConnection extends Connection {
1812         private boolean mImmutable = false;
FailureSignalingConnection(DisconnectCause disconnectCause)1813         public FailureSignalingConnection(DisconnectCause disconnectCause) {
1814             setDisconnected(disconnectCause);
1815             mImmutable = true;
1816         }
1817 
checkImmutable()1818         public void checkImmutable() {
1819             if (mImmutable) {
1820                 throw new UnsupportedOperationException("Connection is immutable");
1821             }
1822         }
1823     }
1824 
1825     /**
1826      * Return a {@code Connection} which represents a failed connection attempt. The returned
1827      * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified,
1828      * and a {@link #getState()} of {@link #STATE_DISCONNECTED}.
1829      * <p>
1830      * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate,
1831      * so users of this method need not maintain a reference to its return value to destroy it.
1832      *
1833      * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
1834      * @return A {@code Connection} which indicates failure.
1835      */
createFailedConnection(DisconnectCause disconnectCause)1836     public static Connection createFailedConnection(DisconnectCause disconnectCause) {
1837         return new FailureSignalingConnection(disconnectCause);
1838     }
1839 
1840     /**
1841      * Override to throw an {@link UnsupportedOperationException} if this {@code Connection} is
1842      * not intended to be mutated, e.g., if it is a marker for failure. Only for framework use;
1843      * this should never be un-@hide-den.
1844      *
1845      * @hide
1846      */
checkImmutable()1847     public void checkImmutable() {}
1848 
1849     /**
1850      * Return a {@code Connection} which represents a canceled connection attempt. The returned
1851      * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of
1852      * that state. This connection should not be used for anything, and no other
1853      * {@code Connection}s should be attempted.
1854      * <p>
1855      * so users of this method need not maintain a reference to its return value to destroy it.
1856      *
1857      * @return A {@code Connection} which indicates that the underlying connection should
1858      * be canceled.
1859      */
createCanceledConnection()1860     public static Connection createCanceledConnection() {
1861         return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED));
1862     }
1863 
fireOnConferenceableConnectionsChanged()1864     private final void fireOnConferenceableConnectionsChanged() {
1865         for (Listener l : mListeners) {
1866             l.onConferenceablesChanged(this, getConferenceables());
1867         }
1868     }
1869 
fireConferenceChanged()1870     private final void fireConferenceChanged() {
1871         for (Listener l : mListeners) {
1872             l.onConferenceChanged(this, mConference);
1873         }
1874     }
1875 
clearConferenceableList()1876     private final void clearConferenceableList() {
1877         for (Conferenceable c : mConferenceables) {
1878             if (c instanceof Connection) {
1879                 Connection connection = (Connection) c;
1880                 connection.removeConnectionListener(mConnectionDeathListener);
1881             } else if (c instanceof Conference) {
1882                 Conference conference = (Conference) c;
1883                 conference.removeListener(mConferenceDeathListener);
1884             }
1885         }
1886         mConferenceables.clear();
1887     }
1888 
1889     /**
1890      * Notifies listeners that the merge request failed.
1891      *
1892      * @hide
1893      */
notifyConferenceMergeFailed()1894     protected final void notifyConferenceMergeFailed() {
1895         for (Listener l : mListeners) {
1896             l.onConferenceMergeFailed(this);
1897         }
1898     }
1899 
1900     /**
1901      * Notifies listeners of a change to conference participant(s).
1902      *
1903      * @param conferenceParticipants The participants.
1904      * @hide
1905      */
updateConferenceParticipants( List<ConferenceParticipant> conferenceParticipants)1906     protected final void updateConferenceParticipants(
1907             List<ConferenceParticipant> conferenceParticipants) {
1908         for (Listener l : mListeners) {
1909             l.onConferenceParticipantsChanged(this, conferenceParticipants);
1910         }
1911     }
1912 
1913     /**
1914      * Notifies listeners that a conference call has been started.
1915      * @hide
1916      */
notifyConferenceStarted()1917     protected void notifyConferenceStarted() {
1918         for (Listener l : mListeners) {
1919             l.onConferenceStarted();
1920         }
1921     }
1922 }
1923