1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.telephony;
18
19import android.net.Uri;
20import android.os.SystemClock;
21import android.telecom.ConferenceParticipant;
22import android.telephony.Rlog;
23import android.util.Log;
24
25import java.lang.Override;
26import java.util.ArrayList;
27import java.util.List;
28import java.util.Set;
29import java.util.concurrent.CopyOnWriteArraySet;
30
31/**
32 * {@hide}
33 */
34public abstract class Connection {
35    public interface PostDialListener {
36        void onPostDialWait();
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 {
45        public void onVideoStateChanged(int videoState);
46        public void onLocalVideoCapabilityChanged(boolean capable);
47        public void onRemoteVideoCapabilityChanged(boolean capable);
48        public void onVideoProviderChanged(
49                android.telecom.Connection.VideoProvider videoProvider);
50        public void onAudioQualityChanged(int audioQuality);
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
59        public void onVideoStateChanged(int videoState) {}
60        @Override
61        public void onLocalVideoCapabilityChanged(boolean capable) {}
62        @Override
63        public void onRemoteVideoCapabilityChanged(boolean capable) {}
64        @Override
65        public void onVideoProviderChanged(
66                android.telecom.Connection.VideoProvider videoProvider) {}
67        @Override
68        public void onAudioQualityChanged(int audioQuality) {}
69        @Override
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
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     */
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     */
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
149    public int getCnapNamePresentation() {
150       return mCnapNamePresentation;
151    }
152
153    /**
154     * @return Call that owns this Connection, or null if none
155     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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     */
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     */
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     */
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     */
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
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
295    isRinging() {
296        return getState().isRinging();
297    }
298
299    /**
300     *
301     * @return the userdata set in setUserData()
302     */
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     */
311    public void setUserData(Object userdata) {
312        mUserData = userdata;
313    }
314
315    /**
316     * Hangup individual Connection
317     */
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     */
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
343    public void clearUserData(){
344        mUserData = null;
345    }
346
347    public final void addPostDialListener(PostDialListener listener) {
348        if (!mPostDialListeners.contains(listener)) {
349            mPostDialListeners.add(listener);
350        }
351    }
352
353    protected final void clearPostDialListeners() {
354        mPostDialListeners.clear();
355    }
356
357    protected final void notifyPostDialListeners() {
358        if (getPostDialState() == PostDialState.WAIT) {
359            for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) {
360                listener.onPostDialWait();
361            }
362        }
363    }
364
365    protected final void notifyPostDialListenersNextChar(char c) {
366        for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) {
367            listener.onPostDialChar(c);
368        }
369    }
370
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     */
377    public abstract String getRemainingPostDialString();
378
379    /**
380     * See Phone.setOnPostDialWaitCharacter()
381     */
382
383    public abstract void proceedAfterWaitChar();
384
385    /**
386     * See Phone.setOnPostDialWildCharacter()
387     */
388    public abstract void proceedAfterWildChar(String str);
389    /**
390     * Cancel any post
391     */
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     */
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     */
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     */
411    public abstract int getPreciseDisconnectCause();
412
413    /**
414     * Returns the original Connection instance associated with
415     * this Connection
416     */
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     */
426    public abstract boolean isMultiparty();
427
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
561    public void setVideoProvider(android.telecom.Connection.VideoProvider videoProvider) {
562        mVideoProvider = videoProvider;
563        for (Listener l : mListeners) {
564            l.onVideoProviderChanged(mVideoProvider);
565        }
566    }
567
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     */
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     */
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     */
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