• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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