1 /* 2 * Copyright (C) 2014 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 android.telecom; 18 19 import android.os.Parcel; 20 import android.os.Parcelable; 21 import android.media.ToneGenerator; 22 import android.text.TextUtils; 23 24 import java.util.Objects; 25 26 /** 27 * Describes the cause of a disconnected call. This always includes a code describing the generic 28 * cause of the disconnect. Optionally, it may include a label and/or description to display to the 29 * user. It is the responsibility of the {@link ConnectionService} to provide localized versions of 30 * the label and description. It also may contain a reason for the disconnect, which is intended for 31 * logging and not for display to the user. 32 */ 33 public final class DisconnectCause implements Parcelable { 34 35 /** Disconnected because of an unknown or unspecified reason. */ 36 public static final int UNKNOWN = 0; 37 /** Disconnected because there was an error, such as a problem with the network. */ 38 public static final int ERROR = 1; 39 /** Disconnected because of a local user-initiated action, such as hanging up. */ 40 public static final int LOCAL = 2; 41 /** 42 * Disconnected because of a remote user-initiated action, such as the other party hanging up 43 * up. 44 */ 45 public static final int REMOTE = 3; 46 /** Disconnected because it has been canceled. */ 47 public static final int CANCELED = 4; 48 /** Disconnected because there was no response to an incoming call. */ 49 public static final int MISSED = 5; 50 /** Disconnected because the user rejected an incoming call. */ 51 public static final int REJECTED = 6; 52 /** Disconnected because the other party was busy. */ 53 public static final int BUSY = 7; 54 /** 55 * Disconnected because of a restriction on placing the call, such as dialing in airplane 56 * mode. 57 */ 58 public static final int RESTRICTED = 8; 59 /** Disconnected for reason not described by other disconnect codes. */ 60 public static final int OTHER = 9; 61 /** 62 * Disconnected because the connection manager did not support the call. The call will be tried 63 * again without a connection manager. See {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}. 64 */ 65 public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; 66 67 /** 68 * Disconnected because the user did not locally answer the incoming call, but it was answered 69 * on another device where the call was ringing. 70 */ 71 public static final int ANSWERED_ELSEWHERE = 11; 72 73 /** 74 * Disconnected because the call was pulled from the current device to another device. 75 */ 76 public static final int CALL_PULLED = 12; 77 78 /** 79 * Reason code (returned via {@link #getReason()}) which indicates that a call could not be 80 * completed because the cellular radio is off or out of service, the device is connected to 81 * a wifi network, but the user has not enabled wifi calling. 82 * @hide 83 */ 84 public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF"; 85 86 private int mDisconnectCode; 87 private CharSequence mDisconnectLabel; 88 private CharSequence mDisconnectDescription; 89 private String mDisconnectReason; 90 private int mToneToPlay; 91 92 /** 93 * Creates a new DisconnectCause. 94 * 95 * @param code The code for the disconnect cause. 96 */ DisconnectCause(int code)97 public DisconnectCause(int code) { 98 this(code, null, null, null, ToneGenerator.TONE_UNKNOWN); 99 } 100 101 /** 102 * Creates a new DisconnectCause. 103 * 104 * @param code The code for the disconnect cause. 105 * @param reason The reason for the disconnect. 106 */ DisconnectCause(int code, String reason)107 public DisconnectCause(int code, String reason) { 108 this(code, null, null, reason, ToneGenerator.TONE_UNKNOWN); 109 } 110 111 /** 112 * Creates a new DisconnectCause. 113 * 114 * @param code The code for the disconnect cause. 115 * @param label The localized label to show to the user to explain the disconnect. 116 * @param description The localized description to show to the user to explain the disconnect. 117 * @param reason The reason for the disconnect. 118 */ DisconnectCause(int code, CharSequence label, CharSequence description, String reason)119 public DisconnectCause(int code, CharSequence label, CharSequence description, String reason) { 120 this(code, label, description, reason, ToneGenerator.TONE_UNKNOWN); 121 } 122 123 /** 124 * Creates a new DisconnectCause. 125 * 126 * @param code The code for the disconnect cause. 127 * @param label The localized label to show to the user to explain the disconnect. 128 * @param description The localized description to show to the user to explain the disconnect. 129 * @param reason The reason for the disconnect. 130 * @param toneToPlay The tone to play on disconnect, as defined in {@link ToneGenerator}. 131 */ DisconnectCause(int code, CharSequence label, CharSequence description, String reason, int toneToPlay)132 public DisconnectCause(int code, CharSequence label, CharSequence description, String reason, 133 int toneToPlay) { 134 mDisconnectCode = code; 135 mDisconnectLabel = label; 136 mDisconnectDescription = description; 137 mDisconnectReason = reason; 138 mToneToPlay = toneToPlay; 139 } 140 141 /** 142 * Returns the code for the reason for this disconnect. 143 * 144 * @return The disconnect code. 145 */ getCode()146 public int getCode() { 147 return mDisconnectCode; 148 } 149 150 /** 151 * Returns a short label which explains the reason for the disconnect cause and is for display 152 * in the user interface. If not null, it is expected that the In-Call UI should display this 153 * text where it would normally display the call state ("Dialing", "Disconnected") and is 154 * therefore expected to be relatively small. The {@link ConnectionService } is responsible for 155 * providing and localizing this label. If there is no string provided, returns null. 156 * 157 * @return The disconnect label. 158 */ getLabel()159 public CharSequence getLabel() { 160 return mDisconnectLabel; 161 } 162 163 /** 164 * Returns a description which explains the reason for the disconnect cause and is for display 165 * in the user interface. This optional text is generally a longer and more descriptive version 166 * of {@link #getLabel}, however it can exist even if {@link #getLabel} is empty. The In-Call UI 167 * should display this relatively prominently; the traditional implementation displays this as 168 * an alert dialog. The {@link ConnectionService} is responsible for providing and localizing 169 * this message. If there is no string provided, returns null. 170 * 171 * @return The disconnect description. 172 */ getDescription()173 public CharSequence getDescription() { 174 return mDisconnectDescription; 175 } 176 177 /** 178 * Returns an explanation of the reason for the disconnect. This is not intended for display to 179 * the user and is used mainly for logging. 180 * 181 * @return The disconnect reason. 182 */ getReason()183 public String getReason() { 184 return mDisconnectReason; 185 } 186 187 /** 188 * Returns the tone to play when disconnected. 189 * 190 * @return the tone as defined in {@link ToneGenerator} to play when disconnected. 191 */ getTone()192 public int getTone() { 193 return mToneToPlay; 194 } 195 196 public static final Creator<DisconnectCause> CREATOR = new Creator<DisconnectCause>() { 197 @Override 198 public DisconnectCause createFromParcel(Parcel source) { 199 int code = source.readInt(); 200 CharSequence label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 201 CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 202 String reason = source.readString(); 203 int tone = source.readInt(); 204 return new DisconnectCause(code, label, description, reason, tone); 205 } 206 207 @Override 208 public DisconnectCause[] newArray(int size) { 209 return new DisconnectCause[size]; 210 } 211 }; 212 213 @Override writeToParcel(Parcel destination, int flags)214 public void writeToParcel(Parcel destination, int flags) { 215 destination.writeInt(mDisconnectCode); 216 TextUtils.writeToParcel(mDisconnectLabel, destination, flags); 217 TextUtils.writeToParcel(mDisconnectDescription, destination, flags); 218 destination.writeString(mDisconnectReason); 219 destination.writeInt(mToneToPlay); 220 } 221 222 @Override describeContents()223 public int describeContents() { 224 return 0; 225 } 226 227 @Override hashCode()228 public int hashCode() { 229 return Objects.hashCode(mDisconnectCode) 230 + Objects.hashCode(mDisconnectLabel) 231 + Objects.hashCode(mDisconnectDescription) 232 + Objects.hashCode(mDisconnectReason) 233 + Objects.hashCode(mToneToPlay); 234 } 235 236 @Override equals(Object o)237 public boolean equals(Object o) { 238 if (o instanceof DisconnectCause) { 239 DisconnectCause d = (DisconnectCause) o; 240 return Objects.equals(mDisconnectCode, d.getCode()) 241 && Objects.equals(mDisconnectLabel, d.getLabel()) 242 && Objects.equals(mDisconnectDescription, d.getDescription()) 243 && Objects.equals(mDisconnectReason, d.getReason()) 244 && Objects.equals(mToneToPlay, d.getTone()); 245 } 246 return false; 247 } 248 249 @Override toString()250 public String toString() { 251 String code = ""; 252 switch (mDisconnectCode) { 253 case UNKNOWN: 254 code = "UNKNOWN"; 255 break; 256 case ERROR: 257 code = "ERROR"; 258 break; 259 case LOCAL: 260 code = "LOCAL"; 261 break; 262 case REMOTE: 263 code = "REMOTE"; 264 break; 265 case CANCELED: 266 code = "CANCELED"; 267 break; 268 case MISSED: 269 code = "MISSED"; 270 break; 271 case REJECTED: 272 code = "REJECTED"; 273 break; 274 case BUSY: 275 code = "BUSY"; 276 break; 277 case RESTRICTED: 278 code = "RESTRICTED"; 279 break; 280 case OTHER: 281 code = "OTHER"; 282 break; 283 case CONNECTION_MANAGER_NOT_SUPPORTED: 284 code = "CONNECTION_MANAGER_NOT_SUPPORTED"; 285 break; 286 case CALL_PULLED: 287 code = "CALL_PULLED"; 288 break; 289 case ANSWERED_ELSEWHERE: 290 code = "ANSWERED_ELSEWHERE"; 291 break; 292 default: 293 code = "invalid code: " + mDisconnectCode; 294 break; 295 } 296 String label = mDisconnectLabel == null ? "" : mDisconnectLabel.toString(); 297 String description = mDisconnectDescription == null 298 ? "" : mDisconnectDescription.toString(); 299 String reason = mDisconnectReason == null ? "" : mDisconnectReason; 300 return "DisconnectCause [ Code: (" + code + ")" 301 + " Label: (" + label + ")" 302 + " Description: (" + description + ")" 303 + " Reason: (" + reason + ")" 304 + " Tone: (" + mToneToPlay + ") ]"; 305 } 306 } 307