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