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