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