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