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