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