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