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