OSDN Git Service

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