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