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