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.Nullable;
     24 import android.annotation.SystemApi;
     25 import android.hardware.camera2.CameraManager;
     26 import android.net.Uri;
     27 import android.os.Bundle;
     28 import android.os.Handler;
     29 import android.os.IBinder;
     30 import android.os.Looper;
     31 import android.os.Message;
     32 import android.os.RemoteException;
     33 import android.view.Surface;
     34 
     35 import java.util.ArrayList;
     36 import java.util.Collections;
     37 import java.util.List;
     38 import java.util.Set;
     39 import java.util.concurrent.ConcurrentHashMap;
     40 
     41 /**
     42  * Represents a phone call or connection to a remote endpoint that carries voice and/or video
     43  * traffic.
     44  * <p>
     45  * Implementations create a custom subclass of {@code Connection} and return it to the framework
     46  * as the return value of
     47  * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}
     48  * or
     49  * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
     50  * Implementations are then responsible for updating the state of the {@code Connection}, and
     51  * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no
     52  * longer used and associated resources may be recovered.
     53  */
     54 public abstract class Connection extends Conferenceable {
     55 
     56     /**
     57      * The connection is initializing. This is generally the first state for a {@code Connection}
     58      * returned by a {@link ConnectionService}.
     59      */
     60     public static final int STATE_INITIALIZING = 0;
     61 
     62     /**
     63      * The connection is new and not connected.
     64      */
     65     public static final int STATE_NEW = 1;
     66 
     67     /**
     68      * An incoming connection is in the ringing state. During this state, the user's ringer or
     69      * vibration feature will be activated.
     70      */
     71     public static final int STATE_RINGING = 2;
     72 
     73     /**
     74      * An outgoing connection is in the dialing state. In this state the other party has not yet
     75      * answered the call and the user traditionally hears a ringback tone.
     76      */
     77     public static final int STATE_DIALING = 3;
     78 
     79     /**
     80      * A connection is active. Both parties are connected to the call and can actively communicate.
     81      */
     82     public static final int STATE_ACTIVE = 4;
     83 
     84     /**
     85      * A connection is on hold.
     86      */
     87     public static final int STATE_HOLDING = 5;
     88 
     89     /**
     90      * A connection has been disconnected. This is the final state once the user has been
     91      * disconnected from a call either locally, remotely or by an error in the service.
     92      */
     93     public static final int STATE_DISCONNECTED = 6;
     94 
     95     /**
     96      * Connection can currently be put on hold or unheld. This is distinct from
     97      * {@link #CAPABILITY_SUPPORT_HOLD} in that although a connection may support 'hold' most times,
     98      * it does not at the moment support the function. This can be true while the call is in the
     99      * state {@link #STATE_DIALING}, for example. During this condition, an in-call UI may
    100      * display a disabled 'hold' button.
    101      */
    102     public static final int CAPABILITY_HOLD = 0x00000001;
    103 
    104     /** Connection supports the hold feature. */
    105     public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
    106 
    107     /**
    108      * Connections within a conference can be merged. A {@link ConnectionService} has the option to
    109      * add a {@link Conference} before the child {@link Connection}s are merged. This is how
    110      * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
    111      * capability allows a merge button to be shown while the conference is in the foreground
    112      * of the in-call UI.
    113      * <p>
    114      * This is only intended for use by a {@link Conference}.
    115      */
    116     public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
    117 
    118     /**
    119      * Connections within a conference can be swapped between foreground and background.
    120      * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
    121      * <p>
    122      * This is only intended for use by a {@link Conference}.
    123      */
    124     public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
    125 
    126     /**
    127      * @hide
    128      */
    129     public static final int CAPABILITY_UNUSED = 0x00000010;
    130 
    131     /** Connection supports responding via text option. */
    132     public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
    133 
    134     /** Connection can be muted. */
    135     public static final int CAPABILITY_MUTE = 0x00000040;
    136 
    137     /**
    138      * Connection supports conference management. This capability only applies to
    139      * {@link Conference}s which can have {@link Connection}s as children.
    140      */
    141     public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
    142 
    143     /**
    144      * Local device supports receiving video.
    145      */
    146     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
    147 
    148     /**
    149      * Local device supports transmitting video.
    150      */
    151     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
    152 
    153     /**
    154      * Local device supports bidirectional video calling.
    155      */
    156     public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
    157             CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
    158 
    159     /**
    160      * Remote device supports receiving video.
    161      */
    162     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
    163 
    164     /**
    165      * Remote device supports transmitting video.
    166      */
    167     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
    168 
    169     /**
    170      * Remote device supports bidirectional video calling.
    171      */
    172     public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
    173             CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
    174 
    175     /**
    176      * Connection is able to be separated from its parent {@code Conference}, if any.
    177      */
    178     public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
    179 
    180     /**
    181      * Connection is able to be individually disconnected when in a {@code Conference}.
    182      */
    183     public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
    184 
    185     /**
    186      * Whether the call is a generic conference, where we do not know the precise state of
    187      * participants in the conference (eg. on CDMA).
    188      *
    189      * @hide
    190      */
    191     public static final int CAPABILITY_GENERIC_CONFERENCE = 0x00004000;
    192 
    193     /**
    194      * Connection is using high definition audio.
    195      * @hide
    196      */
    197     public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00008000;
    198 
    199     /**
    200      * Connection is using WIFI.
    201      * @hide
    202      */
    203     public static final int CAPABILITY_WIFI = 0x00010000;
    204 
    205     /**
    206      * Indicates that the current device callback number should be shown.
    207      *
    208      * @hide
    209      */
    210     public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 0x00020000;
    211 
    212     /**
    213      * Speed up audio setup for MT call.
    214      * @hide
    215      */
    216     public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
    217 
    218     /**
    219      * Call can be upgraded to a video call.
    220      */
    221     public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
    222 
    223     /**
    224      * For video calls, indicates whether the outgoing video for the call can be paused using
    225      * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
    226      */
    227     public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
    228 
    229     /**
    230      * For a conference, indicates the conference will not have child connections.
    231      * <p>
    232      * An example of a conference with child connections is a GSM conference call, where the radio
    233      * retains connections to the individual participants of the conference.  Another example is an
    234      * IMS conference call where conference event package functionality is supported; in this case
    235      * the conference server ensures the radio is aware of the participants in the conference, which
    236      * are represented by child connections.
    237      * <p>
    238      * An example of a conference with no child connections is an IMS conference call with no
    239      * conference event package support.  Such a conference is represented by the radio as a single
    240      * connection to the IMS conference server.
    241      * <p>
    242      * Indicating whether a conference has children or not is important to help user interfaces
    243      * visually represent a conference.  A conference with no children, for example, will have the
    244      * conference connection shown in the list of calls on a Bluetooth device, where if the
    245      * conference has children, only the children will be shown in the list of calls on a Bluetooth
    246      * device.
    247      * @hide
    248      */
    249     public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
    250 
    251     //**********************************************************************************************
    252     // Next CAPABILITY value: 0x00400000
    253     //**********************************************************************************************
    254 
    255     /**
    256      * Connection extra key used to store the last forwarded number associated with the current
    257      * connection.  Used to communicate to the user interface that the connection was forwarded via
    258      * the specified number.
    259      */
    260     public static final String EXTRA_LAST_FORWARDED_NUMBER =
    261             "android.telecom.extra.LAST_FORWARDED_NUMBER";
    262 
    263     /**
    264      * Connection extra key used to store a child number associated with the current connection.
    265      * Used to communicate to the user interface that the connection was received via
    266      * a child address (i.e. phone number) associated with the {@link PhoneAccount}'s primary
    267      * address.
    268      */
    269     public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
    270 
    271     /**
    272      * Connection extra key used to store the subject for an incoming call.  The user interface can
    273      * query this extra and display its contents for incoming calls.  Will only be used if the
    274      * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}.
    275      */
    276     public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
    277 
    278     // Flag controlling whether PII is emitted into the logs
    279     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
    280 
    281     /**
    282      * Whether the given capabilities support the specified capability.
    283      *
    284      * @param capabilities A capability bit field.
    285      * @param capability The capability to check capabilities for.
    286      * @return Whether the specified capability is supported.
    287      * @hide
    288      */
    289     public static boolean can(int capabilities, int capability) {
    290         return (capabilities & capability) != 0;
    291     }
    292 
    293     /**
    294      * Whether the capabilities of this {@code Connection} supports the specified capability.
    295      *
    296      * @param capability The capability to check capabilities for.
    297      * @return Whether the specified capability is supported.
    298      * @hide
    299      */
    300     public boolean can(int capability) {
    301         return can(mConnectionCapabilities, capability);
    302     }
    303 
    304     /**
    305      * Removes the specified capability from the set of capabilities of this {@code Connection}.
    306      *
    307      * @param capability The capability to remove from the set.
    308      * @hide
    309      */
    310     public void removeCapability(int capability) {
    311         mConnectionCapabilities &= ~capability;
    312     }
    313 
    314     /**
    315      * Adds the specified capability to the set of capabilities of this {@code Connection}.
    316      *
    317      * @param capability The capability to add to the set.
    318      * @hide
    319      */
    320     public void addCapability(int capability) {
    321         mConnectionCapabilities |= capability;
    322     }
    323 
    324 
    325     public static String capabilitiesToString(int capabilities) {
    326         StringBuilder builder = new StringBuilder();
    327         builder.append("[Capabilities:");
    328         if (can(capabilities, CAPABILITY_HOLD)) {
    329             builder.append(" CAPABILITY_HOLD");
    330         }
    331         if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
    332             builder.append(" CAPABILITY_SUPPORT_HOLD");
    333         }
    334         if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
    335             builder.append(" CAPABILITY_MERGE_CONFERENCE");
    336         }
    337         if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
    338             builder.append(" CAPABILITY_SWAP_CONFERENCE");
    339         }
    340         if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
    341             builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
    342         }
    343         if (can(capabilities, CAPABILITY_MUTE)) {
    344             builder.append(" CAPABILITY_MUTE");
    345         }
    346         if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
    347             builder.append(" CAPABILITY_MANAGE_CONFERENCE");
    348         }
    349         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
    350             builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
    351         }
    352         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
    353             builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
    354         }
    355         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
    356             builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
    357         }
    358         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
    359             builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
    360         }
    361         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
    362             builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
    363         }
    364         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
    365             builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
    366         }
    367         if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
    368             builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
    369         }
    370         if (can(capabilities, CAPABILITY_WIFI)) {
    371             builder.append(" CAPABILITY_WIFI");
    372         }
    373         if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) {
    374             builder.append(" CAPABILITY_GENERIC_CONFERENCE");
    375         }
    376         if (can(capabilities, CAPABILITY_SHOW_CALLBACK_NUMBER)) {
    377             builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
    378         }
    379         if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
    380             builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
    381         }
    382         if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
    383             builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
    384         }
    385         if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
    386             builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
    387         }
    388         if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
    389             builder.append(" CAPABILITY_SINGLE_PARTY_CONFERENCE");
    390         }
    391         builder.append("]");
    392         return builder.toString();
    393     }
    394 
    395     /** @hide */
    396     public abstract static class Listener {
    397         public void onStateChanged(Connection c, int state) {}
    398         public void onAddressChanged(Connection c, Uri newAddress, int presentation) {}
    399         public void onCallerDisplayNameChanged(
    400                 Connection c, String callerDisplayName, int presentation) {}
    401         public void onVideoStateChanged(Connection c, int videoState) {}
    402         public void onDisconnected(Connection c, DisconnectCause disconnectCause) {}
    403         public void onPostDialWait(Connection c, String remaining) {}
    404         public void onPostDialChar(Connection c, char nextChar) {}
    405         public void onRingbackRequested(Connection c, boolean ringback) {}
    406         public void onDestroyed(Connection c) {}
    407         public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {}
    408         public void onVideoProviderChanged(
    409                 Connection c, VideoProvider videoProvider) {}
    410         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
    411         public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
    412         public void onConferenceablesChanged(
    413                 Connection c, List<Conferenceable> conferenceables) {}
    414         public void onConferenceChanged(Connection c, Conference conference) {}
    415         /** @hide */
    416         public void onConferenceParticipantsChanged(Connection c,
    417                 List<ConferenceParticipant> participants) {}
    418         public void onConferenceStarted() {}
    419         public void onConferenceMergeFailed(Connection c) {}
    420         public void onExtrasChanged(Connection c, Bundle extras) {}
    421     }
    422 
    423     /**
    424      * Provides a means of controlling the video session associated with a {@link Connection}.
    425      * <p>
    426      * Implementations create a custom subclass of {@link VideoProvider} and the
    427      * {@link ConnectionService} creates an instance sets it on the {@link Connection} using
    428      * {@link Connection#setVideoProvider(VideoProvider)}.  Any connection which supports video
    429      * should set the {@link VideoProvider}.
    430      * <p>
    431      * The {@link VideoProvider} serves two primary purposes: it provides a means for Telecom and
    432      * {@link InCallService} implementations to issue requests related to the video session;
    433      * it provides a means for the {@link ConnectionService} to report events and information
    434      * related to the video session to Telecom and the {@link InCallService} implementations.
    435      * <p>
    436      * {@link InCallService} implementations interact with the {@link VideoProvider} via
    437      * {@link android.telecom.InCallService.VideoCall}.
    438      */
    439     public static abstract class VideoProvider {
    440 
    441         /**
    442          * Video is not being received (no protocol pause was issued).
    443          * @see #handleCallSessionEvent(int)
    444          */
    445         public static final int SESSION_EVENT_RX_PAUSE = 1;
    446 
    447         /**
    448          * Video reception has resumed after a {@link #SESSION_EVENT_RX_PAUSE}.
    449          * @see #handleCallSessionEvent(int)
    450          */
    451         public static final int SESSION_EVENT_RX_RESUME = 2;
    452 
    453         /**
    454          * Video transmission has begun. This occurs after a negotiated start of video transmission
    455          * when the underlying protocol has actually begun transmitting video to the remote party.
    456          * @see #handleCallSessionEvent(int)
    457          */
    458         public static final int SESSION_EVENT_TX_START = 3;
    459 
    460         /**
    461          * Video transmission has stopped. This occurs after a negotiated stop of video transmission
    462          * when the underlying protocol has actually stopped transmitting video to the remote party.
    463          * @see #handleCallSessionEvent(int)
    464          */
    465         public static final int SESSION_EVENT_TX_STOP = 4;
    466 
    467         /**
    468          * A camera failure has occurred for the selected camera.  The {@link InCallService} can use
    469          * this as a cue to inform the user the camera is not available.
    470          * @see #handleCallSessionEvent(int)
    471          */
    472         public static final int SESSION_EVENT_CAMERA_FAILURE = 5;
    473 
    474         /**
    475          * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready
    476          * for operation.  The {@link InCallService} can use this as a cue to inform the user that
    477          * the camera has become available again.
    478          * @see #handleCallSessionEvent(int)
    479          */
    480         public static final int SESSION_EVENT_CAMERA_READY = 6;
    481 
    482         /**
    483          * Session modify request was successful.
    484          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
    485          */
    486         public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1;
    487 
    488         /**
    489          * Session modify request failed.
    490          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
    491          */
    492         public static final int SESSION_MODIFY_REQUEST_FAIL = 2;
    493 
    494         /**
    495          * Session modify request ignored due to invalid parameters.
    496          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
    497          */
    498         public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
    499 
    500         /**
    501          * Session modify request timed out.
    502          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
    503          */
    504         public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4;
    505 
    506         /**
    507          * Session modify request rejected by remote user.
    508          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
    509          */
    510         public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5;
    511 
    512         private static final int MSG_ADD_VIDEO_CALLBACK = 1;
    513         private static final int MSG_SET_CAMERA = 2;
    514         private static final int MSG_SET_PREVIEW_SURFACE = 3;
    515         private static final int MSG_SET_DISPLAY_SURFACE = 4;
    516         private static final int MSG_SET_DEVICE_ORIENTATION = 5;
    517         private static final int MSG_SET_ZOOM = 6;
    518         private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
    519         private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
    520         private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
    521         private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10;
    522         private static final int MSG_SET_PAUSE_IMAGE = 11;
    523         private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
    524 
    525         private VideoProvider.VideoProviderHandler mMessageHandler;
    526         private final VideoProvider.VideoProviderBinder mBinder;
    527 
    528         /**
    529          * Stores a list of the video callbacks, keyed by IBinder.
    530          *
    531          * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
    532          * load factor before resizing, 1 means we only expect a single thread to
    533          * access the map so make only a single shard
    534          */
    535         private ConcurrentHashMap<IBinder, IVideoCallback> mVideoCallbacks =
    536                 new ConcurrentHashMap<IBinder, IVideoCallback>(8, 0.9f, 1);
    537 
    538         /**
    539          * Default handler used to consolidate binder method calls onto a single thread.
    540          */
    541         private final class VideoProviderHandler extends Handler {
    542             public VideoProviderHandler() {
    543                 super();
    544             }
    545 
    546             public VideoProviderHandler(Looper looper) {
    547                 super(looper);
    548             }
    549 
    550             @Override
    551             public void handleMessage(Message msg) {
    552                 switch (msg.what) {
    553                     case MSG_ADD_VIDEO_CALLBACK: {
    554                         IBinder binder = (IBinder) msg.obj;
    555                         IVideoCallback callback = IVideoCallback.Stub
    556                                 .asInterface((IBinder) msg.obj);
    557                         if (callback == null) {
    558                             Log.w(this, "addVideoProvider - skipped; callback is null.");
    559                             break;
    560                         }
    561 
    562                         if (mVideoCallbacks.containsKey(binder)) {
    563                             Log.i(this, "addVideoProvider - skipped; already present.");
    564                             break;
    565                         }
    566                         mVideoCallbacks.put(binder, callback);
    567                         break;
    568                     }
    569                     case MSG_REMOVE_VIDEO_CALLBACK: {
    570                         IBinder binder = (IBinder) msg.obj;
    571                         IVideoCallback callback = IVideoCallback.Stub
    572                                 .asInterface((IBinder) msg.obj);
    573                         if (!mVideoCallbacks.containsKey(binder)) {
    574                             Log.i(this, "removeVideoProvider - skipped; not present.");
    575                             break;
    576                         }
    577                         mVideoCallbacks.remove(binder);
    578                         break;
    579                     }
    580                     case MSG_SET_CAMERA:
    581                         onSetCamera((String) msg.obj);
    582                         break;
    583                     case MSG_SET_PREVIEW_SURFACE:
    584                         onSetPreviewSurface((Surface) msg.obj);
    585                         break;
    586                     case MSG_SET_DISPLAY_SURFACE:
    587                         onSetDisplaySurface((Surface) msg.obj);
    588                         break;
    589                     case MSG_SET_DEVICE_ORIENTATION:
    590                         onSetDeviceOrientation(msg.arg1);
    591                         break;
    592                     case MSG_SET_ZOOM:
    593                         onSetZoom((Float) msg.obj);
    594                         break;
    595                     case MSG_SEND_SESSION_MODIFY_REQUEST: {
    596                         SomeArgs args = (SomeArgs) msg.obj;
    597                         try {
    598                             onSendSessionModifyRequest((VideoProfile) args.arg1,
    599                                     (VideoProfile) args.arg2);
    600                         } finally {
    601                             args.recycle();
    602                         }
    603                         break;
    604                     }
    605                     case MSG_SEND_SESSION_MODIFY_RESPONSE:
    606                         onSendSessionModifyResponse((VideoProfile) msg.obj);
    607                         break;
    608                     case MSG_REQUEST_CAMERA_CAPABILITIES:
    609                         onRequestCameraCapabilities();
    610                         break;
    611                     case MSG_REQUEST_CONNECTION_DATA_USAGE:
    612                         onRequestConnectionDataUsage();
    613                         break;
    614                     case MSG_SET_PAUSE_IMAGE:
    615                         onSetPauseImage((Uri) msg.obj);
    616                         break;
    617                     default:
    618                         break;
    619                 }
    620             }
    621         }
    622 
    623         /**
    624          * IVideoProvider stub implementation.
    625          */
    626         private final class VideoProviderBinder extends IVideoProvider.Stub {
    627             public void addVideoCallback(IBinder videoCallbackBinder) {
    628                 mMessageHandler.obtainMessage(
    629                         MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
    630             }
    631 
    632             public void removeVideoCallback(IBinder videoCallbackBinder) {
    633                 mMessageHandler.obtainMessage(
    634                         MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
    635             }
    636 
    637             public void setCamera(String cameraId) {
    638                 mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
    639             }
    640 
    641             public void setPreviewSurface(Surface surface) {
    642                 mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
    643             }
    644 
    645             public void setDisplaySurface(Surface surface) {
    646                 mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
    647             }
    648 
    649             public void setDeviceOrientation(int rotation) {
    650                 mMessageHandler.obtainMessage(
    651                         MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget();
    652             }
    653 
    654             public void setZoom(float value) {
    655                 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
    656             }
    657 
    658             public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
    659                 SomeArgs args = SomeArgs.obtain();
    660                 args.arg1 = fromProfile;
    661                 args.arg2 = toProfile;
    662                 mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
    663             }
    664 
    665             public void sendSessionModifyResponse(VideoProfile responseProfile) {
    666                 mMessageHandler.obtainMessage(
    667                         MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
    668             }
    669 
    670             public void requestCameraCapabilities() {
    671                 mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
    672             }
    673 
    674             public void requestCallDataUsage() {
    675                 mMessageHandler.obtainMessage(MSG_REQUEST_CONNECTION_DATA_USAGE).sendToTarget();
    676             }
    677 
    678             public void setPauseImage(Uri uri) {
    679                 mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
    680             }
    681         }
    682 
    683         public VideoProvider() {
    684             mBinder = new VideoProvider.VideoProviderBinder();
    685             mMessageHandler = new VideoProvider.VideoProviderHandler(Looper.getMainLooper());
    686         }
    687 
    688         /**
    689          * Creates an instance of the {@link VideoProvider}, specifying the looper to use.
    690          *
    691          * @param looper The looper.
    692          * @hide
    693          */
    694         public VideoProvider(Looper looper) {
    695             mBinder = new VideoProvider.VideoProviderBinder();
    696             mMessageHandler = new VideoProvider.VideoProviderHandler(looper);
    697         }
    698 
    699         /**
    700          * Returns binder object which can be used across IPC methods.
    701          * @hide
    702          */
    703         public final IVideoProvider getInterface() {
    704             return mBinder;
    705         }
    706 
    707         /**
    708          * Sets the camera to be used for the outgoing video.
    709          * <p>
    710          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
    711          * camera via
    712          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
    713          * <p>
    714          * Sent from the {@link InCallService} via
    715          * {@link InCallService.VideoCall#setCamera(String)}.
    716          *
    717          * @param cameraId The id of the camera (use ids as reported by
    718          * {@link CameraManager#getCameraIdList()}).
    719          */
    720         public abstract void onSetCamera(String cameraId);
    721 
    722         /**
    723          * Sets the surface to be used for displaying a preview of what the user's camera is
    724          * currently capturing.  When video transmission is enabled, this is the video signal which
    725          * is sent to the remote device.
    726          * <p>
    727          * Sent from the {@link InCallService} via
    728          * {@link InCallService.VideoCall#setPreviewSurface(Surface)}.
    729          *
    730          * @param surface The {@link Surface}.
    731          */
    732         public abstract void onSetPreviewSurface(Surface surface);
    733 
    734         /**
    735          * Sets the surface to be used for displaying the video received from the remote device.
    736          * <p>
    737          * Sent from the {@link InCallService} via
    738          * {@link InCallService.VideoCall#setDisplaySurface(Surface)}.
    739          *
    740          * @param surface The {@link Surface}.
    741          */
    742         public abstract void onSetDisplaySurface(Surface surface);
    743 
    744         /**
    745          * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of
    746          * the device is 0 degrees.
    747          * <p>
    748          * Sent from the {@link InCallService} via
    749          * {@link InCallService.VideoCall#setDeviceOrientation(int)}.
    750          *
    751          * @param rotation The device orientation, in degrees.
    752          */
    753         public abstract void onSetDeviceOrientation(int rotation);
    754 
    755         /**
    756          * Sets camera zoom ratio.
    757          * <p>
    758          * Sent from the {@link InCallService} via {@link InCallService.VideoCall#setZoom(float)}.
    759          *
    760          * @param value The camera zoom ratio.
    761          */
    762         public abstract void onSetZoom(float value);
    763 
    764         /**
    765          * Issues a request to modify the properties of the current video session.
    766          * <p>
    767          * Example scenarios include: requesting an audio-only call to be upgraded to a
    768          * bi-directional video call, turning on or off the user's camera, sending a pause signal
    769          * when the {@link InCallService} is no longer the foreground application.
    770          * <p>
    771          * If the {@link VideoProvider} determines a request to be invalid, it should call
    772          * {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} to report the
    773          * invalid request back to the {@link InCallService}.
    774          * <p>
    775          * Where a request requires confirmation from the user of the peer device, the
    776          * {@link VideoProvider} must communicate the request to the peer device and handle the
    777          * user's response.  {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)}
    778          * is used to inform the {@link InCallService} of the result of the request.
    779          * <p>
    780          * Sent from the {@link InCallService} via
    781          * {@link InCallService.VideoCall#sendSessionModifyRequest(VideoProfile)}.
    782          *
    783          * @param fromProfile The video profile prior to the request.
    784          * @param toProfile The video profile with the requested changes made.
    785          */
    786         public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
    787                 VideoProfile toProfile);
    788 
    789         /**
    790          * Provides a response to a request to change the current video session properties.
    791          * <p>
    792          * For example, if the peer requests and upgrade from an audio-only call to a bi-directional
    793          * video call, could decline the request and keep the call as audio-only.
    794          * In such a scenario, the {@code responseProfile} would have a video state of
    795          * {@link VideoProfile#STATE_AUDIO_ONLY}.  If the user had decided to accept the request,
    796          * the video state would be {@link VideoProfile#STATE_BIDIRECTIONAL}.
    797          * <p>
    798          * Sent from the {@link InCallService} via
    799          * {@link InCallService.VideoCall#sendSessionModifyResponse(VideoProfile)} in response to
    800          * a {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)}
    801          * callback.
    802          *
    803          * @param responseProfile The response video profile.
    804          */
    805         public abstract void onSendSessionModifyResponse(VideoProfile responseProfile);
    806 
    807         /**
    808          * Issues a request to the {@link VideoProvider} to retrieve the camera capabilities.
    809          * <p>
    810          * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
    811          * camera via
    812          * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
    813          * <p>
    814          * Sent from the {@link InCallService} via
    815          * {@link InCallService.VideoCall#requestCameraCapabilities()}.
    816          */
    817         public abstract void onRequestCameraCapabilities();
    818 
    819         /**
    820          * Issues a request to the {@link VideoProvider} to retrieve the current data usage for the
    821          * video component of the current {@link Connection}.
    822          * <p>
    823          * The {@link VideoProvider} should respond by communicating current data usage, in bytes,
    824          * via {@link VideoProvider#setCallDataUsage(long)}.
    825          * <p>
    826          * Sent from the {@link InCallService} via
    827          * {@link InCallService.VideoCall#requestCallDataUsage()}.
    828          */
    829         public abstract void onRequestConnectionDataUsage();
    830 
    831         /**
    832          * Provides the {@link VideoProvider} with the {@link Uri} of an image to be displayed to
    833          * the peer device when the video signal is paused.
    834          * <p>
    835          * Sent from the {@link InCallService} via
    836          * {@link InCallService.VideoCall#setPauseImage(Uri)}.
    837          *
    838          * @param uri URI of image to display.
    839          */
    840         public abstract void onSetPauseImage(Uri uri);
    841 
    842         /**
    843          * Used to inform listening {@link InCallService} implementations when the
    844          * {@link VideoProvider} receives a session modification request.
    845          * <p>
    846          * Received by the {@link InCallService} via
    847          * {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)},
    848          *
    849          * @param videoProfile The requested video profile.
    850          * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)
    851          */
    852         public void receiveSessionModifyRequest(VideoProfile videoProfile) {
    853             if (mVideoCallbacks != null) {
    854                 for (IVideoCallback callback : mVideoCallbacks.values()) {
    855                     try {
    856                         callback.receiveSessionModifyRequest(videoProfile);
    857                     } catch (RemoteException ignored) {
    858                         Log.w(this, "receiveSessionModifyRequest callback failed", ignored);
    859                     }
    860                 }
    861             }
    862         }
    863 
    864         /**
    865          * Used to inform listening {@link InCallService} implementations when the
    866          * {@link VideoProvider} receives a response to a session modification request.
    867          * <p>
    868          * Received by the {@link InCallService} via
    869          * {@link InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int,
    870          * VideoProfile, VideoProfile)}.
    871          *
    872          * @param status Status of the session modify request.  Valid values are
    873          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS},
    874          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_FAIL},
    875          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_INVALID},
    876          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_TIMED_OUT},
    877          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE}
    878          * @param requestedProfile The original request which was sent to the peer device.
    879          * @param responseProfile The actual profile changes agreed to by the peer device.
    880          * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)
    881          */
    882         public void receiveSessionModifyResponse(int status,
    883                 VideoProfile requestedProfile, VideoProfile responseProfile) {
    884             if (mVideoCallbacks != null) {
    885                 for (IVideoCallback callback : mVideoCallbacks.values()) {
    886                     try {
    887                         callback.receiveSessionModifyResponse(status, requestedProfile,
    888                                 responseProfile);
    889                     } catch (RemoteException ignored) {
    890                         Log.w(this, "receiveSessionModifyResponse callback failed", ignored);
    891                     }
    892                 }
    893             }
    894         }
    895 
    896         /**
    897          * Used to inform listening {@link InCallService} implementations when the
    898          * {@link VideoProvider} reports a call session event.
    899          * <p>
    900          * Received by the {@link InCallService} via
    901          * {@link InCallService.VideoCall.Callback#onCallSessionEvent(int)}.
    902          *
    903          * @param event The event.  Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE},
    904          *      {@link VideoProvider#SESSION_EVENT_RX_RESUME},
    905          *      {@link VideoProvider#SESSION_EVENT_TX_START},
    906          *      {@link VideoProvider#SESSION_EVENT_TX_STOP},
    907          *      {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
    908          *      {@link VideoProvider#SESSION_EVENT_CAMERA_READY}.
    909          */
    910         public void handleCallSessionEvent(int event) {
    911             if (mVideoCallbacks != null) {
    912                 for (IVideoCallback callback : mVideoCallbacks.values()) {
    913                     try {
    914                         callback.handleCallSessionEvent(event);
    915                     } catch (RemoteException ignored) {
    916                         Log.w(this, "handleCallSessionEvent callback failed", ignored);
    917                     }
    918                 }
    919             }
    920         }
    921 
    922         /**
    923          * Used to inform listening {@link InCallService} implementations when the dimensions of the
    924          * peer's video have changed.
    925          * <p>
    926          * This could occur if, for example, the peer rotates their device, changing the aspect
    927          * ratio of the video, or if the user switches between the back and front cameras.
    928          * <p>
    929          * Received by the {@link InCallService} via
    930          * {@link InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int)}.
    931          *
    932          * @param width  The updated peer video width.
    933          * @param height The updated peer video height.
    934          */
    935         public void changePeerDimensions(int width, int height) {
    936             if (mVideoCallbacks != null) {
    937                 for (IVideoCallback callback : mVideoCallbacks.values()) {
    938                     try {
    939                         callback.changePeerDimensions(width, height);
    940                     } catch (RemoteException ignored) {
    941                         Log.w(this, "changePeerDimensions callback failed", ignored);
    942                     }
    943                 }
    944             }
    945         }
    946 
    947         /**
    948          * Used to inform listening {@link InCallService} implementations when the data usage of the
    949          * video associated with the current {@link Connection} has changed.
    950          * <p>
    951          * This could be in response to a preview request via
    952          * {@link #onRequestConnectionDataUsage()}, or as a periodic update by the
    953          * {@link VideoProvider}.  Where periodic updates of data usage are provided, they should be
    954          * provided at most for every 1 MB of data transferred and no more than once every 10 sec.
    955          * <p>
    956          * Received by the {@link InCallService} via
    957          * {@link InCallService.VideoCall.Callback#onCallDataUsageChanged(long)}.
    958          *
    959          * @param dataUsage The updated data usage (in bytes).  Reported as the cumulative bytes
    960          *                  used since the start of the call.
    961          */
    962         public void setCallDataUsage(long dataUsage) {
    963             if (mVideoCallbacks != null) {
    964                 for (IVideoCallback callback : mVideoCallbacks.values()) {
    965                     try {
    966                         callback.changeCallDataUsage(dataUsage);
    967                     } catch (RemoteException ignored) {
    968                         Log.w(this, "setCallDataUsage callback failed", ignored);
    969                     }
    970                 }
    971             }
    972         }
    973 
    974         /**
    975          * @see #setCallDataUsage(long)
    976          *
    977          * @param dataUsage The updated data usage (in byes).
    978          * @deprecated - Use {@link #setCallDataUsage(long)} instead.
    979          * @hide
    980          */
    981         public void changeCallDataUsage(long dataUsage) {
    982             setCallDataUsage(dataUsage);
    983         }
    984 
    985         /**
    986          * Used to inform listening {@link InCallService} implementations when the capabilities of
    987          * the current camera have changed.
    988          * <p>
    989          * The {@link VideoProvider} should call this in response to
    990          * {@link VideoProvider#onRequestCameraCapabilities()}, or when the current camera is
    991          * changed via {@link VideoProvider#onSetCamera(String)}.
    992          * <p>
    993          * Received by the {@link InCallService} via
    994          * {@link InCallService.VideoCall.Callback#onCameraCapabilitiesChanged(
    995          * VideoProfile.CameraCapabilities)}.
    996          *
    997          * @param cameraCapabilities The new camera capabilities.
    998          */
    999         public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
   1000             if (mVideoCallbacks != null) {
   1001                 for (IVideoCallback callback : mVideoCallbacks.values()) {
   1002                     try {
   1003                         callback.changeCameraCapabilities(cameraCapabilities);
   1004                     } catch (RemoteException ignored) {
   1005                         Log.w(this, "changeCameraCapabilities callback failed", ignored);
   1006                     }
   1007                 }
   1008             }
   1009         }
   1010 
   1011         /**
   1012          * Used to inform listening {@link InCallService} implementations when the video quality
   1013          * of the call has changed.
   1014          * <p>
   1015          * Received by the {@link InCallService} via
   1016          * {@link InCallService.VideoCall.Callback#onVideoQualityChanged(int)}.
   1017          *
   1018          * @param videoQuality The updated video quality.  Valid values:
   1019          *      {@link VideoProfile#QUALITY_HIGH},
   1020          *      {@link VideoProfile#QUALITY_MEDIUM},
   1021          *      {@link VideoProfile#QUALITY_LOW},
   1022          *      {@link VideoProfile#QUALITY_DEFAULT}.
   1023          */
   1024         public void changeVideoQuality(int videoQuality) {
   1025             if (mVideoCallbacks != null) {
   1026                 for (IVideoCallback callback : mVideoCallbacks.values()) {
   1027                     try {
   1028                         callback.changeVideoQuality(videoQuality);
   1029                     } catch (RemoteException ignored) {
   1030                         Log.w(this, "changeVideoQuality callback failed", ignored);
   1031                     }
   1032                 }
   1033             }
   1034         }
   1035     }
   1036 
   1037     private final Listener mConnectionDeathListener = new Listener() {
   1038         @Override
   1039         public void onDestroyed(Connection c) {
   1040             if (mConferenceables.remove(c)) {
   1041                 fireOnConferenceableConnectionsChanged();
   1042             }
   1043         }
   1044     };
   1045 
   1046     private final Conference.Listener mConferenceDeathListener = new Conference.Listener() {
   1047         @Override
   1048         public void onDestroyed(Conference c) {
   1049             if (mConferenceables.remove(c)) {
   1050                 fireOnConferenceableConnectionsChanged();
   1051             }
   1052         }
   1053     };
   1054 
   1055     /**
   1056      * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
   1057      * load factor before resizing, 1 means we only expect a single thread to
   1058      * access the map so make only a single shard
   1059      */
   1060     private final Set<Listener> mListeners = Collections.newSetFromMap(
   1061             new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
   1062     private final List<Conferenceable> mConferenceables = new ArrayList<>();
   1063     private final List<Conferenceable> mUnmodifiableConferenceables =
   1064             Collections.unmodifiableList(mConferenceables);
   1065 
   1066     private int mState = STATE_NEW;
   1067     private CallAudioState mCallAudioState;
   1068     private Uri mAddress;
   1069     private int mAddressPresentation;
   1070     private String mCallerDisplayName;
   1071     private int mCallerDisplayNamePresentation;
   1072     private boolean mRingbackRequested = false;
   1073     private int mConnectionCapabilities;
   1074     private VideoProvider mVideoProvider;
   1075     private boolean mAudioModeIsVoip;
   1076     private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
   1077     private StatusHints mStatusHints;
   1078     private int mVideoState;
   1079     private DisconnectCause mDisconnectCause;
   1080     private Conference mConference;
   1081     private ConnectionService mConnectionService;
   1082     private Bundle mExtras;
   1083 
   1084     /**
   1085      * Create a new Connection.
   1086      */
   1087     public Connection() {}
   1088 
   1089     /**
   1090      * @return The address (e.g., phone number) to which this Connection is currently communicating.
   1091      */
   1092     public final Uri getAddress() {
   1093         return mAddress;
   1094     }
   1095 
   1096     /**
   1097      * @return The presentation requirements for the address.
   1098      *         See {@link TelecomManager} for valid values.
   1099      */
   1100     public final int getAddressPresentation() {
   1101         return mAddressPresentation;
   1102     }
   1103 
   1104     /**
   1105      * @return The caller display name (CNAP).
   1106      */
   1107     public final String getCallerDisplayName() {
   1108         return mCallerDisplayName;
   1109     }
   1110 
   1111     /**
   1112      * @return The presentation requirements for the handle.
   1113      *         See {@link TelecomManager} for valid values.
   1114      */
   1115     public final int getCallerDisplayNamePresentation() {
   1116         return mCallerDisplayNamePresentation;
   1117     }
   1118 
   1119     /**
   1120      * @return The state of this Connection.
   1121      */
   1122     public final int getState() {
   1123         return mState;
   1124     }
   1125 
   1126     /**
   1127      * Returns the video state of the connection.
   1128      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
   1129      * {@link VideoProfile#STATE_BIDIRECTIONAL},
   1130      * {@link VideoProfile#STATE_TX_ENABLED},
   1131      * {@link VideoProfile#STATE_RX_ENABLED}.
   1132      *
   1133      * @return The video state of the connection.
   1134      * @hide
   1135      */
   1136     public final int getVideoState() {
   1137         return mVideoState;
   1138     }
   1139 
   1140     /**
   1141      * @return The audio state of the connection, describing how its audio is currently
   1142      *         being routed by the system. This is {@code null} if this Connection
   1143      *         does not directly know about its audio state.
   1144      * @deprecated Use {@link #getCallAudioState()} instead.
   1145      * @hide
   1146      */
   1147     @SystemApi
   1148     @Deprecated
   1149     public final AudioState getAudioState() {
   1150         if (mCallAudioState == null) {
   1151           return null;
   1152         }
   1153         return new AudioState(mCallAudioState);
   1154     }
   1155 
   1156     /**
   1157      * @return The audio state of the connection, describing how its audio is currently
   1158      *         being routed by the system. This is {@code null} if this Connection
   1159      *         does not directly know about its audio state.
   1160      */
   1161     public final CallAudioState getCallAudioState() {
   1162         return mCallAudioState;
   1163     }
   1164 
   1165     /**
   1166      * @return The conference that this connection is a part of.  Null if it is not part of any
   1167      *         conference.
   1168      */
   1169     public final Conference getConference() {
   1170         return mConference;
   1171     }
   1172 
   1173     /**
   1174      * Returns whether this connection is requesting that the system play a ringback tone
   1175      * on its behalf.
   1176      */
   1177     public final boolean isRingbackRequested() {
   1178         return mRingbackRequested;
   1179     }
   1180 
   1181     /**
   1182      * @return True if the connection's audio mode is VOIP.
   1183      */
   1184     public final boolean getAudioModeIsVoip() {
   1185         return mAudioModeIsVoip;
   1186     }
   1187 
   1188     /**
   1189      * Retrieves the connection start time of the {@code Connnection}, if specified.  A value of
   1190      * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the
   1191      * start time of the conference.
   1192      *
   1193      * @return The time at which the {@code Connnection} was connected.
   1194      *
   1195      * @hide
   1196      */
   1197     public final long getConnectTimeMillis() {
   1198         return mConnectTimeMillis;
   1199     }
   1200 
   1201     /**
   1202      * @return The status hints for this connection.
   1203      */
   1204     public final StatusHints getStatusHints() {
   1205         return mStatusHints;
   1206     }
   1207 
   1208     /**
   1209      * @return The extras associated with this connection.
   1210      */
   1211     public final Bundle getExtras() {
   1212         return mExtras;
   1213     }
   1214 
   1215     /**
   1216      * Assign a listener to be notified of state changes.
   1217      *
   1218      * @param l A listener.
   1219      * @return This Connection.
   1220      *
   1221      * @hide
   1222      */
   1223     public final Connection addConnectionListener(Listener l) {
   1224         mListeners.add(l);
   1225         return this;
   1226     }
   1227 
   1228     /**
   1229      * Remove a previously assigned listener that was being notified of state changes.
   1230      *
   1231      * @param l A Listener.
   1232      * @return This Connection.
   1233      *
   1234      * @hide
   1235      */
   1236     public final Connection removeConnectionListener(Listener l) {
   1237         if (l != null) {
   1238             mListeners.remove(l);
   1239         }
   1240         return this;
   1241     }
   1242 
   1243     /**
   1244      * @return The {@link DisconnectCause} for this connection.
   1245      */
   1246     public final DisconnectCause getDisconnectCause() {
   1247         return mDisconnectCause;
   1248     }
   1249 
   1250     /**
   1251      * Inform this Connection that the state of its audio output has been changed externally.
   1252      *
   1253      * @param state The new audio state.
   1254      * @hide
   1255      */
   1256     final void setCallAudioState(CallAudioState state) {
   1257         checkImmutable();
   1258         Log.d(this, "setAudioState %s", state);
   1259         mCallAudioState = state;
   1260         onAudioStateChanged(getAudioState());
   1261         onCallAudioStateChanged(state);
   1262     }
   1263 
   1264     /**
   1265      * @param state An integer value of a {@code STATE_*} constant.
   1266      * @return A string representation of the value.
   1267      */
   1268     public static String stateToString(int state) {
   1269         switch (state) {
   1270             case STATE_INITIALIZING:
   1271                 return "INITIALIZING";
   1272             case STATE_NEW:
   1273                 return "NEW";
   1274             case STATE_RINGING:
   1275                 return "RINGING";
   1276             case STATE_DIALING:
   1277                 return "DIALING";
   1278             case STATE_ACTIVE:
   1279                 return "ACTIVE";
   1280             case STATE_HOLDING:
   1281                 return "HOLDING";
   1282             case STATE_DISCONNECTED:
   1283                 return "DISCONNECTED";
   1284             default:
   1285                 Log.wtf(Connection.class, "Unknown state %d", state);
   1286                 return "UNKNOWN";
   1287         }
   1288     }
   1289 
   1290     /**
   1291      * Returns the connection's capabilities, as a bit mask of the {@code CAPABILITY_*} constants.
   1292      */
   1293     public final int getConnectionCapabilities() {
   1294         return mConnectionCapabilities;
   1295     }
   1296 
   1297     /**
   1298      * Sets the value of the {@link #getAddress()} property.
   1299      *
   1300      * @param address The new address.
   1301      * @param presentation The presentation requirements for the address.
   1302      *        See {@link TelecomManager} for valid values.
   1303      */
   1304     public final void setAddress(Uri address, int presentation) {
   1305         checkImmutable();
   1306         Log.d(this, "setAddress %s", address);
   1307         mAddress = address;
   1308         mAddressPresentation = presentation;
   1309         for (Listener l : mListeners) {
   1310             l.onAddressChanged(this, address, presentation);
   1311         }
   1312     }
   1313 
   1314     /**
   1315      * Sets the caller display name (CNAP).
   1316      *
   1317      * @param callerDisplayName The new display name.
   1318      * @param presentation The presentation requirements for the handle.
   1319      *        See {@link TelecomManager} for valid values.
   1320      */
   1321     public final void setCallerDisplayName(String callerDisplayName, int presentation) {
   1322         checkImmutable();
   1323         Log.d(this, "setCallerDisplayName %s", callerDisplayName);
   1324         mCallerDisplayName = callerDisplayName;
   1325         mCallerDisplayNamePresentation = presentation;
   1326         for (Listener l : mListeners) {
   1327             l.onCallerDisplayNameChanged(this, callerDisplayName, presentation);
   1328         }
   1329     }
   1330 
   1331     /**
   1332      * Set the video state for the connection.
   1333      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
   1334      * {@link VideoProfile#STATE_BIDIRECTIONAL},
   1335      * {@link VideoProfile#STATE_TX_ENABLED},
   1336      * {@link VideoProfile#STATE_RX_ENABLED}.
   1337      *
   1338      * @param videoState The new video state.
   1339      */
   1340     public final void setVideoState(int videoState) {
   1341         checkImmutable();
   1342         Log.d(this, "setVideoState %d", videoState);
   1343         mVideoState = videoState;
   1344         for (Listener l : mListeners) {
   1345             l.onVideoStateChanged(this, mVideoState);
   1346         }
   1347     }
   1348 
   1349     /**
   1350      * Sets state to active (e.g., an ongoing connection where two or more parties can actively
   1351      * communicate).
   1352      */
   1353     public final void setActive() {
   1354         checkImmutable();
   1355         setRingbackRequested(false);
   1356         setState(STATE_ACTIVE);
   1357     }
   1358 
   1359     /**
   1360      * Sets state to ringing (e.g., an inbound ringing connection).
   1361      */
   1362     public final void setRinging() {
   1363         checkImmutable();
   1364         setState(STATE_RINGING);
   1365     }
   1366 
   1367     /**
   1368      * Sets state to initializing (this Connection is not yet ready to be used).
   1369      */
   1370     public final void setInitializing() {
   1371         checkImmutable();
   1372         setState(STATE_INITIALIZING);
   1373     }
   1374 
   1375     /**
   1376      * Sets state to initialized (the Connection has been set up and is now ready to be used).
   1377      */
   1378     public final void setInitialized() {
   1379         checkImmutable();
   1380         setState(STATE_NEW);
   1381     }
   1382 
   1383     /**
   1384      * Sets state to dialing (e.g., dialing an outbound connection).
   1385      */
   1386     public final void setDialing() {
   1387         checkImmutable();
   1388         setState(STATE_DIALING);
   1389     }
   1390 
   1391     /**
   1392      * Sets state to be on hold.
   1393      */
   1394     public final void setOnHold() {
   1395         checkImmutable();
   1396         setState(STATE_HOLDING);
   1397     }
   1398 
   1399     /**
   1400      * Sets the video connection provider.
   1401      * @param videoProvider The video provider.
   1402      */
   1403     public final void setVideoProvider(VideoProvider videoProvider) {
   1404         checkImmutable();
   1405         mVideoProvider = videoProvider;
   1406         for (Listener l : mListeners) {
   1407             l.onVideoProviderChanged(this, videoProvider);
   1408         }
   1409     }
   1410 
   1411     public final VideoProvider getVideoProvider() {
   1412         return mVideoProvider;
   1413     }
   1414 
   1415     /**
   1416      * Sets state to disconnected.
   1417      *
   1418      * @param disconnectCause The reason for the disconnection, as specified by
   1419      *         {@link DisconnectCause}.
   1420      */
   1421     public final void setDisconnected(DisconnectCause disconnectCause) {
   1422         checkImmutable();
   1423         mDisconnectCause = disconnectCause;
   1424         setState(STATE_DISCONNECTED);
   1425         Log.d(this, "Disconnected with cause %s", disconnectCause);
   1426         for (Listener l : mListeners) {
   1427             l.onDisconnected(this, disconnectCause);
   1428         }
   1429     }
   1430 
   1431     /**
   1432      * Informs listeners that this {@code Connection} is in a post-dial wait state. This is done
   1433      * when (a) the {@code Connection} is issuing a DTMF sequence; (b) it has encountered a "wait"
   1434      * character; and (c) it wishes to inform the In-Call app that it is waiting for the end-user
   1435      * to send an {@link #onPostDialContinue(boolean)} signal.
   1436      *
   1437      * @param remaining The DTMF character sequence remaining to be emitted once the
   1438      *         {@link #onPostDialContinue(boolean)} is received, including any "wait" characters
   1439      *         that remaining sequence may contain.
   1440      */
   1441     public final void setPostDialWait(String remaining) {
   1442         checkImmutable();
   1443         for (Listener l : mListeners) {
   1444             l.onPostDialWait(this, remaining);
   1445         }
   1446     }
   1447 
   1448     /**
   1449      * Informs listeners that this {@code Connection} has processed a character in the post-dial
   1450      * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence;
   1451      * and (b) it wishes to signal Telecom to play the corresponding DTMF tone locally.
   1452      *
   1453      * @param nextChar The DTMF character that was just processed by the {@code Connection}.
   1454      */
   1455     public final void setNextPostDialChar(char nextChar) {
   1456         checkImmutable();
   1457         for (Listener l : mListeners) {
   1458             l.onPostDialChar(this, nextChar);
   1459         }
   1460     }
   1461 
   1462     /**
   1463      * Requests that the framework play a ringback tone. This is to be invoked by implementations
   1464      * that do not play a ringback tone themselves in the connection's audio stream.
   1465      *
   1466      * @param ringback Whether the ringback tone is to be played.
   1467      */
   1468     public final void setRingbackRequested(boolean ringback) {
   1469         checkImmutable();
   1470         if (mRingbackRequested != ringback) {
   1471             mRingbackRequested = ringback;
   1472             for (Listener l : mListeners) {
   1473                 l.onRingbackRequested(this, ringback);
   1474             }
   1475         }
   1476     }
   1477 
   1478     /**
   1479      * Sets the connection's capabilities as a bit mask of the {@code CAPABILITY_*} constants.
   1480      *
   1481      * @param connectionCapabilities The new connection capabilities.
   1482      */
   1483     public final void setConnectionCapabilities(int connectionCapabilities) {
   1484         checkImmutable();
   1485         if (mConnectionCapabilities != connectionCapabilities) {
   1486             mConnectionCapabilities = connectionCapabilities;
   1487             for (Listener l : mListeners) {
   1488                 l.onConnectionCapabilitiesChanged(this, mConnectionCapabilities);
   1489             }
   1490         }
   1491     }
   1492 
   1493     /**
   1494      * Tears down the Connection object.
   1495      */
   1496     public final void destroy() {
   1497         for (Listener l : mListeners) {
   1498             l.onDestroyed(this);
   1499         }
   1500     }
   1501 
   1502     /**
   1503      * Requests that the framework use VOIP audio mode for this connection.
   1504      *
   1505      * @param isVoip True if the audio mode is VOIP.
   1506      */
   1507     public final void setAudioModeIsVoip(boolean isVoip) {
   1508         checkImmutable();
   1509         mAudioModeIsVoip = isVoip;
   1510         for (Listener l : mListeners) {
   1511             l.onAudioModeIsVoipChanged(this, isVoip);
   1512         }
   1513     }
   1514 
   1515     /**
   1516      * Sets the time at which a call became active on this Connection. This is set only
   1517      * when a conference call becomes active on this connection.
   1518      *
   1519      * @param connectionTimeMillis The connection time, in milliseconds.
   1520      *
   1521      * @hide
   1522      */
   1523     public final void setConnectTimeMillis(long connectTimeMillis) {
   1524         mConnectTimeMillis = connectTimeMillis;
   1525     }
   1526 
   1527     /**
   1528      * Sets the label and icon status to display in the in-call UI.
   1529      *
   1530      * @param statusHints The status label and icon to set.
   1531      */
   1532     public final void setStatusHints(StatusHints statusHints) {
   1533         checkImmutable();
   1534         mStatusHints = statusHints;
   1535         for (Listener l : mListeners) {
   1536             l.onStatusHintsChanged(this, statusHints);
   1537         }
   1538     }
   1539 
   1540     /**
   1541      * Sets the connections with which this connection can be conferenced.
   1542      *
   1543      * @param conferenceableConnections The set of connections this connection can conference with.
   1544      */
   1545     public final void setConferenceableConnections(List<Connection> conferenceableConnections) {
   1546         checkImmutable();
   1547         clearConferenceableList();
   1548         for (Connection c : conferenceableConnections) {
   1549             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
   1550             // small amount of items here.
   1551             if (!mConferenceables.contains(c)) {
   1552                 c.addConnectionListener(mConnectionDeathListener);
   1553                 mConferenceables.add(c);
   1554             }
   1555         }
   1556         fireOnConferenceableConnectionsChanged();
   1557     }
   1558 
   1559     /**
   1560      * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections
   1561      * or conferences with which this connection can be conferenced.
   1562      *
   1563      * @param conferenceables The conferenceables.
   1564      */
   1565     public final void setConferenceables(List<Conferenceable> conferenceables) {
   1566         clearConferenceableList();
   1567         for (Conferenceable c : conferenceables) {
   1568             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
   1569             // small amount of items here.
   1570             if (!mConferenceables.contains(c)) {
   1571                 if (c instanceof Connection) {
   1572                     Connection connection = (Connection) c;
   1573                     connection.addConnectionListener(mConnectionDeathListener);
   1574                 } else if (c instanceof Conference) {
   1575                     Conference conference = (Conference) c;
   1576                     conference.addListener(mConferenceDeathListener);
   1577                 }
   1578                 mConferenceables.add(c);
   1579             }
   1580         }
   1581         fireOnConferenceableConnectionsChanged();
   1582     }
   1583 
   1584     /**
   1585      * Returns the connections or conferences with which this connection can be conferenced.
   1586      */
   1587     public final List<Conferenceable> getConferenceables() {
   1588         return mUnmodifiableConferenceables;
   1589     }
   1590 
   1591     /**
   1592      * @hide
   1593      */
   1594     public final void setConnectionService(ConnectionService connectionService) {
   1595         checkImmutable();
   1596         if (mConnectionService != null) {
   1597             Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " +
   1598                     "which is already associated with another ConnectionService.");
   1599         } else {
   1600             mConnectionService = connectionService;
   1601         }
   1602     }
   1603 
   1604     /**
   1605      * @hide
   1606      */
   1607     public final void unsetConnectionService(ConnectionService connectionService) {
   1608         if (mConnectionService != connectionService) {
   1609             Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " +
   1610                     "that does not belong to the ConnectionService.");
   1611         } else {
   1612             mConnectionService = null;
   1613         }
   1614     }
   1615 
   1616     /**
   1617      * @hide
   1618      */
   1619     public final ConnectionService getConnectionService() {
   1620         return mConnectionService;
   1621     }
   1622 
   1623     /**
   1624      * Sets the conference that this connection is a part of. This will fail if the connection is
   1625      * already part of a conference. {@link #resetConference} to un-set the conference first.
   1626      *
   1627      * @param conference The conference.
   1628      * @return {@code true} if the conference was successfully set.
   1629      * @hide
   1630      */
   1631     public final boolean setConference(Conference conference) {
   1632         checkImmutable();
   1633         // We check to see if it is already part of another conference.
   1634         if (mConference == null) {
   1635             mConference = conference;
   1636             if (mConnectionService != null && mConnectionService.containsConference(conference)) {
   1637                 fireConferenceChanged();
   1638             }
   1639             return true;
   1640         }
   1641         return false;
   1642     }
   1643 
   1644     /**
   1645      * Resets the conference that this connection is a part of.
   1646      * @hide
   1647      */
   1648     public final void resetConference() {
   1649         if (mConference != null) {
   1650             Log.d(this, "Conference reset");
   1651             mConference = null;
   1652             fireConferenceChanged();
   1653         }
   1654     }
   1655 
   1656     /**
   1657      * Set some extras that can be associated with this {@code Connection}. No assumptions should
   1658      * be made as to how an In-Call UI or service will handle these extras.
   1659      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
   1660      *
   1661      * @param extras The extras associated with this {@code Connection}.
   1662      */
   1663     public final void setExtras(@Nullable Bundle extras) {
   1664         checkImmutable();
   1665         mExtras = extras;
   1666         for (Listener l : mListeners) {
   1667             l.onExtrasChanged(this, extras);
   1668         }
   1669     }
   1670 
   1671     /**
   1672      * Notifies this Connection that the {@link #getAudioState()} property has a new value.
   1673      *
   1674      * @param state The new connection audio state.
   1675      * @deprecated Use {@link #onCallAudioStateChanged(CallAudioState)} instead.
   1676      * @hide
   1677      */
   1678     @SystemApi
   1679     @Deprecated
   1680     public void onAudioStateChanged(AudioState state) {}
   1681 
   1682     /**
   1683      * Notifies this Connection that the {@link #getCallAudioState()} property has a new value.
   1684      *
   1685      * @param state The new connection audio state.
   1686      */
   1687     public void onCallAudioStateChanged(CallAudioState state) {}
   1688 
   1689     /**
   1690      * Notifies this Connection of an internal state change. This method is called after the
   1691      * state is changed.
   1692      *
   1693      * @param state The new state, one of the {@code STATE_*} constants.
   1694      */
   1695     public void onStateChanged(int state) {}
   1696 
   1697     /**
   1698      * Notifies this Connection of a request to play a DTMF tone.
   1699      *
   1700      * @param c A DTMF character.
   1701      */
   1702     public void onPlayDtmfTone(char c) {}
   1703 
   1704     /**
   1705      * Notifies this Connection of a request to stop any currently playing DTMF tones.
   1706      */
   1707     public void onStopDtmfTone() {}
   1708 
   1709     /**
   1710      * Notifies this Connection of a request to disconnect.
   1711      */
   1712     public void onDisconnect() {}
   1713 
   1714     /**
   1715      * Notifies this Connection of a request to disconnect a participant of the conference managed
   1716      * by the connection.
   1717      *
   1718      * @param endpoint the {@link Uri} of the participant to disconnect.
   1719      * @hide
   1720      */
   1721     public void onDisconnectConferenceParticipant(Uri endpoint) {}
   1722 
   1723     /**
   1724      * Notifies this Connection of a request to separate from its parent conference.
   1725      */
   1726     public void onSeparate() {}
   1727 
   1728     /**
   1729      * Notifies this Connection of a request to abort.
   1730      */
   1731     public void onAbort() {}
   1732 
   1733     /**
   1734      * Notifies this Connection of a request to hold.
   1735      */
   1736     public void onHold() {}
   1737 
   1738     /**
   1739      * Notifies this Connection of a request to exit a hold state.
   1740      */
   1741     public void onUnhold() {}
   1742 
   1743     /**
   1744      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
   1745      * a request to accept.
   1746      *
   1747      * @param videoState The video state in which to answer the connection.
   1748      */
   1749     public void onAnswer(int videoState) {}
   1750 
   1751     /**
   1752      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
   1753      * a request to accept.
   1754      */
   1755     public void onAnswer() {
   1756         onAnswer(VideoProfile.STATE_AUDIO_ONLY);
   1757     }
   1758 
   1759     /**
   1760      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
   1761      * a request to reject.
   1762      */
   1763     public void onReject() {}
   1764 
   1765     /**
   1766      * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
   1767      */
   1768     public void onPostDialContinue(boolean proceed) {}
   1769 
   1770     static String toLogSafePhoneNumber(String number) {
   1771         // For unknown number, log empty string.
   1772         if (number == null) {
   1773             return "";
   1774         }
   1775 
   1776         if (PII_DEBUG) {
   1777             // When PII_DEBUG is true we emit PII.
   1778             return number;
   1779         }
   1780 
   1781         // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
   1782         // sanitized phone numbers.
   1783         StringBuilder builder = new StringBuilder();
   1784         for (int i = 0; i < number.length(); i++) {
   1785             char c = number.charAt(i);
   1786             if (c == '-' || c == '@' || c == '.') {
   1787                 builder.append(c);
   1788             } else {
   1789                 builder.append('x');
   1790             }
   1791         }
   1792         return builder.toString();
   1793     }
   1794 
   1795     private void setState(int state) {
   1796         checkImmutable();
   1797         if (mState == STATE_DISCONNECTED && mState != state) {
   1798             Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state.");
   1799             return;
   1800         }
   1801         if (mState != state) {
   1802             Log.d(this, "setState: %s", stateToString(state));
   1803             mState = state;
   1804             onStateChanged(state);
   1805             for (Listener l : mListeners) {
   1806                 l.onStateChanged(this, state);
   1807             }
   1808         }
   1809     }
   1810 
   1811     private static class FailureSignalingConnection extends Connection {
   1812         private boolean mImmutable = false;
   1813         public FailureSignalingConnection(DisconnectCause disconnectCause) {
   1814             setDisconnected(disconnectCause);
   1815             mImmutable = true;
   1816         }
   1817 
   1818         public void checkImmutable() {
   1819             if (mImmutable) {
   1820                 throw new UnsupportedOperationException("Connection is immutable");
   1821             }
   1822         }
   1823     }
   1824 
   1825     /**
   1826      * Return a {@code Connection} which represents a failed connection attempt. The returned
   1827      * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified,
   1828      * and a {@link #getState()} of {@link #STATE_DISCONNECTED}.
   1829      * <p>
   1830      * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate,
   1831      * so users of this method need not maintain a reference to its return value to destroy it.
   1832      *
   1833      * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
   1834      * @return A {@code Connection} which indicates failure.
   1835      */
   1836     public static Connection createFailedConnection(DisconnectCause disconnectCause) {
   1837         return new FailureSignalingConnection(disconnectCause);
   1838     }
   1839 
   1840     /**
   1841      * Override to throw an {@link UnsupportedOperationException} if this {@code Connection} is
   1842      * not intended to be mutated, e.g., if it is a marker for failure. Only for framework use;
   1843      * this should never be un-@hide-den.
   1844      *
   1845      * @hide
   1846      */
   1847     public void checkImmutable() {}
   1848 
   1849     /**
   1850      * Return a {@code Connection} which represents a canceled connection attempt. The returned
   1851      * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of
   1852      * that state. This connection should not be used for anything, and no other
   1853      * {@code Connection}s should be attempted.
   1854      * <p>
   1855      * so users of this method need not maintain a reference to its return value to destroy it.
   1856      *
   1857      * @return A {@code Connection} which indicates that the underlying connection should
   1858      * be canceled.
   1859      */
   1860     public static Connection createCanceledConnection() {
   1861         return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED));
   1862     }
   1863 
   1864     private final void fireOnConferenceableConnectionsChanged() {
   1865         for (Listener l : mListeners) {
   1866             l.onConferenceablesChanged(this, getConferenceables());
   1867         }
   1868     }
   1869 
   1870     private final void fireConferenceChanged() {
   1871         for (Listener l : mListeners) {
   1872             l.onConferenceChanged(this, mConference);
   1873         }
   1874     }
   1875 
   1876     private final void clearConferenceableList() {
   1877         for (Conferenceable c : mConferenceables) {
   1878             if (c instanceof Connection) {
   1879                 Connection connection = (Connection) c;
   1880                 connection.removeConnectionListener(mConnectionDeathListener);
   1881             } else if (c instanceof Conference) {
   1882                 Conference conference = (Conference) c;
   1883                 conference.removeListener(mConferenceDeathListener);
   1884             }
   1885         }
   1886         mConferenceables.clear();
   1887     }
   1888 
   1889     /**
   1890      * Notifies listeners that the merge request failed.
   1891      *
   1892      * @hide
   1893      */
   1894     protected final void notifyConferenceMergeFailed() {
   1895         for (Listener l : mListeners) {
   1896             l.onConferenceMergeFailed(this);
   1897         }
   1898     }
   1899 
   1900     /**
   1901      * Notifies listeners of a change to conference participant(s).
   1902      *
   1903      * @param conferenceParticipants The participants.
   1904      * @hide
   1905      */
   1906     protected final void updateConferenceParticipants(
   1907             List<ConferenceParticipant> conferenceParticipants) {
   1908         for (Listener l : mListeners) {
   1909             l.onConferenceParticipantsChanged(this, conferenceParticipants);
   1910         }
   1911     }
   1912 
   1913     /**
   1914      * Notifies listeners that a conference call has been started.
   1915      * @hide
   1916      */
   1917     protected void notifyConferenceStarted() {
   1918         for (Listener l : mListeners) {
   1919             l.onConferenceStarted();
   1920         }
   1921     }
   1922 }
   1923