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