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