Home | History | Annotate | Download | only in incallui
      1 /*
      2  * Copyright (C) 2013 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.incallui;
     18 
     19 import com.android.contacts.common.CallUtil;
     20 
     21 import android.content.Context;
     22 import android.net.Uri;
     23 import android.telecom.CallProperties;
     24 import android.telecom.DisconnectCause;
     25 import android.telecom.GatewayInfo;
     26 import android.telecom.InCallService.VideoCall;
     27 import android.telecom.PhoneAccountHandle;
     28 import android.telecom.VideoProfile;
     29 
     30 import java.util.ArrayList;
     31 import java.util.List;
     32 import java.util.Locale;
     33 
     34 /**
     35  * Describes a single call and its state.
     36  */
     37 public final class Call {
     38     /* Defines different states of this call */
     39     public static class State {
     40         public static final int INVALID = 0;
     41         public static final int NEW = 1;            /* The call is new. */
     42         public static final int IDLE = 2;           /* The call is idle.  Nothing active */
     43         public static final int ACTIVE = 3;         /* There is an active call */
     44         public static final int INCOMING = 4;       /* A normal incoming phone call */
     45         public static final int CALL_WAITING = 5;   /* Incoming call while another is active */
     46         public static final int DIALING = 6;        /* An outgoing call during dial phase */
     47         public static final int REDIALING = 7;      /* Subsequent dialing attempt after a failure */
     48         public static final int ONHOLD = 8;         /* An active phone call placed on hold */
     49         public static final int DISCONNECTING = 9;  /* A call is being ended. */
     50         public static final int DISCONNECTED = 10;  /* State after a call disconnects */
     51         public static final int CONFERENCED = 11;   /* Call part of a conference call */
     52         public static final int PRE_DIAL_WAIT = 12; /* Waiting for user before outgoing call */
     53         public static final int CONNECTING = 13;    /* Waiting for Telecomm broadcast to finish */
     54 
     55 
     56         public static boolean isConnectingOrConnected(int state) {
     57             switch(state) {
     58                 case ACTIVE:
     59                 case INCOMING:
     60                 case CALL_WAITING:
     61                 case CONNECTING:
     62                 case DIALING:
     63                 case REDIALING:
     64                 case ONHOLD:
     65                 case CONFERENCED:
     66                     return true;
     67                 default:
     68             }
     69             return false;
     70         }
     71 
     72         public static boolean isDialing(int state) {
     73             return state == DIALING || state == REDIALING;
     74         }
     75 
     76         public static String toString(int state) {
     77             switch (state) {
     78                 case INVALID:
     79                     return "INVALID";
     80                 case NEW:
     81                     return "NEW";
     82                 case IDLE:
     83                     return "IDLE";
     84                 case ACTIVE:
     85                     return "ACTIVE";
     86                 case INCOMING:
     87                     return "INCOMING";
     88                 case CALL_WAITING:
     89                     return "CALL_WAITING";
     90                 case DIALING:
     91                     return "DIALING";
     92                 case REDIALING:
     93                     return "REDIALING";
     94                 case ONHOLD:
     95                     return "ONHOLD";
     96                 case DISCONNECTING:
     97                     return "DISCONNECTING";
     98                 case DISCONNECTED:
     99                     return "DISCONNECTED";
    100                 case CONFERENCED:
    101                     return "CONFERENCED";
    102                 case PRE_DIAL_WAIT:
    103                     return "PRE_DIAL_WAIT";
    104                 case CONNECTING:
    105                     return "CONNECTING";
    106                 default:
    107                     return "UNKNOWN";
    108             }
    109         }
    110     }
    111 
    112     /**
    113      * Defines different states of session modify requests, which are used to upgrade to video, or
    114      * downgrade to audio.
    115      */
    116     public static class SessionModificationState {
    117         public static final int NO_REQUEST = 0;
    118         public static final int WAITING_FOR_RESPONSE = 1;
    119         public static final int REQUEST_FAILED = 2;
    120         public static final int RECEIVED_UPGRADE_TO_VIDEO_REQUEST = 3;
    121     }
    122 
    123     private static final String ID_PREFIX = Call.class.getSimpleName() + "_";
    124     private static int sIdCounter = 0;
    125 
    126     private android.telecom.Call.Listener mTelecommCallListener =
    127             new android.telecom.Call.Listener() {
    128                 @Override
    129                 public void onStateChanged(android.telecom.Call call, int newState) {
    130                     update();
    131                 }
    132 
    133                 @Override
    134                 public void onParentChanged(android.telecom.Call call,
    135                         android.telecom.Call newParent) {
    136                     update();
    137                 }
    138 
    139                 @Override
    140                 public void onChildrenChanged(android.telecom.Call call,
    141                         List<android.telecom.Call> children) {
    142                     update();
    143                 }
    144 
    145                 @Override
    146                 public void onDetailsChanged(android.telecom.Call call,
    147                         android.telecom.Call.Details details) {
    148                     update();
    149                 }
    150 
    151                 @Override
    152                 public void onCannedTextResponsesLoaded(android.telecom.Call call,
    153                         List<String> cannedTextResponses) {
    154                     update();
    155                 }
    156 
    157                 @Override
    158                 public void onPostDialWait(android.telecom.Call call,
    159                         String remainingPostDialSequence) {
    160                     update();
    161                 }
    162 
    163                 @Override
    164                 public void onVideoCallChanged(android.telecom.Call call,
    165                         VideoCall videoCall) {
    166                     update();
    167                 }
    168 
    169                 @Override
    170                 public void onCallDestroyed(android.telecom.Call call) {
    171                     call.removeListener(mTelecommCallListener);
    172                 }
    173 
    174                 @Override
    175                 public void onConferenceableCallsChanged(android.telecom.Call call,
    176                         List<android.telecom.Call> conferenceableCalls) {
    177                     update();
    178                 }
    179             };
    180 
    181     private final android.telecom.Call mTelecommCall;
    182     private final String mId;
    183     private int mState = State.INVALID;
    184     private DisconnectCause mDisconnectCause;
    185     private int mSessionModificationState;
    186     private final List<String> mChildCallIds = new ArrayList<>();
    187 
    188     private InCallVideoCallListener mVideoCallListener;
    189 
    190     public Call(android.telecom.Call telecommCall) {
    191         mTelecommCall = telecommCall;
    192         mId = ID_PREFIX + Integer.toString(sIdCounter++);
    193         updateFromTelecommCall();
    194         mTelecommCall.addListener(mTelecommCallListener);
    195     }
    196 
    197     public android.telecom.Call getTelecommCall() {
    198         return mTelecommCall;
    199     }
    200 
    201     private void update() {
    202         int oldState = getState();
    203         updateFromTelecommCall();
    204         if (oldState != getState() && getState() == Call.State.DISCONNECTED) {
    205             CallList.getInstance().onDisconnect(this);
    206         } else {
    207             CallList.getInstance().onUpdate(this);
    208         }
    209     }
    210 
    211     private void updateFromTelecommCall() {
    212         Log.d(this, "updateFromTelecommCall: " + mTelecommCall);
    213         setState(translateState(mTelecommCall.getState()));
    214         setDisconnectCause(mTelecommCall.getDetails().getDisconnectCause());
    215 
    216         if (mTelecommCall.getVideoCall() != null) {
    217             if (mVideoCallListener == null) {
    218                 mVideoCallListener = new InCallVideoCallListener(this);
    219             }
    220             mTelecommCall.getVideoCall().setVideoCallListener(mVideoCallListener);
    221         }
    222 
    223         mChildCallIds.clear();
    224         for (int i = 0; i < mTelecommCall.getChildren().size(); i++) {
    225             mChildCallIds.add(
    226                     CallList.getInstance().getCallByTelecommCall(
    227                             mTelecommCall.getChildren().get(i)).getId());
    228         }
    229     }
    230 
    231     private static int translateState(int state) {
    232         switch (state) {
    233             case android.telecom.Call.STATE_NEW:
    234                 return Call.State.NEW;
    235             case android.telecom.Call.STATE_CONNECTING:
    236                 return Call.State.CONNECTING;
    237             case android.telecom.Call.STATE_PRE_DIAL_WAIT:
    238                 return Call.State.PRE_DIAL_WAIT;
    239             case android.telecom.Call.STATE_DIALING:
    240                 return Call.State.DIALING;
    241             case android.telecom.Call.STATE_RINGING:
    242                 return Call.State.INCOMING;
    243             case android.telecom.Call.STATE_ACTIVE:
    244                 return Call.State.ACTIVE;
    245             case android.telecom.Call.STATE_HOLDING:
    246                 return Call.State.ONHOLD;
    247             case android.telecom.Call.STATE_DISCONNECTED:
    248                 return Call.State.DISCONNECTED;
    249             case android.telecom.Call.STATE_DISCONNECTING:
    250                 return Call.State.DISCONNECTING;
    251             default:
    252                 return Call.State.INVALID;
    253         }
    254     }
    255 
    256     public String getId() {
    257         return mId;
    258     }
    259 
    260     public String getNumber() {
    261         if (mTelecommCall.getDetails().getGatewayInfo() != null) {
    262             return mTelecommCall.getDetails().getGatewayInfo()
    263                     .getOriginalAddress().getSchemeSpecificPart();
    264         }
    265         return getHandle() == null ? null : getHandle().getSchemeSpecificPart();
    266     }
    267 
    268     public Uri getHandle() {
    269         return mTelecommCall.getDetails().getHandle();
    270     }
    271 
    272     public int getState() {
    273         if (mTelecommCall.getParent() != null) {
    274             return State.CONFERENCED;
    275         } else {
    276             return mState;
    277         }
    278     }
    279 
    280     public void setState(int state) {
    281         mState = state;
    282     }
    283 
    284     public int getNumberPresentation() {
    285         return getTelecommCall().getDetails().getHandlePresentation();
    286     }
    287 
    288     public int getCnapNamePresentation() {
    289         return getTelecommCall().getDetails().getCallerDisplayNamePresentation();
    290     }
    291 
    292     public String getCnapName() {
    293         return getTelecommCall().getDetails().getCallerDisplayName();
    294     }
    295 
    296     /** Returns call disconnect cause, defined by {@link DisconnectCause}. */
    297     public DisconnectCause getDisconnectCause() {
    298         if (mState == State.DISCONNECTED || mState == State.IDLE) {
    299             return mDisconnectCause;
    300         }
    301 
    302         return new DisconnectCause(DisconnectCause.UNKNOWN);
    303     }
    304 
    305     public void setDisconnectCause(DisconnectCause disconnectCause) {
    306         mDisconnectCause = disconnectCause;
    307     }
    308 
    309     /** Returns the possible text message responses. */
    310     public List<String> getCannedSmsResponses() {
    311         return mTelecommCall.getCannedTextResponses();
    312     }
    313 
    314     /** Checks if the call supports the given set of capabilities supplied as a bit mask. */
    315     public boolean can(int capabilities) {
    316         int supportedCapabilities = mTelecommCall.getDetails().getCallCapabilities();
    317 
    318         if ((capabilities & android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE) != 0) {
    319             // We allow you to merge if the capabilities allow it or if it is a call with
    320             // conferenceable calls.
    321             if (mTelecommCall.getConferenceableCalls().isEmpty() &&
    322                 ((android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE
    323                         & supportedCapabilities) == 0)) {
    324                 // Cannot merge calls if there are no calls to merge with.
    325                 return false;
    326             }
    327             capabilities &= ~android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE;
    328         }
    329         return (capabilities == (capabilities & mTelecommCall.getDetails().getCallCapabilities()));
    330     }
    331 
    332     private boolean hasProperty(int property) {
    333         return property == (property & mTelecommCall.getDetails().getCallProperties());
    334     }
    335 
    336     /** Gets the time when the call first became active. */
    337     public long getConnectTimeMillis() {
    338         return mTelecommCall.getDetails().getConnectTimeMillis();
    339     }
    340 
    341     public boolean isConferenceCall() {
    342         return hasProperty(CallProperties.CONFERENCE);
    343     }
    344 
    345     public GatewayInfo getGatewayInfo() {
    346         return mTelecommCall.getDetails().getGatewayInfo();
    347     }
    348 
    349     public PhoneAccountHandle getAccountHandle() {
    350         return mTelecommCall.getDetails().getAccountHandle();
    351     }
    352 
    353     public VideoCall getVideoCall() {
    354         return mTelecommCall.getVideoCall();
    355     }
    356 
    357     public List<String> getChildCallIds() {
    358         return mChildCallIds;
    359     }
    360 
    361     public String getParentId() {
    362         android.telecom.Call parentCall = mTelecommCall.getParent();
    363         if (parentCall != null) {
    364             return CallList.getInstance().getCallByTelecommCall(parentCall).getId();
    365         }
    366         return null;
    367     }
    368 
    369     public int getVideoState() {
    370         return mTelecommCall.getDetails().getVideoState();
    371     }
    372 
    373     public boolean isVideoCall(Context context) {
    374         return CallUtil.isVideoEnabled(context) &&
    375                 VideoProfile.VideoState.isBidirectional(getVideoState());
    376     }
    377 
    378     public void setSessionModificationState(int state) {
    379         boolean hasChanged = mSessionModificationState != state;
    380         mSessionModificationState = state;
    381 
    382         if (hasChanged) {
    383             update();
    384         }
    385     }
    386 
    387     public static boolean areSame(Call call1, Call call2) {
    388         if (call1 == null && call2 == null) {
    389             return true;
    390         } else if (call1 == null || call2 == null) {
    391             return false;
    392         }
    393 
    394         // otherwise compare call Ids
    395         return call1.getId().equals(call2.getId());
    396     }
    397 
    398     public int getSessionModificationState() {
    399         return mSessionModificationState;
    400     }
    401 
    402     @Override
    403     public String toString() {
    404         return String.format(Locale.US, "[%s, %s, %s, children:%s, parent:%s, conferenceable:%s, " +
    405                 "videoState:%d]",
    406                 mId,
    407                 State.toString(getState()),
    408                 android.telecom.Call.Details
    409                         .capabilitiesToString(mTelecommCall.getDetails().getCallCapabilities()),
    410                 mChildCallIds,
    411                 getParentId(),
    412                 this.mTelecommCall.getConferenceableCalls(),
    413                 mTelecommCall.getDetails().getVideoState());
    414     }
    415 }
    416