Home | History | Annotate | Download | only in telephony
      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 {
     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 onWifiChanged(boolean isWifi);
     49         public void onVideoProviderChanged(
     50                 android.telecom.Connection.VideoProvider videoProvider);
     51         public void onAudioQualityChanged(int audioQuality);
     52         public void onConferenceParticipantsChanged(List<ConferenceParticipant> participants);
     53         public void onCallSubstateChanged(int callSubstate);
     54         public void onMultipartyStateChanged(boolean isMultiParty);
     55         public void onConferenceMergedFailed();
     56     }
     57 
     58     /**
     59      * Base listener implementation.
     60      */
     61     public abstract static class ListenerBase implements Listener {
     62         @Override
     63         public void onVideoStateChanged(int videoState) {}
     64         @Override
     65         public void onLocalVideoCapabilityChanged(boolean capable) {}
     66         @Override
     67         public void onRemoteVideoCapabilityChanged(boolean capable) {}
     68         @Override
     69         public void onWifiChanged(boolean isWifi) {}
     70         @Override
     71         public void onVideoProviderChanged(
     72                 android.telecom.Connection.VideoProvider videoProvider) {}
     73         @Override
     74         public void onAudioQualityChanged(int audioQuality) {}
     75         @Override
     76         public void onConferenceParticipantsChanged(List<ConferenceParticipant> participants) {}
     77         @Override
     78         public void onCallSubstateChanged(int callSubstate) {}
     79         @Override
     80         public void onMultipartyStateChanged(boolean isMultiParty) {}
     81         @Override
     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 
    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      */
    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      */
    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 
    163     public int getCnapNamePresentation() {
    164        return mCnapNamePresentation;
    165     }
    166 
    167     /**
    168      * @return Call that owns this Connection, or null if none
    169      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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
    334     isRinging() {
    335         return getState().isRinging();
    336     }
    337 
    338     /**
    339      *
    340      * @return the userdata set in setUserData()
    341      */
    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      */
    350     public void setUserData(Object userdata) {
    351         mUserData = userdata;
    352     }
    353 
    354     /**
    355      * Hangup individual Connection
    356      */
    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      */
    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 
    382     public void clearUserData(){
    383         mUserData = null;
    384     }
    385 
    386     public final void addPostDialListener(PostDialListener listener) {
    387         if (!mPostDialListeners.contains(listener)) {
    388             mPostDialListeners.add(listener);
    389         }
    390     }
    391 
    392     public final void removePostDialListener(PostDialListener listener) {
    393         mPostDialListeners.remove(listener);
    394     }
    395 
    396     protected final void clearPostDialListeners() {
    397         mPostDialListeners.clear();
    398     }
    399 
    400     protected final void notifyPostDialListeners() {
    401         if (getPostDialState() == PostDialState.WAIT) {
    402             for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) {
    403                 listener.onPostDialWait();
    404             }
    405         }
    406     }
    407 
    408     protected final void notifyPostDialListenersNextChar(char c) {
    409         for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) {
    410             listener.onPostDialChar(c);
    411         }
    412     }
    413 
    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      */
    420     public abstract String getRemainingPostDialString();
    421 
    422     /**
    423      * See Phone.setOnPostDialWaitCharacter()
    424      */
    425 
    426     public abstract void proceedAfterWaitChar();
    427 
    428     /**
    429      * See Phone.setOnPostDialWildCharacter()
    430      */
    431     public abstract void proceedAfterWildChar(String str);
    432     /**
    433      * Cancel any post
    434      */
    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      */
    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      */
    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      */
    454     public abstract int getPreciseDisconnectCause();
    455 
    456     /**
    457      * Returns the original Connection instance associated with
    458      * this Connection
    459      */
    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      */
    469     public abstract boolean isMultiparty();
    470 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    649     public void setVideoProvider(android.telecom.Connection.VideoProvider videoProvider) {
    650         mVideoProvider = videoProvider;
    651         for (Listener l : mListeners) {
    652             l.onVideoProviderChanged(mVideoProvider);
    653         }
    654     }
    655 
    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      */
    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      */
    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      */
    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      */
    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      */
    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