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.telecom.IConnectionService;
     20 import com.android.internal.telecom.IVideoCallback;
     21 import com.android.internal.telecom.IVideoProvider;
     22 
     23 import android.annotation.SystemApi;
     24 import android.net.Uri;
     25 import android.os.IBinder;
     26 import android.os.RemoteException;
     27 import android.view.Surface;
     28 
     29 import java.util.ArrayList;
     30 import java.util.Collections;
     31 import java.util.List;
     32 import java.util.Set;
     33 import java.util.concurrent.ConcurrentHashMap;
     34 
     35 /**
     36  * A connection provided to a {@link ConnectionService} by another {@code ConnectionService}
     37  * running in a different process.
     38  *
     39  * @see ConnectionService#createRemoteOutgoingConnection(PhoneAccountHandle, ConnectionRequest)
     40  * @see ConnectionService#createRemoteIncomingConnection(PhoneAccountHandle, ConnectionRequest)
     41  * @hide
     42  */
     43 @SystemApi
     44 public final class RemoteConnection {
     45 
     46     public static abstract class Callback {
     47         /**
     48          * Invoked when the state of this {@code RemoteConnection} has changed. See
     49          * {@link #getState()}.
     50          *
     51          * @param connection The {@code RemoteConnection} invoking this method.
     52          * @param state The new state of the {@code RemoteConnection}.
     53          */
     54         public void onStateChanged(RemoteConnection connection, int state) {}
     55 
     56         /**
     57          * Invoked when this {@code RemoteConnection} is disconnected.
     58          *
     59          * @param connection The {@code RemoteConnection} invoking this method.
     60          * @param disconnectCause The ({@see DisconnectCause}) associated with this failed
     61          *     connection.
     62          */
     63         public void onDisconnected(
     64                 RemoteConnection connection,
     65                 DisconnectCause disconnectCause) {}
     66 
     67         /**
     68          * Invoked when this {@code RemoteConnection} is requesting ringback. See
     69          * {@link #isRingbackRequested()}.
     70          *
     71          * @param connection The {@code RemoteConnection} invoking this method.
     72          * @param ringback Whether the {@code RemoteConnection} is requesting ringback.
     73          */
     74         public void onRingbackRequested(RemoteConnection connection, boolean ringback) {}
     75 
     76         /**
     77          * Indicates that the call capabilities of this {@code RemoteConnection} have changed.
     78          * See {@link #getCallCapabilities()}.
     79          *
     80          * @param connection The {@code RemoteConnection} invoking this method.
     81          * @param callCapabilities The new call capabilities of the {@code RemoteConnection}.
     82          */
     83         public void onCallCapabilitiesChanged(RemoteConnection connection, int callCapabilities) {}
     84 
     85         /**
     86          * Invoked when the post-dial sequence in the outgoing {@code Connection} has reached a
     87          * pause character. This causes the post-dial signals to stop pending user confirmation. An
     88          * implementation should present this choice to the user and invoke
     89          * {@link RemoteConnection#postDialContinue(boolean)} when the user makes the choice.
     90          *
     91          * @param connection The {@code RemoteConnection} invoking this method.
     92          * @param remainingPostDialSequence The post-dial characters that remain to be sent.
     93          */
     94         public void onPostDialWait(RemoteConnection connection, String remainingPostDialSequence) {}
     95 
     96         /**
     97          * Indicates that the VOIP audio status of this {@code RemoteConnection} has changed.
     98          * See {@link #isVoipAudioMode()}.
     99          *
    100          * @param connection The {@code RemoteConnection} invoking this method.
    101          * @param isVoip Whether the new audio state of the {@code RemoteConnection} is VOIP.
    102          */
    103         public void onVoipAudioChanged(RemoteConnection connection, boolean isVoip) {}
    104 
    105         /**
    106          * Indicates that the status hints of this {@code RemoteConnection} have changed. See
    107          * {@link #getStatusHints()} ()}.
    108          *
    109          * @param connection The {@code RemoteConnection} invoking this method.
    110          * @param statusHints The new status hints of the {@code RemoteConnection}.
    111          */
    112         public void onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints) {}
    113 
    114         /**
    115          * Indicates that the address (e.g., phone number) of this {@code RemoteConnection} has
    116          * changed. See {@link #getAddress()} and {@link #getAddressPresentation()}.
    117          *
    118          * @param connection The {@code RemoteConnection} invoking this method.
    119          * @param address The new address of the {@code RemoteConnection}.
    120          * @param presentation The presentation requirements for the address.
    121          *        See {@link TelecomManager} for valid values.
    122          */
    123         public void onAddressChanged(RemoteConnection connection, Uri address, int presentation) {}
    124 
    125         /**
    126          * Indicates that the caller display name of this {@code RemoteConnection} has changed.
    127          * See {@link #getCallerDisplayName()} and {@link #getCallerDisplayNamePresentation()}.
    128          *
    129          * @param connection The {@code RemoteConnection} invoking this method.
    130          * @param callerDisplayName The new caller display name of the {@code RemoteConnection}.
    131          * @param presentation The presentation requirements for the handle.
    132          *        See {@link TelecomManager} for valid values.
    133          */
    134         public void onCallerDisplayNameChanged(
    135                 RemoteConnection connection, String callerDisplayName, int presentation) {}
    136 
    137         /**
    138          * Indicates that the video state of this {@code RemoteConnection} has changed.
    139          * See {@link #getVideoState()}.
    140          *
    141          * @param connection The {@code RemoteConnection} invoking this method.
    142          * @param videoState The new video state of the {@code RemoteConnection}.
    143          * @hide
    144          */
    145         public void onVideoStateChanged(RemoteConnection connection, int videoState) {}
    146 
    147         /**
    148          * Indicates that this {@code RemoteConnection} has been destroyed. No further requests
    149          * should be made to the {@code RemoteConnection}, and references to it should be cleared.
    150          *
    151          * @param connection The {@code RemoteConnection} invoking this method.
    152          */
    153         public void onDestroyed(RemoteConnection connection) {}
    154 
    155         /**
    156          * Indicates that the {@code RemoteConnection}s with which this {@code RemoteConnection}
    157          * may be asked to create a conference has changed.
    158          *
    159          * @param connection The {@code RemoteConnection} invoking this method.
    160          * @param conferenceableConnections The {@code RemoteConnection}s with which this
    161          *         {@code RemoteConnection} may be asked to create a conference.
    162          */
    163         public void onConferenceableConnectionsChanged(
    164                 RemoteConnection connection,
    165                 List<RemoteConnection> conferenceableConnections) {}
    166 
    167         /**
    168          * Indicates that the {@code VideoProvider} associated with this {@code RemoteConnection}
    169          * has changed.
    170          *
    171          * @param connection The {@code RemoteConnection} invoking this method.
    172          * @param videoProvider The new {@code VideoProvider} associated with this
    173          *         {@code RemoteConnection}.
    174          * @hide
    175          */
    176         public void onVideoProviderChanged(
    177                 RemoteConnection connection, VideoProvider videoProvider) {}
    178 
    179         /**
    180          * Indicates that the {@code RemoteConference} that this {@code RemoteConnection} is a part
    181          * of has changed.
    182          *
    183          * @param connection The {@code RemoteConnection} invoking this method.
    184          * @param conference The {@code RemoteConference} of which this {@code RemoteConnection} is
    185          *         a part, which may be {@code null}.
    186          */
    187         public void onConferenceChanged(
    188                 RemoteConnection connection,
    189                 RemoteConference conference) {}
    190     }
    191 
    192     /** {@hide} */
    193     public static class VideoProvider {
    194 
    195         public abstract static class Listener {
    196             public void onReceiveSessionModifyRequest(
    197                     VideoProvider videoProvider,
    198                     VideoProfile videoProfile) {}
    199 
    200             public void onReceiveSessionModifyResponse(
    201                     VideoProvider videoProvider,
    202                     int status,
    203                     VideoProfile requestedProfile,
    204                     VideoProfile responseProfile) {}
    205 
    206             public void onHandleCallSessionEvent(VideoProvider videoProvider, int event) {}
    207 
    208             public void onPeerDimensionsChanged(VideoProvider videoProvider, int width, int height) {}
    209 
    210             public void onCallDataUsageChanged(VideoProvider videoProvider, int dataUsage) {}
    211 
    212             public void onCameraCapabilitiesChanged(
    213                     VideoProvider videoProvider,
    214                     CameraCapabilities cameraCapabilities) {}
    215         }
    216 
    217         private final IVideoCallback mVideoCallbackDelegate = new IVideoCallback() {
    218             @Override
    219             public void receiveSessionModifyRequest(VideoProfile videoProfile) {
    220                 for (Listener l : mListeners) {
    221                     l.onReceiveSessionModifyRequest(VideoProvider.this, videoProfile);
    222                 }
    223             }
    224 
    225             @Override
    226             public void receiveSessionModifyResponse(int status, VideoProfile requestedProfile,
    227                     VideoProfile responseProfile) {
    228                 for (Listener l : mListeners) {
    229                     l.onReceiveSessionModifyResponse(
    230                             VideoProvider.this,
    231                             status,
    232                             requestedProfile,
    233                             responseProfile);
    234                 }
    235             }
    236 
    237             @Override
    238             public void handleCallSessionEvent(int event) {
    239                 for (Listener l : mListeners) {
    240                     l.onHandleCallSessionEvent(VideoProvider.this, event);
    241                 }
    242             }
    243 
    244             @Override
    245             public void changePeerDimensions(int width, int height) {
    246                 for (Listener l : mListeners) {
    247                     l.onPeerDimensionsChanged(VideoProvider.this, width, height);
    248                 }
    249             }
    250 
    251             @Override
    252             public void changeCallDataUsage(int dataUsage) {
    253                 for (Listener l : mListeners) {
    254                     l.onCallDataUsageChanged(VideoProvider.this, dataUsage);
    255                 }
    256             }
    257 
    258             @Override
    259             public void changeCameraCapabilities(CameraCapabilities cameraCapabilities) {
    260                 for (Listener l : mListeners) {
    261                     l.onCameraCapabilitiesChanged(VideoProvider.this, cameraCapabilities);
    262                 }
    263             }
    264 
    265             @Override
    266             public IBinder asBinder() {
    267                 return null;
    268             }
    269         };
    270 
    271         private final VideoCallbackServant mVideoCallbackServant =
    272                 new VideoCallbackServant(mVideoCallbackDelegate);
    273 
    274         private final IVideoProvider mVideoProviderBinder;
    275 
    276         /**
    277          * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
    278          * load factor before resizing, 1 means we only expect a single thread to
    279          * access the map so make only a single shard
    280          */
    281         private final Set<Listener> mListeners = Collections.newSetFromMap(
    282                 new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
    283 
    284         public VideoProvider(IVideoProvider videoProviderBinder) {
    285             mVideoProviderBinder = videoProviderBinder;
    286             try {
    287                 mVideoProviderBinder.setVideoCallback(mVideoCallbackServant.getStub().asBinder());
    288             } catch (RemoteException e) {
    289             }
    290         }
    291 
    292         public void addListener(Listener l) {
    293             mListeners.add(l);
    294         }
    295 
    296         public void removeListener(Listener l) {
    297             mListeners.remove(l);
    298         }
    299 
    300         public void setCamera(String cameraId) {
    301             try {
    302                 mVideoProviderBinder.setCamera(cameraId);
    303             } catch (RemoteException e) {
    304             }
    305         }
    306 
    307         public void setPreviewSurface(Surface surface) {
    308             try {
    309                 mVideoProviderBinder.setPreviewSurface(surface);
    310             } catch (RemoteException e) {
    311             }
    312         }
    313 
    314         public void setDisplaySurface(Surface surface) {
    315             try {
    316                 mVideoProviderBinder.setDisplaySurface(surface);
    317             } catch (RemoteException e) {
    318             }
    319         }
    320 
    321         public void setDeviceOrientation(int rotation) {
    322             try {
    323                 mVideoProviderBinder.setDeviceOrientation(rotation);
    324             } catch (RemoteException e) {
    325             }
    326         }
    327 
    328         public void setZoom(float value) {
    329             try {
    330                 mVideoProviderBinder.setZoom(value);
    331             } catch (RemoteException e) {
    332             }
    333         }
    334 
    335         public void sendSessionModifyRequest(VideoProfile reqProfile) {
    336             try {
    337                 mVideoProviderBinder.sendSessionModifyRequest(reqProfile);
    338             } catch (RemoteException e) {
    339             }
    340         }
    341 
    342         public void sendSessionModifyResponse(VideoProfile responseProfile) {
    343             try {
    344                 mVideoProviderBinder.sendSessionModifyResponse(responseProfile);
    345             } catch (RemoteException e) {
    346             }
    347         }
    348 
    349         public void requestCameraCapabilities() {
    350             try {
    351                 mVideoProviderBinder.requestCameraCapabilities();
    352             } catch (RemoteException e) {
    353             }
    354         }
    355 
    356         public void requestCallDataUsage() {
    357             try {
    358                 mVideoProviderBinder.requestCallDataUsage();
    359             } catch (RemoteException e) {
    360             }
    361         }
    362 
    363         public void setPauseImage(String uri) {
    364             try {
    365                 mVideoProviderBinder.setPauseImage(uri);
    366             } catch (RemoteException e) {
    367             }
    368         }
    369     }
    370 
    371     private IConnectionService mConnectionService;
    372     private final String mConnectionId;
    373     /**
    374      * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
    375      * load factor before resizing, 1 means we only expect a single thread to
    376      * access the map so make only a single shard
    377      */
    378     private final Set<Callback> mCallbacks = Collections.newSetFromMap(
    379             new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1));
    380     private final List<RemoteConnection> mConferenceableConnections = new ArrayList<>();
    381     private final List<RemoteConnection> mUnmodifiableconferenceableConnections =
    382             Collections.unmodifiableList(mConferenceableConnections);
    383 
    384     private int mState = Connection.STATE_NEW;
    385     private DisconnectCause mDisconnectCause;
    386     private boolean mRingbackRequested;
    387     private boolean mConnected;
    388     private int mCallCapabilities;
    389     private int mVideoState;
    390     private VideoProvider mVideoProvider;
    391     private boolean mIsVoipAudioMode;
    392     private StatusHints mStatusHints;
    393     private Uri mAddress;
    394     private int mAddressPresentation;
    395     private String mCallerDisplayName;
    396     private int mCallerDisplayNamePresentation;
    397     private RemoteConference mConference;
    398 
    399     /**
    400      * @hide
    401      */
    402     RemoteConnection(
    403             String id,
    404             IConnectionService connectionService,
    405             ConnectionRequest request) {
    406         mConnectionId = id;
    407         mConnectionService = connectionService;
    408         mConnected = true;
    409         mState = Connection.STATE_INITIALIZING;
    410     }
    411 
    412     /**
    413      * Create a RemoteConnection which is used for failed connections. Note that using it for any
    414      * "real" purpose will almost certainly fail. Callers should note the failure and act
    415      * accordingly (moving on to another RemoteConnection, for example)
    416      *
    417      * @param disconnectCause The reason for the failed connection.
    418      * @hide
    419      */
    420     RemoteConnection(DisconnectCause disconnectCause) {
    421         this("NULL", null, null);
    422         mConnected = false;
    423         mState = Connection.STATE_DISCONNECTED;
    424         mDisconnectCause = disconnectCause;
    425     }
    426 
    427     /**
    428      * Adds a callback to this {@code RemoteConnection}.
    429      *
    430      * @param callback A {@code Callback}.
    431      */
    432     public void registerCallback(Callback callback) {
    433         mCallbacks.add(callback);
    434     }
    435 
    436     /**
    437      * Removes a callback from this {@code RemoteConnection}.
    438      *
    439      * @param callback A {@code Callback}.
    440      */
    441     public void unregisterCallback(Callback callback) {
    442         if (callback != null) {
    443             mCallbacks.remove(callback);
    444         }
    445     }
    446 
    447     /**
    448      * Obtains the state of this {@code RemoteConnection}.
    449      *
    450      * @return A state value, chosen from the {@code STATE_*} constants.
    451      */
    452     public int getState() {
    453         return mState;
    454     }
    455 
    456     /**
    457      * @return For a {@link Connection#STATE_DISCONNECTED} {@code RemoteConnection}, the
    458      * disconnect cause expressed as a code chosen from among those declared in
    459      * {@link DisconnectCause}.
    460      */
    461     public DisconnectCause getDisconnectCause() {
    462         return mDisconnectCause;
    463     }
    464 
    465     /**
    466      * @return A bitmask of the capabilities of the {@code RemoteConnection}, as defined in
    467      *         {@link PhoneCapabilities}.
    468      */
    469     public int getCallCapabilities() {
    470         return mCallCapabilities;
    471     }
    472 
    473     /**
    474      * @return {@code true} if the {@code RemoteConnection}'s current audio mode is VOIP.
    475      */
    476     public boolean isVoipAudioMode() {
    477         return mIsVoipAudioMode;
    478     }
    479 
    480     /**
    481      * @return The current {@link StatusHints} of this {@code RemoteConnection},
    482      * or {@code null} if none have been set.
    483      */
    484     public StatusHints getStatusHints() {
    485         return mStatusHints;
    486     }
    487 
    488     /**
    489      * @return The address (e.g., phone number) to which the {@code RemoteConnection} is currently
    490      * connected.
    491      */
    492     public Uri getAddress() {
    493         return mAddress;
    494     }
    495 
    496     /**
    497      * @return The presentation requirements for the address. See {@link TelecomManager} for valid
    498      * values.
    499      */
    500     public int getAddressPresentation() {
    501         return mAddressPresentation;
    502     }
    503 
    504     /**
    505      * @return The display name for the caller.
    506      */
    507     public CharSequence getCallerDisplayName() {
    508         return mCallerDisplayName;
    509     }
    510 
    511     /**
    512      * @return The presentation requirements for the caller display name. See
    513      * {@link TelecomManager} for valid values.
    514      */
    515     public int getCallerDisplayNamePresentation() {
    516         return mCallerDisplayNamePresentation;
    517     }
    518 
    519     /**
    520      * @return The video state of the {@code RemoteConnection}. See
    521      * {@link VideoProfile.VideoState}.
    522      * @hide
    523      */
    524     public int getVideoState() {
    525         return mVideoState;
    526     }
    527 
    528     /**
    529      * @return The video provider associated with this {@code RemoteConnection}.
    530      * @hide
    531      */
    532     public final VideoProvider getVideoProvider() {
    533         return mVideoProvider;
    534     }
    535 
    536     /**
    537      * @return Whether the {@code RemoteConnection} is requesting that the framework play a
    538      * ringback tone on its behalf.
    539      */
    540     public boolean isRingbackRequested() {
    541         return false;
    542     }
    543 
    544     /**
    545      * Instructs this {@code RemoteConnection} to abort.
    546      */
    547     public void abort() {
    548         try {
    549             if (mConnected) {
    550                 mConnectionService.abort(mConnectionId);
    551             }
    552         } catch (RemoteException ignored) {
    553         }
    554     }
    555 
    556     /**
    557      * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to answer.
    558      */
    559     public void answer() {
    560         try {
    561             if (mConnected) {
    562                 mConnectionService.answer(mConnectionId);
    563             }
    564         } catch (RemoteException ignored) {
    565         }
    566     }
    567 
    568     /**
    569      * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to answer.
    570      * @param videoState The video state in which to answer the call.
    571      * @hide
    572      */
    573     public void answer(int videoState) {
    574         try {
    575             if (mConnected) {
    576                 mConnectionService.answerVideo(mConnectionId, videoState);
    577             }
    578         } catch (RemoteException ignored) {
    579         }
    580     }
    581 
    582     /**
    583      * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to reject.
    584      */
    585     public void reject() {
    586         try {
    587             if (mConnected) {
    588                 mConnectionService.reject(mConnectionId);
    589             }
    590         } catch (RemoteException ignored) {
    591         }
    592     }
    593 
    594     /**
    595      * Instructs this {@code RemoteConnection} to go on hold.
    596      */
    597     public void hold() {
    598         try {
    599             if (mConnected) {
    600                 mConnectionService.hold(mConnectionId);
    601             }
    602         } catch (RemoteException ignored) {
    603         }
    604     }
    605 
    606     /**
    607      * Instructs this {@link Connection#STATE_HOLDING} call to release from hold.
    608      */
    609     public void unhold() {
    610         try {
    611             if (mConnected) {
    612                 mConnectionService.unhold(mConnectionId);
    613             }
    614         } catch (RemoteException ignored) {
    615         }
    616     }
    617 
    618     /**
    619      * Instructs this {@code RemoteConnection} to disconnect.
    620      */
    621     public void disconnect() {
    622         try {
    623             if (mConnected) {
    624                 mConnectionService.disconnect(mConnectionId);
    625             }
    626         } catch (RemoteException ignored) {
    627         }
    628     }
    629 
    630     /**
    631      * Instructs this {@code RemoteConnection} to play a dual-tone multi-frequency signaling
    632      * (DTMF) tone.
    633      *
    634      * Any other currently playing DTMF tone in the specified call is immediately stopped.
    635      *
    636      * @param digit A character representing the DTMF digit for which to play the tone. This
    637      *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
    638      */
    639     public void playDtmfTone(char digit) {
    640         try {
    641             if (mConnected) {
    642                 mConnectionService.playDtmfTone(mConnectionId, digit);
    643             }
    644         } catch (RemoteException ignored) {
    645         }
    646     }
    647 
    648     /**
    649      * Instructs this {@code RemoteConnection} to stop any dual-tone multi-frequency signaling
    650      * (DTMF) tone currently playing.
    651      *
    652      * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
    653      * currently playing, this method will do nothing.
    654      */
    655     public void stopDtmfTone() {
    656         try {
    657             if (mConnected) {
    658                 mConnectionService.stopDtmfTone(mConnectionId);
    659             }
    660         } catch (RemoteException ignored) {
    661         }
    662     }
    663 
    664     /**
    665      * Instructs this {@code RemoteConnection} to continue playing a post-dial DTMF string.
    666      *
    667      * A post-dial DTMF string is a string of digits following the first instance of either
    668      * {@link TelecomManager#DTMF_CHARACTER_WAIT} or {@link TelecomManager#DTMF_CHARACTER_PAUSE}.
    669      * These digits are immediately sent as DTMF tones to the recipient as soon as the
    670      * connection is made.
    671      *
    672      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
    673      * {@code RemoteConnection} will temporarily pause playing the tones for a pre-defined period
    674      * of time.
    675      *
    676      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
    677      * {@code RemoteConnection} will pause playing the tones and notify callbackss via
    678      * {@link Callback#onPostDialWait(RemoteConnection, String)}. At this point, the in-call app
    679      * should display to the user an indication of this state and an affordance to continue
    680      * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
    681      * app should invoke the {@link #postDialContinue(boolean)} method.
    682      *
    683      * @param proceed Whether or not to continue with the post-dial sequence.
    684      */
    685     public void postDialContinue(boolean proceed) {
    686         try {
    687             if (mConnected) {
    688                 mConnectionService.onPostDialContinue(mConnectionId, proceed);
    689             }
    690         } catch (RemoteException ignored) {
    691         }
    692     }
    693 
    694     /**
    695      * Set the audio state of this {@code RemoteConnection}.
    696      *
    697      * @param state The audio state of this {@code RemoteConnection}.
    698      */
    699     public void setAudioState(AudioState state) {
    700         try {
    701             if (mConnected) {
    702                 mConnectionService.onAudioStateChanged(mConnectionId, state);
    703             }
    704         } catch (RemoteException ignored) {
    705         }
    706     }
    707 
    708     /**
    709      * Obtain the {@code RemoteConnection}s with which this {@code RemoteConnection} may be
    710      * successfully asked to create a conference with.
    711      *
    712      * @return The {@code RemoteConnection}s with which this {@code RemoteConnection} may be
    713      *         merged into a {@link RemoteConference}.
    714      */
    715     public List<RemoteConnection> getConferenceableConnections() {
    716         return mUnmodifiableconferenceableConnections;
    717     }
    718 
    719     /**
    720      * Obtain the {@code RemoteConference} that this {@code RemoteConnection} may be a part
    721      * of, or {@code null} if there is no such {@code RemoteConference}.
    722      *
    723      * @return A {@code RemoteConference} or {@code null};
    724      */
    725     public RemoteConference getConference() {
    726         return mConference;
    727     }
    728 
    729     /** {@hide} */
    730     String getId() {
    731         return mConnectionId;
    732     }
    733 
    734     /** {@hide} */
    735     IConnectionService getConnectionService() {
    736         return mConnectionService;
    737     }
    738 
    739     /**
    740      * @hide
    741      */
    742     void setState(int state) {
    743         if (mState != state) {
    744             mState = state;
    745             for (Callback c: mCallbacks) {
    746                 c.onStateChanged(this, state);
    747             }
    748         }
    749     }
    750 
    751     /**
    752      * @hide
    753      */
    754     void setDisconnected(DisconnectCause disconnectCause) {
    755         if (mState != Connection.STATE_DISCONNECTED) {
    756             mState = Connection.STATE_DISCONNECTED;
    757             mDisconnectCause = disconnectCause;
    758 
    759             for (Callback c : mCallbacks) {
    760                 c.onDisconnected(this, mDisconnectCause);
    761             }
    762         }
    763     }
    764 
    765     /**
    766      * @hide
    767      */
    768     void setRingbackRequested(boolean ringback) {
    769         if (mRingbackRequested != ringback) {
    770             mRingbackRequested = ringback;
    771             for (Callback c : mCallbacks) {
    772                 c.onRingbackRequested(this, ringback);
    773             }
    774         }
    775     }
    776 
    777     /**
    778      * @hide
    779      */
    780     void setCallCapabilities(int callCapabilities) {
    781         mCallCapabilities = callCapabilities;
    782         for (Callback c : mCallbacks) {
    783             c.onCallCapabilitiesChanged(this, callCapabilities);
    784         }
    785     }
    786 
    787     /**
    788      * @hide
    789      */
    790     void setDestroyed() {
    791         if (!mCallbacks.isEmpty()) {
    792             // Make sure that the callbacks are notified that the call is destroyed first.
    793             if (mState != Connection.STATE_DISCONNECTED) {
    794                 setDisconnected(
    795                         new DisconnectCause(DisconnectCause.ERROR, "Connection destroyed."));
    796             }
    797 
    798             for (Callback c : mCallbacks) {
    799                 c.onDestroyed(this);
    800             }
    801             mCallbacks.clear();
    802 
    803             mConnected = false;
    804         }
    805     }
    806 
    807     /**
    808      * @hide
    809      */
    810     void setPostDialWait(String remainingDigits) {
    811         for (Callback c : mCallbacks) {
    812             c.onPostDialWait(this, remainingDigits);
    813         }
    814     }
    815 
    816     /**
    817      * @hide
    818      */
    819     void setVideoState(int videoState) {
    820         mVideoState = videoState;
    821         for (Callback c : mCallbacks) {
    822             c.onVideoStateChanged(this, videoState);
    823         }
    824     }
    825 
    826     /**
    827      * @hide
    828      */
    829     void setVideoProvider(VideoProvider videoProvider) {
    830         mVideoProvider = videoProvider;
    831         for (Callback c : mCallbacks) {
    832             c.onVideoProviderChanged(this, videoProvider);
    833         }
    834     }
    835 
    836     /** @hide */
    837     void setIsVoipAudioMode(boolean isVoip) {
    838         mIsVoipAudioMode = isVoip;
    839         for (Callback c : mCallbacks) {
    840             c.onVoipAudioChanged(this, isVoip);
    841         }
    842     }
    843 
    844     /** @hide */
    845     void setStatusHints(StatusHints statusHints) {
    846         mStatusHints = statusHints;
    847         for (Callback c : mCallbacks) {
    848             c.onStatusHintsChanged(this, statusHints);
    849         }
    850     }
    851 
    852     /** @hide */
    853     void setAddress(Uri address, int presentation) {
    854         mAddress = address;
    855         mAddressPresentation = presentation;
    856         for (Callback c : mCallbacks) {
    857             c.onAddressChanged(this, address, presentation);
    858         }
    859     }
    860 
    861     /** @hide */
    862     void setCallerDisplayName(String callerDisplayName, int presentation) {
    863         mCallerDisplayName = callerDisplayName;
    864         mCallerDisplayNamePresentation = presentation;
    865         for (Callback c : mCallbacks) {
    866             c.onCallerDisplayNameChanged(this, callerDisplayName, presentation);
    867         }
    868     }
    869 
    870     /** @hide */
    871     void setConferenceableConnections(List<RemoteConnection> conferenceableConnections) {
    872         mConferenceableConnections.clear();
    873         mConferenceableConnections.addAll(conferenceableConnections);
    874         for (Callback c : mCallbacks) {
    875             c.onConferenceableConnectionsChanged(this, mUnmodifiableconferenceableConnections);
    876         }
    877     }
    878 
    879     /** @hide */
    880     void setConference(RemoteConference conference) {
    881         if (mConference != conference) {
    882             mConference = conference;
    883             for (Callback c : mCallbacks) {
    884                 c.onConferenceChanged(this, conference);
    885             }
    886         }
    887     }
    888 
    889     /**
    890      * Create a RemoteConnection represents a failure, and which will be in
    891      * {@link Connection#STATE_DISCONNECTED}. Attempting to use it for anything will almost
    892      * certainly result in bad things happening. Do not do this.
    893      *
    894      * @return a failed {@link RemoteConnection}
    895      *
    896      * @hide
    897      */
    898     public static RemoteConnection failure(DisconnectCause disconnectCause) {
    899         return new RemoteConnection(disconnectCause);
    900     }
    901 }
    902