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