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 com.android.internal.os.SomeArgs;
     20 import com.android.internal.telecom.IVideoCallback;
     21 import com.android.internal.telecom.IVideoProvider;
     22 
     23 import android.annotation.NonNull;
     24 import android.annotation.Nullable;
     25 import android.annotation.SystemApi;
     26 import android.hardware.camera2.CameraManager;
     27 import android.net.Uri;
     28 import android.os.Bundle;
     29 import android.os.Handler;
     30 import android.os.IBinder;
     31 import android.os.Looper;
     32 import android.os.Message;
     33 import android.os.RemoteException;
     34 import android.util.ArraySet;
     35 import android.view.Surface;
     36 
     37 import java.util.ArrayList;
     38 import java.util.Arrays;
     39 import java.util.Collections;
     40 import java.util.List;
     41 import java.util.Set;
     42 import java.util.concurrent.ConcurrentHashMap;
     43 
     44 /**
     45  * Represents a phone call or connection to a remote endpoint that carries voice and/or video
     46  * traffic.
     47  * <p>
     48  * Implementations create a custom subclass of {@code Connection} and return it to the framework
     49  * as the return value of
     50  * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}
     51  * or
     52  * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
     53  * Implementations are then responsible for updating the state of the {@code Connection}, and
     54  * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no
     55  * longer used and associated resources may be recovered.
     56  * <p>
     57  * Subclasses of {@code Connection} override the {@code on*} methods to provide the the
     58  * {@link ConnectionService}'s implementation of calling functionality.  The {@code on*} methods are
     59  * called by Telecom to inform an instance of a {@code Connection} of actions specific to that
     60  * {@code Connection} instance.
     61  * <p>
     62  * Basic call support requires overriding the following methods: {@link #onAnswer()},
     63  * {@link #onDisconnect()}, {@link #onReject()}, {@link #onAbort()}
     64  * <p>
     65  * Where a {@code Connection} has {@link #CAPABILITY_SUPPORT_HOLD}, the {@link #onHold()} and
     66  * {@link #onUnhold()} methods should be overridden to provide hold support for the
     67  * {@code Connection}.
     68  * <p>
     69  * Where a {@code Connection} supports a variation of video calling (e.g. the
     70  * {@code CAPABILITY_SUPPORTS_VT_*} capability bits), {@link #onAnswer(int)} should be overridden
     71  * to support answering a call as a video call.
     72  * <p>
     73  * Where a {@code Connection} has {@link #PROPERTY_IS_EXTERNAL_CALL} and
     74  * {@link #CAPABILITY_CAN_PULL_CALL}, {@link #onPullExternalCall()} should be overridden to provide
     75  * support for pulling the external call.
     76  * <p>
     77  * Where a {@code Connection} supports conference calling {@link #onSeparate()} should be
     78  * overridden.
     79  * <p>
     80  * There are a number of other {@code on*} methods which a {@code Connection} can choose to
     81  * implement, depending on whether it is concerned with the associated calls from Telecom.  If,
     82  * for example, call events from a {@link InCallService} are handled,
     83  * {@link #onCallEvent(String, Bundle)} should be overridden.  Another example is
     84  * {@link #onExtrasChanged(Bundle)}, which should be overridden if the {@code Connection} wishes to
     85  * make use of extra information provided via the {@link Call#putExtras(Bundle)} and
     86  * {@link Call#removeExtras(String...)} methods.
     87  */
     88 public abstract class Connection extends Conferenceable {
     89 
     90     /**
     91      * The connection is initializing. This is generally the first state for a {@code Connection}
     92      * returned by a {@link ConnectionService}.
     93      */
     94     public static final int STATE_INITIALIZING = 0;
     95 
     96     /**
     97      * The connection is new and not connected.
     98      */
     99     public static final int STATE_NEW = 1;
    100 
    101     /**
    102      * An incoming connection is in the ringing state. During this state, the user's ringer or
    103      * vibration feature will be activated.
    104      */
    105     public static final int STATE_RINGING = 2;
    106 
    107     /**
    108      * An outgoing connection is in the dialing state. In this state the other party has not yet
    109      * answered the call and the user traditionally hears a ringback tone.
    110      */
    111     public static final int STATE_DIALING = 3;
    112 
    113     /**
    114      * A connection is active. Both parties are connected to the call and can actively communicate.
    115      */
    116     public static final int STATE_ACTIVE = 4;
    117 
    118     /**
    119      * A connection is on hold.
    120      */
    121     public static final int STATE_HOLDING = 5;
    122 
    123     /**
    124      * A connection has been disconnected. This is the final state once the user has been
    125      * disconnected from a call either locally, remotely or by an error in the service.
    126      */
    127     public static final int STATE_DISCONNECTED = 6;
    128 
    129     /**
    130      * The state of an external connection which is in the process of being pulled from a remote
    131      * device to the local device.
    132      * <p>
    133      * A connection can only be in this state if the {@link #PROPERTY_IS_EXTERNAL_CALL} property and
    134      * {@link #CAPABILITY_CAN_PULL_CALL} capability bits are set on the connection.
    135      */
    136     public static final int STATE_PULLING_CALL = 7;
    137 
    138     /**
    139      * Connection can currently be put on hold or unheld. This is distinct from
    140      * {@link #CAPABILITY_SUPPORT_HOLD} in that although a connection may support 'hold' most times,
    141      * it does not at the moment support the function. This can be true while the call is in the
    142      * state {@link #STATE_DIALING}, for example. During this condition, an in-call UI may
    143      * display a disabled 'hold' button.
    144      */
    145     public static final int CAPABILITY_HOLD = 0x00000001;
    146 
    147     /** Connection supports the hold feature. */
    148     public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
    149 
    150     /**
    151      * Connections within a conference can be merged. A {@link ConnectionService} has the option to
    152      * add a {@link Conference} before the child {@link Connection}s are merged. This is how
    153      * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
    154      * capability allows a merge button to be shown while the conference is in the foreground
    155      * of the in-call UI.
    156      * <p>
    157      * This is only intended for use by a {@link Conference}.
    158      */
    159     public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
    160 
    161     /**
    162      * Connections within a conference can be swapped between foreground and background.
    163      * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
    164      * <p>
    165      * This is only intended for use by a {@link Conference}.
    166      */
    167     public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
    168 
    169     /**
    170      * @hide
    171      */
    172     public static final int CAPABILITY_UNUSED = 0x00000010;
    173 
    174     /** Connection supports responding via text option. */
    175     public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
    176 
    177     /** Connection can be muted. */
    178     public static final int CAPABILITY_MUTE = 0x00000040;
    179 
    180     /**
    181      * Connection supports conference management. This capability only applies to
    182      * {@link Conference}s which can have {@link Connection}s as children.
    183      */
    184     public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
    185 
    186     /**
    187      * Local device supports receiving video.
    188      */
    189     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
    190 
    191     /**
    192      * Local device supports transmitting video.
    193      */
    194     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
    195 
    196     /**
    197      * Local device supports bidirectional video calling.
    198      */
    199     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
    200             CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
    201 
    202     /**
    203      * Remote device supports receiving video.
    204      */
    205     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
    206 
    207     /**
    208      * Remote device supports transmitting video.
    209      */
    210     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
    211 
    212     /**
    213      * Remote device supports bidirectional video calling.
    214      */
    215     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
    216             CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
    217 
    218     /**
    219      * Connection is able to be separated from its parent {@code Conference}, if any.
    220      */
    221     public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
    222 
    223     /**
    224      * Connection is able to be individually disconnected when in a {@code Conference}.
    225      */
    226     public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
    227 
    228     /**
    229      * Un-used.
    230      * @hide
    231      */
    232     public static final int CAPABILITY_UNUSED_2 = 0x00004000;
    233 
    234     /**
    235      * Un-used.
    236      * @hide
    237      */
    238     public static final int CAPABILITY_UNUSED_3 = 0x00008000;
    239 
    240     /**
    241      * Un-used.
    242      * @hide
    243      */
    244     public static final int CAPABILITY_UNUSED_4 = 0x00010000;
    245 
    246     /**
    247      * Un-used.
    248      * @hide
    249      */
    250     public static final int CAPABILITY_UNUSED_5 = 0x00020000;
    251 
    252     /**
    253      * Speed up audio setup for MT call.
    254      * @hide
    255      */
    256     public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
    257 
    258     /**
    259      * Call can be upgraded to a video call.
    260      */
    261     public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
    262 
    263     /**
    264      * For video calls, indicates whether the outgoing video for the call can be paused using
    265      * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
    266      */
    267     public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
    268 
    269     /**
    270      * For a conference, indicates the conference will not have child connections.
    271      * <p>
    272      * An example of a conference with child connections is a GSM conference call, where the radio
    273      * retains connections to the individual participants of the conference.  Another example is an
    274      * IMS conference call where conference event package functionality is supported; in this case
    275      * the conference server ensures the radio is aware of the participants in the conference, which
    276      * are represented by child connections.
    277      * <p>
    278      * An example of a conference with no child connections is an IMS conference call with no
    279      * conference event package support.  Such a conference is represented by the radio as a single
    280      * connection to the IMS conference server.
    281      * <p>
    282      * Indicating whether a conference has children or not is important to help user interfaces
    283      * visually represent a conference.  A conference with no children, for example, will have the
    284      * conference connection shown in the list of calls on a Bluetooth device, where if the
    285      * conference has children, only the children will be shown in the list of calls on a Bluetooth
    286      * device.
    287      * @hide
    288      */
    289     public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
    290 
    291     /**
    292      * Indicates that the connection itself wants to handle any sort of reply response, rather than
    293      * relying on SMS.
    294      */
    295     public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
    296 
    297     /**
    298      * When set, prevents a video call from being downgraded to an audio-only call.
    299      * <p>
    300      * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
    301      * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
    302      * downgraded from a video call back to a VideoState of
    303      * {@link VideoProfile#STATE_AUDIO_ONLY}.
    304      * <p>
    305      * Intuitively, a call which can be downgraded to audio should also have local and remote
    306      * video
    307      * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
    308      * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
    309      */
    310     public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00800000;
    311 
    312     /**
    313      * When set for an external connection, indicates that this {@code Connection} can be pulled
    314      * from a remote device to the current device.
    315      * <p>
    316      * Should only be set on a {@code Connection} where {@link #PROPERTY_IS_EXTERNAL_CALL}
    317      * is set.
    318      */
    319     public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000;
    320 
    321     //**********************************************************************************************
    322     // Next CAPABILITY value: 0x02000000
    323     //**********************************************************************************************
    324 
    325     /**
    326      * Indicates that the current device callback number should be shown.
    327      *
    328      * @hide
    329      */
    330     public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1<<0;
    331 
    332     /**
    333      * Whether the call is a generic conference, where we do not know the precise state of
    334      * participants in the conference (eg. on CDMA).
    335      *
    336      * @hide
    337      */
    338     public static final int PROPERTY_GENERIC_CONFERENCE = 1<<1;
    339 
    340     /**
    341      * Connection is using high definition audio.
    342      * @hide
    343      */
    344     public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2;
    345 
    346     /**
    347      * Connection is using WIFI.
    348      * @hide
    349      */
    350     public static final int PROPERTY_WIFI = 1<<3;
    351 
    352     /**
    353      * When set, indicates that the {@code Connection} does not actually exist locally for the
    354      * {@link ConnectionService}.
    355      * <p>
    356      * Consider, for example, a scenario where a user has two devices with the same phone number.
    357      * When a user places a call on one devices, the telephony stack can represent that call on the
    358      * other device by adding is to the {@link ConnectionService} with the
    359      * {@link #PROPERTY_IS_EXTERNAL_CALL} capability set.
    360      * <p>
    361      * An {@link ConnectionService} should not assume that all {@link InCallService}s will handle
    362      * external connections.  Only those {@link InCallService}s which have the
    363      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
    364      * manifest will see external connections.
    365      */
    366     public static final int PROPERTY_IS_EXTERNAL_CALL = 1<<4;
    367 
    368     /**
    369      * Indicates that the connection has CDMA Enhanced Voice Privacy enabled.
    370      */
    371     public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 1<<5;
    372 
    373     /**
    374      * Indicates that the connection represents a downgraded IMS conference.
    375      * @hide
    376      */
    377     public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 1<<6;
    378 
    379     //**********************************************************************************************
    380     // Next PROPERTY value: 1<<7
    381     //**********************************************************************************************
    382 
    383     /**
    384      * Connection extra key used to store the last forwarded number associated with the current
    385      * connection.  Used to communicate to the user interface that the connection was forwarded via
    386      * the specified number.
    387      */
    388     public static final String EXTRA_LAST_FORWARDED_NUMBER =
    389             "android.telecom.extra.LAST_FORWARDED_NUMBER";
    390 
    391     /**
    392      * Connection extra key used to store a child number associated with the current connection.
    393      * Used to communicate to the user interface that the connection was received via
    394      * a child address (i.e. phone number) associated with the {@link PhoneAccount}'s primary
    395      * address.
    396      */
    397     public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
    398 
    399     /**
    400      * Connection extra key used to store the subject for an incoming call.  The user interface can
    401      * query this extra and display its contents for incoming calls.  Will only be used if the
    402      * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}.
    403      */
    404     public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
    405 
    406     /**
    407      * Boolean connection extra key set on a {@link Connection} in
    408      * {@link Connection#STATE_RINGING} state to indicate that answering the call will cause the
    409      * current active foreground call to be dropped.
    410      */
    411     public static final String EXTRA_ANSWERING_DROPS_FG_CALL =
    412             "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
    413 
    414     /**
    415      * Boolean connection extra key on a {@link Connection} which indicates that adding an
    416      * additional call is disallowed.
    417      * @hide
    418      */
    419     public static final String EXTRA_DISABLE_ADD_CALL =
    420             "android.telecom.extra.DISABLE_ADD_CALL";
    421 
    422     /**
    423      * String connection extra key on a {@link Connection} or {@link Conference} which contains the
    424      * original Connection ID associated with the connection.  Used in
    425      * {@link RemoteConnectionService} to track the Connection ID which was originally assigned to a
    426      * connection/conference added via
    427      * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)} and
    428      * {@link ConnectionService#addConference(Conference)} APIs.  This is important to pass to
    429      * Telecom for when it deals with RemoteConnections.  When the ConnectionManager wraps the
    430      * {@link RemoteConnection} and {@link RemoteConference} and adds it to Telecom, there needs to
    431      * be a way to ensure that we don't add the connection again as a duplicate.
    432      * <p>
    433      * For example, the TelephonyCS calls addExistingConnection for a Connection with ID
    434      * {@code TelephonyCS@1}.  The ConnectionManager learns of this via
    435      * {@link ConnectionService#onRemoteExistingConnectionAdded(RemoteConnection)}, and wraps this
    436      * in a new {@link Connection} which it adds to Telecom via
    437      * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)}.  As part of
    438      * this process, the wrapped RemoteConnection gets assigned a new ID (e.g. {@code ConnMan@1}).
    439      * The TelephonyCS will ALSO try to add the existing connection to Telecom, except with the
    440      * ID it originally referred to the connection as.  Thus Telecom needs to know that the
    441      * Connection with ID {@code ConnMan@1} is really the same as {@code TelephonyCS@1}.
    442      * @hide
    443      */
    444     public static final String EXTRA_ORIGINAL_CONNECTION_ID =
    445             "android.telecom.extra.ORIGINAL_CONNECTION_ID";
    446 
    447     /**
    448      * Connection event used to inform Telecom that it should play the on hold tone.  This is used
    449      * to play a tone when the peer puts the current call on hold.  Sent to Telecom via
    450      * {@link #sendConnectionEvent(String, Bundle)}.
    451      * @hide
    452      */
    453     public static final String EVENT_ON_HOLD_TONE_START =
    454             "android.telecom.event.ON_HOLD_TONE_START";
    455 
    456     /**
    457      * Connection event used to inform Telecom that it should stop the on hold tone.  This is used
    458      * to stop a tone when the peer puts the current call on hold.  Sent to Telecom via
    459      * {@link #sendConnectionEvent(String, Bundle)}.
    460      * @hide
    461      */
    462     public static final String EVENT_ON_HOLD_TONE_END =
    463             "android.telecom.event.ON_HOLD_TONE_END";
    464 
    465     /**
    466      * Connection event used to inform {@link InCallService}s when pulling of an external call has
    467      * failed.  The user interface should inform the user of the error.
    468      * <p>
    469      * Expected to be used by the {@link ConnectionService} when the {@link Call#pullExternalCall()}
    470      * API is called on a {@link Call} with the properties
    471      * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} and
    472      * {@link Call.Details#CAPABILITY_CAN_PULL_CALL}, but the {@link ConnectionService} could not
    473      * pull the external call due to an error condition.
    474      * <p>
    475      * Sent via {@link #sendConnectionEvent(String, Bundle)}.  The {@link Bundle} parameter is
    476      * expected to be null when this connection event is used.
    477      */
    478     public static final String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
    479 
    480     /**
    481      * Connection event used to inform {@link InCallService}s when the merging of two calls has
    482      * failed. The User Interface should use this message to inform the user of the error.
    483      * <p>
    484      * Sent via {@link #sendConnectionEvent(String, Bundle)}.  The {@link Bundle} parameter is
    485      * expected to be null when this connection event is used.
    486      */
    487     public static final String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
    488 
    489     /**
    490      * Connection event used to inform {@link InCallService}s when a call has been put on hold by
    491      * the remote party.
    492      * <p>
    493      * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the
    494      * call is being held locally on the device.  When a capable {@link ConnectionService} receives
    495      * signalling to indicate that the remote party has put the call on hold, it can send this
    496      * connection event.
    497      * @hide
    498      */
    499     public static final String EVENT_CALL_REMOTELY_HELD =
    500             "android.telecom.event.CALL_REMOTELY_HELD";
    501 
    502     /**
    503      * Connection event used to inform {@link InCallService}s when a call which was remotely held
    504      * (see {@link #EVENT_CALL_REMOTELY_HELD}) has been un-held by the remote party.
    505      * <p>
    506      * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the
    507      * call is being held locally on the device.  When a capable {@link ConnectionService} receives
    508      * signalling to indicate that the remote party has taken the call off hold, it can send this
    509      * connection event.
    510      * @hide
    511      */
    512     public static final String EVENT_CALL_REMOTELY_UNHELD =
    513             "android.telecom.event.CALL_REMOTELY_UNHELD";
    514 
    515     // Flag controlling whether PII is emitted into the logs
    516     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
    517 
    518     /**
    519      * Whether the given capabilities support the specified capability.
    520      *
    521      * @param capabilities A capability bit field.
    522      * @param capability The capability to check capabilities for.
    523      * @return Whether the specified capability is supported.
    524      * @hide
    525      */
    526     public static boolean can(int capabilities, int capability) {
    527         return (capabilities & capability) == capability;
    528     }
    529 
    530     /**
    531      * Whether the capabilities of this {@code Connection} supports the specified capability.
    532      *
    533      * @param capability The capability to check capabilities for.
    534      * @return Whether the specified capability is supported.
    535      * @hide
    536      */
    537     public boolean can(int capability) {
    538         return can(mConnectionCapabilities, capability);
    539     }
    540 
    541     /**
    542      * Removes the specified capability from the set of capabilities of this {@code Connection}.
    543      *
    544      * @param capability The capability to remove from the set.
    545      * @hide
    546      */
    547     public void removeCapability(int capability) {
    548         mConnectionCapabilities &= ~capability;
    549     }
    550 
    551     /**
    552      * Adds the specified capability to the set of capabilities of this {@code Connection}.
    553      *
    554      * @param capability The capability to add to the set.
    555      * @hide
    556      */
    557     public void addCapability(int capability) {
    558         mConnectionCapabilities |= capability;
    559     }
    560 
    561     /**
    562      * Renders a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
    563      *
    564      * @param capabilities A capability bit field.
    565      * @return A human readable string representation.
    566      */
    567     public static String capabilitiesToString(int capabilities) {
    568         return capabilitiesToStringInternal(capabilities, true /* isLong */);
    569     }
    570 
    571     /**
    572      * Renders a set of capability bits ({@code CAPABILITY_*}) as a *short* human readable
    573      * string.
    574      *
    575      * @param capabilities A capability bit field.
    576      * @return A human readable string representation.
    577      * @hide
    578      */
    579     public static String capabilitiesToStringShort(int capabilities) {
    580         return capabilitiesToStringInternal(capabilities, false /* isLong */);
    581     }
    582 
    583     private static String capabilitiesToStringInternal(int capabilities, boolean isLong) {
    584         StringBuilder builder = new StringBuilder();
    585         builder.append("[");
    586         if (isLong) {
    587             builder.append("Capabilities:");
    588         }
    589 
    590         if (can(capabilities, CAPABILITY_HOLD)) {
    591             builder.append(isLong ? " CAPABILITY_HOLD" : " hld");
    592         }
    593         if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
    594             builder.append(isLong ? " CAPABILITY_SUPPORT_HOLD" : " sup_hld");
    595         }
    596         if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
    597             builder.append(isLong ? " CAPABILITY_MERGE_CONFERENCE" : " mrg_cnf");
    598         }
    599         if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
    600             builder.append(isLong ? " CAPABILITY_SWAP_CONFERENCE" : " swp_cnf");
    601         }
    602         if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
    603             builder.append(isLong ? " CAPABILITY_RESPOND_VIA_TEXT" : " txt");
    604         }
    605         if (can(capabilities, CAPABILITY_MUTE)) {
    606             builder.append(isLong ? " CAPABILITY_MUTE" : " mut");
    607         }
    608         if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
    609             builder.append(isLong ? " CAPABILITY_MANAGE_CONFERENCE" : " mng_cnf");
    610         }
    611         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
    612             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_RX" : " VTlrx");
    613         }
    614         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
    615             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_TX" : " VTltx");
    616         }
    617         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
    618             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL" : " VTlbi");
    619         }
    620         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
    621             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_RX" : " VTrrx");
    622         }
    623         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
    624             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_TX" : " VTrtx");
    625         }
    626         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
    627             builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL" : " VTrbi");
    628         }
    629         if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
    630             builder.append(isLong ? " CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO" : " !v2a");
    631         }
    632         if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
    633             builder.append(isLong ? " CAPABILITY_SPEED_UP_MT_AUDIO" : " spd_aud");
    634         }
    635         if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
    636             builder.append(isLong ? " CAPABILITY_CAN_UPGRADE_TO_VIDEO" : " a2v");
    637         }
    638         if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
    639             builder.append(isLong ? " CAPABILITY_CAN_PAUSE_VIDEO" : " paus_VT");
    640         }
    641         if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
    642             builder.append(isLong ? " CAPABILITY_SINGLE_PARTY_CONFERENCE" : " 1p_cnf");
    643         }
    644         if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
    645             builder.append(isLong ? " CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION" : " rsp_by_con");
    646         }
    647         if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
    648             builder.append(isLong ? " CAPABILITY_CAN_PULL_CALL" : " pull");
    649         }
    650 
    651         builder.append("]");
    652         return builder.toString();
    653     }
    654 
    655     /**
    656      * Renders a set of property bits ({@code PROPERTY_*}) as a human readable string.
    657      *
    658      * @param properties A property bit field.
    659      * @return A human readable string representation.
    660      */
    661     public static String propertiesToString(int properties) {
    662         return propertiesToStringInternal(properties, true /* isLong */);
    663     }
    664 
    665     /**
    666      * Renders a set of property bits ({@code PROPERTY_*}) as a *short* human readable string.
    667      *
    668      * @param properties A property bit field.
    669      * @return A human readable string representation.
    670      * @hide
    671      */
    672     public static String propertiesToStringShort(int properties) {
    673         return propertiesToStringInternal(properties, false /* isLong */);
    674     }
    675 
    676     private static String propertiesToStringInternal(int properties, boolean isLong) {
    677         StringBuilder builder = new StringBuilder();
    678         builder.append("[");
    679         if (isLong) {
    680             builder.append("Properties:");
    681         }
    682 
    683         if (can(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
    684             builder.append(isLong ? " PROPERTY_EMERGENCY_CALLBACK_MODE" : " ecbm");
    685         }
    686 
    687         if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) {
    688             builder.append(isLong ? " PROPERTY_HIGH_DEF_AUDIO" : " HD");
    689         }
    690 
    691         if (can(properties, PROPERTY_WIFI)) {
    692             builder.append(isLong ? " PROPERTY_WIFI" : " wifi");
    693         }
    694 
    695         if (can(properties, PROPERTY_GENERIC_CONFERENCE)) {
    696             builder.append(isLong ? " PROPERTY_GENERIC_CONFERENCE" : " gen_conf");
    697         }
    698 
    699         if (can(properties, PROPERTY_IS_EXTERNAL_CALL)) {
    700             builder.append(isLong ? " PROPERTY_IS_EXTERNAL_CALL" : " xtrnl");
    701         }
    702 
    703         if (can(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
    704             builder.append(isLong ? " PROPERTY_HAS_CDMA_VOICE_PRIVACY" : " priv");
    705         }
    706 
    707         builder.append("]");
    708         return builder.toString();
    709     }
    710 
    711     /** @hide */
    712     public abstract static class Listener {
    713         public void onStateChanged(Connection c, int state) {}
    714         public void onAddressChanged(Connection c, Uri newAddress, int presentation) {}
    715         public void onCallerDisplayNameChanged(
    716                 Connection c, String callerDisplayName, int presentation) {}
    717         public void onVideoStateChanged(Connection c, int videoState) {}
    718         public void onDisconnected(Connection c, DisconnectCause disconnectCause) {}
    719         public void onPostDialWait(Connection c, String remaining) {}
    720         public void onPostDialChar(Connection c, char nextChar) {}
    721         public void onRingbackRequested(Connection c, boolean ringback) {}
    722         public void onDestroyed(Connection c) {}
    723         public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {}
    724         public void onConnectionPropertiesChanged(Connection c, int properties) {}
    725         public void onVideoProviderChanged(
    726                 Connection c, VideoProvider videoProvider) {}
    727         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
    728         public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
    729         public void onConferenceablesChanged(
    730                 Connection c, List<Conferenceable> conferenceables) {}
    731         public void onConferenceChanged(Connection c, Conference conference) {}
    732         /** @hide */
    733         public void onConferenceParticipantsChanged(Connection c,
    734                 List<ConferenceParticipant> participants) {}
    735         public void onConferenceStarted() {}
    736         public void onConferenceMergeFailed(Connection c) {}
    737         public void onExtrasChanged(Connection c, Bundle extras) {}
    738         public void onExtrasRemoved(Connection c, List<String> keys) {}
    739         public void onConnectionEvent(Connection c, String event, Bundle extras) {}
    740         /** @hide */
    741         public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {}
    742     }
    743 
    744     /**
    745      * Provides a means of controlling the video session associated with a {@link Connection}.
    746      * <p>
    747      * Implementations create a custom subclass of {@link VideoProvider} and the
    748      * {@link ConnectionService} creates an instance sets it on the {@link Connection} using
    749      * {@link Connection#setVideoProvider(VideoProvider)}.  Any connection which supports video
    750      * should set the {@link VideoProvider}.
    751      * <p>
    752      * The {@link VideoProvider} serves two primary purposes: it provides a means for Telecom and
    753      * {@link InCallService} implementations to issue requests related to the video session;
    754      * it provides a means for the {@link ConnectionService} to report events and information
    755      * related to the video session to Telecom and the {@link InCallService} implementations.
    756      * <p>
    757      * {@link InCallService} implementations interact with the {@link VideoProvider} via
    758      * {@link android.telecom.InCallService.VideoCall}.
    759      */
    760     public static abstract class VideoProvider {
    761         /**
    762          * Video is not being received (no protocol pause was issued).
    763          * @see #handleCallSessionEvent(int)
    764          */
    765         public static final int SESSION_EVENT_RX_PAUSE = 1;
    766 
    767         /**
    768          * Video reception has resumed after a {@link #SESSION_EVENT_RX_PAUSE}.
    769          * @see #handleCallSessionEvent(int)
    770          */
    771         public static final int SESSION_EVENT_RX_RESUME = 2;
    772 
    773         /**
    774          * Video transmission has begun. This occurs after a negotiated start of video transmission
    775          * when the underlying protocol has actually begun transmitting video to the remote party.
    776          * @see #handleCallSessionEvent(int)
    777          */
    778         public static final int SESSION_EVENT_TX_START = 3;
    779 
    780         /**
    781          * Video transmission has stopped. This occurs after a negotiated stop of video transmission
    782          * when the underlying protocol has actually stopped transmitting video to the remote party.
    783          * @see #handleCallSessionEvent(int)
    784          */
    785         public static final int SESSION_EVENT_TX_STOP = 4;
    786 
    787         /**
    788          * A camera failure has occurred for the selected camera.  The {@link InCallService} can use
    789          * this as a cue to inform the user the camera is not available.
    790          * @see #handleCallSessionEvent(int)
    791          */
    792         public static final int SESSION_EVENT_CAMERA_FAILURE = 5;
    793 
    794         /**
    795          * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready
    796          * for operation.  The {@link InCallService} can use this as a cue to inform the user that
    797          * the camera has become available again.
    798          * @see #handleCallSessionEvent(int)
    799          */
    800         public static final int SESSION_EVENT_CAMERA_READY = 6;
    801 
    802         /**
    803          * Session modify request was successful.
    804          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
    805          */
    806         public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1;
    807 
    808         /**
    809          * Session modify request failed.
    810          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
    811          */
    812         public static final int SESSION_MODIFY_REQUEST_FAIL = 2;
    813 
    814         /**
    815          * Session modify request ignored due to invalid parameters.
    816          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
    817          */
    818         public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
    819 
    820         /**
    821          * Session modify request timed out.
    822          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
    823          */
    824         public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4;
    825 
    826         /**
    827          * Session modify request rejected by remote user.
    828          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
    829          */
    830         public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5;
    831 
    832         private static final int MSG_ADD_VIDEO_CALLBACK = 1;
    833         private static final int MSG_SET_CAMERA = 2;
    834         private static final int MSG_SET_PREVIEW_SURFACE = 3;
    835         private static final int MSG_SET_DISPLAY_SURFACE = 4;
    836         private static final int MSG_SET_DEVICE_ORIENTATION = 5;
    837         private static final int MSG_SET_ZOOM = 6;
    838         private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
    839         private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
    840         private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
    841         private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10;
    842         private static final int MSG_SET_PAUSE_IMAGE = 11;
    843         private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
    844 
    845         private static final String SESSION_EVENT_RX_PAUSE_STR = "RX_PAUSE";
    846         private static final String SESSION_EVENT_RX_RESUME_STR = "RX_RESUME";
    847         private static final String SESSION_EVENT_TX_START_STR = "TX_START";
    848         private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
    849         private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
    850         private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
    851         private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
    852 
    853         private VideoProvider.VideoProviderHandler mMessageHandler;
    854         private final VideoProvider.VideoProviderBinder mBinder;
    855 
    856         /**
    857          * Stores a list of the video callbacks, keyed by IBinder.
    858          *
    859          * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
    860          * load factor before resizing, 1 means we only expect a single thread to
    861          * access the map so make only a single shard
    862          */
    863         private ConcurrentHashMap<IBinder, IVideoCallback> mVideoCallbacks =
    864                 new ConcurrentHashMap<IBinder, IVideoCallback>(8, 0.9f, 1);
    865 
    866         /**
    867          * Default handler used to consolidate binder method calls onto a single thread.
    868          */
    869         private final class VideoProviderHandler extends Handler {
    870             public VideoProviderHandler() {
    871                 super();
    872             }
    873 
    874             public VideoProviderHandler(Looper looper) {
    875                 super(looper);
    876             }
    877 
    878             @Override
    879             public void handleMessage(Message msg) {
    880                 switch (msg.what) {
    881                     case MSG_ADD_VIDEO_CALLBACK: {
    882                         IBinder binder = (IBinder) msg.obj;
    883                         IVideoCallback callback = IVideoCallback.Stub
    884                                 .asInterface((IBinder) msg.obj);
    885                         if (callback == null) {
    886                             Log.w(this, "addVideoProvider - skipped; callback is null.");
    887                             break;
    888                         }
    889 
    890                         if (mVideoCallbacks.containsKey(binder)) {
    891                             Log.i(this, "addVideoProvider - skipped; already present.");
    892                             break;
    893                         }
    894                         mVideoCallbacks.put(binder, callback);
    895                         break;
    896                     }
    897                     case MSG_REMOVE_VIDEO_CALLBACK: {
    898                         IBinder binder = (IBinder) msg.obj;
    899                         IVideoCallback callback = IVideoCallback.Stub
    900                                 .asInterface((IBinder) msg.obj);
    901                         if (!mVideoCallbacks.containsKey(binder)) {
    902                             Log.i(this, "removeVideoProvider - skipped; not present.");
    903                             break;
    904                         }
    905                         mVideoCallbacks.remove(binder);
    906                         break;
    907                     }
    908                     case MSG_SET_CAMERA:
    909                         onSetCamera((String) msg.obj);
    910                         break;
    911                     case MSG_SET_PREVIEW_SURFACE:
    912                         onSetPreviewSurface((Surface) msg.obj);
    913                         break;
    914                     case MSG_SET_DISPLAY_SURFACE:
    915                         onSetDisplaySurface((Surface) msg.obj);
    916                         break;
    917                     case MSG_SET_DEVICE_ORIENTATION:
    918                         onSetDeviceOrientation(msg.arg1);
    919                         break;
    920                     case MSG_SET_ZOOM:
    921                         onSetZoom((Float) msg.obj);
    922                         break;
    923                     case MSG_SEND_SESSION_MODIFY_REQUEST: {
    924                         SomeArgs args = (SomeArgs) msg.obj;
    925                         try {
    926                             onSendSessionModifyRequest((VideoProfile) args.arg1,
    927                                     (VideoProfile) args.arg2);
    928                         } finally {
    929                             args.recycle();
    930                         }
    931                         break;
    932                     }
    933                     case MSG_SEND_SESSION_MODIFY_RESPONSE:
    934                         onSendSessionModifyResponse((VideoProfile) msg.obj);
    935                         break;
    936                     case MSG_REQUEST_CAMERA_CAPABILITIES:
    937                         onRequestCameraCapabilities();
    938                         break;
    939                     case MSG_REQUEST_CONNECTION_DATA_USAGE:
    940                         onRequestConnectionDataUsage();
    941                         break;
    942                     case MSG_SET_PAUSE_IMAGE:
    943                         onSetPauseImage((Uri) msg.obj);
    944                         break;
    945                     default:
    946                         break;
    947                 }
    948             }
    949         }
    950 
    951         /**
    952          * IVideoProvider stub implementation.
    953          */
    954         private final class VideoProviderBinder extends IVideoProvider.Stub {
    955             public void addVideoCallback(IBinder videoCallbackBinder) {
    956                 mMessageHandler.obtainMessage(
    957                         MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
    958             }
    959 
    960             public void removeVideoCallback(IBinder videoCallbackBinder) {
    961                 mMessageHandler.obtainMessage(
    962                         MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
    963             }
    964 
    965             public void setCamera(String cameraId) {
    966                 mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
    967             }
    968 
    969             public void setPreviewSurface(Surface surface) {
    970                 mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
    971             }
    972 
    973             public void setDisplaySurface(Surface surface) {
    974                 mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
    975             }
    976 
    977             public void setDeviceOrientation(int rotation) {
    978                 mMessageHandler.obtainMessage(
    979                         MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget();
    980             }
    981 
    982             public void setZoom(float value) {
    983                 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
    984             }
    985 
    986             public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
    987                 SomeArgs args = SomeArgs.obtain();
    988                 args.arg1 = fromProfile;
    989                 args.arg2 = toProfile;
    990                 mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
    991             }
    992 
    993             public void sendSessionModifyResponse(VideoProfile responseProfile) {
    994                 mMessageHandler.obtainMessage(
    995                         MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
    996             }
    997 
    998             public void requestCameraCapabilities() {
    999                 mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
   1000             }
   1001 
   1002             public void requestCallDataUsage() {
   1003                 mMessageHandler.obtainMessage(MSG_REQUEST_CONNECTION_DATA_USAGE).sendToTarget();
   1004             }
   1005 
   1006             public void setPauseImage(Uri uri) {
   1007                 mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
   1008             }
   1009         }
   1010 
   1011         public VideoProvider() {
   1012             mBinder = new VideoProvider.VideoProviderBinder();
   1013             mMessageHandler = new VideoProvider.VideoProviderHandler(Looper.getMainLooper());
   1014         }
   1015 
   1016         /**
   1017          * Creates an instance of the {@link VideoProvider}, specifying the looper to use.
   1018          *
   1019          * @param looper The looper.
   1020          * @hide
   1021          */
   1022         public VideoProvider(Looper looper) {
   1023             mBinder = new VideoProvider.VideoProviderBinder();
   1024             mMessageHandler = new VideoProvider.VideoProviderHandler(looper);
   1025         }
   1026 
   1027         /**
   1028          * Returns binder object which can be used across IPC methods.
   1029          * @hide
   1030          */
   1031         public final IVideoProvider getInterface() {
   1032             return mBinder;
   1033         }
   1034 
   1035         /**
   1036          * Sets the camera to be used for the outgoing video.
   1037          * <p>
   1038          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
   1039          * camera via
   1040          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
   1041          * <p>
   1042          * Sent from the {@link InCallService} via
   1043          * {@link InCallService.VideoCall#setCamera(String)}.
   1044          *
   1045          * @param cameraId The id of the camera (use ids as reported by
   1046          * {@link CameraManager#getCameraIdList()}).
   1047          */
   1048         public abstract void onSetCamera(String cameraId);
   1049 
   1050         /**
   1051          * Sets the surface to be used for displaying a preview of what the user's camera is
   1052          * currently capturing.  When video transmission is enabled, this is the video signal which
   1053          * is sent to the remote device.
   1054          * <p>
   1055          * Sent from the {@link InCallService} via
   1056          * {@link InCallService.VideoCall#setPreviewSurface(Surface)}.
   1057          *
   1058          * @param surface The {@link Surface}.
   1059          */
   1060         public abstract void onSetPreviewSurface(Surface surface);
   1061 
   1062         /**
   1063          * Sets the surface to be used for displaying the video received from the remote device.
   1064          * <p>
   1065          * Sent from the {@link InCallService} via
   1066          * {@link InCallService.VideoCall#setDisplaySurface(Surface)}.
   1067          *
   1068          * @param surface The {@link Surface}.
   1069          */
   1070         public abstract void onSetDisplaySurface(Surface surface);
   1071 
   1072         /**
   1073          * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of
   1074          * the device is 0 degrees.
   1075          * <p>
   1076          * Sent from the {@link InCallService} via
   1077          * {@link InCallService.VideoCall#setDeviceOrientation(int)}.
   1078          *
   1079          * @param rotation The device orientation, in degrees.
   1080          */
   1081         public abstract void onSetDeviceOrientation(int rotation);
   1082 
   1083         /**
   1084          * Sets camera zoom ratio.
   1085          * <p>
   1086          * Sent from the {@link InCallService} via {@link InCallService.VideoCall#setZoom(float)}.
   1087          *
   1088          * @param value The camera zoom ratio.
   1089          */
   1090         public abstract void onSetZoom(float value);
   1091 
   1092         /**
   1093          * Issues a request to modify the properties of the current video session.
   1094          * <p>
   1095          * Example scenarios include: requesting an audio-only call to be upgraded to a
   1096          * bi-directional video call, turning on or off the user's camera, sending a pause signal
   1097          * when the {@link InCallService} is no longer the foreground application.
   1098          * <p>
   1099          * If the {@link VideoProvider} determines a request to be invalid, it should call
   1100          * {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} to report the
   1101          * invalid request back to the {@link InCallService}.
   1102          * <p>
   1103          * Where a request requires confirmation from the user of the peer device, the
   1104          * {@link VideoProvider} must communicate the request to the peer device and handle the
   1105          * user's response.  {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)}
   1106          * is used to inform the {@link InCallService} of the result of the request.
   1107          * <p>
   1108          * Sent from the {@link InCallService} via
   1109          * {@link InCallService.VideoCall#sendSessionModifyRequest(VideoProfile)}.
   1110          *
   1111          * @param fromProfile The video profile prior to the request.
   1112          * @param toProfile The video profile with the requested changes made.
   1113          */
   1114         public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
   1115                 VideoProfile toProfile);
   1116 
   1117         /**
   1118          * Provides a response to a request to change the current video session properties.
   1119          * <p>
   1120          * For example, if the peer requests and upgrade from an audio-only call to a bi-directional
   1121          * video call, could decline the request and keep the call as audio-only.
   1122          * In such a scenario, the {@code responseProfile} would have a video state of
   1123          * {@link VideoProfile#STATE_AUDIO_ONLY}.  If the user had decided to accept the request,
   1124          * the video state would be {@link VideoProfile#STATE_BIDIRECTIONAL}.
   1125          * <p>
   1126          * Sent from the {@link InCallService} via
   1127          * {@link InCallService.VideoCall#sendSessionModifyResponse(VideoProfile)} in response to
   1128          * a {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)}
   1129          * callback.
   1130          *
   1131          * @param responseProfile The response video profile.
   1132          */
   1133         public abstract void onSendSessionModifyResponse(VideoProfile responseProfile);
   1134 
   1135         /**
   1136          * Issues a request to the {@link VideoProvider} to retrieve the camera capabilities.
   1137          * <p>
   1138          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
   1139          * camera via
   1140          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
   1141          * <p>
   1142          * Sent from the {@link InCallService} via
   1143          * {@link InCallService.VideoCall#requestCameraCapabilities()}.
   1144          */
   1145         public abstract void onRequestCameraCapabilities();
   1146 
   1147         /**
   1148          * Issues a request to the {@link VideoProvider} to retrieve the current data usage for the
   1149          * video component of the current {@link Connection}.
   1150          * <p>
   1151          * The {@link VideoProvider} should respond by communicating current data usage, in bytes,
   1152          * via {@link VideoProvider#setCallDataUsage(long)}.
   1153          * <p>
   1154          * Sent from the {@link InCallService} via
   1155          * {@link InCallService.VideoCall#requestCallDataUsage()}.
   1156          */
   1157         public abstract void onRequestConnectionDataUsage();
   1158 
   1159         /**
   1160          * Provides the {@link VideoProvider} with the {@link Uri} of an image to be displayed to
   1161          * the peer device when the video signal is paused.
   1162          * <p>
   1163          * Sent from the {@link InCallService} via
   1164          * {@link InCallService.VideoCall#setPauseImage(Uri)}.
   1165          *
   1166          * @param uri URI of image to display.
   1167          */
   1168         public abstract void onSetPauseImage(Uri uri);
   1169 
   1170         /**
   1171          * Used to inform listening {@link InCallService} implementations when the
   1172          * {@link VideoProvider} receives a session modification request.
   1173          * <p>
   1174          * Received by the {@link InCallService} via
   1175          * {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)},
   1176          *
   1177          * @param videoProfile The requested video profile.
   1178          * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)
   1179          */
   1180         public void receiveSessionModifyRequest(VideoProfile videoProfile) {
   1181             if (mVideoCallbacks != null) {
   1182                 for (IVideoCallback callback : mVideoCallbacks.values()) {
   1183                     try {
   1184                         callback.receiveSessionModifyRequest(videoProfile);
   1185                     } catch (RemoteException ignored) {
   1186                         Log.w(this, "receiveSessionModifyRequest callback failed", ignored);
   1187                     }
   1188                 }
   1189             }
   1190         }
   1191 
   1192         /**
   1193          * Used to inform listening {@link InCallService} implementations when the
   1194          * {@link VideoProvider} receives a response to a session modification request.
   1195          * <p>
   1196          * Received by the {@link InCallService} via
   1197          * {@link InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int,
   1198          * VideoProfile, VideoProfile)}.
   1199          *
   1200          * @param status Status of the session modify request.  Valid values are
   1201          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS},
   1202          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_FAIL},
   1203          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_INVALID},
   1204          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_TIMED_OUT},
   1205          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE}
   1206          * @param requestedProfile The original request which was sent to the peer device.
   1207          * @param responseProfile The actual profile changes agreed to by the peer device.
   1208          * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)
   1209          */
   1210         public void receiveSessionModifyResponse(int status,
   1211                 VideoProfile requestedProfile, VideoProfile responseProfile) {
   1212             if (mVideoCallbacks != null) {
   1213                 for (IVideoCallback callback : mVideoCallbacks.values()) {
   1214                     try {
   1215                         callback.receiveSessionModifyResponse(status, requestedProfile,
   1216                                 responseProfile);
   1217                     } catch (RemoteException ignored) {
   1218                         Log.w(this, "receiveSessionModifyResponse callback failed", ignored);
   1219                     }
   1220                 }
   1221             }
   1222         }
   1223 
   1224         /**
   1225          * Used to inform listening {@link InCallService} implementations when the
   1226          * {@link VideoProvider} reports a call session event.
   1227          * <p>
   1228          * Received by the {@link InCallService} via
   1229          * {@link InCallService.VideoCall.Callback#onCallSessionEvent(int)}.
   1230          *
   1231          * @param event The event.  Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE},
   1232          *      {@link VideoProvider#SESSION_EVENT_RX_RESUME},
   1233          *      {@link VideoProvider#SESSION_EVENT_TX_START},
   1234          *      {@link VideoProvider#SESSION_EVENT_TX_STOP},
   1235          *      {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
   1236          *      {@link VideoProvider#SESSION_EVENT_CAMERA_READY}.
   1237          */
   1238         public void handleCallSessionEvent(int event) {
   1239             if (mVideoCallbacks != null) {
   1240                 for (IVideoCallback callback : mVideoCallbacks.values()) {
   1241                     try {
   1242                         callback.handleCallSessionEvent(event);
   1243                     } catch (RemoteException ignored) {
   1244                         Log.w(this, "handleCallSessionEvent callback failed", ignored);
   1245                     }
   1246                 }
   1247             }
   1248         }
   1249 
   1250         /**
   1251          * Used to inform listening {@link InCallService} implementations when the dimensions of the
   1252          * peer's video have changed.
   1253          * <p>
   1254          * This could occur if, for example, the peer rotates their device, changing the aspect
   1255          * ratio of the video, or if the user switches between the back and front cameras.
   1256          * <p>
   1257          * Received by the {@link InCallService} via
   1258          * {@link InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int)}.
   1259          *
   1260          * @param width  The updated peer video width.
   1261          * @param height The updated peer video height.
   1262          */
   1263         public void changePeerDimensions(int width, int height) {
   1264             if (mVideoCallbacks != null) {
   1265                 for (IVideoCallback callback : mVideoCallbacks.values()) {
   1266                     try {
   1267                         callback.changePeerDimensions(width, height);
   1268                     } catch (RemoteException ignored) {
   1269                         Log.w(this, "changePeerDimensions callback failed", ignored);
   1270                     }
   1271                 }
   1272             }
   1273         }
   1274 
   1275         /**
   1276          * Used to inform listening {@link InCallService} implementations when the data usage of the
   1277          * video associated with the current {@link Connection} has changed.
   1278          * <p>
   1279          * This could be in response to a preview request via
   1280          * {@link #onRequestConnectionDataUsage()}, or as a periodic update by the
   1281          * {@link VideoProvider}.  Where periodic updates of data usage are provided, they should be
   1282          * provided at most for every 1 MB of data transferred and no more than once every 10 sec.
   1283          * <p>
   1284          * Received by the {@link InCallService} via
   1285          * {@link InCallService.VideoCall.Callback#onCallDataUsageChanged(long)}.
   1286          *
   1287          * @param dataUsage The updated data usage (in bytes).  Reported as the cumulative bytes
   1288          *                  used since the start of the call.
   1289          */
   1290         public void setCallDataUsage(long dataUsage) {
   1291             if (mVideoCallbacks != null) {
   1292                 for (IVideoCallback callback : mVideoCallbacks.values()) {
   1293                     try {
   1294                         callback.changeCallDataUsage(dataUsage);
   1295                     } catch (RemoteException ignored) {
   1296                         Log.w(this, "setCallDataUsage callback failed", ignored);
   1297                     }
   1298                 }
   1299             }
   1300         }
   1301 
   1302         /**
   1303          * @see #setCallDataUsage(long)
   1304          *
   1305          * @param dataUsage The updated data usage (in byes).
   1306          * @deprecated - Use {@link #setCallDataUsage(long)} instead.
   1307          * @hide
   1308          */
   1309         public void changeCallDataUsage(long dataUsage) {
   1310             setCallDataUsage(dataUsage);
   1311         }
   1312 
   1313         /**
   1314          * Used to inform listening {@link InCallService} implementations when the capabilities of
   1315          * the current camera have changed.
   1316          * <p>
   1317          * The {@link VideoProvider} should call this in response to
   1318          * {@link VideoProvider#onRequestCameraCapabilities()}, or when the current camera is
   1319          * changed via {@link VideoProvider#onSetCamera(String)}.
   1320          * <p>
   1321          * Received by the {@link InCallService} via
   1322          * {@link InCallService.VideoCall.Callback#onCameraCapabilitiesChanged(
   1323          * VideoProfile.CameraCapabilities)}.
   1324          *
   1325          * @param cameraCapabilities The new camera capabilities.
   1326          */
   1327         public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
   1328             if (mVideoCallbacks != null) {
   1329                 for (IVideoCallback callback : mVideoCallbacks.values()) {
   1330                     try {
   1331                         callback.changeCameraCapabilities(cameraCapabilities);
   1332                     } catch (RemoteException ignored) {
   1333                         Log.w(this, "changeCameraCapabilities callback failed", ignored);
   1334                     }
   1335                 }
   1336             }
   1337         }
   1338 
   1339         /**
   1340          * Used to inform listening {@link InCallService} implementations when the video quality
   1341          * of the call has changed.
   1342          * <p>
   1343          * Received by the {@link InCallService} via
   1344          * {@link InCallService.VideoCall.Callback#onVideoQualityChanged(int)}.
   1345          *
   1346          * @param videoQuality The updated video quality.  Valid values:
   1347          *      {@link VideoProfile#QUALITY_HIGH},
   1348          *      {@link VideoProfile#QUALITY_MEDIUM},
   1349          *      {@link VideoProfile#QUALITY_LOW},
   1350          *      {@link VideoProfile#QUALITY_DEFAULT}.
   1351          */
   1352         public void changeVideoQuality(int videoQuality) {
   1353             if (mVideoCallbacks != null) {
   1354                 for (IVideoCallback callback : mVideoCallbacks.values()) {
   1355                     try {
   1356                         callback.changeVideoQuality(videoQuality);
   1357                     } catch (RemoteException ignored) {
   1358                         Log.w(this, "changeVideoQuality callback failed", ignored);
   1359                     }
   1360                 }
   1361             }
   1362         }
   1363 
   1364         /**
   1365          * Returns a string representation of a call session event.
   1366          *
   1367          * @param event A call session event passed to {@link #handleCallSessionEvent(int)}.
   1368          * @return String representation of the call session event.
   1369          * @hide
   1370          */
   1371         public static String sessionEventToString(int event) {
   1372             switch (event) {
   1373                 case SESSION_EVENT_CAMERA_FAILURE:
   1374                     return SESSION_EVENT_CAMERA_FAILURE_STR;
   1375                 case SESSION_EVENT_CAMERA_READY:
   1376                     return SESSION_EVENT_CAMERA_READY_STR;
   1377                 case SESSION_EVENT_RX_PAUSE:
   1378                     return SESSION_EVENT_RX_PAUSE_STR;
   1379                 case SESSION_EVENT_RX_RESUME:
   1380                     return SESSION_EVENT_RX_RESUME_STR;
   1381                 case SESSION_EVENT_TX_START:
   1382                     return SESSION_EVENT_TX_START_STR;
   1383                 case SESSION_EVENT_TX_STOP:
   1384                     return SESSION_EVENT_TX_STOP_STR;
   1385                 default:
   1386                     return SESSION_EVENT_UNKNOWN_STR + " " + event;
   1387             }
   1388         }
   1389     }
   1390 
   1391     private final Listener mConnectionDeathListener = new Listener() {
   1392         @Override
   1393         public void onDestroyed(Connection c) {
   1394             if (mConferenceables.remove(c)) {
   1395                 fireOnConferenceableConnectionsChanged();
   1396             }
   1397         }
   1398     };
   1399 
   1400     private final Conference.Listener mConferenceDeathListener = new Conference.Listener() {
   1401         @Override
   1402         public void onDestroyed(Conference c) {
   1403             if (mConferenceables.remove(c)) {
   1404                 fireOnConferenceableConnectionsChanged();
   1405             }
   1406         }
   1407     };
   1408 
   1409     /**
   1410      * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
   1411      * load factor before resizing, 1 means we only expect a single thread to
   1412      * access the map so make only a single shard
   1413      */
   1414     private final Set<Listener> mListeners = Collections.newSetFromMap(
   1415             new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
   1416     private final List<Conferenceable> mConferenceables = new ArrayList<>();
   1417     private final List<Conferenceable> mUnmodifiableConferenceables =
   1418             Collections.unmodifiableList(mConferenceables);
   1419 
   1420     // The internal telecom call ID associated with this connection.
   1421     private String mTelecomCallId;
   1422     private int mState = STATE_NEW;
   1423     private CallAudioState mCallAudioState;
   1424     private Uri mAddress;
   1425     private int mAddressPresentation;
   1426     private String mCallerDisplayName;
   1427     private int mCallerDisplayNamePresentation;
   1428     private boolean mRingbackRequested = false;
   1429     private int mConnectionCapabilities;
   1430     private int mConnectionProperties;
   1431     private VideoProvider mVideoProvider;
   1432     private boolean mAudioModeIsVoip;
   1433     private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
   1434     private StatusHints mStatusHints;
   1435     private int mVideoState;
   1436     private DisconnectCause mDisconnectCause;
   1437     private Conference mConference;
   1438     private ConnectionService mConnectionService;
   1439     private Bundle mExtras;
   1440     private final Object mExtrasLock = new Object();
   1441 
   1442     /**
   1443      * Tracks the key set for the extras bundle provided on the last invocation of
   1444      * {@link #setExtras(Bundle)}.  Used so that on subsequent invocations we can remove any extras
   1445      * keys which were set previously but are no longer present in the replacement Bundle.
   1446      */
   1447     private Set<String> mPreviousExtraKeys;
   1448 
   1449     /**
   1450      * Create a new Connection.
   1451      */
   1452     public Connection() {}
   1453 
   1454     /**
   1455      * Returns the Telecom internal call ID associated with this connection.  Should only be used
   1456      * for debugging and tracing purposes.
   1457      *
   1458      * @return The Telecom call ID.
   1459      * @hide
   1460      */
   1461     public final String getTelecomCallId() {
   1462         return mTelecomCallId;
   1463     }
   1464 
   1465     /**
   1466      * @return The address (e.g., phone number) to which this Connection is currently communicating.
   1467      */
   1468     public final Uri getAddress() {
   1469         return mAddress;
   1470     }
   1471 
   1472     /**
   1473      * @return The presentation requirements for the address.
   1474      *         See {@link TelecomManager} for valid values.
   1475      */
   1476     public final int getAddressPresentation() {
   1477         return mAddressPresentation;
   1478     }
   1479 
   1480     /**
   1481      * @return The caller display name (CNAP).
   1482      */
   1483     public final String getCallerDisplayName() {
   1484         return mCallerDisplayName;
   1485     }
   1486 
   1487     /**
   1488      * @return The presentation requirements for the handle.
   1489      *         See {@link TelecomManager} for valid values.
   1490      */
   1491     public final int getCallerDisplayNamePresentation() {
   1492         return mCallerDisplayNamePresentation;
   1493     }
   1494 
   1495     /**
   1496      * @return The state of this Connection.
   1497      */
   1498     public final int getState() {
   1499         return mState;
   1500     }
   1501 
   1502     /**
   1503      * Returns the video state of the connection.
   1504      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
   1505      * {@link VideoProfile#STATE_BIDIRECTIONAL},
   1506      * {@link VideoProfile#STATE_TX_ENABLED},
   1507      * {@link VideoProfile#STATE_RX_ENABLED}.
   1508      *
   1509      * @return The video state of the connection.
   1510      * @hide
   1511      */
   1512     public final int getVideoState() {
   1513         return mVideoState;
   1514     }
   1515 
   1516     /**
   1517      * @return The audio state of the connection, describing how its audio is currently
   1518      *         being routed by the system. This is {@code null} if this Connection
   1519      *         does not directly know about its audio state.
   1520      * @deprecated Use {@link #getCallAudioState()} instead.
   1521      * @hide
   1522      */
   1523     @SystemApi
   1524     @Deprecated
   1525     public final AudioState getAudioState() {
   1526         if (mCallAudioState == null) {
   1527           return null;
   1528         }
   1529         return new AudioState(mCallAudioState);
   1530     }
   1531 
   1532     /**
   1533      * @return The audio state of the connection, describing how its audio is currently
   1534      *         being routed by the system. This is {@code null} if this Connection
   1535      *         does not directly know about its audio state.
   1536      */
   1537     public final CallAudioState getCallAudioState() {
   1538         return mCallAudioState;
   1539     }
   1540 
   1541     /**
   1542      * @return The conference that this connection is a part of.  Null if it is not part of any
   1543      *         conference.
   1544      */
   1545     public final Conference getConference() {
   1546         return mConference;
   1547     }
   1548 
   1549     /**
   1550      * Returns whether this connection is requesting that the system play a ringback tone
   1551      * on its behalf.
   1552      */
   1553     public final boolean isRingbackRequested() {
   1554         return mRingbackRequested;
   1555     }
   1556 
   1557     /**
   1558      * @return True if the connection's audio mode is VOIP.
   1559      */
   1560     public final boolean getAudioModeIsVoip() {
   1561         return mAudioModeIsVoip;
   1562     }
   1563 
   1564     /**
   1565      * Retrieves the connection start time of the {@code Connnection}, if specified.  A value of
   1566      * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the
   1567      * start time of the conference.
   1568      *
   1569      * @return The time at which the {@code Connnection} was connected.
   1570      *
   1571      * @hide
   1572      */
   1573     public final long getConnectTimeMillis() {
   1574         return mConnectTimeMillis;
   1575     }
   1576 
   1577     /**
   1578      * @return The status hints for this connection.
   1579      */
   1580     public final StatusHints getStatusHints() {
   1581         return mStatusHints;
   1582     }
   1583 
   1584     /**
   1585      * Returns the extras associated with this connection.
   1586      * <p>
   1587      * Extras should be updated using {@link #putExtras(Bundle)}.
   1588      * <p>
   1589      * Telecom or an {@link InCallService} can also update the extras via
   1590      * {@link android.telecom.Call#putExtras(Bundle)}, and
   1591      * {@link Call#removeExtras(List)}.
   1592      * <p>
   1593      * The connection is notified of changes to the extras made by Telecom or an
   1594      * {@link InCallService} by {@link #onExtrasChanged(Bundle)}.
   1595      *
   1596      * @return The extras associated with this connection.
   1597      */
   1598     public final Bundle getExtras() {
   1599         Bundle extras = null;
   1600         synchronized (mExtrasLock) {
   1601             if (mExtras != null) {
   1602                 extras = new Bundle(mExtras);
   1603             }
   1604         }
   1605         return extras;
   1606     }
   1607 
   1608     /**
   1609      * Assign a listener to be notified of state changes.
   1610      *
   1611      * @param l A listener.
   1612      * @return This Connection.
   1613      *
   1614      * @hide
   1615      */
   1616     public final Connection addConnectionListener(Listener l) {
   1617         mListeners.add(l);
   1618         return this;
   1619     }
   1620 
   1621     /**
   1622      * Remove a previously assigned listener that was being notified of state changes.
   1623      *
   1624      * @param l A Listener.
   1625      * @return This Connection.
   1626      *
   1627      * @hide
   1628      */
   1629     public final Connection removeConnectionListener(Listener l) {
   1630         if (l != null) {
   1631             mListeners.remove(l);
   1632         }
   1633         return this;
   1634     }
   1635 
   1636     /**
   1637      * @return The {@link DisconnectCause} for this connection.
   1638      */
   1639     public final DisconnectCause getDisconnectCause() {
   1640         return mDisconnectCause;
   1641     }
   1642 
   1643     /**
   1644      * Sets the telecom call ID associated with this Connection.  The Telecom Call ID should be used
   1645      * ONLY for debugging purposes.
   1646      *
   1647      * @param callId The telecom call ID.
   1648      * @hide
   1649      */
   1650     public void setTelecomCallId(String callId) {
   1651         mTelecomCallId = callId;
   1652     }
   1653 
   1654     /**
   1655      * Inform this Connection that the state of its audio output has been changed externally.
   1656      *
   1657      * @param state The new audio state.
   1658      * @hide
   1659      */
   1660     final void setCallAudioState(CallAudioState state) {
   1661         checkImmutable();
   1662         Log.d(this, "setAudioState %s", state);
   1663         mCallAudioState = state;
   1664         onAudioStateChanged(getAudioState());
   1665         onCallAudioStateChanged(state);
   1666     }
   1667 
   1668     /**
   1669      * @param state An integer value of a {@code STATE_*} constant.
   1670      * @return A string representation of the value.
   1671      */
   1672     public static String stateToString(int state) {
   1673         switch (state) {
   1674             case STATE_INITIALIZING:
   1675                 return "INITIALIZING";
   1676             case STATE_NEW:
   1677                 return "NEW";
   1678             case STATE_RINGING:
   1679                 return "RINGING";
   1680             case STATE_DIALING:
   1681                 return "DIALING";
   1682             case STATE_PULLING_CALL:
   1683                 return "PULLING_CALL";
   1684             case STATE_ACTIVE:
   1685                 return "ACTIVE";
   1686             case STATE_HOLDING:
   1687                 return "HOLDING";
   1688             case STATE_DISCONNECTED:
   1689                 return "DISCONNECTED";
   1690             default:
   1691                 Log.wtf(Connection.class, "Unknown state %d", state);
   1692                 return "UNKNOWN";
   1693         }
   1694     }
   1695 
   1696     /**
   1697      * Returns the connection's capabilities, as a bit mask of the {@code CAPABILITY_*} constants.
   1698      */
   1699     public final int getConnectionCapabilities() {
   1700         return mConnectionCapabilities;
   1701     }
   1702 
   1703     /**
   1704      * Returns the connection's properties, as a bit mask of the {@code PROPERTY_*} constants.
   1705      */
   1706     public final int getConnectionProperties() {
   1707         return mConnectionProperties;
   1708     }
   1709 
   1710     /**
   1711      * Sets the value of the {@link #getAddress()} property.
   1712      *
   1713      * @param address The new address.
   1714      * @param presentation The presentation requirements for the address.
   1715      *        See {@link TelecomManager} for valid values.
   1716      */
   1717     public final void setAddress(Uri address, int presentation) {
   1718         checkImmutable();
   1719         Log.d(this, "setAddress %s", address);
   1720         mAddress = address;
   1721         mAddressPresentation = presentation;
   1722         for (Listener l : mListeners) {
   1723             l.onAddressChanged(this, address, presentation);
   1724         }
   1725     }
   1726 
   1727     /**
   1728      * Sets the caller display name (CNAP).
   1729      *
   1730      * @param callerDisplayName The new display name.
   1731      * @param presentation The presentation requirements for the handle.
   1732      *        See {@link TelecomManager} for valid values.
   1733      */
   1734     public final void setCallerDisplayName(String callerDisplayName, int presentation) {
   1735         checkImmutable();
   1736         Log.d(this, "setCallerDisplayName %s", callerDisplayName);
   1737         mCallerDisplayName = callerDisplayName;
   1738         mCallerDisplayNamePresentation = presentation;
   1739         for (Listener l : mListeners) {
   1740             l.onCallerDisplayNameChanged(this, callerDisplayName, presentation);
   1741         }
   1742     }
   1743 
   1744     /**
   1745      * Set the video state for the connection.
   1746      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
   1747      * {@link VideoProfile#STATE_BIDIRECTIONAL},
   1748      * {@link VideoProfile#STATE_TX_ENABLED},
   1749      * {@link VideoProfile#STATE_RX_ENABLED}.
   1750      *
   1751      * @param videoState The new video state.
   1752      */
   1753     public final void setVideoState(int videoState) {
   1754         checkImmutable();
   1755         Log.d(this, "setVideoState %d", videoState);
   1756         mVideoState = videoState;
   1757         for (Listener l : mListeners) {
   1758             l.onVideoStateChanged(this, mVideoState);
   1759         }
   1760     }
   1761 
   1762     /**
   1763      * Sets state to active (e.g., an ongoing connection where two or more parties can actively
   1764      * communicate).
   1765      */
   1766     public final void setActive() {
   1767         checkImmutable();
   1768         setRingbackRequested(false);
   1769         setState(STATE_ACTIVE);
   1770     }
   1771 
   1772     /**
   1773      * Sets state to ringing (e.g., an inbound ringing connection).
   1774      */
   1775     public final void setRinging() {
   1776         checkImmutable();
   1777         setState(STATE_RINGING);
   1778     }
   1779 
   1780     /**
   1781      * Sets state to initializing (this Connection is not yet ready to be used).
   1782      */
   1783     public final void setInitializing() {
   1784         checkImmutable();
   1785         setState(STATE_INITIALIZING);
   1786     }
   1787 
   1788     /**
   1789      * Sets state to initialized (the Connection has been set up and is now ready to be used).
   1790      */
   1791     public final void setInitialized() {
   1792         checkImmutable();
   1793         setState(STATE_NEW);
   1794     }
   1795 
   1796     /**
   1797      * Sets state to dialing (e.g., dialing an outbound connection).
   1798      */
   1799     public final void setDialing() {
   1800         checkImmutable();
   1801         setState(STATE_DIALING);
   1802     }
   1803 
   1804     /**
   1805      * Sets state to pulling (e.g. the connection is being pulled to the local device from another
   1806      * device).  Only applicable for {@link Connection}s with
   1807      * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} and {@link Connection#CAPABILITY_CAN_PULL_CALL}.
   1808      */
   1809     public final void setPulling() {
   1810         checkImmutable();
   1811         setState(STATE_PULLING_CALL);
   1812     }
   1813 
   1814     /**
   1815      * Sets state to be on hold.
   1816      */
   1817     public final void setOnHold() {
   1818         checkImmutable();
   1819         setState(STATE_HOLDING);
   1820     }
   1821 
   1822     /**
   1823      * Sets the video connection provider.
   1824      * @param videoProvider The video provider.
   1825      */
   1826     public final void setVideoProvider(VideoProvider videoProvider) {
   1827         checkImmutable();
   1828         mVideoProvider = videoProvider;
   1829         for (Listener l : mListeners) {
   1830             l.onVideoProviderChanged(this, videoProvider);
   1831         }
   1832     }
   1833 
   1834     public final VideoProvider getVideoProvider() {
   1835         return mVideoProvider;
   1836     }
   1837 
   1838     /**
   1839      * Sets state to disconnected.
   1840      *
   1841      * @param disconnectCause The reason for the disconnection, as specified by
   1842      *         {@link DisconnectCause}.
   1843      */
   1844     public final void setDisconnected(DisconnectCause disconnectCause) {
   1845         checkImmutable();
   1846         mDisconnectCause = disconnectCause;
   1847         setState(STATE_DISCONNECTED);
   1848         Log.d(this, "Disconnected with cause %s", disconnectCause);
   1849         for (Listener l : mListeners) {
   1850             l.onDisconnected(this, disconnectCause);
   1851         }
   1852     }
   1853 
   1854     /**
   1855      * Informs listeners that this {@code Connection} is in a post-dial wait state. This is done
   1856      * when (a) the {@code Connection} is issuing a DTMF sequence; (b) it has encountered a "wait"
   1857      * character; and (c) it wishes to inform the In-Call app that it is waiting for the end-user
   1858      * to send an {@link #onPostDialContinue(boolean)} signal.
   1859      *
   1860      * @param remaining The DTMF character sequence remaining to be emitted once the
   1861      *         {@link #onPostDialContinue(boolean)} is received, including any "wait" characters
   1862      *         that remaining sequence may contain.
   1863      */
   1864     public final void setPostDialWait(String remaining) {
   1865         checkImmutable();
   1866         for (Listener l : mListeners) {
   1867             l.onPostDialWait(this, remaining);
   1868         }
   1869     }
   1870 
   1871     /**
   1872      * Informs listeners that this {@code Connection} has processed a character in the post-dial
   1873      * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence;
   1874      * and (b) it wishes to signal Telecom to play the corresponding DTMF tone locally.
   1875      *
   1876      * @param nextChar The DTMF character that was just processed by the {@code Connection}.
   1877      */
   1878     public final void setNextPostDialChar(char nextChar) {
   1879         checkImmutable();
   1880         for (Listener l : mListeners) {
   1881             l.onPostDialChar(this, nextChar);
   1882         }
   1883     }
   1884 
   1885     /**
   1886      * Requests that the framework play a ringback tone. This is to be invoked by implementations
   1887      * that do not play a ringback tone themselves in the connection's audio stream.
   1888      *
   1889      * @param ringback Whether the ringback tone is to be played.
   1890      */
   1891     public final void setRingbackRequested(boolean ringback) {
   1892         checkImmutable();
   1893         if (mRingbackRequested != ringback) {
   1894             mRingbackRequested = ringback;
   1895             for (Listener l : mListeners) {
   1896                 l.onRingbackRequested(this, ringback);
   1897             }
   1898         }
   1899     }
   1900 
   1901     /**
   1902      * Sets the connection's capabilities as a bit mask of the {@code CAPABILITY_*} constants.
   1903      *
   1904      * @param connectionCapabilities The new connection capabilities.
   1905      */
   1906     public final void setConnectionCapabilities(int connectionCapabilities) {
   1907         checkImmutable();
   1908         if (mConnectionCapabilities != connectionCapabilities) {
   1909             mConnectionCapabilities = connectionCapabilities;
   1910             for (Listener l : mListeners) {
   1911                 l.onConnectionCapabilitiesChanged(this, mConnectionCapabilities);
   1912             }
   1913         }
   1914     }
   1915 
   1916     /**
   1917      * Sets the connection's properties as a bit mask of the {@code PROPERTY_*} constants.
   1918      *
   1919      * @param connectionProperties The new connection properties.
   1920      */
   1921     public final void setConnectionProperties(int connectionProperties) {
   1922         checkImmutable();
   1923         if (mConnectionProperties != connectionProperties) {
   1924             mConnectionProperties = connectionProperties;
   1925             for (Listener l : mListeners) {
   1926                 l.onConnectionPropertiesChanged(this, mConnectionProperties);
   1927             }
   1928         }
   1929     }
   1930 
   1931     /**
   1932      * Tears down the Connection object.
   1933      */
   1934     public final void destroy() {
   1935         for (Listener l : mListeners) {
   1936             l.onDestroyed(this);
   1937         }
   1938     }
   1939 
   1940     /**
   1941      * Requests that the framework use VOIP audio mode for this connection.
   1942      *
   1943      * @param isVoip True if the audio mode is VOIP.
   1944      */
   1945     public final void setAudioModeIsVoip(boolean isVoip) {
   1946         checkImmutable();
   1947         mAudioModeIsVoip = isVoip;
   1948         for (Listener l : mListeners) {
   1949             l.onAudioModeIsVoipChanged(this, isVoip);
   1950         }
   1951     }
   1952 
   1953     /**
   1954      * Sets the time at which a call became active on this Connection. This is set only
   1955      * when a conference call becomes active on this connection.
   1956      *
   1957      * @param connectionTimeMillis The connection time, in milliseconds.
   1958      *
   1959      * @hide
   1960      */
   1961     public final void setConnectTimeMillis(long connectTimeMillis) {
   1962         mConnectTimeMillis = connectTimeMillis;
   1963     }
   1964 
   1965     /**
   1966      * Sets the label and icon status to display in the in-call UI.
   1967      *
   1968      * @param statusHints The status label and icon to set.
   1969      */
   1970     public final void setStatusHints(StatusHints statusHints) {
   1971         checkImmutable();
   1972         mStatusHints = statusHints;
   1973         for (Listener l : mListeners) {
   1974             l.onStatusHintsChanged(this, statusHints);
   1975         }
   1976     }
   1977 
   1978     /**
   1979      * Sets the connections with which this connection can be conferenced.
   1980      *
   1981      * @param conferenceableConnections The set of connections this connection can conference with.
   1982      */
   1983     public final void setConferenceableConnections(List<Connection> conferenceableConnections) {
   1984         checkImmutable();
   1985         clearConferenceableList();
   1986         for (Connection c : conferenceableConnections) {
   1987             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
   1988             // small amount of items here.
   1989             if (!mConferenceables.contains(c)) {
   1990                 c.addConnectionListener(mConnectionDeathListener);
   1991                 mConferenceables.add(c);
   1992             }
   1993         }
   1994         fireOnConferenceableConnectionsChanged();
   1995     }
   1996 
   1997     /**
   1998      * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections
   1999      * or conferences with which this connection can be conferenced.
   2000      *
   2001      * @param conferenceables The conferenceables.
   2002      */
   2003     public final void setConferenceables(List<Conferenceable> conferenceables) {
   2004         clearConferenceableList();
   2005         for (Conferenceable c : conferenceables) {
   2006             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
   2007             // small amount of items here.
   2008             if (!mConferenceables.contains(c)) {
   2009                 if (c instanceof Connection) {
   2010                     Connection connection = (Connection) c;
   2011                     connection.addConnectionListener(mConnectionDeathListener);
   2012                 } else if (c instanceof Conference) {
   2013                     Conference conference = (Conference) c;
   2014                     conference.addListener(mConferenceDeathListener);
   2015                 }
   2016                 mConferenceables.add(c);
   2017             }
   2018         }
   2019         fireOnConferenceableConnectionsChanged();
   2020     }
   2021 
   2022     /**
   2023      * Returns the connections or conferences with which this connection can be conferenced.
   2024      */
   2025     public final List<Conferenceable> getConferenceables() {
   2026         return mUnmodifiableConferenceables;
   2027     }
   2028 
   2029     /**
   2030      * @hide
   2031      */
   2032     public final void setConnectionService(ConnectionService connectionService) {
   2033         checkImmutable();
   2034         if (mConnectionService != null) {
   2035             Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " +
   2036                     "which is already associated with another ConnectionService.");
   2037         } else {
   2038             mConnectionService = connectionService;
   2039         }
   2040     }
   2041 
   2042     /**
   2043      * @hide
   2044      */
   2045     public final void unsetConnectionService(ConnectionService connectionService) {
   2046         if (mConnectionService != connectionService) {
   2047             Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " +
   2048                     "that does not belong to the ConnectionService.");
   2049         } else {
   2050             mConnectionService = null;
   2051         }
   2052     }
   2053 
   2054     /**
   2055      * @hide
   2056      */
   2057     public final ConnectionService getConnectionService() {
   2058         return mConnectionService;
   2059     }
   2060 
   2061     /**
   2062      * Sets the conference that this connection is a part of. This will fail if the connection is
   2063      * already part of a conference. {@link #resetConference} to un-set the conference first.
   2064      *
   2065      * @param conference The conference.
   2066      * @return {@code true} if the conference was successfully set.
   2067      * @hide
   2068      */
   2069     public final boolean setConference(Conference conference) {
   2070         checkImmutable();
   2071         // We check to see if it is already part of another conference.
   2072         if (mConference == null) {
   2073             mConference = conference;
   2074             if (mConnectionService != null && mConnectionService.containsConference(conference)) {
   2075                 fireConferenceChanged();
   2076             }
   2077             return true;
   2078         }
   2079         return false;
   2080     }
   2081 
   2082     /**
   2083      * Resets the conference that this connection is a part of.
   2084      * @hide
   2085      */
   2086     public final void resetConference() {
   2087         if (mConference != null) {
   2088             Log.d(this, "Conference reset");
   2089             mConference = null;
   2090             fireConferenceChanged();
   2091         }
   2092     }
   2093 
   2094     /**
   2095      * Set some extras that can be associated with this {@code Connection}.
   2096      * <p>
   2097      * New or existing keys are replaced in the {@code Connection} extras.  Keys which are no longer
   2098      * in the new extras, but were present the last time {@code setExtras} was called are removed.
   2099      * <p>
   2100      * Alternatively you may use the {@link #putExtras(Bundle)}, and
   2101      * {@link #removeExtras(String...)} methods to modify the extras.
   2102      * <p>
   2103      * No assumptions should be made as to how an In-Call UI or service will handle these extras.
   2104      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
   2105      *
   2106      * @param extras The extras associated with this {@code Connection}.
   2107      */
   2108     public final void setExtras(@Nullable Bundle extras) {
   2109         checkImmutable();
   2110 
   2111         // Add/replace any new or changed extras values.
   2112         putExtras(extras);
   2113 
   2114         // If we have used "setExtras" in the past, compare the key set from the last invocation to
   2115         // the current one and remove any keys that went away.
   2116         if (mPreviousExtraKeys != null) {
   2117             List<String> toRemove = new ArrayList<String>();
   2118             for (String oldKey : mPreviousExtraKeys) {
   2119                 if (extras == null || !extras.containsKey(oldKey)) {
   2120                     toRemove.add(oldKey);
   2121                 }
   2122             }
   2123             if (!toRemove.isEmpty()) {
   2124                 removeExtras(toRemove);
   2125             }
   2126         }
   2127 
   2128         // Track the keys the last time set called setExtras.  This way, the next time setExtras is
   2129         // called we can see if the caller has removed any extras values.
   2130         if (mPreviousExtraKeys == null) {
   2131             mPreviousExtraKeys = new ArraySet<String>();
   2132         }
   2133         mPreviousExtraKeys.clear();
   2134         if (extras != null) {
   2135             mPreviousExtraKeys.addAll(extras.keySet());
   2136         }
   2137     }
   2138 
   2139     /**
   2140      * Adds some extras to this {@code Connection}.  Existing keys are replaced and new ones are
   2141      * added.
   2142      * <p>
   2143      * No assumptions should be made as to how an In-Call UI or service will handle these extras.
   2144      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
   2145      *
   2146      * @param extras The extras to add.
   2147      */
   2148     public final void putExtras(@NonNull Bundle extras) {
   2149         checkImmutable();
   2150         if (extras == null) {
   2151             return;
   2152         }
   2153         // Creating a duplicate bundle so we don't have to synchronize on mExtrasLock while calling
   2154         // the listeners.
   2155         Bundle listenerExtras;
   2156         synchronized (mExtrasLock) {
   2157             if (mExtras == null) {
   2158                 mExtras = new Bundle();
   2159             }
   2160             mExtras.putAll(extras);
   2161             listenerExtras = new Bundle(mExtras);
   2162         }
   2163         for (Listener l : mListeners) {
   2164             // Create a new clone of the extras for each listener so that they don't clobber
   2165             // each other
   2166             l.onExtrasChanged(this, new Bundle(listenerExtras));
   2167         }
   2168     }
   2169 
   2170     /**
   2171      * Adds a boolean extra to this {@code Connection}.
   2172      *
   2173      * @param key The extra key.
   2174      * @param value The value.
   2175      * @hide
   2176      */
   2177     public final void putExtra(String key, boolean value) {
   2178         Bundle newExtras = new Bundle();
   2179         newExtras.putBoolean(key, value);
   2180         putExtras(newExtras);
   2181     }
   2182 
   2183     /**
   2184      * Adds an integer extra to this {@code Connection}.
   2185      *
   2186      * @param key The extra key.
   2187      * @param value The value.
   2188      * @hide
   2189      */
   2190     public final void putExtra(String key, int value) {
   2191         Bundle newExtras = new Bundle();
   2192         newExtras.putInt(key, value);
   2193         putExtras(newExtras);
   2194     }
   2195 
   2196     /**
   2197      * Adds a string extra to this {@code Connection}.
   2198      *
   2199      * @param key The extra key.
   2200      * @param value The value.
   2201      * @hide
   2202      */
   2203     public final void putExtra(String key, String value) {
   2204         Bundle newExtras = new Bundle();
   2205         newExtras.putString(key, value);
   2206         putExtras(newExtras);
   2207     }
   2208 
   2209     /**
   2210      * Removes extras from this {@code Connection}.
   2211      *
   2212      * @param keys The keys of the extras to remove.
   2213      */
   2214     public final void removeExtras(List<String> keys) {
   2215         synchronized (mExtrasLock) {
   2216             if (mExtras != null) {
   2217                 for (String key : keys) {
   2218                     mExtras.remove(key);
   2219                 }
   2220             }
   2221         }
   2222         List<String> unmodifiableKeys = Collections.unmodifiableList(keys);
   2223         for (Listener l : mListeners) {
   2224             l.onExtrasRemoved(this, unmodifiableKeys);
   2225         }
   2226     }
   2227 
   2228     /**
   2229      * Removes extras from this {@code Connection}.
   2230      *
   2231      * @param keys The keys of the extras to remove.
   2232      */
   2233     public final void removeExtras(String ... keys) {
   2234         removeExtras(Arrays.asList(keys));
   2235     }
   2236 
   2237     /**
   2238      * Notifies this Connection that the {@link #getAudioState()} property has a new value.
   2239      *
   2240      * @param state The new connection audio state.
   2241      * @deprecated Use {@link #onCallAudioStateChanged(CallAudioState)} instead.
   2242      * @hide
   2243      */
   2244     @SystemApi
   2245     @Deprecated
   2246     public void onAudioStateChanged(AudioState state) {}
   2247 
   2248     /**
   2249      * Notifies this Connection that the {@link #getCallAudioState()} property has a new value.
   2250      *
   2251      * @param state The new connection audio state.
   2252      */
   2253     public void onCallAudioStateChanged(CallAudioState state) {}
   2254 
   2255     /**
   2256      * Notifies this Connection of an internal state change. This method is called after the
   2257      * state is changed.
   2258      *
   2259      * @param state The new state, one of the {@code STATE_*} constants.
   2260      */
   2261     public void onStateChanged(int state) {}
   2262 
   2263     /**
   2264      * Notifies this Connection of a request to play a DTMF tone.
   2265      *
   2266      * @param c A DTMF character.
   2267      */
   2268     public void onPlayDtmfTone(char c) {}
   2269 
   2270     /**
   2271      * Notifies this Connection of a request to stop any currently playing DTMF tones.
   2272      */
   2273     public void onStopDtmfTone() {}
   2274 
   2275     /**
   2276      * Notifies this Connection of a request to disconnect.
   2277      */
   2278     public void onDisconnect() {}
   2279 
   2280     /**
   2281      * Notifies this Connection of a request to disconnect a participant of the conference managed
   2282      * by the connection.
   2283      *
   2284      * @param endpoint the {@link Uri} of the participant to disconnect.
   2285      * @hide
   2286      */
   2287     public void onDisconnectConferenceParticipant(Uri endpoint) {}
   2288 
   2289     /**
   2290      * Notifies this Connection of a request to separate from its parent conference.
   2291      */
   2292     public void onSeparate() {}
   2293 
   2294     /**
   2295      * Notifies this Connection of a request to abort.
   2296      */
   2297     public void onAbort() {}
   2298 
   2299     /**
   2300      * Notifies this Connection of a request to hold.
   2301      */
   2302     public void onHold() {}
   2303 
   2304     /**
   2305      * Notifies this Connection of a request to exit a hold state.
   2306      */
   2307     public void onUnhold() {}
   2308 
   2309     /**
   2310      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
   2311      * a request to accept.
   2312      *
   2313      * @param videoState The video state in which to answer the connection.
   2314      */
   2315     public void onAnswer(int videoState) {}
   2316 
   2317     /**
   2318      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
   2319      * a request to accept.
   2320      */
   2321     public void onAnswer() {
   2322         onAnswer(VideoProfile.STATE_AUDIO_ONLY);
   2323     }
   2324 
   2325     /**
   2326      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
   2327      * a request to reject.
   2328      */
   2329     public void onReject() {}
   2330 
   2331     /**
   2332      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
   2333      * a request to reject with a message.
   2334      */
   2335     public void onReject(String replyMessage) {}
   2336 
   2337     /**
   2338      * Notifies the Connection of a request to silence the ringer.
   2339      *
   2340      * @hide
   2341      */
   2342     public void onSilence() {}
   2343 
   2344     /**
   2345      * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
   2346      */
   2347     public void onPostDialContinue(boolean proceed) {}
   2348 
   2349     /**
   2350      * Notifies this Connection of a request to pull an external call to the local device.
   2351      * <p>
   2352      * The {@link InCallService} issues a request to pull an external call to the local device via
   2353      * {@link Call#pullExternalCall()}.
   2354      * <p>
   2355      * For a Connection to be pulled, both the {@link Connection#CAPABILITY_CAN_PULL_CALL}
   2356      * capability and {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property bits must be set.
   2357      * <p>
   2358      * For more information on external calls, see {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
   2359      */
   2360     public void onPullExternalCall() {}
   2361 
   2362     /**
   2363      * Notifies this Connection of a {@link Call} event initiated from an {@link InCallService}.
   2364      * <p>
   2365      * The {@link InCallService} issues a Call event via {@link Call#sendCallEvent(String, Bundle)}.
   2366      * <p>
   2367      * Where possible, the Connection should make an attempt to handle {@link Call} events which
   2368      * are part of the {@code android.telecom.*} namespace.  The Connection should ignore any events
   2369      * it does not wish to handle.  Unexpected events should be handled gracefully, as it is
   2370      * possible that a {@link InCallService} has defined its own Call events which a Connection is
   2371      * not aware of.
   2372      * <p>
   2373      * See also {@link Call#sendCallEvent(String, Bundle)}.
   2374      *
   2375      * @param event The call event.
   2376      * @param extras Extras associated with the call event.
   2377      */
   2378     public void onCallEvent(String event, Bundle extras) {}
   2379 
   2380     /**
   2381      * Notifies this {@link Connection} of a change to the extras made outside the
   2382      * {@link ConnectionService}.
   2383      * <p>
   2384      * These extras changes can originate from Telecom itself, or from an {@link InCallService} via
   2385      * the {@link android.telecom.Call#putExtras(Bundle)} and
   2386      * {@link Call#removeExtras(List)}.
   2387      *
   2388      * @param extras The new extras bundle.
   2389      */
   2390     public void onExtrasChanged(Bundle extras) {}
   2391 
   2392     static String toLogSafePhoneNumber(String number) {
   2393         // For unknown number, log empty string.
   2394         if (number == null) {
   2395             return "";
   2396         }
   2397 
   2398         if (PII_DEBUG) {
   2399             // When PII_DEBUG is true we emit PII.
   2400             return number;
   2401         }
   2402 
   2403         // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
   2404         // sanitized phone numbers.
   2405         StringBuilder builder = new StringBuilder();
   2406         for (int i = 0; i < number.length(); i++) {
   2407             char c = number.charAt(i);
   2408             if (c == '-' || c == '@' || c == '.') {
   2409                 builder.append(c);
   2410             } else {
   2411                 builder.append('x');
   2412             }
   2413         }
   2414         return builder.toString();
   2415     }
   2416 
   2417     private void setState(int state) {
   2418         checkImmutable();
   2419         if (mState == STATE_DISCONNECTED && mState != state) {
   2420             Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state.");
   2421             return;
   2422         }
   2423         if (mState != state) {
   2424             Log.d(this, "setState: %s", stateToString(state));
   2425             mState = state;
   2426             onStateChanged(state);
   2427             for (Listener l : mListeners) {
   2428                 l.onStateChanged(this, state);
   2429             }
   2430         }
   2431     }
   2432 
   2433     private static class FailureSignalingConnection extends Connection {
   2434         private boolean mImmutable = false;
   2435         public FailureSignalingConnection(DisconnectCause disconnectCause) {
   2436             setDisconnected(disconnectCause);
   2437             mImmutable = true;
   2438         }
   2439 
   2440         public void checkImmutable() {
   2441             if (mImmutable) {
   2442                 throw new UnsupportedOperationException("Connection is immutable");
   2443             }
   2444         }
   2445     }
   2446 
   2447     /**
   2448      * Return a {@code Connection} which represents a failed connection attempt. The returned
   2449      * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified,
   2450      * and a {@link #getState()} of {@link #STATE_DISCONNECTED}.
   2451      * <p>
   2452      * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate,
   2453      * so users of this method need not maintain a reference to its return value to destroy it.
   2454      *
   2455      * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
   2456      * @return A {@code Connection} which indicates failure.
   2457      */
   2458     public static Connection createFailedConnection(DisconnectCause disconnectCause) {
   2459         return new FailureSignalingConnection(disconnectCause);
   2460     }
   2461 
   2462     /**
   2463      * Override to throw an {@link UnsupportedOperationException} if this {@code Connection} is
   2464      * not intended to be mutated, e.g., if it is a marker for failure. Only for framework use;
   2465      * this should never be un-@hide-den.
   2466      *
   2467      * @hide
   2468      */
   2469     public void checkImmutable() {}
   2470 
   2471     /**
   2472      * Return a {@code Connection} which represents a canceled connection attempt. The returned
   2473      * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of
   2474      * that state. This connection should not be used for anything, and no other
   2475      * {@code Connection}s should be attempted.
   2476      * <p>
   2477      * so users of this method need not maintain a reference to its return value to destroy it.
   2478      *
   2479      * @return A {@code Connection} which indicates that the underlying connection should
   2480      * be canceled.
   2481      */
   2482     public static Connection createCanceledConnection() {
   2483         return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED));
   2484     }
   2485 
   2486     private final void fireOnConferenceableConnectionsChanged() {
   2487         for (Listener l : mListeners) {
   2488             l.onConferenceablesChanged(this, getConferenceables());
   2489         }
   2490     }
   2491 
   2492     private final void fireConferenceChanged() {
   2493         for (Listener l : mListeners) {
   2494             l.onConferenceChanged(this, mConference);
   2495         }
   2496     }
   2497 
   2498     private final void clearConferenceableList() {
   2499         for (Conferenceable c : mConferenceables) {
   2500             if (c instanceof Connection) {
   2501                 Connection connection = (Connection) c;
   2502                 connection.removeConnectionListener(mConnectionDeathListener);
   2503             } else if (c instanceof Conference) {
   2504                 Conference conference = (Conference) c;
   2505                 conference.removeListener(mConferenceDeathListener);
   2506             }
   2507         }
   2508         mConferenceables.clear();
   2509     }
   2510 
   2511     /**
   2512      * Handles a change to extras received from Telecom.
   2513      *
   2514      * @param extras The new extras.
   2515      * @hide
   2516      */
   2517     final void handleExtrasChanged(Bundle extras) {
   2518         Bundle b = null;
   2519         synchronized (mExtrasLock) {
   2520             mExtras = extras;
   2521             if (mExtras != null) {
   2522                 b = new Bundle(mExtras);
   2523             }
   2524         }
   2525         onExtrasChanged(b);
   2526     }
   2527 
   2528     /**
   2529      * Notifies listeners that the merge request failed.
   2530      *
   2531      * @hide
   2532      */
   2533     protected final void notifyConferenceMergeFailed() {
   2534         for (Listener l : mListeners) {
   2535             l.onConferenceMergeFailed(this);
   2536         }
   2537     }
   2538 
   2539     /**
   2540      * Notifies listeners of a change to conference participant(s).
   2541      *
   2542      * @param conferenceParticipants The participants.
   2543      * @hide
   2544      */
   2545     protected final void updateConferenceParticipants(
   2546             List<ConferenceParticipant> conferenceParticipants) {
   2547         for (Listener l : mListeners) {
   2548             l.onConferenceParticipantsChanged(this, conferenceParticipants);
   2549         }
   2550     }
   2551 
   2552     /**
   2553      * Notifies listeners that a conference call has been started.
   2554      * @hide
   2555      */
   2556     protected void notifyConferenceStarted() {
   2557         for (Listener l : mListeners) {
   2558             l.onConferenceStarted();
   2559         }
   2560     }
   2561 
   2562     /**
   2563      * Notifies listeners when a change has occurred to the Connection which impacts its ability to
   2564      * be a part of a conference call.
   2565      * @param isConferenceSupported {@code true} if the connection supports being part of a
   2566      *      conference call, {@code false} otherwise.
   2567      * @hide
   2568      */
   2569     protected void notifyConferenceSupportedChanged(boolean isConferenceSupported) {
   2570         for (Listener l : mListeners) {
   2571             l.onConferenceSupportedChanged(this, isConferenceSupported);
   2572         }
   2573     }
   2574 
   2575     /**
   2576      * Sends an event associated with this {@code Connection} with associated event extras to the
   2577      * {@link InCallService}.
   2578      * <p>
   2579      * Connection events are used to communicate point in time information from a
   2580      * {@link ConnectionService} to a {@link InCallService} implementations.  An example of a
   2581      * custom connection event includes notifying the UI when a WIFI call has been handed over to
   2582      * LTE, which the InCall UI might use to inform the user that billing charges may apply.  The
   2583      * Android Telephony framework will send the {@link #EVENT_CALL_MERGE_FAILED} connection event
   2584      * when a call to {@link Call#mergeConference()} has failed to complete successfully.  A
   2585      * connection event could also be used to trigger UI in the {@link InCallService} which prompts
   2586      * the user to make a choice (e.g. whether they want to incur roaming costs for making a call),
   2587      * which is communicated back via {@link Call#sendCallEvent(String, Bundle)}.
   2588      * <p>
   2589      * Events are exposed to {@link InCallService} implementations via
   2590      * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
   2591      * <p>
   2592      * No assumptions should be made as to how an In-Call UI or service will handle these events.
   2593      * The {@link ConnectionService} must assume that the In-Call UI could even chose to ignore
   2594      * some events altogether.
   2595      * <p>
   2596      * Events should be fully qualified (e.g. {@code com.example.event.MY_EVENT}) to avoid
   2597      * conflicts between {@link ConnectionService} implementations.  Further, custom
   2598      * {@link ConnectionService} implementations shall not re-purpose events in the
   2599      * {@code android.*} namespace, nor shall they define new event types in this namespace.  When
   2600      * defining a custom event type, ensure the contents of the extras {@link Bundle} is clearly
   2601      * defined.  Extra keys for this bundle should be named similar to the event type (e.g.
   2602      * {@code com.example.extra.MY_EXTRA}).
   2603      * <p>
   2604      *  When defining events and the associated extras, it is important to keep their behavior
   2605      * consistent when the associated {@link ConnectionService} is updated.  Support for deprecated
   2606      * events/extras should me maintained to ensure backwards compatibility with older
   2607      * {@link InCallService} implementations which were built to support the older behavior.
   2608      *
   2609      * @param event The connection event.
   2610      * @param extras Optional bundle containing extra information associated with the event.
   2611      */
   2612     public void sendConnectionEvent(String event, Bundle extras) {
   2613         for (Listener l : mListeners) {
   2614             l.onConnectionEvent(this, event, extras);
   2615         }
   2616     }
   2617 }
   2618