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