1/*
2 * Copyright (C) 2006 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 com.android.internal.telephony;
18
19import android.net.Uri;
20import android.os.Bundle;
21import android.os.SystemClock;
22import android.telecom.ConferenceParticipant;
23import android.telephony.DisconnectCause;
24import android.telephony.Rlog;
25import android.util.Log;
26
27import java.lang.Override;
28import java.util.ArrayList;
29import java.util.List;
30import java.util.Set;
31import java.util.concurrent.CopyOnWriteArraySet;
32
33/**
34 * {@hide}
35 */
36public abstract class Connection {
37    public interface PostDialListener {
38        void onPostDialWait();
39        void onPostDialChar(char c);
40    }
41
42    /**
43     * Capabilities that will be mapped to telecom connection
44     * capabilities.
45     */
46    public static class Capability {
47
48        /**
49         * For an IMS video call, indicates that the local side of the call supports downgrading
50         * from a video call to an audio-only call.
51         */
52        public static final int SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL = 0x00000001;
53
54        /**
55         * For an IMS video call, indicates that the peer supports downgrading to an audio-only
56         * call.
57         */
58        public static final int SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE = 0x00000002;
59
60        /**
61         * For an IMS call, indicates that the call supports video locally.
62         */
63        public static final int SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 0x00000004;
64
65        /**
66         * For an IMS call, indicates that the peer supports video.
67         */
68        public static final int SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 0x00000008;
69
70        /**
71         * Indicates that the connection is an external connection (e.g. an instance of the class
72         * {@link com.android.internal.telephony.imsphone.ImsExternalConnection}.
73         */
74        public static final int IS_EXTERNAL_CONNECTION = 0x00000010;
75
76        /**
77         * Indicates that this external connection can be pulled from the remote device to the
78         * local device.
79         */
80        public static final int IS_PULLABLE = 0x00000020;
81    }
82
83    /**
84     * Listener interface for events related to the connection which should be reported to the
85     * {@link android.telecom.Connection}.
86     */
87    public interface Listener {
88        public void onVideoStateChanged(int videoState);
89        public void onConnectionCapabilitiesChanged(int capability);
90        public void onWifiChanged(boolean isWifi);
91        public void onVideoProviderChanged(
92                android.telecom.Connection.VideoProvider videoProvider);
93        public void onAudioQualityChanged(int audioQuality);
94        public void onConferenceParticipantsChanged(List<ConferenceParticipant> participants);
95        public void onCallSubstateChanged(int callSubstate);
96        public void onMultipartyStateChanged(boolean isMultiParty);
97        public void onConferenceMergedFailed();
98        public void onExtrasChanged(Bundle extras);
99        public void onExitedEcmMode();
100    }
101
102    /**
103     * Base listener implementation.
104     */
105    public abstract static class ListenerBase implements Listener {
106        @Override
107        public void onVideoStateChanged(int videoState) {}
108        @Override
109        public void onConnectionCapabilitiesChanged(int capability) {}
110        @Override
111        public void onWifiChanged(boolean isWifi) {}
112        @Override
113        public void onVideoProviderChanged(
114                android.telecom.Connection.VideoProvider videoProvider) {}
115        @Override
116        public void onAudioQualityChanged(int audioQuality) {}
117        @Override
118        public void onConferenceParticipantsChanged(List<ConferenceParticipant> participants) {}
119        @Override
120        public void onCallSubstateChanged(int callSubstate) {}
121        @Override
122        public void onMultipartyStateChanged(boolean isMultiParty) {}
123        @Override
124        public void onConferenceMergedFailed() {}
125        @Override
126        public void onExtrasChanged(Bundle extras) {}
127        @Override
128        public void onExitedEcmMode() {}
129    }
130
131    public static final int AUDIO_QUALITY_STANDARD = 1;
132    public static final int AUDIO_QUALITY_HIGH_DEFINITION = 2;
133
134    /**
135     * The telecom internal call ID associated with this connection.  Only to be used for debugging
136     * purposes.
137     */
138    private String mTelecomCallId;
139
140    //Caller Name Display
141    protected String mCnapName;
142    protected int mCnapNamePresentation  = PhoneConstants.PRESENTATION_ALLOWED;
143    protected String mAddress;     // MAY BE NULL!!!
144    protected String mDialString;          // outgoing calls only
145    protected int mNumberPresentation = PhoneConstants.PRESENTATION_ALLOWED;
146    protected boolean mIsIncoming;
147    /*
148     * These time/timespan values are based on System.currentTimeMillis(),
149     * i.e., "wall clock" time.
150     */
151    protected long mCreateTime;
152    protected long mConnectTime;
153    /*
154     * These time/timespan values are based on SystemClock.elapsedRealTime(),
155     * i.e., time since boot.  They are appropriate for comparison and
156     * calculating deltas.
157     */
158    protected long mConnectTimeReal;
159    protected long mDuration;
160    protected long mHoldingStartTime;  // The time when the Connection last transitioned
161                            // into HOLDING
162    protected Connection mOrigConnection;
163    private List<PostDialListener> mPostDialListeners = new ArrayList<>();
164    public Set<Listener> mListeners = new CopyOnWriteArraySet<>();
165
166    protected boolean mNumberConverted = false;
167    protected String mConvertedNumber;
168
169    protected String mPostDialString;      // outgoing calls only
170    protected int mNextPostDialChar;       // index into postDialString
171
172    protected int mCause = DisconnectCause.NOT_DISCONNECTED;
173    protected PostDialState mPostDialState = PostDialState.NOT_STARTED;
174
175    private static String LOG_TAG = "Connection";
176
177    Object mUserData;
178    private int mVideoState;
179    private int mConnectionCapabilities;
180    private boolean mIsWifi;
181    private int mAudioQuality;
182    private int mCallSubstate;
183    private android.telecom.Connection.VideoProvider mVideoProvider;
184    public Call.State mPreHandoverState = Call.State.IDLE;
185    private Bundle mExtras;
186    private int mPhoneType;
187
188    protected Connection(int phoneType) {
189        mPhoneType = phoneType;
190    }
191
192    /* Instance Methods */
193
194    /**
195     * @return The telecom internal call ID associated with this connection.  Only to be used for
196     * debugging purposes.
197     */
198    public String getTelecomCallId() {
199        return mTelecomCallId;
200    }
201
202    /**
203     * Sets the telecom call ID associated with this connection.
204     *
205     * @param telecomCallId The telecom call ID.
206     */
207    public void setTelecomCallId(String telecomCallId) {
208        mTelecomCallId = telecomCallId;
209    }
210
211    /**
212     * Gets address (e.g. phone number) associated with connection.
213     * TODO: distinguish reasons for unavailability
214     *
215     * @return address or null if unavailable
216     */
217
218    public String getAddress() {
219        return mAddress;
220    }
221
222    /**
223     * Gets CNAP name associated with connection.
224     * @return cnap name or null if unavailable
225     */
226    public String getCnapName() {
227        return mCnapName;
228    }
229
230    /**
231     * Get original dial string.
232     * @return original dial string or null if unavailable
233     */
234    public String getOrigDialString(){
235        return null;
236    }
237
238    /**
239     * Gets CNAP presentation associated with connection.
240     * @return cnap name or null if unavailable
241     */
242
243    public int getCnapNamePresentation() {
244       return mCnapNamePresentation;
245    }
246
247    /**
248     * @return Call that owns this Connection, or null if none
249     */
250    public abstract Call getCall();
251
252    /**
253     * Connection create time in currentTimeMillis() format
254     * Basically, set when object is created.
255     * Effectively, when an incoming call starts ringing or an
256     * outgoing call starts dialing
257     */
258    public long getCreateTime() {
259        return mCreateTime;
260    }
261
262    /**
263     * Connection connect time in currentTimeMillis() format.
264     * For outgoing calls: Begins at (DIALING|ALERTING) -> ACTIVE transition.
265     * For incoming calls: Begins at (INCOMING|WAITING) -> ACTIVE transition.
266     * Returns 0 before then.
267     */
268    public long getConnectTime() {
269        return mConnectTime;
270    }
271
272    /**
273     * Sets the Connection connect time in currentTimeMillis() format.
274     *
275     * @param connectTime the new connect time.
276     */
277    public void setConnectTime(long connectTime) {
278        mConnectTime = connectTime;
279    }
280
281    /**
282     * Connection connect time in elapsedRealtime() format.
283     * For outgoing calls: Begins at (DIALING|ALERTING) -> ACTIVE transition.
284     * For incoming calls: Begins at (INCOMING|WAITING) -> ACTIVE transition.
285     * Returns 0 before then.
286     */
287    public long getConnectTimeReal() {
288        return mConnectTimeReal;
289    }
290
291    /**
292     * Disconnect time in currentTimeMillis() format.
293     * The time when this Connection makes a transition into ENDED or FAIL.
294     * Returns 0 before then.
295     */
296    public abstract long getDisconnectTime();
297
298    /**
299     * Returns the number of milliseconds the call has been connected,
300     * or 0 if the call has never connected.
301     * If the call is still connected, then returns the elapsed
302     * time since connect.
303     */
304    public long getDurationMillis() {
305        if (mConnectTimeReal == 0) {
306            return 0;
307        } else if (mDuration == 0) {
308            return SystemClock.elapsedRealtime() - mConnectTimeReal;
309        } else {
310            return mDuration;
311        }
312    }
313
314    /**
315     * The time when this Connection last transitioned into HOLDING
316     * in elapsedRealtime() format.
317     * Returns 0, if it has never made a transition into HOLDING.
318     */
319    public long getHoldingStartTime() {
320        return mHoldingStartTime;
321    }
322
323    /**
324     * If this connection is HOLDING, return the number of milliseconds
325     * that it has been on hold for (approximately).
326     * If this connection is in any other state, return 0.
327     */
328
329    public abstract long getHoldDurationMillis();
330
331    /**
332     * Returns call disconnect cause. Values are defined in
333     * {@link android.telephony.DisconnectCause}. If the call is not yet
334     * disconnected, NOT_DISCONNECTED is returned.
335     */
336    public int getDisconnectCause() {
337        return mCause;
338    }
339
340    /**
341     * Returns a string disconnect cause which is from vendor.
342     * Vendors may use this string to explain the underline causes of failed calls.
343     * There is no guarantee that it is non-null nor it'll have meaningful stable values.
344     * Only use it when getDisconnectCause() returns a value that is not specific enough, like
345     * ERROR_UNSPECIFIED.
346     */
347    public abstract String getVendorDisconnectCause();
348
349    /**
350     * Returns true of this connection originated elsewhere
351     * ("MT" or mobile terminated; another party called this terminal)
352     * or false if this call originated here (MO or mobile originated).
353     */
354    public boolean isIncoming() {
355        return mIsIncoming;
356    }
357
358    /**
359     * If this Connection is connected, then it is associated with
360     * a Call.
361     *
362     * Returns getCall().getState() or Call.State.IDLE if not
363     * connected
364     */
365    public Call.State getState() {
366        Call c;
367
368        c = getCall();
369
370        if (c == null) {
371            return Call.State.IDLE;
372        } else {
373            return c.getState();
374        }
375    }
376
377    /**
378     * If this connection went through handover return the state of the
379     * call that contained this connection before handover.
380     */
381    public Call.State getStateBeforeHandover() {
382        return mPreHandoverState;
383   }
384
385    /**
386     * Get the details of conference participants. Expected to be
387     * overwritten by the Connection subclasses.
388     */
389    public List<ConferenceParticipant> getConferenceParticipants() {
390        Call c;
391
392        c = getCall();
393
394        if (c == null) {
395            return null;
396        } else {
397            return c.getConferenceParticipants();
398        }
399    }
400
401    /**
402     * isAlive()
403     *
404     * @return true if the connection isn't disconnected
405     * (could be active, holding, ringing, dialing, etc)
406     */
407    public boolean
408    isAlive() {
409        return getState().isAlive();
410    }
411
412    /**
413     * Returns true if Connection is connected and is INCOMING or WAITING
414     */
415    public boolean
416    isRinging() {
417        return getState().isRinging();
418    }
419
420    /**
421     *
422     * @return the userdata set in setUserData()
423     */
424    public Object getUserData() {
425        return mUserData;
426    }
427
428    /**
429     *
430     * @param userdata user can store an any userdata in the Connection object.
431     */
432    public void setUserData(Object userdata) {
433        mUserData = userdata;
434    }
435
436    /**
437     * Hangup individual Connection
438     */
439    public abstract void hangup() throws CallStateException;
440
441    /**
442     * Separate this call from its owner Call and assigns it to a new Call
443     * (eg if it is currently part of a Conference call
444     * TODO: Throw exception? Does GSM require error display on failure here?
445     */
446    public abstract void separate() throws CallStateException;
447
448    public enum PostDialState {
449        NOT_STARTED,    /* The post dial string playback hasn't
450                           been started, or this call is not yet
451                           connected, or this is an incoming call */
452        STARTED,        /* The post dial string playback has begun */
453        WAIT,           /* The post dial string playback is waiting for a
454                           call to proceedAfterWaitChar() */
455        WILD,           /* The post dial string playback is waiting for a
456                           call to proceedAfterWildChar() */
457        COMPLETE,       /* The post dial string playback is complete */
458        CANCELLED,       /* The post dial string playback was cancelled
459                           with cancelPostDial() */
460        PAUSE           /* The post dial string playback is pausing for a
461                           call to processNextPostDialChar*/
462    }
463
464    public void clearUserData(){
465        mUserData = null;
466    }
467
468    public final void addPostDialListener(PostDialListener listener) {
469        if (!mPostDialListeners.contains(listener)) {
470            mPostDialListeners.add(listener);
471        }
472    }
473
474    public final void removePostDialListener(PostDialListener listener) {
475        mPostDialListeners.remove(listener);
476    }
477
478    protected final void clearPostDialListeners() {
479        mPostDialListeners.clear();
480    }
481
482    protected final void notifyPostDialListeners() {
483        if (getPostDialState() == PostDialState.WAIT) {
484            for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) {
485                listener.onPostDialWait();
486            }
487        }
488    }
489
490    protected final void notifyPostDialListenersNextChar(char c) {
491        for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) {
492            listener.onPostDialChar(c);
493        }
494    }
495
496    public PostDialState getPostDialState() {
497        return mPostDialState;
498    }
499
500    /**
501     * Returns the portion of the post dial string that has not
502     * yet been dialed, or "" if none
503     */
504    public String getRemainingPostDialString() {
505        if (mPostDialState == PostDialState.CANCELLED
506                || mPostDialState == PostDialState.COMPLETE
507                || mPostDialString == null
508                || mPostDialString.length() <= mNextPostDialChar) {
509            return "";
510        }
511
512        return mPostDialString.substring(mNextPostDialChar);
513    }
514
515    /**
516     * See Phone.setOnPostDialWaitCharacter()
517     */
518
519    public abstract void proceedAfterWaitChar();
520
521    /**
522     * See Phone.setOnPostDialWildCharacter()
523     */
524    public abstract void proceedAfterWildChar(String str);
525    /**
526     * Cancel any post
527     */
528    public abstract void cancelPostDial();
529
530    /** Called when the connection has been disconnected */
531    public boolean onDisconnect(int cause) {
532        return false;
533    }
534
535    /**
536     * Returns the caller id presentation type for incoming and waiting calls
537     * @return one of PRESENTATION_*
538     */
539    public abstract int getNumberPresentation();
540
541    /**
542     * Returns the User to User Signaling (UUS) information associated with
543     * incoming and waiting calls
544     * @return UUSInfo containing the UUS userdata.
545     */
546    public abstract UUSInfo getUUSInfo();
547
548    /**
549     * Returns the CallFail reason provided by the RIL with the result of
550     * RIL_REQUEST_LAST_CALL_FAIL_CAUSE
551     */
552    public abstract int getPreciseDisconnectCause();
553
554    /**
555     * Returns the original Connection instance associated with
556     * this Connection
557     */
558    public Connection getOrigConnection() {
559        return mOrigConnection;
560    }
561
562    /**
563     * Returns whether the original ImsPhoneConnection was a member
564     * of a conference call
565     * @return valid only when getOrigConnection() is not null
566     */
567    public abstract boolean isMultiparty();
568
569    /**
570     * Applicable only for IMS Call. Determines if this call is the origin of the conference call
571     * (i.e. {@code #isConferenceHost()} is {@code true}), or if it is a member of a conference
572     * hosted on another device.
573     *
574     * @return {@code true} if this call is the origin of the conference call it is a member of,
575     *      {@code false} otherwise.
576     */
577    public boolean isConferenceHost() {
578        return false;
579    }
580
581    /**
582     * Applicable only for IMS Call. Determines if a connection is a member of a conference hosted
583     * on another device.
584     *
585     * @return {@code true} if the connection is a member of a conference hosted on another device.
586     */
587    public boolean isMemberOfPeerConference() {
588        return false;
589    }
590
591    public void migrateFrom(Connection c) {
592        if (c == null) return;
593        mListeners = c.mListeners;
594        mDialString = c.getOrigDialString();
595        mCreateTime = c.getCreateTime();
596        mConnectTime = c.getConnectTime();
597        mConnectTimeReal = c.getConnectTimeReal();
598        mHoldingStartTime = c.getHoldingStartTime();
599        mOrigConnection = c.getOrigConnection();
600        mPostDialString = c.mPostDialString;
601        mNextPostDialChar = c.mNextPostDialChar;
602    }
603
604    /**
605     * Assign a listener to be notified of state changes.
606     *
607     * @param listener A listener.
608     */
609    public final void addListener(Listener listener) {
610        mListeners.add(listener);
611    }
612
613    /**
614     * Removes a listener.
615     *
616     * @param listener A listener.
617     */
618    public final void removeListener(Listener listener) {
619        mListeners.remove(listener);
620    }
621
622    /**
623     * Returns the current video state of the connection.
624     *
625     * @return The video state of the connection.
626     */
627    public int getVideoState() {
628        return mVideoState;
629    }
630
631    /**
632     * Called to get Connection capabilities.Returns Capabilities bitmask.
633     * @See Connection.Capability.
634     */
635    public int getConnectionCapabilities() {
636        return mConnectionCapabilities;
637    }
638
639    /**
640     * Applies a capability to a capabilities bit-mask.
641     *
642     * @param capabilities The capabilities bit-mask.
643     * @param capability The capability to apply.
644     * @return The capabilities bit-mask with the capability applied.
645     */
646    public static int addCapability(int capabilities, int capability) {
647        return capabilities | capability;
648    }
649
650    /**
651     * Removes a capability to a capabilities bit-mask.
652     *
653     * @param capabilities The capabilities bit-mask.
654     * @param capability The capability to remove.
655     * @return The capabilities bit-mask with the capability removed.
656     */
657    public static int removeCapability(int capabilities, int capability) {
658        return capabilities & ~capability;
659    }
660
661    /**
662     * Returns whether the connection is using a wifi network.
663     *
664     * @return {@code True} if the connection is using a wifi network.
665     */
666    public boolean isWifi() {
667        return mIsWifi;
668    }
669
670    /**
671     * Returns the {@link android.telecom.Connection.VideoProvider} for the connection.
672     *
673     * @return The {@link android.telecom.Connection.VideoProvider}.
674     */
675    public android.telecom.Connection.VideoProvider getVideoProvider() {
676        return mVideoProvider;
677    }
678
679    /**
680     * Returns the audio-quality for the connection.
681     *
682     * @return The audio quality for the connection.
683     */
684    public int getAudioQuality() {
685        return mAudioQuality;
686    }
687
688
689    /**
690     * Returns the current call substate of the connection.
691     *
692     * @return The call substate of the connection.
693     */
694    public int getCallSubstate() {
695        return mCallSubstate;
696    }
697
698
699    /**
700     * Sets the videoState for the current connection and reports the changes to all listeners.
701     * Valid video states are defined in {@link android.telecom.VideoProfile}.
702     *
703     * @return The video state.
704     */
705    public void setVideoState(int videoState) {
706        mVideoState = videoState;
707        for (Listener l : mListeners) {
708            l.onVideoStateChanged(mVideoState);
709        }
710    }
711
712    /**
713     * Called to set Connection capabilities.  This will take Capabilities bitmask as input which is
714     * converted from Capabilities constants.
715     *
716     * @See Connection.Capability.
717     * @param capabilities The Capabilities bitmask.
718     */
719    public void setConnectionCapabilities(int capabilities) {
720        if (mConnectionCapabilities != capabilities) {
721            mConnectionCapabilities = capabilities;
722            for (Listener l : mListeners) {
723                l.onConnectionCapabilitiesChanged(mConnectionCapabilities);
724            }
725        }
726    }
727
728    /**
729     * Sets whether a wifi network is used for the connection.
730     *
731     * @param isWifi {@code True} if wifi is being used.
732     */
733    public void setWifi(boolean isWifi) {
734        mIsWifi = isWifi;
735        for (Listener l : mListeners) {
736            l.onWifiChanged(mIsWifi);
737        }
738    }
739
740    /**
741     * Set the audio quality for the connection.
742     *
743     * @param audioQuality The audio quality.
744     */
745    public void setAudioQuality(int audioQuality) {
746        mAudioQuality = audioQuality;
747        for (Listener l : mListeners) {
748            l.onAudioQualityChanged(mAudioQuality);
749        }
750    }
751
752    /**
753     * Notifies listeners that connection extras has changed.
754     * @param extras New connection extras. This Bundle will be cloned to ensure that any concurrent
755     * modifications to the extras Bundle do not affect Bundle operations in the onExtrasChanged
756     * listeners.
757     */
758    public void setConnectionExtras(Bundle extras) {
759        if(extras != null) {
760            mExtras = new Bundle(extras);
761        } else {
762            mExtras = null;
763        }
764        for (Listener l : mListeners) {
765            l.onExtrasChanged(mExtras);
766        }
767    }
768
769    /**
770     * Retrieves the current connection extras.
771     * @return the connection extras.
772     */
773    public Bundle getConnectionExtras() {
774        return mExtras;
775    }
776
777    /**
778     * Sets the call substate for the current connection and reports the changes to all listeners.
779     * Valid call substates are defined in {@link android.telecom.Connection}.
780     *
781     * @return The call substate.
782     */
783    public void setCallSubstate(int callSubstate) {
784        mCallSubstate = callSubstate;
785        for (Listener l : mListeners) {
786            l.onCallSubstateChanged(mCallSubstate);
787        }
788    }
789
790    /**
791     * Sets the {@link android.telecom.Connection.VideoProvider} for the connection.
792     *
793     * @param videoProvider The video call provider.
794     */
795    public void setVideoProvider(android.telecom.Connection.VideoProvider videoProvider) {
796        mVideoProvider = videoProvider;
797        for (Listener l : mListeners) {
798            l.onVideoProviderChanged(mVideoProvider);
799        }
800    }
801
802    public void setConverted(String oriNumber) {
803        mNumberConverted = true;
804        mConvertedNumber = mAddress;
805        mAddress = oriNumber;
806        mDialString = oriNumber;
807    }
808
809    /**
810     * Notifies listeners of a change to conference participant(s).
811     *
812     * @param conferenceParticipants The participant(s).
813     */
814    public void updateConferenceParticipants(List<ConferenceParticipant> conferenceParticipants) {
815        for (Listener l : mListeners) {
816            l.onConferenceParticipantsChanged(conferenceParticipants);
817        }
818    }
819
820    /**
821     * Notifies listeners of a change to the multiparty state of the connection.
822     *
823     * @param isMultiparty The participant(s).
824     */
825    public void updateMultipartyState(boolean isMultiparty) {
826        for (Listener l : mListeners) {
827            l.onMultipartyStateChanged(isMultiparty);
828        }
829    }
830
831    /**
832     * Notifies listeners of a failure in merging this connection with the background connection.
833     */
834    public void onConferenceMergeFailed() {
835        for (Listener l : mListeners) {
836            l.onConferenceMergedFailed();
837        }
838    }
839
840    /**
841     * Notifies that the underlying phone has exited ECM mode.
842     */
843    public void onExitedEcmMode() {
844        for (Listener l : mListeners) {
845            l.onExitedEcmMode();
846        }
847    }
848
849    /**
850     * Notifies this Connection of a request to disconnect a participant of the conference managed
851     * by the connection.
852     *
853     * @param endpoint the {@link Uri} of the participant to disconnect.
854     */
855    public void onDisconnectConferenceParticipant(Uri endpoint) {
856    }
857
858    /**
859     * Called by a {@link android.telecom.Connection} to indicate that this call should be pulled
860     * to the local device.
861     */
862    public void pullExternalCall() {
863    }
864
865    /**
866     *
867     */
868    public int getPhoneType() {
869        return mPhoneType;
870    }
871
872    /**
873     * Build a human representation of a connection instance, suitable for debugging.
874     * Don't log personal stuff unless in debug mode.
875     * @return a string representing the internal state of this connection.
876     */
877    public String toString() {
878        StringBuilder str = new StringBuilder(128);
879
880        str.append(" callId: " + getTelecomCallId());
881        if (Rlog.isLoggable(LOG_TAG, Log.DEBUG)) {
882            str.append("addr: " + getAddress())
883                    .append(" pres.: " + getNumberPresentation())
884                    .append(" dial: " + getOrigDialString())
885                    .append(" postdial: " + getRemainingPostDialString())
886                    .append(" cnap name: " + getCnapName())
887                    .append("(" + getCnapNamePresentation() + ")");
888        }
889        str.append(" incoming: " + isIncoming())
890                .append(" state: " + getState())
891                .append(" post dial state: " + getPostDialState());
892        return str.toString();
893    }
894}
895