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