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