• 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.IntDef;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.net.Uri;
23 import android.os.Bundle;
24 import android.os.Handler;
25 import android.os.ParcelFileDescriptor;
26 
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.io.OutputStreamWriter;
30 import java.lang.String;
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 import java.nio.charset.StandardCharsets;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collections;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Objects;
40 import java.util.concurrent.CopyOnWriteArrayList;
41 
42 /**
43  * Represents an ongoing phone call that the in-call app should present to the user.
44  */
45 public final class Call {
46     /**
47      * The state of a {@code Call} when newly created.
48      */
49     public static final int STATE_NEW = 0;
50 
51     /**
52      * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
53      */
54     public static final int STATE_DIALING = 1;
55 
56     /**
57      * The state of an incoming {@code Call} when ringing locally, but not yet connected.
58      */
59     public static final int STATE_RINGING = 2;
60 
61     /**
62      * The state of a {@code Call} when in a holding state.
63      */
64     public static final int STATE_HOLDING = 3;
65 
66     /**
67      * The state of a {@code Call} when actively supporting conversation.
68      */
69     public static final int STATE_ACTIVE = 4;
70 
71     /**
72      * The state of a {@code Call} when no further voice or other communication is being
73      * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
74      * is no longer active, and the local data transport has or inevitably will release resources
75      * associated with this {@code Call}.
76      */
77     public static final int STATE_DISCONNECTED = 7;
78 
79     /**
80      * The state of an outgoing {@code Call} when waiting on user to select a
81      * {@link PhoneAccount} through which to place the call.
82      */
83     public static final int STATE_SELECT_PHONE_ACCOUNT = 8;
84 
85     /**
86      * @hide
87      * @deprecated use STATE_SELECT_PHONE_ACCOUNT.
88      */
89     @Deprecated
90     @SystemApi
91     public static final int STATE_PRE_DIAL_WAIT = STATE_SELECT_PHONE_ACCOUNT;
92 
93     /**
94      * The initial state of an outgoing {@code Call}.
95      * Common transitions are to {@link #STATE_DIALING} state for a successful call or
96      * {@link #STATE_DISCONNECTED} if it failed.
97      */
98     public static final int STATE_CONNECTING = 9;
99 
100     /**
101      * The state of a {@code Call} when the user has initiated a disconnection of the call, but the
102      * call has not yet been disconnected by the underlying {@code ConnectionService}.  The next
103      * state of the call is (potentially) {@link #STATE_DISCONNECTED}.
104      */
105     public static final int STATE_DISCONNECTING = 10;
106 
107     /**
108      * The state of an external call which is in the process of being pulled from a remote device to
109      * the local device.
110      * <p>
111      * A call can only be in this state if the {@link Details#PROPERTY_IS_EXTERNAL_CALL} property
112      * and {@link Details#CAPABILITY_CAN_PULL_CALL} capability are set on the call.
113      * <p>
114      * An {@link InCallService} will only see this state if it has the
115      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
116      * manifest.
117      */
118     public static final int STATE_PULLING_CALL = 11;
119 
120     /**
121      * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
122      * extras. Used to pass the phone accounts to display on the front end to the user in order to
123      * select phone accounts to (for example) place a call.
124      */
125     public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
126 
127     /**
128      * Extra key used to indicate the time (in milliseconds since midnight, January 1, 1970 UTC)
129      * when the last outgoing emergency call was made.  This is used to identify potential emergency
130      * callbacks.
131      */
132     public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS =
133             "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
134 
135     public static class Details {
136 
137         /** Call can currently be put on hold or unheld. */
138         public static final int CAPABILITY_HOLD = 0x00000001;
139 
140         /** Call supports the hold feature. */
141         public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
142 
143         /**
144          * Calls within a conference can be merged. A {@link ConnectionService} has the option to
145          * add a {@link Conference} call before the child {@link Connection}s are merged. This is how
146          * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
147          * capability allows a merge button to be shown while the conference call is in the foreground
148          * of the in-call UI.
149          * <p>
150          * This is only intended for use by a {@link Conference}.
151          */
152         public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
153 
154         /**
155          * Calls within a conference can be swapped between foreground and background.
156          * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
157          * <p>
158          * This is only intended for use by a {@link Conference}.
159          */
160         public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
161 
162         /**
163          * @hide
164          */
165         public static final int CAPABILITY_UNUSED_1 = 0x00000010;
166 
167         /** Call supports responding via text option. */
168         public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
169 
170         /** Call can be muted. */
171         public static final int CAPABILITY_MUTE = 0x00000040;
172 
173         /**
174          * Call supports conference call management. This capability only applies to {@link Conference}
175          * calls which can have {@link Connection}s as children.
176          */
177         public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
178 
179         /**
180          * Local device supports receiving video.
181          */
182         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
183 
184         /**
185          * Local device supports transmitting video.
186          */
187         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
188 
189         /**
190          * Local device supports bidirectional video calling.
191          */
192         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
193                 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
194 
195         /**
196          * Remote device supports receiving video.
197          */
198         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
199 
200         /**
201          * Remote device supports transmitting video.
202          */
203         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
204 
205         /**
206          * Remote device supports bidirectional video calling.
207          */
208         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
209                 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
210 
211         /**
212          * Call is able to be separated from its parent {@code Conference}, if any.
213          */
214         public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
215 
216         /**
217          * Call is able to be individually disconnected when in a {@code Conference}.
218          */
219         public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
220 
221         /**
222          * Speed up audio setup for MT call.
223          * @hide
224          */
225         public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
226 
227         /**
228          * Call can be upgraded to a video call.
229          * @hide
230          */
231         public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
232 
233         /**
234          * For video calls, indicates whether the outgoing video for the call can be paused using
235          * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
236          */
237         public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
238 
239         /**
240          * Call sends responses through connection.
241          * @hide
242          */
243         public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000;
244 
245         /**
246          * When set, prevents a video {@code Call} from being downgraded to an audio-only call.
247          * <p>
248          * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
249          * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
250          * downgraded from a video call back to a VideoState of
251          * {@link VideoProfile#STATE_AUDIO_ONLY}.
252          * <p>
253          * Intuitively, a call which can be downgraded to audio should also have local and remote
254          * video
255          * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
256          * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
257          */
258         public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000;
259 
260         /**
261          * When set for an external call, indicates that this {@code Call} can be pulled from a
262          * remote device to the current device.
263          * <p>
264          * Should only be set on a {@code Call} where {@link #PROPERTY_IS_EXTERNAL_CALL} is set.
265          * <p>
266          * An {@link InCallService} will only see calls with this capability if it has the
267          * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
268          * in its manifest.
269          * <p>
270          * See {@link Connection#CAPABILITY_CAN_PULL_CALL} and
271          * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
272          */
273         public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
274 
275         //******************************************************************************************
276         // Next CAPABILITY value: 0x01000000
277         //******************************************************************************************
278 
279         /**
280          * Whether the call is currently a conference.
281          */
282         public static final int PROPERTY_CONFERENCE = 0x00000001;
283 
284         /**
285          * Whether the call is a generic conference, where we do not know the precise state of
286          * participants in the conference (eg. on CDMA).
287          */
288         public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002;
289 
290         /**
291          * Whether the call is made while the device is in emergency callback mode.
292          */
293         public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004;
294 
295         /**
296          * Connection is using WIFI.
297          */
298         public static final int PROPERTY_WIFI = 0x00000008;
299 
300         /**
301          * Call is using high definition audio.
302          */
303         public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
304 
305         /**
306          * Whether the call is associated with the work profile.
307          */
308         public static final int PROPERTY_ENTERPRISE_CALL = 0x00000020;
309 
310         /**
311          * When set, indicates that this {@code Call} does not actually exist locally for the
312          * {@link ConnectionService}.
313          * <p>
314          * Consider, for example, a scenario where a user has two phones with the same phone number.
315          * When a user places a call on one device, the telephony stack can represent that call on
316          * the other device by adding it to the {@link ConnectionService} with the
317          * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property set.
318          * <p>
319          * An {@link InCallService} will only see calls with this property if it has the
320          * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
321          * in its manifest.
322          * <p>
323          * See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
324          */
325         public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040;
326 
327         /**
328          * Indicates that the call has CDMA Enhanced Voice Privacy enabled.
329          */
330         public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 0x00000080;
331 
332         /**
333          * Indicates that the call is from a self-managed {@link ConnectionService}.
334          * <p>
335          * See also {@link Connection#PROPERTY_SELF_MANAGED}
336          */
337         public static final int PROPERTY_SELF_MANAGED = 0x00000100;
338 
339         //******************************************************************************************
340         // Next PROPERTY value: 0x00000200
341         //******************************************************************************************
342 
343         private final String mTelecomCallId;
344         private final Uri mHandle;
345         private final int mHandlePresentation;
346         private final String mCallerDisplayName;
347         private final int mCallerDisplayNamePresentation;
348         private final PhoneAccountHandle mAccountHandle;
349         private final int mCallCapabilities;
350         private final int mCallProperties;
351         private final int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
352         private final DisconnectCause mDisconnectCause;
353         private final long mConnectTimeMillis;
354         private final GatewayInfo mGatewayInfo;
355         private final int mVideoState;
356         private final StatusHints mStatusHints;
357         private final Bundle mExtras;
358         private final Bundle mIntentExtras;
359         private final long mCreationTimeMillis;
360 
361         /**
362          * Whether the supplied capabilities  supports the specified capability.
363          *
364          * @param capabilities A bit field of capabilities.
365          * @param capability The capability to check capabilities for.
366          * @return Whether the specified capability is supported.
367          */
can(int capabilities, int capability)368         public static boolean can(int capabilities, int capability) {
369             return (capabilities & capability) == capability;
370         }
371 
372         /**
373          * Whether the capabilities of this {@code Details} supports the specified capability.
374          *
375          * @param capability The capability to check capabilities for.
376          * @return Whether the specified capability is supported.
377          */
can(int capability)378         public boolean can(int capability) {
379             return can(mCallCapabilities, capability);
380         }
381 
382         /**
383          * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
384          *
385          * @param capabilities A capability bit field.
386          * @return A human readable string representation.
387          */
capabilitiesToString(int capabilities)388         public static String capabilitiesToString(int capabilities) {
389             StringBuilder builder = new StringBuilder();
390             builder.append("[Capabilities:");
391             if (can(capabilities, CAPABILITY_HOLD)) {
392                 builder.append(" CAPABILITY_HOLD");
393             }
394             if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
395                 builder.append(" CAPABILITY_SUPPORT_HOLD");
396             }
397             if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
398                 builder.append(" CAPABILITY_MERGE_CONFERENCE");
399             }
400             if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
401                 builder.append(" CAPABILITY_SWAP_CONFERENCE");
402             }
403             if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
404                 builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
405             }
406             if (can(capabilities, CAPABILITY_MUTE)) {
407                 builder.append(" CAPABILITY_MUTE");
408             }
409             if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
410                 builder.append(" CAPABILITY_MANAGE_CONFERENCE");
411             }
412             if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
413                 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
414             }
415             if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
416                 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
417             }
418             if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
419                 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
420             }
421             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
422                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
423             }
424             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
425                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
426             }
427             if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
428                 builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
429             }
430             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
431                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
432             }
433             if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
434                 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
435             }
436             if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
437                 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
438             }
439             if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
440                 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
441             }
442             if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
443                 builder.append(" CAPABILITY_CAN_PULL_CALL");
444             }
445             builder.append("]");
446             return builder.toString();
447         }
448 
449         /**
450          * Whether the supplied properties includes the specified property.
451          *
452          * @param properties A bit field of properties.
453          * @param property The property to check properties for.
454          * @return Whether the specified property is supported.
455          */
hasProperty(int properties, int property)456         public static boolean hasProperty(int properties, int property) {
457             return (properties & property) == property;
458         }
459 
460         /**
461          * Whether the properties of this {@code Details} includes the specified property.
462          *
463          * @param property The property to check properties for.
464          * @return Whether the specified property is supported.
465          */
hasProperty(int property)466         public boolean hasProperty(int property) {
467             return hasProperty(mCallProperties, property);
468         }
469 
470         /**
471          * Render a set of property bits ({@code PROPERTY_*}) as a human readable string.
472          *
473          * @param properties A property bit field.
474          * @return A human readable string representation.
475          */
propertiesToString(int properties)476         public static String propertiesToString(int properties) {
477             StringBuilder builder = new StringBuilder();
478             builder.append("[Properties:");
479             if (hasProperty(properties, PROPERTY_CONFERENCE)) {
480                 builder.append(" PROPERTY_CONFERENCE");
481             }
482             if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) {
483                 builder.append(" PROPERTY_GENERIC_CONFERENCE");
484             }
485             if (hasProperty(properties, PROPERTY_WIFI)) {
486                 builder.append(" PROPERTY_WIFI");
487             }
488             if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) {
489                 builder.append(" PROPERTY_HIGH_DEF_AUDIO");
490             }
491             if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
492                 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
493             }
494             if (hasProperty(properties, PROPERTY_IS_EXTERNAL_CALL)) {
495                 builder.append(" PROPERTY_IS_EXTERNAL_CALL");
496             }
497             if(hasProperty(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
498                 builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY");
499             }
500             builder.append("]");
501             return builder.toString();
502         }
503 
504         /** {@hide} */
getTelecomCallId()505         public String getTelecomCallId() {
506             return mTelecomCallId;
507         }
508 
509         /**
510          * @return The handle (e.g., phone number) to which the {@code Call} is currently
511          * connected.
512          */
getHandle()513         public Uri getHandle() {
514             return mHandle;
515         }
516 
517         /**
518          * @return The presentation requirements for the handle. See
519          * {@link TelecomManager} for valid values.
520          */
getHandlePresentation()521         public int getHandlePresentation() {
522             return mHandlePresentation;
523         }
524 
525         /**
526          * @return The display name for the caller.
527          */
getCallerDisplayName()528         public String getCallerDisplayName() {
529             return mCallerDisplayName;
530         }
531 
532         /**
533          * @return The presentation requirements for the caller display name. See
534          * {@link TelecomManager} for valid values.
535          */
getCallerDisplayNamePresentation()536         public int getCallerDisplayNamePresentation() {
537             return mCallerDisplayNamePresentation;
538         }
539 
540         /**
541          * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
542          * routed.
543          */
getAccountHandle()544         public PhoneAccountHandle getAccountHandle() {
545             return mAccountHandle;
546         }
547 
548         /**
549          * @return A bitmask of the capabilities of the {@code Call}, as defined by the various
550          *         {@code CAPABILITY_*} constants in this class.
551          */
getCallCapabilities()552         public int getCallCapabilities() {
553             return mCallCapabilities;
554         }
555 
556         /**
557          * @return A bitmask of the properties of the {@code Call}, as defined by the various
558          *         {@code PROPERTY_*} constants in this class.
559          */
getCallProperties()560         public int getCallProperties() {
561             return mCallProperties;
562         }
563 
564         /**
565          * @return a bitmask of the audio routes available for the call.
566          *
567          * @hide
568          */
getSupportedAudioRoutes()569         public int getSupportedAudioRoutes() {
570             return mSupportedAudioRoutes;
571         }
572 
573         /**
574          * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
575          * by {@link android.telecom.DisconnectCause}.
576          */
getDisconnectCause()577         public DisconnectCause getDisconnectCause() {
578             return mDisconnectCause;
579         }
580 
581         /**
582          * Returns the time the {@link Call} connected (i.e. became active).  This information is
583          * updated periodically, but user interfaces should not rely on this to display the "call
584          * time clock".  For the time when the call was first added to Telecom, see
585          * {@link #getCreationTimeMillis()}.
586          *
587          * @return The time the {@link Call} connected in milliseconds since the epoch.
588          */
getConnectTimeMillis()589         public final long getConnectTimeMillis() {
590             return mConnectTimeMillis;
591         }
592 
593         /**
594          * @return Information about any calling gateway the {@code Call} may be using.
595          */
getGatewayInfo()596         public GatewayInfo getGatewayInfo() {
597             return mGatewayInfo;
598         }
599 
600         /**
601          * @return The video state of the {@code Call}.
602          */
getVideoState()603         public int getVideoState() {
604             return mVideoState;
605         }
606 
607         /**
608          * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
609          * have been set.
610          */
getStatusHints()611         public StatusHints getStatusHints() {
612             return mStatusHints;
613         }
614 
615         /**
616          * @return The extras associated with this call.
617          */
getExtras()618         public Bundle getExtras() {
619             return mExtras;
620         }
621 
622         /**
623          * @return The extras used with the original intent to place this call.
624          */
getIntentExtras()625         public Bundle getIntentExtras() {
626             return mIntentExtras;
627         }
628 
629         /**
630          * Returns the time when the call was first created and added to Telecom.  This is the same
631          * time that is logged as the start time in the Call Log (see
632          * {@link android.provider.CallLog.Calls#DATE}).  To determine when the call was connected
633          * (became active), see {@link #getConnectTimeMillis()}.
634          *
635          * @return The creation time of the call, in millis since the epoch.
636          */
getCreationTimeMillis()637         public long getCreationTimeMillis() {
638             return mCreationTimeMillis;
639         }
640 
641         @Override
equals(Object o)642         public boolean equals(Object o) {
643             if (o instanceof Details) {
644                 Details d = (Details) o;
645                 return
646                         Objects.equals(mHandle, d.mHandle) &&
647                         Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
648                         Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
649                         Objects.equals(mCallerDisplayNamePresentation,
650                                 d.mCallerDisplayNamePresentation) &&
651                         Objects.equals(mAccountHandle, d.mAccountHandle) &&
652                         Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
653                         Objects.equals(mCallProperties, d.mCallProperties) &&
654                         Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
655                         Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
656                         Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
657                         Objects.equals(mVideoState, d.mVideoState) &&
658                         Objects.equals(mStatusHints, d.mStatusHints) &&
659                         areBundlesEqual(mExtras, d.mExtras) &&
660                         areBundlesEqual(mIntentExtras, d.mIntentExtras) &&
661                         Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis);
662             }
663             return false;
664         }
665 
666         @Override
hashCode()667         public int hashCode() {
668             return Objects.hash(mHandle,
669                             mHandlePresentation,
670                             mCallerDisplayName,
671                             mCallerDisplayNamePresentation,
672                             mAccountHandle,
673                             mCallCapabilities,
674                             mCallProperties,
675                             mDisconnectCause,
676                             mConnectTimeMillis,
677                             mGatewayInfo,
678                             mVideoState,
679                             mStatusHints,
680                             mExtras,
681                             mIntentExtras,
682                             mCreationTimeMillis);
683         }
684 
685         /** {@hide} */
Details( 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)686         public Details(
687                 String telecomCallId,
688                 Uri handle,
689                 int handlePresentation,
690                 String callerDisplayName,
691                 int callerDisplayNamePresentation,
692                 PhoneAccountHandle accountHandle,
693                 int capabilities,
694                 int properties,
695                 DisconnectCause disconnectCause,
696                 long connectTimeMillis,
697                 GatewayInfo gatewayInfo,
698                 int videoState,
699                 StatusHints statusHints,
700                 Bundle extras,
701                 Bundle intentExtras,
702                 long creationTimeMillis) {
703             mTelecomCallId = telecomCallId;
704             mHandle = handle;
705             mHandlePresentation = handlePresentation;
706             mCallerDisplayName = callerDisplayName;
707             mCallerDisplayNamePresentation = callerDisplayNamePresentation;
708             mAccountHandle = accountHandle;
709             mCallCapabilities = capabilities;
710             mCallProperties = properties;
711             mDisconnectCause = disconnectCause;
712             mConnectTimeMillis = connectTimeMillis;
713             mGatewayInfo = gatewayInfo;
714             mVideoState = videoState;
715             mStatusHints = statusHints;
716             mExtras = extras;
717             mIntentExtras = intentExtras;
718             mCreationTimeMillis = creationTimeMillis;
719         }
720 
721         /** {@hide} */
createFromParcelableCall(ParcelableCall parcelableCall)722         public static Details createFromParcelableCall(ParcelableCall parcelableCall) {
723             return new Details(
724                     parcelableCall.getId(),
725                     parcelableCall.getHandle(),
726                     parcelableCall.getHandlePresentation(),
727                     parcelableCall.getCallerDisplayName(),
728                     parcelableCall.getCallerDisplayNamePresentation(),
729                     parcelableCall.getAccountHandle(),
730                     parcelableCall.getCapabilities(),
731                     parcelableCall.getProperties(),
732                     parcelableCall.getDisconnectCause(),
733                     parcelableCall.getConnectTimeMillis(),
734                     parcelableCall.getGatewayInfo(),
735                     parcelableCall.getVideoState(),
736                     parcelableCall.getStatusHints(),
737                     parcelableCall.getExtras(),
738                     parcelableCall.getIntentExtras(),
739                     parcelableCall.getCreationTimeMillis());
740         }
741 
742         @Override
toString()743         public String toString() {
744             StringBuilder sb = new StringBuilder();
745             sb.append("[pa: ");
746             sb.append(mAccountHandle);
747             sb.append(", hdl: ");
748             sb.append(Log.pii(mHandle));
749             sb.append(", caps: ");
750             sb.append(capabilitiesToString(mCallCapabilities));
751             sb.append(", props: ");
752             sb.append(propertiesToString(mCallProperties));
753             sb.append("]");
754             return sb.toString();
755         }
756     }
757 
758     /**
759      * Defines callbacks which inform the {@link InCallService} of changes to a {@link Call}.
760      * These callbacks can originate from the Telecom framework, or a {@link ConnectionService}
761      * implementation.
762      * <p>
763      * You can handle these callbacks by extending the {@link Callback} class and overriding the
764      * callbacks that your {@link InCallService} is interested in.  The callback methods include the
765      * {@link Call} for which the callback applies, allowing reuse of a single instance of your
766      * {@link Callback} implementation, if desired.
767      * <p>
768      * Use {@link Call#registerCallback(Callback)} to register your callback(s).  Ensure
769      * {@link Call#unregisterCallback(Callback)} is called when you no longer require callbacks
770      * (typically in {@link InCallService#onCallRemoved(Call)}).
771      * Note: Callbacks which occur before you call {@link Call#registerCallback(Callback)} will not
772      * reach your implementation of {@link Callback}, so it is important to register your callback
773      * as soon as your {@link InCallService} is notified of a new call via
774      * {@link InCallService#onCallAdded(Call)}.
775      */
776     public static abstract class Callback {
777         /**
778          * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
779          *
780          * @param call The {@code Call} invoking this method.
781          * @param state The new state of the {@code Call}.
782          */
onStateChanged(Call call, int state)783         public void onStateChanged(Call call, int state) {}
784 
785         /**
786          * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
787          *
788          * @param call The {@code Call} invoking this method.
789          * @param parent The new parent of the {@code Call}.
790          */
onParentChanged(Call call, Call parent)791         public void onParentChanged(Call call, Call parent) {}
792 
793         /**
794          * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
795          *
796          * @param call The {@code Call} invoking this method.
797          * @param children The new children of the {@code Call}.
798          */
onChildrenChanged(Call call, List<Call> children)799         public void onChildrenChanged(Call call, List<Call> children) {}
800 
801         /**
802          * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
803          *
804          * @param call The {@code Call} invoking this method.
805          * @param details A {@code Details} object describing the {@code Call}.
806          */
onDetailsChanged(Call call, Details details)807         public void onDetailsChanged(Call call, Details details) {}
808 
809         /**
810          * Invoked when the text messages that can be used as responses to the incoming
811          * {@code Call} are loaded from the relevant database.
812          * See {@link #getCannedTextResponses()}.
813          *
814          * @param call The {@code Call} invoking this method.
815          * @param cannedTextResponses The text messages useable as responses.
816          */
onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses)817         public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
818 
819         /**
820          * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
821          * character. This causes the post-dial signals to stop pending user confirmation. An
822          * implementation should present this choice to the user and invoke
823          * {@link #postDialContinue(boolean)} when the user makes the choice.
824          *
825          * @param call The {@code Call} invoking this method.
826          * @param remainingPostDialSequence The post-dial characters that remain to be sent.
827          */
onPostDialWait(Call call, String remainingPostDialSequence)828         public void onPostDialWait(Call call, String remainingPostDialSequence) {}
829 
830         /**
831          * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
832          *
833          * @param call The {@code Call} invoking this method.
834          * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
835          */
onVideoCallChanged(Call call, InCallService.VideoCall videoCall)836         public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
837 
838         /**
839          * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
840          * up their UI for the {@code Call} in response to state transitions. Specifically,
841          * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
842          * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
843          * clients should wait for this method to be invoked.
844          *
845          * @param call The {@code Call} being destroyed.
846          */
onCallDestroyed(Call call)847         public void onCallDestroyed(Call call) {}
848 
849         /**
850          * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
851          * conferenced.
852          *
853          * @param call The {@code Call} being updated.
854          * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
855          *          conferenced.
856          */
onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls)857         public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
858 
859         /**
860          * Invoked when a {@link Call} receives an event from its associated {@link Connection}.
861          * <p>
862          * Where possible, the Call should make an attempt to handle {@link Connection} events which
863          * are part of the {@code android.telecom.*} namespace.  The Call should ignore any events
864          * it does not wish to handle.  Unexpected events should be handled gracefully, as it is
865          * possible that a {@link ConnectionService} has defined its own Connection events which a
866          * Call is not aware of.
867          * <p>
868          * See {@link Connection#sendConnectionEvent(String, Bundle)}.
869          *
870          * @param call The {@code Call} receiving the event.
871          * @param event The event.
872          * @param extras Extras associated with the connection event.
873          */
onConnectionEvent(Call call, String event, Bundle extras)874         public void onConnectionEvent(Call call, String event, Bundle extras) {}
875 
876         /**
877          * Invoked when the RTT mode changes for this call.
878          * @param call The call whose RTT mode has changed.
879          * @param mode the new RTT mode, one of
880          * {@link RttCall#RTT_MODE_FULL}, {@link RttCall#RTT_MODE_HCO},
881          *             or {@link RttCall#RTT_MODE_VCO}
882          */
onRttModeChanged(Call call, int mode)883         public void onRttModeChanged(Call call, int mode) {}
884 
885         /**
886          * Invoked when the call's RTT status changes, either from off to on or from on to off.
887          * @param call The call whose RTT status has changed.
888          * @param enabled whether RTT is now enabled or disabled
889          * @param rttCall the {@link RttCall} object to use for reading and writing if RTT is now
890          *                on, null otherwise.
891          */
onRttStatusChanged(Call call, boolean enabled, RttCall rttCall)892         public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {}
893 
894         /**
895          * Invoked when the remote end of the connection has requested that an RTT communication
896          * channel be opened. A response to this should be sent via {@link #respondToRttRequest}
897          * with the same ID that this method is invoked with.
898          * @param call The call which the RTT request was placed on
899          * @param id The ID of the request.
900          */
onRttRequest(Call call, int id)901         public void onRttRequest(Call call, int id) {}
902 
903         /**
904          * Invoked when the RTT session failed to initiate for some reason, including rejection
905          * by the remote party.
906          * @param call The call which the RTT initiation failure occurred on.
907          * @param reason One of the status codes defined in
908          *               {@link android.telecom.Connection.RttModifyStatus}, with the exception of
909          *               {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
910          */
onRttInitiationFailure(Call call, int reason)911         public void onRttInitiationFailure(Call call, int reason) {}
912     }
913 
914     /**
915      * A class that holds the state that describes the state of the RTT channel to the remote
916      * party, if it is active.
917      */
918     public static final class RttCall {
919         /** @hide */
920         @Retention(RetentionPolicy.SOURCE)
921         @IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
922         public @interface RttAudioMode {}
923 
924         /**
925          * For metrics use. Default value in the proto.
926          * @hide
927          */
928         public static final int RTT_MODE_INVALID = 0;
929 
930         /**
931          * Indicates that there should be a bidirectional audio stream between the two parties
932          * on the call.
933          */
934         public static final int RTT_MODE_FULL = 1;
935 
936         /**
937          * Indicates that the local user should be able to hear the audio stream from the remote
938          * user, but not vice versa. Equivalent to muting the microphone.
939          */
940         public static final int RTT_MODE_HCO = 2;
941 
942         /**
943          * Indicates that the remote user should be able to hear the audio stream from the local
944          * user, but not vice versa. Equivalent to setting the volume to zero.
945          */
946         public static final int RTT_MODE_VCO = 3;
947 
948         private static final int READ_BUFFER_SIZE = 1000;
949 
950         private InputStreamReader mReceiveStream;
951         private OutputStreamWriter mTransmitStream;
952         private int mRttMode;
953         private final InCallAdapter mInCallAdapter;
954         private final String mTelecomCallId;
955         private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
956 
957         /**
958          * @hide
959          */
RttCall(String telecomCallId, InputStreamReader receiveStream, OutputStreamWriter transmitStream, int mode, InCallAdapter inCallAdapter)960         public RttCall(String telecomCallId, InputStreamReader receiveStream,
961                 OutputStreamWriter transmitStream, int mode, InCallAdapter inCallAdapter) {
962             mTelecomCallId = telecomCallId;
963             mReceiveStream = receiveStream;
964             mTransmitStream = transmitStream;
965             mRttMode = mode;
966             mInCallAdapter = inCallAdapter;
967         }
968 
969         /**
970          * Returns the current RTT audio mode.
971          * @return Current RTT audio mode. One of {@link #RTT_MODE_FULL}, {@link #RTT_MODE_VCO}, or
972          * {@link #RTT_MODE_HCO}.
973          */
getRttAudioMode()974         public int getRttAudioMode() {
975             return mRttMode;
976         }
977 
978         /**
979          * Sets the RTT audio mode. The requested mode change will be communicated through
980          * {@link Callback#onRttModeChanged(Call, int)}.
981          * @param mode The desired RTT audio mode, one of {@link #RTT_MODE_FULL},
982          * {@link #RTT_MODE_VCO}, or {@link #RTT_MODE_HCO}.
983          */
setRttMode(@ttAudioMode int mode)984         public void setRttMode(@RttAudioMode int mode) {
985             mInCallAdapter.setRttMode(mTelecomCallId, mode);
986         }
987 
988         /**
989          * Writes the string {@param input} into the outgoing text stream for this RTT call. Since
990          * RTT transmits text in real-time, this method should be called once for each character
991          * the user enters into the device.
992          *
993          * This method is not thread-safe -- calling it from multiple threads simultaneously may
994          * lead to interleaved text.
995          * @param input The message to send to the remote user.
996          */
write(String input)997         public void write(String input) throws IOException {
998             mTransmitStream.write(input);
999             mTransmitStream.flush();
1000         }
1001 
1002         /**
1003          * Reads a string from the remote user, blocking if there is no data available. Returns
1004          * {@code null} if the RTT conversation has been terminated and there is no further data
1005          * to read.
1006          *
1007          * This method is not thread-safe -- calling it from multiple threads simultaneously may
1008          * lead to interleaved text.
1009          * @return A string containing text sent by the remote user, or {@code null} if the
1010          * conversation has been terminated or if there was an error while reading.
1011          */
read()1012         public String read() {
1013             try {
1014                 int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
1015                 if (numRead < 0) {
1016                     return null;
1017                 }
1018                 return new String(mReadBuffer, 0, numRead);
1019             } catch (IOException e) {
1020                 Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
1021                 return null;
1022             }
1023         }
1024     }
1025 
1026     /**
1027      * @deprecated Use {@code Call.Callback} instead.
1028      * @hide
1029      */
1030     @Deprecated
1031     @SystemApi
1032     public static abstract class Listener extends Callback { }
1033 
1034     private final Phone mPhone;
1035     private final String mTelecomCallId;
1036     private final InCallAdapter mInCallAdapter;
1037     private final List<String> mChildrenIds = new ArrayList<>();
1038     private final List<Call> mChildren = new ArrayList<>();
1039     private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
1040     private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>();
1041     private final List<Call> mConferenceableCalls = new ArrayList<>();
1042     private final List<Call> mUnmodifiableConferenceableCalls =
1043             Collections.unmodifiableList(mConferenceableCalls);
1044 
1045     private boolean mChildrenCached;
1046     private String mParentId = null;
1047     private int mState;
1048     private List<String> mCannedTextResponses = null;
1049     private String mCallingPackage;
1050     private int mTargetSdkVersion;
1051     private String mRemainingPostDialSequence;
1052     private VideoCallImpl mVideoCallImpl;
1053     private RttCall mRttCall;
1054     private Details mDetails;
1055     private Bundle mExtras;
1056 
1057     /**
1058      * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
1059      *
1060      * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
1061      * remaining or this {@code Call} is not in a post-dial state.
1062      */
getRemainingPostDialSequence()1063     public String getRemainingPostDialSequence() {
1064         return mRemainingPostDialSequence;
1065     }
1066 
1067     /**
1068      * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
1069      * @param videoState The video state in which to answer the call.
1070      */
answer(int videoState)1071     public void answer(int videoState) {
1072         mInCallAdapter.answerCall(mTelecomCallId, videoState);
1073     }
1074 
1075     /**
1076      * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
1077      *
1078      * @param rejectWithMessage Whether to reject with a text message.
1079      * @param textMessage An optional text message with which to respond.
1080      */
reject(boolean rejectWithMessage, String textMessage)1081     public void reject(boolean rejectWithMessage, String textMessage) {
1082         mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
1083     }
1084 
1085     /**
1086      * Instructs this {@code Call} to disconnect.
1087      */
disconnect()1088     public void disconnect() {
1089         mInCallAdapter.disconnectCall(mTelecomCallId);
1090     }
1091 
1092     /**
1093      * Instructs this {@code Call} to go on hold.
1094      */
hold()1095     public void hold() {
1096         mInCallAdapter.holdCall(mTelecomCallId);
1097     }
1098 
1099     /**
1100      * Instructs this {@link #STATE_HOLDING} call to release from hold.
1101      */
unhold()1102     public void unhold() {
1103         mInCallAdapter.unholdCall(mTelecomCallId);
1104     }
1105 
1106     /**
1107      * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
1108      *
1109      * Any other currently playing DTMF tone in the specified call is immediately stopped.
1110      *
1111      * @param digit A character representing the DTMF digit for which to play the tone. This
1112      *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
1113      */
playDtmfTone(char digit)1114     public void playDtmfTone(char digit) {
1115         mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
1116     }
1117 
1118     /**
1119      * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
1120      * currently playing.
1121      *
1122      * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
1123      * currently playing, this method will do nothing.
1124      */
stopDtmfTone()1125     public void stopDtmfTone() {
1126         mInCallAdapter.stopDtmfTone(mTelecomCallId);
1127     }
1128 
1129     /**
1130      * Instructs this {@code Call} to continue playing a post-dial DTMF string.
1131      *
1132      * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
1133      * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
1134      *
1135      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
1136      * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
1137      *
1138      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
1139      * {@code Call} will pause playing the tones and notify callbacks via
1140      * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app
1141      * should display to the user an indication of this state and an affordance to continue
1142      * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
1143      * app should invoke the {@link #postDialContinue(boolean)} method.
1144      *
1145      * @param proceed Whether or not to continue with the post-dial sequence.
1146      */
postDialContinue(boolean proceed)1147     public void postDialContinue(boolean proceed) {
1148         mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
1149     }
1150 
1151     /**
1152      * Notifies this {@code Call} that an account has been selected and to proceed with placing
1153      * an outgoing call. Optionally sets this account as the default account.
1154      */
phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault)1155     public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
1156         mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
1157 
1158     }
1159 
1160     /**
1161      * Instructs this {@code Call} to enter a conference.
1162      *
1163      * @param callToConferenceWith The other call with which to conference.
1164      */
conference(Call callToConferenceWith)1165     public void conference(Call callToConferenceWith) {
1166         if (callToConferenceWith != null) {
1167             mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
1168         }
1169     }
1170 
1171     /**
1172      * Instructs this {@code Call} to split from any conference call with which it may be
1173      * connected.
1174      */
splitFromConference()1175     public void splitFromConference() {
1176         mInCallAdapter.splitFromConference(mTelecomCallId);
1177     }
1178 
1179     /**
1180      * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}.
1181      */
mergeConference()1182     public void mergeConference() {
1183         mInCallAdapter.mergeConference(mTelecomCallId);
1184     }
1185 
1186     /**
1187      * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
1188      */
swapConference()1189     public void swapConference() {
1190         mInCallAdapter.swapConference(mTelecomCallId);
1191     }
1192 
1193     /**
1194      * Initiates a request to the {@link ConnectionService} to pull an external call to the local
1195      * device.
1196      * <p>
1197      * Calls to this method are ignored if the call does not have the
1198      * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} property set.
1199      * <p>
1200      * An {@link InCallService} will only see calls which support this method if it has the
1201      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
1202      * in its manifest.
1203      */
pullExternalCall()1204     public void pullExternalCall() {
1205         // If this isn't an external call, ignore the request.
1206         if (!mDetails.hasProperty(Details.PROPERTY_IS_EXTERNAL_CALL)) {
1207             return;
1208         }
1209 
1210         mInCallAdapter.pullExternalCall(mTelecomCallId);
1211     }
1212 
1213     /**
1214      * Sends a {@code Call} event from this {@code Call} to the associated {@link Connection} in
1215      * the {@link ConnectionService}.
1216      * <p>
1217      * Call events are used to communicate point in time information from an {@link InCallService}
1218      * to a {@link ConnectionService}.  A {@link ConnectionService} implementation could define
1219      * events which enable the {@link InCallService}, for example, toggle a unique feature of the
1220      * {@link ConnectionService}.
1221      * <p>
1222      * A {@link ConnectionService} can communicate to the {@link InCallService} using
1223      * {@link Connection#sendConnectionEvent(String, Bundle)}.
1224      * <p>
1225      * Events are exposed to {@link ConnectionService} implementations via
1226      * {@link android.telecom.Connection#onCallEvent(String, Bundle)}.
1227      * <p>
1228      * No assumptions should be made as to how a {@link ConnectionService} will handle these events.
1229      * The {@link InCallService} must assume that the {@link ConnectionService} could chose to
1230      * ignore some events altogether.
1231      * <p>
1232      * Events should be fully qualified (e.g., {@code com.example.event.MY_EVENT}) to avoid
1233      * conflicts between {@link InCallService} implementations.  Further, {@link InCallService}
1234      * implementations shall not re-purpose events in the {@code android.*} namespace, nor shall
1235      * they define their own event types in this namespace.  When defining a custom event type,
1236      * ensure the contents of the extras {@link Bundle} is clearly defined.  Extra keys for this
1237      * bundle should be named similar to the event type (e.g. {@code com.example.extra.MY_EXTRA}).
1238      * <p>
1239      * When defining events and the associated extras, it is important to keep their behavior
1240      * consistent when the associated {@link InCallService} is updated.  Support for deprecated
1241      * events/extras should me maintained to ensure backwards compatibility with older
1242      * {@link ConnectionService} implementations which were built to support the older behavior.
1243      *
1244      * @param event The connection event.
1245      * @param extras Bundle containing extra information associated with the event.
1246      */
sendCallEvent(String event, Bundle extras)1247     public void sendCallEvent(String event, Bundle extras) {
1248         mInCallAdapter.sendCallEvent(mTelecomCallId, event, extras);
1249     }
1250 
1251     /**
1252      * Sends an RTT upgrade request to the remote end of the connection. Success is not
1253      * guaranteed, and notification of success will be via the
1254      * {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
1255      */
sendRttRequest()1256     public void sendRttRequest() {
1257         mInCallAdapter.sendRttRequest(mTelecomCallId);
1258     }
1259 
1260     /**
1261      * Responds to an RTT request received via the {@link Callback#onRttRequest(Call, int)} )}
1262      * callback.
1263      * The ID used here should be the same as the ID that was received via the callback.
1264      * @param id The request ID received via {@link Callback#onRttRequest(Call, int)}
1265      * @param accept {@code true} if the RTT request should be accepted, {@code false} otherwise.
1266      */
respondToRttRequest(int id, boolean accept)1267     public void respondToRttRequest(int id, boolean accept) {
1268         mInCallAdapter.respondToRttRequest(mTelecomCallId, id, accept);
1269     }
1270 
1271     /**
1272      * Terminate the RTT session on this call. The resulting state change will be notified via
1273      * the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
1274      */
stopRtt()1275     public void stopRtt() {
1276         mInCallAdapter.stopRtt(mTelecomCallId);
1277     }
1278 
1279     /**
1280      * Adds some extras to this {@link Call}.  Existing keys are replaced and new ones are
1281      * added.
1282      * <p>
1283      * No assumptions should be made as to how an In-Call UI or service will handle these
1284      * extras.  Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
1285      *
1286      * @param extras The extras to add.
1287      */
putExtras(Bundle extras)1288     public final void putExtras(Bundle extras) {
1289         if (extras == null) {
1290             return;
1291         }
1292 
1293         if (mExtras == null) {
1294             mExtras = new Bundle();
1295         }
1296         mExtras.putAll(extras);
1297         mInCallAdapter.putExtras(mTelecomCallId, extras);
1298     }
1299 
1300     /**
1301      * Adds a boolean extra to this {@link Call}.
1302      *
1303      * @param key The extra key.
1304      * @param value The value.
1305      * @hide
1306      */
putExtra(String key, boolean value)1307     public final void putExtra(String key, boolean value) {
1308         if (mExtras == null) {
1309             mExtras = new Bundle();
1310         }
1311         mExtras.putBoolean(key, value);
1312         mInCallAdapter.putExtra(mTelecomCallId, key, value);
1313     }
1314 
1315     /**
1316      * Adds an integer extra to this {@link Call}.
1317      *
1318      * @param key The extra key.
1319      * @param value The value.
1320      * @hide
1321      */
putExtra(String key, int value)1322     public final void putExtra(String key, int value) {
1323         if (mExtras == null) {
1324             mExtras = new Bundle();
1325         }
1326         mExtras.putInt(key, value);
1327         mInCallAdapter.putExtra(mTelecomCallId, key, value);
1328     }
1329 
1330     /**
1331      * Adds a string extra to this {@link Call}.
1332      *
1333      * @param key The extra key.
1334      * @param value The value.
1335      * @hide
1336      */
putExtra(String key, String value)1337     public final void putExtra(String key, String value) {
1338         if (mExtras == null) {
1339             mExtras = new Bundle();
1340         }
1341         mExtras.putString(key, value);
1342         mInCallAdapter.putExtra(mTelecomCallId, key, value);
1343     }
1344 
1345     /**
1346      * Removes extras from this {@link Call}.
1347      *
1348      * @param keys The keys of the extras to remove.
1349      */
removeExtras(List<String> keys)1350     public final void removeExtras(List<String> keys) {
1351         if (mExtras != null) {
1352             for (String key : keys) {
1353                 mExtras.remove(key);
1354             }
1355             if (mExtras.size() == 0) {
1356                 mExtras = null;
1357             }
1358         }
1359         mInCallAdapter.removeExtras(mTelecomCallId, keys);
1360     }
1361 
1362     /**
1363      * Removes extras from this {@link Call}.
1364      *
1365      * @param keys The keys of the extras to remove.
1366      */
removeExtras(String .... keys)1367     public final void removeExtras(String ... keys) {
1368         removeExtras(Arrays.asList(keys));
1369     }
1370 
1371     /**
1372      * Obtains the parent of this {@code Call} in a conference, if any.
1373      *
1374      * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
1375      * child of any conference {@code Call}s.
1376      */
getParent()1377     public Call getParent() {
1378         if (mParentId != null) {
1379             return mPhone.internalGetCallByTelecomId(mParentId);
1380         }
1381         return null;
1382     }
1383 
1384     /**
1385      * Obtains the children of this conference {@code Call}, if any.
1386      *
1387      * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
1388      * {@code List} otherwise.
1389      */
getChildren()1390     public List<Call> getChildren() {
1391         if (!mChildrenCached) {
1392             mChildrenCached = true;
1393             mChildren.clear();
1394 
1395             for(String id : mChildrenIds) {
1396                 Call call = mPhone.internalGetCallByTelecomId(id);
1397                 if (call == null) {
1398                     // At least one child was still not found, so do not save true for "cached"
1399                     mChildrenCached = false;
1400                 } else {
1401                     mChildren.add(call);
1402                 }
1403             }
1404         }
1405 
1406         return mUnmodifiableChildren;
1407     }
1408 
1409     /**
1410      * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
1411      *
1412      * @return The list of conferenceable {@code Call}s.
1413      */
getConferenceableCalls()1414     public List<Call> getConferenceableCalls() {
1415         return mUnmodifiableConferenceableCalls;
1416     }
1417 
1418     /**
1419      * Obtains the state of this {@code Call}.
1420      *
1421      * @return A state value, chosen from the {@code STATE_*} constants.
1422      */
getState()1423     public int getState() {
1424         return mState;
1425     }
1426 
1427     /**
1428      * Obtains a list of canned, pre-configured message responses to present to the user as
1429      * ways of rejecting this {@code Call} using via a text message.
1430      *
1431      * @see #reject(boolean, String)
1432      *
1433      * @return A list of canned text message responses.
1434      */
getCannedTextResponses()1435     public List<String> getCannedTextResponses() {
1436         return mCannedTextResponses;
1437     }
1438 
1439     /**
1440      * Obtains an object that can be used to display video from this {@code Call}.
1441      *
1442      * @return An {@code Call.VideoCall}.
1443      */
getVideoCall()1444     public InCallService.VideoCall getVideoCall() {
1445         return mVideoCallImpl;
1446     }
1447 
1448     /**
1449      * Obtains an object containing call details.
1450      *
1451      * @return A {@link Details} object. Depending on the state of the {@code Call}, the
1452      * result may be {@code null}.
1453      */
getDetails()1454     public Details getDetails() {
1455         return mDetails;
1456     }
1457 
1458     /**
1459      * Returns this call's RttCall object. The {@link RttCall} instance is used to send and
1460      * receive RTT text data, as well as to change the RTT mode.
1461      * @return A {@link Call.RttCall}. {@code null} if there is no active RTT connection.
1462      */
getRttCall()1463     public @Nullable RttCall getRttCall() {
1464         return mRttCall;
1465     }
1466 
1467     /**
1468      * Returns whether this call has an active RTT connection.
1469      * @return true if there is a connection, false otherwise.
1470      */
isRttActive()1471     public boolean isRttActive() {
1472         return mRttCall != null;
1473     }
1474 
1475     /**
1476      * Registers a callback to this {@code Call}.
1477      *
1478      * @param callback A {@code Callback}.
1479      */
registerCallback(Callback callback)1480     public void registerCallback(Callback callback) {
1481         registerCallback(callback, new Handler());
1482     }
1483 
1484     /**
1485      * Registers a callback to this {@code Call}.
1486      *
1487      * @param callback A {@code Callback}.
1488      * @param handler A handler which command and status changes will be delivered to.
1489      */
registerCallback(Callback callback, Handler handler)1490     public void registerCallback(Callback callback, Handler handler) {
1491         unregisterCallback(callback);
1492         // Don't allow new callback registration if the call is already being destroyed.
1493         if (callback != null && handler != null && mState != STATE_DISCONNECTED) {
1494             mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler));
1495         }
1496     }
1497 
1498     /**
1499      * Unregisters a callback from this {@code Call}.
1500      *
1501      * @param callback A {@code Callback}.
1502      */
unregisterCallback(Callback callback)1503     public void unregisterCallback(Callback callback) {
1504         // Don't allow callback deregistration if the call is already being destroyed.
1505         if (callback != null && mState != STATE_DISCONNECTED) {
1506             for (CallbackRecord<Callback> record : mCallbackRecords) {
1507                 if (record.getCallback() == callback) {
1508                     mCallbackRecords.remove(record);
1509                     break;
1510                 }
1511             }
1512         }
1513     }
1514 
1515     @Override
toString()1516     public String toString() {
1517         return new StringBuilder().
1518                 append("Call [id: ").
1519                 append(mTelecomCallId).
1520                 append(", state: ").
1521                 append(stateToString(mState)).
1522                 append(", details: ").
1523                 append(mDetails).
1524                 append("]").toString();
1525     }
1526 
1527     /**
1528      * @param state An integer value of a {@code STATE_*} constant.
1529      * @return A string representation of the value.
1530      */
stateToString(int state)1531     private static String stateToString(int state) {
1532         switch (state) {
1533             case STATE_NEW:
1534                 return "NEW";
1535             case STATE_RINGING:
1536                 return "RINGING";
1537             case STATE_DIALING:
1538                 return "DIALING";
1539             case STATE_ACTIVE:
1540                 return "ACTIVE";
1541             case STATE_HOLDING:
1542                 return "HOLDING";
1543             case STATE_DISCONNECTED:
1544                 return "DISCONNECTED";
1545             case STATE_CONNECTING:
1546                 return "CONNECTING";
1547             case STATE_DISCONNECTING:
1548                 return "DISCONNECTING";
1549             case STATE_SELECT_PHONE_ACCOUNT:
1550                 return "SELECT_PHONE_ACCOUNT";
1551             default:
1552                 Log.w(Call.class, "Unknown state %d", state);
1553                 return "UNKNOWN";
1554         }
1555     }
1556 
1557     /**
1558      * Adds a listener to this {@code Call}.
1559      *
1560      * @param listener A {@code Listener}.
1561      * @deprecated Use {@link #registerCallback} instead.
1562      * @hide
1563      */
1564     @Deprecated
1565     @SystemApi
addListener(Listener listener)1566     public void addListener(Listener listener) {
1567         registerCallback(listener);
1568     }
1569 
1570     /**
1571      * Removes a listener from this {@code Call}.
1572      *
1573      * @param listener A {@code Listener}.
1574      * @deprecated Use {@link #unregisterCallback} instead.
1575      * @hide
1576      */
1577     @Deprecated
1578     @SystemApi
removeListener(Listener listener)1579     public void removeListener(Listener listener) {
1580         unregisterCallback(listener);
1581     }
1582 
1583     /** {@hide} */
Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage, int targetSdkVersion)1584     Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage,
1585          int targetSdkVersion) {
1586         mPhone = phone;
1587         mTelecomCallId = telecomCallId;
1588         mInCallAdapter = inCallAdapter;
1589         mState = STATE_NEW;
1590         mCallingPackage = callingPackage;
1591         mTargetSdkVersion = targetSdkVersion;
1592     }
1593 
1594     /** {@hide} */
Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state, String callingPackage, int targetSdkVersion)1595     Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state,
1596             String callingPackage, int targetSdkVersion) {
1597         mPhone = phone;
1598         mTelecomCallId = telecomCallId;
1599         mInCallAdapter = inCallAdapter;
1600         mState = state;
1601         mCallingPackage = callingPackage;
1602         mTargetSdkVersion = targetSdkVersion;
1603     }
1604 
1605     /** {@hide} */
internalGetCallId()1606     final String internalGetCallId() {
1607         return mTelecomCallId;
1608     }
1609 
1610     /** {@hide} */
internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap)1611     final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
1612 
1613         // First, we update the internal state as far as possible before firing any updates.
1614         Details details = Details.createFromParcelableCall(parcelableCall);
1615         boolean detailsChanged = !Objects.equals(mDetails, details);
1616         if (detailsChanged) {
1617             mDetails = details;
1618         }
1619 
1620         boolean cannedTextResponsesChanged = false;
1621         if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
1622                 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
1623             mCannedTextResponses =
1624                     Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
1625             cannedTextResponsesChanged = true;
1626         }
1627 
1628         VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage,
1629                 mTargetSdkVersion);
1630         boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
1631                 !Objects.equals(mVideoCallImpl, newVideoCallImpl);
1632         if (videoCallChanged) {
1633             mVideoCallImpl = newVideoCallImpl;
1634         }
1635         if (mVideoCallImpl != null) {
1636             mVideoCallImpl.setVideoState(getDetails().getVideoState());
1637         }
1638 
1639         int state = parcelableCall.getState();
1640         boolean stateChanged = mState != state;
1641         if (stateChanged) {
1642             mState = state;
1643         }
1644 
1645         String parentId = parcelableCall.getParentCallId();
1646         boolean parentChanged = !Objects.equals(mParentId, parentId);
1647         if (parentChanged) {
1648             mParentId = parentId;
1649         }
1650 
1651         List<String> childCallIds = parcelableCall.getChildCallIds();
1652         boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
1653         if (childrenChanged) {
1654             mChildrenIds.clear();
1655             mChildrenIds.addAll(parcelableCall.getChildCallIds());
1656             mChildrenCached = false;
1657         }
1658 
1659         List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
1660         List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
1661         for (String otherId : conferenceableCallIds) {
1662             if (callIdMap.containsKey(otherId)) {
1663                 conferenceableCalls.add(callIdMap.get(otherId));
1664             }
1665         }
1666 
1667         if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
1668             mConferenceableCalls.clear();
1669             mConferenceableCalls.addAll(conferenceableCalls);
1670             fireConferenceableCallsChanged();
1671         }
1672 
1673         boolean isRttChanged = false;
1674         boolean rttModeChanged = false;
1675         if (parcelableCall.getParcelableRttCall() != null && parcelableCall.getIsRttCallChanged()) {
1676             ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
1677             InputStreamReader receiveStream = new InputStreamReader(
1678                     new ParcelFileDescriptor.AutoCloseInputStream(
1679                             parcelableRttCall.getReceiveStream()),
1680                     StandardCharsets.UTF_8);
1681             OutputStreamWriter transmitStream = new OutputStreamWriter(
1682                     new ParcelFileDescriptor.AutoCloseOutputStream(
1683                             parcelableRttCall.getTransmitStream()),
1684                     StandardCharsets.UTF_8);
1685             RttCall newRttCall = new Call.RttCall(mTelecomCallId,
1686                     receiveStream, transmitStream, parcelableRttCall.getRttMode(), mInCallAdapter);
1687             if (mRttCall == null) {
1688                 isRttChanged = true;
1689             } else if (mRttCall.getRttAudioMode() != newRttCall.getRttAudioMode()) {
1690                 rttModeChanged = true;
1691             }
1692             mRttCall = newRttCall;
1693         } else if (mRttCall != null && parcelableCall.getParcelableRttCall() == null
1694                 && parcelableCall.getIsRttCallChanged()) {
1695             isRttChanged = true;
1696             mRttCall = null;
1697         }
1698 
1699         // Now we fire updates, ensuring that any client who listens to any of these notifications
1700         // gets the most up-to-date state.
1701 
1702         if (stateChanged) {
1703             fireStateChanged(mState);
1704         }
1705         if (detailsChanged) {
1706             fireDetailsChanged(mDetails);
1707         }
1708         if (cannedTextResponsesChanged) {
1709             fireCannedTextResponsesLoaded(mCannedTextResponses);
1710         }
1711         if (videoCallChanged) {
1712             fireVideoCallChanged(mVideoCallImpl);
1713         }
1714         if (parentChanged) {
1715             fireParentChanged(getParent());
1716         }
1717         if (childrenChanged) {
1718             fireChildrenChanged(getChildren());
1719         }
1720         if (isRttChanged) {
1721             fireOnIsRttChanged(mRttCall != null, mRttCall);
1722         }
1723         if (rttModeChanged) {
1724             fireOnRttModeChanged(mRttCall.getRttAudioMode());
1725         }
1726 
1727         // If we have transitioned to DISCONNECTED, that means we need to notify clients and
1728         // remove ourselves from the Phone. Note that we do this after completing all state updates
1729         // so a client can cleanly transition all their UI to the state appropriate for a
1730         // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
1731         if (mState == STATE_DISCONNECTED) {
1732             fireCallDestroyed();
1733         }
1734     }
1735 
1736     /** {@hide} */
internalSetPostDialWait(String remaining)1737     final void internalSetPostDialWait(String remaining) {
1738         mRemainingPostDialSequence = remaining;
1739         firePostDialWait(mRemainingPostDialSequence);
1740     }
1741 
1742     /** {@hide} */
internalSetDisconnected()1743     final void internalSetDisconnected() {
1744         if (mState != Call.STATE_DISCONNECTED) {
1745             mState = Call.STATE_DISCONNECTED;
1746             fireStateChanged(mState);
1747             fireCallDestroyed();
1748         }
1749     }
1750 
1751     /** {@hide} */
internalOnConnectionEvent(String event, Bundle extras)1752     final void internalOnConnectionEvent(String event, Bundle extras) {
1753         fireOnConnectionEvent(event, extras);
1754     }
1755 
1756     /** {@hide} */
internalOnRttUpgradeRequest(final int requestId)1757     final void internalOnRttUpgradeRequest(final int requestId) {
1758         for (CallbackRecord<Callback> record : mCallbackRecords) {
1759             final Call call = this;
1760             final Callback callback = record.getCallback();
1761             record.getHandler().post(() -> callback.onRttRequest(call, requestId));
1762         }
1763     }
1764 
1765     /** @hide */
internalOnRttInitiationFailure(int reason)1766     final void internalOnRttInitiationFailure(int reason) {
1767         for (CallbackRecord<Callback> record : mCallbackRecords) {
1768             final Call call = this;
1769             final Callback callback = record.getCallback();
1770             record.getHandler().post(() -> callback.onRttInitiationFailure(call, reason));
1771         }
1772     }
1773 
fireStateChanged(final int newState)1774     private void fireStateChanged(final int newState) {
1775         for (CallbackRecord<Callback> record : mCallbackRecords) {
1776             final Call call = this;
1777             final Callback callback = record.getCallback();
1778             record.getHandler().post(new Runnable() {
1779                 @Override
1780                 public void run() {
1781                     callback.onStateChanged(call, newState);
1782                 }
1783             });
1784         }
1785     }
1786 
fireParentChanged(final Call newParent)1787     private void fireParentChanged(final Call newParent) {
1788         for (CallbackRecord<Callback> record : mCallbackRecords) {
1789             final Call call = this;
1790             final Callback callback = record.getCallback();
1791             record.getHandler().post(new Runnable() {
1792                 @Override
1793                 public void run() {
1794                     callback.onParentChanged(call, newParent);
1795                 }
1796             });
1797         }
1798     }
1799 
fireChildrenChanged(final List<Call> children)1800     private void fireChildrenChanged(final List<Call> children) {
1801         for (CallbackRecord<Callback> record : mCallbackRecords) {
1802             final Call call = this;
1803             final Callback callback = record.getCallback();
1804             record.getHandler().post(new Runnable() {
1805                 @Override
1806                 public void run() {
1807                     callback.onChildrenChanged(call, children);
1808                 }
1809             });
1810         }
1811     }
1812 
fireDetailsChanged(final Details details)1813     private void fireDetailsChanged(final Details details) {
1814         for (CallbackRecord<Callback> record : mCallbackRecords) {
1815             final Call call = this;
1816             final Callback callback = record.getCallback();
1817             record.getHandler().post(new Runnable() {
1818                 @Override
1819                 public void run() {
1820                     callback.onDetailsChanged(call, details);
1821                 }
1822             });
1823         }
1824     }
1825 
fireCannedTextResponsesLoaded(final List<String> cannedTextResponses)1826     private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) {
1827         for (CallbackRecord<Callback> record : mCallbackRecords) {
1828             final Call call = this;
1829             final Callback callback = record.getCallback();
1830             record.getHandler().post(new Runnable() {
1831                 @Override
1832                 public void run() {
1833                     callback.onCannedTextResponsesLoaded(call, cannedTextResponses);
1834                 }
1835             });
1836         }
1837     }
1838 
fireVideoCallChanged(final InCallService.VideoCall videoCall)1839     private void fireVideoCallChanged(final InCallService.VideoCall videoCall) {
1840         for (CallbackRecord<Callback> record : mCallbackRecords) {
1841             final Call call = this;
1842             final Callback callback = record.getCallback();
1843             record.getHandler().post(new Runnable() {
1844                 @Override
1845                 public void run() {
1846                     callback.onVideoCallChanged(call, videoCall);
1847                 }
1848             });
1849         }
1850     }
1851 
firePostDialWait(final String remainingPostDialSequence)1852     private void firePostDialWait(final String remainingPostDialSequence) {
1853         for (CallbackRecord<Callback> record : mCallbackRecords) {
1854             final Call call = this;
1855             final Callback callback = record.getCallback();
1856             record.getHandler().post(new Runnable() {
1857                 @Override
1858                 public void run() {
1859                     callback.onPostDialWait(call, remainingPostDialSequence);
1860                 }
1861             });
1862         }
1863     }
1864 
fireCallDestroyed()1865     private void fireCallDestroyed() {
1866         /**
1867          * To preserve the ordering of the Call's onCallDestroyed callback and Phone's
1868          * onCallRemoved callback, we remove this call from the Phone's record
1869          * only once all of the registered onCallDestroyed callbacks are executed.
1870          * All the callbacks get removed from our records as a part of this operation
1871          * since onCallDestroyed is the final callback.
1872          */
1873         final Call call = this;
1874         if (mCallbackRecords.isEmpty()) {
1875             // No callbacks registered, remove the call from Phone's record.
1876             mPhone.internalRemoveCall(call);
1877         }
1878         for (final CallbackRecord<Callback> record : mCallbackRecords) {
1879             final Callback callback = record.getCallback();
1880             record.getHandler().post(new Runnable() {
1881                 @Override
1882                 public void run() {
1883                     boolean isFinalRemoval = false;
1884                     RuntimeException toThrow = null;
1885                     try {
1886                         callback.onCallDestroyed(call);
1887                     } catch (RuntimeException e) {
1888                             toThrow = e;
1889                     }
1890                     synchronized(Call.this) {
1891                         mCallbackRecords.remove(record);
1892                         if (mCallbackRecords.isEmpty()) {
1893                             isFinalRemoval = true;
1894                         }
1895                     }
1896                     if (isFinalRemoval) {
1897                         mPhone.internalRemoveCall(call);
1898                     }
1899                     if (toThrow != null) {
1900                         throw toThrow;
1901                     }
1902                 }
1903             });
1904         }
1905     }
1906 
fireConferenceableCallsChanged()1907     private void fireConferenceableCallsChanged() {
1908         for (CallbackRecord<Callback> record : mCallbackRecords) {
1909             final Call call = this;
1910             final Callback callback = record.getCallback();
1911             record.getHandler().post(new Runnable() {
1912                 @Override
1913                 public void run() {
1914                     callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls);
1915                 }
1916             });
1917         }
1918     }
1919 
1920     /**
1921      * Notifies listeners of an incoming connection event.
1922      * <p>
1923      * Connection events are issued via {@link Connection#sendConnectionEvent(String, Bundle)}.
1924      *
1925      * @param event
1926      * @param extras
1927      */
fireOnConnectionEvent(final String event, final Bundle extras)1928     private void fireOnConnectionEvent(final String event, final Bundle extras) {
1929         for (CallbackRecord<Callback> record : mCallbackRecords) {
1930             final Call call = this;
1931             final Callback callback = record.getCallback();
1932             record.getHandler().post(new Runnable() {
1933                 @Override
1934                 public void run() {
1935                     callback.onConnectionEvent(call, event, extras);
1936                 }
1937             });
1938         }
1939     }
1940 
1941     /**
1942      * Notifies listeners of an RTT on/off change
1943      *
1944      * @param enabled True if RTT is now enabled, false otherwise
1945      */
fireOnIsRttChanged(final boolean enabled, final RttCall rttCall)1946     private void fireOnIsRttChanged(final boolean enabled, final RttCall rttCall) {
1947         for (CallbackRecord<Callback> record : mCallbackRecords) {
1948             final Call call = this;
1949             final Callback callback = record.getCallback();
1950             record.getHandler().post(() -> callback.onRttStatusChanged(call, enabled, rttCall));
1951         }
1952     }
1953 
1954     /**
1955      * Notifies listeners of a RTT mode change
1956      *
1957      * @param mode The new RTT mode
1958      */
fireOnRttModeChanged(final int mode)1959     private void fireOnRttModeChanged(final int mode) {
1960         for (CallbackRecord<Callback> record : mCallbackRecords) {
1961             final Call call = this;
1962             final Callback callback = record.getCallback();
1963             record.getHandler().post(() -> callback.onRttModeChanged(call, mode));
1964         }
1965     }
1966 
1967     /**
1968      * Determines if two bundles are equal.
1969      *
1970      * @param bundle The original bundle.
1971      * @param newBundle The bundle to compare with.
1972      * @retrun {@code true} if the bundles are equal, {@code false} otherwise.
1973      */
areBundlesEqual(Bundle bundle, Bundle newBundle)1974     private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) {
1975         if (bundle == null || newBundle == null) {
1976             return bundle == newBundle;
1977         }
1978 
1979         if (bundle.size() != newBundle.size()) {
1980             return false;
1981         }
1982 
1983         for(String key : bundle.keySet()) {
1984             if (key != null) {
1985                 final Object value = bundle.get(key);
1986                 final Object newValue = newBundle.get(key);
1987                 if (!Objects.equals(value, newValue)) {
1988                     return false;
1989                 }
1990             }
1991         }
1992         return true;
1993     }
1994 }
1995