• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.SystemApi;
26 import android.hardware.camera2.CameraManager;
27 import android.net.Uri;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.os.IBinder;
31 import android.os.Looper;
32 import android.os.Message;
33 import android.os.RemoteException;
34 import android.util.ArraySet;
35 import android.view.Surface;
36 
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Collections;
40 import java.util.List;
41 import java.util.Set;
42 import java.util.concurrent.ConcurrentHashMap;
43 
44 /**
45  * Represents a phone call or connection to a remote endpoint that carries voice and/or video
46  * traffic.
47  * <p>
48  * Implementations create a custom subclass of {@code Connection} and return it to the framework
49  * as the return value of
50  * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}
51  * or
52  * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
53  * Implementations are then responsible for updating the state of the {@code Connection}, and
54  * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no
55  * longer used and associated resources may be recovered.
56  * <p>
57  * Subclasses of {@code Connection} override the {@code on*} methods to provide the the
58  * {@link ConnectionService}'s implementation of calling functionality.  The {@code on*} methods are
59  * called by Telecom to inform an instance of a {@code Connection} of actions specific to that
60  * {@code Connection} instance.
61  * <p>
62  * Basic call support requires overriding the following methods: {@link #onAnswer()},
63  * {@link #onDisconnect()}, {@link #onReject()}, {@link #onAbort()}
64  * <p>
65  * Where a {@code Connection} has {@link #CAPABILITY_SUPPORT_HOLD}, the {@link #onHold()} and
66  * {@link #onUnhold()} methods should be overridden to provide hold support for the
67  * {@code Connection}.
68  * <p>
69  * Where a {@code Connection} supports a variation of video calling (e.g. the
70  * {@code CAPABILITY_SUPPORTS_VT_*} capability bits), {@link #onAnswer(int)} should be overridden
71  * to support answering a call as a video call.
72  * <p>
73  * Where a {@code Connection} has {@link #PROPERTY_IS_EXTERNAL_CALL} and
74  * {@link #CAPABILITY_CAN_PULL_CALL}, {@link #onPullExternalCall()} should be overridden to provide
75  * support for pulling the external call.
76  * <p>
77  * Where a {@code Connection} supports conference calling {@link #onSeparate()} should be
78  * overridden.
79  * <p>
80  * There are a number of other {@code on*} methods which a {@code Connection} can choose to
81  * implement, depending on whether it is concerned with the associated calls from Telecom.  If,
82  * for example, call events from a {@link InCallService} are handled,
83  * {@link #onCallEvent(String, Bundle)} should be overridden.  Another example is
84  * {@link #onExtrasChanged(Bundle)}, which should be overridden if the {@code Connection} wishes to
85  * make use of extra information provided via the {@link Call#putExtras(Bundle)} and
86  * {@link Call#removeExtras(String...)} methods.
87  */
88 public abstract class Connection extends Conferenceable {
89 
90     /**
91      * The connection is initializing. This is generally the first state for a {@code Connection}
92      * returned by a {@link ConnectionService}.
93      */
94     public static final int STATE_INITIALIZING = 0;
95 
96     /**
97      * The connection is new and not connected.
98      */
99     public static final int STATE_NEW = 1;
100 
101     /**
102      * An incoming connection is in the ringing state. During this state, the user's ringer or
103      * vibration feature will be activated.
104      */
105     public static final int STATE_RINGING = 2;
106 
107     /**
108      * An outgoing connection is in the dialing state. In this state the other party has not yet
109      * answered the call and the user traditionally hears a ringback tone.
110      */
111     public static final int STATE_DIALING = 3;
112 
113     /**
114      * A connection is active. Both parties are connected to the call and can actively communicate.
115      */
116     public static final int STATE_ACTIVE = 4;
117 
118     /**
119      * A connection is on hold.
120      */
121     public static final int STATE_HOLDING = 5;
122 
123     /**
124      * A connection has been disconnected. This is the final state once the user has been
125      * disconnected from a call either locally, remotely or by an error in the service.
126      */
127     public static final int STATE_DISCONNECTED = 6;
128 
129     /**
130      * The state of an external connection which is in the process of being pulled from a remote
131      * device to the local device.
132      * <p>
133      * A connection can only be in this state if the {@link #PROPERTY_IS_EXTERNAL_CALL} property and
134      * {@link #CAPABILITY_CAN_PULL_CALL} capability bits are set on the connection.
135      */
136     public static final int STATE_PULLING_CALL = 7;
137 
138     /**
139      * Connection can currently be put on hold or unheld. This is distinct from
140      * {@link #CAPABILITY_SUPPORT_HOLD} in that although a connection may support 'hold' most times,
141      * it does not at the moment support the function. This can be true while the call is in the
142      * state {@link #STATE_DIALING}, for example. During this condition, an in-call UI may
143      * display a disabled 'hold' button.
144      */
145     public static final int CAPABILITY_HOLD = 0x00000001;
146 
147     /** Connection supports the hold feature. */
148     public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
149 
150     /**
151      * Connections within a conference can be merged. A {@link ConnectionService} has the option to
152      * add a {@link Conference} before the child {@link Connection}s are merged. This is how
153      * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
154      * capability allows a merge button to be shown while the conference is in the foreground
155      * of the in-call UI.
156      * <p>
157      * This is only intended for use by a {@link Conference}.
158      */
159     public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
160 
161     /**
162      * Connections within a conference can be swapped between foreground and background.
163      * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
164      * <p>
165      * This is only intended for use by a {@link Conference}.
166      */
167     public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
168 
169     /**
170      * @hide
171      */
172     public static final int CAPABILITY_UNUSED = 0x00000010;
173 
174     /** Connection supports responding via text option. */
175     public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
176 
177     /** Connection can be muted. */
178     public static final int CAPABILITY_MUTE = 0x00000040;
179 
180     /**
181      * Connection supports conference management. This capability only applies to
182      * {@link Conference}s which can have {@link Connection}s as children.
183      */
184     public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
185 
186     /**
187      * Local device supports receiving video.
188      */
189     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
190 
191     /**
192      * Local device supports transmitting video.
193      */
194     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
195 
196     /**
197      * Local device supports bidirectional video calling.
198      */
199     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
200             CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
201 
202     /**
203      * Remote device supports receiving video.
204      */
205     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
206 
207     /**
208      * Remote device supports transmitting video.
209      */
210     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
211 
212     /**
213      * Remote device supports bidirectional video calling.
214      */
215     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
216             CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
217 
218     /**
219      * Connection is able to be separated from its parent {@code Conference}, if any.
220      */
221     public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
222 
223     /**
224      * Connection is able to be individually disconnected when in a {@code Conference}.
225      */
226     public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
227 
228     /**
229      * Un-used.
230      * @hide
231      */
232     public static final int CAPABILITY_UNUSED_2 = 0x00004000;
233 
234     /**
235      * Un-used.
236      * @hide
237      */
238     public static final int CAPABILITY_UNUSED_3 = 0x00008000;
239 
240     /**
241      * Un-used.
242      * @hide
243      */
244     public static final int CAPABILITY_UNUSED_4 = 0x00010000;
245 
246     /**
247      * Un-used.
248      * @hide
249      */
250     public static final int CAPABILITY_UNUSED_5 = 0x00020000;
251 
252     /**
253      * Speed up audio setup for MT call.
254      * @hide
255      */
256     public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
257 
258     /**
259      * Call can be upgraded to a video call.
260      */
261     public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
262 
263     /**
264      * For video calls, indicates whether the outgoing video for the call can be paused using
265      * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
266      */
267     public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
268 
269     /**
270      * For a conference, indicates the conference will not have child connections.
271      * <p>
272      * An example of a conference with child connections is a GSM conference call, where the radio
273      * retains connections to the individual participants of the conference.  Another example is an
274      * IMS conference call where conference event package functionality is supported; in this case
275      * the conference server ensures the radio is aware of the participants in the conference, which
276      * are represented by child connections.
277      * <p>
278      * An example of a conference with no child connections is an IMS conference call with no
279      * conference event package support.  Such a conference is represented by the radio as a single
280      * connection to the IMS conference server.
281      * <p>
282      * Indicating whether a conference has children or not is important to help user interfaces
283      * visually represent a conference.  A conference with no children, for example, will have the
284      * conference connection shown in the list of calls on a Bluetooth device, where if the
285      * conference has children, only the children will be shown in the list of calls on a Bluetooth
286      * device.
287      * @hide
288      */
289     public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
290 
291     /**
292      * Indicates that the connection itself wants to handle any sort of reply response, rather than
293      * relying on SMS.
294      */
295     public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
296 
297     /**
298      * When set, prevents a video call from being downgraded to an audio-only call.
299      * <p>
300      * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
301      * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
302      * downgraded from a video call back to a VideoState of
303      * {@link VideoProfile#STATE_AUDIO_ONLY}.
304      * <p>
305      * Intuitively, a call which can be downgraded to audio should also have local and remote
306      * video
307      * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
308      * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
309      */
310     public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00800000;
311 
312     /**
313      * When set for an external connection, indicates that this {@code Connection} can be pulled
314      * from a remote device to the current device.
315      * <p>
316      * Should only be set on a {@code Connection} where {@link #PROPERTY_IS_EXTERNAL_CALL}
317      * is set.
318      */
319     public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000;
320 
321     //**********************************************************************************************
322     // Next CAPABILITY value: 0x02000000
323     //**********************************************************************************************
324 
325     /**
326      * Indicates that the current device callback number should be shown.
327      *
328      * @hide
329      */
330     public static final int PROPERTY_SHOW_CALLBACK_NUMBER = 1<<0;
331 
332     /**
333      * Whether the call is a generic conference, where we do not know the precise state of
334      * participants in the conference (eg. on CDMA).
335      *
336      * @hide
337      */
338     public static final int PROPERTY_GENERIC_CONFERENCE = 1<<1;
339 
340     /**
341      * Connection is using high definition audio.
342      * @hide
343      */
344     public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2;
345 
346     /**
347      * Connection is using WIFI.
348      * @hide
349      */
350     public static final int PROPERTY_WIFI = 1<<3;
351 
352     /**
353      * When set, indicates that the {@code Connection} does not actually exist locally for the
354      * {@link ConnectionService}.
355      * <p>
356      * Consider, for example, a scenario where a user has two devices with the same phone number.
357      * When a user places a call on one devices, the telephony stack can represent that call on the
358      * other device by adding is to the {@link ConnectionService} with the
359      * {@link #PROPERTY_IS_EXTERNAL_CALL} capability set.
360      * <p>
361      * An {@link ConnectionService} should not assume that all {@link InCallService}s will handle
362      * external connections.  Only those {@link InCallService}s which have the
363      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
364      * manifest will see external connections.
365      */
366     public static final int PROPERTY_IS_EXTERNAL_CALL = 1<<4;
367 
368     /**
369      * Indicates that the connection has CDMA Enhanced Voice Privacy enabled.
370      */
371     public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 1<<5;
372 
373     /**
374      * Indicates that the connection represents a downgraded IMS conference.
375      * @hide
376      */
377     public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 1<<6;
378 
379     //**********************************************************************************************
380     // Next PROPERTY value: 1<<7
381     //**********************************************************************************************
382 
383     /**
384      * Connection extra key used to store the last forwarded number associated with the current
385      * connection.  Used to communicate to the user interface that the connection was forwarded via
386      * the specified number.
387      */
388     public static final String EXTRA_LAST_FORWARDED_NUMBER =
389             "android.telecom.extra.LAST_FORWARDED_NUMBER";
390 
391     /**
392      * Connection extra key used to store a child number associated with the current connection.
393      * Used to communicate to the user interface that the connection was received via
394      * a child address (i.e. phone number) associated with the {@link PhoneAccount}'s primary
395      * address.
396      */
397     public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
398 
399     /**
400      * Connection extra key used to store the subject for an incoming call.  The user interface can
401      * query this extra and display its contents for incoming calls.  Will only be used if the
402      * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}.
403      */
404     public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
405 
406     /**
407      * Boolean connection extra key set on a {@link Connection} in
408      * {@link Connection#STATE_RINGING} state to indicate that answering the call will cause the
409      * current active foreground call to be dropped.
410      */
411     public static final String EXTRA_ANSWERING_DROPS_FG_CALL =
412             "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
413 
414     /**
415      * Boolean connection extra key on a {@link Connection} which indicates that adding an
416      * additional call is disallowed.
417      * @hide
418      */
419     public static final String EXTRA_DISABLE_ADD_CALL =
420             "android.telecom.extra.DISABLE_ADD_CALL";
421 
422     /**
423      * Connection event used to inform Telecom that it should play the on hold tone.  This is used
424      * to play a tone when the peer puts the current call on hold.  Sent to Telecom via
425      * {@link #sendConnectionEvent(String, Bundle)}.
426      * @hide
427      */
428     public static final String EVENT_ON_HOLD_TONE_START =
429             "android.telecom.event.ON_HOLD_TONE_START";
430 
431     /**
432      * Connection event used to inform Telecom that it should stop the on hold tone.  This is used
433      * to stop a tone when the peer puts the current call on hold.  Sent to Telecom via
434      * {@link #sendConnectionEvent(String, Bundle)}.
435      * @hide
436      */
437     public static final String EVENT_ON_HOLD_TONE_END =
438             "android.telecom.event.ON_HOLD_TONE_END";
439 
440     /**
441      * Connection event used to inform {@link InCallService}s when pulling of an external call has
442      * failed.  The user interface should inform the user of the error.
443      * <p>
444      * Expected to be used by the {@link ConnectionService} when the {@link Call#pullExternalCall()}
445      * API is called on a {@link Call} with the properties
446      * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} and
447      * {@link Call.Details#CAPABILITY_CAN_PULL_CALL}, but the {@link ConnectionService} could not
448      * pull the external call due to an error condition.
449      * <p>
450      * Sent via {@link #sendConnectionEvent(String, Bundle)}.  The {@link Bundle} parameter is
451      * expected to be null when this connection event is used.
452      */
453     public static final String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
454 
455     /**
456      * Connection event used to inform {@link InCallService}s when the merging of two calls has
457      * failed. The User Interface should use this message to inform the user of the error.
458      * <p>
459      * Sent via {@link #sendConnectionEvent(String, Bundle)}.  The {@link Bundle} parameter is
460      * expected to be null when this connection event is used.
461      */
462     public static final String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
463 
464     /**
465      * Connection event used to inform {@link InCallService}s when a call has been put on hold by
466      * the remote party.
467      * <p>
468      * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the
469      * call is being held locally on the device.  When a capable {@link ConnectionService} receives
470      * signalling to indicate that the remote party has put the call on hold, it can send this
471      * connection event.
472      * @hide
473      */
474     public static final String EVENT_CALL_REMOTELY_HELD =
475             "android.telecom.event.CALL_REMOTELY_HELD";
476 
477     /**
478      * Connection event used to inform {@link InCallService}s when a call which was remotely held
479      * (see {@link #EVENT_CALL_REMOTELY_HELD}) has been un-held by the remote party.
480      * <p>
481      * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the
482      * call is being held locally on the device.  When a capable {@link ConnectionService} receives
483      * signalling to indicate that the remote party has taken the call off hold, it can send this
484      * connection event.
485      * @hide
486      */
487     public static final String EVENT_CALL_REMOTELY_UNHELD =
488             "android.telecom.event.CALL_REMOTELY_UNHELD";
489 
490     // Flag controlling whether PII is emitted into the logs
491     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
492 
493     /**
494      * Whether the given capabilities support the specified capability.
495      *
496      * @param capabilities A capability bit field.
497      * @param capability The capability to check capabilities for.
498      * @return Whether the specified capability is supported.
499      * @hide
500      */
can(int capabilities, int capability)501     public static boolean can(int capabilities, int capability) {
502         return (capabilities & capability) == capability;
503     }
504 
505     /**
506      * Whether the capabilities of this {@code Connection} supports the specified capability.
507      *
508      * @param capability The capability to check capabilities for.
509      * @return Whether the specified capability is supported.
510      * @hide
511      */
can(int capability)512     public boolean can(int capability) {
513         return can(mConnectionCapabilities, capability);
514     }
515 
516     /**
517      * Removes the specified capability from the set of capabilities of this {@code Connection}.
518      *
519      * @param capability The capability to remove from the set.
520      * @hide
521      */
removeCapability(int capability)522     public void removeCapability(int capability) {
523         mConnectionCapabilities &= ~capability;
524     }
525 
526     /**
527      * Adds the specified capability to the set of capabilities of this {@code Connection}.
528      *
529      * @param capability The capability to add to the set.
530      * @hide
531      */
addCapability(int capability)532     public void addCapability(int capability) {
533         mConnectionCapabilities |= capability;
534     }
535 
536     /**
537      * Renders a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
538      *
539      * @param capabilities A capability bit field.
540      * @return A human readable string representation.
541      */
capabilitiesToString(int capabilities)542     public static String capabilitiesToString(int capabilities) {
543         return capabilitiesToStringInternal(capabilities, true /* isLong */);
544     }
545 
546     /**
547      * Renders a set of capability bits ({@code CAPABILITY_*}) as a *short* human readable
548      * string.
549      *
550      * @param capabilities A capability bit field.
551      * @return A human readable string representation.
552      * @hide
553      */
capabilitiesToStringShort(int capabilities)554     public static String capabilitiesToStringShort(int capabilities) {
555         return capabilitiesToStringInternal(capabilities, false /* isLong */);
556     }
557 
capabilitiesToStringInternal(int capabilities, boolean isLong)558     private static String capabilitiesToStringInternal(int capabilities, boolean isLong) {
559         StringBuilder builder = new StringBuilder();
560         builder.append("[");
561         if (isLong) {
562             builder.append("Capabilities:");
563         }
564 
565         if (can(capabilities, CAPABILITY_HOLD)) {
566             builder.append(isLong ? " CAPABILITY_HOLD" : " hld");
567         }
568         if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
569             builder.append(isLong ? " CAPABILITY_SUPPORT_HOLD" : " sup_hld");
570         }
571         if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
572             builder.append(isLong ? " CAPABILITY_MERGE_CONFERENCE" : " mrg_cnf");
573         }
574         if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
575             builder.append(isLong ? " CAPABILITY_SWAP_CONFERENCE" : " swp_cnf");
576         }
577         if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
578             builder.append(isLong ? " CAPABILITY_RESPOND_VIA_TEXT" : " txt");
579         }
580         if (can(capabilities, CAPABILITY_MUTE)) {
581             builder.append(isLong ? " CAPABILITY_MUTE" : " mut");
582         }
583         if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
584             builder.append(isLong ? " CAPABILITY_MANAGE_CONFERENCE" : " mng_cnf");
585         }
586         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
587             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_RX" : " VTlrx");
588         }
589         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
590             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_TX" : " VTltx");
591         }
592         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
593             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL" : " VTlbi");
594         }
595         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
596             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_RX" : " VTrrx");
597         }
598         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
599             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_TX" : " VTrtx");
600         }
601         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
602             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL" : " VTrbi");
603         }
604         if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
605             builder.append(isLong ? " CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO" : " !v2a");
606         }
607         if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
608             builder.append(isLong ? " CAPABILITY_SPEED_UP_MT_AUDIO" : " spd_aud");
609         }
610         if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
611             builder.append(isLong ? " CAPABILITY_CAN_UPGRADE_TO_VIDEO" : " a2v");
612         }
613         if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
614             builder.append(isLong ? " CAPABILITY_CAN_PAUSE_VIDEO" : " paus_VT");
615         }
616         if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
617             builder.append(isLong ? " CAPABILITY_SINGLE_PARTY_CONFERENCE" : " 1p_cnf");
618         }
619         if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
620             builder.append(isLong ? " CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION" : " rsp_by_con");
621         }
622         if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
623             builder.append(isLong ? " CAPABILITY_CAN_PULL_CALL" : " pull");
624         }
625 
626         builder.append("]");
627         return builder.toString();
628     }
629 
630     /**
631      * Renders a set of property bits ({@code PROPERTY_*}) as a human readable string.
632      *
633      * @param properties A property bit field.
634      * @return A human readable string representation.
635      */
propertiesToString(int properties)636     public static String propertiesToString(int properties) {
637         return propertiesToStringInternal(properties, true /* isLong */);
638     }
639 
640     /**
641      * Renders a set of property bits ({@code PROPERTY_*}) as a *short* human readable string.
642      *
643      * @param properties A property bit field.
644      * @return A human readable string representation.
645      * @hide
646      */
propertiesToStringShort(int properties)647     public static String propertiesToStringShort(int properties) {
648         return propertiesToStringInternal(properties, false /* isLong */);
649     }
650 
propertiesToStringInternal(int properties, boolean isLong)651     private static String propertiesToStringInternal(int properties, boolean isLong) {
652         StringBuilder builder = new StringBuilder();
653         builder.append("[");
654         if (isLong) {
655             builder.append("Properties:");
656         }
657 
658         if (can(properties, PROPERTY_SHOW_CALLBACK_NUMBER)) {
659             builder.append(isLong ? " PROPERTY_SHOW_CALLBACK_NUMBER" : " clbk");
660         }
661 
662         if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) {
663             builder.append(isLong ? " PROPERTY_HIGH_DEF_AUDIO" : " HD");
664         }
665 
666         if (can(properties, PROPERTY_WIFI)) {
667             builder.append(isLong ? " PROPERTY_WIFI" : " wifi");
668         }
669 
670         if (can(properties, PROPERTY_GENERIC_CONFERENCE)) {
671             builder.append(isLong ? " PROPERTY_GENERIC_CONFERENCE" : " gen_conf");
672         }
673 
674         if (can(properties, PROPERTY_IS_EXTERNAL_CALL)) {
675             builder.append(isLong ? " PROPERTY_IS_EXTERNAL_CALL" : " xtrnl");
676         }
677 
678         if (can(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
679             builder.append(isLong ? " PROPERTY_HAS_CDMA_VOICE_PRIVACY" : " priv");
680         }
681 
682         builder.append("]");
683         return builder.toString();
684     }
685 
686     /** @hide */
687     public abstract static class Listener {
onStateChanged(Connection c, int state)688         public void onStateChanged(Connection c, int state) {}
onAddressChanged(Connection c, Uri newAddress, int presentation)689         public void onAddressChanged(Connection c, Uri newAddress, int presentation) {}
onCallerDisplayNameChanged( Connection c, String callerDisplayName, int presentation)690         public void onCallerDisplayNameChanged(
691                 Connection c, String callerDisplayName, int presentation) {}
onVideoStateChanged(Connection c, int videoState)692         public void onVideoStateChanged(Connection c, int videoState) {}
onDisconnected(Connection c, DisconnectCause disconnectCause)693         public void onDisconnected(Connection c, DisconnectCause disconnectCause) {}
onPostDialWait(Connection c, String remaining)694         public void onPostDialWait(Connection c, String remaining) {}
onPostDialChar(Connection c, char nextChar)695         public void onPostDialChar(Connection c, char nextChar) {}
onRingbackRequested(Connection c, boolean ringback)696         public void onRingbackRequested(Connection c, boolean ringback) {}
onDestroyed(Connection c)697         public void onDestroyed(Connection c) {}
onConnectionCapabilitiesChanged(Connection c, int capabilities)698         public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {}
onConnectionPropertiesChanged(Connection c, int properties)699         public void onConnectionPropertiesChanged(Connection c, int properties) {}
onVideoProviderChanged( Connection c, VideoProvider videoProvider)700         public void onVideoProviderChanged(
701                 Connection c, VideoProvider videoProvider) {}
onAudioModeIsVoipChanged(Connection c, boolean isVoip)702         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
onStatusHintsChanged(Connection c, StatusHints statusHints)703         public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
onConferenceablesChanged( Connection c, List<Conferenceable> conferenceables)704         public void onConferenceablesChanged(
705                 Connection c, List<Conferenceable> conferenceables) {}
onConferenceChanged(Connection c, Conference conference)706         public void onConferenceChanged(Connection c, Conference conference) {}
707         /** @hide */
onConferenceParticipantsChanged(Connection c, List<ConferenceParticipant> participants)708         public void onConferenceParticipantsChanged(Connection c,
709                 List<ConferenceParticipant> participants) {}
onConferenceStarted()710         public void onConferenceStarted() {}
onConferenceMergeFailed(Connection c)711         public void onConferenceMergeFailed(Connection c) {}
onExtrasChanged(Connection c, Bundle extras)712         public void onExtrasChanged(Connection c, Bundle extras) {}
onExtrasRemoved(Connection c, List<String> keys)713         public void onExtrasRemoved(Connection c, List<String> keys) {}
onConnectionEvent(Connection c, String event, Bundle extras)714         public void onConnectionEvent(Connection c, String event, Bundle extras) {}
715         /** @hide */
onConferenceSupportedChanged(Connection c, boolean isConferenceSupported)716         public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {}
717     }
718 
719     /**
720      * Provides a means of controlling the video session associated with a {@link Connection}.
721      * <p>
722      * Implementations create a custom subclass of {@link VideoProvider} and the
723      * {@link ConnectionService} creates an instance sets it on the {@link Connection} using
724      * {@link Connection#setVideoProvider(VideoProvider)}.  Any connection which supports video
725      * should set the {@link VideoProvider}.
726      * <p>
727      * The {@link VideoProvider} serves two primary purposes: it provides a means for Telecom and
728      * {@link InCallService} implementations to issue requests related to the video session;
729      * it provides a means for the {@link ConnectionService} to report events and information
730      * related to the video session to Telecom and the {@link InCallService} implementations.
731      * <p>
732      * {@link InCallService} implementations interact with the {@link VideoProvider} via
733      * {@link android.telecom.InCallService.VideoCall}.
734      */
735     public static abstract class VideoProvider {
736 
737         /**
738          * Video is not being received (no protocol pause was issued).
739          * @see #handleCallSessionEvent(int)
740          */
741         public static final int SESSION_EVENT_RX_PAUSE = 1;
742 
743         /**
744          * Video reception has resumed after a {@link #SESSION_EVENT_RX_PAUSE}.
745          * @see #handleCallSessionEvent(int)
746          */
747         public static final int SESSION_EVENT_RX_RESUME = 2;
748 
749         /**
750          * Video transmission has begun. This occurs after a negotiated start of video transmission
751          * when the underlying protocol has actually begun transmitting video to the remote party.
752          * @see #handleCallSessionEvent(int)
753          */
754         public static final int SESSION_EVENT_TX_START = 3;
755 
756         /**
757          * Video transmission has stopped. This occurs after a negotiated stop of video transmission
758          * when the underlying protocol has actually stopped transmitting video to the remote party.
759          * @see #handleCallSessionEvent(int)
760          */
761         public static final int SESSION_EVENT_TX_STOP = 4;
762 
763         /**
764          * A camera failure has occurred for the selected camera.  The {@link InCallService} can use
765          * this as a cue to inform the user the camera is not available.
766          * @see #handleCallSessionEvent(int)
767          */
768         public static final int SESSION_EVENT_CAMERA_FAILURE = 5;
769 
770         /**
771          * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready
772          * for operation.  The {@link InCallService} can use this as a cue to inform the user that
773          * the camera has become available again.
774          * @see #handleCallSessionEvent(int)
775          */
776         public static final int SESSION_EVENT_CAMERA_READY = 6;
777 
778         /**
779          * Session modify request was successful.
780          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
781          */
782         public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1;
783 
784         /**
785          * Session modify request failed.
786          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
787          */
788         public static final int SESSION_MODIFY_REQUEST_FAIL = 2;
789 
790         /**
791          * Session modify request ignored due to invalid parameters.
792          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
793          */
794         public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
795 
796         /**
797          * Session modify request timed out.
798          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
799          */
800         public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4;
801 
802         /**
803          * Session modify request rejected by remote user.
804          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
805          */
806         public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5;
807 
808         private static final int MSG_ADD_VIDEO_CALLBACK = 1;
809         private static final int MSG_SET_CAMERA = 2;
810         private static final int MSG_SET_PREVIEW_SURFACE = 3;
811         private static final int MSG_SET_DISPLAY_SURFACE = 4;
812         private static final int MSG_SET_DEVICE_ORIENTATION = 5;
813         private static final int MSG_SET_ZOOM = 6;
814         private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
815         private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
816         private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
817         private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10;
818         private static final int MSG_SET_PAUSE_IMAGE = 11;
819         private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
820 
821         private VideoProvider.VideoProviderHandler mMessageHandler;
822         private final VideoProvider.VideoProviderBinder mBinder;
823 
824         /**
825          * Stores a list of the video callbacks, keyed by IBinder.
826          *
827          * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
828          * load factor before resizing, 1 means we only expect a single thread to
829          * access the map so make only a single shard
830          */
831         private ConcurrentHashMap<IBinder, IVideoCallback> mVideoCallbacks =
832                 new ConcurrentHashMap<IBinder, IVideoCallback>(8, 0.9f, 1);
833 
834         /**
835          * Default handler used to consolidate binder method calls onto a single thread.
836          */
837         private final class VideoProviderHandler extends Handler {
VideoProviderHandler()838             public VideoProviderHandler() {
839                 super();
840             }
841 
VideoProviderHandler(Looper looper)842             public VideoProviderHandler(Looper looper) {
843                 super(looper);
844             }
845 
846             @Override
handleMessage(Message msg)847             public void handleMessage(Message msg) {
848                 switch (msg.what) {
849                     case MSG_ADD_VIDEO_CALLBACK: {
850                         IBinder binder = (IBinder) msg.obj;
851                         IVideoCallback callback = IVideoCallback.Stub
852                                 .asInterface((IBinder) msg.obj);
853                         if (callback == null) {
854                             Log.w(this, "addVideoProvider - skipped; callback is null.");
855                             break;
856                         }
857 
858                         if (mVideoCallbacks.containsKey(binder)) {
859                             Log.i(this, "addVideoProvider - skipped; already present.");
860                             break;
861                         }
862                         mVideoCallbacks.put(binder, callback);
863                         break;
864                     }
865                     case MSG_REMOVE_VIDEO_CALLBACK: {
866                         IBinder binder = (IBinder) msg.obj;
867                         IVideoCallback callback = IVideoCallback.Stub
868                                 .asInterface((IBinder) msg.obj);
869                         if (!mVideoCallbacks.containsKey(binder)) {
870                             Log.i(this, "removeVideoProvider - skipped; not present.");
871                             break;
872                         }
873                         mVideoCallbacks.remove(binder);
874                         break;
875                     }
876                     case MSG_SET_CAMERA:
877                         onSetCamera((String) msg.obj);
878                         break;
879                     case MSG_SET_PREVIEW_SURFACE:
880                         onSetPreviewSurface((Surface) msg.obj);
881                         break;
882                     case MSG_SET_DISPLAY_SURFACE:
883                         onSetDisplaySurface((Surface) msg.obj);
884                         break;
885                     case MSG_SET_DEVICE_ORIENTATION:
886                         onSetDeviceOrientation(msg.arg1);
887                         break;
888                     case MSG_SET_ZOOM:
889                         onSetZoom((Float) msg.obj);
890                         break;
891                     case MSG_SEND_SESSION_MODIFY_REQUEST: {
892                         SomeArgs args = (SomeArgs) msg.obj;
893                         try {
894                             onSendSessionModifyRequest((VideoProfile) args.arg1,
895                                     (VideoProfile) args.arg2);
896                         } finally {
897                             args.recycle();
898                         }
899                         break;
900                     }
901                     case MSG_SEND_SESSION_MODIFY_RESPONSE:
902                         onSendSessionModifyResponse((VideoProfile) msg.obj);
903                         break;
904                     case MSG_REQUEST_CAMERA_CAPABILITIES:
905                         onRequestCameraCapabilities();
906                         break;
907                     case MSG_REQUEST_CONNECTION_DATA_USAGE:
908                         onRequestConnectionDataUsage();
909                         break;
910                     case MSG_SET_PAUSE_IMAGE:
911                         onSetPauseImage((Uri) msg.obj);
912                         break;
913                     default:
914                         break;
915                 }
916             }
917         }
918 
919         /**
920          * IVideoProvider stub implementation.
921          */
922         private final class VideoProviderBinder extends IVideoProvider.Stub {
addVideoCallback(IBinder videoCallbackBinder)923             public void addVideoCallback(IBinder videoCallbackBinder) {
924                 mMessageHandler.obtainMessage(
925                         MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
926             }
927 
removeVideoCallback(IBinder videoCallbackBinder)928             public void removeVideoCallback(IBinder videoCallbackBinder) {
929                 mMessageHandler.obtainMessage(
930                         MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
931             }
932 
setCamera(String cameraId)933             public void setCamera(String cameraId) {
934                 mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
935             }
936 
setPreviewSurface(Surface surface)937             public void setPreviewSurface(Surface surface) {
938                 mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
939             }
940 
setDisplaySurface(Surface surface)941             public void setDisplaySurface(Surface surface) {
942                 mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
943             }
944 
setDeviceOrientation(int rotation)945             public void setDeviceOrientation(int rotation) {
946                 mMessageHandler.obtainMessage(
947                         MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget();
948             }
949 
setZoom(float value)950             public void setZoom(float value) {
951                 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
952             }
953 
sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)954             public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
955                 SomeArgs args = SomeArgs.obtain();
956                 args.arg1 = fromProfile;
957                 args.arg2 = toProfile;
958                 mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
959             }
960 
sendSessionModifyResponse(VideoProfile responseProfile)961             public void sendSessionModifyResponse(VideoProfile responseProfile) {
962                 mMessageHandler.obtainMessage(
963                         MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
964             }
965 
requestCameraCapabilities()966             public void requestCameraCapabilities() {
967                 mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
968             }
969 
requestCallDataUsage()970             public void requestCallDataUsage() {
971                 mMessageHandler.obtainMessage(MSG_REQUEST_CONNECTION_DATA_USAGE).sendToTarget();
972             }
973 
setPauseImage(Uri uri)974             public void setPauseImage(Uri uri) {
975                 mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
976             }
977         }
978 
VideoProvider()979         public VideoProvider() {
980             mBinder = new VideoProvider.VideoProviderBinder();
981             mMessageHandler = new VideoProvider.VideoProviderHandler(Looper.getMainLooper());
982         }
983 
984         /**
985          * Creates an instance of the {@link VideoProvider}, specifying the looper to use.
986          *
987          * @param looper The looper.
988          * @hide
989          */
VideoProvider(Looper looper)990         public VideoProvider(Looper looper) {
991             mBinder = new VideoProvider.VideoProviderBinder();
992             mMessageHandler = new VideoProvider.VideoProviderHandler(looper);
993         }
994 
995         /**
996          * Returns binder object which can be used across IPC methods.
997          * @hide
998          */
getInterface()999         public final IVideoProvider getInterface() {
1000             return mBinder;
1001         }
1002 
1003         /**
1004          * Sets the camera to be used for the outgoing video.
1005          * <p>
1006          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
1007          * camera via
1008          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
1009          * <p>
1010          * Sent from the {@link InCallService} via
1011          * {@link InCallService.VideoCall#setCamera(String)}.
1012          *
1013          * @param cameraId The id of the camera (use ids as reported by
1014          * {@link CameraManager#getCameraIdList()}).
1015          */
onSetCamera(String cameraId)1016         public abstract void onSetCamera(String cameraId);
1017 
1018         /**
1019          * Sets the surface to be used for displaying a preview of what the user's camera is
1020          * currently capturing.  When video transmission is enabled, this is the video signal which
1021          * is sent to the remote device.
1022          * <p>
1023          * Sent from the {@link InCallService} via
1024          * {@link InCallService.VideoCall#setPreviewSurface(Surface)}.
1025          *
1026          * @param surface The {@link Surface}.
1027          */
onSetPreviewSurface(Surface surface)1028         public abstract void onSetPreviewSurface(Surface surface);
1029 
1030         /**
1031          * Sets the surface to be used for displaying the video received from the remote device.
1032          * <p>
1033          * Sent from the {@link InCallService} via
1034          * {@link InCallService.VideoCall#setDisplaySurface(Surface)}.
1035          *
1036          * @param surface The {@link Surface}.
1037          */
onSetDisplaySurface(Surface surface)1038         public abstract void onSetDisplaySurface(Surface surface);
1039 
1040         /**
1041          * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of
1042          * the device is 0 degrees.
1043          * <p>
1044          * Sent from the {@link InCallService} via
1045          * {@link InCallService.VideoCall#setDeviceOrientation(int)}.
1046          *
1047          * @param rotation The device orientation, in degrees.
1048          */
onSetDeviceOrientation(int rotation)1049         public abstract void onSetDeviceOrientation(int rotation);
1050 
1051         /**
1052          * Sets camera zoom ratio.
1053          * <p>
1054          * Sent from the {@link InCallService} via {@link InCallService.VideoCall#setZoom(float)}.
1055          *
1056          * @param value The camera zoom ratio.
1057          */
onSetZoom(float value)1058         public abstract void onSetZoom(float value);
1059 
1060         /**
1061          * Issues a request to modify the properties of the current video session.
1062          * <p>
1063          * Example scenarios include: requesting an audio-only call to be upgraded to a
1064          * bi-directional video call, turning on or off the user's camera, sending a pause signal
1065          * when the {@link InCallService} is no longer the foreground application.
1066          * <p>
1067          * If the {@link VideoProvider} determines a request to be invalid, it should call
1068          * {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} to report the
1069          * invalid request back to the {@link InCallService}.
1070          * <p>
1071          * Where a request requires confirmation from the user of the peer device, the
1072          * {@link VideoProvider} must communicate the request to the peer device and handle the
1073          * user's response.  {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)}
1074          * is used to inform the {@link InCallService} of the result of the request.
1075          * <p>
1076          * Sent from the {@link InCallService} via
1077          * {@link InCallService.VideoCall#sendSessionModifyRequest(VideoProfile)}.
1078          *
1079          * @param fromProfile The video profile prior to the request.
1080          * @param toProfile The video profile with the requested changes made.
1081          */
onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)1082         public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
1083                 VideoProfile toProfile);
1084 
1085         /**
1086          * Provides a response to a request to change the current video session properties.
1087          * <p>
1088          * For example, if the peer requests and upgrade from an audio-only call to a bi-directional
1089          * video call, could decline the request and keep the call as audio-only.
1090          * In such a scenario, the {@code responseProfile} would have a video state of
1091          * {@link VideoProfile#STATE_AUDIO_ONLY}.  If the user had decided to accept the request,
1092          * the video state would be {@link VideoProfile#STATE_BIDIRECTIONAL}.
1093          * <p>
1094          * Sent from the {@link InCallService} via
1095          * {@link InCallService.VideoCall#sendSessionModifyResponse(VideoProfile)} in response to
1096          * a {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)}
1097          * callback.
1098          *
1099          * @param responseProfile The response video profile.
1100          */
onSendSessionModifyResponse(VideoProfile responseProfile)1101         public abstract void onSendSessionModifyResponse(VideoProfile responseProfile);
1102 
1103         /**
1104          * Issues a request to the {@link VideoProvider} to retrieve the camera capabilities.
1105          * <p>
1106          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
1107          * camera via
1108          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
1109          * <p>
1110          * Sent from the {@link InCallService} via
1111          * {@link InCallService.VideoCall#requestCameraCapabilities()}.
1112          */
onRequestCameraCapabilities()1113         public abstract void onRequestCameraCapabilities();
1114 
1115         /**
1116          * Issues a request to the {@link VideoProvider} to retrieve the current data usage for the
1117          * video component of the current {@link Connection}.
1118          * <p>
1119          * The {@link VideoProvider} should respond by communicating current data usage, in bytes,
1120          * via {@link VideoProvider#setCallDataUsage(long)}.
1121          * <p>
1122          * Sent from the {@link InCallService} via
1123          * {@link InCallService.VideoCall#requestCallDataUsage()}.
1124          */
onRequestConnectionDataUsage()1125         public abstract void onRequestConnectionDataUsage();
1126 
1127         /**
1128          * Provides the {@link VideoProvider} with the {@link Uri} of an image to be displayed to
1129          * the peer device when the video signal is paused.
1130          * <p>
1131          * Sent from the {@link InCallService} via
1132          * {@link InCallService.VideoCall#setPauseImage(Uri)}.
1133          *
1134          * @param uri URI of image to display.
1135          */
onSetPauseImage(Uri uri)1136         public abstract void onSetPauseImage(Uri uri);
1137 
1138         /**
1139          * Used to inform listening {@link InCallService} implementations when the
1140          * {@link VideoProvider} receives a session modification request.
1141          * <p>
1142          * Received by the {@link InCallService} via
1143          * {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)},
1144          *
1145          * @param videoProfile The requested video profile.
1146          * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)
1147          */
receiveSessionModifyRequest(VideoProfile videoProfile)1148         public void receiveSessionModifyRequest(VideoProfile videoProfile) {
1149             if (mVideoCallbacks != null) {
1150                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1151                     try {
1152                         callback.receiveSessionModifyRequest(videoProfile);
1153                     } catch (RemoteException ignored) {
1154                         Log.w(this, "receiveSessionModifyRequest callback failed", ignored);
1155                     }
1156                 }
1157             }
1158         }
1159 
1160         /**
1161          * Used to inform listening {@link InCallService} implementations when the
1162          * {@link VideoProvider} receives a response to a session modification request.
1163          * <p>
1164          * Received by the {@link InCallService} via
1165          * {@link InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int,
1166          * VideoProfile, VideoProfile)}.
1167          *
1168          * @param status Status of the session modify request.  Valid values are
1169          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS},
1170          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_FAIL},
1171          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_INVALID},
1172          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_TIMED_OUT},
1173          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE}
1174          * @param requestedProfile The original request which was sent to the peer device.
1175          * @param responseProfile The actual profile changes agreed to by the peer device.
1176          * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)
1177          */
receiveSessionModifyResponse(int status, VideoProfile requestedProfile, VideoProfile responseProfile)1178         public void receiveSessionModifyResponse(int status,
1179                 VideoProfile requestedProfile, VideoProfile responseProfile) {
1180             if (mVideoCallbacks != null) {
1181                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1182                     try {
1183                         callback.receiveSessionModifyResponse(status, requestedProfile,
1184                                 responseProfile);
1185                     } catch (RemoteException ignored) {
1186                         Log.w(this, "receiveSessionModifyResponse callback failed", ignored);
1187                     }
1188                 }
1189             }
1190         }
1191 
1192         /**
1193          * Used to inform listening {@link InCallService} implementations when the
1194          * {@link VideoProvider} reports a call session event.
1195          * <p>
1196          * Received by the {@link InCallService} via
1197          * {@link InCallService.VideoCall.Callback#onCallSessionEvent(int)}.
1198          *
1199          * @param event The event.  Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE},
1200          *      {@link VideoProvider#SESSION_EVENT_RX_RESUME},
1201          *      {@link VideoProvider#SESSION_EVENT_TX_START},
1202          *      {@link VideoProvider#SESSION_EVENT_TX_STOP},
1203          *      {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
1204          *      {@link VideoProvider#SESSION_EVENT_CAMERA_READY}.
1205          */
handleCallSessionEvent(int event)1206         public void handleCallSessionEvent(int event) {
1207             if (mVideoCallbacks != null) {
1208                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1209                     try {
1210                         callback.handleCallSessionEvent(event);
1211                     } catch (RemoteException ignored) {
1212                         Log.w(this, "handleCallSessionEvent callback failed", ignored);
1213                     }
1214                 }
1215             }
1216         }
1217 
1218         /**
1219          * Used to inform listening {@link InCallService} implementations when the dimensions of the
1220          * peer's video have changed.
1221          * <p>
1222          * This could occur if, for example, the peer rotates their device, changing the aspect
1223          * ratio of the video, or if the user switches between the back and front cameras.
1224          * <p>
1225          * Received by the {@link InCallService} via
1226          * {@link InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int)}.
1227          *
1228          * @param width  The updated peer video width.
1229          * @param height The updated peer video height.
1230          */
changePeerDimensions(int width, int height)1231         public void changePeerDimensions(int width, int height) {
1232             if (mVideoCallbacks != null) {
1233                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1234                     try {
1235                         callback.changePeerDimensions(width, height);
1236                     } catch (RemoteException ignored) {
1237                         Log.w(this, "changePeerDimensions callback failed", ignored);
1238                     }
1239                 }
1240             }
1241         }
1242 
1243         /**
1244          * Used to inform listening {@link InCallService} implementations when the data usage of the
1245          * video associated with the current {@link Connection} has changed.
1246          * <p>
1247          * This could be in response to a preview request via
1248          * {@link #onRequestConnectionDataUsage()}, or as a periodic update by the
1249          * {@link VideoProvider}.  Where periodic updates of data usage are provided, they should be
1250          * provided at most for every 1 MB of data transferred and no more than once every 10 sec.
1251          * <p>
1252          * Received by the {@link InCallService} via
1253          * {@link InCallService.VideoCall.Callback#onCallDataUsageChanged(long)}.
1254          *
1255          * @param dataUsage The updated data usage (in bytes).  Reported as the cumulative bytes
1256          *                  used since the start of the call.
1257          */
setCallDataUsage(long dataUsage)1258         public void setCallDataUsage(long dataUsage) {
1259             if (mVideoCallbacks != null) {
1260                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1261                     try {
1262                         callback.changeCallDataUsage(dataUsage);
1263                     } catch (RemoteException ignored) {
1264                         Log.w(this, "setCallDataUsage callback failed", ignored);
1265                     }
1266                 }
1267             }
1268         }
1269 
1270         /**
1271          * @see #setCallDataUsage(long)
1272          *
1273          * @param dataUsage The updated data usage (in byes).
1274          * @deprecated - Use {@link #setCallDataUsage(long)} instead.
1275          * @hide
1276          */
changeCallDataUsage(long dataUsage)1277         public void changeCallDataUsage(long dataUsage) {
1278             setCallDataUsage(dataUsage);
1279         }
1280 
1281         /**
1282          * Used to inform listening {@link InCallService} implementations when the capabilities of
1283          * the current camera have changed.
1284          * <p>
1285          * The {@link VideoProvider} should call this in response to
1286          * {@link VideoProvider#onRequestCameraCapabilities()}, or when the current camera is
1287          * changed via {@link VideoProvider#onSetCamera(String)}.
1288          * <p>
1289          * Received by the {@link InCallService} via
1290          * {@link InCallService.VideoCall.Callback#onCameraCapabilitiesChanged(
1291          * VideoProfile.CameraCapabilities)}.
1292          *
1293          * @param cameraCapabilities The new camera capabilities.
1294          */
changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities)1295         public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
1296             if (mVideoCallbacks != null) {
1297                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1298                     try {
1299                         callback.changeCameraCapabilities(cameraCapabilities);
1300                     } catch (RemoteException ignored) {
1301                         Log.w(this, "changeCameraCapabilities callback failed", ignored);
1302                     }
1303                 }
1304             }
1305         }
1306 
1307         /**
1308          * Used to inform listening {@link InCallService} implementations when the video quality
1309          * of the call has changed.
1310          * <p>
1311          * Received by the {@link InCallService} via
1312          * {@link InCallService.VideoCall.Callback#onVideoQualityChanged(int)}.
1313          *
1314          * @param videoQuality The updated video quality.  Valid values:
1315          *      {@link VideoProfile#QUALITY_HIGH},
1316          *      {@link VideoProfile#QUALITY_MEDIUM},
1317          *      {@link VideoProfile#QUALITY_LOW},
1318          *      {@link VideoProfile#QUALITY_DEFAULT}.
1319          */
changeVideoQuality(int videoQuality)1320         public void changeVideoQuality(int videoQuality) {
1321             if (mVideoCallbacks != null) {
1322                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1323                     try {
1324                         callback.changeVideoQuality(videoQuality);
1325                     } catch (RemoteException ignored) {
1326                         Log.w(this, "changeVideoQuality callback failed", ignored);
1327                     }
1328                 }
1329             }
1330         }
1331     }
1332 
1333     private final Listener mConnectionDeathListener = new Listener() {
1334         @Override
1335         public void onDestroyed(Connection c) {
1336             if (mConferenceables.remove(c)) {
1337                 fireOnConferenceableConnectionsChanged();
1338             }
1339         }
1340     };
1341 
1342     private final Conference.Listener mConferenceDeathListener = new Conference.Listener() {
1343         @Override
1344         public void onDestroyed(Conference c) {
1345             if (mConferenceables.remove(c)) {
1346                 fireOnConferenceableConnectionsChanged();
1347             }
1348         }
1349     };
1350 
1351     /**
1352      * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
1353      * load factor before resizing, 1 means we only expect a single thread to
1354      * access the map so make only a single shard
1355      */
1356     private final Set<Listener> mListeners = Collections.newSetFromMap(
1357             new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
1358     private final List<Conferenceable> mConferenceables = new ArrayList<>();
1359     private final List<Conferenceable> mUnmodifiableConferenceables =
1360             Collections.unmodifiableList(mConferenceables);
1361 
1362     // The internal telecom call ID associated with this connection.
1363     private String mTelecomCallId;
1364     private int mState = STATE_NEW;
1365     private CallAudioState mCallAudioState;
1366     private Uri mAddress;
1367     private int mAddressPresentation;
1368     private String mCallerDisplayName;
1369     private int mCallerDisplayNamePresentation;
1370     private boolean mRingbackRequested = false;
1371     private int mConnectionCapabilities;
1372     private int mConnectionProperties;
1373     private VideoProvider mVideoProvider;
1374     private boolean mAudioModeIsVoip;
1375     private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
1376     private StatusHints mStatusHints;
1377     private int mVideoState;
1378     private DisconnectCause mDisconnectCause;
1379     private Conference mConference;
1380     private ConnectionService mConnectionService;
1381     private Bundle mExtras;
1382     private final Object mExtrasLock = new Object();
1383 
1384     /**
1385      * Tracks the key set for the extras bundle provided on the last invocation of
1386      * {@link #setExtras(Bundle)}.  Used so that on subsequent invocations we can remove any extras
1387      * keys which were set previously but are no longer present in the replacement Bundle.
1388      */
1389     private Set<String> mPreviousExtraKeys;
1390 
1391     /**
1392      * Create a new Connection.
1393      */
Connection()1394     public Connection() {}
1395 
1396     /**
1397      * Returns the Telecom internal call ID associated with this connection.  Should only be used
1398      * for debugging and tracing purposes.
1399      *
1400      * @return The Telecom call ID.
1401      * @hide
1402      */
getTelecomCallId()1403     public final String getTelecomCallId() {
1404         return mTelecomCallId;
1405     }
1406 
1407     /**
1408      * @return The address (e.g., phone number) to which this Connection is currently communicating.
1409      */
getAddress()1410     public final Uri getAddress() {
1411         return mAddress;
1412     }
1413 
1414     /**
1415      * @return The presentation requirements for the address.
1416      *         See {@link TelecomManager} for valid values.
1417      */
getAddressPresentation()1418     public final int getAddressPresentation() {
1419         return mAddressPresentation;
1420     }
1421 
1422     /**
1423      * @return The caller display name (CNAP).
1424      */
getCallerDisplayName()1425     public final String getCallerDisplayName() {
1426         return mCallerDisplayName;
1427     }
1428 
1429     /**
1430      * @return The presentation requirements for the handle.
1431      *         See {@link TelecomManager} for valid values.
1432      */
getCallerDisplayNamePresentation()1433     public final int getCallerDisplayNamePresentation() {
1434         return mCallerDisplayNamePresentation;
1435     }
1436 
1437     /**
1438      * @return The state of this Connection.
1439      */
getState()1440     public final int getState() {
1441         return mState;
1442     }
1443 
1444     /**
1445      * Returns the video state of the connection.
1446      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
1447      * {@link VideoProfile#STATE_BIDIRECTIONAL},
1448      * {@link VideoProfile#STATE_TX_ENABLED},
1449      * {@link VideoProfile#STATE_RX_ENABLED}.
1450      *
1451      * @return The video state of the connection.
1452      * @hide
1453      */
getVideoState()1454     public final int getVideoState() {
1455         return mVideoState;
1456     }
1457 
1458     /**
1459      * @return The audio state of the connection, describing how its audio is currently
1460      *         being routed by the system. This is {@code null} if this Connection
1461      *         does not directly know about its audio state.
1462      * @deprecated Use {@link #getCallAudioState()} instead.
1463      * @hide
1464      */
1465     @SystemApi
1466     @Deprecated
getAudioState()1467     public final AudioState getAudioState() {
1468         if (mCallAudioState == null) {
1469           return null;
1470         }
1471         return new AudioState(mCallAudioState);
1472     }
1473 
1474     /**
1475      * @return The audio state of the connection, describing how its audio is currently
1476      *         being routed by the system. This is {@code null} if this Connection
1477      *         does not directly know about its audio state.
1478      */
getCallAudioState()1479     public final CallAudioState getCallAudioState() {
1480         return mCallAudioState;
1481     }
1482 
1483     /**
1484      * @return The conference that this connection is a part of.  Null if it is not part of any
1485      *         conference.
1486      */
getConference()1487     public final Conference getConference() {
1488         return mConference;
1489     }
1490 
1491     /**
1492      * Returns whether this connection is requesting that the system play a ringback tone
1493      * on its behalf.
1494      */
isRingbackRequested()1495     public final boolean isRingbackRequested() {
1496         return mRingbackRequested;
1497     }
1498 
1499     /**
1500      * @return True if the connection's audio mode is VOIP.
1501      */
getAudioModeIsVoip()1502     public final boolean getAudioModeIsVoip() {
1503         return mAudioModeIsVoip;
1504     }
1505 
1506     /**
1507      * Retrieves the connection start time of the {@code Connnection}, if specified.  A value of
1508      * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the
1509      * start time of the conference.
1510      *
1511      * @return The time at which the {@code Connnection} was connected.
1512      *
1513      * @hide
1514      */
getConnectTimeMillis()1515     public final long getConnectTimeMillis() {
1516         return mConnectTimeMillis;
1517     }
1518 
1519     /**
1520      * @return The status hints for this connection.
1521      */
getStatusHints()1522     public final StatusHints getStatusHints() {
1523         return mStatusHints;
1524     }
1525 
1526     /**
1527      * Returns the extras associated with this connection.
1528      * <p>
1529      * Extras should be updated using {@link #putExtras(Bundle)}.
1530      * <p>
1531      * Telecom or an {@link InCallService} can also update the extras via
1532      * {@link android.telecom.Call#putExtras(Bundle)}, and
1533      * {@link Call#removeExtras(List)}.
1534      * <p>
1535      * The connection is notified of changes to the extras made by Telecom or an
1536      * {@link InCallService} by {@link #onExtrasChanged(Bundle)}.
1537      *
1538      * @return The extras associated with this connection.
1539      */
getExtras()1540     public final Bundle getExtras() {
1541         Bundle extras = null;
1542         synchronized (mExtrasLock) {
1543             if (mExtras != null) {
1544                 extras = new Bundle(mExtras);
1545             }
1546         }
1547         return extras;
1548     }
1549 
1550     /**
1551      * Assign a listener to be notified of state changes.
1552      *
1553      * @param l A listener.
1554      * @return This Connection.
1555      *
1556      * @hide
1557      */
addConnectionListener(Listener l)1558     public final Connection addConnectionListener(Listener l) {
1559         mListeners.add(l);
1560         return this;
1561     }
1562 
1563     /**
1564      * Remove a previously assigned listener that was being notified of state changes.
1565      *
1566      * @param l A Listener.
1567      * @return This Connection.
1568      *
1569      * @hide
1570      */
removeConnectionListener(Listener l)1571     public final Connection removeConnectionListener(Listener l) {
1572         if (l != null) {
1573             mListeners.remove(l);
1574         }
1575         return this;
1576     }
1577 
1578     /**
1579      * @return The {@link DisconnectCause} for this connection.
1580      */
getDisconnectCause()1581     public final DisconnectCause getDisconnectCause() {
1582         return mDisconnectCause;
1583     }
1584 
1585     /**
1586      * Sets the telecom call ID associated with this Connection.  The Telecom Call ID should be used
1587      * ONLY for debugging purposes.
1588      *
1589      * @param callId The telecom call ID.
1590      * @hide
1591      */
setTelecomCallId(String callId)1592     public void setTelecomCallId(String callId) {
1593         mTelecomCallId = callId;
1594     }
1595 
1596     /**
1597      * Inform this Connection that the state of its audio output has been changed externally.
1598      *
1599      * @param state The new audio state.
1600      * @hide
1601      */
setCallAudioState(CallAudioState state)1602     final void setCallAudioState(CallAudioState state) {
1603         checkImmutable();
1604         Log.d(this, "setAudioState %s", state);
1605         mCallAudioState = state;
1606         onAudioStateChanged(getAudioState());
1607         onCallAudioStateChanged(state);
1608     }
1609 
1610     /**
1611      * @param state An integer value of a {@code STATE_*} constant.
1612      * @return A string representation of the value.
1613      */
stateToString(int state)1614     public static String stateToString(int state) {
1615         switch (state) {
1616             case STATE_INITIALIZING:
1617                 return "INITIALIZING";
1618             case STATE_NEW:
1619                 return "NEW";
1620             case STATE_RINGING:
1621                 return "RINGING";
1622             case STATE_DIALING:
1623                 return "DIALING";
1624             case STATE_PULLING_CALL:
1625                 return "PULLING_CALL";
1626             case STATE_ACTIVE:
1627                 return "ACTIVE";
1628             case STATE_HOLDING:
1629                 return "HOLDING";
1630             case STATE_DISCONNECTED:
1631                 return "DISCONNECTED";
1632             default:
1633                 Log.wtf(Connection.class, "Unknown state %d", state);
1634                 return "UNKNOWN";
1635         }
1636     }
1637 
1638     /**
1639      * Returns the connection's capabilities, as a bit mask of the {@code CAPABILITY_*} constants.
1640      */
getConnectionCapabilities()1641     public final int getConnectionCapabilities() {
1642         return mConnectionCapabilities;
1643     }
1644 
1645     /**
1646      * Returns the connection's properties, as a bit mask of the {@code PROPERTY_*} constants.
1647      */
getConnectionProperties()1648     public final int getConnectionProperties() {
1649         return mConnectionProperties;
1650     }
1651 
1652     /**
1653      * Sets the value of the {@link #getAddress()} property.
1654      *
1655      * @param address The new address.
1656      * @param presentation The presentation requirements for the address.
1657      *        See {@link TelecomManager} for valid values.
1658      */
setAddress(Uri address, int presentation)1659     public final void setAddress(Uri address, int presentation) {
1660         checkImmutable();
1661         Log.d(this, "setAddress %s", address);
1662         mAddress = address;
1663         mAddressPresentation = presentation;
1664         for (Listener l : mListeners) {
1665             l.onAddressChanged(this, address, presentation);
1666         }
1667     }
1668 
1669     /**
1670      * Sets the caller display name (CNAP).
1671      *
1672      * @param callerDisplayName The new display name.
1673      * @param presentation The presentation requirements for the handle.
1674      *        See {@link TelecomManager} for valid values.
1675      */
setCallerDisplayName(String callerDisplayName, int presentation)1676     public final void setCallerDisplayName(String callerDisplayName, int presentation) {
1677         checkImmutable();
1678         Log.d(this, "setCallerDisplayName %s", callerDisplayName);
1679         mCallerDisplayName = callerDisplayName;
1680         mCallerDisplayNamePresentation = presentation;
1681         for (Listener l : mListeners) {
1682             l.onCallerDisplayNameChanged(this, callerDisplayName, presentation);
1683         }
1684     }
1685 
1686     /**
1687      * Set the video state for the connection.
1688      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
1689      * {@link VideoProfile#STATE_BIDIRECTIONAL},
1690      * {@link VideoProfile#STATE_TX_ENABLED},
1691      * {@link VideoProfile#STATE_RX_ENABLED}.
1692      *
1693      * @param videoState The new video state.
1694      */
setVideoState(int videoState)1695     public final void setVideoState(int videoState) {
1696         checkImmutable();
1697         Log.d(this, "setVideoState %d", videoState);
1698         mVideoState = videoState;
1699         for (Listener l : mListeners) {
1700             l.onVideoStateChanged(this, mVideoState);
1701         }
1702     }
1703 
1704     /**
1705      * Sets state to active (e.g., an ongoing connection where two or more parties can actively
1706      * communicate).
1707      */
setActive()1708     public final void setActive() {
1709         checkImmutable();
1710         setRingbackRequested(false);
1711         setState(STATE_ACTIVE);
1712     }
1713 
1714     /**
1715      * Sets state to ringing (e.g., an inbound ringing connection).
1716      */
setRinging()1717     public final void setRinging() {
1718         checkImmutable();
1719         setState(STATE_RINGING);
1720     }
1721 
1722     /**
1723      * Sets state to initializing (this Connection is not yet ready to be used).
1724      */
setInitializing()1725     public final void setInitializing() {
1726         checkImmutable();
1727         setState(STATE_INITIALIZING);
1728     }
1729 
1730     /**
1731      * Sets state to initialized (the Connection has been set up and is now ready to be used).
1732      */
setInitialized()1733     public final void setInitialized() {
1734         checkImmutable();
1735         setState(STATE_NEW);
1736     }
1737 
1738     /**
1739      * Sets state to dialing (e.g., dialing an outbound connection).
1740      */
setDialing()1741     public final void setDialing() {
1742         checkImmutable();
1743         setState(STATE_DIALING);
1744     }
1745 
1746     /**
1747      * Sets state to pulling (e.g. the connection is being pulled to the local device from another
1748      * device).  Only applicable for {@link Connection}s with
1749      * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} and {@link Connection#CAPABILITY_CAN_PULL_CALL}.
1750      */
setPulling()1751     public final void setPulling() {
1752         checkImmutable();
1753         setState(STATE_PULLING_CALL);
1754     }
1755 
1756     /**
1757      * Sets state to be on hold.
1758      */
setOnHold()1759     public final void setOnHold() {
1760         checkImmutable();
1761         setState(STATE_HOLDING);
1762     }
1763 
1764     /**
1765      * Sets the video connection provider.
1766      * @param videoProvider The video provider.
1767      */
setVideoProvider(VideoProvider videoProvider)1768     public final void setVideoProvider(VideoProvider videoProvider) {
1769         checkImmutable();
1770         mVideoProvider = videoProvider;
1771         for (Listener l : mListeners) {
1772             l.onVideoProviderChanged(this, videoProvider);
1773         }
1774     }
1775 
getVideoProvider()1776     public final VideoProvider getVideoProvider() {
1777         return mVideoProvider;
1778     }
1779 
1780     /**
1781      * Sets state to disconnected.
1782      *
1783      * @param disconnectCause The reason for the disconnection, as specified by
1784      *         {@link DisconnectCause}.
1785      */
setDisconnected(DisconnectCause disconnectCause)1786     public final void setDisconnected(DisconnectCause disconnectCause) {
1787         checkImmutable();
1788         mDisconnectCause = disconnectCause;
1789         setState(STATE_DISCONNECTED);
1790         Log.d(this, "Disconnected with cause %s", disconnectCause);
1791         for (Listener l : mListeners) {
1792             l.onDisconnected(this, disconnectCause);
1793         }
1794     }
1795 
1796     /**
1797      * Informs listeners that this {@code Connection} is in a post-dial wait state. This is done
1798      * when (a) the {@code Connection} is issuing a DTMF sequence; (b) it has encountered a "wait"
1799      * character; and (c) it wishes to inform the In-Call app that it is waiting for the end-user
1800      * to send an {@link #onPostDialContinue(boolean)} signal.
1801      *
1802      * @param remaining The DTMF character sequence remaining to be emitted once the
1803      *         {@link #onPostDialContinue(boolean)} is received, including any "wait" characters
1804      *         that remaining sequence may contain.
1805      */
setPostDialWait(String remaining)1806     public final void setPostDialWait(String remaining) {
1807         checkImmutable();
1808         for (Listener l : mListeners) {
1809             l.onPostDialWait(this, remaining);
1810         }
1811     }
1812 
1813     /**
1814      * Informs listeners that this {@code Connection} has processed a character in the post-dial
1815      * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence;
1816      * and (b) it wishes to signal Telecom to play the corresponding DTMF tone locally.
1817      *
1818      * @param nextChar The DTMF character that was just processed by the {@code Connection}.
1819      */
setNextPostDialChar(char nextChar)1820     public final void setNextPostDialChar(char nextChar) {
1821         checkImmutable();
1822         for (Listener l : mListeners) {
1823             l.onPostDialChar(this, nextChar);
1824         }
1825     }
1826 
1827     /**
1828      * Requests that the framework play a ringback tone. This is to be invoked by implementations
1829      * that do not play a ringback tone themselves in the connection's audio stream.
1830      *
1831      * @param ringback Whether the ringback tone is to be played.
1832      */
setRingbackRequested(boolean ringback)1833     public final void setRingbackRequested(boolean ringback) {
1834         checkImmutable();
1835         if (mRingbackRequested != ringback) {
1836             mRingbackRequested = ringback;
1837             for (Listener l : mListeners) {
1838                 l.onRingbackRequested(this, ringback);
1839             }
1840         }
1841     }
1842 
1843     /**
1844      * Sets the connection's capabilities as a bit mask of the {@code CAPABILITY_*} constants.
1845      *
1846      * @param connectionCapabilities The new connection capabilities.
1847      */
setConnectionCapabilities(int connectionCapabilities)1848     public final void setConnectionCapabilities(int connectionCapabilities) {
1849         checkImmutable();
1850         if (mConnectionCapabilities != connectionCapabilities) {
1851             mConnectionCapabilities = connectionCapabilities;
1852             for (Listener l : mListeners) {
1853                 l.onConnectionCapabilitiesChanged(this, mConnectionCapabilities);
1854             }
1855         }
1856     }
1857 
1858     /**
1859      * Sets the connection's properties as a bit mask of the {@code PROPERTY_*} constants.
1860      *
1861      * @param connectionProperties The new connection properties.
1862      */
setConnectionProperties(int connectionProperties)1863     public final void setConnectionProperties(int connectionProperties) {
1864         checkImmutable();
1865         if (mConnectionProperties != connectionProperties) {
1866             mConnectionProperties = connectionProperties;
1867             for (Listener l : mListeners) {
1868                 l.onConnectionPropertiesChanged(this, mConnectionProperties);
1869             }
1870         }
1871     }
1872 
1873     /**
1874      * Tears down the Connection object.
1875      */
destroy()1876     public final void destroy() {
1877         for (Listener l : mListeners) {
1878             l.onDestroyed(this);
1879         }
1880     }
1881 
1882     /**
1883      * Requests that the framework use VOIP audio mode for this connection.
1884      *
1885      * @param isVoip True if the audio mode is VOIP.
1886      */
setAudioModeIsVoip(boolean isVoip)1887     public final void setAudioModeIsVoip(boolean isVoip) {
1888         checkImmutable();
1889         mAudioModeIsVoip = isVoip;
1890         for (Listener l : mListeners) {
1891             l.onAudioModeIsVoipChanged(this, isVoip);
1892         }
1893     }
1894 
1895     /**
1896      * Sets the time at which a call became active on this Connection. This is set only
1897      * when a conference call becomes active on this connection.
1898      *
1899      * @param connectionTimeMillis The connection time, in milliseconds.
1900      *
1901      * @hide
1902      */
setConnectTimeMillis(long connectTimeMillis)1903     public final void setConnectTimeMillis(long connectTimeMillis) {
1904         mConnectTimeMillis = connectTimeMillis;
1905     }
1906 
1907     /**
1908      * Sets the label and icon status to display in the in-call UI.
1909      *
1910      * @param statusHints The status label and icon to set.
1911      */
setStatusHints(StatusHints statusHints)1912     public final void setStatusHints(StatusHints statusHints) {
1913         checkImmutable();
1914         mStatusHints = statusHints;
1915         for (Listener l : mListeners) {
1916             l.onStatusHintsChanged(this, statusHints);
1917         }
1918     }
1919 
1920     /**
1921      * Sets the connections with which this connection can be conferenced.
1922      *
1923      * @param conferenceableConnections The set of connections this connection can conference with.
1924      */
setConferenceableConnections(List<Connection> conferenceableConnections)1925     public final void setConferenceableConnections(List<Connection> conferenceableConnections) {
1926         checkImmutable();
1927         clearConferenceableList();
1928         for (Connection c : conferenceableConnections) {
1929             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
1930             // small amount of items here.
1931             if (!mConferenceables.contains(c)) {
1932                 c.addConnectionListener(mConnectionDeathListener);
1933                 mConferenceables.add(c);
1934             }
1935         }
1936         fireOnConferenceableConnectionsChanged();
1937     }
1938 
1939     /**
1940      * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections
1941      * or conferences with which this connection can be conferenced.
1942      *
1943      * @param conferenceables The conferenceables.
1944      */
setConferenceables(List<Conferenceable> conferenceables)1945     public final void setConferenceables(List<Conferenceable> conferenceables) {
1946         clearConferenceableList();
1947         for (Conferenceable c : conferenceables) {
1948             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
1949             // small amount of items here.
1950             if (!mConferenceables.contains(c)) {
1951                 if (c instanceof Connection) {
1952                     Connection connection = (Connection) c;
1953                     connection.addConnectionListener(mConnectionDeathListener);
1954                 } else if (c instanceof Conference) {
1955                     Conference conference = (Conference) c;
1956                     conference.addListener(mConferenceDeathListener);
1957                 }
1958                 mConferenceables.add(c);
1959             }
1960         }
1961         fireOnConferenceableConnectionsChanged();
1962     }
1963 
1964     /**
1965      * Returns the connections or conferences with which this connection can be conferenced.
1966      */
getConferenceables()1967     public final List<Conferenceable> getConferenceables() {
1968         return mUnmodifiableConferenceables;
1969     }
1970 
1971     /**
1972      * @hide
1973      */
setConnectionService(ConnectionService connectionService)1974     public final void setConnectionService(ConnectionService connectionService) {
1975         checkImmutable();
1976         if (mConnectionService != null) {
1977             Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " +
1978                     "which is already associated with another ConnectionService.");
1979         } else {
1980             mConnectionService = connectionService;
1981         }
1982     }
1983 
1984     /**
1985      * @hide
1986      */
unsetConnectionService(ConnectionService connectionService)1987     public final void unsetConnectionService(ConnectionService connectionService) {
1988         if (mConnectionService != connectionService) {
1989             Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " +
1990                     "that does not belong to the ConnectionService.");
1991         } else {
1992             mConnectionService = null;
1993         }
1994     }
1995 
1996     /**
1997      * @hide
1998      */
getConnectionService()1999     public final ConnectionService getConnectionService() {
2000         return mConnectionService;
2001     }
2002 
2003     /**
2004      * Sets the conference that this connection is a part of. This will fail if the connection is
2005      * already part of a conference. {@link #resetConference} to un-set the conference first.
2006      *
2007      * @param conference The conference.
2008      * @return {@code true} if the conference was successfully set.
2009      * @hide
2010      */
setConference(Conference conference)2011     public final boolean setConference(Conference conference) {
2012         checkImmutable();
2013         // We check to see if it is already part of another conference.
2014         if (mConference == null) {
2015             mConference = conference;
2016             if (mConnectionService != null && mConnectionService.containsConference(conference)) {
2017                 fireConferenceChanged();
2018             }
2019             return true;
2020         }
2021         return false;
2022     }
2023 
2024     /**
2025      * Resets the conference that this connection is a part of.
2026      * @hide
2027      */
resetConference()2028     public final void resetConference() {
2029         if (mConference != null) {
2030             Log.d(this, "Conference reset");
2031             mConference = null;
2032             fireConferenceChanged();
2033         }
2034     }
2035 
2036     /**
2037      * Set some extras that can be associated with this {@code Connection}.
2038      * <p>
2039      * New or existing keys are replaced in the {@code Connection} extras.  Keys which are no longer
2040      * in the new extras, but were present the last time {@code setExtras} was called are removed.
2041      * <p>
2042      * Alternatively you may use the {@link #putExtras(Bundle)}, and
2043      * {@link #removeExtras(String...)} methods to modify the extras.
2044      * <p>
2045      * No assumptions should be made as to how an In-Call UI or service will handle these extras.
2046      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
2047      *
2048      * @param extras The extras associated with this {@code Connection}.
2049      */
setExtras(@ullable Bundle extras)2050     public final void setExtras(@Nullable Bundle extras) {
2051         checkImmutable();
2052 
2053         // Add/replace any new or changed extras values.
2054         putExtras(extras);
2055 
2056         // If we have used "setExtras" in the past, compare the key set from the last invocation to
2057         // the current one and remove any keys that went away.
2058         if (mPreviousExtraKeys != null) {
2059             List<String> toRemove = new ArrayList<String>();
2060             for (String oldKey : mPreviousExtraKeys) {
2061                 if (extras == null || !extras.containsKey(oldKey)) {
2062                     toRemove.add(oldKey);
2063                 }
2064             }
2065             if (!toRemove.isEmpty()) {
2066                 removeExtras(toRemove);
2067             }
2068         }
2069 
2070         // Track the keys the last time set called setExtras.  This way, the next time setExtras is
2071         // called we can see if the caller has removed any extras values.
2072         if (mPreviousExtraKeys == null) {
2073             mPreviousExtraKeys = new ArraySet<String>();
2074         }
2075         mPreviousExtraKeys.clear();
2076         if (extras != null) {
2077             mPreviousExtraKeys.addAll(extras.keySet());
2078         }
2079     }
2080 
2081     /**
2082      * Adds some extras to this {@code Connection}.  Existing keys are replaced and new ones are
2083      * added.
2084      * <p>
2085      * No assumptions should be made as to how an In-Call UI or service will handle these extras.
2086      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
2087      *
2088      * @param extras The extras to add.
2089      */
putExtras(@onNull Bundle extras)2090     public final void putExtras(@NonNull Bundle extras) {
2091         checkImmutable();
2092         if (extras == null) {
2093             return;
2094         }
2095         // Creating a duplicate bundle so we don't have to synchronize on mExtrasLock while calling
2096         // the listeners.
2097         Bundle listenerExtras;
2098         synchronized (mExtrasLock) {
2099             if (mExtras == null) {
2100                 mExtras = new Bundle();
2101             }
2102             mExtras.putAll(extras);
2103             listenerExtras = new Bundle(mExtras);
2104         }
2105         for (Listener l : mListeners) {
2106             // Create a new clone of the extras for each listener so that they don't clobber
2107             // each other
2108             l.onExtrasChanged(this, new Bundle(listenerExtras));
2109         }
2110     }
2111 
2112     /**
2113      * Adds a boolean extra to this {@code Connection}.
2114      *
2115      * @param key The extra key.
2116      * @param value The value.
2117      * @hide
2118      */
putExtra(String key, boolean value)2119     public final void putExtra(String key, boolean value) {
2120         Bundle newExtras = new Bundle();
2121         newExtras.putBoolean(key, value);
2122         putExtras(newExtras);
2123     }
2124 
2125     /**
2126      * Adds an integer extra to this {@code Connection}.
2127      *
2128      * @param key The extra key.
2129      * @param value The value.
2130      * @hide
2131      */
putExtra(String key, int value)2132     public final void putExtra(String key, int value) {
2133         Bundle newExtras = new Bundle();
2134         newExtras.putInt(key, value);
2135         putExtras(newExtras);
2136     }
2137 
2138     /**
2139      * Adds a string extra to this {@code Connection}.
2140      *
2141      * @param key The extra key.
2142      * @param value The value.
2143      * @hide
2144      */
putExtra(String key, String value)2145     public final void putExtra(String key, String value) {
2146         Bundle newExtras = new Bundle();
2147         newExtras.putString(key, value);
2148         putExtras(newExtras);
2149     }
2150 
2151     /**
2152      * Removes extras from this {@code Connection}.
2153      *
2154      * @param keys The keys of the extras to remove.
2155      */
removeExtras(List<String> keys)2156     public final void removeExtras(List<String> keys) {
2157         synchronized (mExtrasLock) {
2158             if (mExtras != null) {
2159                 for (String key : keys) {
2160                     mExtras.remove(key);
2161                 }
2162             }
2163         }
2164         List<String> unmodifiableKeys = Collections.unmodifiableList(keys);
2165         for (Listener l : mListeners) {
2166             l.onExtrasRemoved(this, unmodifiableKeys);
2167         }
2168     }
2169 
2170     /**
2171      * Removes extras from this {@code Connection}.
2172      *
2173      * @param keys The keys of the extras to remove.
2174      */
removeExtras(String .... keys)2175     public final void removeExtras(String ... keys) {
2176         removeExtras(Arrays.asList(keys));
2177     }
2178 
2179     /**
2180      * Notifies this Connection that the {@link #getAudioState()} property has a new value.
2181      *
2182      * @param state The new connection audio state.
2183      * @deprecated Use {@link #onCallAudioStateChanged(CallAudioState)} instead.
2184      * @hide
2185      */
2186     @SystemApi
2187     @Deprecated
onAudioStateChanged(AudioState state)2188     public void onAudioStateChanged(AudioState state) {}
2189 
2190     /**
2191      * Notifies this Connection that the {@link #getCallAudioState()} property has a new value.
2192      *
2193      * @param state The new connection audio state.
2194      */
onCallAudioStateChanged(CallAudioState state)2195     public void onCallAudioStateChanged(CallAudioState state) {}
2196 
2197     /**
2198      * Notifies this Connection of an internal state change. This method is called after the
2199      * state is changed.
2200      *
2201      * @param state The new state, one of the {@code STATE_*} constants.
2202      */
onStateChanged(int state)2203     public void onStateChanged(int state) {}
2204 
2205     /**
2206      * Notifies this Connection of a request to play a DTMF tone.
2207      *
2208      * @param c A DTMF character.
2209      */
onPlayDtmfTone(char c)2210     public void onPlayDtmfTone(char c) {}
2211 
2212     /**
2213      * Notifies this Connection of a request to stop any currently playing DTMF tones.
2214      */
onStopDtmfTone()2215     public void onStopDtmfTone() {}
2216 
2217     /**
2218      * Notifies this Connection of a request to disconnect.
2219      */
onDisconnect()2220     public void onDisconnect() {}
2221 
2222     /**
2223      * Notifies this Connection of a request to disconnect a participant of the conference managed
2224      * by the connection.
2225      *
2226      * @param endpoint the {@link Uri} of the participant to disconnect.
2227      * @hide
2228      */
onDisconnectConferenceParticipant(Uri endpoint)2229     public void onDisconnectConferenceParticipant(Uri endpoint) {}
2230 
2231     /**
2232      * Notifies this Connection of a request to separate from its parent conference.
2233      */
onSeparate()2234     public void onSeparate() {}
2235 
2236     /**
2237      * Notifies this Connection of a request to abort.
2238      */
onAbort()2239     public void onAbort() {}
2240 
2241     /**
2242      * Notifies this Connection of a request to hold.
2243      */
onHold()2244     public void onHold() {}
2245 
2246     /**
2247      * Notifies this Connection of a request to exit a hold state.
2248      */
onUnhold()2249     public void onUnhold() {}
2250 
2251     /**
2252      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
2253      * a request to accept.
2254      *
2255      * @param videoState The video state in which to answer the connection.
2256      */
onAnswer(int videoState)2257     public void onAnswer(int videoState) {}
2258 
2259     /**
2260      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
2261      * a request to accept.
2262      */
onAnswer()2263     public void onAnswer() {
2264         onAnswer(VideoProfile.STATE_AUDIO_ONLY);
2265     }
2266 
2267     /**
2268      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
2269      * a request to reject.
2270      */
onReject()2271     public void onReject() {}
2272 
2273     /**
2274      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
2275      * a request to reject with a message.
2276      */
onReject(String replyMessage)2277     public void onReject(String replyMessage) {}
2278 
2279     /**
2280      * Notifies the Connection of a request to silence the ringer.
2281      *
2282      * @hide
2283      */
onSilence()2284     public void onSilence() {}
2285 
2286     /**
2287      * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
2288      */
onPostDialContinue(boolean proceed)2289     public void onPostDialContinue(boolean proceed) {}
2290 
2291     /**
2292      * Notifies this Connection of a request to pull an external call to the local device.
2293      * <p>
2294      * The {@link InCallService} issues a request to pull an external call to the local device via
2295      * {@link Call#pullExternalCall()}.
2296      * <p>
2297      * For a Connection to be pulled, both the {@link Connection#CAPABILITY_CAN_PULL_CALL}
2298      * capability and {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property bits must be set.
2299      * <p>
2300      * For more information on external calls, see {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
2301      */
onPullExternalCall()2302     public void onPullExternalCall() {}
2303 
2304     /**
2305      * Notifies this Connection of a {@link Call} event initiated from an {@link InCallService}.
2306      * <p>
2307      * The {@link InCallService} issues a Call event via {@link Call#sendCallEvent(String, Bundle)}.
2308      * <p>
2309      * Where possible, the Connection should make an attempt to handle {@link Call} events which
2310      * are part of the {@code android.telecom.*} namespace.  The Connection should ignore any events
2311      * it does not wish to handle.  Unexpected events should be handled gracefully, as it is
2312      * possible that a {@link InCallService} has defined its own Call events which a Connection is
2313      * not aware of.
2314      * <p>
2315      * See also {@link Call#sendCallEvent(String, Bundle)}.
2316      *
2317      * @param event The call event.
2318      * @param extras Extras associated with the call event.
2319      */
onCallEvent(String event, Bundle extras)2320     public void onCallEvent(String event, Bundle extras) {}
2321 
2322     /**
2323      * Notifies this {@link Connection} of a change to the extras made outside the
2324      * {@link ConnectionService}.
2325      * <p>
2326      * These extras changes can originate from Telecom itself, or from an {@link InCallService} via
2327      * the {@link android.telecom.Call#putExtras(Bundle)} and
2328      * {@link Call#removeExtras(List)}.
2329      *
2330      * @param extras The new extras bundle.
2331      */
onExtrasChanged(Bundle extras)2332     public void onExtrasChanged(Bundle extras) {}
2333 
toLogSafePhoneNumber(String number)2334     static String toLogSafePhoneNumber(String number) {
2335         // For unknown number, log empty string.
2336         if (number == null) {
2337             return "";
2338         }
2339 
2340         if (PII_DEBUG) {
2341             // When PII_DEBUG is true we emit PII.
2342             return number;
2343         }
2344 
2345         // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
2346         // sanitized phone numbers.
2347         StringBuilder builder = new StringBuilder();
2348         for (int i = 0; i < number.length(); i++) {
2349             char c = number.charAt(i);
2350             if (c == '-' || c == '@' || c == '.') {
2351                 builder.append(c);
2352             } else {
2353                 builder.append('x');
2354             }
2355         }
2356         return builder.toString();
2357     }
2358 
setState(int state)2359     private void setState(int state) {
2360         checkImmutable();
2361         if (mState == STATE_DISCONNECTED && mState != state) {
2362             Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state.");
2363             return;
2364         }
2365         if (mState != state) {
2366             Log.d(this, "setState: %s", stateToString(state));
2367             mState = state;
2368             onStateChanged(state);
2369             for (Listener l : mListeners) {
2370                 l.onStateChanged(this, state);
2371             }
2372         }
2373     }
2374 
2375     private static class FailureSignalingConnection extends Connection {
2376         private boolean mImmutable = false;
FailureSignalingConnection(DisconnectCause disconnectCause)2377         public FailureSignalingConnection(DisconnectCause disconnectCause) {
2378             setDisconnected(disconnectCause);
2379             mImmutable = true;
2380         }
2381 
checkImmutable()2382         public void checkImmutable() {
2383             if (mImmutable) {
2384                 throw new UnsupportedOperationException("Connection is immutable");
2385             }
2386         }
2387     }
2388 
2389     /**
2390      * Return a {@code Connection} which represents a failed connection attempt. The returned
2391      * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified,
2392      * and a {@link #getState()} of {@link #STATE_DISCONNECTED}.
2393      * <p>
2394      * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate,
2395      * so users of this method need not maintain a reference to its return value to destroy it.
2396      *
2397      * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
2398      * @return A {@code Connection} which indicates failure.
2399      */
createFailedConnection(DisconnectCause disconnectCause)2400     public static Connection createFailedConnection(DisconnectCause disconnectCause) {
2401         return new FailureSignalingConnection(disconnectCause);
2402     }
2403 
2404     /**
2405      * Override to throw an {@link UnsupportedOperationException} if this {@code Connection} is
2406      * not intended to be mutated, e.g., if it is a marker for failure. Only for framework use;
2407      * this should never be un-@hide-den.
2408      *
2409      * @hide
2410      */
checkImmutable()2411     public void checkImmutable() {}
2412 
2413     /**
2414      * Return a {@code Connection} which represents a canceled connection attempt. The returned
2415      * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of
2416      * that state. This connection should not be used for anything, and no other
2417      * {@code Connection}s should be attempted.
2418      * <p>
2419      * so users of this method need not maintain a reference to its return value to destroy it.
2420      *
2421      * @return A {@code Connection} which indicates that the underlying connection should
2422      * be canceled.
2423      */
createCanceledConnection()2424     public static Connection createCanceledConnection() {
2425         return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED));
2426     }
2427 
fireOnConferenceableConnectionsChanged()2428     private final void fireOnConferenceableConnectionsChanged() {
2429         for (Listener l : mListeners) {
2430             l.onConferenceablesChanged(this, getConferenceables());
2431         }
2432     }
2433 
fireConferenceChanged()2434     private final void fireConferenceChanged() {
2435         for (Listener l : mListeners) {
2436             l.onConferenceChanged(this, mConference);
2437         }
2438     }
2439 
clearConferenceableList()2440     private final void clearConferenceableList() {
2441         for (Conferenceable c : mConferenceables) {
2442             if (c instanceof Connection) {
2443                 Connection connection = (Connection) c;
2444                 connection.removeConnectionListener(mConnectionDeathListener);
2445             } else if (c instanceof Conference) {
2446                 Conference conference = (Conference) c;
2447                 conference.removeListener(mConferenceDeathListener);
2448             }
2449         }
2450         mConferenceables.clear();
2451     }
2452 
2453     /**
2454      * Handles a change to extras received from Telecom.
2455      *
2456      * @param extras The new extras.
2457      * @hide
2458      */
handleExtrasChanged(Bundle extras)2459     final void handleExtrasChanged(Bundle extras) {
2460         Bundle b = null;
2461         synchronized (mExtrasLock) {
2462             mExtras = extras;
2463             if (mExtras != null) {
2464                 b = new Bundle(mExtras);
2465             }
2466         }
2467         onExtrasChanged(b);
2468     }
2469 
2470     /**
2471      * Notifies listeners that the merge request failed.
2472      *
2473      * @hide
2474      */
notifyConferenceMergeFailed()2475     protected final void notifyConferenceMergeFailed() {
2476         for (Listener l : mListeners) {
2477             l.onConferenceMergeFailed(this);
2478         }
2479     }
2480 
2481     /**
2482      * Notifies listeners of a change to conference participant(s).
2483      *
2484      * @param conferenceParticipants The participants.
2485      * @hide
2486      */
updateConferenceParticipants( List<ConferenceParticipant> conferenceParticipants)2487     protected final void updateConferenceParticipants(
2488             List<ConferenceParticipant> conferenceParticipants) {
2489         for (Listener l : mListeners) {
2490             l.onConferenceParticipantsChanged(this, conferenceParticipants);
2491         }
2492     }
2493 
2494     /**
2495      * Notifies listeners that a conference call has been started.
2496      * @hide
2497      */
notifyConferenceStarted()2498     protected void notifyConferenceStarted() {
2499         for (Listener l : mListeners) {
2500             l.onConferenceStarted();
2501         }
2502     }
2503 
2504     /**
2505      * Notifies listeners when a change has occurred to the Connection which impacts its ability to
2506      * be a part of a conference call.
2507      * @param isConferenceSupported {@code true} if the connection supports being part of a
2508      *      conference call, {@code false} otherwise.
2509      * @hide
2510      */
notifyConferenceSupportedChanged(boolean isConferenceSupported)2511     protected void notifyConferenceSupportedChanged(boolean isConferenceSupported) {
2512         for (Listener l : mListeners) {
2513             l.onConferenceSupportedChanged(this, isConferenceSupported);
2514         }
2515     }
2516 
2517     /**
2518      * Sends an event associated with this {@code Connection} with associated event extras to the
2519      * {@link InCallService}.
2520      * <p>
2521      * Connection events are used to communicate point in time information from a
2522      * {@link ConnectionService} to a {@link InCallService} implementations.  An example of a
2523      * custom connection event includes notifying the UI when a WIFI call has been handed over to
2524      * LTE, which the InCall UI might use to inform the user that billing charges may apply.  The
2525      * Android Telephony framework will send the {@link #EVENT_CALL_MERGE_FAILED} connection event
2526      * when a call to {@link Call#mergeConference()} has failed to complete successfully.  A
2527      * connection event could also be used to trigger UI in the {@link InCallService} which prompts
2528      * the user to make a choice (e.g. whether they want to incur roaming costs for making a call),
2529      * which is communicated back via {@link Call#sendCallEvent(String, Bundle)}.
2530      * <p>
2531      * Events are exposed to {@link InCallService} implementations via
2532      * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
2533      * <p>
2534      * No assumptions should be made as to how an In-Call UI or service will handle these events.
2535      * The {@link ConnectionService} must assume that the In-Call UI could even chose to ignore
2536      * some events altogether.
2537      * <p>
2538      * Events should be fully qualified (e.g. {@code com.example.event.MY_EVENT}) to avoid
2539      * conflicts between {@link ConnectionService} implementations.  Further, custom
2540      * {@link ConnectionService} implementations shall not re-purpose events in the
2541      * {@code android.*} namespace, nor shall they define new event types in this namespace.  When
2542      * defining a custom event type, ensure the contents of the extras {@link Bundle} is clearly
2543      * defined.  Extra keys for this bundle should be named similar to the event type (e.g.
2544      * {@code com.example.extra.MY_EXTRA}).
2545      * <p>
2546      *  When defining events and the associated extras, it is important to keep their behavior
2547      * consistent when the associated {@link ConnectionService} is updated.  Support for deprecated
2548      * events/extras should me maintained to ensure backwards compatibility with older
2549      * {@link InCallService} implementations which were built to support the older behavior.
2550      *
2551      * @param event The connection event.
2552      * @param extras Optional bundle containing extra information associated with the event.
2553      */
sendConnectionEvent(String event, Bundle extras)2554     public void sendConnectionEvent(String event, Bundle extras) {
2555         for (Listener l : mListeners) {
2556             l.onConnectionEvent(this, event, extras);
2557         }
2558     }
2559 }
2560