Home | History | Annotate | Download | only in telephony
      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