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