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