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 com.android.services.telephony; 18 19 import android.content.Context; 20 import android.media.ToneGenerator; 21 import android.telecom.DisconnectCause; 22 import android.telephony.SubscriptionManager; 23 24 import com.android.internal.telephony.CallFailCause; 25 import com.android.phone.ImsUtil; 26 import com.android.phone.PhoneGlobals; 27 import com.android.phone.common.R; 28 29 public class DisconnectCauseUtil { 30 31 /** 32 * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more 33 * generic {@link android.telecom.DisconnectCause} object, possibly populated with a localized 34 * message and tone. 35 * 36 * @param telephonyDisconnectCause The code for the reason for the disconnect. 37 */ toTelecomDisconnectCause(int telephonyDisconnectCause)38 public static DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause) { 39 return toTelecomDisconnectCause(telephonyDisconnectCause, 40 CallFailCause.NOT_VALID, null /* reason */); 41 } 42 43 /** 44 * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more 45 * generic {@link android.telecom.DisconnectCause}.object, possibly populated with a localized 46 * message and tone. 47 * 48 * @param telephonyDisconnectCause The code for the reason for the disconnect. 49 * @param reason Description of the reason for the disconnect, not intended for the user to see.. 50 */ toTelecomDisconnectCause( int telephonyDisconnectCause, String reason)51 public static DisconnectCause toTelecomDisconnectCause( 52 int telephonyDisconnectCause, String reason) { 53 return toTelecomDisconnectCause(telephonyDisconnectCause, CallFailCause.NOT_VALID, reason); 54 } 55 56 /** 57 * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more 58 * generic {@link android.telecom.DisconnectCause}.object, possibly populated with a localized 59 * message and tone. 60 * 61 * @param telephonyDisconnectCause The code for the reason for the disconnect. 62 * @param telephonyPerciseDisconnectCause The code for the percise reason for the disconnect. 63 * @param reason Description of the reason for the disconnect, not intended for the user to see.. 64 */ toTelecomDisconnectCause( int telephonyDisconnectCause, int telephonyPerciseDisconnectCause, String reason)65 public static DisconnectCause toTelecomDisconnectCause( 66 int telephonyDisconnectCause, int telephonyPerciseDisconnectCause, String reason) { 67 return toTelecomDisconnectCause(telephonyDisconnectCause, telephonyPerciseDisconnectCause, 68 reason, SubscriptionManager.getDefaultVoicePhoneId()); 69 } 70 71 /** 72 * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more 73 * generic {@link android.telecom.DisconnectCause}.object, possibly populated with a localized 74 * message and tone for Slot. 75 * 76 * @param telephonyDisconnectCause The code for the reason for the disconnect. 77 * @param phoneId To support localized message based on phoneId 78 */ toTelecomDisconnectCause(int telephonyDisconnectCause, String reason, int phoneId)79 public static DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause, 80 String reason, int phoneId) { 81 return toTelecomDisconnectCause(telephonyDisconnectCause, CallFailCause.NOT_VALID, 82 reason, phoneId); 83 } 84 85 /** 86 * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more 87 * generic {@link android.telecom.DisconnectCause}.object, possibly populated with a localized 88 * message and tone for Slot. 89 * 90 * @param telephonyDisconnectCause The code for the reason for the disconnect. 91 * @param telephonyPerciseDisconnectCause The code for the percise reason for the disconnect. 92 * @param reason Description of the reason for the disconnect, not intended for the user to see.. 93 * @param phoneId To support localized message based on phoneId 94 */ toTelecomDisconnectCause( int telephonyDisconnectCause, int telephonyPerciseDisconnectCause, String reason, int phoneId)95 public static DisconnectCause toTelecomDisconnectCause( 96 int telephonyDisconnectCause, int telephonyPerciseDisconnectCause, String reason, 97 int phoneId) { 98 Context context = PhoneGlobals.getInstance(); 99 return new DisconnectCause( 100 toTelecomDisconnectCauseCode(telephonyDisconnectCause), 101 toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause, 102 telephonyPerciseDisconnectCause), 103 toTelecomDisconnectCauseDescription(context, telephonyDisconnectCause, phoneId), 104 toTelecomDisconnectReason(context,telephonyDisconnectCause, reason, phoneId), 105 toTelecomDisconnectCauseTone(telephonyDisconnectCause)); 106 } 107 108 /** 109 * Convert the {@link android.telephony.DisconnectCause} disconnect code into a 110 * {@link android.telecom.DisconnectCause} disconnect code. 111 * @return The disconnect code as defined in {@link android.telecom.DisconnectCause}. 112 */ toTelecomDisconnectCauseCode(int telephonyDisconnectCause)113 private static int toTelecomDisconnectCauseCode(int telephonyDisconnectCause) { 114 switch (telephonyDisconnectCause) { 115 case android.telephony.DisconnectCause.LOCAL: 116 return DisconnectCause.LOCAL; 117 118 case android.telephony.DisconnectCause.NORMAL: 119 case android.telephony.DisconnectCause.NORMAL_UNSPECIFIED: 120 return DisconnectCause.REMOTE; 121 122 case android.telephony.DisconnectCause.OUTGOING_CANCELED: 123 return DisconnectCause.CANCELED; 124 125 case android.telephony.DisconnectCause.INCOMING_MISSED: 126 return DisconnectCause.MISSED; 127 128 case android.telephony.DisconnectCause.INCOMING_REJECTED: 129 return DisconnectCause.REJECTED; 130 131 case android.telephony.DisconnectCause.BUSY: 132 return DisconnectCause.BUSY; 133 134 case android.telephony.DisconnectCause.CALL_BARRED: 135 case android.telephony.DisconnectCause.CDMA_ACCESS_BLOCKED: 136 case android.telephony.DisconnectCause.CDMA_NOT_EMERGENCY: 137 case android.telephony.DisconnectCause.CS_RESTRICTED: 138 case android.telephony.DisconnectCause.CS_RESTRICTED_EMERGENCY: 139 case android.telephony.DisconnectCause.CS_RESTRICTED_NORMAL: 140 case android.telephony.DisconnectCause.EMERGENCY_ONLY: 141 case android.telephony.DisconnectCause.FDN_BLOCKED: 142 case android.telephony.DisconnectCause.LIMIT_EXCEEDED: 143 case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED: 144 return DisconnectCause.RESTRICTED; 145 146 case android.telephony.DisconnectCause.CDMA_ACCESS_FAILURE: 147 case android.telephony.DisconnectCause.CDMA_ALREADY_ACTIVATED: 148 case android.telephony.DisconnectCause.CDMA_CALL_LOST: 149 case android.telephony.DisconnectCause.CDMA_DROP: 150 case android.telephony.DisconnectCause.CDMA_INTERCEPT: 151 case android.telephony.DisconnectCause.CDMA_LOCKED_UNTIL_POWER_CYCLE: 152 case android.telephony.DisconnectCause.CDMA_PREEMPTED: 153 case android.telephony.DisconnectCause.CDMA_REORDER: 154 case android.telephony.DisconnectCause.CDMA_RETRY_ORDER: 155 case android.telephony.DisconnectCause.CDMA_SO_REJECT: 156 case android.telephony.DisconnectCause.CONGESTION: 157 case android.telephony.DisconnectCause.ICC_ERROR: 158 case android.telephony.DisconnectCause.INVALID_CREDENTIALS: 159 case android.telephony.DisconnectCause.INVALID_NUMBER: 160 case android.telephony.DisconnectCause.LOST_SIGNAL: 161 case android.telephony.DisconnectCause.NO_PHONE_NUMBER_SUPPLIED: 162 case android.telephony.DisconnectCause.NUMBER_UNREACHABLE: 163 case android.telephony.DisconnectCause.OUTGOING_FAILURE: 164 case android.telephony.DisconnectCause.OUT_OF_NETWORK: 165 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 166 case android.telephony.DisconnectCause.POWER_OFF: 167 case android.telephony.DisconnectCause.LOW_BATTERY: 168 case android.telephony.DisconnectCause.DIAL_LOW_BATTERY: 169 case android.telephony.DisconnectCause.SERVER_ERROR: 170 case android.telephony.DisconnectCause.SERVER_UNREACHABLE: 171 case android.telephony.DisconnectCause.TIMED_OUT: 172 case android.telephony.DisconnectCause.ALREADY_DIALING: 173 case android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING: 174 case android.telephony.DisconnectCause.CALLING_DISABLED: 175 case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS: 176 case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS: 177 case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER: 178 case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING: 179 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_USSD: 180 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_SS: 181 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_DIAL: 182 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_DIAL_VIDEO: 183 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_SS: 184 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_USSD: 185 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_DIAL: 186 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO: 187 case android.telephony.DisconnectCause.ERROR_UNSPECIFIED: 188 case android.telephony.DisconnectCause.MAXIMUM_NUMBER_OF_CALLS_REACHED: 189 case android.telephony.DisconnectCause.DATA_DISABLED: 190 case android.telephony.DisconnectCause.DATA_LIMIT_REACHED: 191 case android.telephony.DisconnectCause.DIALED_CALL_FORWARDING_WHILE_ROAMING: 192 case android.telephony.DisconnectCause.IMEI_NOT_ACCEPTED: 193 case android.telephony.DisconnectCause.WIFI_LOST: 194 case android.telephony.DisconnectCause.IMS_ACCESS_BLOCKED: 195 case android.telephony.DisconnectCause.IMS_SIP_ALTERNATE_EMERGENCY_CALL: 196 return DisconnectCause.ERROR; 197 198 case android.telephony.DisconnectCause.DIALED_MMI: 199 case android.telephony.DisconnectCause.EXITED_ECM: 200 case android.telephony.DisconnectCause.MMI: 201 case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY: 202 return DisconnectCause.OTHER; 203 204 case android.telephony.DisconnectCause.NOT_VALID: 205 case android.telephony.DisconnectCause.NOT_DISCONNECTED: 206 return DisconnectCause.UNKNOWN; 207 208 case android.telephony.DisconnectCause.CALL_PULLED: 209 return DisconnectCause.CALL_PULLED; 210 211 case android.telephony.DisconnectCause.ANSWERED_ELSEWHERE: 212 return DisconnectCause.ANSWERED_ELSEWHERE; 213 214 default: 215 Log.w("DisconnectCauseUtil.toTelecomDisconnectCauseCode", 216 "Unrecognized Telephony DisconnectCause " 217 + telephonyDisconnectCause); 218 return DisconnectCause.UNKNOWN; 219 } 220 } 221 222 /** 223 * Returns a label for to the disconnect cause to be shown to the user. 224 */ toTelecomDisconnectCauseLabel( Context context, int telephonyDisconnectCause, int telephonyPerciseDisconnectCause)225 private static CharSequence toTelecomDisconnectCauseLabel( 226 Context context, int telephonyDisconnectCause, int telephonyPerciseDisconnectCause) { 227 CharSequence label; 228 if (telephonyPerciseDisconnectCause != CallFailCause.NOT_VALID) { 229 label = getLabelFromPreciseDisconnectCause(context, telephonyPerciseDisconnectCause, 230 telephonyDisconnectCause); 231 } else { 232 label = getLabelFromDisconnectCause(context, telephonyDisconnectCause); 233 } 234 return label; 235 } 236 237 /** 238 * Returns a label for to the generic disconnect cause to be shown to the user. 239 */ getLabelFromDisconnectCause( Context context, int telephonyDisconnectCause)240 private static CharSequence getLabelFromDisconnectCause( 241 Context context, int telephonyDisconnectCause) { 242 if (context == null) { 243 return ""; 244 } 245 246 Integer resourceId = null; 247 switch (telephonyDisconnectCause) { 248 case android.telephony.DisconnectCause.BUSY: 249 resourceId = R.string.callFailed_userBusy; 250 break; 251 252 case android.telephony.DisconnectCause.CDMA_REORDER: 253 resourceId = R.string.callFailed_NetworkBusy; 254 break; 255 256 case android.telephony.DisconnectCause.IMS_ACCESS_BLOCKED: 257 resourceId = R.string.callFailed_NetworkCongested; 258 break; 259 260 case android.telephony.DisconnectCause.CONGESTION: 261 resourceId = R.string.callFailed_congestion; 262 break; 263 264 case android.telephony.DisconnectCause.TIMED_OUT: 265 resourceId = R.string.callFailed_timedOut; 266 break; 267 268 case android.telephony.DisconnectCause.SERVER_UNREACHABLE: 269 resourceId = R.string.callFailed_server_unreachable; 270 break; 271 272 case android.telephony.DisconnectCause.NUMBER_UNREACHABLE: 273 resourceId = R.string.callFailed_number_unreachable; 274 break; 275 276 case android.telephony.DisconnectCause.INVALID_CREDENTIALS: 277 resourceId = R.string.callFailed_invalid_credentials; 278 break; 279 280 case android.telephony.DisconnectCause.SERVER_ERROR: 281 resourceId = R.string.callFailed_server_error; 282 break; 283 284 case android.telephony.DisconnectCause.OUT_OF_NETWORK: 285 resourceId = R.string.callFailed_out_of_network; 286 break; 287 288 case android.telephony.DisconnectCause.LOST_SIGNAL: 289 case android.telephony.DisconnectCause.CDMA_DROP: 290 resourceId = R.string.callFailed_noSignal; 291 break; 292 293 case android.telephony.DisconnectCause.LIMIT_EXCEEDED: 294 resourceId = R.string.callFailed_limitExceeded; 295 break; 296 297 case android.telephony.DisconnectCause.POWER_OFF: 298 resourceId = R.string.callFailed_powerOff; 299 break; 300 301 case android.telephony.DisconnectCause.LOW_BATTERY: 302 resourceId = R.string.callFailed_low_battery; 303 break; 304 305 case android.telephony.DisconnectCause.DIAL_LOW_BATTERY: 306 resourceId = R.string.dialFailed_low_battery; 307 break; 308 309 case android.telephony.DisconnectCause.ICC_ERROR: 310 resourceId = R.string.callFailed_simError; 311 break; 312 313 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 314 resourceId = R.string.callFailed_outOfService; 315 break; 316 317 case android.telephony.DisconnectCause.INVALID_NUMBER: 318 case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER: 319 resourceId = R.string.callFailed_unobtainable_number; 320 break; 321 322 case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING: 323 resourceId = R.string.incall_error_missing_voicemail_number; 324 break; 325 326 case android.telephony.DisconnectCause.CALL_PULLED: 327 resourceId = R.string.callEnded_pulled; 328 break; 329 330 case android.telephony.DisconnectCause.MAXIMUM_NUMBER_OF_CALLS_REACHED: 331 resourceId = R.string.callFailed_maximum_reached; 332 break; 333 334 case android.telephony.DisconnectCause.DATA_DISABLED: 335 resourceId = R.string.callFailed_data_disabled; 336 break; 337 338 case android.telephony.DisconnectCause.DATA_LIMIT_REACHED: 339 resourceId = R.string.callFailed_data_limit_reached; 340 break; 341 case android.telephony.DisconnectCause.ALREADY_DIALING: 342 resourceId = R.string.callFailed_already_dialing; 343 break; 344 case android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING: 345 resourceId = R.string.callFailed_already_ringing; 346 break; 347 case android.telephony.DisconnectCause.CALLING_DISABLED: 348 resourceId = R.string.callFailed_calling_disabled; 349 break; 350 case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS: 351 resourceId = R.string.callFailed_too_many_calls; 352 break; 353 case android.telephony.DisconnectCause.IMS_SIP_ALTERNATE_EMERGENCY_CALL: 354 resourceId = R.string.incall_error_power_off; 355 break; 356 case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS: 357 resourceId = R.string.callFailed_otasp_provisioning_in_process; 358 break; 359 default: 360 break; 361 } 362 return resourceId == null ? "" : context.getResources().getString(resourceId); 363 } 364 365 /** 366 * Returns a label for to the precise disconnect cause to be shown to the user. 367 */ getLabelFromPreciseDisconnectCause( Context context, int telephonyPreciseDisconnectCause, int telephonyDisconnectCause)368 private static CharSequence getLabelFromPreciseDisconnectCause( 369 Context context, int telephonyPreciseDisconnectCause, int telephonyDisconnectCause) { 370 if (context == null) { 371 return ""; 372 } 373 374 Integer resourceId = null; 375 switch (telephonyPreciseDisconnectCause) { 376 case CallFailCause.UNOBTAINABLE_NUMBER: 377 resourceId = R.string.clh_callFailed_unassigned_number_txt; 378 break; 379 case CallFailCause.NO_ROUTE_TO_DEST: 380 resourceId = R.string.clh_callFailed_no_route_to_destination_txt; 381 break; 382 case CallFailCause.CHANNEL_UNACCEPTABLE: 383 resourceId = R.string.clh_callFailed_channel_unacceptable_txt; 384 break; 385 case CallFailCause.OPERATOR_DETERMINED_BARRING: 386 resourceId = R.string.clh_callFailed_operator_determined_barring_txt; 387 break; 388 case CallFailCause.NORMAL_CLEARING: 389 resourceId = R.string.clh_callFailed_normal_call_clearing_txt; 390 break; 391 case CallFailCause.USER_BUSY: 392 resourceId = R.string.clh_callFailed_user_busy_txt; 393 break; 394 case CallFailCause.NO_USER_RESPONDING: 395 resourceId = R.string.clh_callFailed_no_user_responding_txt; 396 break; 397 case CallFailCause.USER_ALERTING_NO_ANSWER: 398 resourceId = R.string.clh_callFailed_user_alerting_txt; 399 break; 400 case CallFailCause.CALL_REJECTED: 401 resourceId = R.string.clh_callFailed_call_rejected_txt; 402 break; 403 case CallFailCause.NUMBER_CHANGED: 404 resourceId = R.string.clh_callFailed_number_changed_txt; 405 break; 406 case CallFailCause.PRE_EMPTION: 407 resourceId = R.string.clh_callFailed_pre_emption_txt; 408 break; 409 case CallFailCause.NON_SELECTED_USER_CLEARING: 410 resourceId = R.string.clh_callFailed_non_selected_user_clearing_txt; 411 break; 412 case CallFailCause.DESTINATION_OUT_OF_ORDER: 413 resourceId = R.string.clh_callFailed_destination_out_of_order_txt; 414 break; 415 case CallFailCause.INVALID_NUMBER_FORMAT: 416 resourceId = R.string.clh_callFailed_invalid_number_format_txt; 417 break; 418 case CallFailCause.FACILITY_REJECTED: 419 resourceId = R.string.clh_callFailed_facility_rejected_txt; 420 break; 421 case CallFailCause.STATUS_ENQUIRY: 422 resourceId = R.string.clh_callFailed_response_to_STATUS_ENQUIRY_txt; 423 break; 424 case CallFailCause.NORMAL_UNSPECIFIED: 425 resourceId = R.string.clh_callFailed_normal_unspecified_txt; 426 break; 427 case CallFailCause.NO_CIRCUIT_AVAIL: 428 resourceId = R.string.clh_callFailed_no_circuit_available_txt; 429 break; 430 case CallFailCause.NETWORK_OUT_OF_ORDER: 431 resourceId = R.string.clh_callFailed_network_out_of_order_txt; 432 break; 433 case CallFailCause.TEMPORARY_FAILURE: 434 resourceId = R.string.clh_callFailed_temporary_failure_txt; 435 break; 436 case CallFailCause.SWITCHING_CONGESTION: 437 resourceId = R.string.clh_callFailed_switching_equipment_congestion_txt; 438 break; 439 case CallFailCause.ACCESS_INFORMATION_DISCARDED: 440 resourceId = R.string.clh_callFailed_access_information_discarded_txt; 441 break; 442 case CallFailCause.CHANNEL_NOT_AVAIL: 443 resourceId = R.string.clh_callFailed_requested_circuit_txt; 444 break; 445 case CallFailCause.RESOURCES_UNAVAILABLE_UNSPECIFIED: 446 resourceId = R.string.clh_callFailed_resources_unavailable_unspecified_txt; 447 break; 448 case CallFailCause.QOS_NOT_AVAIL: 449 resourceId = R.string.clh_callFailed_quality_of_service_unavailable_txt; 450 break; 451 case CallFailCause.REQUESTED_FACILITY_NOT_SUBSCRIBED: 452 resourceId = R.string.clh_callFailed_requested_facility_not_subscribed_txt; 453 break; 454 case CallFailCause.INCOMING_CALL_BARRED_WITHIN_CUG: 455 resourceId = R.string.clh_callFailed_incoming_calls_barred_within_the_CUG_txt; 456 break; 457 case CallFailCause.BEARER_CAPABILITY_NOT_AUTHORISED: 458 resourceId = R.string.clh_callFailed_bearer_capability_not_authorized_txt; 459 break; 460 case CallFailCause.BEARER_NOT_AVAIL: 461 resourceId = R.string.clh_callFailed_bearer_capability_not_presently_available_txt; 462 break; 463 case CallFailCause.SERVICE_OR_OPTION_NOT_AVAILABLE: 464 resourceId = 465 R.string.clh_callFailed_service_or_option_not_available_unspecified_txt; 466 break; 467 case CallFailCause.BEARER_SERVICE_NOT_IMPLEMENTED: 468 resourceId = R.string.clh_callFailed_bearer_service_not_implemented_txt; 469 break; 470 case CallFailCause.ACM_LIMIT_EXCEEDED: 471 resourceId = R.string.clh_callFailed_ACM_equal_to_or_greater_than_ACMmax_txt; 472 break; 473 case CallFailCause.REQUESTED_FACILITY_NOT_IMPLEMENTED: 474 resourceId = R.string.clh_callFailed_requested_facility_not_implemented_txt; 475 break; 476 case CallFailCause.ONLY_RESTRICTED_DIGITAL_INFO_BC_AVAILABLE: 477 resourceId = R.string 478 .clh_callFailed_only_restricted_digital_information_bearer_capability_is_available_txt; 479 break; 480 case CallFailCause.SERVICE_OR_OPTION_NOT_IMPLEMENTED: 481 resourceId = 482 R.string.clh_callFailed_service_or_option_not_implemented_unspecified_txt; 483 break; 484 case CallFailCause.INVALID_TRANSACTION_ID_VALUE: 485 resourceId = R.string.clh_callFailed_invalid_transaction_identifier_value_txt; 486 break; 487 case CallFailCause.USER_NOT_MEMBER_OF_CUG: 488 resourceId = R.string.clh_callFailed_user_not_member_of_CUG_txt; 489 break; 490 case CallFailCause.INCOMPATIBLE_DESTINATION: 491 resourceId = R.string.clh_callFailed_incompatible_destination_txt; 492 break; 493 case CallFailCause.INVALID_TRANSIT_NETWORK_SELECTION: 494 resourceId = R.string.clh_callFailed_invalid_transit_network_selection_txt; 495 break; 496 case CallFailCause.SEMANTICALLY_INCORRECT_MESSAGE: 497 resourceId = R.string.clh_callFailed_semantically_incorrect_message_txt; 498 break; 499 case CallFailCause.INVALID_MANDATORY_INFORMATION: 500 resourceId = R.string.clh_callFailed_invalid_mandatory_information_txt; 501 break; 502 case CallFailCause.MESSAGE_TYPE_NON_EXISTENT: 503 resourceId = 504 R.string.clh_callFailed_message_type_non_existent_or_not_implemented_txt; 505 break; 506 case CallFailCause.MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROT_STATE: 507 resourceId = R.string 508 .clh_callFailed_message_type_not_compatible_with_protocol_state_txt; 509 break; 510 case CallFailCause.IE_NON_EXISTENT_OR_NOT_IMPLEMENTED: 511 resourceId = R.string 512 .clh_callFailed_information_element_non_existent_or_not_implemented_txt; 513 break; 514 case CallFailCause.CONDITIONAL_IE_ERROR: 515 resourceId = R.string.clh_callFailed_conditional_IE_error_txt; 516 break; 517 case CallFailCause.MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE: 518 resourceId = R.string.clh_callFailed_message_not_compatible_with_protocol_state_txt; 519 break; 520 case CallFailCause.RECOVERY_ON_TIMER_EXPIRY: 521 resourceId = R.string.clh_callFailed_recovery_on_timer_expiry_txt; 522 break; 523 case CallFailCause.PROTOCOL_ERROR_UNSPECIFIED: 524 resourceId = R.string.clh_callFailed_protocol_Error_unspecified_txt; 525 break; 526 case CallFailCause.INTERWORKING_UNSPECIFIED: 527 resourceId = R.string.clh_callFailed_interworking_unspecified_txt; 528 break; 529 default: 530 switch (telephonyDisconnectCause) { 531 case android.telephony.DisconnectCause.POWER_OFF: 532 resourceId = R.string.clh_callFailed_powerOff_txt; 533 break; 534 case android.telephony.DisconnectCause.ICC_ERROR: 535 resourceId = R.string.clh_callFailed_simError_txt; 536 break; 537 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 538 resourceId = R.string.clh_incall_error_out_of_service_txt; 539 break; 540 default: 541 resourceId = R.string.clh_card_title_call_ended_txt; 542 break; 543 } 544 break; 545 } 546 return context.getResources().getString(resourceId); 547 } 548 549 /** 550 * Returns a description of the disconnect cause to be shown to the user. 551 */ toTelecomDisconnectCauseDescription( Context context, int telephonyDisconnectCause, int phoneId)552 private static CharSequence toTelecomDisconnectCauseDescription( 553 Context context, int telephonyDisconnectCause, int phoneId) { 554 if (context == null ) { 555 return ""; 556 } 557 558 Integer resourceId = null; 559 switch (telephonyDisconnectCause) { 560 case android.telephony.DisconnectCause.CALL_BARRED: 561 resourceId = R.string.callFailed_cb_enabled; 562 break; 563 564 case android.telephony.DisconnectCause.CDMA_ALREADY_ACTIVATED: 565 resourceId = R.string.callFailed_cdma_activation; 566 break; 567 568 case android.telephony.DisconnectCause.CDMA_REORDER: 569 resourceId = R.string.callFailed_NetworkBusy; 570 break; 571 572 case android.telephony.DisconnectCause.IMS_ACCESS_BLOCKED: 573 resourceId = R.string.callFailed_NetworkCongested; 574 break; 575 576 case android.telephony.DisconnectCause.FDN_BLOCKED: 577 resourceId = R.string.callFailed_fdn_only; 578 break; 579 580 case android.telephony.DisconnectCause.CS_RESTRICTED: 581 resourceId = R.string.callFailed_dsac_restricted; 582 break; 583 584 case android.telephony.DisconnectCause.CS_RESTRICTED_EMERGENCY: 585 resourceId = R.string.callFailed_dsac_restricted_emergency; 586 break; 587 588 case android.telephony.DisconnectCause.CS_RESTRICTED_NORMAL: 589 resourceId = R.string.callFailed_dsac_restricted_normal; 590 break; 591 592 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_USSD: 593 resourceId = R.string.callFailed_dialToUssd; 594 break; 595 596 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_SS: 597 resourceId = R.string.callFailed_dialToSs; 598 break; 599 600 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_DIAL: 601 resourceId = R.string.callFailed_dialToDial; 602 break; 603 604 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_DIAL_VIDEO: 605 resourceId = R.string.callFailed_dialToDialVideo; 606 break; 607 608 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_SS: 609 resourceId = R.string.callFailed_dialVideoToSs; 610 break; 611 612 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_USSD: 613 resourceId = R.string.callFailed_dialVideoToUssd; 614 break; 615 616 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_DIAL: 617 resourceId = R.string.callFailed_dialVideoToDial; 618 break; 619 620 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO: 621 resourceId = R.string.callFailed_dialVideoToDialVideo; 622 break; 623 624 case android.telephony.DisconnectCause.OUTGOING_FAILURE: 625 // We couldn't successfully place the call; there was some 626 // failure in the telephony layer. 627 // TODO: Need UI spec for this failure case; for now just 628 // show a generic error. 629 resourceId = R.string.incall_error_call_failed; 630 break; 631 632 case android.telephony.DisconnectCause.POWER_OFF: 633 // Radio is explictly powered off because the device is in airplane mode. 634 635 // TODO: Offer the option to turn the radio on, and automatically retry the call 636 // once network registration is complete. 637 638 if (ImsUtil.shouldPromoteWfc(context, phoneId)) { 639 resourceId = R.string.incall_error_promote_wfc; 640 } else if (ImsUtil.isWfcModeWifiOnly(context, phoneId)) { 641 resourceId = R.string.incall_error_wfc_only_no_wireless_network; 642 } else if (ImsUtil.isWfcEnabled(context, phoneId)) { 643 resourceId = R.string.incall_error_power_off_wfc; 644 } else { 645 resourceId = R.string.incall_error_power_off; 646 } 647 break; 648 649 case android.telephony.DisconnectCause.LOW_BATTERY: 650 resourceId = R.string.callFailed_low_battery; 651 break; 652 653 case android.telephony.DisconnectCause.DIAL_LOW_BATTERY: 654 resourceId = R.string.dialFailed_low_battery; 655 break; 656 657 case android.telephony.DisconnectCause.CDMA_NOT_EMERGENCY: 658 // Only emergency calls are allowed when in emergency callback mode. 659 resourceId = R.string.incall_error_ecm_emergency_only; 660 break; 661 662 case android.telephony.DisconnectCause.EMERGENCY_ONLY: 663 // Only emergency numbers are allowed, but we tried to dial 664 // a non-emergency number. 665 resourceId = R.string.incall_error_emergency_only; 666 break; 667 668 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 669 // No network connection. 670 if (ImsUtil.shouldPromoteWfc(context, phoneId)) { 671 resourceId = R.string.incall_error_promote_wfc; 672 } else if (ImsUtil.isWfcModeWifiOnly(context, phoneId)) { 673 resourceId = R.string.incall_error_wfc_only_no_wireless_network; 674 } else if (ImsUtil.isWfcEnabled(context, phoneId)) { 675 resourceId = R.string.incall_error_out_of_service_wfc; 676 } else { 677 resourceId = R.string.incall_error_out_of_service; 678 } 679 break; 680 681 case android.telephony.DisconnectCause.NO_PHONE_NUMBER_SUPPLIED: 682 // The supplied Intent didn't contain a valid phone number. 683 // (This is rare and should only ever happen with broken 684 // 3rd-party apps.) For now just show a generic error. 685 resourceId = R.string.incall_error_no_phone_number_supplied; 686 break; 687 688 case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING: 689 resourceId = R.string.incall_error_missing_voicemail_number; 690 break; 691 692 case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED: 693 resourceId = R.string.callFailed_video_call_tty_enabled; 694 break; 695 696 case android.telephony.DisconnectCause.CALL_PULLED: 697 resourceId = R.string.callEnded_pulled; 698 break; 699 700 case android.telephony.DisconnectCause.MAXIMUM_NUMBER_OF_CALLS_REACHED: 701 resourceId = R.string.callFailed_maximum_reached; 702 703 case android.telephony.DisconnectCause.OUTGOING_CANCELED: 704 // We don't want to show any dialog for the canceled case since the call was 705 // either canceled by the user explicitly (end-call button pushed immediately) 706 // or some other app canceled the call and immediately issued a new CALL to 707 // replace it. 708 break; 709 710 case android.telephony.DisconnectCause.DATA_DISABLED: 711 resourceId = R.string.callFailed_data_disabled; 712 break; 713 714 case android.telephony.DisconnectCause.DATA_LIMIT_REACHED: 715 resourceId = R.string.callFailed_data_limit_reached_description; 716 break; 717 case android.telephony.DisconnectCause.DIALED_CALL_FORWARDING_WHILE_ROAMING: 718 resourceId = com.android.internal.R.string.mmiErrorWhileRoaming; 719 break; 720 721 case android.telephony.DisconnectCause.IMEI_NOT_ACCEPTED: 722 resourceId = R.string.callFailed_imei_not_accepted; 723 break; 724 725 case android.telephony.DisconnectCause.WIFI_LOST: 726 resourceId = R.string.callFailed_wifi_lost; 727 break; 728 case android.telephony.DisconnectCause.ALREADY_DIALING: 729 resourceId = R.string.callFailed_already_dialing; 730 break; 731 case android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING: 732 resourceId = R.string.callFailed_already_ringing; 733 break; 734 case android.telephony.DisconnectCause.CALLING_DISABLED: 735 resourceId = R.string.callFailed_calling_disabled; 736 break; 737 case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS: 738 resourceId = R.string.callFailed_too_many_calls; 739 break; 740 case android.telephony.DisconnectCause.IMS_SIP_ALTERNATE_EMERGENCY_CALL: 741 resourceId = R.string.incall_error_power_off; 742 break; 743 case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS: 744 resourceId = R.string.callFailed_otasp_provisioning_in_process; 745 break; 746 default: 747 break; 748 } 749 return resourceId == null ? "" : context.getResources().getString(resourceId); 750 } 751 752 /** 753 * Maps the telephony {@link android.telephony.DisconnectCause} into a reason string which is 754 * returned in the Telecom {@link DisconnectCause#getReason()}. 755 * 756 * @param context The current context. 757 * @param telephonyDisconnectCause The {@link android.telephony.DisconnectCause} code. 758 * @param reason A reason provided by the caller; only used if a more specific reason cannot 759 * be determined here. 760 * @return The disconnect reason. 761 */ toTelecomDisconnectReason(Context context, int telephonyDisconnectCause, String reason, int phoneId)762 private static String toTelecomDisconnectReason(Context context, int telephonyDisconnectCause, 763 String reason, int phoneId) { 764 765 if (context == null) { 766 return ""; 767 } 768 769 switch (telephonyDisconnectCause) { 770 case android.telephony.DisconnectCause.POWER_OFF: 771 // Airplane mode (radio off) 772 // intentional fall-through 773 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 774 // No network connection. 775 if (ImsUtil.shouldPromoteWfc(context, phoneId)) { 776 return android.telecom.DisconnectCause.REASON_WIFI_ON_BUT_WFC_OFF; 777 } 778 break; 779 case android.telephony.DisconnectCause.IMS_ACCESS_BLOCKED: 780 return DisconnectCause.REASON_IMS_ACCESS_BLOCKED; 781 } 782 783 // If no specific code-mapping found, then fall back to using the reason. 784 String causeAsString = android.telephony.DisconnectCause.toString(telephonyDisconnectCause); 785 if (reason == null) { 786 return causeAsString; 787 } else { 788 return reason + ", " + causeAsString; 789 } 790 } 791 792 /** 793 * Returns the tone to play for the disconnect cause, or UNKNOWN if none should be played. 794 */ toTelecomDisconnectCauseTone(int telephonyDisconnectCause)795 private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause) { 796 switch (telephonyDisconnectCause) { 797 case android.telephony.DisconnectCause.BUSY: 798 return ToneGenerator.TONE_SUP_BUSY; 799 800 case android.telephony.DisconnectCause.CONGESTION: 801 return ToneGenerator.TONE_SUP_CONGESTION; 802 803 case android.telephony.DisconnectCause.CDMA_REORDER: 804 return ToneGenerator.TONE_CDMA_REORDER; 805 806 case android.telephony.DisconnectCause.CDMA_INTERCEPT: 807 return ToneGenerator.TONE_CDMA_ABBR_INTERCEPT; 808 809 case android.telephony.DisconnectCause.CDMA_DROP: 810 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 811 return ToneGenerator.TONE_CDMA_CALLDROP_LITE; 812 813 case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER: 814 return ToneGenerator.TONE_SUP_ERROR; 815 816 case android.telephony.DisconnectCause.ERROR_UNSPECIFIED: 817 case android.telephony.DisconnectCause.LOCAL: 818 case android.telephony.DisconnectCause.NORMAL: 819 case android.telephony.DisconnectCause.NORMAL_UNSPECIFIED: 820 case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED: 821 return ToneGenerator.TONE_PROP_PROMPT; 822 823 case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY: 824 // Do not play any tones if disconnected because of a successful merge. 825 default: 826 return ToneGenerator.TONE_UNKNOWN; 827 } 828 } 829 } 830