• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.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.RemoteException;
31 import android.view.Surface;
32 
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.List;
36 import java.util.Set;
37 import java.util.concurrent.ConcurrentHashMap;
38 
39 /**
40  * A connection provided to a {@link ConnectionService} by another {@code ConnectionService}
41  * running in a different process.
42  *
43  * @see ConnectionService#createRemoteOutgoingConnection(PhoneAccountHandle, ConnectionRequest)
44  * @see ConnectionService#createRemoteIncomingConnection(PhoneAccountHandle, ConnectionRequest)
45  */
46 public final class RemoteConnection {
47 
48     /**
49      * Callback base class for {@link RemoteConnection}.
50      */
51     public static abstract class Callback {
52         /**
53          * Invoked when the state of this {@code RemoteConnection} has changed. See
54          * {@link #getState()}.
55          *
56          * @param connection The {@code RemoteConnection} invoking this method.
57          * @param state The new state of the {@code RemoteConnection}.
58          */
onStateChanged(RemoteConnection connection, int state)59         public void onStateChanged(RemoteConnection connection, int state) {}
60 
61         /**
62          * Invoked when this {@code RemoteConnection} is disconnected.
63          *
64          * @param connection The {@code RemoteConnection} invoking this method.
65          * @param disconnectCause The ({@see DisconnectCause}) associated with this failed
66          *     connection.
67          */
onDisconnected( RemoteConnection connection, DisconnectCause disconnectCause)68         public void onDisconnected(
69                 RemoteConnection connection,
70                 DisconnectCause disconnectCause) {}
71 
72         /**
73          * Invoked when this {@code RemoteConnection} is requesting ringback. See
74          * {@link #isRingbackRequested()}.
75          *
76          * @param connection The {@code RemoteConnection} invoking this method.
77          * @param ringback Whether the {@code RemoteConnection} is requesting ringback.
78          */
onRingbackRequested(RemoteConnection connection, boolean ringback)79         public void onRingbackRequested(RemoteConnection connection, boolean ringback) {}
80 
81         /**
82          * Indicates that the call capabilities of this {@code RemoteConnection} have changed.
83          * See {@link #getConnectionCapabilities()}.
84          *
85          * @param connection The {@code RemoteConnection} invoking this method.
86          * @param connectionCapabilities The new capabilities of the {@code RemoteConnection}.
87          */
onConnectionCapabilitiesChanged( RemoteConnection connection, int connectionCapabilities)88         public void onConnectionCapabilitiesChanged(
89                 RemoteConnection connection,
90                 int connectionCapabilities) {}
91 
92         /**
93          * Invoked when the post-dial sequence in the outgoing {@code Connection} has reached a
94          * pause character. This causes the post-dial signals to stop pending user confirmation. An
95          * implementation should present this choice to the user and invoke
96          * {@link RemoteConnection#postDialContinue(boolean)} when the user makes the choice.
97          *
98          * @param connection The {@code RemoteConnection} invoking this method.
99          * @param remainingPostDialSequence The post-dial characters that remain to be sent.
100          */
onPostDialWait(RemoteConnection connection, String remainingPostDialSequence)101         public void onPostDialWait(RemoteConnection connection, String remainingPostDialSequence) {}
102 
103         /**
104          * Invoked when the post-dial sequence in the outgoing {@code Connection} has processed
105          * a character.
106          *
107          * @param connection The {@code RemoteConnection} invoking this method.
108          * @param nextChar The character being processed.
109          */
onPostDialChar(RemoteConnection connection, char nextChar)110         public void onPostDialChar(RemoteConnection connection, char nextChar) {}
111 
112         /**
113          * Indicates that the VOIP audio status of this {@code RemoteConnection} has changed.
114          * See {@link #isVoipAudioMode()}.
115          *
116          * @param connection The {@code RemoteConnection} invoking this method.
117          * @param isVoip Whether the new audio state of the {@code RemoteConnection} is VOIP.
118          */
onVoipAudioChanged(RemoteConnection connection, boolean isVoip)119         public void onVoipAudioChanged(RemoteConnection connection, boolean isVoip) {}
120 
121         /**
122          * Indicates that the status hints of this {@code RemoteConnection} have changed. See
123          * {@link #getStatusHints()} ()}.
124          *
125          * @param connection The {@code RemoteConnection} invoking this method.
126          * @param statusHints The new status hints of the {@code RemoteConnection}.
127          */
onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints)128         public void onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints) {}
129 
130         /**
131          * Indicates that the address (e.g., phone number) of this {@code RemoteConnection} has
132          * changed. See {@link #getAddress()} and {@link #getAddressPresentation()}.
133          *
134          * @param connection The {@code RemoteConnection} invoking this method.
135          * @param address The new address of the {@code RemoteConnection}.
136          * @param presentation The presentation requirements for the address.
137          *        See {@link TelecomManager} for valid values.
138          */
onAddressChanged(RemoteConnection connection, Uri address, int presentation)139         public void onAddressChanged(RemoteConnection connection, Uri address, int presentation) {}
140 
141         /**
142          * Indicates that the caller display name of this {@code RemoteConnection} has changed.
143          * See {@link #getCallerDisplayName()} and {@link #getCallerDisplayNamePresentation()}.
144          *
145          * @param connection The {@code RemoteConnection} invoking this method.
146          * @param callerDisplayName The new caller display name of the {@code RemoteConnection}.
147          * @param presentation The presentation requirements for the handle.
148          *        See {@link TelecomManager} for valid values.
149          */
onCallerDisplayNameChanged( RemoteConnection connection, String callerDisplayName, int presentation)150         public void onCallerDisplayNameChanged(
151                 RemoteConnection connection, String callerDisplayName, int presentation) {}
152 
153         /**
154          * Indicates that the video state of this {@code RemoteConnection} has changed.
155          * See {@link #getVideoState()}.
156          *
157          * @param connection The {@code RemoteConnection} invoking this method.
158          * @param videoState The new video state of the {@code RemoteConnection}.
159          */
onVideoStateChanged(RemoteConnection connection, int videoState)160         public void onVideoStateChanged(RemoteConnection connection, int videoState) {}
161 
162         /**
163          * Indicates that this {@code RemoteConnection} has been destroyed. No further requests
164          * should be made to the {@code RemoteConnection}, and references to it should be cleared.
165          *
166          * @param connection The {@code RemoteConnection} invoking this method.
167          */
onDestroyed(RemoteConnection connection)168         public void onDestroyed(RemoteConnection connection) {}
169 
170         /**
171          * Indicates that the {@code RemoteConnection}s with which this {@code RemoteConnection}
172          * may be asked to create a conference has changed.
173          *
174          * @param connection The {@code RemoteConnection} invoking this method.
175          * @param conferenceableConnections The {@code RemoteConnection}s with which this
176          *         {@code RemoteConnection} may be asked to create a conference.
177          */
onConferenceableConnectionsChanged( RemoteConnection connection, List<RemoteConnection> conferenceableConnections)178         public void onConferenceableConnectionsChanged(
179                 RemoteConnection connection,
180                 List<RemoteConnection> conferenceableConnections) {}
181 
182         /**
183          * Indicates that the {@code VideoProvider} associated with this {@code RemoteConnection}
184          * has changed.
185          *
186          * @param connection The {@code RemoteConnection} invoking this method.
187          * @param videoProvider The new {@code VideoProvider} associated with this
188          *         {@code RemoteConnection}.
189          */
onVideoProviderChanged( RemoteConnection connection, VideoProvider videoProvider)190         public void onVideoProviderChanged(
191                 RemoteConnection connection, VideoProvider videoProvider) {}
192 
193         /**
194          * Indicates that the {@code RemoteConference} that this {@code RemoteConnection} is a part
195          * of has changed.
196          *
197          * @param connection The {@code RemoteConnection} invoking this method.
198          * @param conference The {@code RemoteConference} of which this {@code RemoteConnection} is
199          *         a part, which may be {@code null}.
200          */
onConferenceChanged( RemoteConnection connection, RemoteConference conference)201         public void onConferenceChanged(
202                 RemoteConnection connection,
203                 RemoteConference conference) {}
204 
205         /**
206          * Handles changes to the {@code RemoteConnection} extras.
207          *
208          * @param connection The {@code RemoteConnection} invoking this method.
209          * @param extras The extras containing other information associated with the connection.
210          */
onExtrasChanged(RemoteConnection connection, @Nullable Bundle extras)211         public void onExtrasChanged(RemoteConnection connection, @Nullable Bundle extras) {}
212     }
213 
214     /**
215      * {@link RemoteConnection.VideoProvider} associated with a {@link RemoteConnection}.  Used to
216      * receive video related events and control the video associated with a
217      * {@link RemoteConnection}.
218      *
219      * @see Connection.VideoProvider
220      */
221     public static class VideoProvider {
222 
223         /**
224          * Callback class used by the {@link RemoteConnection.VideoProvider} to relay events from
225          * the {@link Connection.VideoProvider}.
226          */
227         public abstract static class Callback {
228             /**
229              * Reports a session modification request received from the
230              * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}.
231              *
232              * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method.
233              * @param videoProfile The requested video call profile.
234              * @see InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)
235              * @see Connection.VideoProvider#receiveSessionModifyRequest(VideoProfile)
236              */
onSessionModifyRequestReceived( VideoProvider videoProvider, VideoProfile videoProfile)237             public void onSessionModifyRequestReceived(
238                     VideoProvider videoProvider,
239                     VideoProfile videoProfile) {}
240 
241             /**
242              * Reports a session modification response received from the
243              * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}.
244              *
245              * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method.
246              * @param status Status of the session modify request.
247              * @param requestedProfile The original request which was sent to the peer device.
248              * @param responseProfile The actual profile changes made by the peer device.
249              * @see InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int,
250              *      VideoProfile, VideoProfile)
251              * @see Connection.VideoProvider#receiveSessionModifyResponse(int, VideoProfile,
252              *      VideoProfile)
253              */
onSessionModifyResponseReceived( VideoProvider videoProvider, int status, VideoProfile requestedProfile, VideoProfile responseProfile)254             public void onSessionModifyResponseReceived(
255                     VideoProvider videoProvider,
256                     int status,
257                     VideoProfile requestedProfile,
258                     VideoProfile responseProfile) {}
259 
260             /**
261              * Reports a call session event received from the {@link Connection.VideoProvider}
262              * associated with a {@link RemoteConnection}.
263              *
264              * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method.
265              * @param event The event.
266              * @see InCallService.VideoCall.Callback#onCallSessionEvent(int)
267              * @see Connection.VideoProvider#handleCallSessionEvent(int)
268              */
onCallSessionEvent(VideoProvider videoProvider, int event)269             public void onCallSessionEvent(VideoProvider videoProvider, int event) {}
270 
271             /**
272              * Reports a change in the peer video dimensions received from the
273              * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}.
274              *
275              * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method.
276              * @param width  The updated peer video width.
277              * @param height The updated peer video height.
278              * @see InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int)
279              * @see Connection.VideoProvider#changePeerDimensions(int, int)
280              */
onPeerDimensionsChanged(VideoProvider videoProvider, int width, int height)281             public void onPeerDimensionsChanged(VideoProvider videoProvider, int width,
282                     int height) {}
283 
284             /**
285              * Reports a change in the data usage (in bytes) received from the
286              * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}.
287              *
288              * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method.
289              * @param dataUsage The updated data usage (in bytes).
290              * @see InCallService.VideoCall.Callback#onCallDataUsageChanged(long)
291              * @see Connection.VideoProvider#setCallDataUsage(long)
292              */
onCallDataUsageChanged(VideoProvider videoProvider, long dataUsage)293             public void onCallDataUsageChanged(VideoProvider videoProvider, long dataUsage) {}
294 
295             /**
296              * Reports a change in the capabilities of the current camera, received from the
297              * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}.
298              *
299              * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method.
300              * @param cameraCapabilities The changed camera capabilities.
301              * @see InCallService.VideoCall.Callback#onCameraCapabilitiesChanged(
302              *      VideoProfile.CameraCapabilities)
303              * @see Connection.VideoProvider#changeCameraCapabilities(
304              *      VideoProfile.CameraCapabilities)
305              */
onCameraCapabilitiesChanged( VideoProvider videoProvider, VideoProfile.CameraCapabilities cameraCapabilities)306             public void onCameraCapabilitiesChanged(
307                     VideoProvider videoProvider,
308                     VideoProfile.CameraCapabilities cameraCapabilities) {}
309 
310             /**
311              * Reports a change in the video quality received from the
312              * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}.
313              *
314              * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method.
315              * @param videoQuality  The updated peer video quality.
316              * @see InCallService.VideoCall.Callback#onVideoQualityChanged(int)
317              * @see Connection.VideoProvider#changeVideoQuality(int)
318              */
onVideoQualityChanged(VideoProvider videoProvider, int videoQuality)319             public void onVideoQualityChanged(VideoProvider videoProvider, int videoQuality) {}
320         }
321 
322         private final IVideoCallback mVideoCallbackDelegate = new IVideoCallback() {
323             @Override
324             public void receiveSessionModifyRequest(VideoProfile videoProfile) {
325                 for (Callback l : mCallbacks) {
326                     l.onSessionModifyRequestReceived(VideoProvider.this, videoProfile);
327                 }
328             }
329 
330             @Override
331             public void receiveSessionModifyResponse(int status, VideoProfile requestedProfile,
332                     VideoProfile responseProfile) {
333                 for (Callback l : mCallbacks) {
334                     l.onSessionModifyResponseReceived(
335                             VideoProvider.this,
336                             status,
337                             requestedProfile,
338                             responseProfile);
339                 }
340             }
341 
342             @Override
343             public void handleCallSessionEvent(int event) {
344                 for (Callback l : mCallbacks) {
345                     l.onCallSessionEvent(VideoProvider.this, event);
346                 }
347             }
348 
349             @Override
350             public void changePeerDimensions(int width, int height) {
351                 for (Callback l : mCallbacks) {
352                     l.onPeerDimensionsChanged(VideoProvider.this, width, height);
353                 }
354             }
355 
356             @Override
357             public void changeCallDataUsage(long dataUsage) {
358                 for (Callback l : mCallbacks) {
359                     l.onCallDataUsageChanged(VideoProvider.this, dataUsage);
360                 }
361             }
362 
363             @Override
364             public void changeCameraCapabilities(
365                     VideoProfile.CameraCapabilities cameraCapabilities) {
366                 for (Callback l : mCallbacks) {
367                     l.onCameraCapabilitiesChanged(VideoProvider.this, cameraCapabilities);
368                 }
369             }
370 
371             @Override
372             public void changeVideoQuality(int videoQuality) {
373                 for (Callback l : mCallbacks) {
374                     l.onVideoQualityChanged(VideoProvider.this, videoQuality);
375                 }
376             }
377 
378             @Override
379             public IBinder asBinder() {
380                 return null;
381             }
382         };
383 
384         private final VideoCallbackServant mVideoCallbackServant =
385                 new VideoCallbackServant(mVideoCallbackDelegate);
386 
387         private final IVideoProvider mVideoProviderBinder;
388 
389         /**
390          * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
391          * load factor before resizing, 1 means we only expect a single thread to
392          * access the map so make only a single shard
393          */
394         private final Set<Callback> mCallbacks = Collections.newSetFromMap(
395                 new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1));
396 
VideoProvider(IVideoProvider videoProviderBinder)397         VideoProvider(IVideoProvider videoProviderBinder) {
398             mVideoProviderBinder = videoProviderBinder;
399             try {
400                 mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder());
401             } catch (RemoteException e) {
402             }
403         }
404 
405         /**
406          * Registers a callback to receive commands and state changes for video calls.
407          *
408          * @param l The video call callback.
409          */
registerCallback(Callback l)410         public void registerCallback(Callback l) {
411             mCallbacks.add(l);
412         }
413 
414         /**
415          * Clears the video call callback set via {@link #registerCallback}.
416          *
417          * @param l The video call callback to clear.
418          */
unregisterCallback(Callback l)419         public void unregisterCallback(Callback l) {
420             mCallbacks.remove(l);
421         }
422 
423         /**
424          * Sets the camera to be used for the outgoing video for the
425          * {@link RemoteConnection.VideoProvider}.
426          *
427          * @param cameraId The id of the camera (use ids as reported by
428          * {@link CameraManager#getCameraIdList()}).
429          * @see Connection.VideoProvider#onSetCamera(String)
430          */
setCamera(String cameraId)431         public void setCamera(String cameraId) {
432             try {
433                 mVideoProviderBinder.setCamera(cameraId);
434             } catch (RemoteException e) {
435             }
436         }
437 
438         /**
439          * Sets the surface to be used for displaying a preview of what the user's camera is
440          * currently capturing for the {@link RemoteConnection.VideoProvider}.
441          *
442          * @param surface The {@link Surface}.
443          * @see Connection.VideoProvider#onSetPreviewSurface(Surface)
444          */
setPreviewSurface(Surface surface)445         public void setPreviewSurface(Surface surface) {
446             try {
447                 mVideoProviderBinder.setPreviewSurface(surface);
448             } catch (RemoteException e) {
449             }
450         }
451 
452         /**
453          * Sets the surface to be used for displaying the video received from the remote device for
454          * the {@link RemoteConnection.VideoProvider}.
455          *
456          * @param surface The {@link Surface}.
457          * @see Connection.VideoProvider#onSetDisplaySurface(Surface)
458          */
setDisplaySurface(Surface surface)459         public void setDisplaySurface(Surface surface) {
460             try {
461                 mVideoProviderBinder.setDisplaySurface(surface);
462             } catch (RemoteException e) {
463             }
464         }
465 
466         /**
467          * Sets the device orientation, in degrees, for the {@link RemoteConnection.VideoProvider}.
468          * Assumes that a standard portrait orientation of the device is 0 degrees.
469          *
470          * @param rotation The device orientation, in degrees.
471          * @see Connection.VideoProvider#onSetDeviceOrientation(int)
472          */
setDeviceOrientation(int rotation)473         public void setDeviceOrientation(int rotation) {
474             try {
475                 mVideoProviderBinder.setDeviceOrientation(rotation);
476             } catch (RemoteException e) {
477             }
478         }
479 
480         /**
481          * Sets camera zoom ratio for the {@link RemoteConnection.VideoProvider}.
482          *
483          * @param value The camera zoom ratio.
484          * @see Connection.VideoProvider#onSetZoom(float)
485          */
setZoom(float value)486         public void setZoom(float value) {
487             try {
488                 mVideoProviderBinder.setZoom(value);
489             } catch (RemoteException e) {
490             }
491         }
492 
493         /**
494          * Issues a request to modify the properties of the current video session for the
495          * {@link RemoteConnection.VideoProvider}.
496          *
497          * @param fromProfile The video profile prior to the request.
498          * @param toProfile The video profile with the requested changes made.
499          * @see Connection.VideoProvider#onSendSessionModifyRequest(VideoProfile, VideoProfile)
500          */
sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)501         public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
502             try {
503                 mVideoProviderBinder.sendSessionModifyRequest(fromProfile, toProfile);
504             } catch (RemoteException e) {
505             }
506         }
507 
508         /**
509          * Provides a response to a request to change the current call video session
510          * properties for the {@link RemoteConnection.VideoProvider}.
511          *
512          * @param responseProfile The response call video properties.
513          * @see Connection.VideoProvider#onSendSessionModifyResponse(VideoProfile)
514          */
sendSessionModifyResponse(VideoProfile responseProfile)515         public void sendSessionModifyResponse(VideoProfile responseProfile) {
516             try {
517                 mVideoProviderBinder.sendSessionModifyResponse(responseProfile);
518             } catch (RemoteException e) {
519             }
520         }
521 
522         /**
523          * Issues a request to retrieve the capabilities of the current camera for the
524          * {@link RemoteConnection.VideoProvider}.
525          *
526          * @see Connection.VideoProvider#onRequestCameraCapabilities()
527          */
requestCameraCapabilities()528         public void requestCameraCapabilities() {
529             try {
530                 mVideoProviderBinder.requestCameraCapabilities();
531             } catch (RemoteException e) {
532             }
533         }
534 
535         /**
536          * Issues a request to retrieve the data usage (in bytes) of the video portion of the
537          * {@link RemoteConnection} for the {@link RemoteConnection.VideoProvider}.
538          *
539          * @see Connection.VideoProvider#onRequestConnectionDataUsage()
540          */
requestCallDataUsage()541         public void requestCallDataUsage() {
542             try {
543                 mVideoProviderBinder.requestCallDataUsage();
544             } catch (RemoteException e) {
545             }
546         }
547 
548         /**
549          * Sets the {@link Uri} of an image to be displayed to the peer device when the video signal
550          * is paused, for the {@link RemoteConnection.VideoProvider}.
551          *
552          * @see Connection.VideoProvider#onSetPauseImage(Uri)
553          */
setPauseImage(Uri uri)554         public void setPauseImage(Uri uri) {
555             try {
556                 mVideoProviderBinder.setPauseImage(uri);
557             } catch (RemoteException e) {
558             }
559         }
560     }
561 
562     private IConnectionService mConnectionService;
563     private final String mConnectionId;
564     /**
565      * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
566      * load factor before resizing, 1 means we only expect a single thread to
567      * access the map so make only a single shard
568      */
569     private final Set<CallbackRecord> mCallbackRecords = Collections.newSetFromMap(
570             new ConcurrentHashMap<CallbackRecord, Boolean>(8, 0.9f, 1));
571     private final List<RemoteConnection> mConferenceableConnections = new ArrayList<>();
572     private final List<RemoteConnection> mUnmodifiableconferenceableConnections =
573             Collections.unmodifiableList(mConferenceableConnections);
574 
575     private int mState = Connection.STATE_NEW;
576     private DisconnectCause mDisconnectCause;
577     private boolean mRingbackRequested;
578     private boolean mConnected;
579     private int mConnectionCapabilities;
580     private int mVideoState;
581     private VideoProvider mVideoProvider;
582     private boolean mIsVoipAudioMode;
583     private StatusHints mStatusHints;
584     private Uri mAddress;
585     private int mAddressPresentation;
586     private String mCallerDisplayName;
587     private int mCallerDisplayNamePresentation;
588     private RemoteConference mConference;
589     private Bundle mExtras;
590 
591     /**
592      * @hide
593      */
RemoteConnection( String id, IConnectionService connectionService, ConnectionRequest request)594     RemoteConnection(
595             String id,
596             IConnectionService connectionService,
597             ConnectionRequest request) {
598         mConnectionId = id;
599         mConnectionService = connectionService;
600         mConnected = true;
601         mState = Connection.STATE_INITIALIZING;
602     }
603 
604     /**
605      * @hide
606      */
RemoteConnection(String callId, IConnectionService connectionService, ParcelableConnection connection)607     RemoteConnection(String callId, IConnectionService connectionService,
608             ParcelableConnection connection) {
609         mConnectionId = callId;
610         mConnectionService = connectionService;
611         mConnected = true;
612         mState = connection.getState();
613         mDisconnectCause = connection.getDisconnectCause();
614         mRingbackRequested = connection.isRingbackRequested();
615         mConnectionCapabilities = connection.getConnectionCapabilities();
616         mVideoState = connection.getVideoState();
617         mVideoProvider = new RemoteConnection.VideoProvider(connection.getVideoProvider());
618         mIsVoipAudioMode = connection.getIsVoipAudioMode();
619         mStatusHints = connection.getStatusHints();
620         mAddress = connection.getHandle();
621         mAddressPresentation = connection.getHandlePresentation();
622         mCallerDisplayName = connection.getCallerDisplayName();
623         mCallerDisplayNamePresentation = connection.getCallerDisplayNamePresentation();
624         mConference = null;
625     }
626 
627     /**
628      * Create a RemoteConnection which is used for failed connections. Note that using it for any
629      * "real" purpose will almost certainly fail. Callers should note the failure and act
630      * accordingly (moving on to another RemoteConnection, for example)
631      *
632      * @param disconnectCause The reason for the failed connection.
633      * @hide
634      */
RemoteConnection(DisconnectCause disconnectCause)635     RemoteConnection(DisconnectCause disconnectCause) {
636         mConnectionId = "NULL";
637         mConnected = false;
638         mState = Connection.STATE_DISCONNECTED;
639         mDisconnectCause = disconnectCause;
640     }
641 
642     /**
643      * Adds a callback to this {@code RemoteConnection}.
644      *
645      * @param callback A {@code Callback}.
646      */
registerCallback(Callback callback)647     public void registerCallback(Callback callback) {
648         registerCallback(callback, new Handler());
649     }
650 
651     /**
652      * Adds a callback to this {@code RemoteConnection}.
653      *
654      * @param callback A {@code Callback}.
655      * @param handler A {@code Handler} which command and status changes will be delivered to.
656      */
registerCallback(Callback callback, Handler handler)657     public void registerCallback(Callback callback, Handler handler) {
658         unregisterCallback(callback);
659         if (callback != null && handler != null) {
660             mCallbackRecords.add(new CallbackRecord(callback, handler));
661         }
662     }
663 
664     /**
665      * Removes a callback from this {@code RemoteConnection}.
666      *
667      * @param callback A {@code Callback}.
668      */
unregisterCallback(Callback callback)669     public void unregisterCallback(Callback callback) {
670         if (callback != null) {
671             for (CallbackRecord record : mCallbackRecords) {
672                 if (record.getCallback() == callback) {
673                     mCallbackRecords.remove(record);
674                     break;
675                 }
676             }
677         }
678     }
679 
680     /**
681      * Obtains the state of this {@code RemoteConnection}.
682      *
683      * @return A state value, chosen from the {@code STATE_*} constants.
684      */
getState()685     public int getState() {
686         return mState;
687     }
688 
689     /**
690      * Obtains the reason why this {@code RemoteConnection} may have been disconnected.
691      *
692      * @return For a {@link Connection#STATE_DISCONNECTED} {@code RemoteConnection}, the
693      *         disconnect cause expressed as a code chosen from among those declared in
694      *         {@link DisconnectCause}.
695      */
getDisconnectCause()696     public DisconnectCause getDisconnectCause() {
697         return mDisconnectCause;
698     }
699 
700     /**
701      * Obtains the capabilities of this {@code RemoteConnection}.
702      *
703      * @return A bitmask of the capabilities of the {@code RemoteConnection}, as defined in
704      *         the {@code CAPABILITY_*} constants in class {@link Connection}.
705      */
getConnectionCapabilities()706     public int getConnectionCapabilities() {
707         return mConnectionCapabilities;
708     }
709 
710     /**
711      * Determines if the audio mode of this {@code RemoteConnection} is VOIP.
712      *
713      * @return {@code true} if the {@code RemoteConnection}'s current audio mode is VOIP.
714      */
isVoipAudioMode()715     public boolean isVoipAudioMode() {
716         return mIsVoipAudioMode;
717     }
718 
719     /**
720      * Obtains status hints pertaining to this {@code RemoteConnection}.
721      *
722      * @return The current {@link StatusHints} of this {@code RemoteConnection},
723      *         or {@code null} if none have been set.
724      */
getStatusHints()725     public StatusHints getStatusHints() {
726         return mStatusHints;
727     }
728 
729     /**
730      * Obtains the address of this {@code RemoteConnection}.
731      *
732      * @return The address (e.g., phone number) to which the {@code RemoteConnection}
733      *         is currently connected.
734      */
getAddress()735     public Uri getAddress() {
736         return mAddress;
737     }
738 
739     /**
740      * Obtains the presentation requirements for the address of this {@code RemoteConnection}.
741      *
742      * @return The presentation requirements for the address. See
743      *         {@link TelecomManager} for valid values.
744      */
getAddressPresentation()745     public int getAddressPresentation() {
746         return mAddressPresentation;
747     }
748 
749     /**
750      * Obtains the display name for this {@code RemoteConnection}'s caller.
751      *
752      * @return The display name for the caller.
753      */
getCallerDisplayName()754     public CharSequence getCallerDisplayName() {
755         return mCallerDisplayName;
756     }
757 
758     /**
759      * Obtains the presentation requirements for this {@code RemoteConnection}'s
760      * caller's display name.
761      *
762      * @return The presentation requirements for the caller display name. See
763      *         {@link TelecomManager} for valid values.
764      */
getCallerDisplayNamePresentation()765     public int getCallerDisplayNamePresentation() {
766         return mCallerDisplayNamePresentation;
767     }
768 
769     /**
770      * Obtains the video state of this {@code RemoteConnection}.
771      *
772      * @return The video state of the {@code RemoteConnection}. See {@link VideoProfile}.
773      */
getVideoState()774     public int getVideoState() {
775         return mVideoState;
776     }
777 
778     /**
779      * Obtains the video provider of this {@code RemoteConnection}.
780      * @return The video provider associated with this {@code RemoteConnection}.
781      */
getVideoProvider()782     public final VideoProvider getVideoProvider() {
783         return mVideoProvider;
784     }
785 
786     /**
787      * Obtain the extras associated with this {@code RemoteConnection}.
788      *
789      * @return The extras for this connection.
790      */
getExtras()791     public final Bundle getExtras() {
792         return mExtras;
793     }
794 
795     /**
796      * Determines whether this {@code RemoteConnection} is requesting ringback.
797      *
798      * @return Whether the {@code RemoteConnection} is requesting that the framework play a
799      *         ringback tone on its behalf.
800      */
isRingbackRequested()801     public boolean isRingbackRequested() {
802         return mRingbackRequested;
803     }
804 
805     /**
806      * Instructs this {@code RemoteConnection} to abort.
807      */
abort()808     public void abort() {
809         try {
810             if (mConnected) {
811                 mConnectionService.abort(mConnectionId);
812             }
813         } catch (RemoteException ignored) {
814         }
815     }
816 
817     /**
818      * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to answer.
819      */
answer()820     public void answer() {
821         try {
822             if (mConnected) {
823                 mConnectionService.answer(mConnectionId);
824             }
825         } catch (RemoteException ignored) {
826         }
827     }
828 
829     /**
830      * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to answer.
831      * @param videoState The video state in which to answer the call.
832      * @hide
833      */
answer(int videoState)834     public void answer(int videoState) {
835         try {
836             if (mConnected) {
837                 mConnectionService.answerVideo(mConnectionId, videoState);
838             }
839         } catch (RemoteException ignored) {
840         }
841     }
842 
843     /**
844      * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to reject.
845      */
reject()846     public void reject() {
847         try {
848             if (mConnected) {
849                 mConnectionService.reject(mConnectionId);
850             }
851         } catch (RemoteException ignored) {
852         }
853     }
854 
855     /**
856      * Instructs this {@code RemoteConnection} to go on hold.
857      */
hold()858     public void hold() {
859         try {
860             if (mConnected) {
861                 mConnectionService.hold(mConnectionId);
862             }
863         } catch (RemoteException ignored) {
864         }
865     }
866 
867     /**
868      * Instructs this {@link Connection#STATE_HOLDING} call to release from hold.
869      */
unhold()870     public void unhold() {
871         try {
872             if (mConnected) {
873                 mConnectionService.unhold(mConnectionId);
874             }
875         } catch (RemoteException ignored) {
876         }
877     }
878 
879     /**
880      * Instructs this {@code RemoteConnection} to disconnect.
881      */
disconnect()882     public void disconnect() {
883         try {
884             if (mConnected) {
885                 mConnectionService.disconnect(mConnectionId);
886             }
887         } catch (RemoteException ignored) {
888         }
889     }
890 
891     /**
892      * Instructs this {@code RemoteConnection} to play a dual-tone multi-frequency signaling
893      * (DTMF) tone.
894      *
895      * Any other currently playing DTMF tone in the specified call is immediately stopped.
896      *
897      * @param digit A character representing the DTMF digit for which to play the tone. This
898      *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
899      */
playDtmfTone(char digit)900     public void playDtmfTone(char digit) {
901         try {
902             if (mConnected) {
903                 mConnectionService.playDtmfTone(mConnectionId, digit);
904             }
905         } catch (RemoteException ignored) {
906         }
907     }
908 
909     /**
910      * Instructs this {@code RemoteConnection} to stop any dual-tone multi-frequency signaling
911      * (DTMF) tone currently playing.
912      *
913      * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
914      * currently playing, this method will do nothing.
915      */
stopDtmfTone()916     public void stopDtmfTone() {
917         try {
918             if (mConnected) {
919                 mConnectionService.stopDtmfTone(mConnectionId);
920             }
921         } catch (RemoteException ignored) {
922         }
923     }
924 
925     /**
926      * Instructs this {@code RemoteConnection} to continue playing a post-dial DTMF string.
927      *
928      * A post-dial DTMF string is a string of digits following the first instance of either
929      * {@link TelecomManager#DTMF_CHARACTER_WAIT} or {@link TelecomManager#DTMF_CHARACTER_PAUSE}.
930      * These digits are immediately sent as DTMF tones to the recipient as soon as the
931      * connection is made.
932      *
933      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
934      * {@code RemoteConnection} will temporarily pause playing the tones for a pre-defined period
935      * of time.
936      *
937      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
938      * {@code RemoteConnection} will pause playing the tones and notify callbacks via
939      * {@link Callback#onPostDialWait(RemoteConnection, String)}. At this point, the in-call app
940      * should display to the user an indication of this state and an affordance to continue
941      * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
942      * app should invoke the {@link #postDialContinue(boolean)} method.
943      *
944      * @param proceed Whether or not to continue with the post-dial sequence.
945      */
postDialContinue(boolean proceed)946     public void postDialContinue(boolean proceed) {
947         try {
948             if (mConnected) {
949                 mConnectionService.onPostDialContinue(mConnectionId, proceed);
950             }
951         } catch (RemoteException ignored) {
952         }
953     }
954 
955     /**
956      * Set the audio state of this {@code RemoteConnection}.
957      *
958      * @param state The audio state of this {@code RemoteConnection}.
959      * @hide
960      * @deprecated Use {@link #setCallAudioState(CallAudioState) instead.
961      */
962     @SystemApi
963     @Deprecated
setAudioState(AudioState state)964     public void setAudioState(AudioState state) {
965         setCallAudioState(new CallAudioState(state));
966     }
967 
968     /**
969      * Set the audio state of this {@code RemoteConnection}.
970      *
971      * @param state The audio state of this {@code RemoteConnection}.
972      */
setCallAudioState(CallAudioState state)973     public void setCallAudioState(CallAudioState state) {
974         try {
975             if (mConnected) {
976                 mConnectionService.onCallAudioStateChanged(mConnectionId, state);
977             }
978         } catch (RemoteException ignored) {
979         }
980     }
981 
982     /**
983      * Obtain the {@code RemoteConnection}s with which this {@code RemoteConnection} may be
984      * successfully asked to create a conference with.
985      *
986      * @return The {@code RemoteConnection}s with which this {@code RemoteConnection} may be
987      *         merged into a {@link RemoteConference}.
988      */
getConferenceableConnections()989     public List<RemoteConnection> getConferenceableConnections() {
990         return mUnmodifiableconferenceableConnections;
991     }
992 
993     /**
994      * Obtain the {@code RemoteConference} that this {@code RemoteConnection} may be a part
995      * of, or {@code null} if there is no such {@code RemoteConference}.
996      *
997      * @return A {@code RemoteConference} or {@code null};
998      */
getConference()999     public RemoteConference getConference() {
1000         return mConference;
1001     }
1002 
1003     /** {@hide} */
getId()1004     String getId() {
1005         return mConnectionId;
1006     }
1007 
1008     /** {@hide} */
getConnectionService()1009     IConnectionService getConnectionService() {
1010         return mConnectionService;
1011     }
1012 
1013     /**
1014      * @hide
1015      */
setState(final int state)1016     void setState(final int state) {
1017         if (mState != state) {
1018             mState = state;
1019             for (CallbackRecord record: mCallbackRecords) {
1020                 final RemoteConnection connection = this;
1021                 final Callback callback = record.getCallback();
1022                 record.getHandler().post(new Runnable() {
1023                     @Override
1024                     public void run() {
1025                         callback.onStateChanged(connection, state);
1026                     }
1027                 });
1028             }
1029         }
1030     }
1031 
1032     /**
1033      * @hide
1034      */
setDisconnected(final DisconnectCause disconnectCause)1035     void setDisconnected(final DisconnectCause disconnectCause) {
1036         if (mState != Connection.STATE_DISCONNECTED) {
1037             mState = Connection.STATE_DISCONNECTED;
1038             mDisconnectCause = disconnectCause;
1039 
1040             for (CallbackRecord record : mCallbackRecords) {
1041                 final RemoteConnection connection = this;
1042                 final Callback callback = record.getCallback();
1043                 record.getHandler().post(new Runnable() {
1044                     @Override
1045                     public void run() {
1046                         callback.onDisconnected(connection, disconnectCause);
1047                     }
1048                 });
1049             }
1050         }
1051     }
1052 
1053     /**
1054      * @hide
1055      */
setRingbackRequested(final boolean ringback)1056     void setRingbackRequested(final boolean ringback) {
1057         if (mRingbackRequested != ringback) {
1058             mRingbackRequested = ringback;
1059             for (CallbackRecord record : mCallbackRecords) {
1060                 final RemoteConnection connection = this;
1061                 final Callback callback = record.getCallback();
1062                 record.getHandler().post(new Runnable() {
1063                     @Override
1064                     public void run() {
1065                         callback.onRingbackRequested(connection, ringback);
1066                     }
1067                 });
1068             }
1069         }
1070     }
1071 
1072     /**
1073      * @hide
1074      */
setConnectionCapabilities(final int connectionCapabilities)1075     void setConnectionCapabilities(final int connectionCapabilities) {
1076         mConnectionCapabilities = connectionCapabilities;
1077         for (CallbackRecord record : mCallbackRecords) {
1078             final RemoteConnection connection = this;
1079             final Callback callback = record.getCallback();
1080             record.getHandler().post(new Runnable() {
1081                 @Override
1082                 public void run() {
1083                     callback.onConnectionCapabilitiesChanged(connection, connectionCapabilities);
1084                 }
1085             });
1086         }
1087     }
1088 
1089     /**
1090      * @hide
1091      */
setDestroyed()1092     void setDestroyed() {
1093         if (!mCallbackRecords.isEmpty()) {
1094             // Make sure that the callbacks are notified that the call is destroyed first.
1095             if (mState != Connection.STATE_DISCONNECTED) {
1096                 setDisconnected(
1097                         new DisconnectCause(DisconnectCause.ERROR, "Connection destroyed."));
1098             }
1099 
1100             for (CallbackRecord record : mCallbackRecords) {
1101                 final RemoteConnection connection = this;
1102                 final Callback callback = record.getCallback();
1103                 record.getHandler().post(new Runnable() {
1104                     @Override
1105                     public void run() {
1106                         callback.onDestroyed(connection);
1107                     }
1108                 });
1109             }
1110             mCallbackRecords.clear();
1111 
1112             mConnected = false;
1113         }
1114     }
1115 
1116     /**
1117      * @hide
1118      */
setPostDialWait(final String remainingDigits)1119     void setPostDialWait(final String remainingDigits) {
1120         for (CallbackRecord record : mCallbackRecords) {
1121             final RemoteConnection connection = this;
1122             final Callback callback = record.getCallback();
1123             record.getHandler().post(new Runnable() {
1124                 @Override
1125                 public void run() {
1126                     callback.onPostDialWait(connection, remainingDigits);
1127                 }
1128             });
1129         }
1130     }
1131 
1132     /**
1133      * @hide
1134      */
onPostDialChar(final char nextChar)1135     void onPostDialChar(final char nextChar) {
1136         for (CallbackRecord record : mCallbackRecords) {
1137             final RemoteConnection connection = this;
1138             final Callback callback = record.getCallback();
1139             record.getHandler().post(new Runnable() {
1140                 @Override
1141                 public void run() {
1142                     callback.onPostDialChar(connection, nextChar);
1143                 }
1144             });
1145         }
1146     }
1147 
1148     /**
1149      * @hide
1150      */
setVideoState(final int videoState)1151     void setVideoState(final int videoState) {
1152         mVideoState = videoState;
1153         for (CallbackRecord record : mCallbackRecords) {
1154             final RemoteConnection connection = this;
1155             final Callback callback = record.getCallback();
1156             record.getHandler().post(new Runnable() {
1157                 @Override
1158                 public void run() {
1159                     callback.onVideoStateChanged(connection, videoState);
1160                 }
1161             });
1162         }
1163     }
1164 
1165     /**
1166      * @hide
1167      */
setVideoProvider(final VideoProvider videoProvider)1168     void setVideoProvider(final VideoProvider videoProvider) {
1169         mVideoProvider = videoProvider;
1170         for (CallbackRecord record : mCallbackRecords) {
1171             final RemoteConnection connection = this;
1172             final Callback callback = record.getCallback();
1173             record.getHandler().post(new Runnable() {
1174                 @Override
1175                 public void run() {
1176                     callback.onVideoProviderChanged(connection, videoProvider);
1177                 }
1178             });
1179         }
1180     }
1181 
1182     /** @hide */
setIsVoipAudioMode(final boolean isVoip)1183     void setIsVoipAudioMode(final boolean isVoip) {
1184         mIsVoipAudioMode = isVoip;
1185         for (CallbackRecord record : mCallbackRecords) {
1186             final RemoteConnection connection = this;
1187             final Callback callback = record.getCallback();
1188             record.getHandler().post(new Runnable() {
1189                 @Override
1190                 public void run() {
1191                     callback.onVoipAudioChanged(connection, isVoip);
1192                 }
1193             });
1194         }
1195     }
1196 
1197     /** @hide */
setStatusHints(final StatusHints statusHints)1198     void setStatusHints(final StatusHints statusHints) {
1199         mStatusHints = statusHints;
1200         for (CallbackRecord record : mCallbackRecords) {
1201             final RemoteConnection connection = this;
1202             final Callback callback = record.getCallback();
1203             record.getHandler().post(new Runnable() {
1204                 @Override
1205                 public void run() {
1206                     callback.onStatusHintsChanged(connection, statusHints);
1207                 }
1208             });
1209         }
1210     }
1211 
1212     /** @hide */
setAddress(final Uri address, final int presentation)1213     void setAddress(final Uri address, final int presentation) {
1214         mAddress = address;
1215         mAddressPresentation = presentation;
1216         for (CallbackRecord record : mCallbackRecords) {
1217             final RemoteConnection connection = this;
1218             final Callback callback = record.getCallback();
1219             record.getHandler().post(new Runnable() {
1220                 @Override
1221                 public void run() {
1222                     callback.onAddressChanged(connection, address, presentation);
1223                 }
1224             });
1225         }
1226     }
1227 
1228     /** @hide */
setCallerDisplayName(final String callerDisplayName, final int presentation)1229     void setCallerDisplayName(final String callerDisplayName, final int presentation) {
1230         mCallerDisplayName = callerDisplayName;
1231         mCallerDisplayNamePresentation = presentation;
1232         for (CallbackRecord record : mCallbackRecords) {
1233             final RemoteConnection connection = this;
1234             final Callback callback = record.getCallback();
1235             record.getHandler().post(new Runnable() {
1236                 @Override
1237                 public void run() {
1238                     callback.onCallerDisplayNameChanged(
1239                             connection, callerDisplayName, presentation);
1240                 }
1241             });
1242         }
1243     }
1244 
1245     /** @hide */
setConferenceableConnections(final List<RemoteConnection> conferenceableConnections)1246     void setConferenceableConnections(final List<RemoteConnection> conferenceableConnections) {
1247         mConferenceableConnections.clear();
1248         mConferenceableConnections.addAll(conferenceableConnections);
1249         for (CallbackRecord record : mCallbackRecords) {
1250             final RemoteConnection connection = this;
1251             final Callback callback = record.getCallback();
1252             record.getHandler().post(new Runnable() {
1253                 @Override
1254                 public void run() {
1255                     callback.onConferenceableConnectionsChanged(
1256                             connection, mUnmodifiableconferenceableConnections);
1257                 }
1258             });
1259         }
1260     }
1261 
1262     /** @hide */
setConference(final RemoteConference conference)1263     void setConference(final RemoteConference conference) {
1264         if (mConference != conference) {
1265             mConference = conference;
1266             for (CallbackRecord record : mCallbackRecords) {
1267                 final RemoteConnection connection = this;
1268                 final Callback callback = record.getCallback();
1269                 record.getHandler().post(new Runnable() {
1270                     @Override
1271                     public void run() {
1272                         callback.onConferenceChanged(connection, conference);
1273                     }
1274                 });
1275             }
1276         }
1277     }
1278 
1279     /** @hide */
setExtras(final Bundle extras)1280     void setExtras(final Bundle extras) {
1281         mExtras = extras;
1282         for (CallbackRecord record : mCallbackRecords) {
1283             final RemoteConnection connection = this;
1284             final Callback callback = record.getCallback();
1285             record.getHandler().post(new Runnable() {
1286                 @Override
1287                 public void run() {
1288                     callback.onExtrasChanged(connection, extras);
1289                 }
1290             });
1291         }
1292     }
1293 
1294     /**
1295      * Create a RemoteConnection represents a failure, and which will be in
1296      * {@link Connection#STATE_DISCONNECTED}. Attempting to use it for anything will almost
1297      * certainly result in bad things happening. Do not do this.
1298      *
1299      * @return a failed {@link RemoteConnection}
1300      *
1301      * @hide
1302      */
failure(DisconnectCause disconnectCause)1303     public static RemoteConnection failure(DisconnectCause disconnectCause) {
1304         return new RemoteConnection(disconnectCause);
1305     }
1306 
1307     private static final class CallbackRecord extends Callback {
1308         private final Callback mCallback;
1309         private final Handler mHandler;
1310 
CallbackRecord(Callback callback, Handler handler)1311         public CallbackRecord(Callback callback, Handler handler) {
1312             mCallback = callback;
1313             mHandler = handler;
1314         }
1315 
getCallback()1316         public Callback getCallback() {
1317             return mCallback;
1318         }
1319 
getHandler()1320         public Handler getHandler() {
1321             return mHandler;
1322         }
1323     }
1324 }
1325