Call.java revision 164a0acf53a3496c974a97ed35834e6195c14e4b
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_BIDIRECTIONAL =
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_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         * 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 type can be modified for IMS call
226         * @hide
227         */
228        public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
229
230        //******************************************************************************************
231        // Next CAPABILITY value: 0x00100000
232        //******************************************************************************************
233
234        private final Uri mHandle;
235        private final int mHandlePresentation;
236        private final String mCallerDisplayName;
237        private final int mCallerDisplayNamePresentation;
238        private final PhoneAccountHandle mAccountHandle;
239        private final int mCallCapabilities;
240        private final int mCallProperties;
241        private final DisconnectCause mDisconnectCause;
242        private final long mConnectTimeMillis;
243        private final GatewayInfo mGatewayInfo;
244        private final int mVideoState;
245        private final StatusHints mStatusHints;
246        private final Bundle mExtras;
247        private final int mCallSubstate;
248
249        /**
250         * Whether the supplied capabilities  supports the specified capability.
251         *
252         * @param capabilities A bit field of capabilities.
253         * @param capability The capability to check capabilities for.
254         * @return Whether the specified capability is supported.
255         * @hide
256         */
257        public static boolean can(int capabilities, int capability) {
258            return (capabilities & capability) != 0;
259        }
260
261        /**
262         * Whether the capabilities of this {@code Details} supports the specified capability.
263         *
264         * @param capability The capability to check capabilities for.
265         * @return Whether the specified capability is supported.
266         * @hide
267         */
268        public boolean can(int capability) {
269            return can(mCallCapabilities, capability);
270        }
271
272        /**
273         * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
274         *
275         * @param capabilities A capability bit field.
276         * @return A human readable string representation.
277         */
278        public static String capabilitiesToString(int capabilities) {
279            StringBuilder builder = new StringBuilder();
280            builder.append("[Capabilities:");
281            if (can(capabilities, CAPABILITY_HOLD)) {
282                builder.append(" CAPABILITY_HOLD");
283            }
284            if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
285                builder.append(" CAPABILITY_SUPPORT_HOLD");
286            }
287            if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
288                builder.append(" CAPABILITY_MERGE_CONFERENCE");
289            }
290            if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
291                builder.append(" CAPABILITY_SWAP_CONFERENCE");
292            }
293            if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
294                builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
295            }
296            if (can(capabilities, CAPABILITY_MUTE)) {
297                builder.append(" CAPABILITY_MUTE");
298            }
299            if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
300                builder.append(" CAPABILITY_MANAGE_CONFERENCE");
301            }
302            if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
303                builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
304            }
305            if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
306                builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
307            }
308            if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
309                builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
310            }
311            if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
312                builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
313            }
314            if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
315                builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
316            }
317            if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
318                builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
319            }
320            if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
321                builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
322            }
323            if (can(capabilities, CAPABILITY_WIFI)) {
324                builder.append(" CAPABILITY_WIFI");
325            }
326            if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) {
327                builder.append(" CAPABILITY_GENERIC_CONFERENCE");
328            }
329            if (can(capabilities, CAPABILITY_SHOW_CALLBACK_NUMBER)) {
330                builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
331            }
332            if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
333                builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
334            }
335            if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
336                builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
337            }
338            builder.append("]");
339            return builder.toString();
340        }
341
342        /**
343         * @return The handle (e.g., phone number) to which the {@code Call} is currently
344         * connected.
345         */
346        public Uri getHandle() {
347            return mHandle;
348        }
349
350        /**
351         * @return The presentation requirements for the handle. See
352         * {@link TelecomManager} for valid values.
353         */
354        public int getHandlePresentation() {
355            return mHandlePresentation;
356        }
357
358        /**
359         * @return The display name for the caller.
360         */
361        public String getCallerDisplayName() {
362            return mCallerDisplayName;
363        }
364
365        /**
366         * @return The presentation requirements for the caller display name. See
367         * {@link TelecomManager} for valid values.
368         */
369        public int getCallerDisplayNamePresentation() {
370            return mCallerDisplayNamePresentation;
371        }
372
373        /**
374         * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
375         * routed.
376         */
377        public PhoneAccountHandle getAccountHandle() {
378            return mAccountHandle;
379        }
380
381        /**
382         * @return A bitmask of the capabilities of the {@code Call}, as defined by the various
383         *         {@code CAPABILITY_*} constants in this class.
384         */
385        public int getCallCapabilities() {
386            return mCallCapabilities;
387        }
388
389        /**
390         * @return A bitmask of the properties of the {@code Call}, as defined in
391         *         {@link CallProperties}.
392         */
393        public int getCallProperties() {
394            return mCallProperties;
395        }
396
397        /**
398         * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
399         * by {@link android.telecom.DisconnectCause}.
400         */
401        public DisconnectCause getDisconnectCause() {
402            return mDisconnectCause;
403        }
404
405        /**
406         * @return The time the {@code Call} has been connected. This information is updated
407         * periodically, but user interfaces should not rely on this to display any "call time
408         * clock".
409         */
410        public final long getConnectTimeMillis() {
411            return mConnectTimeMillis;
412        }
413
414        /**
415         * @return Information about any calling gateway the {@code Call} may be using.
416         */
417        public GatewayInfo getGatewayInfo() {
418            return mGatewayInfo;
419        }
420
421        /**
422         * @return The video state of the {@code Call}.
423         */
424        public int getVideoState() {
425            return mVideoState;
426        }
427
428        /**
429         * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
430         * have been set.
431         */
432        public StatusHints getStatusHints() {
433            return mStatusHints;
434        }
435
436        /**
437         * @return A bundle extras to pass with the call
438         */
439        public Bundle getExtras() {
440            return mExtras;
441        }
442
443        /**
444         * @return The substate of the {@code Call}.
445         * @hide
446         */
447        public int getCallSubstate() {
448            return mCallSubstate;
449        }
450
451        @Override
452        public boolean equals(Object o) {
453            if (o instanceof Details) {
454                Details d = (Details) o;
455                return
456                        Objects.equals(mHandle, d.mHandle) &&
457                        Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
458                        Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
459                        Objects.equals(mCallerDisplayNamePresentation,
460                                d.mCallerDisplayNamePresentation) &&
461                        Objects.equals(mAccountHandle, d.mAccountHandle) &&
462                        Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
463                        Objects.equals(mCallProperties, d.mCallProperties) &&
464                        Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
465                        Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
466                        Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
467                        Objects.equals(mVideoState, d.mVideoState) &&
468                        Objects.equals(mStatusHints, d.mStatusHints) &&
469                        Objects.equals(mExtras, d.mExtras) &&
470                        Objects.equals(mCallSubstate, d.mCallSubstate);
471            }
472            return false;
473        }
474
475        @Override
476        public int hashCode() {
477            return
478                    Objects.hashCode(mHandle) +
479                    Objects.hashCode(mHandlePresentation) +
480                    Objects.hashCode(mCallerDisplayName) +
481                    Objects.hashCode(mCallerDisplayNamePresentation) +
482                    Objects.hashCode(mAccountHandle) +
483                    Objects.hashCode(mCallCapabilities) +
484                    Objects.hashCode(mCallProperties) +
485                    Objects.hashCode(mDisconnectCause) +
486                    Objects.hashCode(mConnectTimeMillis) +
487                    Objects.hashCode(mGatewayInfo) +
488                    Objects.hashCode(mVideoState) +
489                    Objects.hashCode(mStatusHints) +
490                    Objects.hashCode(mExtras) +
491                    Objects.hashCode(mCallSubstate);
492        }
493
494        /** {@hide} */
495        public Details(
496                Uri handle,
497                int handlePresentation,
498                String callerDisplayName,
499                int callerDisplayNamePresentation,
500                PhoneAccountHandle accountHandle,
501                int capabilities,
502                int properties,
503                DisconnectCause disconnectCause,
504                long connectTimeMillis,
505                GatewayInfo gatewayInfo,
506                int videoState,
507                StatusHints statusHints,
508                Bundle extras,
509                int callSubstate) {
510            mHandle = handle;
511            mHandlePresentation = handlePresentation;
512            mCallerDisplayName = callerDisplayName;
513            mCallerDisplayNamePresentation = callerDisplayNamePresentation;
514            mAccountHandle = accountHandle;
515            mCallCapabilities = capabilities;
516            mCallProperties = properties;
517            mDisconnectCause = disconnectCause;
518            mConnectTimeMillis = connectTimeMillis;
519            mGatewayInfo = gatewayInfo;
520            mVideoState = videoState;
521            mStatusHints = statusHints;
522            mExtras = extras;
523            mCallSubstate = callSubstate;
524        }
525    }
526
527    public static abstract class Listener {
528        /**
529         * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
530         *
531         * @param call The {@code Call} invoking this method.
532         * @param state The new state of the {@code Call}.
533         */
534        public void onStateChanged(Call call, int state) {}
535
536        /**
537         * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
538         *
539         * @param call The {@code Call} invoking this method.
540         * @param parent The new parent of the {@code Call}.
541         */
542        public void onParentChanged(Call call, Call parent) {}
543
544        /**
545         * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
546         *
547         * @param call The {@code Call} invoking this method.
548         * @param children The new children of the {@code Call}.
549         */
550        public void onChildrenChanged(Call call, List<Call> children) {}
551
552        /**
553         * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
554         *
555         * @param call The {@code Call} invoking this method.
556         * @param details A {@code Details} object describing the {@code Call}.
557         */
558        public void onDetailsChanged(Call call, Details details) {}
559
560        /**
561         * Invoked when the text messages that can be used as responses to the incoming
562         * {@code Call} are loaded from the relevant database.
563         * See {@link #getCannedTextResponses()}.
564         *
565         * @param call The {@code Call} invoking this method.
566         * @param cannedTextResponses The text messages useable as responses.
567         */
568        public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
569
570        /**
571         * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
572         * character. This causes the post-dial signals to stop pending user confirmation. An
573         * implementation should present this choice to the user and invoke
574         * {@link #postDialContinue(boolean)} when the user makes the choice.
575         *
576         * @param call The {@code Call} invoking this method.
577         * @param remainingPostDialSequence The post-dial characters that remain to be sent.
578         */
579        public void onPostDialWait(Call call, String remainingPostDialSequence) {}
580
581        /**
582         * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
583         *
584         * @param call The {@code Call} invoking this method.
585         * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
586         * @hide
587         */
588        public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
589
590        /**
591         * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
592         * up their UI for the {@code Call} in response to state transitions. Specifically,
593         * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
594         * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
595         * clients should wait for this method to be invoked.
596         *
597         * @param call The {@code Call} being destroyed.
598         */
599        public void onCallDestroyed(Call call) {}
600
601        /**
602         * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
603         * conferenced.
604         *
605         * @param call The {@code Call} being updated.
606         * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
607         *          conferenced.
608         */
609        public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
610    }
611
612    private final Phone mPhone;
613    private final String mTelecomCallId;
614    private final InCallAdapter mInCallAdapter;
615    private final List<String> mChildrenIds = new ArrayList<>();
616    private final List<Call> mChildren = new ArrayList<>();
617    private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
618    private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
619    private final List<Call> mConferenceableCalls = new ArrayList<>();
620    private final List<Call> mUnmodifiableConferenceableCalls =
621            Collections.unmodifiableList(mConferenceableCalls);
622
623    private boolean mChildrenCached;
624    private String mParentId = null;
625    private int mState;
626    private List<String> mCannedTextResponses = null;
627    private String mRemainingPostDialSequence;
628    private InCallService.VideoCall mVideoCall;
629    private Details mDetails;
630
631    /**
632     * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
633     *
634     * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
635     * remaining or this {@code Call} is not in a post-dial state.
636     */
637    public String getRemainingPostDialSequence() {
638        return mRemainingPostDialSequence;
639    }
640
641    /**
642     * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
643     * @param videoState The video state in which to answer the call.
644     */
645    public void answer(int videoState) {
646        mInCallAdapter.answerCall(mTelecomCallId, videoState);
647    }
648
649    /**
650     * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
651     *
652     * @param rejectWithMessage Whether to reject with a text message.
653     * @param textMessage An optional text message with which to respond.
654     */
655    public void reject(boolean rejectWithMessage, String textMessage) {
656        mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
657    }
658
659    /**
660     * Instructs this {@code Call} to disconnect.
661     */
662    public void disconnect() {
663        mInCallAdapter.disconnectCall(mTelecomCallId);
664    }
665
666    /**
667     * Instructs this {@code Call} to go on hold.
668     */
669    public void hold() {
670        mInCallAdapter.holdCall(mTelecomCallId);
671    }
672
673    /**
674     * Instructs this {@link #STATE_HOLDING} call to release from hold.
675     */
676    public void unhold() {
677        mInCallAdapter.unholdCall(mTelecomCallId);
678    }
679
680    /**
681     * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
682     *
683     * Any other currently playing DTMF tone in the specified call is immediately stopped.
684     *
685     * @param digit A character representing the DTMF digit for which to play the tone. This
686     *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
687     */
688    public void playDtmfTone(char digit) {
689        mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
690    }
691
692    /**
693     * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
694     * currently playing.
695     *
696     * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
697     * currently playing, this method will do nothing.
698     */
699    public void stopDtmfTone() {
700        mInCallAdapter.stopDtmfTone(mTelecomCallId);
701    }
702
703    /**
704     * Instructs this {@code Call} to continue playing a post-dial DTMF string.
705     *
706     * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
707     * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
708     *
709     * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
710     * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
711     *
712     * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
713     * {@code Call} will pause playing the tones and notify listeners via
714     * {@link Listener#onPostDialWait(Call, String)}. At this point, the in-call app
715     * should display to the user an indication of this state and an affordance to continue
716     * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
717     * app should invoke the {@link #postDialContinue(boolean)} method.
718     *
719     * @param proceed Whether or not to continue with the post-dial sequence.
720     */
721    public void postDialContinue(boolean proceed) {
722        mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
723    }
724
725    /**
726     * Notifies this {@code Call} that an account has been selected and to proceed with placing
727     * an outgoing call. Optionally sets this account as the default account.
728     */
729    public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
730        mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
731
732    }
733
734    /**
735     * Instructs this {@code Call} to enter a conference.
736     *
737     * @param callToConferenceWith The other call with which to conference.
738     */
739    public void conference(Call callToConferenceWith) {
740        if (callToConferenceWith != null) {
741            mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
742        }
743    }
744
745    /**
746     * Instructs this {@code Call} to split from any conference call with which it may be
747     * connected.
748     */
749    public void splitFromConference() {
750        mInCallAdapter.splitFromConference(mTelecomCallId);
751    }
752
753    /**
754     * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}.
755     */
756    public void mergeConference() {
757        mInCallAdapter.mergeConference(mTelecomCallId);
758    }
759
760    /**
761     * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
762     */
763    public void swapConference() {
764        mInCallAdapter.swapConference(mTelecomCallId);
765    }
766
767    /**
768     * Obtains the parent of this {@code Call} in a conference, if any.
769     *
770     * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
771     * child of any conference {@code Call}s.
772     */
773    public Call getParent() {
774        if (mParentId != null) {
775            return mPhone.internalGetCallByTelecomId(mParentId);
776        }
777        return null;
778    }
779
780    /**
781     * Obtains the children of this conference {@code Call}, if any.
782     *
783     * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
784     * {@code List} otherwise.
785     */
786    public List<Call> getChildren() {
787        if (!mChildrenCached) {
788            mChildrenCached = true;
789            mChildren.clear();
790
791            for(String id : mChildrenIds) {
792                Call call = mPhone.internalGetCallByTelecomId(id);
793                if (call == null) {
794                    // At least one child was still not found, so do not save true for "cached"
795                    mChildrenCached = false;
796                } else {
797                    mChildren.add(call);
798                }
799            }
800        }
801
802        return mUnmodifiableChildren;
803    }
804
805    /**
806     * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
807     *
808     * @return The list of conferenceable {@code Call}s.
809     */
810    public List<Call> getConferenceableCalls() {
811        return mUnmodifiableConferenceableCalls;
812    }
813
814    /**
815     * Obtains the state of this {@code Call}.
816     *
817     * @return A state value, chosen from the {@code STATE_*} constants.
818     */
819    public int getState() {
820        return mState;
821    }
822
823    /**
824     * Obtains a list of canned, pre-configured message responses to present to the user as
825     * ways of rejecting this {@code Call} using via a text message.
826     *
827     * @see #reject(boolean, String)
828     *
829     * @return A list of canned text message responses.
830     */
831    public List<String> getCannedTextResponses() {
832        return mCannedTextResponses;
833    }
834
835    /**
836     * Obtains an object that can be used to display video from this {@code Call}.
837     *
838     * @return An {@code Call.VideoCall}.
839     * @hide
840     */
841    public InCallService.VideoCall getVideoCall() {
842        return mVideoCall;
843    }
844
845    /**
846     * Obtains an object containing call details.
847     *
848     * @return A {@link Details} object. Depending on the state of the {@code Call}, the
849     * result may be {@code null}.
850     */
851    public Details getDetails() {
852        return mDetails;
853    }
854
855    /**
856     * Adds a listener to this {@code Call}.
857     *
858     * @param listener A {@code Listener}.
859     */
860    public void addListener(Listener listener) {
861        mListeners.add(listener);
862    }
863
864    /**
865     * Removes a listener from this {@code Call}.
866     *
867     * @param listener A {@code Listener}.
868     */
869    public void removeListener(Listener listener) {
870        if (listener != null) {
871            mListeners.remove(listener);
872        }
873    }
874
875    /** {@hide} */
876    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
877        mPhone = phone;
878        mTelecomCallId = telecomCallId;
879        mInCallAdapter = inCallAdapter;
880        mState = STATE_NEW;
881    }
882
883    /** {@hide} */
884    final String internalGetCallId() {
885        return mTelecomCallId;
886    }
887
888    /** {@hide} */
889    final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
890        // First, we update the internal state as far as possible before firing any updates.
891        Details details = new Details(
892                parcelableCall.getHandle(),
893                parcelableCall.getHandlePresentation(),
894                parcelableCall.getCallerDisplayName(),
895                parcelableCall.getCallerDisplayNamePresentation(),
896                parcelableCall.getAccountHandle(),
897                parcelableCall.getCapabilities(),
898                parcelableCall.getProperties(),
899                parcelableCall.getDisconnectCause(),
900                parcelableCall.getConnectTimeMillis(),
901                parcelableCall.getGatewayInfo(),
902                parcelableCall.getVideoState(),
903                parcelableCall.getStatusHints(),
904                parcelableCall.getExtras(),
905                parcelableCall.getCallSubstate());
906        boolean detailsChanged = !Objects.equals(mDetails, details);
907        if (detailsChanged) {
908            mDetails = details;
909        }
910
911        boolean cannedTextResponsesChanged = false;
912        if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
913                && !parcelableCall.getCannedSmsResponses().isEmpty()) {
914            mCannedTextResponses =
915                    Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
916        }
917
918        boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall());
919        if (videoCallChanged) {
920            mVideoCall = parcelableCall.getVideoCall();
921        }
922
923        int state = stateFromParcelableCallState(parcelableCall.getState());
924        boolean stateChanged = mState != state;
925        if (stateChanged) {
926            mState = state;
927        }
928
929        String parentId = parcelableCall.getParentCallId();
930        boolean parentChanged = !Objects.equals(mParentId, parentId);
931        if (parentChanged) {
932            mParentId = parentId;
933        }
934
935        List<String> childCallIds = parcelableCall.getChildCallIds();
936        boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
937        if (childrenChanged) {
938            mChildrenIds.clear();
939            mChildrenIds.addAll(parcelableCall.getChildCallIds());
940            mChildrenCached = false;
941        }
942
943        List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
944        List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
945        for (String otherId : conferenceableCallIds) {
946            if (callIdMap.containsKey(otherId)) {
947                conferenceableCalls.add(callIdMap.get(otherId));
948            }
949        }
950
951        if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
952            mConferenceableCalls.clear();
953            mConferenceableCalls.addAll(conferenceableCalls);
954            fireConferenceableCallsChanged();
955        }
956
957        // Now we fire updates, ensuring that any client who listens to any of these notifications
958        // gets the most up-to-date state.
959
960        if (stateChanged) {
961            fireStateChanged(mState);
962        }
963        if (detailsChanged) {
964            fireDetailsChanged(mDetails);
965        }
966        if (cannedTextResponsesChanged) {
967            fireCannedTextResponsesLoaded(mCannedTextResponses);
968        }
969        if (videoCallChanged) {
970            fireVideoCallChanged(mVideoCall);
971        }
972        if (parentChanged) {
973            fireParentChanged(getParent());
974        }
975        if (childrenChanged) {
976            fireChildrenChanged(getChildren());
977        }
978
979        // If we have transitioned to DISCONNECTED, that means we need to notify clients and
980        // remove ourselves from the Phone. Note that we do this after completing all state updates
981        // so a client can cleanly transition all their UI to the state appropriate for a
982        // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
983        if (mState == STATE_DISCONNECTED) {
984            fireCallDestroyed();
985            mPhone.internalRemoveCall(this);
986        }
987    }
988
989    /** {@hide} */
990    final void internalSetPostDialWait(String remaining) {
991        mRemainingPostDialSequence = remaining;
992        firePostDialWait(mRemainingPostDialSequence);
993    }
994
995    /** {@hide} */
996    final void internalSetDisconnected() {
997        if (mState != Call.STATE_DISCONNECTED) {
998            mState = Call.STATE_DISCONNECTED;
999            fireStateChanged(mState);
1000            fireCallDestroyed();
1001            mPhone.internalRemoveCall(this);
1002        }
1003    }
1004
1005    private void fireStateChanged(int newState) {
1006        for (Listener listener : mListeners) {
1007            listener.onStateChanged(this, newState);
1008        }
1009    }
1010
1011    private void fireParentChanged(Call newParent) {
1012        for (Listener listener : mListeners) {
1013            listener.onParentChanged(this, newParent);
1014        }
1015    }
1016
1017    private void fireChildrenChanged(List<Call> children) {
1018        for (Listener listener : mListeners) {
1019            listener.onChildrenChanged(this, children);
1020        }
1021    }
1022
1023    private void fireDetailsChanged(Details details) {
1024        for (Listener listener : mListeners) {
1025            listener.onDetailsChanged(this, details);
1026        }
1027    }
1028
1029    private void fireCannedTextResponsesLoaded(List<String> cannedTextResponses) {
1030        for (Listener listener : mListeners) {
1031            listener.onCannedTextResponsesLoaded(this, cannedTextResponses);
1032        }
1033    }
1034
1035    private void fireVideoCallChanged(InCallService.VideoCall videoCall) {
1036        for (Listener listener : mListeners) {
1037            listener.onVideoCallChanged(this, videoCall);
1038        }
1039    }
1040
1041    private void firePostDialWait(String remainingPostDialSequence) {
1042        for (Listener listener : mListeners) {
1043            listener.onPostDialWait(this, remainingPostDialSequence);
1044        }
1045    }
1046
1047    private void fireCallDestroyed() {
1048        for (Listener listener : mListeners) {
1049            listener.onCallDestroyed(this);
1050        }
1051    }
1052
1053    private void fireConferenceableCallsChanged() {
1054        for (Listener listener : mListeners) {
1055            listener.onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls);
1056        }
1057    }
1058
1059    private int stateFromParcelableCallState(int parcelableCallState) {
1060        switch (parcelableCallState) {
1061            case CallState.NEW:
1062                return STATE_NEW;
1063            case CallState.CONNECTING:
1064                return STATE_CONNECTING;
1065            case CallState.PRE_DIAL_WAIT:
1066                return STATE_PRE_DIAL_WAIT;
1067            case CallState.DIALING:
1068                return STATE_DIALING;
1069            case CallState.RINGING:
1070                return STATE_RINGING;
1071            case CallState.ACTIVE:
1072                return STATE_ACTIVE;
1073            case CallState.ON_HOLD:
1074                return STATE_HOLDING;
1075            case CallState.DISCONNECTED:
1076                return STATE_DISCONNECTED;
1077            case CallState.ABORTED:
1078                return STATE_DISCONNECTED;
1079            case CallState.DISCONNECTING:
1080                return STATE_DISCONNECTING;
1081            default:
1082                Log.wtf(this, "Unrecognized CallState %s", parcelableCallState);
1083                return STATE_NEW;
1084        }
1085    }
1086}
1087