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