Home | History | Annotate | Download | only in common
      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.services.telephony.common;
     18 
     19 import android.os.Parcel;
     20 import android.os.Parcelable;
     21 
     22 import com.android.internal.telephony.PhoneConstants;
     23 import com.google.android.collect.Sets;
     24 import com.google.common.base.Objects;
     25 import com.google.common.collect.ImmutableMap;
     26 import com.google.common.collect.ImmutableSortedSet;
     27 import com.google.common.primitives.Ints;
     28 
     29 import java.util.Map;
     30 import java.util.SortedSet;
     31 import java.util.TreeSet;
     32 
     33 /**
     34  * Class object used across CallHandlerService APIs.
     35  * Describes a single call and its state.
     36  */
     37 public final class Call implements Parcelable {
     38 
     39     public static final int INVALID_CALL_ID = -1;
     40     public static final int MAX_CONFERENCED_CALLS = 5;
     41 
     42     /* Defines different states of this call */
     43     public static class State {
     44         public static final int INVALID = 0;
     45         public static final int IDLE = 1;           /* The call is idle.  Nothing active */
     46         public static final int ACTIVE = 2;         /* There is an active call */
     47         public static final int INCOMING = 3;       /* A normal incoming phone call */
     48         public static final int CALL_WAITING = 4;   /* Incoming call while another is active */
     49         public static final int DIALING = 5;        /* An outgoing call during dial phase */
     50         public static final int REDIALING = 6;      /* Subsequent dialing attempt after a failure */
     51         public static final int ONHOLD = 7;         /* An active phone call placed on hold */
     52         public static final int DISCONNECTING = 8;  /* A call is being ended. */
     53         public static final int DISCONNECTED = 9;   /* State after a call disconnects */
     54         public static final int CONFERENCED = 10;   /* Call part of a conference call */
     55 
     56         public static boolean isConnected(int state) {
     57             switch(state) {
     58                 case ACTIVE:
     59                 case INCOMING:
     60                 case CALL_WAITING:
     61                 case DIALING:
     62                 case REDIALING:
     63                 case ONHOLD:
     64                 case CONFERENCED:
     65                     return true;
     66                 default:
     67             }
     68             return false;
     69         }
     70 
     71         public static boolean isDialing(int state) {
     72             return state == DIALING || state == REDIALING;
     73         }
     74     }
     75 
     76     /**
     77      * Defines a set of capabilities that a call can have as a bit mask.
     78      * TODO: Should some of these be capabilities of the Phone instead of the call?
     79      * TODO: This is starting to be a mix of capabilities and call properties.  Capabilities
     80      *       and properties should be separated.
     81      */
     82     public static class Capabilities {
     83         public static final int HOLD               = 0x00000001; /* has ability to hold the call */
     84         public static final int SUPPORT_HOLD       = 0x00000002; /* can show the hold button */
     85         public static final int MERGE_CALLS        = 0x00000004; /* has ability to merge calls */
     86         public static final int SWAP_CALLS         = 0x00000008; /* swap with a background call */
     87         public static final int ADD_CALL           = 0x00000010; /* add another call to this one */
     88         public static final int RESPOND_VIA_TEXT   = 0x00000020; /* has respond via text option */
     89         public static final int MUTE               = 0x00000040; /* can mute the call */
     90         public static final int GENERIC_CONFERENCE = 0x00000080; /* Generic conference mode */
     91 
     92         public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CALLS | SWAP_CALLS | ADD_CALL
     93                 | RESPOND_VIA_TEXT | MUTE | GENERIC_CONFERENCE;
     94     }
     95 
     96     /**
     97      * Copy of states found in Connection object since Connection object is not available to the UI
     98      * code.
     99      * TODO: Consider cutting this down to only the types used by the UI.
    100      * TODO: Consider adding a CUSTOM cause type and a customDisconnect member variable to
    101      *       the Call object.  This would allow OEMs to extend the cause list without
    102      *       needing to alter our implementation.
    103      */
    104     public enum DisconnectCause {
    105         NOT_DISCONNECTED,               /* has not yet disconnected */
    106         INCOMING_MISSED,                /* an incoming call that was missed and never answered */
    107         NORMAL,                         /* normal; remote */
    108         LOCAL,                          /* normal; local hangup */
    109         BUSY,                           /* outgoing call to busy line */
    110         CONGESTION,                     /* outgoing call to congested network */
    111         MMI,                            /* not presently used; dial() returns null */
    112         INVALID_NUMBER,                 /* invalid dial string */
    113         NUMBER_UNREACHABLE,             /* cannot reach the peer */
    114         SERVER_UNREACHABLE,             /* cannot reach the server */
    115         INVALID_CREDENTIALS,            /* invalid credentials */
    116         OUT_OF_NETWORK,                 /* calling from out of network is not allowed */
    117         SERVER_ERROR,                   /* server error */
    118         TIMED_OUT,                      /* client timed out */
    119         LOST_SIGNAL,
    120         LIMIT_EXCEEDED,                 /* eg GSM ACM limit exceeded */
    121         INCOMING_REJECTED,              /* an incoming call that was rejected */
    122         POWER_OFF,                      /* radio is turned off explicitly */
    123         OUT_OF_SERVICE,                 /* out of service */
    124         ICC_ERROR,                      /* No ICC, ICC locked, or other ICC error */
    125         CALL_BARRED,                    /* call was blocked by call barring */
    126         FDN_BLOCKED,                    /* call was blocked by fixed dial number */
    127         CS_RESTRICTED,                  /* call was blocked by restricted all voice access */
    128         CS_RESTRICTED_NORMAL,           /* call was blocked by restricted normal voice access */
    129         CS_RESTRICTED_EMERGENCY,        /* call was blocked by restricted emergency voice access */
    130         UNOBTAINABLE_NUMBER,            /* Unassigned number (3GPP TS 24.008 table 10.5.123) */
    131         CDMA_LOCKED_UNTIL_POWER_CYCLE,  /* MS is locked until next power cycle */
    132         CDMA_DROP,
    133         CDMA_INTERCEPT,                 /* INTERCEPT order received, MS state idle entered */
    134         CDMA_REORDER,                   /* MS has been redirected, call is cancelled */
    135         CDMA_SO_REJECT,                 /* service option rejection */
    136         CDMA_RETRY_ORDER,               /* requested service is rejected, retry delay is set */
    137         CDMA_ACCESS_FAILURE,
    138         CDMA_PREEMPTED,
    139         CDMA_NOT_EMERGENCY,              /* not an emergency call */
    140         CDMA_ACCESS_BLOCKED,            /* Access Blocked by CDMA network */
    141         ERROR_UNSPECIFIED,
    142 
    143         UNKNOWN                         /* Disconnect cause doesn't map to any above */
    144     }
    145 
    146     private static final Map<Integer, String> STATE_MAP = ImmutableMap.<Integer, String>builder()
    147             .put(Call.State.ACTIVE, "ACTIVE")
    148             .put(Call.State.CALL_WAITING, "CALL_WAITING")
    149             .put(Call.State.DIALING, "DIALING")
    150             .put(Call.State.REDIALING, "REDIALING")
    151             .put(Call.State.IDLE, "IDLE")
    152             .put(Call.State.INCOMING, "INCOMING")
    153             .put(Call.State.ONHOLD, "ONHOLD")
    154             .put(Call.State.INVALID, "INVALID")
    155             .put(Call.State.DISCONNECTING, "DISCONNECTING")
    156             .put(Call.State.DISCONNECTED, "DISCONNECTED")
    157             .put(Call.State.CONFERENCED, "CONFERENCED")
    158             .build();
    159 
    160     // Number presentation type for caller id display
    161     // normal
    162     public static int PRESENTATION_ALLOWED = PhoneConstants.PRESENTATION_ALLOWED;
    163     // block by user
    164     public static int PRESENTATION_RESTRICTED = PhoneConstants.PRESENTATION_RESTRICTED;
    165     // no specified or unknown by network
    166     public static int PRESENTATION_UNKNOWN = PhoneConstants.PRESENTATION_UNKNOWN;
    167     // show pay phone info
    168     public static int PRESENTATION_PAYPHONE = PhoneConstants.PRESENTATION_PAYPHONE;
    169 
    170     // Unique identifier for the call
    171     private int mCallId;
    172 
    173     private CallIdentification mIdentification;
    174 
    175     // The current state of the call
    176     private int mState = State.INVALID;
    177 
    178     // Reason for disconnect. Valid when the call state is DISCONNECTED.
    179     private DisconnectCause mDisconnectCause = DisconnectCause.UNKNOWN;
    180 
    181     // Bit mask of capabilities unique to this call.
    182     private int mCapabilities;
    183 
    184     // Time that this call transitioned into ACTIVE state from INCOMING, WAITING, or OUTGOING.
    185     private long mConnectTime = 0;
    186 
    187     // List of call Ids for for this call.  (Used for managing conference calls).
    188     private SortedSet<Integer> mChildCallIds = Sets.newSortedSet();
    189 
    190     // Gateway number used to dial this call
    191     private String mGatewayNumber;
    192 
    193     // Gateway service package name
    194     private String mGatewayPackage;
    195 
    196     public Call(int callId) {
    197         mCallId = callId;
    198         mIdentification = new CallIdentification(mCallId);
    199     }
    200 
    201     public Call(Call call) {
    202         mCallId = call.mCallId;
    203         mIdentification = new CallIdentification(call.mIdentification);
    204         mState = call.mState;
    205         mDisconnectCause = call.mDisconnectCause;
    206         mCapabilities = call.mCapabilities;
    207         mConnectTime = call.mConnectTime;
    208         mChildCallIds = new TreeSet<Integer>(call.mChildCallIds);
    209         mGatewayNumber = call.mGatewayNumber;
    210         mGatewayPackage = call.mGatewayPackage;
    211     }
    212 
    213     public int getCallId() {
    214         return mCallId;
    215     }
    216 
    217     public CallIdentification getIdentification() {
    218         return mIdentification;
    219     }
    220 
    221     public String getNumber() {
    222         return mIdentification.getNumber();
    223     }
    224 
    225     public void setNumber(String number) {
    226         mIdentification.setNumber(number);
    227     }
    228 
    229     public int getState() {
    230         return mState;
    231     }
    232 
    233     public void setState(int state) {
    234         mState = state;
    235     }
    236 
    237     public int getNumberPresentation() {
    238         return mIdentification.getNumberPresentation();
    239     }
    240 
    241     public void setNumberPresentation(int presentation) {
    242         mIdentification.setNumberPresentation(presentation);
    243     }
    244 
    245     public int getCnapNamePresentation() {
    246         return mIdentification.getCnapNamePresentation();
    247     }
    248 
    249     public void setCnapNamePresentation(int presentation) {
    250         mIdentification.setCnapNamePresentation(presentation);
    251     }
    252 
    253     public String getCnapName() {
    254         return mIdentification.getCnapName();
    255     }
    256 
    257     public void setCnapName(String cnapName) {
    258         mIdentification.setCnapName(cnapName);
    259     }
    260 
    261     public DisconnectCause getDisconnectCause() {
    262         if (mState == State.DISCONNECTED || mState == State.IDLE) {
    263             return mDisconnectCause;
    264         }
    265 
    266         return DisconnectCause.NOT_DISCONNECTED;
    267     }
    268 
    269     public void setDisconnectCause(DisconnectCause cause) {
    270         mDisconnectCause = cause;
    271     }
    272 
    273     public int getCapabilities() {
    274         return mCapabilities;
    275     }
    276 
    277     public void setCapabilities(int capabilities) {
    278         mCapabilities = (Capabilities.ALL & capabilities);
    279     }
    280 
    281     public boolean can(int capabilities) {
    282         return (capabilities == (capabilities & mCapabilities));
    283     }
    284 
    285     public void addCapabilities(int capabilities) {
    286         setCapabilities(capabilities | mCapabilities);
    287     }
    288 
    289     public void setConnectTime(long connectTime) {
    290         mConnectTime = connectTime;
    291     }
    292 
    293     public long getConnectTime() {
    294         return mConnectTime;
    295     }
    296 
    297     public void removeChildId(int id) {
    298         mChildCallIds.remove(id);
    299     }
    300 
    301     public void removeAllChildren() {
    302         mChildCallIds.clear();
    303     }
    304 
    305     public void addChildId(int id) {
    306         mChildCallIds.add(id);
    307     }
    308 
    309     public ImmutableSortedSet<Integer> getChildCallIds() {
    310         return ImmutableSortedSet.copyOf(mChildCallIds);
    311     }
    312 
    313     public boolean isConferenceCall() {
    314         return mChildCallIds.size() >= 2;
    315     }
    316 
    317     public String getGatewayNumber() {
    318         return mGatewayNumber;
    319     }
    320 
    321     public void setGatewayNumber(String number) {
    322         mGatewayNumber = number;
    323     }
    324 
    325     public String getGatewayPackage() {
    326         return mGatewayPackage;
    327     }
    328 
    329     public void setGatewayPackage(String packageName) {
    330         mGatewayPackage = packageName;
    331     }
    332 
    333     /**
    334      * Parcelable implementation
    335      */
    336 
    337     @Override
    338     public void writeToParcel(Parcel dest, int flags) {
    339         dest.writeInt(mCallId);
    340         dest.writeInt(mState);
    341         dest.writeString(getDisconnectCause().toString());
    342         dest.writeInt(getCapabilities());
    343         dest.writeLong(getConnectTime());
    344         dest.writeIntArray(Ints.toArray(mChildCallIds));
    345         dest.writeString(getGatewayNumber());
    346         dest.writeString(getGatewayPackage());
    347         dest.writeParcelable(mIdentification, 0);
    348     }
    349 
    350     /**
    351      * Constructor for Parcelable implementation.
    352      */
    353     private Call(Parcel in) {
    354         mCallId = in.readInt();
    355         mState = in.readInt();
    356         mDisconnectCause = DisconnectCause.valueOf(in.readString());
    357         mCapabilities = in.readInt();
    358         mConnectTime = in.readLong();
    359         mChildCallIds.addAll(Ints.asList(in.createIntArray()));
    360         mGatewayNumber = in.readString();
    361         mGatewayPackage = in.readString();
    362         mIdentification = in.readParcelable(CallIdentification.class.getClassLoader());
    363     }
    364 
    365     @Override
    366     public int describeContents() {
    367         return 0;
    368     }
    369 
    370     /**
    371      * Creates Call objects for Parcelable implementation.
    372      */
    373     public static final Parcelable.Creator<Call> CREATOR
    374             = new Parcelable.Creator<Call>() {
    375 
    376         @Override
    377         public Call createFromParcel(Parcel in) {
    378             return new Call(in);
    379         }
    380 
    381         @Override
    382         public Call[] newArray(int size) {
    383             return new Call[size];
    384         }
    385     };
    386 
    387     @Override
    388     public String toString() {
    389         return Objects.toStringHelper(this)
    390                 .add("mCallId", mCallId)
    391                 .add("mState", STATE_MAP.get(mState))
    392                 .add("mDisconnectCause", mDisconnectCause)
    393                 .add("mCapabilities", mCapabilities)
    394                 .add("mConnectTime", mConnectTime)
    395                 .add("mChildCallIds", mChildCallIds)
    396                 .add("mGatewayNumber", MoreStrings.toSafeString(mGatewayNumber))
    397                 .add("mGatewayPackage", mGatewayPackage)
    398                 .add("mIdentification", mIdentification)
    399                 .toString();
    400     }
    401 }
    402