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