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