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 import android.os.Handler;
     23 
     24 import java.lang.String;
     25 import java.util.ArrayList;
     26 import java.util.Arrays;
     27 import java.util.Collections;
     28 import java.util.List;
     29 import java.util.Map;
     30 import java.util.Objects;
     31 import java.util.concurrent.CopyOnWriteArrayList;
     32 
     33 /**
     34  * Represents an ongoing phone call that the in-call app should present to the user.
     35  */
     36 public final class Call {
     37     /**
     38      * The state of a {@code Call} when newly created.
     39      */
     40     public static final int STATE_NEW = 0;
     41 
     42     /**
     43      * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
     44      */
     45     public static final int STATE_DIALING = 1;
     46 
     47     /**
     48      * The state of an incoming {@code Call} when ringing locally, but not yet connected.
     49      */
     50     public static final int STATE_RINGING = 2;
     51 
     52     /**
     53      * The state of a {@code Call} when in a holding state.
     54      */
     55     public static final int STATE_HOLDING = 3;
     56 
     57     /**
     58      * The state of a {@code Call} when actively supporting conversation.
     59      */
     60     public static final int STATE_ACTIVE = 4;
     61 
     62     /**
     63      * The state of a {@code Call} when no further voice or other communication is being
     64      * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
     65      * is no longer active, and the local data transport has or inevitably will release resources
     66      * associated with this {@code Call}.
     67      */
     68     public static final int STATE_DISCONNECTED = 7;
     69 
     70     /**
     71      * The state of an outgoing {@code Call} when waiting on user to select a
     72      * {@link PhoneAccount} through which to place the call.
     73      */
     74     public static final int STATE_SELECT_PHONE_ACCOUNT = 8;
     75 
     76     /**
     77      * @hide
     78      * @deprecated use STATE_SELECT_PHONE_ACCOUNT.
     79      */
     80     @Deprecated
     81     @SystemApi
     82     public static final int STATE_PRE_DIAL_WAIT = STATE_SELECT_PHONE_ACCOUNT;
     83 
     84     /**
     85      * The initial state of an outgoing {@code Call}.
     86      * Common transitions are to {@link #STATE_DIALING} state for a successful call or
     87      * {@link #STATE_DISCONNECTED} if it failed.
     88      */
     89     public static final int STATE_CONNECTING = 9;
     90 
     91     /**
     92      * The state of a {@code Call} when the user has initiated a disconnection of the call, but the
     93      * call has not yet been disconnected by the underlying {@code ConnectionService}.  The next
     94      * state of the call is (potentially) {@link #STATE_DISCONNECTED}.
     95      */
     96     public static final int STATE_DISCONNECTING = 10;
     97 
     98     /**
     99      * The state of an external call which is in the process of being pulled from a remote device to
    100      * the local device.
    101      * <p>
    102      * A call can only be in this state if the {@link Details#PROPERTY_IS_EXTERNAL_CALL} property
    103      * and {@link Details#CAPABILITY_CAN_PULL_CALL} capability are set on the call.
    104      * <p>
    105      * An {@link InCallService} will only see this state if it has the
    106      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
    107      * manifest.
    108      */
    109     public static final int STATE_PULLING_CALL = 11;
    110 
    111     /**
    112      * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
    113      * extras. Used to pass the phone accounts to display on the front end to the user in order to
    114      * select phone accounts to (for example) place a call.
    115      */
    116     public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
    117 
    118     public static class Details {
    119 
    120         /** Call can currently be put on hold or unheld. */
    121         public static final int CAPABILITY_HOLD = 0x00000001;
    122 
    123         /** Call supports the hold feature. */
    124         public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
    125 
    126         /**
    127          * Calls within a conference can be merged. A {@link ConnectionService} has the option to
    128          * add a {@link Conference} call before the child {@link Connection}s are merged. This is how
    129          * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
    130          * capability allows a merge button to be shown while the conference call is in the foreground
    131          * of the in-call UI.
    132          * <p>
    133          * This is only intended for use by a {@link Conference}.
    134          */
    135         public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
    136 
    137         /**
    138          * Calls within a conference can be swapped between foreground and background.
    139          * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
    140          * <p>
    141          * This is only intended for use by a {@link Conference}.
    142          */
    143         public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
    144 
    145         /**
    146          * @hide
    147          */
    148         public static final int CAPABILITY_UNUSED_1 = 0x00000010;
    149 
    150         /** Call supports responding via text option. */
    151         public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
    152 
    153         /** Call can be muted. */
    154         public static final int CAPABILITY_MUTE = 0x00000040;
    155 
    156         /**
    157          * Call supports conference call management. This capability only applies to {@link Conference}
    158          * calls which can have {@link Connection}s as children.
    159          */
    160         public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
    161 
    162         /**
    163          * Local device supports receiving video.
    164          */
    165         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
    166 
    167         /**
    168          * Local device supports transmitting video.
    169          */
    170         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
    171 
    172         /**
    173          * Local device supports bidirectional video calling.
    174          */
    175         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
    176                 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
    177 
    178         /**
    179          * Remote device supports receiving video.
    180          */
    181         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
    182 
    183         /**
    184          * Remote device supports transmitting video.
    185          */
    186         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
    187 
    188         /**
    189          * Remote device supports bidirectional video calling.
    190          */
    191         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
    192                 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
    193 
    194         /**
    195          * Call is able to be separated from its parent {@code Conference}, if any.
    196          */
    197         public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
    198 
    199         /**
    200          * Call is able to be individually disconnected when in a {@code Conference}.
    201          */
    202         public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
    203 
    204         /**
    205          * Speed up audio setup for MT call.
    206          * @hide
    207          */
    208         public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
    209 
    210         /**
    211          * Call can be upgraded to a video call.
    212          * @hide
    213          */
    214         public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
    215 
    216         /**
    217          * For video calls, indicates whether the outgoing video for the call can be paused using
    218          * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
    219          */
    220         public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
    221 
    222         /**
    223          * Call sends responses through connection.
    224          * @hide
    225          */
    226         public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000;
    227 
    228         /**
    229          * When set, prevents a video {@code Call} from being downgraded to an audio-only call.
    230          * <p>
    231          * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
    232          * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
    233          * downgraded from a video call back to a VideoState of
    234          * {@link VideoProfile#STATE_AUDIO_ONLY}.
    235          * <p>
    236          * Intuitively, a call which can be downgraded to audio should also have local and remote
    237          * video
    238          * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
    239          * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
    240          */
    241         public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000;
    242 
    243         /**
    244          * When set for an external call, indicates that this {@code Call} can be pulled from a
    245          * remote device to the current device.
    246          * <p>
    247          * Should only be set on a {@code Call} where {@link #PROPERTY_IS_EXTERNAL_CALL} is set.
    248          * <p>
    249          * An {@link InCallService} will only see calls with this capability if it has the
    250          * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
    251          * in its manifest.
    252          * <p>
    253          * See {@link Connection#CAPABILITY_CAN_PULL_CALL} and
    254          * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
    255          */
    256         public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
    257 
    258         //******************************************************************************************
    259         // Next CAPABILITY value: 0x01000000
    260         //******************************************************************************************
    261 
    262         /**
    263          * Whether the call is currently a conference.
    264          */
    265         public static final int PROPERTY_CONFERENCE = 0x00000001;
    266 
    267         /**
    268          * Whether the call is a generic conference, where we do not know the precise state of
    269          * participants in the conference (eg. on CDMA).
    270          */
    271         public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002;
    272 
    273         /**
    274          * Whether the call is made while the device is in emergency callback mode.
    275          */
    276         public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004;
    277 
    278         /**
    279          * Connection is using WIFI.
    280          */
    281         public static final int PROPERTY_WIFI = 0x00000008;
    282 
    283         /**
    284          * Call is using high definition audio.
    285          */
    286         public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
    287 
    288         /**
    289          * Whether the call is associated with the work profile.
    290          */
    291         public static final int PROPERTY_ENTERPRISE_CALL = 0x00000020;
    292 
    293         /**
    294          * When set, indicates that this {@code Call} does not actually exist locally for the
    295          * {@link ConnectionService}.
    296          * <p>
    297          * Consider, for example, a scenario where a user has two phones with the same phone number.
    298          * When a user places a call on one device, the telephony stack can represent that call on
    299          * the other device by adding it to the {@link ConnectionService} with the
    300          * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property set.
    301          * <p>
    302          * An {@link InCallService} will only see calls with this property if it has the
    303          * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
    304          * in its manifest.
    305          * <p>
    306          * See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
    307          */
    308         public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040;
    309 
    310         /**
    311          * Indicates that the call has CDMA Enhanced Voice Privacy enabled.
    312          */
    313         public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 0x00000080;
    314 
    315         //******************************************************************************************
    316         // Next PROPERTY value: 0x00000100
    317         //******************************************************************************************
    318 
    319         private final String mTelecomCallId;
    320         private final Uri mHandle;
    321         private final int mHandlePresentation;
    322         private final String mCallerDisplayName;
    323         private final int mCallerDisplayNamePresentation;
    324         private final PhoneAccountHandle mAccountHandle;
    325         private final int mCallCapabilities;
    326         private final int mCallProperties;
    327         private final DisconnectCause mDisconnectCause;
    328         private final long mConnectTimeMillis;
    329         private final GatewayInfo mGatewayInfo;
    330         private final int mVideoState;
    331         private final StatusHints mStatusHints;
    332         private final Bundle mExtras;
    333         private final Bundle mIntentExtras;
    334 
    335         /**
    336          * Whether the supplied capabilities  supports the specified capability.
    337          *
    338          * @param capabilities A bit field of capabilities.
    339          * @param capability The capability to check capabilities for.
    340          * @return Whether the specified capability is supported.
    341          */
    342         public static boolean can(int capabilities, int capability) {
    343             return (capabilities & capability) == capability;
    344         }
    345 
    346         /**
    347          * Whether the capabilities of this {@code Details} supports the specified capability.
    348          *
    349          * @param capability The capability to check capabilities for.
    350          * @return Whether the specified capability is supported.
    351          */
    352         public boolean can(int capability) {
    353             return can(mCallCapabilities, capability);
    354         }
    355 
    356         /**
    357          * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
    358          *
    359          * @param capabilities A capability bit field.
    360          * @return A human readable string representation.
    361          */
    362         public static String capabilitiesToString(int capabilities) {
    363             StringBuilder builder = new StringBuilder();
    364             builder.append("[Capabilities:");
    365             if (can(capabilities, CAPABILITY_HOLD)) {
    366                 builder.append(" CAPABILITY_HOLD");
    367             }
    368             if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
    369                 builder.append(" CAPABILITY_SUPPORT_HOLD");
    370             }
    371             if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
    372                 builder.append(" CAPABILITY_MERGE_CONFERENCE");
    373             }
    374             if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
    375                 builder.append(" CAPABILITY_SWAP_CONFERENCE");
    376             }
    377             if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
    378                 builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
    379             }
    380             if (can(capabilities, CAPABILITY_MUTE)) {
    381                 builder.append(" CAPABILITY_MUTE");
    382             }
    383             if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
    384                 builder.append(" CAPABILITY_MANAGE_CONFERENCE");
    385             }
    386             if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
    387                 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
    388             }
    389             if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
    390                 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
    391             }
    392             if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
    393                 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
    394             }
    395             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
    396                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
    397             }
    398             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
    399                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
    400             }
    401             if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
    402                 builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
    403             }
    404             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
    405                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
    406             }
    407             if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
    408                 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
    409             }
    410             if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
    411                 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
    412             }
    413             if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
    414                 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
    415             }
    416             if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
    417                 builder.append(" CAPABILITY_CAN_PULL_CALL");
    418             }
    419             builder.append("]");
    420             return builder.toString();
    421         }
    422 
    423         /**
    424          * Whether the supplied properties includes the specified property.
    425          *
    426          * @param properties A bit field of properties.
    427          * @param property The property to check properties for.
    428          * @return Whether the specified property is supported.
    429          */
    430         public static boolean hasProperty(int properties, int property) {
    431             return (properties & property) == property;
    432         }
    433 
    434         /**
    435          * Whether the properties of this {@code Details} includes the specified property.
    436          *
    437          * @param property The property to check properties for.
    438          * @return Whether the specified property is supported.
    439          */
    440         public boolean hasProperty(int property) {
    441             return hasProperty(mCallProperties, property);
    442         }
    443 
    444         /**
    445          * Render a set of property bits ({@code PROPERTY_*}) as a human readable string.
    446          *
    447          * @param properties A property bit field.
    448          * @return A human readable string representation.
    449          */
    450         public static String propertiesToString(int properties) {
    451             StringBuilder builder = new StringBuilder();
    452             builder.append("[Properties:");
    453             if (hasProperty(properties, PROPERTY_CONFERENCE)) {
    454                 builder.append(" PROPERTY_CONFERENCE");
    455             }
    456             if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) {
    457                 builder.append(" PROPERTY_GENERIC_CONFERENCE");
    458             }
    459             if (hasProperty(properties, PROPERTY_WIFI)) {
    460                 builder.append(" PROPERTY_WIFI");
    461             }
    462             if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) {
    463                 builder.append(" PROPERTY_HIGH_DEF_AUDIO");
    464             }
    465             if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
    466                 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
    467             }
    468             if (hasProperty(properties, PROPERTY_IS_EXTERNAL_CALL)) {
    469                 builder.append(" PROPERTY_IS_EXTERNAL_CALL");
    470             }
    471             if(hasProperty(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
    472                 builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY");
    473             }
    474             builder.append("]");
    475             return builder.toString();
    476         }
    477 
    478         /** {@hide} */
    479         public String getTelecomCallId() {
    480             return mTelecomCallId;
    481         }
    482 
    483         /**
    484          * @return The handle (e.g., phone number) to which the {@code Call} is currently
    485          * connected.
    486          */
    487         public Uri getHandle() {
    488             return mHandle;
    489         }
    490 
    491         /**
    492          * @return The presentation requirements for the handle. See
    493          * {@link TelecomManager} for valid values.
    494          */
    495         public int getHandlePresentation() {
    496             return mHandlePresentation;
    497         }
    498 
    499         /**
    500          * @return The display name for the caller.
    501          */
    502         public String getCallerDisplayName() {
    503             return mCallerDisplayName;
    504         }
    505 
    506         /**
    507          * @return The presentation requirements for the caller display name. See
    508          * {@link TelecomManager} for valid values.
    509          */
    510         public int getCallerDisplayNamePresentation() {
    511             return mCallerDisplayNamePresentation;
    512         }
    513 
    514         /**
    515          * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
    516          * routed.
    517          */
    518         public PhoneAccountHandle getAccountHandle() {
    519             return mAccountHandle;
    520         }
    521 
    522         /**
    523          * @return A bitmask of the capabilities of the {@code Call}, as defined by the various
    524          *         {@code CAPABILITY_*} constants in this class.
    525          */
    526         public int getCallCapabilities() {
    527             return mCallCapabilities;
    528         }
    529 
    530         /**
    531          * @return A bitmask of the properties of the {@code Call}, as defined by the various
    532          *         {@code PROPERTY_*} constants in this class.
    533          */
    534         public int getCallProperties() {
    535             return mCallProperties;
    536         }
    537 
    538         /**
    539          * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
    540          * by {@link android.telecom.DisconnectCause}.
    541          */
    542         public DisconnectCause getDisconnectCause() {
    543             return mDisconnectCause;
    544         }
    545 
    546         /**
    547          * @return The time the {@code Call} has been connected. This information is updated
    548          * periodically, but user interfaces should not rely on this to display any "call time
    549          * clock".
    550          */
    551         public final long getConnectTimeMillis() {
    552             return mConnectTimeMillis;
    553         }
    554 
    555         /**
    556          * @return Information about any calling gateway the {@code Call} may be using.
    557          */
    558         public GatewayInfo getGatewayInfo() {
    559             return mGatewayInfo;
    560         }
    561 
    562         /**
    563          * @return The video state of the {@code Call}.
    564          */
    565         public int getVideoState() {
    566             return mVideoState;
    567         }
    568 
    569         /**
    570          * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
    571          * have been set.
    572          */
    573         public StatusHints getStatusHints() {
    574             return mStatusHints;
    575         }
    576 
    577         /**
    578          * @return The extras associated with this call.
    579          */
    580         public Bundle getExtras() {
    581             return mExtras;
    582         }
    583 
    584         /**
    585          * @return The extras used with the original intent to place this call.
    586          */
    587         public Bundle getIntentExtras() {
    588             return mIntentExtras;
    589         }
    590 
    591         @Override
    592         public boolean equals(Object o) {
    593             if (o instanceof Details) {
    594                 Details d = (Details) o;
    595                 return
    596                         Objects.equals(mHandle, d.mHandle) &&
    597                         Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
    598                         Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
    599                         Objects.equals(mCallerDisplayNamePresentation,
    600                                 d.mCallerDisplayNamePresentation) &&
    601                         Objects.equals(mAccountHandle, d.mAccountHandle) &&
    602                         Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
    603                         Objects.equals(mCallProperties, d.mCallProperties) &&
    604                         Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
    605                         Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
    606                         Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
    607                         Objects.equals(mVideoState, d.mVideoState) &&
    608                         Objects.equals(mStatusHints, d.mStatusHints) &&
    609                         areBundlesEqual(mExtras, d.mExtras) &&
    610                         areBundlesEqual(mIntentExtras, d.mIntentExtras);
    611             }
    612             return false;
    613         }
    614 
    615         @Override
    616         public int hashCode() {
    617             return
    618                     Objects.hashCode(mHandle) +
    619                     Objects.hashCode(mHandlePresentation) +
    620                     Objects.hashCode(mCallerDisplayName) +
    621                     Objects.hashCode(mCallerDisplayNamePresentation) +
    622                     Objects.hashCode(mAccountHandle) +
    623                     Objects.hashCode(mCallCapabilities) +
    624                     Objects.hashCode(mCallProperties) +
    625                     Objects.hashCode(mDisconnectCause) +
    626                     Objects.hashCode(mConnectTimeMillis) +
    627                     Objects.hashCode(mGatewayInfo) +
    628                     Objects.hashCode(mVideoState) +
    629                     Objects.hashCode(mStatusHints) +
    630                     Objects.hashCode(mExtras) +
    631                     Objects.hashCode(mIntentExtras);
    632         }
    633 
    634         /** {@hide} */
    635         public Details(
    636                 String telecomCallId,
    637                 Uri handle,
    638                 int handlePresentation,
    639                 String callerDisplayName,
    640                 int callerDisplayNamePresentation,
    641                 PhoneAccountHandle accountHandle,
    642                 int capabilities,
    643                 int properties,
    644                 DisconnectCause disconnectCause,
    645                 long connectTimeMillis,
    646                 GatewayInfo gatewayInfo,
    647                 int videoState,
    648                 StatusHints statusHints,
    649                 Bundle extras,
    650                 Bundle intentExtras) {
    651             mTelecomCallId = telecomCallId;
    652             mHandle = handle;
    653             mHandlePresentation = handlePresentation;
    654             mCallerDisplayName = callerDisplayName;
    655             mCallerDisplayNamePresentation = callerDisplayNamePresentation;
    656             mAccountHandle = accountHandle;
    657             mCallCapabilities = capabilities;
    658             mCallProperties = properties;
    659             mDisconnectCause = disconnectCause;
    660             mConnectTimeMillis = connectTimeMillis;
    661             mGatewayInfo = gatewayInfo;
    662             mVideoState = videoState;
    663             mStatusHints = statusHints;
    664             mExtras = extras;
    665             mIntentExtras = intentExtras;
    666         }
    667 
    668         /** {@hide} */
    669         public static Details createFromParcelableCall(ParcelableCall parcelableCall) {
    670             return new Details(
    671                     parcelableCall.getId(),
    672                     parcelableCall.getHandle(),
    673                     parcelableCall.getHandlePresentation(),
    674                     parcelableCall.getCallerDisplayName(),
    675                     parcelableCall.getCallerDisplayNamePresentation(),
    676                     parcelableCall.getAccountHandle(),
    677                     parcelableCall.getCapabilities(),
    678                     parcelableCall.getProperties(),
    679                     parcelableCall.getDisconnectCause(),
    680                     parcelableCall.getConnectTimeMillis(),
    681                     parcelableCall.getGatewayInfo(),
    682                     parcelableCall.getVideoState(),
    683                     parcelableCall.getStatusHints(),
    684                     parcelableCall.getExtras(),
    685                     parcelableCall.getIntentExtras());
    686         }
    687 
    688         @Override
    689         public String toString() {
    690             StringBuilder sb = new StringBuilder();
    691             sb.append("[pa: ");
    692             sb.append(mAccountHandle);
    693             sb.append(", hdl: ");
    694             sb.append(Log.pii(mHandle));
    695             sb.append(", caps: ");
    696             sb.append(capabilitiesToString(mCallCapabilities));
    697             sb.append(", props: ");
    698             sb.append(propertiesToString(mCallProperties));
    699             sb.append("]");
    700             return sb.toString();
    701         }
    702     }
    703 
    704     /**
    705      * Defines callbacks which inform the {@link InCallService} of changes to a {@link Call}.
    706      * These callbacks can originate from the Telecom framework, or a {@link ConnectionService}
    707      * implementation.
    708      * <p>
    709      * You can handle these callbacks by extending the {@link Callback} class and overriding the
    710      * callbacks that your {@link InCallService} is interested in.  The callback methods include the
    711      * {@link Call} for which the callback applies, allowing reuse of a single instance of your
    712      * {@link Callback} implementation, if desired.
    713      * <p>
    714      * Use {@link Call#registerCallback(Callback)} to register your callback(s).  Ensure
    715      * {@link Call#unregisterCallback(Callback)} is called when you no longer require callbacks
    716      * (typically in {@link InCallService#onCallRemoved(Call)}).
    717      * Note: Callbacks which occur before you call {@link Call#registerCallback(Callback)} will not
    718      * reach your implementation of {@link Callback}, so it is important to register your callback
    719      * as soon as your {@link InCallService} is notified of a new call via
    720      * {@link InCallService#onCallAdded(Call)}.
    721      */
    722     public static abstract class Callback {
    723         /**
    724          * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
    725          *
    726          * @param call The {@code Call} invoking this method.
    727          * @param state The new state of the {@code Call}.
    728          */
    729         public void onStateChanged(Call call, int state) {}
    730 
    731         /**
    732          * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
    733          *
    734          * @param call The {@code Call} invoking this method.
    735          * @param parent The new parent of the {@code Call}.
    736          */
    737         public void onParentChanged(Call call, Call parent) {}
    738 
    739         /**
    740          * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
    741          *
    742          * @param call The {@code Call} invoking this method.
    743          * @param children The new children of the {@code Call}.
    744          */
    745         public void onChildrenChanged(Call call, List<Call> children) {}
    746 
    747         /**
    748          * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
    749          *
    750          * @param call The {@code Call} invoking this method.
    751          * @param details A {@code Details} object describing the {@code Call}.
    752          */
    753         public void onDetailsChanged(Call call, Details details) {}
    754 
    755         /**
    756          * Invoked when the text messages that can be used as responses to the incoming
    757          * {@code Call} are loaded from the relevant database.
    758          * See {@link #getCannedTextResponses()}.
    759          *
    760          * @param call The {@code Call} invoking this method.
    761          * @param cannedTextResponses The text messages useable as responses.
    762          */
    763         public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
    764 
    765         /**
    766          * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
    767          * character. This causes the post-dial signals to stop pending user confirmation. An
    768          * implementation should present this choice to the user and invoke
    769          * {@link #postDialContinue(boolean)} when the user makes the choice.
    770          *
    771          * @param call The {@code Call} invoking this method.
    772          * @param remainingPostDialSequence The post-dial characters that remain to be sent.
    773          */
    774         public void onPostDialWait(Call call, String remainingPostDialSequence) {}
    775 
    776         /**
    777          * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
    778          *
    779          * @param call The {@code Call} invoking this method.
    780          * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
    781          */
    782         public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
    783 
    784         /**
    785          * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
    786          * up their UI for the {@code Call} in response to state transitions. Specifically,
    787          * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
    788          * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
    789          * clients should wait for this method to be invoked.
    790          *
    791          * @param call The {@code Call} being destroyed.
    792          */
    793         public void onCallDestroyed(Call call) {}
    794 
    795         /**
    796          * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
    797          * conferenced.
    798          *
    799          * @param call The {@code Call} being updated.
    800          * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
    801          *          conferenced.
    802          */
    803         public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
    804 
    805         /**
    806          * Invoked when a {@link Call} receives an event from its associated {@link Connection}.
    807          * <p>
    808          * Where possible, the Call should make an attempt to handle {@link Connection} events which
    809          * are part of the {@code android.telecom.*} namespace.  The Call should ignore any events
    810          * it does not wish to handle.  Unexpected events should be handled gracefully, as it is
    811          * possible that a {@link ConnectionService} has defined its own Connection events which a
    812          * Call is not aware of.
    813          * <p>
    814          * See {@link Connection#sendConnectionEvent(String, Bundle)}.
    815          *
    816          * @param call The {@code Call} receiving the event.
    817          * @param event The event.
    818          * @param extras Extras associated with the connection event.
    819          */
    820         public void onConnectionEvent(Call call, String event, Bundle extras) {}
    821     }
    822 
    823     /**
    824      * @deprecated Use {@code Call.Callback} instead.
    825      * @hide
    826      */
    827     @Deprecated
    828     @SystemApi
    829     public static abstract class Listener extends Callback { }
    830 
    831     private final Phone mPhone;
    832     private final String mTelecomCallId;
    833     private final InCallAdapter mInCallAdapter;
    834     private final List<String> mChildrenIds = new ArrayList<>();
    835     private final List<Call> mChildren = new ArrayList<>();
    836     private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
    837     private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>();
    838     private final List<Call> mConferenceableCalls = new ArrayList<>();
    839     private final List<Call> mUnmodifiableConferenceableCalls =
    840             Collections.unmodifiableList(mConferenceableCalls);
    841 
    842     private boolean mChildrenCached;
    843     private String mParentId = null;
    844     private int mState;
    845     private List<String> mCannedTextResponses = null;
    846     private String mRemainingPostDialSequence;
    847     private VideoCallImpl mVideoCallImpl;
    848     private Details mDetails;
    849     private Bundle mExtras;
    850 
    851     /**
    852      * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
    853      *
    854      * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
    855      * remaining or this {@code Call} is not in a post-dial state.
    856      */
    857     public String getRemainingPostDialSequence() {
    858         return mRemainingPostDialSequence;
    859     }
    860 
    861     /**
    862      * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
    863      * @param videoState The video state in which to answer the call.
    864      */
    865     public void answer(int videoState) {
    866         mInCallAdapter.answerCall(mTelecomCallId, videoState);
    867     }
    868 
    869     /**
    870      * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
    871      *
    872      * @param rejectWithMessage Whether to reject with a text message.
    873      * @param textMessage An optional text message with which to respond.
    874      */
    875     public void reject(boolean rejectWithMessage, String textMessage) {
    876         mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
    877     }
    878 
    879     /**
    880      * Instructs this {@code Call} to disconnect.
    881      */
    882     public void disconnect() {
    883         mInCallAdapter.disconnectCall(mTelecomCallId);
    884     }
    885 
    886     /**
    887      * Instructs this {@code Call} to go on hold.
    888      */
    889     public void hold() {
    890         mInCallAdapter.holdCall(mTelecomCallId);
    891     }
    892 
    893     /**
    894      * Instructs this {@link #STATE_HOLDING} call to release from hold.
    895      */
    896     public void unhold() {
    897         mInCallAdapter.unholdCall(mTelecomCallId);
    898     }
    899 
    900     /**
    901      * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
    902      *
    903      * Any other currently playing DTMF tone in the specified call is immediately stopped.
    904      *
    905      * @param digit A character representing the DTMF digit for which to play the tone. This
    906      *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
    907      */
    908     public void playDtmfTone(char digit) {
    909         mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
    910     }
    911 
    912     /**
    913      * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
    914      * currently playing.
    915      *
    916      * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
    917      * currently playing, this method will do nothing.
    918      */
    919     public void stopDtmfTone() {
    920         mInCallAdapter.stopDtmfTone(mTelecomCallId);
    921     }
    922 
    923     /**
    924      * Instructs this {@code Call} to continue playing a post-dial DTMF string.
    925      *
    926      * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
    927      * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
    928      *
    929      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
    930      * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
    931      *
    932      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
    933      * {@code Call} will pause playing the tones and notify callbacks via
    934      * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app
    935      * should display to the user an indication of this state and an affordance to continue
    936      * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
    937      * app should invoke the {@link #postDialContinue(boolean)} method.
    938      *
    939      * @param proceed Whether or not to continue with the post-dial sequence.
    940      */
    941     public void postDialContinue(boolean proceed) {
    942         mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
    943     }
    944 
    945     /**
    946      * Notifies this {@code Call} that an account has been selected and to proceed with placing
    947      * an outgoing call. Optionally sets this account as the default account.
    948      */
    949     public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
    950         mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
    951 
    952     }
    953 
    954     /**
    955      * Instructs this {@code Call} to enter a conference.
    956      *
    957      * @param callToConferenceWith The other call with which to conference.
    958      */
    959     public void conference(Call callToConferenceWith) {
    960         if (callToConferenceWith != null) {
    961             mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
    962         }
    963     }
    964 
    965     /**
    966      * Instructs this {@code Call} to split from any conference call with which it may be
    967      * connected.
    968      */
    969     public void splitFromConference() {
    970         mInCallAdapter.splitFromConference(mTelecomCallId);
    971     }
    972 
    973     /**
    974      * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}.
    975      */
    976     public void mergeConference() {
    977         mInCallAdapter.mergeConference(mTelecomCallId);
    978     }
    979 
    980     /**
    981      * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
    982      */
    983     public void swapConference() {
    984         mInCallAdapter.swapConference(mTelecomCallId);
    985     }
    986 
    987     /**
    988      * Initiates a request to the {@link ConnectionService} to pull an external call to the local
    989      * device.
    990      * <p>
    991      * Calls to this method are ignored if the call does not have the
    992      * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} property set.
    993      * <p>
    994      * An {@link InCallService} will only see calls which support this method if it has the
    995      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
    996      * in its manifest.
    997      */
    998     public void pullExternalCall() {
    999         // If this isn't an external call, ignore the request.
   1000         if (!mDetails.hasProperty(Details.PROPERTY_IS_EXTERNAL_CALL)) {
   1001             return;
   1002         }
   1003 
   1004         mInCallAdapter.pullExternalCall(mTelecomCallId);
   1005     }
   1006 
   1007     /**
   1008      * Sends a {@code Call} event from this {@code Call} to the associated {@link Connection} in
   1009      * the {@link ConnectionService}.
   1010      * <p>
   1011      * Call events are used to communicate point in time information from an {@link InCallService}
   1012      * to a {@link ConnectionService}.  A {@link ConnectionService} implementation could define
   1013      * events which enable the {@link InCallService}, for example, toggle a unique feature of the
   1014      * {@link ConnectionService}.
   1015      * <p>
   1016      * A {@link ConnectionService} can communicate to the {@link InCallService} using
   1017      * {@link Connection#sendConnectionEvent(String, Bundle)}.
   1018      * <p>
   1019      * Events are exposed to {@link ConnectionService} implementations via
   1020      * {@link android.telecom.Connection#onCallEvent(String, Bundle)}.
   1021      * <p>
   1022      * No assumptions should be made as to how a {@link ConnectionService} will handle these events.
   1023      * The {@link InCallService} must assume that the {@link ConnectionService} could chose to
   1024      * ignore some events altogether.
   1025      * <p>
   1026      * Events should be fully qualified (e.g., {@code com.example.event.MY_EVENT}) to avoid
   1027      * conflicts between {@link InCallService} implementations.  Further, {@link InCallService}
   1028      * implementations shall not re-purpose events in the {@code android.*} namespace, nor shall
   1029      * they define their own event types in this namespace.  When defining a custom event type,
   1030      * ensure the contents of the extras {@link Bundle} is clearly defined.  Extra keys for this
   1031      * bundle should be named similar to the event type (e.g. {@code com.example.extra.MY_EXTRA}).
   1032      * <p>
   1033      * When defining events and the associated extras, it is important to keep their behavior
   1034      * consistent when the associated {@link InCallService} is updated.  Support for deprecated
   1035      * events/extras should me maintained to ensure backwards compatibility with older
   1036      * {@link ConnectionService} implementations which were built to support the older behavior.
   1037      *
   1038      * @param event The connection event.
   1039      * @param extras Bundle containing extra information associated with the event.
   1040      */
   1041     public void sendCallEvent(String event, Bundle extras) {
   1042         mInCallAdapter.sendCallEvent(mTelecomCallId, event, extras);
   1043     }
   1044 
   1045     /**
   1046      * Adds some extras to this {@link Call}.  Existing keys are replaced and new ones are
   1047      * added.
   1048      * <p>
   1049      * No assumptions should be made as to how an In-Call UI or service will handle these
   1050      * extras.  Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
   1051      *
   1052      * @param extras The extras to add.
   1053      */
   1054     public final void putExtras(Bundle extras) {
   1055         if (extras == null) {
   1056             return;
   1057         }
   1058 
   1059         if (mExtras == null) {
   1060             mExtras = new Bundle();
   1061         }
   1062         mExtras.putAll(extras);
   1063         mInCallAdapter.putExtras(mTelecomCallId, extras);
   1064     }
   1065 
   1066     /**
   1067      * Adds a boolean extra to this {@link Call}.
   1068      *
   1069      * @param key The extra key.
   1070      * @param value The value.
   1071      * @hide
   1072      */
   1073     public final void putExtra(String key, boolean value) {
   1074         if (mExtras == null) {
   1075             mExtras = new Bundle();
   1076         }
   1077         mExtras.putBoolean(key, value);
   1078         mInCallAdapter.putExtra(mTelecomCallId, key, value);
   1079     }
   1080 
   1081     /**
   1082      * Adds an integer extra to this {@link Call}.
   1083      *
   1084      * @param key The extra key.
   1085      * @param value The value.
   1086      * @hide
   1087      */
   1088     public final void putExtra(String key, int value) {
   1089         if (mExtras == null) {
   1090             mExtras = new Bundle();
   1091         }
   1092         mExtras.putInt(key, value);
   1093         mInCallAdapter.putExtra(mTelecomCallId, key, value);
   1094     }
   1095 
   1096     /**
   1097      * Adds a string extra to this {@link Call}.
   1098      *
   1099      * @param key The extra key.
   1100      * @param value The value.
   1101      * @hide
   1102      */
   1103     public final void putExtra(String key, String value) {
   1104         if (mExtras == null) {
   1105             mExtras = new Bundle();
   1106         }
   1107         mExtras.putString(key, value);
   1108         mInCallAdapter.putExtra(mTelecomCallId, key, value);
   1109     }
   1110 
   1111     /**
   1112      * Removes extras from this {@link Call}.
   1113      *
   1114      * @param keys The keys of the extras to remove.
   1115      */
   1116     public final void removeExtras(List<String> keys) {
   1117         if (mExtras != null) {
   1118             for (String key : keys) {
   1119                 mExtras.remove(key);
   1120             }
   1121             if (mExtras.size() == 0) {
   1122                 mExtras = null;
   1123             }
   1124         }
   1125         mInCallAdapter.removeExtras(mTelecomCallId, keys);
   1126     }
   1127 
   1128     /**
   1129      * Removes extras from this {@link Call}.
   1130      *
   1131      * @param keys The keys of the extras to remove.
   1132      */
   1133     public final void removeExtras(String ... keys) {
   1134         removeExtras(Arrays.asList(keys));
   1135     }
   1136 
   1137     /**
   1138      * Obtains the parent of this {@code Call} in a conference, if any.
   1139      *
   1140      * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
   1141      * child of any conference {@code Call}s.
   1142      */
   1143     public Call getParent() {
   1144         if (mParentId != null) {
   1145             return mPhone.internalGetCallByTelecomId(mParentId);
   1146         }
   1147         return null;
   1148     }
   1149 
   1150     /**
   1151      * Obtains the children of this conference {@code Call}, if any.
   1152      *
   1153      * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
   1154      * {@code List} otherwise.
   1155      */
   1156     public List<Call> getChildren() {
   1157         if (!mChildrenCached) {
   1158             mChildrenCached = true;
   1159             mChildren.clear();
   1160 
   1161             for(String id : mChildrenIds) {
   1162                 Call call = mPhone.internalGetCallByTelecomId(id);
   1163                 if (call == null) {
   1164                     // At least one child was still not found, so do not save true for "cached"
   1165                     mChildrenCached = false;
   1166                 } else {
   1167                     mChildren.add(call);
   1168                 }
   1169             }
   1170         }
   1171 
   1172         return mUnmodifiableChildren;
   1173     }
   1174 
   1175     /**
   1176      * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
   1177      *
   1178      * @return The list of conferenceable {@code Call}s.
   1179      */
   1180     public List<Call> getConferenceableCalls() {
   1181         return mUnmodifiableConferenceableCalls;
   1182     }
   1183 
   1184     /**
   1185      * Obtains the state of this {@code Call}.
   1186      *
   1187      * @return A state value, chosen from the {@code STATE_*} constants.
   1188      */
   1189     public int getState() {
   1190         return mState;
   1191     }
   1192 
   1193     /**
   1194      * Obtains a list of canned, pre-configured message responses to present to the user as
   1195      * ways of rejecting this {@code Call} using via a text message.
   1196      *
   1197      * @see #reject(boolean, String)
   1198      *
   1199      * @return A list of canned text message responses.
   1200      */
   1201     public List<String> getCannedTextResponses() {
   1202         return mCannedTextResponses;
   1203     }
   1204 
   1205     /**
   1206      * Obtains an object that can be used to display video from this {@code Call}.
   1207      *
   1208      * @return An {@code Call.VideoCall}.
   1209      */
   1210     public InCallService.VideoCall getVideoCall() {
   1211         return mVideoCallImpl;
   1212     }
   1213 
   1214     /**
   1215      * Obtains an object containing call details.
   1216      *
   1217      * @return A {@link Details} object. Depending on the state of the {@code Call}, the
   1218      * result may be {@code null}.
   1219      */
   1220     public Details getDetails() {
   1221         return mDetails;
   1222     }
   1223 
   1224     /**
   1225      * Registers a callback to this {@code Call}.
   1226      *
   1227      * @param callback A {@code Callback}.
   1228      */
   1229     public void registerCallback(Callback callback) {
   1230         registerCallback(callback, new Handler());
   1231     }
   1232 
   1233     /**
   1234      * Registers a callback to this {@code Call}.
   1235      *
   1236      * @param callback A {@code Callback}.
   1237      * @param handler A handler which command and status changes will be delivered to.
   1238      */
   1239     public void registerCallback(Callback callback, Handler handler) {
   1240         unregisterCallback(callback);
   1241         // Don't allow new callback registration if the call is already being destroyed.
   1242         if (callback != null && handler != null && mState != STATE_DISCONNECTED) {
   1243             mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler));
   1244         }
   1245     }
   1246 
   1247     /**
   1248      * Unregisters a callback from this {@code Call}.
   1249      *
   1250      * @param callback A {@code Callback}.
   1251      */
   1252     public void unregisterCallback(Callback callback) {
   1253         // Don't allow callback deregistration if the call is already being destroyed.
   1254         if (callback != null && mState != STATE_DISCONNECTED) {
   1255             for (CallbackRecord<Callback> record : mCallbackRecords) {
   1256                 if (record.getCallback() == callback) {
   1257                     mCallbackRecords.remove(record);
   1258                     break;
   1259                 }
   1260             }
   1261         }
   1262     }
   1263 
   1264     @Override
   1265     public String toString() {
   1266         return new StringBuilder().
   1267                 append("Call [id: ").
   1268                 append(mTelecomCallId).
   1269                 append(", state: ").
   1270                 append(stateToString(mState)).
   1271                 append(", details: ").
   1272                 append(mDetails).
   1273                 append("]").toString();
   1274     }
   1275 
   1276     /**
   1277      * @param state An integer value of a {@code STATE_*} constant.
   1278      * @return A string representation of the value.
   1279      */
   1280     private static String stateToString(int state) {
   1281         switch (state) {
   1282             case STATE_NEW:
   1283                 return "NEW";
   1284             case STATE_RINGING:
   1285                 return "RINGING";
   1286             case STATE_DIALING:
   1287                 return "DIALING";
   1288             case STATE_ACTIVE:
   1289                 return "ACTIVE";
   1290             case STATE_HOLDING:
   1291                 return "HOLDING";
   1292             case STATE_DISCONNECTED:
   1293                 return "DISCONNECTED";
   1294             case STATE_CONNECTING:
   1295                 return "CONNECTING";
   1296             case STATE_DISCONNECTING:
   1297                 return "DISCONNECTING";
   1298             case STATE_SELECT_PHONE_ACCOUNT:
   1299                 return "SELECT_PHONE_ACCOUNT";
   1300             default:
   1301                 Log.w(Call.class, "Unknown state %d", state);
   1302                 return "UNKNOWN";
   1303         }
   1304     }
   1305 
   1306     /**
   1307      * Adds a listener to this {@code Call}.
   1308      *
   1309      * @param listener A {@code Listener}.
   1310      * @deprecated Use {@link #registerCallback} instead.
   1311      * @hide
   1312      */
   1313     @Deprecated
   1314     @SystemApi
   1315     public void addListener(Listener listener) {
   1316         registerCallback(listener);
   1317     }
   1318 
   1319     /**
   1320      * Removes a listener from this {@code Call}.
   1321      *
   1322      * @param listener A {@code Listener}.
   1323      * @deprecated Use {@link #unregisterCallback} instead.
   1324      * @hide
   1325      */
   1326     @Deprecated
   1327     @SystemApi
   1328     public void removeListener(Listener listener) {
   1329         unregisterCallback(listener);
   1330     }
   1331 
   1332     /** {@hide} */
   1333     Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
   1334         mPhone = phone;
   1335         mTelecomCallId = telecomCallId;
   1336         mInCallAdapter = inCallAdapter;
   1337         mState = STATE_NEW;
   1338     }
   1339 
   1340     /** {@hide} */
   1341     Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) {
   1342         mPhone = phone;
   1343         mTelecomCallId = telecomCallId;
   1344         mInCallAdapter = inCallAdapter;
   1345         mState = state;
   1346     }
   1347 
   1348     /** {@hide} */
   1349     final String internalGetCallId() {
   1350         return mTelecomCallId;
   1351     }
   1352 
   1353     /** {@hide} */
   1354     final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
   1355         // First, we update the internal state as far as possible before firing any updates.
   1356         Details details = Details.createFromParcelableCall(parcelableCall);
   1357         boolean detailsChanged = !Objects.equals(mDetails, details);
   1358         if (detailsChanged) {
   1359             mDetails = details;
   1360         }
   1361 
   1362         boolean cannedTextResponsesChanged = false;
   1363         if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
   1364                 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
   1365             mCannedTextResponses =
   1366                     Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
   1367             cannedTextResponsesChanged = true;
   1368         }
   1369 
   1370         VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl();
   1371         boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
   1372                 !Objects.equals(mVideoCallImpl, newVideoCallImpl);
   1373         if (videoCallChanged) {
   1374             mVideoCallImpl = newVideoCallImpl;
   1375         }
   1376         if (mVideoCallImpl != null) {
   1377             mVideoCallImpl.setVideoState(getDetails().getVideoState());
   1378         }
   1379 
   1380         int state = parcelableCall.getState();
   1381         boolean stateChanged = mState != state;
   1382         if (stateChanged) {
   1383             mState = state;
   1384         }
   1385 
   1386         String parentId = parcelableCall.getParentCallId();
   1387         boolean parentChanged = !Objects.equals(mParentId, parentId);
   1388         if (parentChanged) {
   1389             mParentId = parentId;
   1390         }
   1391 
   1392         List<String> childCallIds = parcelableCall.getChildCallIds();
   1393         boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
   1394         if (childrenChanged) {
   1395             mChildrenIds.clear();
   1396             mChildrenIds.addAll(parcelableCall.getChildCallIds());
   1397             mChildrenCached = false;
   1398         }
   1399 
   1400         List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
   1401         List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
   1402         for (String otherId : conferenceableCallIds) {
   1403             if (callIdMap.containsKey(otherId)) {
   1404                 conferenceableCalls.add(callIdMap.get(otherId));
   1405             }
   1406         }
   1407 
   1408         if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
   1409             mConferenceableCalls.clear();
   1410             mConferenceableCalls.addAll(conferenceableCalls);
   1411             fireConferenceableCallsChanged();
   1412         }
   1413 
   1414         // Now we fire updates, ensuring that any client who listens to any of these notifications
   1415         // gets the most up-to-date state.
   1416 
   1417         if (stateChanged) {
   1418             fireStateChanged(mState);
   1419         }
   1420         if (detailsChanged) {
   1421             fireDetailsChanged(mDetails);
   1422         }
   1423         if (cannedTextResponsesChanged) {
   1424             fireCannedTextResponsesLoaded(mCannedTextResponses);
   1425         }
   1426         if (videoCallChanged) {
   1427             fireVideoCallChanged(mVideoCallImpl);
   1428         }
   1429         if (parentChanged) {
   1430             fireParentChanged(getParent());
   1431         }
   1432         if (childrenChanged) {
   1433             fireChildrenChanged(getChildren());
   1434         }
   1435 
   1436         // If we have transitioned to DISCONNECTED, that means we need to notify clients and
   1437         // remove ourselves from the Phone. Note that we do this after completing all state updates
   1438         // so a client can cleanly transition all their UI to the state appropriate for a
   1439         // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
   1440         if (mState == STATE_DISCONNECTED) {
   1441             fireCallDestroyed();
   1442         }
   1443     }
   1444 
   1445     /** {@hide} */
   1446     final void internalSetPostDialWait(String remaining) {
   1447         mRemainingPostDialSequence = remaining;
   1448         firePostDialWait(mRemainingPostDialSequence);
   1449     }
   1450 
   1451     /** {@hide} */
   1452     final void internalSetDisconnected() {
   1453         if (mState != Call.STATE_DISCONNECTED) {
   1454             mState = Call.STATE_DISCONNECTED;
   1455             fireStateChanged(mState);
   1456             fireCallDestroyed();
   1457         }
   1458     }
   1459 
   1460     /** {@hide} */
   1461     final void internalOnConnectionEvent(String event, Bundle extras) {
   1462         fireOnConnectionEvent(event, extras);
   1463     }
   1464 
   1465     private void fireStateChanged(final int newState) {
   1466         for (CallbackRecord<Callback> record : mCallbackRecords) {
   1467             final Call call = this;
   1468             final Callback callback = record.getCallback();
   1469             record.getHandler().post(new Runnable() {
   1470                 @Override
   1471                 public void run() {
   1472                     callback.onStateChanged(call, newState);
   1473                 }
   1474             });
   1475         }
   1476     }
   1477 
   1478     private void fireParentChanged(final Call newParent) {
   1479         for (CallbackRecord<Callback> record : mCallbackRecords) {
   1480             final Call call = this;
   1481             final Callback callback = record.getCallback();
   1482             record.getHandler().post(new Runnable() {
   1483                 @Override
   1484                 public void run() {
   1485                     callback.onParentChanged(call, newParent);
   1486                 }
   1487             });
   1488         }
   1489     }
   1490 
   1491     private void fireChildrenChanged(final List<Call> children) {
   1492         for (CallbackRecord<Callback> record : mCallbackRecords) {
   1493             final Call call = this;
   1494             final Callback callback = record.getCallback();
   1495             record.getHandler().post(new Runnable() {
   1496                 @Override
   1497                 public void run() {
   1498                     callback.onChildrenChanged(call, children);
   1499                 }
   1500             });
   1501         }
   1502     }
   1503 
   1504     private void fireDetailsChanged(final Details details) {
   1505         for (CallbackRecord<Callback> record : mCallbackRecords) {
   1506             final Call call = this;
   1507             final Callback callback = record.getCallback();
   1508             record.getHandler().post(new Runnable() {
   1509                 @Override
   1510                 public void run() {
   1511                     callback.onDetailsChanged(call, details);
   1512                 }
   1513             });
   1514         }
   1515     }
   1516 
   1517     private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) {
   1518         for (CallbackRecord<Callback> record : mCallbackRecords) {
   1519             final Call call = this;
   1520             final Callback callback = record.getCallback();
   1521             record.getHandler().post(new Runnable() {
   1522                 @Override
   1523                 public void run() {
   1524                     callback.onCannedTextResponsesLoaded(call, cannedTextResponses);
   1525                 }
   1526             });
   1527         }
   1528     }
   1529 
   1530     private void fireVideoCallChanged(final InCallService.VideoCall videoCall) {
   1531         for (CallbackRecord<Callback> record : mCallbackRecords) {
   1532             final Call call = this;
   1533             final Callback callback = record.getCallback();
   1534             record.getHandler().post(new Runnable() {
   1535                 @Override
   1536                 public void run() {
   1537                     callback.onVideoCallChanged(call, videoCall);
   1538                 }
   1539             });
   1540         }
   1541     }
   1542 
   1543     private void firePostDialWait(final String remainingPostDialSequence) {
   1544         for (CallbackRecord<Callback> record : mCallbackRecords) {
   1545             final Call call = this;
   1546             final Callback callback = record.getCallback();
   1547             record.getHandler().post(new Runnable() {
   1548                 @Override
   1549                 public void run() {
   1550                     callback.onPostDialWait(call, remainingPostDialSequence);
   1551                 }
   1552             });
   1553         }
   1554     }
   1555 
   1556     private void fireCallDestroyed() {
   1557         /**
   1558          * To preserve the ordering of the Call's onCallDestroyed callback and Phone's
   1559          * onCallRemoved callback, we remove this call from the Phone's record
   1560          * only once all of the registered onCallDestroyed callbacks are executed.
   1561          * All the callbacks get removed from our records as a part of this operation
   1562          * since onCallDestroyed is the final callback.
   1563          */
   1564         final Call call = this;
   1565         if (mCallbackRecords.isEmpty()) {
   1566             // No callbacks registered, remove the call from Phone's record.
   1567             mPhone.internalRemoveCall(call);
   1568         }
   1569         for (final CallbackRecord<Callback> record : mCallbackRecords) {
   1570             final Callback callback = record.getCallback();
   1571             record.getHandler().post(new Runnable() {
   1572                 @Override
   1573                 public void run() {
   1574                     boolean isFinalRemoval = false;
   1575                     RuntimeException toThrow = null;
   1576                     try {
   1577                         callback.onCallDestroyed(call);
   1578                     } catch (RuntimeException e) {
   1579                             toThrow = e;
   1580                     }
   1581                     synchronized(Call.this) {
   1582                         mCallbackRecords.remove(record);
   1583                         if (mCallbackRecords.isEmpty()) {
   1584                             isFinalRemoval = true;
   1585                         }
   1586                     }
   1587                     if (isFinalRemoval) {
   1588                         mPhone.internalRemoveCall(call);
   1589                     }
   1590                     if (toThrow != null) {
   1591                         throw toThrow;
   1592                     }
   1593                 }
   1594             });
   1595         }
   1596     }
   1597 
   1598     private void fireConferenceableCallsChanged() {
   1599         for (CallbackRecord<Callback> record : mCallbackRecords) {
   1600             final Call call = this;
   1601             final Callback callback = record.getCallback();
   1602             record.getHandler().post(new Runnable() {
   1603                 @Override
   1604                 public void run() {
   1605                     callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls);
   1606                 }
   1607             });
   1608         }
   1609     }
   1610 
   1611     /**
   1612      * Notifies listeners of an incoming connection event.
   1613      * <p>
   1614      * Connection events are issued via {@link Connection#sendConnectionEvent(String, Bundle)}.
   1615      *
   1616      * @param event
   1617      * @param extras
   1618      */
   1619     private void fireOnConnectionEvent(final String event, final Bundle extras) {
   1620         for (CallbackRecord<Callback> record : mCallbackRecords) {
   1621             final Call call = this;
   1622             final Callback callback = record.getCallback();
   1623             record.getHandler().post(new Runnable() {
   1624                 @Override
   1625                 public void run() {
   1626                     callback.onConnectionEvent(call, event, extras);
   1627                 }
   1628             });
   1629         }
   1630     }
   1631 
   1632     /**
   1633      * Determines if two bundles are equal.
   1634      *
   1635      * @param bundle The original bundle.
   1636      * @param newBundle The bundle to compare with.
   1637      * @retrun {@code true} if the bundles are equal, {@code false} otherwise.
   1638      */
   1639     private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) {
   1640         if (bundle == null || newBundle == null) {
   1641             return bundle == newBundle;
   1642         }
   1643 
   1644         if (bundle.size() != newBundle.size()) {
   1645             return false;
   1646         }
   1647 
   1648         for(String key : bundle.keySet()) {
   1649             if (key != null) {
   1650                 final Object value = bundle.get(key);
   1651                 final Object newValue = newBundle.get(key);
   1652                 if (!Objects.equals(value, newValue)) {
   1653                     return false;
   1654                 }
   1655             }
   1656         }
   1657         return true;
   1658     }
   1659 }
   1660