• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.telecom;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SystemApi;
24 import android.annotation.TestApi;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.content.pm.ServiceInfo;
27 import android.net.Uri;
28 import android.os.BadParcelableException;
29 import android.os.Build;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.os.ParcelFileDescriptor;
33 import android.os.UserHandle;
34 
35 import com.android.internal.telecom.IVideoProvider;
36 import com.android.server.telecom.flags.Flags;
37 
38 import java.io.IOException;
39 import java.io.InputStreamReader;
40 import java.io.OutputStreamWriter;
41 import java.lang.annotation.Retention;
42 import java.lang.annotation.RetentionPolicy;
43 import java.nio.charset.StandardCharsets;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Collections;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.Objects;
50 import java.util.concurrent.CopyOnWriteArrayList;
51 
52 /**
53  * Represents an ongoing phone call that the in-call app should present to the user.
54  */
55 public final class Call {
56     private static final String LOG_TAG = "TelecomCall";
57 
58     /**
59      * The state of a {@code Call} when newly created.
60      */
61     public static final int STATE_NEW = 0;
62 
63     /**
64      * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
65      */
66     public static final int STATE_DIALING = 1;
67 
68     /**
69      * The state of an incoming {@code Call} when ringing locally, but not yet connected.
70      */
71     public static final int STATE_RINGING = 2;
72 
73     /**
74      * The state of a {@code Call} when in a holding state.
75      */
76     public static final int STATE_HOLDING = 3;
77 
78     /**
79      * The state of a {@code Call} when actively supporting conversation.
80      */
81     public static final int STATE_ACTIVE = 4;
82 
83     /**
84      * The state of a {@code Call} when no further voice or other communication is being
85      * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
86      * is no longer active, and the local data transport has or inevitably will release resources
87      * associated with this {@code Call}.
88      */
89     public static final int STATE_DISCONNECTED = 7;
90 
91     /**
92      * The state of an outgoing {@code Call} when waiting on user to select a
93      * {@link PhoneAccount} through which to place the call.
94      */
95     public static final int STATE_SELECT_PHONE_ACCOUNT = 8;
96 
97     /**
98      * @hide
99      * @deprecated use STATE_SELECT_PHONE_ACCOUNT.
100      */
101     @Deprecated
102     @SystemApi
103     public static final int STATE_PRE_DIAL_WAIT = STATE_SELECT_PHONE_ACCOUNT;
104 
105     /**
106      * The initial state of an outgoing {@code Call}.
107      * Common transitions are to {@link #STATE_DIALING} state for a successful call or
108      * {@link #STATE_DISCONNECTED} if it failed.
109      */
110     public static final int STATE_CONNECTING = 9;
111 
112     /**
113      * The state of a {@code Call} when the user has initiated a disconnection of the call, but the
114      * call has not yet been disconnected by the underlying {@code ConnectionService}.  The next
115      * state of the call is (potentially) {@link #STATE_DISCONNECTED}.
116      */
117     public static final int STATE_DISCONNECTING = 10;
118 
119     /**
120      * The state of an external call which is in the process of being pulled from a remote device to
121      * the local device.
122      * <p>
123      * A call can only be in this state if the {@link Details#PROPERTY_IS_EXTERNAL_CALL} property
124      * and {@link Details#CAPABILITY_CAN_PULL_CALL} capability are set on the call.
125      * <p>
126      * An {@link InCallService} will only see this state if it has the
127      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
128      * manifest.
129      */
130     public static final int STATE_PULLING_CALL = 11;
131 
132     /**
133      * The state of a call that is active with the network, but the audio from the call is
134      * being intercepted by an app on the local device. Telecom does not hold audio focus in this
135      * state, and the call will be invisible to the user except for a persistent notification.
136      */
137     public static final int STATE_AUDIO_PROCESSING = 12;
138 
139     /**
140      * The state of a call that is being presented to the user after being in
141      * {@link #STATE_AUDIO_PROCESSING}. The call is still active with the network in this case, and
142      * Telecom will hold audio focus and play a ringtone if appropriate.
143      */
144     public static final int STATE_SIMULATED_RINGING = 13;
145 
146     /**
147      * @hide
148      */
149     @IntDef(prefix = { "STATE_" },
150             value = {
151                     STATE_NEW,
152                     STATE_DIALING,
153                     STATE_RINGING,
154                     STATE_HOLDING,
155                     STATE_ACTIVE,
156                     STATE_DISCONNECTED,
157                     STATE_SELECT_PHONE_ACCOUNT,
158                     STATE_CONNECTING,
159                     STATE_DISCONNECTING,
160                     STATE_PULLING_CALL,
161                     STATE_AUDIO_PROCESSING,
162                     STATE_SIMULATED_RINGING
163             })
164     @Retention(RetentionPolicy.SOURCE)
165     public @interface CallState {};
166 
167     /**
168      * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
169      * extras. Used to pass the phone accounts to display on the front end to the user in order to
170      * select phone accounts to (for example) place a call.
171      * @deprecated Use the list from {@link #EXTRA_SUGGESTED_PHONE_ACCOUNTS} instead.
172      */
173     @Deprecated
174     public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
175 
176     /**
177      * Extra key intended for {@link InCallService}s that notify the user of an incoming call. When
178      * EXTRA_IS_SUPPRESSED_BY_DO_NOT_DISTURB returns true, the {@link InCallService} should not
179      * interrupt the user of the incoming call because the call is being suppressed by Do Not
180      * Disturb settings.
181      *
182      * This extra will be removed from the {@link Call} object for {@link InCallService}s that do
183      * not hold the {@link android.Manifest.permission#READ_CONTACTS} permission.
184      */
185     public static final String EXTRA_IS_SUPPRESSED_BY_DO_NOT_DISTURB =
186             "android.telecom.extra.IS_SUPPRESSED_BY_DO_NOT_DISTURB";
187 
188     /**
189      * Key for extra used to pass along a list of {@link PhoneAccountSuggestion}s to the in-call
190      * UI when a call enters the {@link #STATE_SELECT_PHONE_ACCOUNT} state. The list included here
191      * will have the same length and be in the same order as the list passed with
192      * {@link #AVAILABLE_PHONE_ACCOUNTS}.
193      */
194     public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS =
195             "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
196 
197     /**
198      * Extra key used to indicate the time (in milliseconds since midnight, January 1, 1970 UTC)
199      * when the last outgoing emergency call was made.  This is used to identify potential emergency
200      * callbacks.
201      */
202     public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS =
203             "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
204 
205 
206     /**
207      * Extra key used to indicate whether a {@link CallScreeningService} has requested to silence
208      * the ringtone for a call.  If the {@link InCallService} declares
209      * {@link TelecomManager#METADATA_IN_CALL_SERVICE_RINGING} in its manifest, it should not
210      * play a ringtone for an incoming call with this extra key set.
211      */
212     public static final String EXTRA_SILENT_RINGING_REQUESTED =
213             "android.telecom.extra.SILENT_RINGING_REQUESTED";
214 
215     /**
216      * Event reported from the Telecom stack to report an in-call diagnostic message which the
217      * dialer app may opt to display to the user.  A diagnostic message is used to communicate
218      * scenarios the device has detected which may impact the quality of the ongoing call.
219      * <p>
220      * For example a problem with a bluetooth headset may generate a recommendation for the user to
221      * try using the speakerphone instead, or if the device detects it has entered a poor service
222      * area, the user might be warned so that they can finish their call prior to it dropping.
223      * <p>
224      * A diagnostic message is considered persistent in nature.  When the user enters a poor service
225      * area, for example, the accompanying diagnostic message persists until they leave the area
226      * of poor service.  Each message is accompanied with a {@link #EXTRA_DIAGNOSTIC_MESSAGE_ID}
227      * which uniquely identifies the diagnostic condition being reported.  The framework raises a
228      * call event of type {@link #EVENT_CLEAR_DIAGNOSTIC_MESSAGE} when the condition reported has
229      * been cleared.  The dialer app should display the diagnostic message until it is cleared.
230      * If multiple diagnostic messages are sent with different IDs (which have not yet been cleared)
231      * the dialer app should prioritize the most recently received message, but still provide the
232      * user with a means to review past messages.
233      * <p>
234      * The text of the message is found in {@link #EXTRA_DIAGNOSTIC_MESSAGE} in the form of a human
235      * readable {@link CharSequence} which is intended for display in the call UX.
236      * <p>
237      * The telecom framework audibly notifies the user of the presence of a diagnostic message, so
238      * the dialer app needs only to concern itself with visually displaying the message.
239      * <p>
240      * The dialer app receives this event via
241      * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
242      */
243     public static final String EVENT_DISPLAY_DIAGNOSTIC_MESSAGE =
244             "android.telecom.event.DISPLAY_DIAGNOSTIC_MESSAGE";
245 
246     /**
247      * Event reported from the telecom framework when a diagnostic message previously raised with
248      * {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE} has cleared and is no longer pertinent.
249      * <p>
250      * The {@link #EXTRA_DIAGNOSTIC_MESSAGE_ID} indicates the diagnostic message which has been
251      * cleared.
252      * <p>
253      * The dialer app receives this event via
254      * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
255      */
256     public static final String EVENT_CLEAR_DIAGNOSTIC_MESSAGE =
257             "android.telecom.event.CLEAR_DIAGNOSTIC_MESSAGE";
258 
259     /**
260      * Integer extra representing a message ID for a message posted via
261      * {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE}.  Used to ensure that the dialer app knows when
262      * the message in question has cleared via {@link #EVENT_CLEAR_DIAGNOSTIC_MESSAGE}.
263      */
264     public static final String EXTRA_DIAGNOSTIC_MESSAGE_ID =
265             "android.telecom.extra.DIAGNOSTIC_MESSAGE_ID";
266 
267     /**
268      * {@link CharSequence} extra used with {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE}.  This is the
269      * diagnostic message the dialer app should display.
270      */
271     public static final String EXTRA_DIAGNOSTIC_MESSAGE =
272             "android.telecom.extra.DIAGNOSTIC_MESSAGE";
273 
274     /**
275      * Boolean indicating that the call is a verified business call.
276      *
277      * {@link Connection#setExtras(Bundle)} or {@link Connection#putExtras(Bundle)}
278      * should be used to notify Telecom this extra has been set.
279      */
280     @FlaggedApi(Flags.FLAG_BUSINESS_CALL_COMPOSER)
281     public static final String EXTRA_IS_BUSINESS_CALL =
282             "android.telecom.extra.IS_BUSINESS_CALL";
283 
284     /**
285      * String value indicating the asserted display name reported via
286      * ImsCallProfile#EXTRA_ASSERTED_DISPLAY_NAME.
287      *
288      * {@link Connection#setExtras(Bundle)} or {@link Connection#putExtras(Bundle)}
289      * should be used to notify Telecom this extra has been set.
290      */
291     @FlaggedApi(Flags.FLAG_BUSINESS_CALL_COMPOSER)
292     public static final String EXTRA_ASSERTED_DISPLAY_NAME =
293             "android.telecom.extra.ASSERTED_DISPLAY_NAME";
294 
295     /**
296      * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
297      * call because they have declined to answer it.  This typically means that they are unable
298      * to answer the call at this time and would prefer it be sent to voicemail.
299      */
300     public static final int REJECT_REASON_DECLINED = 1;
301 
302     /**
303      * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
304      * call because it is an unwanted call.  This allows the user to indicate that they are
305      * rejecting a call because it is likely a nuisance call.
306      */
307     public static final int REJECT_REASON_UNWANTED = 2;
308 
309     /**
310      * @hide
311      */
312     @IntDef(prefix = { "REJECT_REASON_" },
313             value = {REJECT_REASON_DECLINED, REJECT_REASON_UNWANTED})
314     @Retention(RetentionPolicy.SOURCE)
315     public @interface RejectReason {};
316 
317     public static class Details {
318         /** @hide */
319         @Retention(RetentionPolicy.SOURCE)
320         @IntDef(
321                 prefix = { "DIRECTION_" },
322                 value = {DIRECTION_UNKNOWN, DIRECTION_INCOMING, DIRECTION_OUTGOING})
323         public @interface CallDirection {}
324 
325         /**
326          * Indicates that the call is neither and incoming nor an outgoing call.  This can be the
327          * case for calls reported directly by a {@link ConnectionService} in special cases such as
328          * call handovers.
329          */
330         public static final int DIRECTION_UNKNOWN = -1;
331 
332         /**
333          * Indicates that the call is an incoming call.
334          */
335         public static final int DIRECTION_INCOMING = 0;
336 
337         /**
338          * Indicates that the call is an outgoing call.
339          */
340         public static final int DIRECTION_OUTGOING = 1;
341 
342         /** Call can currently be put on hold or unheld. */
343         public static final int CAPABILITY_HOLD = 0x00000001;
344 
345         /** Call supports the hold feature. */
346         public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
347 
348         /**
349          * Calls within a conference can be merged. A {@link ConnectionService} has the option to
350          * add a {@link Conference} call before the child {@link Connection}s are merged. This is how
351          * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
352          * capability allows a merge button to be shown while the conference call is in the foreground
353          * of the in-call UI.
354          * <p>
355          * This is only intended for use by a {@link Conference}.
356          */
357         public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
358 
359         /**
360          * Calls within a conference can be swapped between foreground and background.
361          * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
362          * <p>
363          * This is only intended for use by a {@link Conference}.
364          */
365         public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
366 
367         /**
368          * @hide
369          */
370         public static final int CAPABILITY_UNUSED_1 = 0x00000010;
371 
372         /** Call supports responding via text option. */
373         public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
374 
375         /** Call can be muted. */
376         public static final int CAPABILITY_MUTE = 0x00000040;
377 
378         /**
379          * Call supports conference call management. This capability only applies to {@link Conference}
380          * calls which can have {@link Connection}s as children.
381          */
382         public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
383 
384         /**
385          * Local device supports receiving video.
386          */
387         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
388 
389         /**
390          * Local device supports transmitting video.
391          */
392         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
393 
394         /**
395          * Local device supports bidirectional video calling.
396          */
397         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
398                 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
399 
400         /**
401          * Remote device supports receiving video.
402          */
403         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
404 
405         /**
406          * Remote device supports transmitting video.
407          */
408         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
409 
410         /**
411          * Remote device supports bidirectional video calling.
412          */
413         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
414                 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
415 
416         /**
417          * Call is able to be separated from its parent {@code Conference}, if any.
418          */
419         public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
420 
421         /**
422          * Call is able to be individually disconnected when in a {@code Conference}.
423          */
424         public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
425 
426         /**
427          * Speed up audio setup for MT call.
428          * @hide
429          */
430         public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
431 
432         /**
433          * Call can be upgraded to a video call.
434          * @hide
435          * @deprecated Use {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
436          * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL} to indicate for a call
437          * whether or not video calling is supported.
438          */
439         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 119305590)
440         public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
441 
442         /**
443          * For video calls, indicates whether the outgoing video for the call can be paused using
444          * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
445          */
446         public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
447 
448         /**
449          * Call sends responses through connection.
450          * @hide
451          */
452         public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000;
453 
454         /**
455          * When set, prevents a video {@code Call} from being downgraded to an audio-only call.
456          * <p>
457          * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
458          * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
459          * downgraded from a video call back to a VideoState of
460          * {@link VideoProfile#STATE_AUDIO_ONLY}.
461          * <p>
462          * Intuitively, a call which can be downgraded to audio should also have local and remote
463          * video
464          * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
465          * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
466          */
467         public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000;
468 
469         /**
470          * When set for an external call, indicates that this {@code Call} can be pulled from a
471          * remote device to the current device.
472          * <p>
473          * Should only be set on a {@code Call} where {@link #PROPERTY_IS_EXTERNAL_CALL} is set.
474          * <p>
475          * An {@link InCallService} will only see calls with this capability if it has the
476          * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
477          * in its manifest.
478          * <p>
479          * See {@link Connection#CAPABILITY_CAN_PULL_CALL} and
480          * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
481          */
482         public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
483 
484         /** Call supports the deflect feature. */
485         public static final int CAPABILITY_SUPPORT_DEFLECT = 0x01000000;
486 
487         /**
488          * Call supports adding participants to the call via
489          * {@link #addConferenceParticipants(List)}. Once participants are added, the call becomes
490          * an adhoc conference call ({@link #PROPERTY_IS_ADHOC_CONFERENCE}).
491          */
492         public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000;
493 
494         /**
495          * When set for a call, indicates that this {@code Call} can be transferred to another
496          * number.
497          * Call supports the confirmed and unconfirmed call transfer feature.
498          *
499          * @hide
500          */
501         public static final int CAPABILITY_TRANSFER = 0x04000000;
502 
503         /**
504          * When set for a call, indicates that this {@code Call} can be transferred to another
505          * ongoing call.
506          * Call supports the consultative call transfer feature.
507          *
508          * @hide
509          */
510         public static final int CAPABILITY_TRANSFER_CONSULTATIVE = 0x08000000;
511 
512         /**
513          * Indicates whether the remote party supports RTT or not to the UI.
514          */
515 
516         public static final int CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT = 0x10000000;
517 
518         //******************************************************************************************
519         // Next CAPABILITY value: 0x20000000
520         //******************************************************************************************
521 
522         /**
523          * Whether the call is currently a conference.
524          */
525         public static final int PROPERTY_CONFERENCE = 0x00000001;
526 
527         /**
528          * Whether the call is a generic conference, where we do not know the precise state of
529          * participants in the conference (eg. on CDMA).
530          */
531         public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002;
532 
533         /**
534          * Whether the call is made while the device is in emergency callback mode.
535          */
536         public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004;
537 
538         /**
539          * Connection is using WIFI.
540          */
541         public static final int PROPERTY_WIFI = 0x00000008;
542 
543         /**
544          * When set, the UI should indicate to the user that a call is using high definition
545          * audio.
546          * <p>
547          * The underlying {@link ConnectionService} is responsible for reporting this
548          * property.  It is important to note that this property is not intended to report the
549          * actual audio codec being used for a Call, but whether the call should be indicated
550          * to the user as high definition.
551          * <p>
552          * The Android Telephony stack reports this property for calls based on a number
553          * of factors, including which audio codec is used and whether a call is using an HD
554          * codec end-to-end.  Some mobile operators choose to suppress display of an HD indication,
555          * and in these cases this property will not be set for a call even if the underlying audio
556          * codec is in fact "high definition".
557          */
558         public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
559 
560         /**
561          * Whether the call is associated with the work profile.
562          */
563         public static final int PROPERTY_ENTERPRISE_CALL = 0x00000020;
564 
565         /**
566          * When set, indicates that this {@code Call} does not actually exist locally for the
567          * {@link ConnectionService}.
568          * <p>
569          * Consider, for example, a scenario where a user has two phones with the same phone number.
570          * When a user places a call on one device, the telephony stack can represent that call on
571          * the other device by adding it to the {@link ConnectionService} with the
572          * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property set.
573          * <p>
574          * An {@link InCallService} will only see calls with this property if it has the
575          * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
576          * in its manifest.
577          * <p>
578          * See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
579          */
580         public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040;
581 
582         /**
583          * Indicates that the call has CDMA Enhanced Voice Privacy enabled.
584          */
585         public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 0x00000080;
586 
587         /**
588          * Indicates that the call is from a self-managed {@link ConnectionService}.
589          * <p>
590          * See also {@link Connection#PROPERTY_SELF_MANAGED}
591          */
592         public static final int PROPERTY_SELF_MANAGED = 0x00000100;
593 
594         /**
595          * Indicates the call used Assisted Dialing.
596          *
597          * @see TelecomManager#EXTRA_USE_ASSISTED_DIALING
598          */
599         public static final int PROPERTY_ASSISTED_DIALING = 0x00000200;
600 
601         /**
602          * Indicates that the call is an RTT call. Use {@link #getRttCall()} to get the
603          * {@link RttCall} object that is used to send and receive text.
604          */
605         public static final int PROPERTY_RTT = 0x00000400;
606 
607         /**
608          * Indicates that the call has been identified as the network as an emergency call. This
609          * property may be set for both incoming and outgoing calls which the network identifies as
610          * emergency calls.
611          */
612         public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 0x00000800;
613 
614         /**
615          * Indicates that the call is using VoIP audio mode.
616          * <p>
617          * When this property is set, the {@link android.media.AudioManager} audio mode for this
618          * call will be {@link android.media.AudioManager#MODE_IN_COMMUNICATION}.  When this
619          * property is not set, the audio mode for this call will be
620          * {@link android.media.AudioManager#MODE_IN_CALL}.
621          * <p>
622          * This property reflects changes made using {@link Connection#setAudioModeIsVoip(boolean)}.
623          * <p>
624          * You can use this property to determine whether an un-answered incoming call or a held
625          * call will use VoIP audio mode (if the call does not currently have focus, the system
626          * audio mode may not reflect the mode the call will use).
627          */
628         public static final int PROPERTY_VOIP_AUDIO_MODE = 0x00001000;
629 
630         /**
631          * Indicates that the call is an adhoc conference call. This property can be set for both
632          * incoming and outgoing calls. An adhoc conference call is formed using
633          * {@link #addConferenceParticipants(List)},
634          * {@link TelecomManager#addNewIncomingConference(PhoneAccountHandle, Bundle)}, or
635          * {@link TelecomManager#startConference(List, Bundle)}, rather than by merging existing
636          * call using {@link #conference(Call)}.
637          */
638         public static final int PROPERTY_IS_ADHOC_CONFERENCE = 0x00002000;
639 
640         /**
641          * Connection is using cross sim technology.
642          * <p>
643          * Indicates that the {@link Connection} is using a cross sim technology which would
644          * register IMS over internet APN of default data subscription.
645          * <p>
646          */
647         public static final int PROPERTY_CROSS_SIM = 0x00004000;
648 
649         /**
650          * The connection is using transactional call APIs.
651          * <p>
652          * The underlying connection was added as a transactional call via the
653          * {@link TelecomManager#addCall} API.
654          */
655         @FlaggedApi(Flags.FLAG_VOIP_APP_ACTIONS_SUPPORT)
656         public static final int PROPERTY_IS_TRANSACTIONAL = 0x00008000;
657 
658         //******************************************************************************************
659         // Next PROPERTY value: 0x00010000
660         //******************************************************************************************
661 
662         private final @CallState int mState;
663         private final String mTelecomCallId;
664         private final Uri mHandle;
665         private final int mHandlePresentation;
666         private final String mCallerDisplayName;
667         private final int mCallerDisplayNamePresentation;
668         private final PhoneAccountHandle mAccountHandle;
669         private final int mCallCapabilities;
670         private final int mCallProperties;
671         private final int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
672         private final DisconnectCause mDisconnectCause;
673         private final long mConnectTimeMillis;
674         private final GatewayInfo mGatewayInfo;
675         private final int mVideoState;
676         private final StatusHints mStatusHints;
677         private final Bundle mExtras;
678         private final Bundle mIntentExtras;
679         private final long mCreationTimeMillis;
680         private final String mContactDisplayName;
681         private final @CallDirection int mCallDirection;
682         private final @Connection.VerificationStatus int mCallerNumberVerificationStatus;
683         private final Uri mContactPhotoUri;
684         private final UserHandle mAssociatedUser;
685 
686         /**
687          * Whether the supplied capabilities  supports the specified capability.
688          *
689          * @param capabilities A bit field of capabilities.
690          * @param capability The capability to check capabilities for.
691          * @return Whether the specified capability is supported.
692          */
can(int capabilities, int capability)693         public static boolean can(int capabilities, int capability) {
694             return (capabilities & capability) == capability;
695         }
696 
697         /**
698          * Whether the capabilities of this {@code Details} supports the specified capability.
699          *
700          * @param capability The capability to check capabilities for.
701          * @return Whether the specified capability is supported.
702          */
can(int capability)703         public boolean can(int capability) {
704             return can(mCallCapabilities, capability);
705         }
706 
707         /**
708          * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
709          *
710          * @param capabilities A capability bit field.
711          * @return A human readable string representation.
712          */
capabilitiesToString(int capabilities)713         public static String capabilitiesToString(int capabilities) {
714             StringBuilder builder = new StringBuilder();
715             builder.append("[Capabilities:");
716             if (can(capabilities, CAPABILITY_HOLD)) {
717                 builder.append(" CAPABILITY_HOLD");
718             }
719             if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
720                 builder.append(" CAPABILITY_SUPPORT_HOLD");
721             }
722             if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
723                 builder.append(" CAPABILITY_MERGE_CONFERENCE");
724             }
725             if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
726                 builder.append(" CAPABILITY_SWAP_CONFERENCE");
727             }
728             if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
729                 builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
730             }
731             if (can(capabilities, CAPABILITY_MUTE)) {
732                 builder.append(" CAPABILITY_MUTE");
733             }
734             if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
735                 builder.append(" CAPABILITY_MANAGE_CONFERENCE");
736             }
737             if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
738                 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
739             }
740             if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
741                 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
742             }
743             if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
744                 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
745             }
746             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
747                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
748             }
749             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
750                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
751             }
752             if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
753                 builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
754             }
755             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
756                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
757             }
758             if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
759                 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
760             }
761             if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
762                 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
763             }
764             if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
765                 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
766             }
767             if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
768                 builder.append(" CAPABILITY_CAN_PULL_CALL");
769             }
770             if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) {
771                 builder.append(" CAPABILITY_SUPPORT_DEFLECT");
772             }
773             if (can(capabilities, CAPABILITY_ADD_PARTICIPANT)) {
774                 builder.append(" CAPABILITY_ADD_PARTICIPANT");
775             }
776             if (can(capabilities, CAPABILITY_TRANSFER)) {
777                 builder.append(" CAPABILITY_TRANSFER");
778             }
779             if (can(capabilities, CAPABILITY_TRANSFER_CONSULTATIVE)) {
780                 builder.append(" CAPABILITY_TRANSFER_CONSULTATIVE");
781             }
782             if (can(capabilities, CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT)) {
783                 builder.append(" CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT");
784             }
785             builder.append("]");
786             return builder.toString();
787         }
788 
789         /**
790          * Whether the supplied properties includes the specified property.
791          *
792          * @param properties A bit field of properties.
793          * @param property The property to check properties for.
794          * @return Whether the specified property is supported.
795          */
hasProperty(int properties, int property)796         public static boolean hasProperty(int properties, int property) {
797             return (properties & property) == property;
798         }
799 
800         /**
801          * Whether the properties of this {@code Details} includes the specified property.
802          *
803          * @param property The property to check properties for.
804          * @return Whether the specified property is supported.
805          */
hasProperty(int property)806         public boolean hasProperty(int property) {
807             return hasProperty(mCallProperties, property);
808         }
809 
810         /**
811          * Render a set of property bits ({@code PROPERTY_*}) as a human readable string.
812          *
813          * @param properties A property bit field.
814          * @return A human readable string representation.
815          */
propertiesToString(int properties)816         public static String propertiesToString(int properties) {
817             StringBuilder builder = new StringBuilder();
818             builder.append("[Properties:");
819             if (hasProperty(properties, PROPERTY_CONFERENCE)) {
820                 builder.append(" PROPERTY_CONFERENCE");
821             }
822             if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) {
823                 builder.append(" PROPERTY_GENERIC_CONFERENCE");
824             }
825             if (hasProperty(properties, PROPERTY_WIFI)) {
826                 builder.append(" PROPERTY_WIFI");
827             }
828             if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) {
829                 builder.append(" PROPERTY_HIGH_DEF_AUDIO");
830             }
831             if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
832                 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
833             }
834             if (hasProperty(properties, PROPERTY_IS_EXTERNAL_CALL)) {
835                 builder.append(" PROPERTY_IS_EXTERNAL_CALL");
836             }
837             if (hasProperty(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
838                 builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY");
839             }
840             if (hasProperty(properties, PROPERTY_ASSISTED_DIALING)) {
841                 builder.append(" PROPERTY_ASSISTED_DIALING_USED");
842             }
843             if (hasProperty(properties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)) {
844                 builder.append(" PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL");
845             }
846             if (hasProperty(properties, PROPERTY_RTT)) {
847                 builder.append(" PROPERTY_RTT");
848             }
849             if (hasProperty(properties, PROPERTY_VOIP_AUDIO_MODE)) {
850                 builder.append(" PROPERTY_VOIP_AUDIO_MODE");
851             }
852             if (hasProperty(properties, PROPERTY_IS_ADHOC_CONFERENCE)) {
853                 builder.append(" PROPERTY_IS_ADHOC_CONFERENCE");
854             }
855             if (hasProperty(properties, PROPERTY_CROSS_SIM)) {
856                 builder.append(" PROPERTY_CROSS_SIM");
857             }
858             if (hasProperty(properties, PROPERTY_IS_TRANSACTIONAL)) {
859                 builder.append(" PROPERTY_IS_TRANSACTIONAL");
860             }
861             builder.append("]");
862             return builder.toString();
863         }
864 
865         /**
866          * @return the state of the {@link Call} represented by this {@link Call.Details}.
867          */
getState()868         public final @CallState int getState() {
869             return mState;
870         }
871 
872         /**
873          * @return the Telecom identifier associated with this {@link Call} . This is not a stable
874          * identifier and is not guaranteed to be unique across device reboots.
875          */
876         @FlaggedApi(Flags.FLAG_CALL_DETAILS_ID_CHANGES)
getId()877         public @NonNull String getId() { return mTelecomCallId; }
878 
879         /** {@hide} */
880         @TestApi
getTelecomCallId()881         public String getTelecomCallId() {
882             return mTelecomCallId;
883         }
884 
885         /**
886          * @return The handle (e.g., phone number) to which the {@code Call} is currently
887          * connected.
888          */
getHandle()889         public Uri getHandle() {
890             return mHandle;
891         }
892 
893         /**
894          * @return The presentation requirements for the handle. See
895          * {@link TelecomManager} for valid values.
896          */
getHandlePresentation()897         public int getHandlePresentation() {
898             return mHandlePresentation;
899         }
900 
901         /**
902          * @return The contact photo URI which corresponds to
903          * {@link android.provider.ContactsContract.PhoneLookup#PHOTO_URI}, or {@code null} if the
904          * lookup is not yet complete, if there's no contacts entry for the caller,
905          * or if the {@link InCallService} does not hold the
906          * {@link android.Manifest.permission#READ_CONTACTS} permission.
907          */
getContactPhotoUri()908         public @Nullable Uri getContactPhotoUri() {
909             return mContactPhotoUri;
910         }
911 
912         /**
913          * The display name for the caller.
914          * <p>
915          * This is the name as reported by the {@link ConnectionService} associated with this call.
916          *
917          * @return The display name for the caller.
918          */
getCallerDisplayName()919         public String getCallerDisplayName() {
920             return mCallerDisplayName;
921         }
922 
923         /**
924          * @return The presentation requirements for the caller display name. See
925          * {@link TelecomManager} for valid values.
926          */
getCallerDisplayNamePresentation()927         public int getCallerDisplayNamePresentation() {
928             return mCallerDisplayNamePresentation;
929         }
930 
931         /**
932          * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
933          * routed.
934          */
getAccountHandle()935         public PhoneAccountHandle getAccountHandle() {
936             return mAccountHandle;
937         }
938 
939         /**
940          * @return A bitmask of the capabilities of the {@code Call}, as defined by the various
941          *         {@code CAPABILITY_*} constants in this class.
942          */
getCallCapabilities()943         public int getCallCapabilities() {
944             return mCallCapabilities;
945         }
946 
947         /**
948          * @return A bitmask of the properties of the {@code Call}, as defined by the various
949          *         {@code PROPERTY_*} constants in this class.
950          */
getCallProperties()951         public int getCallProperties() {
952             return mCallProperties;
953         }
954 
955         /**
956          * @return a bitmask of the audio routes available for the call.
957          *
958          * @hide
959          */
getSupportedAudioRoutes()960         public int getSupportedAudioRoutes() {
961             return mSupportedAudioRoutes;
962         }
963 
964         /**
965          * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
966          * by {@link android.telecom.DisconnectCause}.
967          */
getDisconnectCause()968         public DisconnectCause getDisconnectCause() {
969             return mDisconnectCause;
970         }
971 
972         /**
973          * Returns the time the {@link Call} connected (i.e. became active).  This information is
974          * updated periodically, but user interfaces should not rely on this to display the "call
975          * time clock".  For the time when the call was first added to Telecom, see
976          * {@link #getCreationTimeMillis()}.
977          *
978          * @return The time the {@link Call} connected in milliseconds since the epoch.
979          */
getConnectTimeMillis()980         public final long getConnectTimeMillis() {
981             return mConnectTimeMillis;
982         }
983 
984         /**
985          * @return Information about any calling gateway the {@code Call} may be using.
986          */
getGatewayInfo()987         public GatewayInfo getGatewayInfo() {
988             return mGatewayInfo;
989         }
990 
991         /**
992          * @return The video state of the {@code Call}.
993          */
getVideoState()994         public int getVideoState() {
995             return mVideoState;
996         }
997 
998         /**
999          * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
1000          * have been set.
1001          */
getStatusHints()1002         public StatusHints getStatusHints() {
1003             return mStatusHints;
1004         }
1005 
1006         /**
1007          * @return The extras associated with this call.
1008          */
getExtras()1009         public Bundle getExtras() {
1010             return mExtras;
1011         }
1012 
1013         /**
1014          * @return The extras used with the original intent to place this call.
1015          */
getIntentExtras()1016         public Bundle getIntentExtras() {
1017             return mIntentExtras;
1018         }
1019 
1020         /**
1021          * Returns the time when the call was first created and added to Telecom.  This is the same
1022          * time that is logged as the start time in the Call Log (see
1023          * {@link android.provider.CallLog.Calls#DATE}).  To determine when the call was connected
1024          * (became active), see {@link #getConnectTimeMillis()}.
1025          *
1026          * @return The creation time of the call, in millis since the epoch.
1027          */
getCreationTimeMillis()1028         public long getCreationTimeMillis() {
1029             return mCreationTimeMillis;
1030         }
1031 
1032         /**
1033          * Returns the name of the caller on the remote end, as derived from a
1034          * {@link android.provider.ContactsContract} lookup of the call's handle.
1035          * @return The name of the caller, or {@code null} if the lookup is not yet complete, if
1036          *         there's no contacts entry for the caller, or if the {@link InCallService} does
1037          *         not hold the {@link android.Manifest.permission#READ_CONTACTS} permission.
1038          */
getContactDisplayName()1039         public @Nullable String getContactDisplayName() {
1040             return mContactDisplayName;
1041         }
1042 
1043         /**
1044          * Indicates whether the call is an incoming or outgoing call.
1045          * @return The call's direction.
1046          */
getCallDirection()1047         public @CallDirection int getCallDirection() {
1048             return mCallDirection;
1049         }
1050 
1051         /**
1052          * Gets the verification status for the phone number of an incoming call as identified in
1053          * ATIS-1000082.
1054          * <p>
1055          * For incoming calls, the number verification status indicates whether the device was
1056          * able to verify the authenticity of the calling number using the STIR process outlined
1057          * in ATIS-1000082.  {@link Connection#VERIFICATION_STATUS_NOT_VERIFIED} indicates that
1058          * the network was not able to use STIR to verify the caller's number (i.e. nothing is
1059          * known regarding the authenticity of the number.
1060          * {@link Connection#VERIFICATION_STATUS_PASSED} indicates that the network was able to
1061          * use STIR to verify the caller's number.  This indicates that the network has a high
1062          * degree of confidence that the incoming call actually originated from the indicated
1063          * number.  {@link Connection#VERIFICATION_STATUS_FAILED} indicates that the network's
1064          * STIR verification did not pass.  This indicates that the incoming call may not
1065          * actually be from the indicated number.  This could occur if, for example, the caller
1066          * is using an impersonated phone number.
1067          * <p>
1068          * A {@link CallScreeningService} can use this information to help determine if an
1069          * incoming call is potentially an unwanted call.  A verification status of
1070          * {@link Connection#VERIFICATION_STATUS_FAILED} indicates that an incoming call may not
1071          * actually be from the number indicated on the call (i.e. impersonated number) and that it
1072          * should potentially be blocked.  Likewise,
1073          * {@link Connection#VERIFICATION_STATUS_PASSED} can be used as a positive signal to
1074          * help clarify that the incoming call is originating from the indicated number and it
1075          * is less likely to be an undesirable call.
1076          * <p>
1077          * An {@link InCallService} can use this information to provide a visual indicator to the
1078          * user regarding the verification status of a call and to help identify calls from
1079          * potentially impersonated numbers.
1080          * @return the verification status.
1081          */
getCallerNumberVerificationStatus()1082         public @Connection.VerificationStatus int getCallerNumberVerificationStatus() {
1083             return mCallerNumberVerificationStatus;
1084         }
1085 
1086         /**
1087          * Gets the user that originated the call
1088          * @return The user
1089          *
1090          * @hide
1091          */
getAssociatedUser()1092         public UserHandle getAssociatedUser() {
1093             return mAssociatedUser;
1094         }
1095 
1096         @Override
equals(Object o)1097         public boolean equals(Object o) {
1098             if (o instanceof Details) {
1099                 Details d = (Details) o;
1100                 return
1101                         Objects.equals(mState, d.mState) &&
1102                         Objects.equals(mHandle, d.mHandle) &&
1103                         Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
1104                         Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
1105                         Objects.equals(mCallerDisplayNamePresentation,
1106                                 d.mCallerDisplayNamePresentation) &&
1107                         Objects.equals(mAccountHandle, d.mAccountHandle) &&
1108                         Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
1109                         Objects.equals(mCallProperties, d.mCallProperties) &&
1110                         Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
1111                         Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
1112                         Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
1113                         Objects.equals(mVideoState, d.mVideoState) &&
1114                         Objects.equals(mStatusHints, d.mStatusHints) &&
1115                         areBundlesEqual(mExtras, d.mExtras) &&
1116                         areBundlesEqual(mIntentExtras, d.mIntentExtras) &&
1117                         Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) &&
1118                         Objects.equals(mContactDisplayName, d.mContactDisplayName) &&
1119                         Objects.equals(mCallDirection, d.mCallDirection) &&
1120                         Objects.equals(mCallerNumberVerificationStatus,
1121                                 d.mCallerNumberVerificationStatus) &&
1122                         Objects.equals(mContactPhotoUri, d.mContactPhotoUri) &&
1123                         Objects.equals(mAssociatedUser, d.mAssociatedUser);
1124             }
1125             return false;
1126         }
1127 
1128         @Override
hashCode()1129         public int hashCode() {
1130             return Objects.hash(mState,
1131                             mHandle,
1132                             mHandlePresentation,
1133                             mCallerDisplayName,
1134                             mCallerDisplayNamePresentation,
1135                             mAccountHandle,
1136                             mCallCapabilities,
1137                             mCallProperties,
1138                             mDisconnectCause,
1139                             mConnectTimeMillis,
1140                             mGatewayInfo,
1141                             mVideoState,
1142                             mStatusHints,
1143                             mExtras,
1144                             mIntentExtras,
1145                             mCreationTimeMillis,
1146                             mContactDisplayName,
1147                             mCallDirection,
1148                             mCallerNumberVerificationStatus,
1149                             mContactPhotoUri,
1150                     mAssociatedUser);
1151         }
1152 
1153         /** {@hide} */
Details( @allState int state, String telecomCallId, Uri handle, int handlePresentation, String callerDisplayName, int callerDisplayNamePresentation, PhoneAccountHandle accountHandle, int capabilities, int properties, DisconnectCause disconnectCause, long connectTimeMillis, GatewayInfo gatewayInfo, int videoState, StatusHints statusHints, Bundle extras, Bundle intentExtras, long creationTimeMillis, String contactDisplayName, int callDirection, int callerNumberVerificationStatus, Uri contactPhotoUri, UserHandle originatingUser)1154         public Details(
1155                 @CallState int state,
1156                 String telecomCallId,
1157                 Uri handle,
1158                 int handlePresentation,
1159                 String callerDisplayName,
1160                 int callerDisplayNamePresentation,
1161                 PhoneAccountHandle accountHandle,
1162                 int capabilities,
1163                 int properties,
1164                 DisconnectCause disconnectCause,
1165                 long connectTimeMillis,
1166                 GatewayInfo gatewayInfo,
1167                 int videoState,
1168                 StatusHints statusHints,
1169                 Bundle extras,
1170                 Bundle intentExtras,
1171                 long creationTimeMillis,
1172                 String contactDisplayName,
1173                 int callDirection,
1174                 int callerNumberVerificationStatus,
1175                 Uri contactPhotoUri,
1176                 UserHandle originatingUser) {
1177             mState = state;
1178             mTelecomCallId = telecomCallId;
1179             mHandle = handle;
1180             mHandlePresentation = handlePresentation;
1181             mCallerDisplayName = callerDisplayName;
1182             mCallerDisplayNamePresentation = callerDisplayNamePresentation;
1183             mAccountHandle = accountHandle;
1184             mCallCapabilities = capabilities;
1185             mCallProperties = properties;
1186             mDisconnectCause = disconnectCause;
1187             mConnectTimeMillis = connectTimeMillis;
1188             mGatewayInfo = gatewayInfo;
1189             mVideoState = videoState;
1190             mStatusHints = statusHints;
1191             mExtras = extras;
1192             mIntentExtras = intentExtras;
1193             mCreationTimeMillis = creationTimeMillis;
1194             mContactDisplayName = contactDisplayName;
1195             mCallDirection = callDirection;
1196             mCallerNumberVerificationStatus = callerNumberVerificationStatus;
1197             mContactPhotoUri = contactPhotoUri;
1198             mAssociatedUser = originatingUser;
1199         }
1200 
1201         /** {@hide} */
createFromParcelableCall(ParcelableCall parcelableCall)1202         public static Details createFromParcelableCall(ParcelableCall parcelableCall) {
1203             return new Details(
1204                     parcelableCall.getState(),
1205                     parcelableCall.getId(),
1206                     parcelableCall.getHandle(),
1207                     parcelableCall.getHandlePresentation(),
1208                     parcelableCall.getCallerDisplayName(),
1209                     parcelableCall.getCallerDisplayNamePresentation(),
1210                     parcelableCall.getAccountHandle(),
1211                     parcelableCall.getCapabilities(),
1212                     parcelableCall.getProperties(),
1213                     parcelableCall.getDisconnectCause(),
1214                     parcelableCall.getConnectTimeMillis(),
1215                     parcelableCall.getGatewayInfo(),
1216                     parcelableCall.getVideoState(),
1217                     parcelableCall.getStatusHints(),
1218                     parcelableCall.getExtras(),
1219                     parcelableCall.getIntentExtras(),
1220                     parcelableCall.getCreationTimeMillis(),
1221                     parcelableCall.getContactDisplayName(),
1222                     parcelableCall.getCallDirection(),
1223                     parcelableCall.getCallerNumberVerificationStatus(),
1224                     parcelableCall.getContactPhotoUri(),
1225                     parcelableCall.getAssociatedUser()
1226             );
1227         }
1228 
1229         @Override
toString()1230         public String toString() {
1231             StringBuilder sb = new StringBuilder();
1232             sb.append("[id: ");
1233             sb.append(mTelecomCallId);
1234             sb.append(", state: ");
1235             sb.append(Call.stateToString(mState));
1236             sb.append(", pa: ");
1237             sb.append(mAccountHandle);
1238             sb.append(", hdl: ");
1239             sb.append(Log.piiHandle(mHandle));
1240             sb.append(", hdlPres: ");
1241             sb.append(mHandlePresentation);
1242             sb.append(", videoState: ");
1243             sb.append(VideoProfile.videoStateToString(mVideoState));
1244             sb.append(", caps: ");
1245             sb.append(capabilitiesToString(mCallCapabilities));
1246             sb.append(", props: ");
1247             sb.append(propertiesToString(mCallProperties));
1248             sb.append("]");
1249             return sb.toString();
1250         }
1251     }
1252 
1253     /**
1254      * Defines callbacks which inform the {@link InCallService} of changes to a {@link Call}.
1255      * These callbacks can originate from the Telecom framework, or a {@link ConnectionService}
1256      * implementation.
1257      * <p>
1258      * You can handle these callbacks by extending the {@link Callback} class and overriding the
1259      * callbacks that your {@link InCallService} is interested in.  The callback methods include the
1260      * {@link Call} for which the callback applies, allowing reuse of a single instance of your
1261      * {@link Callback} implementation, if desired.
1262      * <p>
1263      * Use {@link Call#registerCallback(Callback)} to register your callback(s).  Ensure
1264      * {@link Call#unregisterCallback(Callback)} is called when you no longer require callbacks
1265      * (typically in {@link InCallService#onCallRemoved(Call)}).
1266      * Note: Callbacks which occur before you call {@link Call#registerCallback(Callback)} will not
1267      * reach your implementation of {@link Callback}, so it is important to register your callback
1268      * as soon as your {@link InCallService} is notified of a new call via
1269      * {@link InCallService#onCallAdded(Call)}.
1270      */
1271     public static abstract class Callback {
1272         /**
1273          * @hide
1274          */
1275         @IntDef(prefix = { "HANDOVER_" },
1276                 value = {HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_NOT_SUPPORTED,
1277                 HANDOVER_FAILURE_USER_REJECTED, HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL,
1278                 HANDOVER_FAILURE_UNKNOWN})
1279         @Retention(RetentionPolicy.SOURCE)
1280         public @interface HandoverFailureErrors {}
1281 
1282         /**
1283          * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the app
1284          * to handover the call to rejects the handover request.
1285          * <p>
1286          * Will be returned when {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} is called
1287          * and the destination {@link PhoneAccountHandle}'s {@link ConnectionService} returns a
1288          * {@code null} {@link Connection} from
1289          * {@link ConnectionService#onCreateOutgoingHandoverConnection(PhoneAccountHandle,
1290          * ConnectionRequest)}.
1291          * <p>
1292          * For more information on call handovers, see
1293          * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
1294          */
1295         public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1;
1296 
1297         /**
1298          * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when a handover
1299          * is initiated but the source or destination app does not support handover.
1300          * <p>
1301          * Will be returned when a handover is requested via
1302          * {@link #handoverTo(PhoneAccountHandle, int, Bundle)} and the destination
1303          * {@link PhoneAccountHandle} does not declare
1304          * {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_TO}.  May also be returned when a handover is
1305          * requested at the {@link PhoneAccountHandle} for the current call (i.e. the source call's
1306          * {@link Details#getAccountHandle()}) does not declare
1307          * {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_FROM}.
1308          * <p>
1309          * For more information on call handovers, see
1310          * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
1311          */
1312         public static final int HANDOVER_FAILURE_NOT_SUPPORTED = 2;
1313 
1314         /**
1315          * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the remote
1316          * user rejects the handover request.
1317          * <p>
1318          * For more information on call handovers, see
1319          * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
1320          */
1321         public static final int HANDOVER_FAILURE_USER_REJECTED = 3;
1322 
1323         /**
1324          * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there
1325          * is ongoing emergency call.
1326          * <p>
1327          * This error code is returned when {@link #handoverTo(PhoneAccountHandle, int, Bundle)} is
1328          * called on an emergency call, or if any other call is an emergency call.
1329          * <p>
1330          * Handovers are not permitted while there are ongoing emergency calls.
1331          * <p>
1332          * For more information on call handovers, see
1333          * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
1334          */
1335         public static final int HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL = 4;
1336 
1337         /**
1338          * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when a handover
1339          * fails for an unknown reason.
1340          * <p>
1341          * For more information on call handovers, see
1342          * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
1343          */
1344         public static final int HANDOVER_FAILURE_UNKNOWN = 5;
1345 
1346         /**
1347          * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
1348          *
1349          * @param call The {@code Call} invoking this method.
1350          * @param state The new state of the {@code Call}.
1351          */
onStateChanged(Call call, @CallState int state)1352         public void onStateChanged(Call call, @CallState int state) {}
1353 
1354         /**
1355          * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
1356          *
1357          * @param call The {@code Call} invoking this method.
1358          * @param parent The new parent of the {@code Call}.
1359          */
onParentChanged(Call call, Call parent)1360         public void onParentChanged(Call call, Call parent) {}
1361 
1362         /**
1363          * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
1364          *
1365          * @param call The {@code Call} invoking this method.
1366          * @param children The new children of the {@code Call}.
1367          */
onChildrenChanged(Call call, List<Call> children)1368         public void onChildrenChanged(Call call, List<Call> children) {}
1369 
1370         /**
1371          * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
1372          *
1373          * @param call The {@code Call} invoking this method.
1374          * @param details A {@code Details} object describing the {@code Call}.
1375          */
onDetailsChanged(Call call, Details details)1376         public void onDetailsChanged(Call call, Details details) {}
1377 
1378         /**
1379          * Invoked when the text messages that can be used as responses to the incoming
1380          * {@code Call} are loaded from the relevant database.
1381          * See {@link #getCannedTextResponses()}.
1382          *
1383          * @param call The {@code Call} invoking this method.
1384          * @param cannedTextResponses The text messages useable as responses.
1385          */
onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses)1386         public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
1387 
1388         /**
1389          * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
1390          * character. This causes the post-dial signals to stop pending user confirmation. An
1391          * implementation should present this choice to the user and invoke
1392          * {@link #postDialContinue(boolean)} when the user makes the choice.
1393          *
1394          * @param call The {@code Call} invoking this method.
1395          * @param remainingPostDialSequence The post-dial characters that remain to be sent.
1396          */
onPostDialWait(Call call, String remainingPostDialSequence)1397         public void onPostDialWait(Call call, String remainingPostDialSequence) {}
1398 
1399         /**
1400          * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
1401          *
1402          * @param call The {@code Call} invoking this method.
1403          * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
1404          */
onVideoCallChanged(Call call, InCallService.VideoCall videoCall)1405         public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
1406 
1407         /**
1408          * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
1409          * up their UI for the {@code Call} in response to state transitions. Specifically,
1410          * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
1411          * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
1412          * clients should wait for this method to be invoked.
1413          *
1414          * @param call The {@code Call} being destroyed.
1415          */
onCallDestroyed(Call call)1416         public void onCallDestroyed(Call call) {}
1417 
1418         /**
1419          * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
1420          * conferenced.
1421          *
1422          * @param call The {@code Call} being updated.
1423          * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
1424          *          conferenced.
1425          */
onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls)1426         public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
1427 
1428         /**
1429          * Invoked when a {@link Call} receives an event from its associated {@link Connection} or
1430          * {@link Conference}.
1431          * <p>
1432          * Where possible, the Call should make an attempt to handle {@link Connection} events which
1433          * are part of the {@code android.telecom.*} namespace.  The Call should ignore any events
1434          * it does not wish to handle.  Unexpected events should be handled gracefully, as it is
1435          * possible that a {@link ConnectionService} has defined its own Connection events which a
1436          * Call is not aware of.
1437          * <p>
1438          * See {@link Connection#sendConnectionEvent(String, Bundle)},
1439          * {@link Conference#sendConferenceEvent(String, Bundle)}.
1440          *
1441          * @param call The {@code Call} receiving the event.
1442          * @param event The event.
1443          * @param extras Extras associated with the connection event.
1444          */
onConnectionEvent(Call call, String event, Bundle extras)1445         public void onConnectionEvent(Call call, String event, Bundle extras) {}
1446 
1447         /**
1448          * Invoked when the RTT mode changes for this call.
1449          * @param call The call whose RTT mode has changed.
1450          * @param mode the new RTT mode, one of
1451          * {@link RttCall#RTT_MODE_FULL}, {@link RttCall#RTT_MODE_HCO},
1452          *             or {@link RttCall#RTT_MODE_VCO}
1453          */
onRttModeChanged(Call call, int mode)1454         public void onRttModeChanged(Call call, int mode) {}
1455 
1456         /**
1457          * Invoked when the call's RTT status changes, either from off to on or from on to off.
1458          * @param call The call whose RTT status has changed.
1459          * @param enabled whether RTT is now enabled or disabled
1460          * @param rttCall the {@link RttCall} object to use for reading and writing if RTT is now
1461          *                on, null otherwise.
1462          */
onRttStatusChanged(Call call, boolean enabled, RttCall rttCall)1463         public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {}
1464 
1465         /**
1466          * Invoked when the remote end of the connection has requested that an RTT communication
1467          * channel be opened. A response to this should be sent via {@link #respondToRttRequest}
1468          * with the same ID that this method is invoked with.
1469          * @param call The call which the RTT request was placed on
1470          * @param id The ID of the request.
1471          */
onRttRequest(Call call, int id)1472         public void onRttRequest(Call call, int id) {}
1473 
1474         /**
1475          * Invoked when the RTT session failed to initiate for some reason, including rejection
1476          * by the remote party.
1477          * <p>
1478          * This callback will ONLY be invoked to report a failure related to a user initiated
1479          * session modification request (i.e. {@link Call#sendRttRequest()}).
1480          * <p>
1481          * If a call is initiated with {@link TelecomManager#EXTRA_START_CALL_WITH_RTT} specified,
1482          * the availability of RTT can be determined by checking {@link Details#PROPERTY_RTT}
1483          * once the call enters state {@link Details#STATE_ACTIVE}.
1484          *
1485          * @param call The call which the RTT initiation failure occurred on.
1486          * @param reason One of the status codes defined in
1487          *      {@link android.telecom.Connection.RttModifyStatus}, with the exception of
1488          *      {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
1489          */
onRttInitiationFailure(Call call, @android.telecom.Connection.RttModifyStatus.RttSessionModifyStatus int reason)1490         public void onRttInitiationFailure(Call call,
1491                 @android.telecom.Connection.RttModifyStatus.RttSessionModifyStatus int reason) {}
1492 
1493         /**
1494          * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
1495          * has completed successfully.
1496          * <p>
1497          * For a full discussion of the handover process and the APIs involved, see
1498          * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
1499          *
1500          * @param call The call which had initiated handover.
1501          */
onHandoverComplete(Call call)1502         public void onHandoverComplete(Call call) {}
1503 
1504         /**
1505          * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
1506          * has failed.
1507          * <p>
1508          * For a full discussion of the handover process and the APIs involved, see
1509          * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
1510          *
1511          * @param call The call which had initiated handover.
1512          * @param failureReason Error reason for failure.
1513          */
onHandoverFailed(Call call, @HandoverFailureErrors int failureReason)1514         public void onHandoverFailed(Call call, @HandoverFailureErrors int failureReason) {}
1515     }
1516 
1517     /**
1518      * A class that holds the state that describes the state of the RTT channel to the remote
1519      * party, if it is active.
1520      */
1521     public static final class RttCall {
1522         /** @hide */
1523         @Retention(RetentionPolicy.SOURCE)
1524         @IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
1525         public @interface RttAudioMode {}
1526 
1527         /**
1528          * For metrics use. Default value in the proto.
1529          * @hide
1530          */
1531         public static final int RTT_MODE_INVALID = 0;
1532 
1533         /**
1534          * Indicates that there should be a bidirectional audio stream between the two parties
1535          * on the call.
1536          */
1537         public static final int RTT_MODE_FULL = 1;
1538 
1539         /**
1540          * Indicates that the local user should be able to hear the audio stream from the remote
1541          * user, but not vice versa. Equivalent to muting the microphone.
1542          */
1543         public static final int RTT_MODE_HCO = 2;
1544 
1545         /**
1546          * Indicates that the remote user should be able to hear the audio stream from the local
1547          * user, but not vice versa. Equivalent to setting the volume to zero.
1548          */
1549         public static final int RTT_MODE_VCO = 3;
1550 
1551         private static final int READ_BUFFER_SIZE = 1000;
1552 
1553         private InputStreamReader mReceiveStream;
1554         private OutputStreamWriter mTransmitStream;
1555         private int mRttMode;
1556         private final InCallAdapter mInCallAdapter;
1557         private final String mTelecomCallId;
1558         private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
1559 
1560         /**
1561          * @hide
1562          */
RttCall(String telecomCallId, InputStreamReader receiveStream, OutputStreamWriter transmitStream, int mode, InCallAdapter inCallAdapter)1563         public RttCall(String telecomCallId, InputStreamReader receiveStream,
1564                 OutputStreamWriter transmitStream, int mode, InCallAdapter inCallAdapter) {
1565             mTelecomCallId = telecomCallId;
1566             mReceiveStream = receiveStream;
1567             mTransmitStream = transmitStream;
1568             mRttMode = mode;
1569             mInCallAdapter = inCallAdapter;
1570         }
1571 
1572         /**
1573          * Returns the current RTT audio mode.
1574          * @return Current RTT audio mode. One of {@link #RTT_MODE_FULL}, {@link #RTT_MODE_VCO}, or
1575          * {@link #RTT_MODE_HCO}.
1576          */
getRttAudioMode()1577         public int getRttAudioMode() {
1578             return mRttMode;
1579         }
1580 
1581         /**
1582          * Sets the RTT audio mode. The requested mode change will be communicated through
1583          * {@link Callback#onRttModeChanged(Call, int)}.
1584          * @param mode The desired RTT audio mode, one of {@link #RTT_MODE_FULL},
1585          * {@link #RTT_MODE_VCO}, or {@link #RTT_MODE_HCO}.
1586          */
setRttMode(@ttAudioMode int mode)1587         public void setRttMode(@RttAudioMode int mode) {
1588             mInCallAdapter.setRttMode(mTelecomCallId, mode);
1589         }
1590 
1591         /**
1592          * Writes the string {@param input} into the outgoing text stream for this RTT call. Since
1593          * RTT transmits text in real-time, this method should be called once for each user action.
1594          * For example, when the user enters text as discrete characters using the keyboard, this
1595          * method should be called once for each character. However, if the user enters text by
1596          * pasting or autocomplete, the entire contents of the pasted or autocompleted text should
1597          * be sent in one call to this method.
1598          *
1599          * This method is not thread-safe -- calling it from multiple threads simultaneously may
1600          * lead to interleaved text.
1601          * @param input The message to send to the remote user.
1602          */
write(String input)1603         public void write(String input) throws IOException {
1604             mTransmitStream.write(input);
1605             mTransmitStream.flush();
1606         }
1607 
1608         /**
1609          * Reads a string from the remote user, blocking if there is no data available. Returns
1610          * {@code null} if the RTT conversation has been terminated and there is no further data
1611          * to read.
1612          *
1613          * This method is not thread-safe -- calling it from multiple threads simultaneously may
1614          * lead to interleaved text.
1615          * @return A string containing text sent by the remote user, or {@code null} if the
1616          * conversation has been terminated or if there was an error while reading.
1617          */
read()1618         public String read() {
1619             try {
1620                 int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
1621                 if (numRead < 0) {
1622                     return null;
1623                 }
1624                 return new String(mReadBuffer, 0, numRead);
1625             } catch (IOException e) {
1626                 Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
1627                 return null;
1628             }
1629         }
1630 
1631         /**
1632          * Non-blocking version of {@link #read()}. Returns {@code null} if there is nothing to
1633          * be read.
1634          * @return A string containing text entered by the user, or {@code null} if the user has
1635          * not entered any new text yet.
1636          */
readImmediately()1637         public String readImmediately() throws IOException {
1638             if (mReceiveStream.ready()) {
1639                 int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
1640                 if (numRead < 0) {
1641                     return null;
1642                 }
1643                 return new String(mReadBuffer, 0, numRead);
1644             } else {
1645                 return null;
1646             }
1647         }
1648 
1649         /**
1650          * Closes the underlying file descriptors
1651          * @hide
1652          */
close()1653         public void close() {
1654             try {
1655                 mReceiveStream.close();
1656             } catch (IOException e) {
1657                 // ignore
1658             }
1659             try {
1660                 mTransmitStream.close();
1661             } catch (IOException e) {
1662                 // ignore
1663             }
1664         }
1665     }
1666 
1667     /**
1668      * @deprecated Use {@code Call.Callback} instead.
1669      * @hide
1670      */
1671     @Deprecated
1672     @SystemApi
1673     public static abstract class Listener extends Callback { }
1674 
1675     private final Phone mPhone;
1676     private final String mTelecomCallId;
1677     private final InCallAdapter mInCallAdapter;
1678     private final List<String> mChildrenIds = new ArrayList<>();
1679     private final List<Call> mChildren = new ArrayList<>();
1680     private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
1681     private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>();
1682     private final List<Call> mConferenceableCalls = new ArrayList<>();
1683     private final List<Call> mUnmodifiableConferenceableCalls =
1684             Collections.unmodifiableList(mConferenceableCalls);
1685 
1686     private boolean mChildrenCached;
1687     private String mParentId = null;
1688     private String mActiveGenericConferenceChild = null;
1689     private int mState;
1690     private List<String> mCannedTextResponses = null;
1691     private String mCallingPackage;
1692     private int mTargetSdkVersion;
1693     private String mRemainingPostDialSequence;
1694     private VideoCallImpl mVideoCallImpl;
1695     private RttCall mRttCall;
1696     private Details mDetails;
1697     private Bundle mExtras;
1698 
1699     /**
1700      * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
1701      *
1702      * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
1703      * remaining or this {@code Call} is not in a post-dial state.
1704      */
getRemainingPostDialSequence()1705     public String getRemainingPostDialSequence() {
1706         return mRemainingPostDialSequence;
1707     }
1708 
1709     /**
1710      * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
1711      * @param videoState The video state in which to answer the call.
1712      */
answer(@ideoProfile.VideoState int videoState)1713     public void answer(@VideoProfile.VideoState int videoState) {
1714         mInCallAdapter.answerCall(mTelecomCallId, videoState);
1715     }
1716 
1717     /**
1718      * Instructs this {@link #STATE_RINGING} {@code Call} to deflect.
1719      *
1720      * @param address The address to which the call will be deflected.
1721      */
deflect(Uri address)1722     public void deflect(Uri address) {
1723         mInCallAdapter.deflectCall(mTelecomCallId, address);
1724     }
1725 
1726     /**
1727      * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
1728      *
1729      * @param rejectWithMessage Whether to reject with a text message.
1730      * @param textMessage An optional text message with which to respond.
1731      */
reject(boolean rejectWithMessage, String textMessage)1732     public void reject(boolean rejectWithMessage, String textMessage) {
1733         mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
1734     }
1735 
1736     /**
1737      * Instructs the {@link ConnectionService} providing this {@link #STATE_RINGING} call that the
1738      * user has chosen to reject the call and has indicated a reason why the call is being rejected.
1739      *
1740      * @param rejectReason the reason the call is being rejected.
1741      */
reject(@ejectReason int rejectReason)1742     public void reject(@RejectReason int rejectReason) {
1743         mInCallAdapter.rejectCall(mTelecomCallId, rejectReason);
1744     }
1745 
1746     /**
1747      * Instructs this {@code Call} to be transferred to another number.
1748      *
1749      * @param targetNumber The address to which the call will be transferred.
1750      * @param isConfirmationRequired if {@code true} it will initiate a confirmed transfer,
1751      * if {@code false}, it will initiate an unconfirmed transfer.
1752      *
1753      * @hide
1754      */
transfer(@onNull Uri targetNumber, boolean isConfirmationRequired)1755     public void transfer(@NonNull Uri targetNumber, boolean isConfirmationRequired) {
1756         mInCallAdapter.transferCall(mTelecomCallId, targetNumber, isConfirmationRequired);
1757     }
1758 
1759     /**
1760      * Instructs this {@code Call} to be transferred to another ongoing call.
1761      * This will initiate CONSULTATIVE transfer.
1762      * @param toCall The other ongoing {@code Call} to which this call will be transferred.
1763      *
1764      * @hide
1765      */
transfer(@onNull android.telecom.Call toCall)1766     public void transfer(@NonNull android.telecom.Call toCall) {
1767         mInCallAdapter.transferCall(mTelecomCallId, toCall.mTelecomCallId);
1768     }
1769 
1770     /**
1771      * Instructs this {@code Call} to disconnect.
1772      */
disconnect()1773     public void disconnect() {
1774         mInCallAdapter.disconnectCall(mTelecomCallId);
1775     }
1776 
1777     /**
1778      * Instructs this {@code Call} to go on hold.
1779      */
hold()1780     public void hold() {
1781         mInCallAdapter.holdCall(mTelecomCallId);
1782     }
1783 
1784     /**
1785      * Instructs this {@link #STATE_HOLDING} call to release from hold.
1786      */
unhold()1787     public void unhold() {
1788         mInCallAdapter.unholdCall(mTelecomCallId);
1789     }
1790 
1791     /**
1792      * Instructs Telecom to put the call into the background audio processing state.
1793      * <p>
1794      * This method can be called either when the call is in {@link #STATE_RINGING} or
1795      * {@link #STATE_ACTIVE}. After Telecom acknowledges the request by setting the call's state to
1796      * {@link #STATE_AUDIO_PROCESSING}, your app may setup the audio paths with the audio stack in
1797      * order to capture and play audio on the call stream.
1798      * <p>
1799      * This method can only be called by the default dialer app.
1800      * <p>
1801      * Apps built with SDK version {@link android.os.Build.VERSION_CODES#R} or later which are using
1802      * the microphone as part of audio processing should specify the foreground service type using
1803      * the attribute {@link android.R.attr#foregroundServiceType} in the {@link InCallService}
1804      * service element of the app's manifest file.
1805      * The {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MICROPHONE} attribute should be specified.
1806      * @see <a href="https://developer.android.com/preview/privacy/foreground-service-types">
1807      * the Android Developer Site</a> for more information.
1808      * @hide
1809      */
1810     @SystemApi
enterBackgroundAudioProcessing()1811     public void enterBackgroundAudioProcessing() {
1812         if (mState != STATE_ACTIVE && mState != STATE_RINGING) {
1813             throw new IllegalStateException("Call must be active or ringing");
1814         }
1815         mInCallAdapter.enterBackgroundAudioProcessing(mTelecomCallId);
1816     }
1817 
1818     /**
1819      * Instructs Telecom to come out of the background audio processing state requested by
1820      * {@link #enterBackgroundAudioProcessing()} or from the call screening service.
1821      *
1822      * This method can only be called when the call is in {@link #STATE_AUDIO_PROCESSING}.
1823      *
1824      * @param shouldRing If true, Telecom will put the call into the
1825      *                   {@link #STATE_SIMULATED_RINGING} state and notify other apps that there is
1826      *                   a ringing call. Otherwise, the call will go into {@link #STATE_ACTIVE}
1827      *                   immediately.
1828      * @hide
1829      */
1830     @SystemApi
exitBackgroundAudioProcessing(boolean shouldRing)1831     public void exitBackgroundAudioProcessing(boolean shouldRing) {
1832         if (mState != STATE_AUDIO_PROCESSING) {
1833             throw new IllegalStateException("Call must in the audio processing state");
1834         }
1835         mInCallAdapter.exitBackgroundAudioProcessing(mTelecomCallId, shouldRing);
1836     }
1837 
1838     /**
1839      * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
1840      * <p>
1841      * Tones are both played locally for the user to hear and sent to the network to be relayed
1842      * to the remote device.
1843      * <p>
1844      * You must ensure that any call to {@link #playDtmfTone(char)} is followed by a matching
1845      * call to {@link #stopDtmfTone()} and that each tone is stopped before a new one is started.
1846      * The play and stop commands are relayed to the underlying
1847      * {@link android.telecom.ConnectionService} as executed; implementations may not correctly
1848      * handle out of order commands.
1849      *
1850      * @param digit A character representing the DTMF digit for which to play the tone. This
1851      *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
1852      */
playDtmfTone(char digit)1853     public void playDtmfTone(char digit) {
1854         mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
1855     }
1856 
1857     /**
1858      * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
1859      * currently playing.
1860      *
1861      * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
1862      * currently playing, this method will do nothing.
1863      */
stopDtmfTone()1864     public void stopDtmfTone() {
1865         mInCallAdapter.stopDtmfTone(mTelecomCallId);
1866     }
1867 
1868     /**
1869      * Instructs this {@code Call} to continue playing a post-dial DTMF string.
1870      *
1871      * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
1872      * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
1873      *
1874      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
1875      * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
1876      *
1877      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
1878      * {@code Call} will pause playing the tones and notify callbacks via
1879      * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app
1880      * should display to the user an indication of this state and an affordance to continue
1881      * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
1882      * app should invoke the {@link #postDialContinue(boolean)} method.
1883      *
1884      * @param proceed Whether or not to continue with the post-dial sequence.
1885      */
postDialContinue(boolean proceed)1886     public void postDialContinue(boolean proceed) {
1887         mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
1888     }
1889 
1890     /**
1891      * Notifies this {@code Call} that an account has been selected and to proceed with placing
1892      * an outgoing call. Optionally sets this account as the default account.
1893      */
phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault)1894     public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
1895         mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
1896 
1897     }
1898 
1899     /**
1900      * Instructs this {@code Call} to enter a conference.
1901      *
1902      * @param callToConferenceWith The other call with which to conference.
1903      */
conference(Call callToConferenceWith)1904     public void conference(Call callToConferenceWith) {
1905         if (callToConferenceWith != null) {
1906             mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
1907         }
1908     }
1909 
1910     /**
1911      * Instructs this {@code Call} to split from any conference call with which it may be
1912      * connected.
1913      */
splitFromConference()1914     public void splitFromConference() {
1915         mInCallAdapter.splitFromConference(mTelecomCallId);
1916     }
1917 
1918     /**
1919      * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}.
1920      */
mergeConference()1921     public void mergeConference() {
1922         mInCallAdapter.mergeConference(mTelecomCallId);
1923     }
1924 
1925     /**
1926      * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
1927      */
swapConference()1928     public void swapConference() {
1929         mInCallAdapter.swapConference(mTelecomCallId);
1930     }
1931 
1932     /**
1933      * Pulls participants to existing call by forming a conference call.
1934      * See {@link Details#CAPABILITY_ADD_PARTICIPANT}.
1935      *
1936      * @param participants participants to be pulled to existing call.
1937      */
addConferenceParticipants(@onNull List<Uri> participants)1938     public void addConferenceParticipants(@NonNull List<Uri> participants) {
1939         mInCallAdapter.addConferenceParticipants(mTelecomCallId, participants);
1940     }
1941 
1942     /**
1943      * Initiates a request to the {@link ConnectionService} to pull an external call to the local
1944      * device.
1945      * <p>
1946      * Calls to this method are ignored if the call does not have the
1947      * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} property set.
1948      * <p>
1949      * An {@link InCallService} will only see calls which support this method if it has the
1950      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
1951      * in its manifest.
1952      */
pullExternalCall()1953     public void pullExternalCall() {
1954         // If this isn't an external call, ignore the request.
1955         if (!mDetails.hasProperty(Details.PROPERTY_IS_EXTERNAL_CALL)) {
1956             return;
1957         }
1958 
1959         mInCallAdapter.pullExternalCall(mTelecomCallId);
1960     }
1961 
1962     /**
1963      * Sends a {@code Call} event from this {@code Call} to the associated {@link Connection} in
1964      * the {@link ConnectionService}.
1965      * <p>
1966      * Call events are used to communicate point in time information from an {@link InCallService}
1967      * to a {@link ConnectionService}.  A {@link ConnectionService} implementation could define
1968      * events which enable the {@link InCallService}, for example, toggle a unique feature of the
1969      * {@link ConnectionService}.
1970      * <p>
1971      * A {@link ConnectionService} can communicate to the {@link InCallService} using
1972      * {@link Connection#sendConnectionEvent(String, Bundle)}.
1973      * <p>
1974      * Events are exposed to {@link ConnectionService} implementations via
1975      * {@link android.telecom.Connection#onCallEvent(String, Bundle)}.
1976      * <p>
1977      * No assumptions should be made as to how a {@link ConnectionService} will handle these events.
1978      * The {@link InCallService} must assume that the {@link ConnectionService} could chose to
1979      * ignore some events altogether.
1980      * <p>
1981      * Events should be fully qualified (e.g., {@code com.example.event.MY_EVENT}) to avoid
1982      * conflicts between {@link InCallService} implementations.  Further, {@link InCallService}
1983      * implementations shall not re-purpose events in the {@code android.*} namespace, nor shall
1984      * they define their own event types in this namespace.  When defining a custom event type,
1985      * ensure the contents of the extras {@link Bundle} is clearly defined.  Extra keys for this
1986      * bundle should be named similar to the event type (e.g. {@code com.example.extra.MY_EXTRA}).
1987      * <p>
1988      * When defining events and the associated extras, it is important to keep their behavior
1989      * consistent when the associated {@link InCallService} is updated.  Support for deprecated
1990      * events/extras should me maintained to ensure backwards compatibility with older
1991      * {@link ConnectionService} implementations which were built to support the older behavior.
1992      *
1993      * @param event The connection event.
1994      * @param extras Bundle containing extra information associated with the event.
1995      */
sendCallEvent(String event, Bundle extras)1996     public void sendCallEvent(String event, Bundle extras) {
1997         mInCallAdapter.sendCallEvent(mTelecomCallId, event, mTargetSdkVersion, extras);
1998     }
1999 
2000     /**
2001      * Sends an RTT upgrade request to the remote end of the connection. Success is not
2002      * guaranteed, and notification of success will be via the
2003      * {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
2004      */
sendRttRequest()2005     public void sendRttRequest() {
2006         mInCallAdapter.sendRttRequest(mTelecomCallId);
2007     }
2008 
2009     /**
2010      * Responds to an RTT request received via the {@link Callback#onRttRequest(Call, int)} )}
2011      * callback.
2012      * The ID used here should be the same as the ID that was received via the callback.
2013      * @param id The request ID received via {@link Callback#onRttRequest(Call, int)}
2014      * @param accept {@code true} if the RTT request should be accepted, {@code false} otherwise.
2015      */
respondToRttRequest(int id, boolean accept)2016     public void respondToRttRequest(int id, boolean accept) {
2017         mInCallAdapter.respondToRttRequest(mTelecomCallId, id, accept);
2018     }
2019 
2020     /**
2021      * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
2022      * by {@code toHandle}.  The videoState specified indicates the desired video state after the
2023      * handover.
2024      * <p>
2025      * A call handover is the process where an ongoing call is transferred from one app (i.e.
2026      * {@link ConnectionService} to another app.  The user could, for example, choose to continue a
2027      * mobile network call in a video calling app.  The mobile network call via the Telephony stack
2028      * is referred to as the source of the handover, and the video calling app is referred to as the
2029      * destination.
2030      * <p>
2031      * When considering a handover scenario the device this method is called on is considered the
2032      * <em>initiating</em> device (since the user initiates the handover from this device), and the
2033      * other device is considered the <em>receiving</em> device.
2034      * <p>
2035      * When this method is called on the <em>initiating</em> device, the Telecom framework will bind
2036      * to the {@link ConnectionService} defined by the {@code toHandle} {@link PhoneAccountHandle}
2037      * and invoke
2038      * {@link ConnectionService#onCreateOutgoingHandoverConnection(PhoneAccountHandle,
2039      * ConnectionRequest)} to inform the destination app that a request has been made to handover a
2040      * call to it.  The app returns an instance of {@link Connection} to represent the handover call
2041      * At this point the app should display UI to indicate to the user that a call
2042      * handover is in process.
2043      * <p>
2044      * The destination app is responsible for communicating the handover request from the
2045      * <em>initiating</em> device to the <em>receiving</em> device.
2046      * <p>
2047      * When the app on the <em>receiving</em> device receives the handover request, it calls
2048      * {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)} to continue the handover
2049      * process from the <em>initiating</em> device to the <em>receiving</em> device.  At this point
2050      * the destination app on the <em>receiving</em> device should show UI to allow the user to
2051      * choose whether they want to continue their call in the destination app.
2052      * <p>
2053      * When the destination app on the <em>receiving</em> device calls
2054      * {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)}, Telecom will bind to its
2055      * {@link ConnectionService} and call
2056      * {@link ConnectionService#onCreateIncomingHandoverConnection(PhoneAccountHandle,
2057      * ConnectionRequest)} to inform it of the handover request.  The app returns an instance of
2058      * {@link Connection} to represent the handover call.
2059      * <p>
2060      * If the user of the <em>receiving</em> device accepts the handover, the app calls
2061      * {@link Connection#setActive()} to complete the handover process; Telecom will disconnect the
2062      * original call.  If the user rejects the handover, the app calls
2063      * {@link Connection#setDisconnected(DisconnectCause)} and specifies a {@link DisconnectCause}
2064      * of {@link DisconnectCause#CANCELED} to indicate that the handover has been cancelled.
2065      * <p>
2066      * Telecom will only allow handovers from {@link PhoneAccount}s which declare
2067      * {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_FROM}.  Similarly, the {@link PhoneAccount}
2068      * specified by {@code toHandle} must declare {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_TO}.
2069      * <p>
2070      * Errors in the handover process are reported to the {@link InCallService} via
2071      * {@link Callback#onHandoverFailed(Call, int)}.  Errors in the handover process are reported to
2072      * the involved {@link ConnectionService}s via
2073      * {@link ConnectionService#onHandoverFailed(ConnectionRequest, int)}.
2074      *
2075      * @param toHandle {@link PhoneAccountHandle} of the {@link ConnectionService} to handover
2076      *                 this call to.
2077      * @param videoState Indicates the video state desired after the handover (see the
2078      *               {@code STATE_*} constants defined in {@link VideoProfile}).
2079      * @param extras Bundle containing extra information to be passed to the
2080      *               {@link ConnectionService}
2081      */
handoverTo(PhoneAccountHandle toHandle, @VideoProfile.VideoState int videoState, Bundle extras)2082     public void handoverTo(PhoneAccountHandle toHandle, @VideoProfile.VideoState int videoState,
2083             Bundle extras) {
2084         mInCallAdapter.handoverTo(mTelecomCallId, toHandle, videoState, extras);
2085     }
2086 
2087     /**
2088      * Terminate the RTT session on this call. The resulting state change will be notified via
2089      * the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
2090      */
stopRtt()2091     public void stopRtt() {
2092         mInCallAdapter.stopRtt(mTelecomCallId);
2093     }
2094 
2095     /**
2096      * Adds some extras to this {@link Call}.  Existing keys are replaced and new ones are
2097      * added.
2098      * <p>
2099      * No assumptions should be made as to how an In-Call UI or service will handle these
2100      * extras.  Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
2101      * <p>
2102      * Extras added using this method will be made available to the {@link ConnectionService}
2103      * associated with this {@link Call} and notified via
2104      * {@link Connection#onExtrasChanged(Bundle)}.
2105      * <p>
2106      * Extras added using this method will also be available to other running {@link InCallService}s
2107      * and notified via {@link Call.Callback#onDetailsChanged(Call, Details)}.  The extras can be
2108      * accessed via {@link Details#getExtras()}.
2109      *
2110      * @param extras The extras to add.
2111      */
putExtras(Bundle extras)2112     public final void putExtras(Bundle extras) {
2113         if (extras == null) {
2114             return;
2115         }
2116 
2117         if (mExtras == null) {
2118             mExtras = new Bundle();
2119         }
2120         mExtras.putAll(extras);
2121         mInCallAdapter.putExtras(mTelecomCallId, extras);
2122     }
2123 
2124     /**
2125      * Adds a boolean extra to this {@link Call}.
2126      *
2127      * @param key The extra key.
2128      * @param value The value.
2129      * @hide
2130      */
putExtra(String key, boolean value)2131     public final void putExtra(String key, boolean value) {
2132         if (mExtras == null) {
2133             mExtras = new Bundle();
2134         }
2135         mExtras.putBoolean(key, value);
2136         mInCallAdapter.putExtra(mTelecomCallId, key, value);
2137     }
2138 
2139     /**
2140      * Adds an integer extra to this {@link Call}.
2141      *
2142      * @param key The extra key.
2143      * @param value The value.
2144      * @hide
2145      */
putExtra(String key, int value)2146     public final void putExtra(String key, int value) {
2147         if (mExtras == null) {
2148             mExtras = new Bundle();
2149         }
2150         mExtras.putInt(key, value);
2151         mInCallAdapter.putExtra(mTelecomCallId, key, value);
2152     }
2153 
2154     /**
2155      * Adds a string extra to this {@link Call}.
2156      *
2157      * @param key The extra key.
2158      * @param value The value.
2159      * @hide
2160      */
putExtra(String key, String value)2161     public final void putExtra(String key, String value) {
2162         if (mExtras == null) {
2163             mExtras = new Bundle();
2164         }
2165         mExtras.putString(key, value);
2166         mInCallAdapter.putExtra(mTelecomCallId, key, value);
2167     }
2168 
2169     /**
2170      * Removes extras from this {@link Call}.
2171      *
2172      * @param keys The keys of the extras to remove.
2173      */
removeExtras(List<String> keys)2174     public final void removeExtras(List<String> keys) {
2175         if (mExtras != null) {
2176             for (String key : keys) {
2177                 mExtras.remove(key);
2178             }
2179             if (mExtras.size() == 0) {
2180                 mExtras = null;
2181             }
2182         }
2183         mInCallAdapter.removeExtras(mTelecomCallId, keys);
2184     }
2185 
2186     /**
2187      * Removes extras from this {@link Call}.
2188      *
2189      * @param keys The keys of the extras to remove.
2190      */
removeExtras(String .... keys)2191     public final void removeExtras(String ... keys) {
2192         removeExtras(Arrays.asList(keys));
2193     }
2194 
2195     /**
2196      * Obtains the parent of this {@code Call} in a conference, if any.
2197      *
2198      * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
2199      * child of any conference {@code Call}s.
2200      */
getParent()2201     public Call getParent() {
2202         if (mParentId != null) {
2203             return mPhone.internalGetCallByTelecomId(mParentId);
2204         }
2205         return null;
2206     }
2207 
2208     /**
2209      * Obtains the children of this conference {@code Call}, if any.
2210      *
2211      * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
2212      * {@code List} otherwise.
2213      */
getChildren()2214     public List<Call> getChildren() {
2215         if (!mChildrenCached) {
2216             mChildrenCached = true;
2217             mChildren.clear();
2218 
2219             for(String id : mChildrenIds) {
2220                 Call call = mPhone.internalGetCallByTelecomId(id);
2221                 if (call == null) {
2222                     // At least one child was still not found, so do not save true for "cached"
2223                     mChildrenCached = false;
2224                 } else {
2225                     mChildren.add(call);
2226                 }
2227             }
2228         }
2229 
2230         return mUnmodifiableChildren;
2231     }
2232 
2233     /**
2234      * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
2235      *
2236      * @return The list of conferenceable {@code Call}s.
2237      */
getConferenceableCalls()2238     public List<Call> getConferenceableCalls() {
2239         return mUnmodifiableConferenceableCalls;
2240     }
2241 
2242     /**
2243      * Obtains the state of this {@code Call}.
2244      *
2245      * @return The call state.
2246      * @deprecated The call state is available via {@link Call.Details#getState()}.
2247      */
2248     @Deprecated
getState()2249     public @CallState int getState() {
2250         return mState;
2251     }
2252 
2253     /**
2254      * Returns the child {@link Call} in a generic conference that is currently active.
2255      *
2256      * A "generic conference" is the mechanism used to support two simultaneous calls on a device
2257      * in CDMA networks. It is effectively equivalent to having one call active and one call on hold
2258      * in GSM or IMS calls. This method returns the currently active call.
2259      *
2260      * In a generic conference, the network exposes the conference to us as a single call, and we
2261      * switch between talking to the two participants using a CDMA flash command. Since the network
2262      * exposes no additional information about the call, the only way we know which caller we're
2263      * currently talking to is by keeping track of the flash commands that we've sent to the
2264      * network.
2265      *
2266      * For calls that are not generic conferences, or when the generic conference has more than
2267      * 2 children, returns {@code null}.
2268      * @see Details#PROPERTY_GENERIC_CONFERENCE
2269      * @return The active child call.
2270      */
getGenericConferenceActiveChildCall()2271     public @Nullable Call getGenericConferenceActiveChildCall() {
2272         if (mActiveGenericConferenceChild != null) {
2273             return mPhone.internalGetCallByTelecomId(mActiveGenericConferenceChild);
2274         }
2275         return null;
2276     }
2277 
2278     /**
2279      * Obtains a list of canned, pre-configured message responses to present to the user as
2280      * ways of rejecting an incoming {@code Call} using via a text message.
2281      * <p>
2282      * <em>Note:</em> Since canned responses may be loaded from the file system, they are not
2283      * guaranteed to be present when this {@link Call} is first added to the {@link InCallService}
2284      * via {@link InCallService#onCallAdded(Call)}.  The callback
2285      * {@link Call.Callback#onCannedTextResponsesLoaded(Call, List)} will be called when/if canned
2286      * responses for the call become available.
2287      *
2288      * @see #reject(boolean, String)
2289      *
2290      * @return A list of canned text message responses.
2291      */
getCannedTextResponses()2292     public List<String> getCannedTextResponses() {
2293         return mCannedTextResponses;
2294     }
2295 
2296     /**
2297      * Obtains an object that can be used to display video from this {@code Call}.
2298      *
2299      * @return An {@code Call.VideoCall}.
2300      */
getVideoCall()2301     public InCallService.VideoCall getVideoCall() {
2302         return mVideoCallImpl;
2303     }
2304 
2305     /**
2306      * Obtains an object containing call details.
2307      *
2308      * @return A {@link Details} object. Depending on the state of the {@code Call}, the
2309      * result may be {@code null}.
2310      */
getDetails()2311     public Details getDetails() {
2312         return mDetails;
2313     }
2314 
2315     /**
2316      * Returns this call's RttCall object. The {@link RttCall} instance is used to send and
2317      * receive RTT text data, as well as to change the RTT mode.
2318      * @return A {@link Call.RttCall}. {@code null} if there is no active RTT connection.
2319      */
getRttCall()2320     public @Nullable RttCall getRttCall() {
2321         return mRttCall;
2322     }
2323 
2324     /**
2325      * Returns whether this call has an active RTT connection.
2326      * @return true if there is a connection, false otherwise.
2327      */
isRttActive()2328     public boolean isRttActive() {
2329         return mRttCall != null && mDetails.hasProperty(Details.PROPERTY_RTT);
2330     }
2331 
2332     /**
2333      * Registers a callback to this {@code Call}.
2334      *
2335      * @param callback A {@code Callback}.
2336      */
registerCallback(Callback callback)2337     public void registerCallback(Callback callback) {
2338         registerCallback(callback, new Handler());
2339     }
2340 
2341     /**
2342      * Registers a callback to this {@code Call}.
2343      *
2344      * @param callback A {@code Callback}.
2345      * @param handler A handler which command and status changes will be delivered to.
2346      */
registerCallback(Callback callback, Handler handler)2347     public void registerCallback(Callback callback, Handler handler) {
2348         unregisterCallback(callback);
2349         // Don't allow new callback registration if the call is already being destroyed.
2350         if (callback != null && handler != null && mState != STATE_DISCONNECTED) {
2351             mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler));
2352         }
2353     }
2354 
2355     /**
2356      * Unregisters a callback from this {@code Call}.
2357      *
2358      * @param callback A {@code Callback}.
2359      */
unregisterCallback(Callback callback)2360     public void unregisterCallback(Callback callback) {
2361         // Don't allow callback deregistration if the call is already being destroyed.
2362         if (callback != null && mState != STATE_DISCONNECTED) {
2363             for (CallbackRecord<Callback> record : mCallbackRecords) {
2364                 if (record.getCallback() == callback) {
2365                     mCallbackRecords.remove(record);
2366                     break;
2367                 }
2368             }
2369         }
2370     }
2371 
2372     @Override
toString()2373     public String toString() {
2374         return new StringBuilder().
2375                 append("Call [id: ").
2376                 append(mTelecomCallId).
2377                 append(", state: ").
2378                 append(stateToString(mState)).
2379                 append(", details: ").
2380                 append(mDetails).
2381                 append("]").toString();
2382     }
2383 
2384     /**
2385      * @param state An integer value of a {@code STATE_*} constant.
2386      * @return A string representation of the value.
2387      */
stateToString(int state)2388     private static String stateToString(int state) {
2389         switch (state) {
2390             case STATE_NEW:
2391                 return "NEW";
2392             case STATE_RINGING:
2393                 return "RINGING";
2394             case STATE_DIALING:
2395                 return "DIALING";
2396             case STATE_ACTIVE:
2397                 return "ACTIVE";
2398             case STATE_HOLDING:
2399                 return "HOLDING";
2400             case STATE_DISCONNECTED:
2401                 return "DISCONNECTED";
2402             case STATE_CONNECTING:
2403                 return "CONNECTING";
2404             case STATE_DISCONNECTING:
2405                 return "DISCONNECTING";
2406             case STATE_SELECT_PHONE_ACCOUNT:
2407                 return "SELECT_PHONE_ACCOUNT";
2408             case STATE_SIMULATED_RINGING:
2409                 return "SIMULATED_RINGING";
2410             case STATE_AUDIO_PROCESSING:
2411                 return "AUDIO_PROCESSING";
2412             default:
2413                 Log.w(Call.class, "Unknown state %d", state);
2414                 return "UNKNOWN";
2415         }
2416     }
2417 
2418     /**
2419      * Adds a listener to this {@code Call}.
2420      *
2421      * @param listener A {@code Listener}.
2422      * @deprecated Use {@link #registerCallback} instead.
2423      * @hide
2424      */
2425     @Deprecated
2426     @SystemApi
addListener(Listener listener)2427     public void addListener(Listener listener) {
2428         registerCallback(listener);
2429     }
2430 
2431     /**
2432      * Removes a listener from this {@code Call}.
2433      *
2434      * @param listener A {@code Listener}.
2435      * @deprecated Use {@link #unregisterCallback} instead.
2436      * @hide
2437      */
2438     @Deprecated
2439     @SystemApi
removeListener(Listener listener)2440     public void removeListener(Listener listener) {
2441         unregisterCallback(listener);
2442     }
2443 
2444     /** {@hide} */
Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage, int targetSdkVersion)2445     Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage,
2446          int targetSdkVersion) {
2447         mPhone = phone;
2448         mTelecomCallId = telecomCallId;
2449         mInCallAdapter = inCallAdapter;
2450         mState = STATE_NEW;
2451         mCallingPackage = callingPackage;
2452         mTargetSdkVersion = targetSdkVersion;
2453     }
2454 
2455     /** {@hide} */
Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state, String callingPackage, int targetSdkVersion)2456     Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state,
2457             String callingPackage, int targetSdkVersion) {
2458         mPhone = phone;
2459         mTelecomCallId = telecomCallId;
2460         mInCallAdapter = inCallAdapter;
2461         mState = state;
2462         mCallingPackage = callingPackage;
2463         mTargetSdkVersion = targetSdkVersion;
2464     }
2465 
2466     /** {@hide} */
internalGetCallId()2467     final String internalGetCallId() {
2468         return mTelecomCallId;
2469     }
2470 
2471     /** {@hide} */
internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap)2472     final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
2473 
2474         // First, we update the internal state as far as possible before firing any updates.
2475         Details details = Details.createFromParcelableCall(parcelableCall);
2476         boolean detailsChanged = !Objects.equals(mDetails, details);
2477         if (detailsChanged) {
2478             mDetails = details;
2479         }
2480 
2481         boolean cannedTextResponsesChanged = false;
2482         if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
2483                 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
2484             mCannedTextResponses =
2485                     Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
2486             cannedTextResponsesChanged = true;
2487         }
2488 
2489         IVideoProvider previousVideoProvider = mVideoCallImpl == null ? null :
2490                 mVideoCallImpl.getVideoProvider();
2491         IVideoProvider newVideoProvider = parcelableCall.getVideoProvider();
2492 
2493         // parcelableCall.isVideoCallProviderChanged is only true when we have a video provider
2494         // specified; so we should check if the actual IVideoProvider changes as well.
2495         boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged()
2496                 && !Objects.equals(previousVideoProvider, newVideoProvider);
2497         if (videoCallChanged) {
2498             if (mVideoCallImpl != null) {
2499                 mVideoCallImpl.destroy();
2500             }
2501             mVideoCallImpl = parcelableCall.isVideoCallProviderChanged() ?
2502                     parcelableCall.getVideoCallImpl(mCallingPackage, mTargetSdkVersion) : null;
2503         }
2504 
2505         if (mVideoCallImpl != null) {
2506             mVideoCallImpl.setVideoState(getDetails().getVideoState());
2507         }
2508 
2509         int state = parcelableCall.getState();
2510         if (mTargetSdkVersion < Phone.SDK_VERSION_R && state == Call.STATE_SIMULATED_RINGING) {
2511             state = Call.STATE_RINGING;
2512         }
2513         boolean stateChanged = mState != state;
2514         if (stateChanged) {
2515             mState = state;
2516         }
2517 
2518         String parentId = parcelableCall.getParentCallId();
2519         boolean parentChanged = !Objects.equals(mParentId, parentId);
2520         if (parentChanged) {
2521             mParentId = parentId;
2522         }
2523 
2524         List<String> childCallIds = parcelableCall.getChildCallIds();
2525         boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
2526         if (childrenChanged) {
2527             mChildrenIds.clear();
2528             mChildrenIds.addAll(parcelableCall.getChildCallIds());
2529             mChildrenCached = false;
2530         }
2531 
2532         String activeChildCallId = parcelableCall.getActiveChildCallId();
2533         boolean activeChildChanged = !Objects.equals(activeChildCallId,
2534                 mActiveGenericConferenceChild);
2535         if (activeChildChanged) {
2536             mActiveGenericConferenceChild = activeChildCallId;
2537         }
2538 
2539         List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
2540         List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
2541         for (String otherId : conferenceableCallIds) {
2542             if (callIdMap.containsKey(otherId)) {
2543                 conferenceableCalls.add(callIdMap.get(otherId));
2544             }
2545         }
2546 
2547         if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
2548             mConferenceableCalls.clear();
2549             mConferenceableCalls.addAll(conferenceableCalls);
2550             fireConferenceableCallsChanged();
2551         }
2552 
2553         boolean isRttChanged = false;
2554         boolean rttModeChanged = false;
2555         if (parcelableCall.getIsRttCallChanged()
2556                 && mDetails.hasProperty(Details.PROPERTY_RTT)) {
2557             ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
2558             InputStreamReader receiveStream = new InputStreamReader(
2559                     new ParcelFileDescriptor.AutoCloseInputStream(
2560                             parcelableRttCall.getReceiveStream()),
2561                     StandardCharsets.UTF_8);
2562             OutputStreamWriter transmitStream = new OutputStreamWriter(
2563                     new ParcelFileDescriptor.AutoCloseOutputStream(
2564                             parcelableRttCall.getTransmitStream()),
2565                     StandardCharsets.UTF_8);
2566             RttCall newRttCall = new Call.RttCall(mTelecomCallId,
2567                     receiveStream, transmitStream, parcelableRttCall.getRttMode(), mInCallAdapter);
2568             if (mRttCall == null) {
2569                 isRttChanged = true;
2570             } else if (mRttCall.getRttAudioMode() != newRttCall.getRttAudioMode()) {
2571                 rttModeChanged = true;
2572             }
2573             mRttCall = newRttCall;
2574         } else if (mRttCall != null && parcelableCall.getParcelableRttCall() == null
2575                 && parcelableCall.getIsRttCallChanged()) {
2576             isRttChanged = true;
2577             mRttCall.close();
2578             mRttCall = null;
2579         }
2580 
2581         // Now we fire updates, ensuring that any client who listens to any of these notifications
2582         // gets the most up-to-date state.
2583 
2584         if (stateChanged) {
2585             fireStateChanged(mState);
2586         }
2587         if (detailsChanged) {
2588             fireDetailsChanged(mDetails);
2589         }
2590         if (cannedTextResponsesChanged) {
2591             fireCannedTextResponsesLoaded(mCannedTextResponses);
2592         }
2593         if (videoCallChanged) {
2594             fireVideoCallChanged(mVideoCallImpl);
2595         }
2596         if (parentChanged) {
2597             fireParentChanged(getParent());
2598         }
2599         if (childrenChanged || activeChildChanged) {
2600             fireChildrenChanged(getChildren());
2601         }
2602         if (isRttChanged) {
2603             fireOnIsRttChanged(mRttCall != null, mRttCall);
2604         }
2605         if (rttModeChanged) {
2606             fireOnRttModeChanged(mRttCall.getRttAudioMode());
2607         }
2608 
2609         // If we have transitioned to DISCONNECTED, that means we need to notify clients and
2610         // remove ourselves from the Phone. Note that we do this after completing all state updates
2611         // so a client can cleanly transition all their UI to the state appropriate for a
2612         // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
2613         // Check if the original state is already disconnected, otherwise onCallRemoved will be
2614         // triggered before onCallAdded.
2615         if (mState == STATE_DISCONNECTED && stateChanged) {
2616             fireCallDestroyed();
2617         }
2618     }
2619 
2620     /** {@hide} */
internalSetPostDialWait(String remaining)2621     final void internalSetPostDialWait(String remaining) {
2622         mRemainingPostDialSequence = remaining;
2623         firePostDialWait(mRemainingPostDialSequence);
2624     }
2625 
2626     /** {@hide} */
internalSetDisconnected()2627     final void internalSetDisconnected() {
2628         if (mState != Call.STATE_DISCONNECTED) {
2629             mState = Call.STATE_DISCONNECTED;
2630             if (mDetails != null) {
2631                 mDetails = new Details(mState,
2632                         mDetails.getTelecomCallId(),
2633                         mDetails.getHandle(),
2634                         mDetails.getHandlePresentation(),
2635                         mDetails.getCallerDisplayName(),
2636                         mDetails.getCallerDisplayNamePresentation(),
2637                         mDetails.getAccountHandle(),
2638                         mDetails.getCallCapabilities(),
2639                         mDetails.getCallProperties(),
2640                         mDetails.getDisconnectCause(),
2641                         mDetails.getConnectTimeMillis(),
2642                         mDetails.getGatewayInfo(),
2643                         mDetails.getVideoState(),
2644                         mDetails.getStatusHints(),
2645                         mDetails.getExtras(),
2646                         mDetails.getIntentExtras(),
2647                         mDetails.getCreationTimeMillis(),
2648                         mDetails.getContactDisplayName(),
2649                         mDetails.getCallDirection(),
2650                         mDetails.getCallerNumberVerificationStatus(),
2651                         mDetails.getContactPhotoUri(),
2652                         mDetails.getAssociatedUser()
2653                         );
2654                 fireDetailsChanged(mDetails);
2655             }
2656             fireStateChanged(mState);
2657             fireCallDestroyed();
2658         }
2659     }
2660 
2661     /** {@hide} */
internalOnConnectionEvent(String event, Bundle extras)2662     final void internalOnConnectionEvent(String event, Bundle extras) {
2663         fireOnConnectionEvent(event, extras);
2664     }
2665 
2666     /** {@hide} */
internalOnRttUpgradeRequest(final int requestId)2667     final void internalOnRttUpgradeRequest(final int requestId) {
2668         for (CallbackRecord<Callback> record : mCallbackRecords) {
2669             final Call call = this;
2670             final Callback callback = record.getCallback();
2671             record.getHandler().post(() -> callback.onRttRequest(call, requestId));
2672         }
2673     }
2674 
2675     /** @hide */
internalOnRttInitiationFailure(int reason)2676     final void internalOnRttInitiationFailure(int reason) {
2677         for (CallbackRecord<Callback> record : mCallbackRecords) {
2678             final Call call = this;
2679             final Callback callback = record.getCallback();
2680             record.getHandler().post(() -> callback.onRttInitiationFailure(call, reason));
2681         }
2682     }
2683 
2684     /** {@hide} */
internalOnHandoverFailed(int error)2685     final void internalOnHandoverFailed(int error) {
2686         for (CallbackRecord<Callback> record : mCallbackRecords) {
2687             final Call call = this;
2688             final Callback callback = record.getCallback();
2689             record.getHandler().post(() -> callback.onHandoverFailed(call, error));
2690         }
2691     }
2692 
2693     /** {@hide} */
internalOnHandoverComplete()2694     final void internalOnHandoverComplete() {
2695         for (CallbackRecord<Callback> record : mCallbackRecords) {
2696             final Call call = this;
2697             final Callback callback = record.getCallback();
2698             record.getHandler().post(() -> callback.onHandoverComplete(call));
2699         }
2700     }
2701 
fireStateChanged(final int newState)2702     private void fireStateChanged(final int newState) {
2703         for (CallbackRecord<Callback> record : mCallbackRecords) {
2704             final Call call = this;
2705             final Callback callback = record.getCallback();
2706             record.getHandler().post(new Runnable() {
2707                 @Override
2708                 public void run() {
2709                     callback.onStateChanged(call, newState);
2710                 }
2711             });
2712         }
2713     }
2714 
fireParentChanged(final Call newParent)2715     private void fireParentChanged(final Call newParent) {
2716         for (CallbackRecord<Callback> record : mCallbackRecords) {
2717             final Call call = this;
2718             final Callback callback = record.getCallback();
2719             record.getHandler().post(new Runnable() {
2720                 @Override
2721                 public void run() {
2722                     callback.onParentChanged(call, newParent);
2723                 }
2724             });
2725         }
2726     }
2727 
fireChildrenChanged(final List<Call> children)2728     private void fireChildrenChanged(final List<Call> children) {
2729         for (CallbackRecord<Callback> record : mCallbackRecords) {
2730             final Call call = this;
2731             final Callback callback = record.getCallback();
2732             record.getHandler().post(new Runnable() {
2733                 @Override
2734                 public void run() {
2735                     callback.onChildrenChanged(call, children);
2736                 }
2737             });
2738         }
2739     }
2740 
fireDetailsChanged(final Details details)2741     private void fireDetailsChanged(final Details details) {
2742         for (CallbackRecord<Callback> record : mCallbackRecords) {
2743             final Call call = this;
2744             final Callback callback = record.getCallback();
2745             record.getHandler().post(new Runnable() {
2746                 @Override
2747                 public void run() {
2748                     callback.onDetailsChanged(call, details);
2749                 }
2750             });
2751         }
2752     }
2753 
fireCannedTextResponsesLoaded(final List<String> cannedTextResponses)2754     private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) {
2755         for (CallbackRecord<Callback> record : mCallbackRecords) {
2756             final Call call = this;
2757             final Callback callback = record.getCallback();
2758             record.getHandler().post(new Runnable() {
2759                 @Override
2760                 public void run() {
2761                     callback.onCannedTextResponsesLoaded(call, cannedTextResponses);
2762                 }
2763             });
2764         }
2765     }
2766 
fireVideoCallChanged(final InCallService.VideoCall videoCall)2767     private void fireVideoCallChanged(final InCallService.VideoCall videoCall) {
2768         for (CallbackRecord<Callback> record : mCallbackRecords) {
2769             final Call call = this;
2770             final Callback callback = record.getCallback();
2771             record.getHandler().post(new Runnable() {
2772                 @Override
2773                 public void run() {
2774                     callback.onVideoCallChanged(call, videoCall);
2775                 }
2776             });
2777         }
2778     }
2779 
firePostDialWait(final String remainingPostDialSequence)2780     private void firePostDialWait(final String remainingPostDialSequence) {
2781         for (CallbackRecord<Callback> record : mCallbackRecords) {
2782             final Call call = this;
2783             final Callback callback = record.getCallback();
2784             record.getHandler().post(new Runnable() {
2785                 @Override
2786                 public void run() {
2787                     callback.onPostDialWait(call, remainingPostDialSequence);
2788                 }
2789             });
2790         }
2791     }
2792 
fireCallDestroyed()2793     private void fireCallDestroyed() {
2794         /**
2795          * To preserve the ordering of the Call's onCallDestroyed callback and Phone's
2796          * onCallRemoved callback, we remove this call from the Phone's record
2797          * only once all of the registered onCallDestroyed callbacks are executed.
2798          * All the callbacks get removed from our records as a part of this operation
2799          * since onCallDestroyed is the final callback.
2800          */
2801         final Call call = this;
2802         if (mCallbackRecords.isEmpty()) {
2803             // No callbacks registered, remove the call from Phone's record.
2804             mPhone.internalRemoveCall(call);
2805         }
2806         for (final CallbackRecord<Callback> record : mCallbackRecords) {
2807             final Callback callback = record.getCallback();
2808             record.getHandler().post(new Runnable() {
2809                 @Override
2810                 public void run() {
2811                     boolean isFinalRemoval = false;
2812                     RuntimeException toThrow = null;
2813                     try {
2814                         callback.onCallDestroyed(call);
2815                     } catch (RuntimeException e) {
2816                             toThrow = e;
2817                     }
2818                     synchronized(Call.this) {
2819                         mCallbackRecords.remove(record);
2820                         if (mCallbackRecords.isEmpty()) {
2821                             isFinalRemoval = true;
2822                         }
2823                     }
2824                     if (isFinalRemoval) {
2825                         mPhone.internalRemoveCall(call);
2826                     }
2827                     if (toThrow != null) {
2828                         throw toThrow;
2829                     }
2830                 }
2831             });
2832         }
2833     }
2834 
fireConferenceableCallsChanged()2835     private void fireConferenceableCallsChanged() {
2836         for (CallbackRecord<Callback> record : mCallbackRecords) {
2837             final Call call = this;
2838             final Callback callback = record.getCallback();
2839             record.getHandler().post(new Runnable() {
2840                 @Override
2841                 public void run() {
2842                     callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls);
2843                 }
2844             });
2845         }
2846     }
2847 
2848     /**
2849      * Notifies listeners of an incoming connection event.
2850      * <p>
2851      * Connection events are issued via {@link Connection#sendConnectionEvent(String, Bundle)}.
2852      *
2853      * @param event
2854      * @param extras
2855      */
fireOnConnectionEvent(final String event, final Bundle extras)2856     private void fireOnConnectionEvent(final String event, final Bundle extras) {
2857         for (CallbackRecord<Callback> record : mCallbackRecords) {
2858             final Call call = this;
2859             final Callback callback = record.getCallback();
2860             record.getHandler().post(new Runnable() {
2861                 @Override
2862                 public void run() {
2863                     callback.onConnectionEvent(call, event, extras);
2864                 }
2865             });
2866         }
2867     }
2868 
2869     /**
2870      * Notifies listeners of an RTT on/off change
2871      *
2872      * @param enabled True if RTT is now enabled, false otherwise
2873      */
fireOnIsRttChanged(final boolean enabled, final RttCall rttCall)2874     private void fireOnIsRttChanged(final boolean enabled, final RttCall rttCall) {
2875         for (CallbackRecord<Callback> record : mCallbackRecords) {
2876             final Call call = this;
2877             final Callback callback = record.getCallback();
2878             record.getHandler().post(() -> callback.onRttStatusChanged(call, enabled, rttCall));
2879         }
2880     }
2881 
2882     /**
2883      * Notifies listeners of a RTT mode change
2884      *
2885      * @param mode The new RTT mode
2886      */
fireOnRttModeChanged(final int mode)2887     private void fireOnRttModeChanged(final int mode) {
2888         for (CallbackRecord<Callback> record : mCallbackRecords) {
2889             final Call call = this;
2890             final Callback callback = record.getCallback();
2891             record.getHandler().post(() -> callback.onRttModeChanged(call, mode));
2892         }
2893     }
2894 
2895     /**
2896      * Determines if two bundles are equal.
2897      *
2898      * @param bundle The original bundle.
2899      * @param newBundle The bundle to compare with.
2900      * @retrun {@code true} if the bundles are equal, {@code false} otherwise.
2901      */
areBundlesEqual(Bundle bundle, Bundle newBundle)2902     private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) {
2903         if (bundle == null || newBundle == null) {
2904             return bundle == newBundle;
2905         }
2906 
2907         if (bundle.size() != newBundle.size()) {
2908             return false;
2909         }
2910         try {
2911             for (String key : bundle.keySet()) {
2912                 if (key != null) {
2913                     if (!newBundle.containsKey(key)) {
2914                         return false;
2915                     }
2916                     // In case new call extra contains non-framework class objects, return false to
2917                     // force update the call extra
2918                     try {
2919                         final Object value = bundle.get(key);
2920                         final Object newValue = newBundle.get(key);
2921                         if (value instanceof Bundle && newValue instanceof Bundle) {
2922                             if (!areBundlesEqual((Bundle) value, (Bundle) newValue)) {
2923                                 return false;
2924                             }
2925                         }
2926                         if (value instanceof byte[] && newValue instanceof byte[]) {
2927                             if (!Arrays.equals((byte[]) value, (byte[]) newValue)) {
2928                                 return false;
2929                             }
2930                         } else if (!Objects.equals(value, newValue)) {
2931                             return false;
2932                         }
2933                     } catch (BadParcelableException e) {
2934                         return false;
2935                     }
2936                 }
2937             }
2938         } catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
2939             // Unfortunately this may get raised when accessing the bundle's keyset, so we cannot
2940             // determine WHY a class cast exception is happening.  We had tried in the past to do
2941             // this down in the for loop so we could figure out which key is causing an issue.
2942             // Bundles are not thread safe, so the most likely issue here is that the InCallService
2943             // implementation is accessing the Bundle WHILE an incoming Telecom update comes in to
2944             // potentially replace the Bundle.  We call "areBundlesEqual" to see if the newly
2945             // unparceled Call.Details is the same as what is already in the current Call instance.
2946             // If those two operations overleave, I can see the potential for concurrent
2947             // modification and edit of the Bundle.  So we'll just catch here and assume the Bundles
2948             // are not the same.  This means a Call.CallBack may fire the onCallDetails changed
2949             // callback when the Bundle didn't actually change.
2950             Log.e(LOG_TAG, e, "areBundlesEqual: failed!");
2951             return false;
2952         }
2953         return true;
2954     }
2955 }
2956