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 
17 package com.android.internal.telephony;
18 
19 import android.net.Uri;
20 import android.os.Bundle;
21 import android.os.SystemClock;
22 import android.telecom.ConferenceParticipant;
23 import android.telephony.DisconnectCause;
24 import android.telephony.Rlog;
25 import android.util.Log;
26 
27 import java.lang.Override;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Set;
31 import java.util.concurrent.CopyOnWriteArraySet;
32 
33 /**
34  * {@hide}
35  */
36 public abstract class Connection {
37     private static final String TAG = "Connection";
38 
39     public interface PostDialListener {
onPostDialWait()40         void onPostDialWait();
onPostDialChar(char c)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 {
onVideoStateChanged(int videoState)90         public void onVideoStateChanged(int videoState);
onConnectionCapabilitiesChanged(int capability)91         public void onConnectionCapabilitiesChanged(int capability);
onWifiChanged(boolean isWifi)92         public void onWifiChanged(boolean isWifi);
onVideoProviderChanged( android.telecom.Connection.VideoProvider videoProvider)93         public void onVideoProviderChanged(
94                 android.telecom.Connection.VideoProvider videoProvider);
onAudioQualityChanged(int audioQuality)95         public void onAudioQualityChanged(int audioQuality);
onConferenceParticipantsChanged(List<ConferenceParticipant> participants)96         public void onConferenceParticipantsChanged(List<ConferenceParticipant> participants);
onCallSubstateChanged(int callSubstate)97         public void onCallSubstateChanged(int callSubstate);
onMultipartyStateChanged(boolean isMultiParty)98         public void onMultipartyStateChanged(boolean isMultiParty);
onConferenceMergedFailed()99         public void onConferenceMergedFailed();
onExtrasChanged(Bundle extras)100         public void onExtrasChanged(Bundle extras);
onExitedEcmMode()101         public void onExitedEcmMode();
onCallPullFailed(Connection externalConnection)102         public void onCallPullFailed(Connection externalConnection);
onHandoverToWifiFailed()103         public void onHandoverToWifiFailed();
onConnectionEvent(String event, Bundle extras)104         public void onConnectionEvent(String event, Bundle extras);
onRttModifyRequestReceived()105         public void onRttModifyRequestReceived();
onRttModifyResponseReceived(int status)106         public void onRttModifyResponseReceived(int status);
onDisconnect(int cause)107         public void onDisconnect(int cause);
onRttInitiated()108         public void onRttInitiated();
onRttTerminated()109         public void onRttTerminated();
110     }
111 
112     /**
113      * Base listener implementation.
114      */
115     public abstract static class ListenerBase implements Listener {
116         @Override
onVideoStateChanged(int videoState)117         public void onVideoStateChanged(int videoState) {}
118         @Override
onConnectionCapabilitiesChanged(int capability)119         public void onConnectionCapabilitiesChanged(int capability) {}
120         @Override
onWifiChanged(boolean isWifi)121         public void onWifiChanged(boolean isWifi) {}
122         @Override
onVideoProviderChanged( android.telecom.Connection.VideoProvider videoProvider)123         public void onVideoProviderChanged(
124                 android.telecom.Connection.VideoProvider videoProvider) {}
125         @Override
onAudioQualityChanged(int audioQuality)126         public void onAudioQualityChanged(int audioQuality) {}
127         @Override
onConferenceParticipantsChanged(List<ConferenceParticipant> participants)128         public void onConferenceParticipantsChanged(List<ConferenceParticipant> participants) {}
129         @Override
onCallSubstateChanged(int callSubstate)130         public void onCallSubstateChanged(int callSubstate) {}
131         @Override
onMultipartyStateChanged(boolean isMultiParty)132         public void onMultipartyStateChanged(boolean isMultiParty) {}
133         @Override
onConferenceMergedFailed()134         public void onConferenceMergedFailed() {}
135         @Override
onExtrasChanged(Bundle extras)136         public void onExtrasChanged(Bundle extras) {}
137         @Override
onExitedEcmMode()138         public void onExitedEcmMode() {}
139         @Override
onCallPullFailed(Connection externalConnection)140         public void onCallPullFailed(Connection externalConnection) {}
141         @Override
onHandoverToWifiFailed()142         public void onHandoverToWifiFailed() {}
143         @Override
onConnectionEvent(String event, Bundle extras)144         public void onConnectionEvent(String event, Bundle extras) {}
145         @Override
onRttModifyRequestReceived()146         public void onRttModifyRequestReceived() {}
147         @Override
onRttModifyResponseReceived(int status)148         public void onRttModifyResponseReceived(int status) {}
149         @Override
onDisconnect(int cause)150         public void onDisconnect(int cause) {}
151         @Override
onRttInitiated()152         public void onRttInitiated() {}
153         @Override
onRttTerminated()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 
Connection(int phoneType)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      */
getTelecomCallId()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      */
setTelecomCallId(String telecomCallId)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 
getAddress()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      */
getCnapName()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      */
getOrigDialString()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 
getCnapNamePresentation()285     public int getCnapNamePresentation() {
286        return mCnapNamePresentation;
287     }
288 
289     /**
290      * @return Call that owns this Connection, or null if none
291      */
getCall()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      */
getCreateTime()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      */
getConnectTime()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      */
setConnectTime(long connectTime)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      */
setConnectTimeReal(long connectTimeReal)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      */
getConnectTimeReal()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      */
getDisconnectTime()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      */
getDurationMillis()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      */
getHoldingStartTime()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 
getHoldDurationMillis()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      */
getDisconnectCause()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      */
getVendorDisconnectCause()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      */
isIncoming()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      */
setIsIncoming(boolean isIncoming)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      */
getState()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      */
getStateBeforeHandover()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      */
getConferenceParticipants()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
isAlive()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
isRinging()476     isRinging() {
477         return getState().isRinging();
478     }
479 
480     /**
481      *
482      * @return the userdata set in setUserData()
483      */
getUserData()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      */
setUserData(Object userdata)492     public void setUserData(Object userdata) {
493         mUserData = userdata;
494     }
495 
496     /**
497      * Deflect individual Connection
498      */
deflect(String number)499     public abstract void deflect(String number) throws CallStateException;
500 
501     /**
502      * Hangup individual Connection
503      */
hangup()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      */
separate()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 
clearUserData()529     public void clearUserData(){
530         mUserData = null;
531     }
532 
addPostDialListener(PostDialListener listener)533     public void addPostDialListener(PostDialListener listener) {
534         if (!mPostDialListeners.contains(listener)) {
535             mPostDialListeners.add(listener);
536         }
537     }
538 
removePostDialListener(PostDialListener listener)539     public final void removePostDialListener(PostDialListener listener) {
540         mPostDialListeners.remove(listener);
541     }
542 
clearPostDialListeners()543     protected final void clearPostDialListeners() {
544         if (mPostDialListeners != null) {
545             mPostDialListeners.clear();
546         }
547     }
548 
notifyPostDialListeners()549     protected final void notifyPostDialListeners() {
550         if (getPostDialState() == PostDialState.WAIT) {
551             for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) {
552                 listener.onPostDialWait();
553             }
554         }
555     }
556 
notifyPostDialListenersNextChar(char c)557     protected final void notifyPostDialListenersNextChar(char c) {
558         for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) {
559             listener.onPostDialChar(c);
560         }
561     }
562 
getPostDialState()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      */
getRemainingPostDialString()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 
proceedAfterWaitChar()586     public abstract void proceedAfterWaitChar();
587 
588     /**
589      * See Phone.setOnPostDialWildCharacter()
590      */
proceedAfterWildChar(String str)591     public abstract void proceedAfterWildChar(String str);
592     /**
593      * Cancel any post
594      */
cancelPostDial()595     public abstract void cancelPostDial();
596 
597     /** Called when the connection has been disconnected */
onDisconnect(int cause)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      */
getNumberPresentation()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      */
getUUSInfo()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      */
getPreciseDisconnectCause()619     public abstract int getPreciseDisconnectCause();
620 
621     /**
622      * Returns the original Connection instance associated with
623      * this Connection
624      */
getOrigConnection()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      */
isMultiparty()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      */
isConferenceHost()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      */
isMemberOfPeerConference()654     public boolean isMemberOfPeerConference() {
655         return false;
656     }
657 
migrateFrom(Connection c)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      */
addListener(Listener listener)677     public void addListener(Listener listener) {
678         mListeners.add(listener);
679     }
680 
681     /**
682      * Removes a listener.
683      *
684      * @param listener A listener.
685      */
removeListener(Listener listener)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      */
getVideoState()695     public int getVideoState() {
696         return mVideoState;
697     }
698 
699     /**
700      * Called to get Connection capabilities.Returns Capabilities bitmask.
701      * @See Connection.Capability.
702      */
getConnectionCapabilities()703     public int getConnectionCapabilities() {
704         return mConnectionCapabilities;
705     }
706 
707     /**
708      * @return {@code} true if the connection has the specified capabilities.
709      */
hasCapabilities(int connectionCapabilities)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      */
addCapability(int capabilities, int capability)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      */
removeCapability(int capabilities, int capability)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      */
isWifi()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      */
getAudioModeIsVoip()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      */
getVideoProvider()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      */
getAudioQuality()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      */
getCallSubstate()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      */
setVideoState(int videoState)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      */
setConnectionCapabilities(int capabilities)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      */
setWifi(boolean isWifi)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      */
setAudioModeIsVoip(boolean isVoip)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      */
setAudioQuality(int audioQuality)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      */
setConnectionExtras(Bundle extras)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      */
getConnectionExtras()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      */
isActiveCallDisconnectedOnAnswer()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      */
setActiveCallDisconnectedOnAnswer(boolean answeringDisconnectsActiveCall)897     public void setActiveCallDisconnectedOnAnswer(boolean answeringDisconnectsActiveCall) {
898         mAnsweringDisconnectsActiveCall = answeringDisconnectsActiveCall;
899     }
900 
shouldAllowAddCallDuringVideoCall()901     public boolean shouldAllowAddCallDuringVideoCall() {
902         return mAllowAddCallDuringVideoCall;
903     }
904 
setAllowAddCallDuringVideoCall(boolean allowAddCallDuringVideoCall)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      */
setIsPulledCall(boolean isPulledCall)916     public void setIsPulledCall(boolean isPulledCall) {
917         mIsPulledCall = isPulledCall;
918     }
919 
isPulledCall()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      */
setPulledDialogId(int pulledDialogId)931     public void setPulledDialogId(int pulledDialogId) {
932         mPulledDialogId = pulledDialogId;
933     }
934 
getPulledDialogId()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      */
setCallSubstate(int callSubstate)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      */
setVideoProvider(android.telecom.Connection.VideoProvider videoProvider)957     public void setVideoProvider(android.telecom.Connection.VideoProvider videoProvider) {
958         mVideoProvider = videoProvider;
959         for (Listener l : mListeners) {
960             l.onVideoProviderChanged(mVideoProvider);
961         }
962     }
963 
setConverted(String oriNumber)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      */
updateConferenceParticipants(List<ConferenceParticipant> conferenceParticipants)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      */
updateMultipartyState(boolean isMultiparty)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      */
onConferenceMergeFailed()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      */
onExitedEcmMode()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      */
onCallPullFailed(Connection externalConnection)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      */
onHandoverToWifiFailed()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      */
onConnectionEvent(String event, Bundle extras)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      */
onDisconnectConferenceParticipant(Uri endpoint)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      */
pullExternalCall()1056     public void pullExternalCall() {
1057     }
1058 
onRttModifyRequestReceived()1059     public void onRttModifyRequestReceived() {
1060         for (Listener l : mListeners) {
1061             l.onRttModifyRequestReceived();
1062         }
1063     }
1064 
onRttModifyResponseReceived(int status)1065     public void onRttModifyResponseReceived(int status) {
1066         for (Listener l : mListeners) {
1067             l.onRttModifyResponseReceived(status);
1068         }
1069     }
1070 
onRttInitiated()1071     public void onRttInitiated() {
1072         for (Listener l : mListeners) {
1073             l.onRttInitiated();
1074         }
1075     }
1076 
onRttTerminated()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      */
notifyDisconnect(int reason)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      */
getPhoneType()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      */
toString()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