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.os.PersistableBundle; 22 import android.provider.Settings; 23 import android.telecom.DisconnectCause; 24 import android.telephony.CarrierConfigManager; 25 import android.telephony.SubscriptionManager; 26 import android.telephony.TelephonyManager; 27 import android.telephony.ims.ImsReasonInfo; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.telephony.CallFailCause; 31 import com.android.internal.telephony.Phone; 32 import com.android.internal.telephony.PhoneFactory; 33 import com.android.internal.telephony.flags.FeatureFlags; 34 import com.android.internal.telephony.flags.FeatureFlagsImpl; 35 import com.android.internal.telephony.satellite.SatelliteController; 36 import com.android.phone.ImsUtil; 37 import com.android.phone.PhoneGlobals; 38 import com.android.phone.R; 39 40 public class DisconnectCauseUtil { 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 */ toTelecomDisconnectCause(int telephonyDisconnectCause)49 public static DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause) { 50 return toTelecomDisconnectCause(telephonyDisconnectCause, 51 CallFailCause.NOT_VALID, null /* reason */); 52 } 53 54 /** 55 * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more 56 * generic {@link android.telecom.DisconnectCause}.object, possibly populated with a localized 57 * message and tone. 58 * 59 * @param telephonyDisconnectCause The code for the reason for the disconnect. 60 * @param reason Description of the reason for the disconnect, not intended for the user to see.. 61 */ toTelecomDisconnectCause( int telephonyDisconnectCause, String reason)62 public static DisconnectCause toTelecomDisconnectCause( 63 int telephonyDisconnectCause, String reason) { 64 return toTelecomDisconnectCause(telephonyDisconnectCause, CallFailCause.NOT_VALID, reason); 65 } 66 67 /** 68 * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more 69 * generic {@link android.telecom.DisconnectCause}.object, possibly populated with a localized 70 * message and tone. 71 * 72 * @param telephonyDisconnectCause The code for the reason for the disconnect. 73 * @param telephonyPreciseDisconnectCause The code for the precise reason for the disconnect. 74 * @param reason Description of the reason for the disconnect, not intended for the user to see.. 75 */ toTelecomDisconnectCause( int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason)76 public static DisconnectCause toTelecomDisconnectCause( 77 int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason) { 78 return toTelecomDisconnectCause(telephonyDisconnectCause, telephonyPreciseDisconnectCause, 79 reason, SubscriptionManager.getDefaultVoicePhoneId(), null, new FlagsAdapterImpl()); 80 } 81 82 /** 83 * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more 84 * generic {@link android.telecom.DisconnectCause}.object, possibly populated with a localized 85 * message and tone for Slot. 86 * 87 * @param telephonyDisconnectCause The code for the reason for the disconnect. 88 * @param phoneId To support localized message based on phoneId 89 */ toTelecomDisconnectCause(int telephonyDisconnectCause, String reason, int phoneId)90 public static DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause, 91 String reason, int phoneId) { 92 return toTelecomDisconnectCause(telephonyDisconnectCause, CallFailCause.NOT_VALID, 93 reason, phoneId, null, new FlagsAdapterImpl(), false); 94 } 95 96 /** 97 * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more 98 * generic {@link android.telecom.DisconnectCause}.object, possibly populated with a localized 99 * message and tone for Slot. 100 * @param telephonyDisconnectCause The code for the reason for the disconnect. 101 * @param telephonyPreciseDisconnectCause The code for the precise reason for the disconnect. 102 * @param reason Description of the reason for the disconnect, not intended for the user to see. 103 * @param phoneId To support localized message based on phoneId 104 * @param imsReasonInfo 105 */ toTelecomDisconnectCause( int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason, int phoneId, ImsReasonInfo imsReasonInfo, FlagsAdapter featureFlags)106 public static DisconnectCause toTelecomDisconnectCause( 107 int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason, 108 int phoneId, ImsReasonInfo imsReasonInfo, FlagsAdapter featureFlags) { 109 return toTelecomDisconnectCause(telephonyDisconnectCause, telephonyPreciseDisconnectCause, 110 reason, phoneId, imsReasonInfo, getCarrierConfigBundle(phoneId), featureFlags, 111 false); 112 } 113 114 /** 115 * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more 116 * generic {@link android.telecom.DisconnectCause}.object, possibly populated with a localized 117 * message and tone for Slot. 118 * @param telephonyDisconnectCause The code for the reason for the disconnect. 119 * @param telephonyPreciseDisconnectCause The code for the precise reason for the disconnect. 120 * @param reason Description of the reason for the disconnect, not intended for the user to see. 121 * @param phoneId To support localized message based on phoneId 122 * @param imsReasonInfo 123 */ toTelecomDisconnectCause( int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason, int phoneId, ImsReasonInfo imsReasonInfo, FlagsAdapter featureFlags, boolean shouldTreatAsEmergency)124 public static DisconnectCause toTelecomDisconnectCause( 125 int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason, 126 int phoneId, ImsReasonInfo imsReasonInfo, FlagsAdapter featureFlags, 127 boolean shouldTreatAsEmergency) { 128 return toTelecomDisconnectCause(telephonyDisconnectCause, telephonyPreciseDisconnectCause, 129 reason, phoneId, imsReasonInfo, getCarrierConfigBundle(phoneId), featureFlags, 130 shouldTreatAsEmergency); 131 } 132 133 /** 134 * Final pre-processing method in creating a DisconnectCause. This method should NOT be called 135 * from another class directly. It only has private-package visibility for testing. 136 * 137 * @param carrierConfig 138 */ 139 @VisibleForTesting toTelecomDisconnectCause( int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason, int phoneId, ImsReasonInfo imsReasonInfo, PersistableBundle carrierConfig, FlagsAdapter featureFlags, boolean shouldTreatAsEmergency)140 static DisconnectCause toTelecomDisconnectCause( 141 int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason, 142 int phoneId, ImsReasonInfo imsReasonInfo, PersistableBundle carrierConfig, 143 FlagsAdapter featureFlags, boolean shouldTreatAsEmergency) { 144 Context context = PhoneGlobals.getInstance(); 145 146 return new DisconnectCause.Builder( 147 toTelecomDisconnectCauseCode(telephonyDisconnectCause, carrierConfig)) 148 .setLabel(toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause, 149 telephonyPreciseDisconnectCause, carrierConfig, featureFlags)) 150 .setDescription(toTelecomDisconnectCauseDescription( 151 context, telephonyDisconnectCause, phoneId, shouldTreatAsEmergency)) 152 .setReason(toTelecomDisconnectReason( 153 context, telephonyDisconnectCause, reason, phoneId)) 154 .setTone(toTelecomDisconnectCauseTone( 155 telephonyDisconnectCause, carrierConfig, featureFlags)) 156 .setTelephonyDisconnectCause(telephonyDisconnectCause) 157 .setTelephonyPreciseDisconnectCause(telephonyPreciseDisconnectCause) 158 .setImsReasonInfo(imsReasonInfo) 159 .build(); 160 } 161 162 /** 163 * Convert the {@link android.telephony.DisconnectCause} disconnect code into a 164 * {@link android.telecom.DisconnectCause} disconnect code. 165 * @return The disconnect code as defined in {@link android.telecom.DisconnectCause}. 166 */ toTelecomDisconnectCauseCode( int telephonyDisconnectCause, PersistableBundle carrierConfig)167 private static @DisconnectCause.DisconnectCauseCode int toTelecomDisconnectCauseCode( 168 int telephonyDisconnectCause, PersistableBundle carrierConfig) { 169 170 // special case: some carriers determine what disconnect causes play the BUSY tone. 171 // hence, must adjust the disconnectCause CODE to match the tone. 172 if (doesCarrierClassifyDisconnectCauseAsBusyCause(telephonyDisconnectCause, 173 carrierConfig)) { 174 return DisconnectCause.BUSY; 175 } 176 177 switch (telephonyDisconnectCause) { 178 case android.telephony.DisconnectCause.LOCAL: 179 // The call was still disconnected locally, so this is not an error condition. 180 case android.telephony.DisconnectCause.OUTGOING_EMERGENCY_CALL_PLACED: 181 return DisconnectCause.LOCAL; 182 183 case android.telephony.DisconnectCause.NORMAL: 184 case android.telephony.DisconnectCause.NORMAL_UNSPECIFIED: 185 return DisconnectCause.REMOTE; 186 187 case android.telephony.DisconnectCause.OUTGOING_CANCELED: 188 return DisconnectCause.CANCELED; 189 190 case android.telephony.DisconnectCause.INCOMING_MISSED: 191 return DisconnectCause.MISSED; 192 193 case android.telephony.DisconnectCause.INCOMING_REJECTED: 194 return DisconnectCause.REJECTED; 195 196 case android.telephony.DisconnectCause.BUSY: 197 return DisconnectCause.BUSY; 198 199 case android.telephony.DisconnectCause.CALL_BARRED: 200 case android.telephony.DisconnectCause.CDMA_ACCESS_BLOCKED: 201 case android.telephony.DisconnectCause.CDMA_NOT_EMERGENCY: 202 case android.telephony.DisconnectCause.CS_RESTRICTED: 203 case android.telephony.DisconnectCause.CS_RESTRICTED_EMERGENCY: 204 case android.telephony.DisconnectCause.CS_RESTRICTED_NORMAL: 205 case android.telephony.DisconnectCause.EMERGENCY_ONLY: 206 case android.telephony.DisconnectCause.FDN_BLOCKED: 207 case android.telephony.DisconnectCause.LIMIT_EXCEEDED: 208 case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED: 209 return DisconnectCause.RESTRICTED; 210 211 case android.telephony.DisconnectCause.CDMA_ACCESS_FAILURE: 212 case android.telephony.DisconnectCause.CDMA_ALREADY_ACTIVATED: 213 case android.telephony.DisconnectCause.CDMA_CALL_LOST: 214 case android.telephony.DisconnectCause.CDMA_DROP: 215 case android.telephony.DisconnectCause.CDMA_INTERCEPT: 216 case android.telephony.DisconnectCause.CDMA_LOCKED_UNTIL_POWER_CYCLE: 217 case android.telephony.DisconnectCause.CDMA_PREEMPTED: 218 case android.telephony.DisconnectCause.CDMA_REORDER: 219 case android.telephony.DisconnectCause.CDMA_RETRY_ORDER: 220 case android.telephony.DisconnectCause.CDMA_SO_REJECT: 221 case android.telephony.DisconnectCause.CONGESTION: 222 case android.telephony.DisconnectCause.ICC_ERROR: 223 case android.telephony.DisconnectCause.INVALID_CREDENTIALS: 224 case android.telephony.DisconnectCause.INVALID_NUMBER: 225 case android.telephony.DisconnectCause.LOST_SIGNAL: 226 case android.telephony.DisconnectCause.NO_PHONE_NUMBER_SUPPLIED: 227 case android.telephony.DisconnectCause.NUMBER_UNREACHABLE: 228 case android.telephony.DisconnectCause.OUTGOING_FAILURE: 229 case android.telephony.DisconnectCause.OUT_OF_NETWORK: 230 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 231 case android.telephony.DisconnectCause.POWER_OFF: 232 case android.telephony.DisconnectCause.LOW_BATTERY: 233 case android.telephony.DisconnectCause.DIAL_LOW_BATTERY: 234 case android.telephony.DisconnectCause.EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE: 235 case android.telephony.DisconnectCause.WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION: 236 case android.telephony.DisconnectCause.SERVER_ERROR: 237 case android.telephony.DisconnectCause.SERVER_UNREACHABLE: 238 case android.telephony.DisconnectCause.TIMED_OUT: 239 case android.telephony.DisconnectCause.ALREADY_DIALING: 240 case android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING: 241 case android.telephony.DisconnectCause.CALLING_DISABLED: 242 case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS: 243 case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS: 244 case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER: 245 case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING: 246 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_USSD: 247 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_SS: 248 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_DIAL: 249 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_DIAL_VIDEO: 250 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_SS: 251 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_USSD: 252 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_DIAL: 253 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO: 254 case android.telephony.DisconnectCause.ERROR_UNSPECIFIED: 255 case android.telephony.DisconnectCause.MAXIMUM_NUMBER_OF_CALLS_REACHED: 256 case android.telephony.DisconnectCause.DATA_DISABLED: 257 case android.telephony.DisconnectCause.DATA_LIMIT_REACHED: 258 case android.telephony.DisconnectCause.DIALED_CALL_FORWARDING_WHILE_ROAMING: 259 case android.telephony.DisconnectCause.IMEI_NOT_ACCEPTED: 260 case android.telephony.DisconnectCause.WIFI_LOST: 261 case android.telephony.DisconnectCause.IMS_ACCESS_BLOCKED: 262 case android.telephony.DisconnectCause.IMS_SIP_ALTERNATE_EMERGENCY_CALL: 263 case android.telephony.DisconnectCause.MEDIA_TIMEOUT: 264 case android.telephony.DisconnectCause.SATELLITE_ENABLED: 265 return DisconnectCause.ERROR; 266 267 case android.telephony.DisconnectCause.DIALED_MMI: 268 case android.telephony.DisconnectCause.EXITED_ECM: 269 case android.telephony.DisconnectCause.MMI: 270 case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY: 271 return DisconnectCause.OTHER; 272 273 case android.telephony.DisconnectCause.NOT_VALID: 274 case android.telephony.DisconnectCause.NOT_DISCONNECTED: 275 return DisconnectCause.UNKNOWN; 276 277 case android.telephony.DisconnectCause.CALL_PULLED: 278 return DisconnectCause.CALL_PULLED; 279 280 case android.telephony.DisconnectCause.ANSWERED_ELSEWHERE: 281 return DisconnectCause.ANSWERED_ELSEWHERE; 282 283 default: 284 Log.w("DisconnectCauseUtil.toTelecomDisconnectCauseCode", 285 "Unrecognized Telephony DisconnectCause " 286 + telephonyDisconnectCause); 287 return DisconnectCause.UNKNOWN; 288 } 289 } 290 291 /** 292 * Returns a label for to the disconnect cause to be shown to the user. 293 */ toTelecomDisconnectCauseLabel( Context context, int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, PersistableBundle carrierConfig, FlagsAdapter featureFlags)294 private static CharSequence toTelecomDisconnectCauseLabel( 295 Context context, int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, 296 PersistableBundle carrierConfig, FlagsAdapter featureFlags) { 297 CharSequence label; 298 if (!featureFlags.doNotOverridePreciseLabel()) { 299 // special case: some carriers determine what disconnect causes play the BUSY tone. 300 // hence, must adjust the disconnectCause LABEL to match the tone. 301 if (doesCarrierClassifyDisconnectCauseAsBusyCause(telephonyDisconnectCause, 302 carrierConfig)) { 303 return context.getResources().getString(R.string.callFailed_userBusy); 304 } 305 } 306 307 if (telephonyPreciseDisconnectCause != CallFailCause.NOT_VALID) { 308 label = getLabelFromPreciseDisconnectCause(context, telephonyPreciseDisconnectCause, 309 telephonyDisconnectCause); 310 } else { 311 if (featureFlags.doNotOverridePreciseLabel()) { 312 // special case: some carriers determine what disconnect causes play the BUSY tone. 313 // hence, must adjust the disconnectCause LABEL to match the tone. 314 if (doesCarrierClassifyDisconnectCauseAsBusyCause(telephonyDisconnectCause, 315 carrierConfig)) { 316 return context.getResources().getString(R.string.callFailed_userBusy); 317 } 318 } 319 label = getLabelFromDisconnectCause(context, telephonyDisconnectCause); 320 } 321 return label; 322 } 323 324 /** 325 * Returns a label for to the generic disconnect cause to be shown to the user. 326 */ getLabelFromDisconnectCause( Context context, int telephonyDisconnectCause)327 private static CharSequence getLabelFromDisconnectCause( 328 Context context, int telephonyDisconnectCause) { 329 if (context == null) { 330 return ""; 331 } 332 333 Integer resourceId = null; 334 switch (telephonyDisconnectCause) { 335 case android.telephony.DisconnectCause.BUSY: 336 resourceId = R.string.callFailed_userBusy; 337 break; 338 339 case android.telephony.DisconnectCause.CDMA_REORDER: 340 resourceId = R.string.callFailed_NetworkBusy; 341 break; 342 343 case android.telephony.DisconnectCause.IMS_ACCESS_BLOCKED: 344 resourceId = R.string.callFailed_NetworkCongested; 345 break; 346 347 case android.telephony.DisconnectCause.CONGESTION: 348 resourceId = R.string.callFailed_congestion; 349 break; 350 351 case android.telephony.DisconnectCause.TIMED_OUT: 352 resourceId = R.string.callFailed_timedOut; 353 break; 354 355 case android.telephony.DisconnectCause.SERVER_UNREACHABLE: 356 resourceId = R.string.callFailed_server_unreachable; 357 break; 358 359 case android.telephony.DisconnectCause.NUMBER_UNREACHABLE: 360 resourceId = R.string.callFailed_number_unreachable; 361 break; 362 363 case android.telephony.DisconnectCause.INVALID_CREDENTIALS: 364 resourceId = R.string.callFailed_invalid_credentials; 365 break; 366 367 case android.telephony.DisconnectCause.SERVER_ERROR: 368 resourceId = R.string.callFailed_server_error; 369 break; 370 371 case android.telephony.DisconnectCause.OUT_OF_NETWORK: 372 resourceId = R.string.callFailed_out_of_network; 373 break; 374 375 case android.telephony.DisconnectCause.LOST_SIGNAL: 376 case android.telephony.DisconnectCause.CDMA_DROP: 377 resourceId = R.string.callFailed_noSignal; 378 break; 379 380 case android.telephony.DisconnectCause.LIMIT_EXCEEDED: 381 resourceId = R.string.callFailed_limitExceeded; 382 break; 383 384 case android.telephony.DisconnectCause.POWER_OFF: 385 resourceId = R.string.callFailed_powerOff; 386 break; 387 388 case android.telephony.DisconnectCause.LOW_BATTERY: 389 resourceId = R.string.callFailed_low_battery; 390 break; 391 392 case android.telephony.DisconnectCause.DIAL_LOW_BATTERY: 393 resourceId = R.string.dialFailed_low_battery; 394 break; 395 396 case android.telephony.DisconnectCause.ICC_ERROR: 397 resourceId = R.string.callFailed_simError; 398 break; 399 400 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 401 resourceId = R.string.callFailed_outOfService; 402 break; 403 404 case android.telephony.DisconnectCause.INVALID_NUMBER: 405 case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER: 406 resourceId = R.string.callFailed_unobtainable_number; 407 break; 408 409 case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING: 410 resourceId = R.string.incall_error_missing_voicemail_number; 411 break; 412 413 case android.telephony.DisconnectCause.CALL_PULLED: 414 resourceId = R.string.callEnded_pulled; 415 break; 416 417 case android.telephony.DisconnectCause.MAXIMUM_NUMBER_OF_CALLS_REACHED: 418 resourceId = R.string.callFailed_maximum_reached; 419 break; 420 421 case android.telephony.DisconnectCause.DATA_DISABLED: 422 resourceId = R.string.callFailed_data_disabled; 423 break; 424 425 case android.telephony.DisconnectCause.DATA_LIMIT_REACHED: 426 resourceId = R.string.callFailed_data_limit_reached; 427 break; 428 case android.telephony.DisconnectCause.WIFI_LOST: 429 resourceId = R.string.callFailed_wifi_lost; 430 break; 431 case android.telephony.DisconnectCause.ALREADY_DIALING: 432 resourceId = R.string.callFailed_already_dialing; 433 break; 434 case android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING: 435 resourceId = R.string.callFailed_already_ringing; 436 break; 437 case android.telephony.DisconnectCause.CALLING_DISABLED: 438 resourceId = R.string.callFailed_calling_disabled; 439 break; 440 case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS: 441 resourceId = R.string.callFailed_too_many_calls; 442 break; 443 case android.telephony.DisconnectCause.IMS_SIP_ALTERNATE_EMERGENCY_CALL: 444 int airplaneMode = Settings.Global.getInt(context.getContentResolver(), 445 Settings.Global.AIRPLANE_MODE_ON, 0); 446 resourceId = R.string.incall_error_call_failed; 447 if (airplaneMode != 0) { 448 resourceId = R.string.incall_error_power_off; 449 } 450 break; 451 case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS: 452 resourceId = R.string.callFailed_otasp_provisioning_in_process; 453 break; 454 case android.telephony.DisconnectCause.EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE: 455 resourceId = R.string.callFailed_emergency_call_over_wfc_not_available; 456 break; 457 case android.telephony.DisconnectCause.WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION: 458 resourceId = R.string.callFailed_wfc_service_not_available_in_this_location; 459 break; 460 case android.telephony.DisconnectCause.SATELLITE_ENABLED: 461 resourceId = getSatelliteErrorString(); 462 break; 463 default: 464 break; 465 } 466 return resourceId == null ? "" : context.getResources().getString(resourceId); 467 } 468 469 /** 470 * Returns a label for to the precise disconnect cause to be shown to the user. 471 */ getLabelFromPreciseDisconnectCause( Context context, int telephonyPreciseDisconnectCause, int telephonyDisconnectCause)472 private static CharSequence getLabelFromPreciseDisconnectCause( 473 Context context, int telephonyPreciseDisconnectCause, int telephonyDisconnectCause) { 474 if (context == null) { 475 return ""; 476 } 477 478 Integer resourceId = null; 479 switch (telephonyPreciseDisconnectCause) { 480 case CallFailCause.UNOBTAINABLE_NUMBER: 481 resourceId = R.string.clh_callFailed_unassigned_number_txt; 482 break; 483 case CallFailCause.NO_ROUTE_TO_DEST: 484 resourceId = R.string.clh_callFailed_no_route_to_destination_txt; 485 break; 486 case CallFailCause.CHANNEL_UNACCEPTABLE: 487 resourceId = R.string.clh_callFailed_channel_unacceptable_txt; 488 break; 489 case CallFailCause.OPERATOR_DETERMINED_BARRING: 490 resourceId = R.string.clh_callFailed_operator_determined_barring_txt; 491 break; 492 case CallFailCause.NORMAL_CLEARING: 493 resourceId = R.string.clh_callFailed_normal_call_clearing_txt; 494 break; 495 case CallFailCause.USER_BUSY: 496 resourceId = R.string.clh_callFailed_user_busy_txt; 497 break; 498 case CallFailCause.NO_USER_RESPONDING: 499 resourceId = R.string.clh_callFailed_no_user_responding_txt; 500 break; 501 case CallFailCause.USER_ALERTING_NO_ANSWER: 502 resourceId = R.string.clh_callFailed_user_alerting_txt; 503 break; 504 case CallFailCause.CALL_REJECTED: 505 resourceId = R.string.clh_callFailed_call_rejected_txt; 506 break; 507 case CallFailCause.NUMBER_CHANGED: 508 resourceId = R.string.clh_callFailed_number_changed_txt; 509 break; 510 case CallFailCause.PRE_EMPTION: 511 resourceId = R.string.clh_callFailed_pre_emption_txt; 512 break; 513 case CallFailCause.NON_SELECTED_USER_CLEARING: 514 resourceId = R.string.clh_callFailed_non_selected_user_clearing_txt; 515 break; 516 case CallFailCause.DESTINATION_OUT_OF_ORDER: 517 resourceId = R.string.clh_callFailed_destination_out_of_order_txt; 518 break; 519 case CallFailCause.INVALID_NUMBER_FORMAT: 520 resourceId = R.string.clh_callFailed_invalid_number_format_txt; 521 break; 522 case CallFailCause.FACILITY_REJECTED: 523 resourceId = R.string.clh_callFailed_facility_rejected_txt; 524 break; 525 case CallFailCause.STATUS_ENQUIRY: 526 resourceId = R.string.clh_callFailed_response_to_STATUS_ENQUIRY_txt; 527 break; 528 case CallFailCause.NORMAL_UNSPECIFIED: 529 resourceId = R.string.clh_callFailed_normal_unspecified_txt; 530 break; 531 case CallFailCause.NO_CIRCUIT_AVAIL: 532 resourceId = R.string.clh_callFailed_no_circuit_available_txt; 533 break; 534 case CallFailCause.NETWORK_OUT_OF_ORDER: 535 resourceId = R.string.clh_callFailed_network_out_of_order_txt; 536 break; 537 case CallFailCause.TEMPORARY_FAILURE: 538 resourceId = R.string.clh_callFailed_temporary_failure_txt; 539 break; 540 case CallFailCause.SWITCHING_CONGESTION: 541 resourceId = R.string.clh_callFailed_switching_equipment_congestion_txt; 542 break; 543 case CallFailCause.ACCESS_INFORMATION_DISCARDED: 544 resourceId = R.string.clh_callFailed_access_information_discarded_txt; 545 break; 546 case CallFailCause.CHANNEL_NOT_AVAIL: 547 resourceId = R.string.clh_callFailed_requested_circuit_txt; 548 break; 549 case CallFailCause.RESOURCES_UNAVAILABLE_UNSPECIFIED: 550 resourceId = R.string.clh_callFailed_resources_unavailable_unspecified_txt; 551 break; 552 case CallFailCause.QOS_NOT_AVAIL: 553 resourceId = R.string.clh_callFailed_quality_of_service_unavailable_txt; 554 break; 555 case CallFailCause.REQUESTED_FACILITY_NOT_SUBSCRIBED: 556 resourceId = R.string.clh_callFailed_requested_facility_not_subscribed_txt; 557 break; 558 case CallFailCause.INCOMING_CALL_BARRED_WITHIN_CUG: 559 resourceId = R.string.clh_callFailed_incoming_calls_barred_within_the_CUG_txt; 560 break; 561 case CallFailCause.BEARER_CAPABILITY_NOT_AUTHORISED: 562 resourceId = R.string.clh_callFailed_bearer_capability_not_authorized_txt; 563 break; 564 case CallFailCause.BEARER_NOT_AVAIL: 565 resourceId = R.string.clh_callFailed_bearer_capability_not_presently_available_txt; 566 break; 567 case CallFailCause.SERVICE_OR_OPTION_NOT_AVAILABLE: 568 resourceId = 569 R.string.clh_callFailed_service_or_option_not_available_unspecified_txt; 570 break; 571 case CallFailCause.BEARER_SERVICE_NOT_IMPLEMENTED: 572 resourceId = R.string.clh_callFailed_bearer_service_not_implemented_txt; 573 break; 574 case CallFailCause.ACM_LIMIT_EXCEEDED: 575 resourceId = R.string.clh_callFailed_ACM_equal_to_or_greater_than_ACMmax_txt; 576 break; 577 case CallFailCause.REQUESTED_FACILITY_NOT_IMPLEMENTED: 578 resourceId = R.string.clh_callFailed_requested_facility_not_implemented_txt; 579 break; 580 case CallFailCause.ONLY_RESTRICTED_DIGITAL_INFO_BC_AVAILABLE: 581 resourceId = R.string 582 .clh_callFailed_only_restricted_digital_information_bearer_capability_is_available_txt; 583 break; 584 case CallFailCause.SERVICE_OR_OPTION_NOT_IMPLEMENTED: 585 resourceId = 586 R.string.clh_callFailed_service_or_option_not_implemented_unspecified_txt; 587 break; 588 case CallFailCause.INVALID_TRANSACTION_ID_VALUE: 589 resourceId = R.string.clh_callFailed_invalid_transaction_identifier_value_txt; 590 break; 591 case CallFailCause.USER_NOT_MEMBER_OF_CUG: 592 resourceId = R.string.clh_callFailed_user_not_member_of_CUG_txt; 593 break; 594 case CallFailCause.INCOMPATIBLE_DESTINATION: 595 resourceId = R.string.clh_callFailed_incompatible_destination_txt; 596 break; 597 case CallFailCause.INVALID_TRANSIT_NETWORK_SELECTION: 598 resourceId = R.string.clh_callFailed_invalid_transit_network_selection_txt; 599 break; 600 case CallFailCause.SEMANTICALLY_INCORRECT_MESSAGE: 601 resourceId = R.string.clh_callFailed_semantically_incorrect_message_txt; 602 break; 603 case CallFailCause.INVALID_MANDATORY_INFORMATION: 604 resourceId = R.string.clh_callFailed_invalid_mandatory_information_txt; 605 break; 606 case CallFailCause.MESSAGE_TYPE_NON_EXISTENT: 607 resourceId = 608 R.string.clh_callFailed_message_type_non_existent_or_not_implemented_txt; 609 break; 610 case CallFailCause.MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROT_STATE: 611 resourceId = R.string 612 .clh_callFailed_message_type_not_compatible_with_protocol_state_txt; 613 break; 614 case CallFailCause.IE_NON_EXISTENT_OR_NOT_IMPLEMENTED: 615 resourceId = R.string 616 .clh_callFailed_information_element_non_existent_or_not_implemented_txt; 617 break; 618 case CallFailCause.CONDITIONAL_IE_ERROR: 619 resourceId = R.string.clh_callFailed_conditional_IE_error_txt; 620 break; 621 case CallFailCause.MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE: 622 resourceId = R.string.clh_callFailed_message_not_compatible_with_protocol_state_txt; 623 break; 624 case CallFailCause.RECOVERY_ON_TIMER_EXPIRY: 625 resourceId = R.string.clh_callFailed_recovery_on_timer_expiry_txt; 626 break; 627 case CallFailCause.PROTOCOL_ERROR_UNSPECIFIED: 628 resourceId = R.string.clh_callFailed_protocol_Error_unspecified_txt; 629 break; 630 case CallFailCause.INTERWORKING_UNSPECIFIED: 631 resourceId = R.string.clh_callFailed_interworking_unspecified_txt; 632 break; 633 default: 634 switch (telephonyDisconnectCause) { 635 case android.telephony.DisconnectCause.POWER_OFF: 636 resourceId = R.string.clh_callFailed_powerOff_txt; 637 break; 638 case android.telephony.DisconnectCause.ICC_ERROR: 639 resourceId = R.string.clh_callFailed_simError_txt; 640 break; 641 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 642 resourceId = R.string.clh_incall_error_out_of_service_txt; 643 break; 644 case android.telephony.DisconnectCause.SATELLITE_ENABLED: 645 resourceId = getSatelliteErrorString(); 646 break; 647 default: 648 resourceId = R.string.clh_card_title_call_ended_txt; 649 break; 650 } 651 break; 652 } 653 return context.getResources().getString(resourceId); 654 } 655 656 /** 657 * Returns a description of the disconnect cause to be shown to the user. 658 */ toTelecomDisconnectCauseDescription( Context context, int telephonyDisconnectCause, int phoneId, boolean shouldTreatAsEmergency)659 private static CharSequence toTelecomDisconnectCauseDescription( 660 Context context, int telephonyDisconnectCause, int phoneId, 661 boolean shouldTreatAsEmergency) { 662 if (context == null ) { 663 return ""; 664 } 665 666 Integer resourceId = null; 667 switch (telephonyDisconnectCause) { 668 case android.telephony.DisconnectCause.CALL_BARRED: 669 resourceId = R.string.callFailed_cb_enabled; 670 break; 671 672 case android.telephony.DisconnectCause.CDMA_ALREADY_ACTIVATED: 673 resourceId = R.string.callFailed_cdma_activation; 674 break; 675 676 case android.telephony.DisconnectCause.CDMA_REORDER: 677 resourceId = R.string.callFailed_NetworkBusy; 678 break; 679 680 case android.telephony.DisconnectCause.IMS_ACCESS_BLOCKED: 681 resourceId = R.string.callFailed_NetworkCongested; 682 break; 683 684 case android.telephony.DisconnectCause.FDN_BLOCKED: 685 resourceId = R.string.callFailed_fdn_only; 686 break; 687 688 case android.telephony.DisconnectCause.CS_RESTRICTED: 689 resourceId = R.string.callFailed_dsac_restricted; 690 break; 691 692 case android.telephony.DisconnectCause.CS_RESTRICTED_EMERGENCY: 693 resourceId = R.string.callFailed_dsac_restricted_emergency; 694 break; 695 696 case android.telephony.DisconnectCause.CS_RESTRICTED_NORMAL: 697 resourceId = R.string.callFailed_dsac_restricted_normal; 698 break; 699 700 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_USSD: 701 resourceId = R.string.callFailed_dialToUssd; 702 break; 703 704 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_SS: 705 resourceId = R.string.callFailed_dialToSs; 706 break; 707 708 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_DIAL: 709 resourceId = R.string.callFailed_dialToDial; 710 break; 711 712 case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_DIAL_VIDEO: 713 resourceId = R.string.callFailed_dialToDialVideo; 714 break; 715 716 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_SS: 717 resourceId = R.string.callFailed_dialVideoToSs; 718 break; 719 720 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_USSD: 721 resourceId = R.string.callFailed_dialVideoToUssd; 722 break; 723 724 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_DIAL: 725 resourceId = R.string.callFailed_dialVideoToDial; 726 break; 727 728 case android.telephony.DisconnectCause.DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO: 729 resourceId = R.string.callFailed_dialVideoToDialVideo; 730 break; 731 732 case android.telephony.DisconnectCause.OUTGOING_FAILURE: 733 // We couldn't successfully place the call; there was some 734 // failure in the telephony layer. 735 // TODO: Need UI spec for this failure case; for now just 736 // show a generic error. 737 resourceId = R.string.incall_error_call_failed; 738 break; 739 740 case android.telephony.DisconnectCause.POWER_OFF: 741 // Radio is explicitly powered off because the device's radio is off. 742 743 // TODO: Offer the option to turn the radio on, and automatically retry the call 744 // once network registration is complete. 745 746 if (isRadioOffForThermalMitigation(phoneId)) { 747 resourceId = R.string.incall_error_power_off_thermal; 748 } else if (ImsUtil.shouldPromoteWfc(context, phoneId)) { 749 resourceId = R.string.incall_error_promote_wfc; 750 } else if (ImsUtil.isWfcModeWifiOnly(context, phoneId)) { 751 resourceId = R.string.incall_error_wfc_only_no_wireless_network; 752 } else if (ImsUtil.isWfcEnabled(context, phoneId)) { 753 resourceId = R.string.incall_error_power_off_wfc; 754 } else { 755 resourceId = R.string.incall_error_power_off; 756 } 757 break; 758 759 case android.telephony.DisconnectCause.LOW_BATTERY: 760 resourceId = R.string.callFailed_low_battery; 761 break; 762 763 case android.telephony.DisconnectCause.DIAL_LOW_BATTERY: 764 resourceId = R.string.dialFailed_low_battery; 765 break; 766 767 case android.telephony.DisconnectCause.CDMA_NOT_EMERGENCY: 768 // Only emergency calls are allowed when in emergency callback mode. 769 resourceId = R.string.incall_error_ecm_emergency_only; 770 break; 771 772 case android.telephony.DisconnectCause.EMERGENCY_ONLY: 773 // Only emergency numbers are allowed, but we tried to dial 774 // a non-emergency number. 775 resourceId = R.string.incall_error_emergency_only; 776 break; 777 778 case android.telephony.DisconnectCause.ICC_ERROR: 779 resourceId = R.string.callFailed_simError; 780 break; 781 782 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 783 // No network connection. 784 FeatureFlags mFeatureFlags = new FeatureFlagsImpl(); 785 if (ImsUtil.shouldPromoteWfc(context, phoneId)) { 786 resourceId = R.string.incall_error_promote_wfc; 787 } else if (ImsUtil.isWfcModeWifiOnly(context, phoneId)) { 788 resourceId = R.string.incall_error_wfc_only_no_wireless_network; 789 } else if (ImsUtil.isWfcEnabled(context, phoneId)) { 790 if (!mFeatureFlags.showCallFailNotificationFor2gToggle()) { 791 resourceId = R.string.incall_error_out_of_service_wfc; 792 break; 793 } 794 if (is2gDisabled(phoneId) && !shouldTreatAsEmergency) { 795 resourceId = R.string.incall_error_out_of_service_wfc_2g_user; 796 } else { 797 resourceId = R.string.incall_error_out_of_service_wfc; 798 } 799 } else { 800 if (!mFeatureFlags.showCallFailNotificationFor2gToggle()) { 801 resourceId = R.string.incall_error_out_of_service; 802 break; 803 } 804 if (is2gDisabled(phoneId) && !shouldTreatAsEmergency) { 805 resourceId = R.string.incall_error_out_of_service_2g; 806 } else { 807 resourceId = R.string.incall_error_out_of_service; 808 } 809 } 810 break; 811 812 case android.telephony.DisconnectCause.NO_PHONE_NUMBER_SUPPLIED: 813 // The supplied Intent didn't contain a valid phone number. 814 // (This is rare and should only ever happen with broken 815 // 3rd-party apps.) For now just show a generic error. 816 resourceId = R.string.incall_error_no_phone_number_supplied; 817 break; 818 819 case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING: 820 resourceId = R.string.incall_error_missing_voicemail_number; 821 break; 822 823 case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED: 824 resourceId = R.string.callFailed_video_call_tty_enabled; 825 break; 826 827 case android.telephony.DisconnectCause.CALL_PULLED: 828 resourceId = R.string.callEnded_pulled; 829 break; 830 831 case android.telephony.DisconnectCause.MAXIMUM_NUMBER_OF_CALLS_REACHED: 832 resourceId = R.string.callFailed_maximum_reached; 833 834 case android.telephony.DisconnectCause.OUTGOING_CANCELED: 835 // We don't want to show any dialog for the canceled case since the call was 836 // either canceled by the user explicitly (end-call button pushed immediately) 837 // or some other app canceled the call and immediately issued a new CALL to 838 // replace it. 839 break; 840 841 case android.telephony.DisconnectCause.DATA_DISABLED: 842 resourceId = R.string.callFailed_data_disabled; 843 break; 844 845 case android.telephony.DisconnectCause.DATA_LIMIT_REACHED: 846 resourceId = R.string.callFailed_data_limit_reached_description; 847 break; 848 case android.telephony.DisconnectCause.DIALED_CALL_FORWARDING_WHILE_ROAMING: 849 resourceId = com.android.internal.R.string.mmiErrorWhileRoaming; 850 break; 851 852 case android.telephony.DisconnectCause.IMEI_NOT_ACCEPTED: 853 resourceId = R.string.callFailed_imei_not_accepted; 854 break; 855 856 case android.telephony.DisconnectCause.WIFI_LOST: 857 resourceId = R.string.callFailed_wifi_lost; 858 break; 859 case android.telephony.DisconnectCause.ALREADY_DIALING: 860 resourceId = R.string.callFailed_already_dialing; 861 break; 862 case android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING: 863 resourceId = R.string.callFailed_already_ringing; 864 break; 865 case android.telephony.DisconnectCause.CALLING_DISABLED: 866 resourceId = R.string.callFailed_calling_disabled; 867 break; 868 case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS: 869 resourceId = R.string.callFailed_too_many_calls; 870 break; 871 case android.telephony.DisconnectCause.IMS_SIP_ALTERNATE_EMERGENCY_CALL: 872 int airplaneMode = Settings.Global.getInt(context.getContentResolver(), 873 Settings.Global.AIRPLANE_MODE_ON, 0); 874 resourceId = R.string.incall_error_call_failed; 875 if (airplaneMode != 0) { 876 resourceId = R.string.incall_error_power_off; 877 } 878 break; 879 case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS: 880 resourceId = R.string.callFailed_otasp_provisioning_in_process; 881 break; 882 case android.telephony.DisconnectCause.EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE: 883 resourceId = R.string.callFailed_emergency_call_over_wfc_not_available; 884 break; 885 case android.telephony.DisconnectCause.WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION: 886 resourceId = R.string.callFailed_wfc_service_not_available_in_this_location; 887 break; 888 case android.telephony.DisconnectCause.SATELLITE_ENABLED: 889 resourceId = getSatelliteErrorString(); 890 break; 891 default: 892 break; 893 } 894 return resourceId == null ? "" : context.getResources().getString(resourceId); 895 } 896 isRadioOffForThermalMitigation(int phoneId)897 private static boolean isRadioOffForThermalMitigation(int phoneId) { 898 Phone phone = PhoneFactory.getPhone(phoneId); 899 return phone == null ? false : phone.isRadioOffForThermalMitigation(); 900 } 901 902 /** 903 * Maps the telephony {@link android.telephony.DisconnectCause} into a reason string which is 904 * returned in the Telecom {@link DisconnectCause#getReason()}. 905 * 906 * @param context The current context. 907 * @param telephonyDisconnectCause The {@link android.telephony.DisconnectCause} code. 908 * @param reason A reason provided by the caller; only used if a more specific reason cannot 909 * be determined here. 910 * @return The disconnect reason. 911 */ toTelecomDisconnectReason(Context context, int telephonyDisconnectCause, String reason, int phoneId)912 private static String toTelecomDisconnectReason(Context context, int telephonyDisconnectCause, 913 String reason, int phoneId) { 914 915 if (context == null) { 916 return ""; 917 } 918 919 switch (telephonyDisconnectCause) { 920 case android.telephony.DisconnectCause.POWER_OFF: 921 // Airplane mode (radio off) 922 // intentional fall-through 923 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 924 // No network connection. 925 if (ImsUtil.shouldPromoteWfc(context, phoneId)) { 926 return android.telecom.DisconnectCause.REASON_WIFI_ON_BUT_WFC_OFF; 927 } 928 break; 929 case android.telephony.DisconnectCause.IMS_ACCESS_BLOCKED: 930 return DisconnectCause.REASON_IMS_ACCESS_BLOCKED; 931 case android.telephony.DisconnectCause.OUTGOING_EMERGENCY_CALL_PLACED: 932 return DisconnectCause.REASON_EMERGENCY_CALL_PLACED; 933 case android.telephony.DisconnectCause.SATELLITE_ENABLED: 934 return reason; 935 } 936 937 // If no specific code-mapping found, then fall back to using the reason. 938 String causeAsString = android.telephony.DisconnectCause.toString(telephonyDisconnectCause); 939 if (reason == null) { 940 return causeAsString; 941 } else { 942 return reason + ", " + causeAsString; 943 } 944 } 945 946 /** 947 * Returns the tone to play for the disconnect cause, or UNKNOWN if none should be played. 948 */ toTelecomDisconnectCauseTone(int telephonyDisconnectCause, PersistableBundle carrierConfig, FlagsAdapter featureFlags)949 private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause, 950 PersistableBundle carrierConfig, FlagsAdapter featureFlags) { 951 952 // special case: some carriers determine what disconnect causes play the BUSY tone. 953 if (doesCarrierClassifyDisconnectCauseAsBusyCause(telephonyDisconnectCause, 954 carrierConfig)) { 955 return ToneGenerator.TONE_SUP_BUSY; 956 } 957 958 switch (telephonyDisconnectCause) { 959 case android.telephony.DisconnectCause.BUSY: 960 if (featureFlags.doNotOverridePreciseLabel()) { 961 return ToneGenerator.TONE_SUP_BUSY; 962 } 963 case android.telephony.DisconnectCause.CONGESTION: 964 return ToneGenerator.TONE_SUP_CONGESTION; 965 966 case android.telephony.DisconnectCause.CDMA_REORDER: 967 return ToneGenerator.TONE_CDMA_REORDER; 968 969 case android.telephony.DisconnectCause.CDMA_INTERCEPT: 970 return ToneGenerator.TONE_CDMA_ABBR_INTERCEPT; 971 972 case android.telephony.DisconnectCause.CDMA_DROP: 973 case android.telephony.DisconnectCause.OUT_OF_SERVICE: 974 return ToneGenerator.TONE_CDMA_CALLDROP_LITE; 975 976 case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER: 977 return ToneGenerator.TONE_SUP_ERROR; 978 979 case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY: 980 // Do not play any tones if disconnected because of a successful merge. 981 return -1; 982 983 case android.telephony.DisconnectCause.ERROR_UNSPECIFIED: 984 case android.telephony.DisconnectCause.LOCAL: 985 case android.telephony.DisconnectCause.NORMAL: 986 case android.telephony.DisconnectCause.NORMAL_UNSPECIFIED: 987 case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED: 988 case android.telephony.DisconnectCause.WIFI_LOST: 989 default: 990 return ToneGenerator.TONE_PROP_PROMPT; 991 } 992 } 993 994 /** 995 * Helper method that examines the carrierConfig KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY 996 * containing the DisconnectCauses that are classified as DisconnectCause.BUSY 997 * 998 * @param carrierConfig object that holds all the carrier specific settings 999 * @return whether the cause is in the carrier config busy tone array 1000 */ 1001 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) doesCarrierClassifyDisconnectCauseAsBusyCause( int telephonyDisconnectCause, PersistableBundle carrierConfig)1002 public static boolean doesCarrierClassifyDisconnectCauseAsBusyCause( 1003 int telephonyDisconnectCause, PersistableBundle carrierConfig) { 1004 if (carrierConfig == null) { 1005 return false; 1006 } 1007 int[] busyToneArray = carrierConfig.getIntArray( 1008 CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY); 1009 if (busyToneArray == null) { 1010 return false; 1011 } 1012 for (int busyTone : busyToneArray) { 1013 if (busyTone == telephonyDisconnectCause) { 1014 return true; 1015 } 1016 } 1017 return false; 1018 } 1019 getCarrierConfigBundle(int phoneId)1020 private static PersistableBundle getCarrierConfigBundle(int phoneId) { 1021 Phone phone = PhoneFactory.getPhone(phoneId); 1022 PersistableBundle config; 1023 1024 if (phone != null) { 1025 config = PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId()); 1026 } else { 1027 config = PhoneGlobals.getInstance().getCarrierConfig(); 1028 } 1029 1030 return config; 1031 } 1032 1033 /** 1034 * Returns true if 2G is disabled. 1035 */ is2gDisabled(int phoneId)1036 protected static boolean is2gDisabled(int phoneId) { 1037 Phone phone = PhoneFactory.getPhone(phoneId); 1038 if (phone == null) { 1039 return false; 1040 } 1041 long bitmask2g = TelephonyManager.NETWORK_CLASS_BITMASK_2G; 1042 long currentlyAllowedNetworkTypes = phone.getAllowedNetworkTypes( 1043 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G); 1044 boolean is2gEnabled = (currentlyAllowedNetworkTypes & bitmask2g) != 0; 1045 return !is2gEnabled; 1046 } 1047 getSatelliteErrorString()1048 private static Integer getSatelliteErrorString() { 1049 if (SatelliteController.getInstance().isSatelliteEnabled()) { 1050 return R.string.incall_error_satellite_enabled; 1051 } 1052 return R.string.incall_error_carrier_roaming_satellite_mode; 1053 } 1054 } 1055