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