OSDN Git Service

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