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.app.Notification;
27 import android.bluetooth.BluetoothDevice;
28 import android.content.Intent;
29 import android.hardware.camera2.CameraManager;
30 import android.net.Uri;
31 import android.os.Binder;
32 import android.os.Bundle;
33 import android.os.Handler;
34 import android.os.IBinder;
35 import android.os.Looper;
36 import android.os.Message;
37 import android.os.ParcelFileDescriptor;
38 import android.os.RemoteException;
39 import android.os.SystemClock;
40 import android.util.ArraySet;
41 import android.view.Surface;
42 
43 import java.io.FileInputStream;
44 import java.io.FileOutputStream;
45 import java.io.IOException;
46 import java.io.InputStreamReader;
47 import java.io.OutputStreamWriter;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Collections;
51 import java.util.List;
52 import java.util.Set;
53 import java.util.concurrent.ConcurrentHashMap;
54 
55 /**
56  * Represents a phone call or connection to a remote endpoint that carries voice and/or video
57  * traffic.
58  * <p>
59  * Implementations create a custom subclass of {@code Connection} and return it to the framework
60  * as the return value of
61  * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}
62  * or
63  * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
64  * Implementations are then responsible for updating the state of the {@code Connection}, and
65  * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no
66  * longer used and associated resources may be recovered.
67  * <p>
68  * Subclasses of {@code Connection} override the {@code on*} methods to provide the the
69  * {@link ConnectionService}'s implementation of calling functionality.  The {@code on*} methods are
70  * called by Telecom to inform an instance of a {@code Connection} of actions specific to that
71  * {@code Connection} instance.
72  * <p>
73  * Basic call support requires overriding the following methods: {@link #onAnswer()},
74  * {@link #onDisconnect()}, {@link #onReject()}, {@link #onAbort()}
75  * <p>
76  * Where a {@code Connection} has {@link #CAPABILITY_SUPPORT_HOLD}, the {@link #onHold()} and
77  * {@link #onUnhold()} methods should be overridden to provide hold support for the
78  * {@code Connection}.
79  * <p>
80  * Where a {@code Connection} supports a variation of video calling (e.g. the
81  * {@code CAPABILITY_SUPPORTS_VT_*} capability bits), {@link #onAnswer(int)} should be overridden
82  * to support answering a call as a video call.
83  * <p>
84  * Where a {@code Connection} has {@link #PROPERTY_IS_EXTERNAL_CALL} and
85  * {@link #CAPABILITY_CAN_PULL_CALL}, {@link #onPullExternalCall()} should be overridden to provide
86  * support for pulling the external call.
87  * <p>
88  * Where a {@code Connection} supports conference calling {@link #onSeparate()} should be
89  * overridden.
90  * <p>
91  * There are a number of other {@code on*} methods which a {@code Connection} can choose to
92  * implement, depending on whether it is concerned with the associated calls from Telecom.  If,
93  * for example, call events from a {@link InCallService} are handled,
94  * {@link #onCallEvent(String, Bundle)} should be overridden.  Another example is
95  * {@link #onExtrasChanged(Bundle)}, which should be overridden if the {@code Connection} wishes to
96  * make use of extra information provided via the {@link Call#putExtras(Bundle)} and
97  * {@link Call#removeExtras(String...)} methods.
98  */
99 public abstract class Connection extends Conferenceable {
100 
101     /**
102      * The connection is initializing. This is generally the first state for a {@code Connection}
103      * returned by a {@link ConnectionService}.
104      */
105     public static final int STATE_INITIALIZING = 0;
106 
107     /**
108      * The connection is new and not connected.
109      */
110     public static final int STATE_NEW = 1;
111 
112     /**
113      * An incoming connection is in the ringing state. During this state, the user's ringer or
114      * vibration feature will be activated.
115      */
116     public static final int STATE_RINGING = 2;
117 
118     /**
119      * An outgoing connection is in the dialing state. In this state the other party has not yet
120      * answered the call and the user traditionally hears a ringback tone.
121      */
122     public static final int STATE_DIALING = 3;
123 
124     /**
125      * A connection is active. Both parties are connected to the call and can actively communicate.
126      */
127     public static final int STATE_ACTIVE = 4;
128 
129     /**
130      * A connection is on hold.
131      */
132     public static final int STATE_HOLDING = 5;
133 
134     /**
135      * A connection has been disconnected. This is the final state once the user has been
136      * disconnected from a call either locally, remotely or by an error in the service.
137      */
138     public static final int STATE_DISCONNECTED = 6;
139 
140     /**
141      * The state of an external connection which is in the process of being pulled from a remote
142      * device to the local device.
143      * <p>
144      * A connection can only be in this state if the {@link #PROPERTY_IS_EXTERNAL_CALL} property and
145      * {@link #CAPABILITY_CAN_PULL_CALL} capability bits are set on the connection.
146      */
147     public static final int STATE_PULLING_CALL = 7;
148 
149     /**
150      * Connection can currently be put on hold or unheld. This is distinct from
151      * {@link #CAPABILITY_SUPPORT_HOLD} in that although a connection may support 'hold' most times,
152      * it does not at the moment support the function. This can be true while the call is in the
153      * state {@link #STATE_DIALING}, for example. During this condition, an in-call UI may
154      * display a disabled 'hold' button.
155      */
156     public static final int CAPABILITY_HOLD = 0x00000001;
157 
158     /** Connection supports the hold feature. */
159     public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
160 
161     /**
162      * Connections within a conference can be merged. A {@link ConnectionService} has the option to
163      * add a {@link Conference} before the child {@link Connection}s are merged. This is how
164      * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
165      * capability allows a merge button to be shown while the conference is in the foreground
166      * of the in-call UI.
167      * <p>
168      * This is only intended for use by a {@link Conference}.
169      */
170     public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
171 
172     /**
173      * Connections within a conference can be swapped between foreground and background.
174      * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
175      * <p>
176      * This is only intended for use by a {@link Conference}.
177      */
178     public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
179 
180     /**
181      * @hide
182      */
183     public static final int CAPABILITY_UNUSED = 0x00000010;
184 
185     /** Connection supports responding via text option. */
186     public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
187 
188     /** Connection can be muted. */
189     public static final int CAPABILITY_MUTE = 0x00000040;
190 
191     /**
192      * Connection supports conference management. This capability only applies to
193      * {@link Conference}s which can have {@link Connection}s as children.
194      */
195     public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
196 
197     /**
198      * Local device supports receiving video.
199      */
200     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
201 
202     /**
203      * Local device supports transmitting video.
204      */
205     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
206 
207     /**
208      * Local device supports bidirectional video calling.
209      */
210     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
211             CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
212 
213     /**
214      * Remote device supports receiving video.
215      */
216     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
217 
218     /**
219      * Remote device supports transmitting video.
220      */
221     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
222 
223     /**
224      * Remote device supports bidirectional video calling.
225      */
226     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
227             CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
228 
229     /**
230      * Connection is able to be separated from its parent {@code Conference}, if any.
231      */
232     public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
233 
234     /**
235      * Connection is able to be individually disconnected when in a {@code Conference}.
236      */
237     public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
238 
239     /**
240      * Un-used.
241      * @hide
242      */
243     public static final int CAPABILITY_UNUSED_2 = 0x00004000;
244 
245     /**
246      * Un-used.
247      * @hide
248      */
249     public static final int CAPABILITY_UNUSED_3 = 0x00008000;
250 
251     /**
252      * Un-used.
253      * @hide
254      */
255     public static final int CAPABILITY_UNUSED_4 = 0x00010000;
256 
257     /**
258      * Un-used.
259      * @hide
260      */
261     public static final int CAPABILITY_UNUSED_5 = 0x00020000;
262 
263     /**
264      * Speed up audio setup for MT call.
265      * @hide
266      */
267     public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
268 
269     /**
270      * Call can be upgraded to a video call.
271      */
272     public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
273 
274     /**
275      * For video calls, indicates whether the outgoing video for the call can be paused using
276      * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
277      */
278     public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
279 
280     /**
281      * For a conference, indicates the conference will not have child connections.
282      * <p>
283      * An example of a conference with child connections is a GSM conference call, where the radio
284      * retains connections to the individual participants of the conference.  Another example is an
285      * IMS conference call where conference event package functionality is supported; in this case
286      * the conference server ensures the radio is aware of the participants in the conference, which
287      * are represented by child connections.
288      * <p>
289      * An example of a conference with no child connections is an IMS conference call with no
290      * conference event package support.  Such a conference is represented by the radio as a single
291      * connection to the IMS conference server.
292      * <p>
293      * Indicating whether a conference has children or not is important to help user interfaces
294      * visually represent a conference.  A conference with no children, for example, will have the
295      * conference connection shown in the list of calls on a Bluetooth device, where if the
296      * conference has children, only the children will be shown in the list of calls on a Bluetooth
297      * device.
298      * @hide
299      */
300     public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
301 
302     /**
303      * Indicates that the connection itself wants to handle any sort of reply response, rather than
304      * relying on SMS.
305      */
306     public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
307 
308     /**
309      * When set, prevents a video call from being downgraded to an audio-only call.
310      * <p>
311      * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
312      * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
313      * downgraded from a video call back to a VideoState of
314      * {@link VideoProfile#STATE_AUDIO_ONLY}.
315      * <p>
316      * Intuitively, a call which can be downgraded to audio should also have local and remote
317      * video
318      * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
319      * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
320      */
321     public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00800000;
322 
323     /**
324      * When set for an external connection, indicates that this {@code Connection} can be pulled
325      * from a remote device to the current device.
326      * <p>
327      * Should only be set on a {@code Connection} where {@link #PROPERTY_IS_EXTERNAL_CALL}
328      * is set.
329      */
330     public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000;
331 
332     /** Call supports the deflect feature. */
333     public static final int CAPABILITY_SUPPORT_DEFLECT = 0x02000000;
334 
335     //**********************************************************************************************
336     // Next CAPABILITY value: 0x04000000
337     //**********************************************************************************************
338 
339     /**
340      * Indicates that the current device callback number should be shown.
341      *
342      * @hide
343      */
344     public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1<<0;
345 
346     /**
347      * Whether the call is a generic conference, where we do not know the precise state of
348      * participants in the conference (eg. on CDMA).
349      *
350      * @hide
351      */
352     public static final int PROPERTY_GENERIC_CONFERENCE = 1<<1;
353 
354     /**
355      * Connection is using high definition audio.
356      * @hide
357      */
358     public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2;
359 
360     /**
361      * Connection is using WIFI.
362      * @hide
363      */
364     public static final int PROPERTY_WIFI = 1<<3;
365 
366     /**
367      * When set, indicates that the {@code Connection} does not actually exist locally for the
368      * {@link ConnectionService}.
369      * <p>
370      * Consider, for example, a scenario where a user has two devices with the same phone number.
371      * When a user places a call on one devices, the telephony stack can represent that call on the
372      * other device by adding is to the {@link ConnectionService} with the
373      * {@link #PROPERTY_IS_EXTERNAL_CALL} capability set.
374      * <p>
375      * An {@link ConnectionService} should not assume that all {@link InCallService}s will handle
376      * external connections.  Only those {@link InCallService}s which have the
377      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
378      * manifest will see external connections.
379      */
380     public static final int PROPERTY_IS_EXTERNAL_CALL = 1<<4;
381 
382     /**
383      * Indicates that the connection has CDMA Enhanced Voice Privacy enabled.
384      */
385     public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 1<<5;
386 
387     /**
388      * Indicates that the connection represents a downgraded IMS conference.
389      * @hide
390      */
391     public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 1<<6;
392 
393     /**
394      * Set by the framework to indicate that the {@link Connection} originated from a self-managed
395      * {@link ConnectionService}.
396      * <p>
397      * See {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.
398      */
399     public static final int PROPERTY_SELF_MANAGED = 1<<7;
400 
401     /**
402      * Set by the framework to indicate that a connection has an active RTT session associated with
403      * it.
404      */
405     public static final int PROPERTY_IS_RTT = 1 << 8;
406 
407     /**
408      * Set by the framework to indicate that a connection is using assisted dialing.
409      * @hide
410      */
411     public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9;
412 
413     //**********************************************************************************************
414     // Next PROPERTY value: 1<<10
415     //**********************************************************************************************
416 
417     /**
418      * Connection extra key used to store the last forwarded number associated with the current
419      * connection.  Used to communicate to the user interface that the connection was forwarded via
420      * the specified number.
421      */
422     public static final String EXTRA_LAST_FORWARDED_NUMBER =
423             "android.telecom.extra.LAST_FORWARDED_NUMBER";
424 
425     /**
426      * Connection extra key used to store a child number associated with the current connection.
427      * Used to communicate to the user interface that the connection was received via
428      * a child address (i.e. phone number) associated with the {@link PhoneAccount}'s primary
429      * address.
430      */
431     public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
432 
433     /**
434      * Connection extra key used to store the subject for an incoming call.  The user interface can
435      * query this extra and display its contents for incoming calls.  Will only be used if the
436      * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}.
437      */
438     public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
439 
440     /**
441      * Boolean connection extra key set on a {@link Connection} in
442      * {@link Connection#STATE_RINGING} state to indicate that answering the call will cause the
443      * current active foreground call to be dropped.
444      */
445     public static final String EXTRA_ANSWERING_DROPS_FG_CALL =
446             "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
447 
448     /**
449      * String connection extra key set on a {@link Connection} in {@link Connection#STATE_RINGING}
450      * state to indicate the name of the third-party app which is responsible for the current
451      * foreground call.
452      * <p>
453      * Used when {@link #EXTRA_ANSWERING_DROPS_FG_CALL} is true to ensure that the default Phone app
454      * is able to inform the user that answering the new incoming call will cause a call owned by
455      * another app to be dropped when the incoming call is answered.
456      */
457     public static final String EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME =
458             "android.telecom.extra.ANSWERING_DROPS_FG_CALL_APP_NAME";
459 
460     /**
461      * Boolean connection extra key on a {@link Connection} which indicates that adding an
462      * additional call is disallowed.
463      * @hide
464      */
465     public static final String EXTRA_DISABLE_ADD_CALL =
466             "android.telecom.extra.DISABLE_ADD_CALL";
467 
468     /**
469      * String connection extra key on a {@link Connection} or {@link Conference} which contains the
470      * original Connection ID associated with the connection.  Used in
471      * {@link RemoteConnectionService} to track the Connection ID which was originally assigned to a
472      * connection/conference added via
473      * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)} and
474      * {@link ConnectionService#addConference(Conference)} APIs.  This is important to pass to
475      * Telecom for when it deals with RemoteConnections.  When the ConnectionManager wraps the
476      * {@link RemoteConnection} and {@link RemoteConference} and adds it to Telecom, there needs to
477      * be a way to ensure that we don't add the connection again as a duplicate.
478      * <p>
479      * For example, the TelephonyCS calls addExistingConnection for a Connection with ID
480      * {@code TelephonyCS@1}.  The ConnectionManager learns of this via
481      * {@link ConnectionService#onRemoteExistingConnectionAdded(RemoteConnection)}, and wraps this
482      * in a new {@link Connection} which it adds to Telecom via
483      * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)}.  As part of
484      * this process, the wrapped RemoteConnection gets assigned a new ID (e.g. {@code ConnMan@1}).
485      * The TelephonyCS will ALSO try to add the existing connection to Telecom, except with the
486      * ID it originally referred to the connection as.  Thus Telecom needs to know that the
487      * Connection with ID {@code ConnMan@1} is really the same as {@code TelephonyCS@1}.
488      * @hide
489      */
490     public static final String EXTRA_ORIGINAL_CONNECTION_ID =
491             "android.telecom.extra.ORIGINAL_CONNECTION_ID";
492 
493     /**
494      * Connection event used to inform Telecom that it should play the on hold tone.  This is used
495      * to play a tone when the peer puts the current call on hold.  Sent to Telecom via
496      * {@link #sendConnectionEvent(String, Bundle)}.
497      * @hide
498      */
499     public static final String EVENT_ON_HOLD_TONE_START =
500             "android.telecom.event.ON_HOLD_TONE_START";
501 
502     /**
503      * Connection event used to inform Telecom that it should stop the on hold tone.  This is used
504      * to stop a tone when the peer puts the current call on hold.  Sent to Telecom via
505      * {@link #sendConnectionEvent(String, Bundle)}.
506      * @hide
507      */
508     public static final String EVENT_ON_HOLD_TONE_END =
509             "android.telecom.event.ON_HOLD_TONE_END";
510 
511     /**
512      * Connection event used to inform {@link InCallService}s when pulling of an external call has
513      * failed.  The user interface should inform the user of the error.
514      * <p>
515      * Expected to be used by the {@link ConnectionService} when the {@link Call#pullExternalCall()}
516      * API is called on a {@link Call} with the properties
517      * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} and
518      * {@link Call.Details#CAPABILITY_CAN_PULL_CALL}, but the {@link ConnectionService} could not
519      * pull the external call due to an error condition.
520      * <p>
521      * Sent via {@link #sendConnectionEvent(String, Bundle)}.  The {@link Bundle} parameter is
522      * expected to be null when this connection event is used.
523      */
524     public static final String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
525 
526     /**
527      * Connection event used to inform {@link InCallService}s when the merging of two calls has
528      * failed. The User Interface should use this message to inform the user of the error.
529      * <p>
530      * Sent via {@link #sendConnectionEvent(String, Bundle)}.  The {@link Bundle} parameter is
531      * expected to be null when this connection event is used.
532      */
533     public static final String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
534 
535     /**
536      * Connection event used to inform {@link InCallService}s when the process of merging a
537      * Connection into a conference has begun.
538      * <p>
539      * Sent via {@link #sendConnectionEvent(String, Bundle)}.  The {@link Bundle} parameter is
540      * expected to be null when this connection event is used.
541      * @hide
542      */
543     public static final String EVENT_MERGE_START = "android.telecom.event.MERGE_START";
544 
545     /**
546      * Connection event used to inform {@link InCallService}s when the process of merging a
547      * Connection into a conference has completed.
548      * <p>
549      * Sent via {@link #sendConnectionEvent(String, Bundle)}.  The {@link Bundle} parameter is
550      * expected to be null when this connection event is used.
551      * @hide
552      */
553     public static final String EVENT_MERGE_COMPLETE = "android.telecom.event.MERGE_COMPLETE";
554 
555     /**
556      * Connection event used to inform {@link InCallService}s when a call has been put on hold by
557      * the remote party.
558      * <p>
559      * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the
560      * call is being held locally on the device.  When a capable {@link ConnectionService} receives
561      * signalling to indicate that the remote party has put the call on hold, it can send this
562      * connection event.
563      * @hide
564      */
565     public static final String EVENT_CALL_REMOTELY_HELD =
566             "android.telecom.event.CALL_REMOTELY_HELD";
567 
568     /**
569      * Connection event used to inform {@link InCallService}s when a call which was remotely held
570      * (see {@link #EVENT_CALL_REMOTELY_HELD}) has been un-held by the remote party.
571      * <p>
572      * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the
573      * call is being held locally on the device.  When a capable {@link ConnectionService} receives
574      * signalling to indicate that the remote party has taken the call off hold, it can send this
575      * connection event.
576      * @hide
577      */
578     public static final String EVENT_CALL_REMOTELY_UNHELD =
579             "android.telecom.event.CALL_REMOTELY_UNHELD";
580 
581     /**
582      * Connection event used to inform an {@link InCallService} which initiated a call handover via
583      * {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has
584      * successfully completed.
585      * @hide
586      */
587     public static final String EVENT_HANDOVER_COMPLETE =
588             "android.telecom.event.HANDOVER_COMPLETE";
589 
590     /**
591      * Connection event used to inform an {@link InCallService} which initiated a call handover via
592      * {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has failed
593      * to complete.
594      * @hide
595      */
596     public static final String EVENT_HANDOVER_FAILED =
597             "android.telecom.event.HANDOVER_FAILED";
598 
599     // Flag controlling whether PII is emitted into the logs
600     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
601 
602     /**
603      * Whether the given capabilities support the specified capability.
604      *
605      * @param capabilities A capability bit field.
606      * @param capability The capability to check capabilities for.
607      * @return Whether the specified capability is supported.
608      * @hide
609      */
can(int capabilities, int capability)610     public static boolean can(int capabilities, int capability) {
611         return (capabilities & capability) == capability;
612     }
613 
614     /**
615      * Whether the capabilities of this {@code Connection} supports the specified capability.
616      *
617      * @param capability The capability to check capabilities for.
618      * @return Whether the specified capability is supported.
619      * @hide
620      */
can(int capability)621     public boolean can(int capability) {
622         return can(mConnectionCapabilities, capability);
623     }
624 
625     /**
626      * Removes the specified capability from the set of capabilities of this {@code Connection}.
627      *
628      * @param capability The capability to remove from the set.
629      * @hide
630      */
removeCapability(int capability)631     public void removeCapability(int capability) {
632         mConnectionCapabilities &= ~capability;
633     }
634 
635     /**
636      * Adds the specified capability to the set of capabilities of this {@code Connection}.
637      *
638      * @param capability The capability to add to the set.
639      * @hide
640      */
addCapability(int capability)641     public void addCapability(int capability) {
642         mConnectionCapabilities |= capability;
643     }
644 
645     /**
646      * Renders a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
647      *
648      * @param capabilities A capability bit field.
649      * @return A human readable string representation.
650      */
capabilitiesToString(int capabilities)651     public static String capabilitiesToString(int capabilities) {
652         return capabilitiesToStringInternal(capabilities, true /* isLong */);
653     }
654 
655     /**
656      * Renders a set of capability bits ({@code CAPABILITY_*}) as a *short* human readable
657      * string.
658      *
659      * @param capabilities A capability bit field.
660      * @return A human readable string representation.
661      * @hide
662      */
capabilitiesToStringShort(int capabilities)663     public static String capabilitiesToStringShort(int capabilities) {
664         return capabilitiesToStringInternal(capabilities, false /* isLong */);
665     }
666 
capabilitiesToStringInternal(int capabilities, boolean isLong)667     private static String capabilitiesToStringInternal(int capabilities, boolean isLong) {
668         StringBuilder builder = new StringBuilder();
669         builder.append("[");
670         if (isLong) {
671             builder.append("Capabilities:");
672         }
673 
674         if (can(capabilities, CAPABILITY_HOLD)) {
675             builder.append(isLong ? " CAPABILITY_HOLD" : " hld");
676         }
677         if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
678             builder.append(isLong ? " CAPABILITY_SUPPORT_HOLD" : " sup_hld");
679         }
680         if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
681             builder.append(isLong ? " CAPABILITY_MERGE_CONFERENCE" : " mrg_cnf");
682         }
683         if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
684             builder.append(isLong ? " CAPABILITY_SWAP_CONFERENCE" : " swp_cnf");
685         }
686         if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
687             builder.append(isLong ? " CAPABILITY_RESPOND_VIA_TEXT" : " txt");
688         }
689         if (can(capabilities, CAPABILITY_MUTE)) {
690             builder.append(isLong ? " CAPABILITY_MUTE" : " mut");
691         }
692         if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
693             builder.append(isLong ? " CAPABILITY_MANAGE_CONFERENCE" : " mng_cnf");
694         }
695         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
696             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_RX" : " VTlrx");
697         }
698         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
699             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_TX" : " VTltx");
700         }
701         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
702             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL" : " VTlbi");
703         }
704         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
705             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_RX" : " VTrrx");
706         }
707         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
708             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_TX" : " VTrtx");
709         }
710         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
711             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL" : " VTrbi");
712         }
713         if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
714             builder.append(isLong ? " CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO" : " !v2a");
715         }
716         if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
717             builder.append(isLong ? " CAPABILITY_SPEED_UP_MT_AUDIO" : " spd_aud");
718         }
719         if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
720             builder.append(isLong ? " CAPABILITY_CAN_UPGRADE_TO_VIDEO" : " a2v");
721         }
722         if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
723             builder.append(isLong ? " CAPABILITY_CAN_PAUSE_VIDEO" : " paus_VT");
724         }
725         if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
726             builder.append(isLong ? " CAPABILITY_SINGLE_PARTY_CONFERENCE" : " 1p_cnf");
727         }
728         if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
729             builder.append(isLong ? " CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION" : " rsp_by_con");
730         }
731         if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
732             builder.append(isLong ? " CAPABILITY_CAN_PULL_CALL" : " pull");
733         }
734         if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) {
735             builder.append(isLong ? " CAPABILITY_SUPPORT_DEFLECT" : " sup_def");
736         }
737 
738         builder.append("]");
739         return builder.toString();
740     }
741 
742     /**
743      * Renders a set of property bits ({@code PROPERTY_*}) as a human readable string.
744      *
745      * @param properties A property bit field.
746      * @return A human readable string representation.
747      */
propertiesToString(int properties)748     public static String propertiesToString(int properties) {
749         return propertiesToStringInternal(properties, true /* isLong */);
750     }
751 
752     /**
753      * Renders a set of property bits ({@code PROPERTY_*}) as a *short* human readable string.
754      *
755      * @param properties A property bit field.
756      * @return A human readable string representation.
757      * @hide
758      */
propertiesToStringShort(int properties)759     public static String propertiesToStringShort(int properties) {
760         return propertiesToStringInternal(properties, false /* isLong */);
761     }
762 
propertiesToStringInternal(int properties, boolean isLong)763     private static String propertiesToStringInternal(int properties, boolean isLong) {
764         StringBuilder builder = new StringBuilder();
765         builder.append("[");
766         if (isLong) {
767             builder.append("Properties:");
768         }
769 
770         if (can(properties, PROPERTY_SELF_MANAGED)) {
771             builder.append(isLong ? " PROPERTY_SELF_MANAGED" : " self_mng");
772         }
773 
774         if (can(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
775             builder.append(isLong ? " PROPERTY_EMERGENCY_CALLBACK_MODE" : " ecbm");
776         }
777 
778         if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) {
779             builder.append(isLong ? " PROPERTY_HIGH_DEF_AUDIO" : " HD");
780         }
781 
782         if (can(properties, PROPERTY_WIFI)) {
783             builder.append(isLong ? " PROPERTY_WIFI" : " wifi");
784         }
785 
786         if (can(properties, PROPERTY_GENERIC_CONFERENCE)) {
787             builder.append(isLong ? " PROPERTY_GENERIC_CONFERENCE" : " gen_conf");
788         }
789 
790         if (can(properties, PROPERTY_IS_EXTERNAL_CALL)) {
791             builder.append(isLong ? " PROPERTY_IS_EXTERNAL_CALL" : " xtrnl");
792         }
793 
794         if (can(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
795             builder.append(isLong ? " PROPERTY_HAS_CDMA_VOICE_PRIVACY" : " priv");
796         }
797 
798         if (can(properties, PROPERTY_IS_RTT)) {
799             builder.append(isLong ? " PROPERTY_IS_RTT" : " rtt");
800         }
801 
802         builder.append("]");
803         return builder.toString();
804     }
805 
806     /** @hide */
807     public abstract static class Listener {
onStateChanged(Connection c, int state)808         public void onStateChanged(Connection c, int state) {}
onAddressChanged(Connection c, Uri newAddress, int presentation)809         public void onAddressChanged(Connection c, Uri newAddress, int presentation) {}
onCallerDisplayNameChanged( Connection c, String callerDisplayName, int presentation)810         public void onCallerDisplayNameChanged(
811                 Connection c, String callerDisplayName, int presentation) {}
onVideoStateChanged(Connection c, int videoState)812         public void onVideoStateChanged(Connection c, int videoState) {}
onDisconnected(Connection c, DisconnectCause disconnectCause)813         public void onDisconnected(Connection c, DisconnectCause disconnectCause) {}
onPostDialWait(Connection c, String remaining)814         public void onPostDialWait(Connection c, String remaining) {}
onPostDialChar(Connection c, char nextChar)815         public void onPostDialChar(Connection c, char nextChar) {}
onRingbackRequested(Connection c, boolean ringback)816         public void onRingbackRequested(Connection c, boolean ringback) {}
onDestroyed(Connection c)817         public void onDestroyed(Connection c) {}
onConnectionCapabilitiesChanged(Connection c, int capabilities)818         public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {}
onConnectionPropertiesChanged(Connection c, int properties)819         public void onConnectionPropertiesChanged(Connection c, int properties) {}
onSupportedAudioRoutesChanged(Connection c, int supportedAudioRoutes)820         public void onSupportedAudioRoutesChanged(Connection c, int supportedAudioRoutes) {}
onVideoProviderChanged( Connection c, VideoProvider videoProvider)821         public void onVideoProviderChanged(
822                 Connection c, VideoProvider videoProvider) {}
onAudioModeIsVoipChanged(Connection c, boolean isVoip)823         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
onStatusHintsChanged(Connection c, StatusHints statusHints)824         public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
onConferenceablesChanged( Connection c, List<Conferenceable> conferenceables)825         public void onConferenceablesChanged(
826                 Connection c, List<Conferenceable> conferenceables) {}
onConferenceChanged(Connection c, Conference conference)827         public void onConferenceChanged(Connection c, Conference conference) {}
828         /** @hide */
onConferenceParticipantsChanged(Connection c, List<ConferenceParticipant> participants)829         public void onConferenceParticipantsChanged(Connection c,
830                 List<ConferenceParticipant> participants) {}
onConferenceStarted()831         public void onConferenceStarted() {}
onConferenceMergeFailed(Connection c)832         public void onConferenceMergeFailed(Connection c) {}
onExtrasChanged(Connection c, Bundle extras)833         public void onExtrasChanged(Connection c, Bundle extras) {}
onExtrasRemoved(Connection c, List<String> keys)834         public void onExtrasRemoved(Connection c, List<String> keys) {}
onConnectionEvent(Connection c, String event, Bundle extras)835         public void onConnectionEvent(Connection c, String event, Bundle extras) {}
836         /** @hide */
onConferenceSupportedChanged(Connection c, boolean isConferenceSupported)837         public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {}
onAudioRouteChanged(Connection c, int audioRoute, String bluetoothAddress)838         public void onAudioRouteChanged(Connection c, int audioRoute, String bluetoothAddress) {}
onRttInitiationSuccess(Connection c)839         public void onRttInitiationSuccess(Connection c) {}
onRttInitiationFailure(Connection c, int reason)840         public void onRttInitiationFailure(Connection c, int reason) {}
onRttSessionRemotelyTerminated(Connection c)841         public void onRttSessionRemotelyTerminated(Connection c) {}
onRemoteRttRequest(Connection c)842         public void onRemoteRttRequest(Connection c) {}
843         /** @hide */
onPhoneAccountChanged(Connection c, PhoneAccountHandle pHandle)844         public void onPhoneAccountChanged(Connection c, PhoneAccountHandle pHandle) {}
845     }
846 
847     /**
848      * Provides methods to read and write RTT data to/from the in-call app.
849      */
850     public static final class RttTextStream {
851         private static final int READ_BUFFER_SIZE = 1000;
852         private final InputStreamReader mPipeFromInCall;
853         private final OutputStreamWriter mPipeToInCall;
854         private final ParcelFileDescriptor mFdFromInCall;
855         private final ParcelFileDescriptor mFdToInCall;
856         private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
857 
858         /**
859          * @hide
860          */
RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall)861         public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) {
862             mFdFromInCall = fromInCall;
863             mFdToInCall = toInCall;
864             mPipeFromInCall = new InputStreamReader(
865                     new FileInputStream(fromInCall.getFileDescriptor()));
866             mPipeToInCall = new OutputStreamWriter(
867                     new FileOutputStream(toInCall.getFileDescriptor()));
868         }
869 
870         /**
871          * Writes the string {@param input} into the text stream to the UI for this RTT call. Since
872          * RTT transmits text in real-time, this method should be called as often as text snippets
873          * are received from the remote user, even if it is only one character.
874          * <p>
875          * This method is not thread-safe -- calling it from multiple threads simultaneously may
876          * lead to interleaved text.
877          *
878          * @param input The message to send to the in-call app.
879          */
write(String input)880         public void write(String input) throws IOException {
881             mPipeToInCall.write(input);
882             mPipeToInCall.flush();
883         }
884 
885 
886         /**
887          * Reads a string from the in-call app, blocking if there is no data available. Returns
888          * {@code null} if the RTT conversation has been terminated and there is no further data
889          * to read.
890          * <p>
891          * This method is not thread-safe -- calling it from multiple threads simultaneously may
892          * lead to interleaved text.
893          *
894          * @return A string containing text entered by the user, or {@code null} if the
895          * conversation has been terminated or if there was an error while reading.
896          */
read()897         public String read() throws IOException {
898             int numRead = mPipeFromInCall.read(mReadBuffer, 0, READ_BUFFER_SIZE);
899             if (numRead < 0) {
900                 return null;
901             }
902             return new String(mReadBuffer, 0, numRead);
903         }
904 
905         /**
906          * Non-blocking version of {@link #read()}. Returns {@code null} if there is nothing to
907          * be read.
908          *
909          * @return A string containing text entered by the user, or {@code null} if the user has
910          * not entered any new text yet.
911          */
readImmediately()912         public String readImmediately() throws IOException {
913             if (mPipeFromInCall.ready()) {
914                 return read();
915             } else {
916                 return null;
917             }
918         }
919 
920         /** @hide */
getFdFromInCall()921         public ParcelFileDescriptor getFdFromInCall() {
922             return mFdFromInCall;
923         }
924 
925         /** @hide */
getFdToInCall()926         public ParcelFileDescriptor getFdToInCall() {
927             return mFdToInCall;
928         }
929     }
930 
931     /**
932      * Provides constants to represent the results of responses to session modify requests sent via
933      * {@link Call#sendRttRequest()}
934      */
935     public static final class RttModifyStatus {
RttModifyStatus()936         private RttModifyStatus() {}
937         /**
938          * Session modify request was successful.
939          */
940         public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1;
941 
942         /**
943          * Session modify request failed.
944          */
945         public static final int SESSION_MODIFY_REQUEST_FAIL = 2;
946 
947         /**
948          * Session modify request ignored due to invalid parameters.
949          */
950         public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
951 
952         /**
953          * Session modify request timed out.
954          */
955         public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4;
956 
957         /**
958          * Session modify request rejected by remote user.
959          */
960         public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5;
961     }
962 
963     /**
964      * Provides a means of controlling the video session associated with a {@link Connection}.
965      * <p>
966      * Implementations create a custom subclass of {@link VideoProvider} and the
967      * {@link ConnectionService} creates an instance sets it on the {@link Connection} using
968      * {@link Connection#setVideoProvider(VideoProvider)}.  Any connection which supports video
969      * should set the {@link VideoProvider}.
970      * <p>
971      * The {@link VideoProvider} serves two primary purposes: it provides a means for Telecom and
972      * {@link InCallService} implementations to issue requests related to the video session;
973      * it provides a means for the {@link ConnectionService} to report events and information
974      * related to the video session to Telecom and the {@link InCallService} implementations.
975      * <p>
976      * {@link InCallService} implementations interact with the {@link VideoProvider} via
977      * {@link android.telecom.InCallService.VideoCall}.
978      */
979     public static abstract class VideoProvider {
980         /**
981          * Video is not being received (no protocol pause was issued).
982          * @see #handleCallSessionEvent(int)
983          */
984         public static final int SESSION_EVENT_RX_PAUSE = 1;
985 
986         /**
987          * Video reception has resumed after a {@link #SESSION_EVENT_RX_PAUSE}.
988          * @see #handleCallSessionEvent(int)
989          */
990         public static final int SESSION_EVENT_RX_RESUME = 2;
991 
992         /**
993          * Video transmission has begun. This occurs after a negotiated start of video transmission
994          * when the underlying protocol has actually begun transmitting video to the remote party.
995          * @see #handleCallSessionEvent(int)
996          */
997         public static final int SESSION_EVENT_TX_START = 3;
998 
999         /**
1000          * Video transmission has stopped. This occurs after a negotiated stop of video transmission
1001          * when the underlying protocol has actually stopped transmitting video to the remote party.
1002          * @see #handleCallSessionEvent(int)
1003          */
1004         public static final int SESSION_EVENT_TX_STOP = 4;
1005 
1006         /**
1007          * A camera failure has occurred for the selected camera.  The {@link VideoProvider} can use
1008          * this as a cue to inform the user the camera is not available.
1009          * @see #handleCallSessionEvent(int)
1010          */
1011         public static final int SESSION_EVENT_CAMERA_FAILURE = 5;
1012 
1013         /**
1014          * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready
1015          * for operation.  The {@link VideoProvider} can use this as a cue to inform the user that
1016          * the camera has become available again.
1017          * @see #handleCallSessionEvent(int)
1018          */
1019         public static final int SESSION_EVENT_CAMERA_READY = 6;
1020 
1021         /**
1022          * Session event raised by Telecom when
1023          * {@link android.telecom.InCallService.VideoCall#setCamera(String)} is called and the
1024          * caller does not have the necessary {@link android.Manifest.permission#CAMERA} permission.
1025          * @see #handleCallSessionEvent(int)
1026          */
1027         public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7;
1028 
1029         /**
1030          * Session modify request was successful.
1031          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
1032          */
1033         public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1;
1034 
1035         /**
1036          * Session modify request failed.
1037          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
1038          */
1039         public static final int SESSION_MODIFY_REQUEST_FAIL = 2;
1040 
1041         /**
1042          * Session modify request ignored due to invalid parameters.
1043          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
1044          */
1045         public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
1046 
1047         /**
1048          * Session modify request timed out.
1049          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
1050          */
1051         public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4;
1052 
1053         /**
1054          * Session modify request rejected by remote user.
1055          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
1056          */
1057         public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5;
1058 
1059         private static final int MSG_ADD_VIDEO_CALLBACK = 1;
1060         private static final int MSG_SET_CAMERA = 2;
1061         private static final int MSG_SET_PREVIEW_SURFACE = 3;
1062         private static final int MSG_SET_DISPLAY_SURFACE = 4;
1063         private static final int MSG_SET_DEVICE_ORIENTATION = 5;
1064         private static final int MSG_SET_ZOOM = 6;
1065         private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
1066         private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
1067         private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
1068         private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10;
1069         private static final int MSG_SET_PAUSE_IMAGE = 11;
1070         private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
1071 
1072         private static final String SESSION_EVENT_RX_PAUSE_STR = "RX_PAUSE";
1073         private static final String SESSION_EVENT_RX_RESUME_STR = "RX_RESUME";
1074         private static final String SESSION_EVENT_TX_START_STR = "TX_START";
1075         private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
1076         private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
1077         private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
1078         private static final String SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR =
1079                 "CAMERA_PERMISSION_ERROR";
1080         private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
1081 
1082         private VideoProvider.VideoProviderHandler mMessageHandler;
1083         private final VideoProvider.VideoProviderBinder mBinder;
1084 
1085         /**
1086          * Stores a list of the video callbacks, keyed by IBinder.
1087          *
1088          * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
1089          * load factor before resizing, 1 means we only expect a single thread to
1090          * access the map so make only a single shard
1091          */
1092         private ConcurrentHashMap<IBinder, IVideoCallback> mVideoCallbacks =
1093                 new ConcurrentHashMap<IBinder, IVideoCallback>(8, 0.9f, 1);
1094 
1095         /**
1096          * Default handler used to consolidate binder method calls onto a single thread.
1097          */
1098         private final class VideoProviderHandler extends Handler {
VideoProviderHandler()1099             public VideoProviderHandler() {
1100                 super();
1101             }
1102 
VideoProviderHandler(Looper looper)1103             public VideoProviderHandler(Looper looper) {
1104                 super(looper);
1105             }
1106 
1107             @Override
handleMessage(Message msg)1108             public void handleMessage(Message msg) {
1109                 switch (msg.what) {
1110                     case MSG_ADD_VIDEO_CALLBACK: {
1111                         IBinder binder = (IBinder) msg.obj;
1112                         IVideoCallback callback = IVideoCallback.Stub
1113                                 .asInterface((IBinder) msg.obj);
1114                         if (callback == null) {
1115                             Log.w(this, "addVideoProvider - skipped; callback is null.");
1116                             break;
1117                         }
1118 
1119                         if (mVideoCallbacks.containsKey(binder)) {
1120                             Log.i(this, "addVideoProvider - skipped; already present.");
1121                             break;
1122                         }
1123                         mVideoCallbacks.put(binder, callback);
1124                         break;
1125                     }
1126                     case MSG_REMOVE_VIDEO_CALLBACK: {
1127                         IBinder binder = (IBinder) msg.obj;
1128                         IVideoCallback callback = IVideoCallback.Stub
1129                                 .asInterface((IBinder) msg.obj);
1130                         if (!mVideoCallbacks.containsKey(binder)) {
1131                             Log.i(this, "removeVideoProvider - skipped; not present.");
1132                             break;
1133                         }
1134                         mVideoCallbacks.remove(binder);
1135                         break;
1136                     }
1137                     case MSG_SET_CAMERA:
1138                     {
1139                         SomeArgs args = (SomeArgs) msg.obj;
1140                         try {
1141                             onSetCamera((String) args.arg1);
1142                             onSetCamera((String) args.arg1, (String) args.arg2, args.argi1,
1143                                     args.argi2, args.argi3);
1144                         } finally {
1145                             args.recycle();
1146                         }
1147                     }
1148                     break;
1149                     case MSG_SET_PREVIEW_SURFACE:
1150                         onSetPreviewSurface((Surface) msg.obj);
1151                         break;
1152                     case MSG_SET_DISPLAY_SURFACE:
1153                         onSetDisplaySurface((Surface) msg.obj);
1154                         break;
1155                     case MSG_SET_DEVICE_ORIENTATION:
1156                         onSetDeviceOrientation(msg.arg1);
1157                         break;
1158                     case MSG_SET_ZOOM:
1159                         onSetZoom((Float) msg.obj);
1160                         break;
1161                     case MSG_SEND_SESSION_MODIFY_REQUEST: {
1162                         SomeArgs args = (SomeArgs) msg.obj;
1163                         try {
1164                             onSendSessionModifyRequest((VideoProfile) args.arg1,
1165                                     (VideoProfile) args.arg2);
1166                         } finally {
1167                             args.recycle();
1168                         }
1169                         break;
1170                     }
1171                     case MSG_SEND_SESSION_MODIFY_RESPONSE:
1172                         onSendSessionModifyResponse((VideoProfile) msg.obj);
1173                         break;
1174                     case MSG_REQUEST_CAMERA_CAPABILITIES:
1175                         onRequestCameraCapabilities();
1176                         break;
1177                     case MSG_REQUEST_CONNECTION_DATA_USAGE:
1178                         onRequestConnectionDataUsage();
1179                         break;
1180                     case MSG_SET_PAUSE_IMAGE:
1181                         onSetPauseImage((Uri) msg.obj);
1182                         break;
1183                     default:
1184                         break;
1185                 }
1186             }
1187         }
1188 
1189         /**
1190          * IVideoProvider stub implementation.
1191          */
1192         private final class VideoProviderBinder extends IVideoProvider.Stub {
addVideoCallback(IBinder videoCallbackBinder)1193             public void addVideoCallback(IBinder videoCallbackBinder) {
1194                 mMessageHandler.obtainMessage(
1195                         MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
1196             }
1197 
removeVideoCallback(IBinder videoCallbackBinder)1198             public void removeVideoCallback(IBinder videoCallbackBinder) {
1199                 mMessageHandler.obtainMessage(
1200                         MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
1201             }
1202 
setCamera(String cameraId, String callingPackageName, int targetSdkVersion)1203             public void setCamera(String cameraId, String callingPackageName,
1204                                   int targetSdkVersion) {
1205 
1206                 SomeArgs args = SomeArgs.obtain();
1207                 args.arg1 = cameraId;
1208                 // Propagate the calling package; originally determined in
1209                 // android.telecom.InCallService.VideoCall#setCamera(String) from the calling
1210                 // process.
1211                 args.arg2 = callingPackageName;
1212                 // Pass along the uid and pid of the calling app; this gets lost when we put the
1213                 // message onto the handler.  These are required for Telecom to perform a permission
1214                 // check to see if the calling app is able to use the camera.
1215                 args.argi1 = Binder.getCallingUid();
1216                 args.argi2 = Binder.getCallingPid();
1217                 // Pass along the target SDK version of the calling InCallService.  This is used to
1218                 // maintain backwards compatibility of the API for older callers.
1219                 args.argi3 = targetSdkVersion;
1220                 mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
1221             }
1222 
setPreviewSurface(Surface surface)1223             public void setPreviewSurface(Surface surface) {
1224                 mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
1225             }
1226 
setDisplaySurface(Surface surface)1227             public void setDisplaySurface(Surface surface) {
1228                 mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
1229             }
1230 
setDeviceOrientation(int rotation)1231             public void setDeviceOrientation(int rotation) {
1232                 mMessageHandler.obtainMessage(
1233                         MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget();
1234             }
1235 
setZoom(float value)1236             public void setZoom(float value) {
1237                 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
1238             }
1239 
sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)1240             public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
1241                 SomeArgs args = SomeArgs.obtain();
1242                 args.arg1 = fromProfile;
1243                 args.arg2 = toProfile;
1244                 mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
1245             }
1246 
sendSessionModifyResponse(VideoProfile responseProfile)1247             public void sendSessionModifyResponse(VideoProfile responseProfile) {
1248                 mMessageHandler.obtainMessage(
1249                         MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
1250             }
1251 
requestCameraCapabilities()1252             public void requestCameraCapabilities() {
1253                 mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
1254             }
1255 
requestCallDataUsage()1256             public void requestCallDataUsage() {
1257                 mMessageHandler.obtainMessage(MSG_REQUEST_CONNECTION_DATA_USAGE).sendToTarget();
1258             }
1259 
setPauseImage(Uri uri)1260             public void setPauseImage(Uri uri) {
1261                 mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
1262             }
1263         }
1264 
VideoProvider()1265         public VideoProvider() {
1266             mBinder = new VideoProvider.VideoProviderBinder();
1267             mMessageHandler = new VideoProvider.VideoProviderHandler(Looper.getMainLooper());
1268         }
1269 
1270         /**
1271          * Creates an instance of the {@link VideoProvider}, specifying the looper to use.
1272          *
1273          * @param looper The looper.
1274          * @hide
1275          */
VideoProvider(Looper looper)1276         public VideoProvider(Looper looper) {
1277             mBinder = new VideoProvider.VideoProviderBinder();
1278             mMessageHandler = new VideoProvider.VideoProviderHandler(looper);
1279         }
1280 
1281         /**
1282          * Returns binder object which can be used across IPC methods.
1283          * @hide
1284          */
getInterface()1285         public final IVideoProvider getInterface() {
1286             return mBinder;
1287         }
1288 
1289         /**
1290          * Sets the camera to be used for the outgoing video.
1291          * <p>
1292          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
1293          * camera via
1294          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
1295          * <p>
1296          * Sent from the {@link InCallService} via
1297          * {@link InCallService.VideoCall#setCamera(String)}.
1298          *
1299          * @param cameraId The id of the camera (use ids as reported by
1300          * {@link CameraManager#getCameraIdList()}).
1301          */
onSetCamera(String cameraId)1302         public abstract void onSetCamera(String cameraId);
1303 
1304         /**
1305          * Sets the camera to be used for the outgoing video.
1306          * <p>
1307          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
1308          * camera via
1309          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
1310          * <p>
1311          * This prototype is used internally to ensure that the calling package name, UID and PID
1312          * are sent to Telecom so that can perform a camera permission check on the caller.
1313          * <p>
1314          * Sent from the {@link InCallService} via
1315          * {@link InCallService.VideoCall#setCamera(String)}.
1316          *
1317          * @param cameraId The id of the camera (use ids as reported by
1318          * {@link CameraManager#getCameraIdList()}).
1319          * @param callingPackageName The AppOpps package name of the caller.
1320          * @param callingUid The UID of the caller.
1321          * @param callingPid The PID of the caller.
1322          * @param targetSdkVersion The target SDK version of the caller.
1323          * @hide
1324          */
onSetCamera(String cameraId, String callingPackageName, int callingUid, int callingPid, int targetSdkVersion)1325         public void onSetCamera(String cameraId, String callingPackageName, int callingUid,
1326                 int callingPid, int targetSdkVersion) {}
1327 
1328         /**
1329          * Sets the surface to be used for displaying a preview of what the user's camera is
1330          * currently capturing.  When video transmission is enabled, this is the video signal which
1331          * is sent to the remote device.
1332          * <p>
1333          * Sent from the {@link InCallService} via
1334          * {@link InCallService.VideoCall#setPreviewSurface(Surface)}.
1335          *
1336          * @param surface The {@link Surface}.
1337          */
onSetPreviewSurface(Surface surface)1338         public abstract void onSetPreviewSurface(Surface surface);
1339 
1340         /**
1341          * Sets the surface to be used for displaying the video received from the remote device.
1342          * <p>
1343          * Sent from the {@link InCallService} via
1344          * {@link InCallService.VideoCall#setDisplaySurface(Surface)}.
1345          *
1346          * @param surface The {@link Surface}.
1347          */
onSetDisplaySurface(Surface surface)1348         public abstract void onSetDisplaySurface(Surface surface);
1349 
1350         /**
1351          * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of
1352          * the device is 0 degrees.
1353          * <p>
1354          * Sent from the {@link InCallService} via
1355          * {@link InCallService.VideoCall#setDeviceOrientation(int)}.
1356          *
1357          * @param rotation The device orientation, in degrees.
1358          */
onSetDeviceOrientation(int rotation)1359         public abstract void onSetDeviceOrientation(int rotation);
1360 
1361         /**
1362          * Sets camera zoom ratio.
1363          * <p>
1364          * Sent from the {@link InCallService} via {@link InCallService.VideoCall#setZoom(float)}.
1365          *
1366          * @param value The camera zoom ratio.
1367          */
onSetZoom(float value)1368         public abstract void onSetZoom(float value);
1369 
1370         /**
1371          * Issues a request to modify the properties of the current video session.
1372          * <p>
1373          * Example scenarios include: requesting an audio-only call to be upgraded to a
1374          * bi-directional video call, turning on or off the user's camera, sending a pause signal
1375          * when the {@link InCallService} is no longer the foreground application.
1376          * <p>
1377          * If the {@link VideoProvider} determines a request to be invalid, it should call
1378          * {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} to report the
1379          * invalid request back to the {@link InCallService}.
1380          * <p>
1381          * Where a request requires confirmation from the user of the peer device, the
1382          * {@link VideoProvider} must communicate the request to the peer device and handle the
1383          * user's response.  {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)}
1384          * is used to inform the {@link InCallService} of the result of the request.
1385          * <p>
1386          * Sent from the {@link InCallService} via
1387          * {@link InCallService.VideoCall#sendSessionModifyRequest(VideoProfile)}.
1388          *
1389          * @param fromProfile The video profile prior to the request.
1390          * @param toProfile The video profile with the requested changes made.
1391          */
onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)1392         public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
1393                 VideoProfile toProfile);
1394 
1395         /**
1396          * Provides a response to a request to change the current video session properties.
1397          * <p>
1398          * For example, if the peer requests and upgrade from an audio-only call to a bi-directional
1399          * video call, could decline the request and keep the call as audio-only.
1400          * In such a scenario, the {@code responseProfile} would have a video state of
1401          * {@link VideoProfile#STATE_AUDIO_ONLY}.  If the user had decided to accept the request,
1402          * the video state would be {@link VideoProfile#STATE_BIDIRECTIONAL}.
1403          * <p>
1404          * Sent from the {@link InCallService} via
1405          * {@link InCallService.VideoCall#sendSessionModifyResponse(VideoProfile)} in response to
1406          * a {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)}
1407          * callback.
1408          *
1409          * @param responseProfile The response video profile.
1410          */
onSendSessionModifyResponse(VideoProfile responseProfile)1411         public abstract void onSendSessionModifyResponse(VideoProfile responseProfile);
1412 
1413         /**
1414          * Issues a request to the {@link VideoProvider} to retrieve the camera capabilities.
1415          * <p>
1416          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
1417          * camera via
1418          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
1419          * <p>
1420          * Sent from the {@link InCallService} via
1421          * {@link InCallService.VideoCall#requestCameraCapabilities()}.
1422          */
onRequestCameraCapabilities()1423         public abstract void onRequestCameraCapabilities();
1424 
1425         /**
1426          * Issues a request to the {@link VideoProvider} to retrieve the current data usage for the
1427          * video component of the current {@link Connection}.
1428          * <p>
1429          * The {@link VideoProvider} should respond by communicating current data usage, in bytes,
1430          * via {@link VideoProvider#setCallDataUsage(long)}.
1431          * <p>
1432          * Sent from the {@link InCallService} via
1433          * {@link InCallService.VideoCall#requestCallDataUsage()}.
1434          */
onRequestConnectionDataUsage()1435         public abstract void onRequestConnectionDataUsage();
1436 
1437         /**
1438          * Provides the {@link VideoProvider} with the {@link Uri} of an image to be displayed to
1439          * the peer device when the video signal is paused.
1440          * <p>
1441          * Sent from the {@link InCallService} via
1442          * {@link InCallService.VideoCall#setPauseImage(Uri)}.
1443          *
1444          * @param uri URI of image to display.
1445          */
onSetPauseImage(Uri uri)1446         public abstract void onSetPauseImage(Uri uri);
1447 
1448         /**
1449          * Used to inform listening {@link InCallService} implementations when the
1450          * {@link VideoProvider} receives a session modification request.
1451          * <p>
1452          * Received by the {@link InCallService} via
1453          * {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)},
1454          *
1455          * @param videoProfile The requested video profile.
1456          * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)
1457          */
receiveSessionModifyRequest(VideoProfile videoProfile)1458         public void receiveSessionModifyRequest(VideoProfile videoProfile) {
1459             if (mVideoCallbacks != null) {
1460                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1461                     try {
1462                         callback.receiveSessionModifyRequest(videoProfile);
1463                     } catch (RemoteException ignored) {
1464                         Log.w(this, "receiveSessionModifyRequest callback failed", ignored);
1465                     }
1466                 }
1467             }
1468         }
1469 
1470         /**
1471          * Used to inform listening {@link InCallService} implementations when the
1472          * {@link VideoProvider} receives a response to a session modification request.
1473          * <p>
1474          * Received by the {@link InCallService} via
1475          * {@link InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int,
1476          * VideoProfile, VideoProfile)}.
1477          *
1478          * @param status Status of the session modify request.  Valid values are
1479          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS},
1480          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_FAIL},
1481          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_INVALID},
1482          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_TIMED_OUT},
1483          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE}
1484          * @param requestedProfile The original request which was sent to the peer device.
1485          * @param responseProfile The actual profile changes agreed to by the peer device.
1486          * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)
1487          */
receiveSessionModifyResponse(int status, VideoProfile requestedProfile, VideoProfile responseProfile)1488         public void receiveSessionModifyResponse(int status,
1489                 VideoProfile requestedProfile, VideoProfile responseProfile) {
1490             if (mVideoCallbacks != null) {
1491                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1492                     try {
1493                         callback.receiveSessionModifyResponse(status, requestedProfile,
1494                                 responseProfile);
1495                     } catch (RemoteException ignored) {
1496                         Log.w(this, "receiveSessionModifyResponse callback failed", ignored);
1497                     }
1498                 }
1499             }
1500         }
1501 
1502         /**
1503          * Used to inform listening {@link InCallService} implementations when the
1504          * {@link VideoProvider} reports a call session event.
1505          * <p>
1506          * Received by the {@link InCallService} via
1507          * {@link InCallService.VideoCall.Callback#onCallSessionEvent(int)}.
1508          *
1509          * @param event The event.  Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE},
1510          *      {@link VideoProvider#SESSION_EVENT_RX_RESUME},
1511          *      {@link VideoProvider#SESSION_EVENT_TX_START},
1512          *      {@link VideoProvider#SESSION_EVENT_TX_STOP},
1513          *      {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
1514          *      {@link VideoProvider#SESSION_EVENT_CAMERA_READY},
1515          *      {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}.
1516          */
handleCallSessionEvent(int event)1517         public void handleCallSessionEvent(int event) {
1518             if (mVideoCallbacks != null) {
1519                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1520                     try {
1521                         callback.handleCallSessionEvent(event);
1522                     } catch (RemoteException ignored) {
1523                         Log.w(this, "handleCallSessionEvent callback failed", ignored);
1524                     }
1525                 }
1526             }
1527         }
1528 
1529         /**
1530          * Used to inform listening {@link InCallService} implementations when the dimensions of the
1531          * peer's video have changed.
1532          * <p>
1533          * This could occur if, for example, the peer rotates their device, changing the aspect
1534          * ratio of the video, or if the user switches between the back and front cameras.
1535          * <p>
1536          * Received by the {@link InCallService} via
1537          * {@link InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int)}.
1538          *
1539          * @param width  The updated peer video width.
1540          * @param height The updated peer video height.
1541          */
changePeerDimensions(int width, int height)1542         public void changePeerDimensions(int width, int height) {
1543             if (mVideoCallbacks != null) {
1544                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1545                     try {
1546                         callback.changePeerDimensions(width, height);
1547                     } catch (RemoteException ignored) {
1548                         Log.w(this, "changePeerDimensions callback failed", ignored);
1549                     }
1550                 }
1551             }
1552         }
1553 
1554         /**
1555          * Used to inform listening {@link InCallService} implementations when the data usage of the
1556          * video associated with the current {@link Connection} has changed.
1557          * <p>
1558          * This could be in response to a preview request via
1559          * {@link #onRequestConnectionDataUsage()}, or as a periodic update by the
1560          * {@link VideoProvider}.  Where periodic updates of data usage are provided, they should be
1561          * provided at most for every 1 MB of data transferred and no more than once every 10 sec.
1562          * <p>
1563          * Received by the {@link InCallService} via
1564          * {@link InCallService.VideoCall.Callback#onCallDataUsageChanged(long)}.
1565          *
1566          * @param dataUsage The updated data usage (in bytes).  Reported as the cumulative bytes
1567          *                  used since the start of the call.
1568          */
setCallDataUsage(long dataUsage)1569         public void setCallDataUsage(long dataUsage) {
1570             if (mVideoCallbacks != null) {
1571                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1572                     try {
1573                         callback.changeCallDataUsage(dataUsage);
1574                     } catch (RemoteException ignored) {
1575                         Log.w(this, "setCallDataUsage callback failed", ignored);
1576                     }
1577                 }
1578             }
1579         }
1580 
1581         /**
1582          * @see #setCallDataUsage(long)
1583          *
1584          * @param dataUsage The updated data usage (in byes).
1585          * @deprecated - Use {@link #setCallDataUsage(long)} instead.
1586          * @hide
1587          */
changeCallDataUsage(long dataUsage)1588         public void changeCallDataUsage(long dataUsage) {
1589             setCallDataUsage(dataUsage);
1590         }
1591 
1592         /**
1593          * Used to inform listening {@link InCallService} implementations when the capabilities of
1594          * the current camera have changed.
1595          * <p>
1596          * The {@link VideoProvider} should call this in response to
1597          * {@link VideoProvider#onRequestCameraCapabilities()}, or when the current camera is
1598          * changed via {@link VideoProvider#onSetCamera(String)}.
1599          * <p>
1600          * Received by the {@link InCallService} via
1601          * {@link InCallService.VideoCall.Callback#onCameraCapabilitiesChanged(
1602          * VideoProfile.CameraCapabilities)}.
1603          *
1604          * @param cameraCapabilities The new camera capabilities.
1605          */
changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities)1606         public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
1607             if (mVideoCallbacks != null) {
1608                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1609                     try {
1610                         callback.changeCameraCapabilities(cameraCapabilities);
1611                     } catch (RemoteException ignored) {
1612                         Log.w(this, "changeCameraCapabilities callback failed", ignored);
1613                     }
1614                 }
1615             }
1616         }
1617 
1618         /**
1619          * Used to inform listening {@link InCallService} implementations when the video quality
1620          * of the call has changed.
1621          * <p>
1622          * Received by the {@link InCallService} via
1623          * {@link InCallService.VideoCall.Callback#onVideoQualityChanged(int)}.
1624          *
1625          * @param videoQuality The updated video quality.  Valid values:
1626          *      {@link VideoProfile#QUALITY_HIGH},
1627          *      {@link VideoProfile#QUALITY_MEDIUM},
1628          *      {@link VideoProfile#QUALITY_LOW},
1629          *      {@link VideoProfile#QUALITY_DEFAULT}.
1630          */
changeVideoQuality(int videoQuality)1631         public void changeVideoQuality(int videoQuality) {
1632             if (mVideoCallbacks != null) {
1633                 for (IVideoCallback callback : mVideoCallbacks.values()) {
1634                     try {
1635                         callback.changeVideoQuality(videoQuality);
1636                     } catch (RemoteException ignored) {
1637                         Log.w(this, "changeVideoQuality callback failed", ignored);
1638                     }
1639                 }
1640             }
1641         }
1642 
1643         /**
1644          * Returns a string representation of a call session event.
1645          *
1646          * @param event A call session event passed to {@link #handleCallSessionEvent(int)}.
1647          * @return String representation of the call session event.
1648          * @hide
1649          */
sessionEventToString(int event)1650         public static String sessionEventToString(int event) {
1651             switch (event) {
1652                 case SESSION_EVENT_CAMERA_FAILURE:
1653                     return SESSION_EVENT_CAMERA_FAILURE_STR;
1654                 case SESSION_EVENT_CAMERA_READY:
1655                     return SESSION_EVENT_CAMERA_READY_STR;
1656                 case SESSION_EVENT_RX_PAUSE:
1657                     return SESSION_EVENT_RX_PAUSE_STR;
1658                 case SESSION_EVENT_RX_RESUME:
1659                     return SESSION_EVENT_RX_RESUME_STR;
1660                 case SESSION_EVENT_TX_START:
1661                     return SESSION_EVENT_TX_START_STR;
1662                 case SESSION_EVENT_TX_STOP:
1663                     return SESSION_EVENT_TX_STOP_STR;
1664                 case SESSION_EVENT_CAMERA_PERMISSION_ERROR:
1665                     return SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR;
1666                 default:
1667                     return SESSION_EVENT_UNKNOWN_STR + " " + event;
1668             }
1669         }
1670     }
1671 
1672     private final Listener mConnectionDeathListener = new Listener() {
1673         @Override
1674         public void onDestroyed(Connection c) {
1675             if (mConferenceables.remove(c)) {
1676                 fireOnConferenceableConnectionsChanged();
1677             }
1678         }
1679     };
1680 
1681     private final Conference.Listener mConferenceDeathListener = new Conference.Listener() {
1682         @Override
1683         public void onDestroyed(Conference c) {
1684             if (mConferenceables.remove(c)) {
1685                 fireOnConferenceableConnectionsChanged();
1686             }
1687         }
1688     };
1689 
1690     /**
1691      * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
1692      * load factor before resizing, 1 means we only expect a single thread to
1693      * access the map so make only a single shard
1694      */
1695     private final Set<Listener> mListeners = Collections.newSetFromMap(
1696             new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
1697     private final List<Conferenceable> mConferenceables = new ArrayList<>();
1698     private final List<Conferenceable> mUnmodifiableConferenceables =
1699             Collections.unmodifiableList(mConferenceables);
1700 
1701     // The internal telecom call ID associated with this connection.
1702     private String mTelecomCallId;
1703     // The PhoneAccountHandle associated with this connection.
1704     private PhoneAccountHandle mPhoneAccountHandle;
1705     private int mState = STATE_NEW;
1706     private CallAudioState mCallAudioState;
1707     private Uri mAddress;
1708     private int mAddressPresentation;
1709     private String mCallerDisplayName;
1710     private int mCallerDisplayNamePresentation;
1711     private boolean mRingbackRequested = false;
1712     private int mConnectionCapabilities;
1713     private int mConnectionProperties;
1714     private int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
1715     private VideoProvider mVideoProvider;
1716     private boolean mAudioModeIsVoip;
1717     private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
1718     private long mConnectElapsedTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
1719     private StatusHints mStatusHints;
1720     private int mVideoState;
1721     private DisconnectCause mDisconnectCause;
1722     private Conference mConference;
1723     private ConnectionService mConnectionService;
1724     private Bundle mExtras;
1725     private final Object mExtrasLock = new Object();
1726 
1727     /**
1728      * Tracks the key set for the extras bundle provided on the last invocation of
1729      * {@link #setExtras(Bundle)}.  Used so that on subsequent invocations we can remove any extras
1730      * keys which were set previously but are no longer present in the replacement Bundle.
1731      */
1732     private Set<String> mPreviousExtraKeys;
1733 
1734     /**
1735      * Create a new Connection.
1736      */
Connection()1737     public Connection() {}
1738 
1739     /**
1740      * Returns the Telecom internal call ID associated with this connection.  Should only be used
1741      * for debugging and tracing purposes.
1742      *
1743      * @return The Telecom call ID.
1744      * @hide
1745      */
getTelecomCallId()1746     public final String getTelecomCallId() {
1747         return mTelecomCallId;
1748     }
1749 
1750     /**
1751      * @return The address (e.g., phone number) to which this Connection is currently communicating.
1752      */
getAddress()1753     public final Uri getAddress() {
1754         return mAddress;
1755     }
1756 
1757     /**
1758      * @return The presentation requirements for the address.
1759      *         See {@link TelecomManager} for valid values.
1760      */
getAddressPresentation()1761     public final int getAddressPresentation() {
1762         return mAddressPresentation;
1763     }
1764 
1765     /**
1766      * @return The caller display name (CNAP).
1767      */
getCallerDisplayName()1768     public final String getCallerDisplayName() {
1769         return mCallerDisplayName;
1770     }
1771 
1772     /**
1773      * @return The presentation requirements for the handle.
1774      *         See {@link TelecomManager} for valid values.
1775      */
getCallerDisplayNamePresentation()1776     public final int getCallerDisplayNamePresentation() {
1777         return mCallerDisplayNamePresentation;
1778     }
1779 
1780     /**
1781      * @return The state of this Connection.
1782      */
getState()1783     public final int getState() {
1784         return mState;
1785     }
1786 
1787     /**
1788      * Returns the video state of the connection.
1789      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
1790      * {@link VideoProfile#STATE_BIDIRECTIONAL},
1791      * {@link VideoProfile#STATE_TX_ENABLED},
1792      * {@link VideoProfile#STATE_RX_ENABLED}.
1793      *
1794      * @return The video state of the connection.
1795      * @hide
1796      */
getVideoState()1797     public final int getVideoState() {
1798         return mVideoState;
1799     }
1800 
1801     /**
1802      * @return The audio state of the connection, describing how its audio is currently
1803      *         being routed by the system. This is {@code null} if this Connection
1804      *         does not directly know about its audio state.
1805      * @deprecated Use {@link #getCallAudioState()} instead.
1806      * @hide
1807      */
1808     @SystemApi
1809     @Deprecated
getAudioState()1810     public final AudioState getAudioState() {
1811         if (mCallAudioState == null) {
1812           return null;
1813         }
1814         return new AudioState(mCallAudioState);
1815     }
1816 
1817     /**
1818      * @return The audio state of the connection, describing how its audio is currently
1819      *         being routed by the system. This is {@code null} if this Connection
1820      *         does not directly know about its audio state.
1821      */
getCallAudioState()1822     public final CallAudioState getCallAudioState() {
1823         return mCallAudioState;
1824     }
1825 
1826     /**
1827      * @return The conference that this connection is a part of.  Null if it is not part of any
1828      *         conference.
1829      */
getConference()1830     public final Conference getConference() {
1831         return mConference;
1832     }
1833 
1834     /**
1835      * Returns whether this connection is requesting that the system play a ringback tone
1836      * on its behalf.
1837      */
isRingbackRequested()1838     public final boolean isRingbackRequested() {
1839         return mRingbackRequested;
1840     }
1841 
1842     /**
1843      * @return True if the connection's audio mode is VOIP.
1844      */
getAudioModeIsVoip()1845     public final boolean getAudioModeIsVoip() {
1846         return mAudioModeIsVoip;
1847     }
1848 
1849     /**
1850      * Retrieves the connection start time of the {@code Connnection}, if specified.  A value of
1851      * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the
1852      * start time of the conference.
1853      *
1854      * @return The time at which the {@code Connnection} was connected.
1855      *
1856      * @hide
1857      */
getConnectTimeMillis()1858     public final long getConnectTimeMillis() {
1859         return mConnectTimeMillis;
1860     }
1861 
1862     /**
1863      * Retrieves the connection start time of the {@link Connection}, if specified.  A value of
1864      * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the
1865      * start time of the conference.
1866      *
1867      * Based on the value of {@link SystemClock#elapsedRealtime()}, which ensures that wall-clock
1868      * changes do not impact the call duration.
1869      *
1870      * @return The time at which the {@link Connection} was connected.
1871      *
1872      * @hide
1873      */
getConnectElapsedTimeMillis()1874     public final long getConnectElapsedTimeMillis() {
1875         return mConnectElapsedTimeMillis;
1876     }
1877 
1878     /**
1879      * @return The status hints for this connection.
1880      */
getStatusHints()1881     public final StatusHints getStatusHints() {
1882         return mStatusHints;
1883     }
1884 
1885     /**
1886      * Returns the extras associated with this connection.
1887      * <p>
1888      * Extras should be updated using {@link #putExtras(Bundle)}.
1889      * <p>
1890      * Telecom or an {@link InCallService} can also update the extras via
1891      * {@link android.telecom.Call#putExtras(Bundle)}, and
1892      * {@link Call#removeExtras(List)}.
1893      * <p>
1894      * The connection is notified of changes to the extras made by Telecom or an
1895      * {@link InCallService} by {@link #onExtrasChanged(Bundle)}.
1896      *
1897      * @return The extras associated with this connection.
1898      */
getExtras()1899     public final Bundle getExtras() {
1900         Bundle extras = null;
1901         synchronized (mExtrasLock) {
1902             if (mExtras != null) {
1903                 extras = new Bundle(mExtras);
1904             }
1905         }
1906         return extras;
1907     }
1908 
1909     /**
1910      * Assign a listener to be notified of state changes.
1911      *
1912      * @param l A listener.
1913      * @return This Connection.
1914      *
1915      * @hide
1916      */
addConnectionListener(Listener l)1917     public final Connection addConnectionListener(Listener l) {
1918         mListeners.add(l);
1919         return this;
1920     }
1921 
1922     /**
1923      * Remove a previously assigned listener that was being notified of state changes.
1924      *
1925      * @param l A Listener.
1926      * @return This Connection.
1927      *
1928      * @hide
1929      */
removeConnectionListener(Listener l)1930     public final Connection removeConnectionListener(Listener l) {
1931         if (l != null) {
1932             mListeners.remove(l);
1933         }
1934         return this;
1935     }
1936 
1937     /**
1938      * @return The {@link DisconnectCause} for this connection.
1939      */
getDisconnectCause()1940     public final DisconnectCause getDisconnectCause() {
1941         return mDisconnectCause;
1942     }
1943 
1944     /**
1945      * Sets the telecom call ID associated with this Connection.  The Telecom Call ID should be used
1946      * ONLY for debugging purposes.
1947      *
1948      * @param callId The telecom call ID.
1949      * @hide
1950      */
setTelecomCallId(String callId)1951     public void setTelecomCallId(String callId) {
1952         mTelecomCallId = callId;
1953     }
1954 
1955     /**
1956      * Inform this Connection that the state of its audio output has been changed externally.
1957      *
1958      * @param state The new audio state.
1959      * @hide
1960      */
setCallAudioState(CallAudioState state)1961     final void setCallAudioState(CallAudioState state) {
1962         checkImmutable();
1963         Log.d(this, "setAudioState %s", state);
1964         mCallAudioState = state;
1965         onAudioStateChanged(getAudioState());
1966         onCallAudioStateChanged(state);
1967     }
1968 
1969     /**
1970      * @param state An integer value of a {@code STATE_*} constant.
1971      * @return A string representation of the value.
1972      */
stateToString(int state)1973     public static String stateToString(int state) {
1974         switch (state) {
1975             case STATE_INITIALIZING:
1976                 return "INITIALIZING";
1977             case STATE_NEW:
1978                 return "NEW";
1979             case STATE_RINGING:
1980                 return "RINGING";
1981             case STATE_DIALING:
1982                 return "DIALING";
1983             case STATE_PULLING_CALL:
1984                 return "PULLING_CALL";
1985             case STATE_ACTIVE:
1986                 return "ACTIVE";
1987             case STATE_HOLDING:
1988                 return "HOLDING";
1989             case STATE_DISCONNECTED:
1990                 return "DISCONNECTED";
1991             default:
1992                 Log.wtf(Connection.class, "Unknown state %d", state);
1993                 return "UNKNOWN";
1994         }
1995     }
1996 
1997     /**
1998      * Returns the connection's capabilities, as a bit mask of the {@code CAPABILITY_*} constants.
1999      */
getConnectionCapabilities()2000     public final int getConnectionCapabilities() {
2001         return mConnectionCapabilities;
2002     }
2003 
2004     /**
2005      * Returns the connection's properties, as a bit mask of the {@code PROPERTY_*} constants.
2006      */
getConnectionProperties()2007     public final int getConnectionProperties() {
2008         return mConnectionProperties;
2009     }
2010 
2011     /**
2012      * Returns the connection's supported audio routes.
2013      *
2014      * @hide
2015      */
getSupportedAudioRoutes()2016     public final int getSupportedAudioRoutes() {
2017         return mSupportedAudioRoutes;
2018     }
2019 
2020     /**
2021      * Sets the value of the {@link #getAddress()} property.
2022      *
2023      * @param address The new address.
2024      * @param presentation The presentation requirements for the address.
2025      *        See {@link TelecomManager} for valid values.
2026      */
setAddress(Uri address, int presentation)2027     public final void setAddress(Uri address, int presentation) {
2028         checkImmutable();
2029         Log.d(this, "setAddress %s", address);
2030         mAddress = address;
2031         mAddressPresentation = presentation;
2032         for (Listener l : mListeners) {
2033             l.onAddressChanged(this, address, presentation);
2034         }
2035     }
2036 
2037     /**
2038      * Sets the caller display name (CNAP).
2039      *
2040      * @param callerDisplayName The new display name.
2041      * @param presentation The presentation requirements for the handle.
2042      *        See {@link TelecomManager} for valid values.
2043      */
setCallerDisplayName(String callerDisplayName, int presentation)2044     public final void setCallerDisplayName(String callerDisplayName, int presentation) {
2045         checkImmutable();
2046         Log.d(this, "setCallerDisplayName %s", callerDisplayName);
2047         mCallerDisplayName = callerDisplayName;
2048         mCallerDisplayNamePresentation = presentation;
2049         for (Listener l : mListeners) {
2050             l.onCallerDisplayNameChanged(this, callerDisplayName, presentation);
2051         }
2052     }
2053 
2054     /**
2055      * Set the video state for the connection.
2056      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
2057      * {@link VideoProfile#STATE_BIDIRECTIONAL},
2058      * {@link VideoProfile#STATE_TX_ENABLED},
2059      * {@link VideoProfile#STATE_RX_ENABLED}.
2060      *
2061      * @param videoState The new video state.
2062      */
setVideoState(int videoState)2063     public final void setVideoState(int videoState) {
2064         checkImmutable();
2065         Log.d(this, "setVideoState %d", videoState);
2066         mVideoState = videoState;
2067         for (Listener l : mListeners) {
2068             l.onVideoStateChanged(this, mVideoState);
2069         }
2070     }
2071 
2072     /**
2073      * Sets state to active (e.g., an ongoing connection where two or more parties can actively
2074      * communicate).
2075      */
setActive()2076     public final void setActive() {
2077         checkImmutable();
2078         setRingbackRequested(false);
2079         setState(STATE_ACTIVE);
2080     }
2081 
2082     /**
2083      * Sets state to ringing (e.g., an inbound ringing connection).
2084      */
setRinging()2085     public final void setRinging() {
2086         checkImmutable();
2087         setState(STATE_RINGING);
2088     }
2089 
2090     /**
2091      * Sets state to initializing (this Connection is not yet ready to be used).
2092      */
setInitializing()2093     public final void setInitializing() {
2094         checkImmutable();
2095         setState(STATE_INITIALIZING);
2096     }
2097 
2098     /**
2099      * Sets state to initialized (the Connection has been set up and is now ready to be used).
2100      */
setInitialized()2101     public final void setInitialized() {
2102         checkImmutable();
2103         setState(STATE_NEW);
2104     }
2105 
2106     /**
2107      * Sets state to dialing (e.g., dialing an outbound connection).
2108      */
setDialing()2109     public final void setDialing() {
2110         checkImmutable();
2111         setState(STATE_DIALING);
2112     }
2113 
2114     /**
2115      * Sets state to pulling (e.g. the connection is being pulled to the local device from another
2116      * device).  Only applicable for {@link Connection}s with
2117      * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} and {@link Connection#CAPABILITY_CAN_PULL_CALL}.
2118      */
setPulling()2119     public final void setPulling() {
2120         checkImmutable();
2121         setState(STATE_PULLING_CALL);
2122     }
2123 
2124     /**
2125      * Sets state to be on hold.
2126      */
setOnHold()2127     public final void setOnHold() {
2128         checkImmutable();
2129         setState(STATE_HOLDING);
2130     }
2131 
2132     /**
2133      * Sets the video connection provider.
2134      * @param videoProvider The video provider.
2135      */
setVideoProvider(VideoProvider videoProvider)2136     public final void setVideoProvider(VideoProvider videoProvider) {
2137         checkImmutable();
2138         mVideoProvider = videoProvider;
2139         for (Listener l : mListeners) {
2140             l.onVideoProviderChanged(this, videoProvider);
2141         }
2142     }
2143 
getVideoProvider()2144     public final VideoProvider getVideoProvider() {
2145         return mVideoProvider;
2146     }
2147 
2148     /**
2149      * Sets state to disconnected.
2150      *
2151      * @param disconnectCause The reason for the disconnection, as specified by
2152      *         {@link DisconnectCause}.
2153      */
setDisconnected(DisconnectCause disconnectCause)2154     public final void setDisconnected(DisconnectCause disconnectCause) {
2155         checkImmutable();
2156         mDisconnectCause = disconnectCause;
2157         setState(STATE_DISCONNECTED);
2158         Log.d(this, "Disconnected with cause %s", disconnectCause);
2159         for (Listener l : mListeners) {
2160             l.onDisconnected(this, disconnectCause);
2161         }
2162     }
2163 
2164     /**
2165      * Informs listeners that this {@code Connection} is in a post-dial wait state. This is done
2166      * when (a) the {@code Connection} is issuing a DTMF sequence; (b) it has encountered a "wait"
2167      * character; and (c) it wishes to inform the In-Call app that it is waiting for the end-user
2168      * to send an {@link #onPostDialContinue(boolean)} signal.
2169      *
2170      * @param remaining The DTMF character sequence remaining to be emitted once the
2171      *         {@link #onPostDialContinue(boolean)} is received, including any "wait" characters
2172      *         that remaining sequence may contain.
2173      */
setPostDialWait(String remaining)2174     public final void setPostDialWait(String remaining) {
2175         checkImmutable();
2176         for (Listener l : mListeners) {
2177             l.onPostDialWait(this, remaining);
2178         }
2179     }
2180 
2181     /**
2182      * Informs listeners that this {@code Connection} has processed a character in the post-dial
2183      * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence;
2184      * and (b) it wishes to signal Telecom to play the corresponding DTMF tone locally.
2185      *
2186      * @param nextChar The DTMF character that was just processed by the {@code Connection}.
2187      */
setNextPostDialChar(char nextChar)2188     public final void setNextPostDialChar(char nextChar) {
2189         checkImmutable();
2190         for (Listener l : mListeners) {
2191             l.onPostDialChar(this, nextChar);
2192         }
2193     }
2194 
2195     /**
2196      * Requests that the framework play a ringback tone. This is to be invoked by implementations
2197      * that do not play a ringback tone themselves in the connection's audio stream.
2198      *
2199      * @param ringback Whether the ringback tone is to be played.
2200      */
setRingbackRequested(boolean ringback)2201     public final void setRingbackRequested(boolean ringback) {
2202         checkImmutable();
2203         if (mRingbackRequested != ringback) {
2204             mRingbackRequested = ringback;
2205             for (Listener l : mListeners) {
2206                 l.onRingbackRequested(this, ringback);
2207             }
2208         }
2209     }
2210 
2211     /**
2212      * Sets the connection's capabilities as a bit mask of the {@code CAPABILITY_*} constants.
2213      *
2214      * @param connectionCapabilities The new connection capabilities.
2215      */
setConnectionCapabilities(int connectionCapabilities)2216     public final void setConnectionCapabilities(int connectionCapabilities) {
2217         checkImmutable();
2218         if (mConnectionCapabilities != connectionCapabilities) {
2219             mConnectionCapabilities = connectionCapabilities;
2220             for (Listener l : mListeners) {
2221                 l.onConnectionCapabilitiesChanged(this, mConnectionCapabilities);
2222             }
2223         }
2224     }
2225 
2226     /**
2227      * Sets the connection's properties as a bit mask of the {@code PROPERTY_*} constants.
2228      *
2229      * @param connectionProperties The new connection properties.
2230      */
setConnectionProperties(int connectionProperties)2231     public final void setConnectionProperties(int connectionProperties) {
2232         checkImmutable();
2233         if (mConnectionProperties != connectionProperties) {
2234             mConnectionProperties = connectionProperties;
2235             for (Listener l : mListeners) {
2236                 l.onConnectionPropertiesChanged(this, mConnectionProperties);
2237             }
2238         }
2239     }
2240 
2241     /**
2242      * Sets the supported audio routes.
2243      *
2244      * @param supportedAudioRoutes the supported audio routes as a bitmask.
2245      *                             See {@link CallAudioState}
2246      * @hide
2247      */
setSupportedAudioRoutes(int supportedAudioRoutes)2248     public final void setSupportedAudioRoutes(int supportedAudioRoutes) {
2249         if ((supportedAudioRoutes
2250                 & (CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER)) == 0) {
2251             throw new IllegalArgumentException(
2252                     "supported audio routes must include either speaker or earpiece");
2253         }
2254 
2255         if (mSupportedAudioRoutes != supportedAudioRoutes) {
2256             mSupportedAudioRoutes = supportedAudioRoutes;
2257             for (Listener l : mListeners) {
2258                 l.onSupportedAudioRoutesChanged(this, mSupportedAudioRoutes);
2259             }
2260         }
2261     }
2262 
2263     /**
2264      * Tears down the Connection object.
2265      */
destroy()2266     public final void destroy() {
2267         for (Listener l : mListeners) {
2268             l.onDestroyed(this);
2269         }
2270     }
2271 
2272     /**
2273      * Requests that the framework use VOIP audio mode for this connection.
2274      *
2275      * @param isVoip True if the audio mode is VOIP.
2276      */
setAudioModeIsVoip(boolean isVoip)2277     public final void setAudioModeIsVoip(boolean isVoip) {
2278         checkImmutable();
2279         mAudioModeIsVoip = isVoip;
2280         for (Listener l : mListeners) {
2281             l.onAudioModeIsVoipChanged(this, isVoip);
2282         }
2283     }
2284 
2285     /**
2286      * Sets the time at which a call became active on this Connection. This is set only
2287      * when a conference call becomes active on this connection.
2288      *
2289      * @param connectTimeMillis The connection time, in milliseconds.  Should be set using a value
2290      *                          obtained from {@link System#currentTimeMillis()}.
2291      *
2292      * @hide
2293      */
setConnectTimeMillis(long connectTimeMillis)2294     public final void setConnectTimeMillis(long connectTimeMillis) {
2295         mConnectTimeMillis = connectTimeMillis;
2296     }
2297 
2298     /**
2299      * Sets the time at which a call became active on this Connection. This is set only
2300      * when a conference call becomes active on this connection.
2301      *
2302      * @param connectElapsedTimeMillis The connection time, in milliseconds.  Stored in the format
2303      *                              {@link SystemClock#elapsedRealtime()}.
2304      *
2305      * @hide
2306      */
setConnectionStartElapsedRealTime(long connectElapsedTimeMillis)2307     public final void setConnectionStartElapsedRealTime(long connectElapsedTimeMillis) {
2308         mConnectElapsedTimeMillis = connectElapsedTimeMillis;
2309     }
2310 
2311     /**
2312      * Sets the label and icon status to display in the in-call UI.
2313      *
2314      * @param statusHints The status label and icon to set.
2315      */
setStatusHints(StatusHints statusHints)2316     public final void setStatusHints(StatusHints statusHints) {
2317         checkImmutable();
2318         mStatusHints = statusHints;
2319         for (Listener l : mListeners) {
2320             l.onStatusHintsChanged(this, statusHints);
2321         }
2322     }
2323 
2324     /**
2325      * Sets the connections with which this connection can be conferenced.
2326      *
2327      * @param conferenceableConnections The set of connections this connection can conference with.
2328      */
setConferenceableConnections(List<Connection> conferenceableConnections)2329     public final void setConferenceableConnections(List<Connection> conferenceableConnections) {
2330         checkImmutable();
2331         clearConferenceableList();
2332         for (Connection c : conferenceableConnections) {
2333             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
2334             // small amount of items here.
2335             if (!mConferenceables.contains(c)) {
2336                 c.addConnectionListener(mConnectionDeathListener);
2337                 mConferenceables.add(c);
2338             }
2339         }
2340         fireOnConferenceableConnectionsChanged();
2341     }
2342 
2343     /**
2344      * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections
2345      * or conferences with which this connection can be conferenced.
2346      *
2347      * @param conferenceables The conferenceables.
2348      */
setConferenceables(List<Conferenceable> conferenceables)2349     public final void setConferenceables(List<Conferenceable> conferenceables) {
2350         clearConferenceableList();
2351         for (Conferenceable c : conferenceables) {
2352             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
2353             // small amount of items here.
2354             if (!mConferenceables.contains(c)) {
2355                 if (c instanceof Connection) {
2356                     Connection connection = (Connection) c;
2357                     connection.addConnectionListener(mConnectionDeathListener);
2358                 } else if (c instanceof Conference) {
2359                     Conference conference = (Conference) c;
2360                     conference.addListener(mConferenceDeathListener);
2361                 }
2362                 mConferenceables.add(c);
2363             }
2364         }
2365         fireOnConferenceableConnectionsChanged();
2366     }
2367 
2368     /**
2369      * Returns the connections or conferences with which this connection can be conferenced.
2370      */
getConferenceables()2371     public final List<Conferenceable> getConferenceables() {
2372         return mUnmodifiableConferenceables;
2373     }
2374 
2375     /**
2376      * @hide
2377      */
setConnectionService(ConnectionService connectionService)2378     public final void setConnectionService(ConnectionService connectionService) {
2379         checkImmutable();
2380         if (mConnectionService != null) {
2381             Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " +
2382                     "which is already associated with another ConnectionService.");
2383         } else {
2384             mConnectionService = connectionService;
2385         }
2386     }
2387 
2388     /**
2389      * @hide
2390      */
unsetConnectionService(ConnectionService connectionService)2391     public final void unsetConnectionService(ConnectionService connectionService) {
2392         if (mConnectionService != connectionService) {
2393             Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " +
2394                     "that does not belong to the ConnectionService.");
2395         } else {
2396             mConnectionService = null;
2397         }
2398     }
2399 
2400     /**
2401      * @hide
2402      */
getConnectionService()2403     public final ConnectionService getConnectionService() {
2404         return mConnectionService;
2405     }
2406 
2407     /**
2408      * Sets the conference that this connection is a part of. This will fail if the connection is
2409      * already part of a conference. {@link #resetConference} to un-set the conference first.
2410      *
2411      * @param conference The conference.
2412      * @return {@code true} if the conference was successfully set.
2413      * @hide
2414      */
setConference(Conference conference)2415     public final boolean setConference(Conference conference) {
2416         checkImmutable();
2417         // We check to see if it is already part of another conference.
2418         if (mConference == null) {
2419             mConference = conference;
2420             if (mConnectionService != null && mConnectionService.containsConference(conference)) {
2421                 fireConferenceChanged();
2422             }
2423             return true;
2424         }
2425         return false;
2426     }
2427 
2428     /**
2429      * Resets the conference that this connection is a part of.
2430      * @hide
2431      */
resetConference()2432     public final void resetConference() {
2433         if (mConference != null) {
2434             Log.d(this, "Conference reset");
2435             mConference = null;
2436             fireConferenceChanged();
2437         }
2438     }
2439 
2440     /**
2441      * Set some extras that can be associated with this {@code Connection}.
2442      * <p>
2443      * New or existing keys are replaced in the {@code Connection} extras.  Keys which are no longer
2444      * in the new extras, but were present the last time {@code setExtras} was called are removed.
2445      * <p>
2446      * Alternatively you may use the {@link #putExtras(Bundle)}, and
2447      * {@link #removeExtras(String...)} methods to modify the extras.
2448      * <p>
2449      * No assumptions should be made as to how an In-Call UI or service will handle these extras.
2450      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
2451      *
2452      * @param extras The extras associated with this {@code Connection}.
2453      */
setExtras(@ullable Bundle extras)2454     public final void setExtras(@Nullable Bundle extras) {
2455         checkImmutable();
2456 
2457         // Add/replace any new or changed extras values.
2458         putExtras(extras);
2459 
2460         // If we have used "setExtras" in the past, compare the key set from the last invocation to
2461         // the current one and remove any keys that went away.
2462         if (mPreviousExtraKeys != null) {
2463             List<String> toRemove = new ArrayList<String>();
2464             for (String oldKey : mPreviousExtraKeys) {
2465                 if (extras == null || !extras.containsKey(oldKey)) {
2466                     toRemove.add(oldKey);
2467                 }
2468             }
2469             if (!toRemove.isEmpty()) {
2470                 removeExtras(toRemove);
2471             }
2472         }
2473 
2474         // Track the keys the last time set called setExtras.  This way, the next time setExtras is
2475         // called we can see if the caller has removed any extras values.
2476         if (mPreviousExtraKeys == null) {
2477             mPreviousExtraKeys = new ArraySet<String>();
2478         }
2479         mPreviousExtraKeys.clear();
2480         if (extras != null) {
2481             mPreviousExtraKeys.addAll(extras.keySet());
2482         }
2483     }
2484 
2485     /**
2486      * Adds some extras to this {@code Connection}.  Existing keys are replaced and new ones are
2487      * added.
2488      * <p>
2489      * No assumptions should be made as to how an In-Call UI or service will handle these extras.
2490      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
2491      *
2492      * @param extras The extras to add.
2493      */
putExtras(@onNull Bundle extras)2494     public final void putExtras(@NonNull Bundle extras) {
2495         checkImmutable();
2496         if (extras == null) {
2497             return;
2498         }
2499         // Creating a duplicate bundle so we don't have to synchronize on mExtrasLock while calling
2500         // the listeners.
2501         Bundle listenerExtras;
2502         synchronized (mExtrasLock) {
2503             if (mExtras == null) {
2504                 mExtras = new Bundle();
2505             }
2506             mExtras.putAll(extras);
2507             listenerExtras = new Bundle(mExtras);
2508         }
2509         for (Listener l : mListeners) {
2510             // Create a new clone of the extras for each listener so that they don't clobber
2511             // each other
2512             l.onExtrasChanged(this, new Bundle(listenerExtras));
2513         }
2514     }
2515 
2516     /**
2517      * Adds a boolean extra to this {@code Connection}.
2518      *
2519      * @param key The extra key.
2520      * @param value The value.
2521      * @hide
2522      */
putExtra(String key, boolean value)2523     public final void putExtra(String key, boolean value) {
2524         Bundle newExtras = new Bundle();
2525         newExtras.putBoolean(key, value);
2526         putExtras(newExtras);
2527     }
2528 
2529     /**
2530      * Adds an integer extra to this {@code Connection}.
2531      *
2532      * @param key The extra key.
2533      * @param value The value.
2534      * @hide
2535      */
putExtra(String key, int value)2536     public final void putExtra(String key, int value) {
2537         Bundle newExtras = new Bundle();
2538         newExtras.putInt(key, value);
2539         putExtras(newExtras);
2540     }
2541 
2542     /**
2543      * Adds a string extra to this {@code Connection}.
2544      *
2545      * @param key The extra key.
2546      * @param value The value.
2547      * @hide
2548      */
putExtra(String key, String value)2549     public final void putExtra(String key, String value) {
2550         Bundle newExtras = new Bundle();
2551         newExtras.putString(key, value);
2552         putExtras(newExtras);
2553     }
2554 
2555     /**
2556      * Removes extras from this {@code Connection}.
2557      *
2558      * @param keys The keys of the extras to remove.
2559      */
removeExtras(List<String> keys)2560     public final void removeExtras(List<String> keys) {
2561         synchronized (mExtrasLock) {
2562             if (mExtras != null) {
2563                 for (String key : keys) {
2564                     mExtras.remove(key);
2565                 }
2566             }
2567         }
2568         List<String> unmodifiableKeys = Collections.unmodifiableList(keys);
2569         for (Listener l : mListeners) {
2570             l.onExtrasRemoved(this, unmodifiableKeys);
2571         }
2572     }
2573 
2574     /**
2575      * Removes extras from this {@code Connection}.
2576      *
2577      * @param keys The keys of the extras to remove.
2578      */
removeExtras(String .... keys)2579     public final void removeExtras(String ... keys) {
2580         removeExtras(Arrays.asList(keys));
2581     }
2582 
2583     /**
2584      * Sets the audio route (speaker, bluetooth, etc...).  When this request is honored, there will
2585      * be change to the {@link #getCallAudioState()}.
2586      * <p>
2587      * Used by self-managed {@link ConnectionService}s which wish to change the audio route for a
2588      * self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.)
2589      * <p>
2590      * See also {@link InCallService#setAudioRoute(int)}.
2591      *
2592      * @param route The audio route to use (one of {@link CallAudioState#ROUTE_BLUETOOTH},
2593      *              {@link CallAudioState#ROUTE_EARPIECE}, {@link CallAudioState#ROUTE_SPEAKER}, or
2594      *              {@link CallAudioState#ROUTE_WIRED_HEADSET}).
2595      */
setAudioRoute(int route)2596     public final void setAudioRoute(int route) {
2597         for (Listener l : mListeners) {
2598             l.onAudioRouteChanged(this, route, null);
2599         }
2600     }
2601 
2602     /**
2603      * Request audio routing to a specific bluetooth device. Calling this method may result in
2604      * the device routing audio to a different bluetooth device than the one specified if the
2605      * bluetooth stack is unable to route audio to the requested device.
2606      * A list of available devices can be obtained via
2607      * {@link CallAudioState#getSupportedBluetoothDevices()}
2608      *
2609      * <p>
2610      * Used by self-managed {@link ConnectionService}s which wish to use bluetooth audio for a
2611      * self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.)
2612      * <p>
2613      * See also {@link InCallService#requestBluetoothAudio(BluetoothDevice)}
2614      * @param bluetoothDevice The bluetooth device to connect to.
2615      */
requestBluetoothAudio(@onNull BluetoothDevice bluetoothDevice)2616     public void requestBluetoothAudio(@NonNull BluetoothDevice bluetoothDevice) {
2617         for (Listener l : mListeners) {
2618             l.onAudioRouteChanged(this, CallAudioState.ROUTE_BLUETOOTH,
2619                     bluetoothDevice.getAddress());
2620         }
2621     }
2622 
2623     /**
2624      * Informs listeners that a previously requested RTT session via
2625      * {@link ConnectionRequest#isRequestingRtt()} or
2626      * {@link #onStartRtt(RttTextStream)} has succeeded.
2627      */
sendRttInitiationSuccess()2628     public final void sendRttInitiationSuccess() {
2629         mListeners.forEach((l) -> l.onRttInitiationSuccess(Connection.this));
2630     }
2631 
2632     /**
2633      * Informs listeners that a previously requested RTT session via
2634      * {@link ConnectionRequest#isRequestingRtt()} or {@link #onStartRtt(RttTextStream)}
2635      * has failed.
2636      * @param reason One of the reason codes defined in {@link RttModifyStatus}, with the
2637      *               exception of {@link RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
2638      */
sendRttInitiationFailure(int reason)2639     public final void sendRttInitiationFailure(int reason) {
2640         mListeners.forEach((l) -> l.onRttInitiationFailure(Connection.this, reason));
2641     }
2642 
2643     /**
2644      * Informs listeners that a currently active RTT session has been terminated by the remote
2645      * side of the coll.
2646      */
sendRttSessionRemotelyTerminated()2647     public final void sendRttSessionRemotelyTerminated() {
2648         mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this));
2649     }
2650 
2651     /**
2652      * Informs listeners that the remote side of the call has requested an upgrade to include an
2653      * RTT session in the call.
2654      */
sendRemoteRttRequest()2655     public final void sendRemoteRttRequest() {
2656         mListeners.forEach((l) -> l.onRemoteRttRequest(Connection.this));
2657     }
2658 
2659     /**
2660      * Notifies this Connection that the {@link #getAudioState()} property has a new value.
2661      *
2662      * @param state The new connection audio state.
2663      * @deprecated Use {@link #onCallAudioStateChanged(CallAudioState)} instead.
2664      * @hide
2665      */
2666     @SystemApi
2667     @Deprecated
onAudioStateChanged(AudioState state)2668     public void onAudioStateChanged(AudioState state) {}
2669 
2670     /**
2671      * Notifies this Connection that the {@link #getCallAudioState()} property has a new value.
2672      *
2673      * @param state The new connection audio state.
2674      */
onCallAudioStateChanged(CallAudioState state)2675     public void onCallAudioStateChanged(CallAudioState state) {}
2676 
2677     /**
2678      * Notifies this Connection of an internal state change. This method is called after the
2679      * state is changed.
2680      *
2681      * @param state The new state, one of the {@code STATE_*} constants.
2682      */
onStateChanged(int state)2683     public void onStateChanged(int state) {}
2684 
2685     /**
2686      * Notifies this Connection of a request to play a DTMF tone.
2687      *
2688      * @param c A DTMF character.
2689      */
onPlayDtmfTone(char c)2690     public void onPlayDtmfTone(char c) {}
2691 
2692     /**
2693      * Notifies this Connection of a request to stop any currently playing DTMF tones.
2694      */
onStopDtmfTone()2695     public void onStopDtmfTone() {}
2696 
2697     /**
2698      * Notifies this Connection of a request to disconnect.
2699      */
onDisconnect()2700     public void onDisconnect() {}
2701 
2702     /**
2703      * Notifies this Connection of a request to disconnect a participant of the conference managed
2704      * by the connection.
2705      *
2706      * @param endpoint the {@link Uri} of the participant to disconnect.
2707      * @hide
2708      */
onDisconnectConferenceParticipant(Uri endpoint)2709     public void onDisconnectConferenceParticipant(Uri endpoint) {}
2710 
2711     /**
2712      * Notifies this Connection of a request to separate from its parent conference.
2713      */
onSeparate()2714     public void onSeparate() {}
2715 
2716     /**
2717      * Notifies this Connection of a request to abort.
2718      */
onAbort()2719     public void onAbort() {}
2720 
2721     /**
2722      * Notifies this Connection of a request to hold.
2723      */
onHold()2724     public void onHold() {}
2725 
2726     /**
2727      * Notifies this Connection of a request to exit a hold state.
2728      */
onUnhold()2729     public void onUnhold() {}
2730 
2731     /**
2732      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
2733      * a request to accept.
2734      * <p>
2735      * For managed {@link ConnectionService}s, this will be called when the user answers a call via
2736      * the default dialer's {@link InCallService}.
2737      * <p>
2738      * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the
2739      * Telecom framework may request that the call is answered in the following circumstances:
2740      * <ul>
2741      *     <li>The user chooses to answer an incoming call via a Bluetooth device.</li>
2742      *     <li>A car mode {@link InCallService} is in use which has declared
2743      *     {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest.  Such an
2744      *     {@link InCallService} will be able to see calls from self-managed
2745      *     {@link ConnectionService}s, and will be able to display an incoming call UI on their
2746      *     behalf.</li>
2747      * </ul>
2748      * @param videoState The video state in which to answer the connection.
2749      */
onAnswer(int videoState)2750     public void onAnswer(int videoState) {}
2751 
2752     /**
2753      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
2754      * a request to accept.
2755      * <p>
2756      * For managed {@link ConnectionService}s, this will be called when the user answers a call via
2757      * the default dialer's {@link InCallService}.
2758      * <p>
2759      * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the
2760      * Telecom framework may request that the call is answered in the following circumstances:
2761      * <ul>
2762      *     <li>The user chooses to answer an incoming call via a Bluetooth device.</li>
2763      *     <li>A car mode {@link InCallService} is in use which has declared
2764      *     {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest.  Such an
2765      *     {@link InCallService} will be able to see calls from self-managed
2766      *     {@link ConnectionService}s, and will be able to display an incoming call UI on their
2767      *     behalf.</li>
2768      * </ul>
2769      */
onAnswer()2770     public void onAnswer() {
2771         onAnswer(VideoProfile.STATE_AUDIO_ONLY);
2772     }
2773 
2774     /**
2775      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
2776      * a request to deflect.
2777      */
onDeflect(Uri address)2778     public void onDeflect(Uri address) {}
2779 
2780     /**
2781      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
2782      * a request to reject.
2783      * <p>
2784      * For managed {@link ConnectionService}s, this will be called when the user rejects a call via
2785      * the default dialer's {@link InCallService}.
2786      * <p>
2787      * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the
2788      * Telecom framework may request that the call is rejected in the following circumstances:
2789      * <ul>
2790      *     <li>The user chooses to reject an incoming call via a Bluetooth device.</li>
2791      *     <li>A car mode {@link InCallService} is in use which has declared
2792      *     {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest.  Such an
2793      *     {@link InCallService} will be able to see calls from self-managed
2794      *     {@link ConnectionService}s, and will be able to display an incoming call UI on their
2795      *     behalf.</li>
2796      * </ul>
2797      */
onReject()2798     public void onReject() {}
2799 
2800     /**
2801      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
2802      * a request to reject with a message.
2803      */
onReject(String replyMessage)2804     public void onReject(String replyMessage) {}
2805 
2806     /**
2807      * Notifies the Connection of a request to silence the ringer.
2808      *
2809      * @hide
2810      */
onSilence()2811     public void onSilence() {}
2812 
2813     /**
2814      * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
2815      */
onPostDialContinue(boolean proceed)2816     public void onPostDialContinue(boolean proceed) {}
2817 
2818     /**
2819      * Notifies this Connection of a request to pull an external call to the local device.
2820      * <p>
2821      * The {@link InCallService} issues a request to pull an external call to the local device via
2822      * {@link Call#pullExternalCall()}.
2823      * <p>
2824      * For a Connection to be pulled, both the {@link Connection#CAPABILITY_CAN_PULL_CALL}
2825      * capability and {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property bits must be set.
2826      * <p>
2827      * For more information on external calls, see {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
2828      */
onPullExternalCall()2829     public void onPullExternalCall() {}
2830 
2831     /**
2832      * Notifies this Connection of a {@link Call} event initiated from an {@link InCallService}.
2833      * <p>
2834      * The {@link InCallService} issues a Call event via {@link Call#sendCallEvent(String, Bundle)}.
2835      * <p>
2836      * Where possible, the Connection should make an attempt to handle {@link Call} events which
2837      * are part of the {@code android.telecom.*} namespace.  The Connection should ignore any events
2838      * it does not wish to handle.  Unexpected events should be handled gracefully, as it is
2839      * possible that a {@link InCallService} has defined its own Call events which a Connection is
2840      * not aware of.
2841      * <p>
2842      * See also {@link Call#sendCallEvent(String, Bundle)}.
2843      *
2844      * @param event The call event.
2845      * @param extras Extras associated with the call event.
2846      */
onCallEvent(String event, Bundle extras)2847     public void onCallEvent(String event, Bundle extras) {}
2848 
2849     /**
2850      * Notifies this {@link Connection} that a handover has completed.
2851      * <p>
2852      * A handover is initiated with {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int,
2853      * Bundle)} on the initiating side of the handover, and
2854      * {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)}.
2855      */
onHandoverComplete()2856     public void onHandoverComplete() {}
2857 
2858     /**
2859      * Notifies this {@link Connection} of a change to the extras made outside the
2860      * {@link ConnectionService}.
2861      * <p>
2862      * These extras changes can originate from Telecom itself, or from an {@link InCallService} via
2863      * the {@link android.telecom.Call#putExtras(Bundle)} and
2864      * {@link Call#removeExtras(List)}.
2865      *
2866      * @param extras The new extras bundle.
2867      */
onExtrasChanged(Bundle extras)2868     public void onExtrasChanged(Bundle extras) {}
2869 
2870     /**
2871      * Notifies this {@link Connection} that its {@link ConnectionService} is responsible for
2872      * displaying its incoming call user interface for the {@link Connection}.
2873      * <p>
2874      * Will only be called for incoming calls added via a self-managed {@link ConnectionService}
2875      * (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}), where the {@link ConnectionService}
2876      * should show its own incoming call user interface.
2877      * <p>
2878      * Where there are ongoing calls in other self-managed {@link ConnectionService}s, or in a
2879      * regular {@link ConnectionService}, and it is not possible to hold these other calls, the
2880      * Telecom framework will display its own incoming call user interface to allow the user to
2881      * choose whether to answer the new incoming call and disconnect other ongoing calls, or to
2882      * reject the new incoming call.
2883      * <p>
2884      * You should trigger the display of the incoming call user interface for your application by
2885      * showing a {@link Notification} with a full-screen {@link Intent} specified.
2886      * For example:
2887      * <pre><code>
2888      *     // Create an intent which triggers your fullscreen incoming call user interface.
2889      *     Intent intent = new Intent(Intent.ACTION_MAIN, null);
2890      *     intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
2891      *     intent.setClass(context, YourIncomingCallActivity.class);
2892      *     PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, 0);
2893      *
2894      *     // Build the notification as an ongoing high priority item; this ensures it will show as
2895      *     // a heads up notification which slides down over top of the current content.
2896      *     final Notification.Builder builder = new Notification.Builder(context);
2897      *     builder.setOngoing(true);
2898      *     builder.setPriority(Notification.PRIORITY_HIGH);
2899      *
2900      *     // Set notification content intent to take user to fullscreen UI if user taps on the
2901      *     // notification body.
2902      *     builder.setContentIntent(pendingIntent);
2903      *     // Set full screen intent to trigger display of the fullscreen UI when the notification
2904      *     // manager deems it appropriate.
2905      *     builder.setFullScreenIntent(pendingIntent, true);
2906      *
2907      *     // Setup notification content.
2908      *     builder.setSmallIcon( yourIconResourceId );
2909      *     builder.setContentTitle("Your notification title");
2910      *     builder.setContentText("Your notification content.");
2911      *
2912      *     // Use builder.addAction(..) to add buttons to answer or reject the call.
2913      *
2914      *     NotificationManager notificationManager = mContext.getSystemService(
2915      *         NotificationManager.class);
2916      *     notificationManager.notify(YOUR_TAG, YOUR_ID, builder.build());
2917      * </code></pre>
2918      */
onShowIncomingCallUi()2919     public void onShowIncomingCallUi() {}
2920 
2921     /**
2922      * Notifies this {@link Connection} that the user has requested an RTT session.
2923      * The connection service should call {@link #sendRttInitiationSuccess} or
2924      * {@link #sendRttInitiationFailure} to inform Telecom of the success or failure of the
2925      * request, respectively.
2926      * @param rttTextStream The object that should be used to send text to or receive text from
2927      *                      the in-call app.
2928      */
onStartRtt(@onNull RttTextStream rttTextStream)2929     public void onStartRtt(@NonNull RttTextStream rttTextStream) {}
2930 
2931     /**
2932      * Notifies this {@link Connection} that it should terminate any existing RTT communication
2933      * channel. No response to Telecom is needed for this method.
2934      */
onStopRtt()2935     public void onStopRtt() {}
2936 
2937     /**
2938      * Notifies this connection of a response to a previous remotely-initiated RTT upgrade
2939      * request sent via {@link #sendRemoteRttRequest}. Acceptance of the request is
2940      * indicated by the supplied {@link RttTextStream} being non-null, and rejection is
2941      * indicated by {@code rttTextStream} being {@code null}
2942      * @param rttTextStream The object that should be used to send text to or receive text from
2943      *                      the in-call app.
2944      */
handleRttUpgradeResponse(@ullable RttTextStream rttTextStream)2945     public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
2946 
toLogSafePhoneNumber(String number)2947     static String toLogSafePhoneNumber(String number) {
2948         // For unknown number, log empty string.
2949         if (number == null) {
2950             return "";
2951         }
2952 
2953         if (PII_DEBUG) {
2954             // When PII_DEBUG is true we emit PII.
2955             return number;
2956         }
2957 
2958         // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
2959         // sanitized phone numbers.
2960         StringBuilder builder = new StringBuilder();
2961         for (int i = 0; i < number.length(); i++) {
2962             char c = number.charAt(i);
2963             if (c == '-' || c == '@' || c == '.') {
2964                 builder.append(c);
2965             } else {
2966                 builder.append('x');
2967             }
2968         }
2969         return builder.toString();
2970     }
2971 
setState(int state)2972     private void setState(int state) {
2973         checkImmutable();
2974         if (mState == STATE_DISCONNECTED && mState != state) {
2975             Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state.");
2976             return;
2977         }
2978         if (mState != state) {
2979             Log.d(this, "setState: %s", stateToString(state));
2980             mState = state;
2981             onStateChanged(state);
2982             for (Listener l : mListeners) {
2983                 l.onStateChanged(this, state);
2984             }
2985         }
2986     }
2987 
2988     private static class FailureSignalingConnection extends Connection {
2989         private boolean mImmutable = false;
FailureSignalingConnection(DisconnectCause disconnectCause)2990         public FailureSignalingConnection(DisconnectCause disconnectCause) {
2991             setDisconnected(disconnectCause);
2992             mImmutable = true;
2993         }
2994 
checkImmutable()2995         public void checkImmutable() {
2996             if (mImmutable) {
2997                 throw new UnsupportedOperationException("Connection is immutable");
2998             }
2999         }
3000     }
3001 
3002     /**
3003      * Return a {@code Connection} which represents a failed connection attempt. The returned
3004      * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified,
3005      * and a {@link #getState()} of {@link #STATE_DISCONNECTED}.
3006      * <p>
3007      * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate,
3008      * so users of this method need not maintain a reference to its return value to destroy it.
3009      *
3010      * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
3011      * @return A {@code Connection} which indicates failure.
3012      */
createFailedConnection(DisconnectCause disconnectCause)3013     public static Connection createFailedConnection(DisconnectCause disconnectCause) {
3014         return new FailureSignalingConnection(disconnectCause);
3015     }
3016 
3017     /**
3018      * Override to throw an {@link UnsupportedOperationException} if this {@code Connection} is
3019      * not intended to be mutated, e.g., if it is a marker for failure. Only for framework use;
3020      * this should never be un-@hide-den.
3021      *
3022      * @hide
3023      */
checkImmutable()3024     public void checkImmutable() {}
3025 
3026     /**
3027      * Return a {@code Connection} which represents a canceled connection attempt. The returned
3028      * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of
3029      * that state. This connection should not be used for anything, and no other
3030      * {@code Connection}s should be attempted.
3031      * <p>
3032      * so users of this method need not maintain a reference to its return value to destroy it.
3033      *
3034      * @return A {@code Connection} which indicates that the underlying connection should
3035      * be canceled.
3036      */
createCanceledConnection()3037     public static Connection createCanceledConnection() {
3038         return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED));
3039     }
3040 
fireOnConferenceableConnectionsChanged()3041     private final void fireOnConferenceableConnectionsChanged() {
3042         for (Listener l : mListeners) {
3043             l.onConferenceablesChanged(this, getConferenceables());
3044         }
3045     }
3046 
fireConferenceChanged()3047     private final void fireConferenceChanged() {
3048         for (Listener l : mListeners) {
3049             l.onConferenceChanged(this, mConference);
3050         }
3051     }
3052 
clearConferenceableList()3053     private final void clearConferenceableList() {
3054         for (Conferenceable c : mConferenceables) {
3055             if (c instanceof Connection) {
3056                 Connection connection = (Connection) c;
3057                 connection.removeConnectionListener(mConnectionDeathListener);
3058             } else if (c instanceof Conference) {
3059                 Conference conference = (Conference) c;
3060                 conference.removeListener(mConferenceDeathListener);
3061             }
3062         }
3063         mConferenceables.clear();
3064     }
3065 
3066     /**
3067      * Handles a change to extras received from Telecom.
3068      *
3069      * @param extras The new extras.
3070      * @hide
3071      */
handleExtrasChanged(Bundle extras)3072     final void handleExtrasChanged(Bundle extras) {
3073         Bundle b = null;
3074         synchronized (mExtrasLock) {
3075             mExtras = extras;
3076             if (mExtras != null) {
3077                 b = new Bundle(mExtras);
3078             }
3079         }
3080         onExtrasChanged(b);
3081     }
3082 
3083     /**
3084      * Notifies listeners that the merge request failed.
3085      *
3086      * @hide
3087      */
notifyConferenceMergeFailed()3088     protected final void notifyConferenceMergeFailed() {
3089         for (Listener l : mListeners) {
3090             l.onConferenceMergeFailed(this);
3091         }
3092     }
3093 
3094     /**
3095      * Notifies listeners of a change to conference participant(s).
3096      *
3097      * @param conferenceParticipants The participants.
3098      * @hide
3099      */
updateConferenceParticipants( List<ConferenceParticipant> conferenceParticipants)3100     protected final void updateConferenceParticipants(
3101             List<ConferenceParticipant> conferenceParticipants) {
3102         for (Listener l : mListeners) {
3103             l.onConferenceParticipantsChanged(this, conferenceParticipants);
3104         }
3105     }
3106 
3107     /**
3108      * Notifies listeners that a conference call has been started.
3109      * @hide
3110      */
notifyConferenceStarted()3111     protected void notifyConferenceStarted() {
3112         for (Listener l : mListeners) {
3113             l.onConferenceStarted();
3114         }
3115     }
3116 
3117     /**
3118      * Notifies listeners when a change has occurred to the Connection which impacts its ability to
3119      * be a part of a conference call.
3120      * @param isConferenceSupported {@code true} if the connection supports being part of a
3121      *      conference call, {@code false} otherwise.
3122      * @hide
3123      */
notifyConferenceSupportedChanged(boolean isConferenceSupported)3124     protected void notifyConferenceSupportedChanged(boolean isConferenceSupported) {
3125         for (Listener l : mListeners) {
3126             l.onConferenceSupportedChanged(this, isConferenceSupported);
3127         }
3128     }
3129 
3130     /**
3131      * Notifies listeners when phone account is changed. For example, when the PhoneAccount is
3132      * changed due to an emergency call being redialed.
3133      * @param pHandle The new PhoneAccountHandle for this connection.
3134      * @hide
3135      */
notifyPhoneAccountChanged(PhoneAccountHandle pHandle)3136     public void notifyPhoneAccountChanged(PhoneAccountHandle pHandle) {
3137         for (Listener l : mListeners) {
3138             l.onPhoneAccountChanged(this, pHandle);
3139         }
3140     }
3141 
3142     /**
3143      * Sets the {@link PhoneAccountHandle} associated with this connection.
3144      *
3145      * @hide
3146      */
setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle)3147     public void setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
3148         if (mPhoneAccountHandle != phoneAccountHandle) {
3149             mPhoneAccountHandle = phoneAccountHandle;
3150             notifyPhoneAccountChanged(phoneAccountHandle);
3151         }
3152     }
3153 
3154     /**
3155      * Returns the {@link PhoneAccountHandle} associated with this connection.
3156      *
3157      * @hide
3158      */
getPhoneAccountHandle()3159     public PhoneAccountHandle getPhoneAccountHandle() {
3160         return mPhoneAccountHandle;
3161     }
3162 
3163     /**
3164      * Sends an event associated with this {@code Connection} with associated event extras to the
3165      * {@link InCallService}.
3166      * <p>
3167      * Connection events are used to communicate point in time information from a
3168      * {@link ConnectionService} to a {@link InCallService} implementations.  An example of a
3169      * custom connection event includes notifying the UI when a WIFI call has been handed over to
3170      * LTE, which the InCall UI might use to inform the user that billing charges may apply.  The
3171      * Android Telephony framework will send the {@link #EVENT_CALL_MERGE_FAILED} connection event
3172      * when a call to {@link Call#mergeConference()} has failed to complete successfully.  A
3173      * connection event could also be used to trigger UI in the {@link InCallService} which prompts
3174      * the user to make a choice (e.g. whether they want to incur roaming costs for making a call),
3175      * which is communicated back via {@link Call#sendCallEvent(String, Bundle)}.
3176      * <p>
3177      * Events are exposed to {@link InCallService} implementations via
3178      * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
3179      * <p>
3180      * No assumptions should be made as to how an In-Call UI or service will handle these events.
3181      * The {@link ConnectionService} must assume that the In-Call UI could even chose to ignore
3182      * some events altogether.
3183      * <p>
3184      * Events should be fully qualified (e.g. {@code com.example.event.MY_EVENT}) to avoid
3185      * conflicts between {@link ConnectionService} implementations.  Further, custom
3186      * {@link ConnectionService} implementations shall not re-purpose events in the
3187      * {@code android.*} namespace, nor shall they define new event types in this namespace.  When
3188      * defining a custom event type, ensure the contents of the extras {@link Bundle} is clearly
3189      * defined.  Extra keys for this bundle should be named similar to the event type (e.g.
3190      * {@code com.example.extra.MY_EXTRA}).
3191      * <p>
3192      *  When defining events and the associated extras, it is important to keep their behavior
3193      * consistent when the associated {@link ConnectionService} is updated.  Support for deprecated
3194      * events/extras should me maintained to ensure backwards compatibility with older
3195      * {@link InCallService} implementations which were built to support the older behavior.
3196      *
3197      * @param event The connection event.
3198      * @param extras Optional bundle containing extra information associated with the event.
3199      */
sendConnectionEvent(String event, Bundle extras)3200     public void sendConnectionEvent(String event, Bundle extras) {
3201         for (Listener l : mListeners) {
3202             l.onConnectionEvent(this, event, extras);
3203         }
3204     }
3205 }
3206