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