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.phone.PhoneGlobals;
     24 import com.android.phone.common.R;
     25 
     26 public class DisconnectCauseUtil {
     27 
     28    /**
     29     * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more generic
     30     * {@link android.telecom.DisconnectCause}.object, possibly populated with a localized message
     31     * and tone.
     32     *
     33     * @param context The context.
     34     * @param telephonyDisconnectCause The code for the reason for the disconnect.
     35     */
     36     public static DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause) {
     37         return toTelecomDisconnectCause(telephonyDisconnectCause, null /* reason */);
     38     }
     39 
     40    /**
     41     * Converts from a disconnect code in {@link android.telephony.DisconnectCause} into a more generic
     42     * {@link android.telecom.DisconnectCause}.object, possibly populated with a localized message
     43     * and tone.
     44     *
     45     * @param context The context.
     46     * @param telephonyDisconnectCause The code for the reason for the disconnect.
     47     * @param reason Description of the reason for the disconnect, not intended for the user to see..
     48     */
     49     public static DisconnectCause toTelecomDisconnectCause(
     50             int telephonyDisconnectCause, String reason) {
     51         Context context = PhoneGlobals.getInstance();
     52         return new DisconnectCause(
     53                 toTelecomDisconnectCauseCode(telephonyDisconnectCause),
     54                 toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause),
     55                 toTelecomDisconnectCauseDescription(context, telephonyDisconnectCause),
     56                 toTelecomDisconnectReason(telephonyDisconnectCause, reason),
     57                 toTelecomDisconnectCauseTone(telephonyDisconnectCause));
     58     }
     59 
     60     /**
     61      * Convert the {@link android.telephony.DisconnectCause} disconnect code into a
     62      * {@link android.telecom.DisconnectCause} disconnect code.
     63      * @return The disconnect code as defined in {@link android.telecom.DisconnectCause}.
     64      */
     65     private static int toTelecomDisconnectCauseCode(int telephonyDisconnectCause) {
     66         switch (telephonyDisconnectCause) {
     67             case android.telephony.DisconnectCause.LOCAL:
     68                 return DisconnectCause.LOCAL;
     69 
     70             case android.telephony.DisconnectCause.NORMAL:
     71                 return DisconnectCause.REMOTE;
     72 
     73             case android.telephony.DisconnectCause.OUTGOING_CANCELED:
     74                 return DisconnectCause.CANCELED;
     75 
     76             case android.telephony.DisconnectCause.INCOMING_MISSED:
     77                 return DisconnectCause.MISSED;
     78 
     79             case android.telephony.DisconnectCause.INCOMING_REJECTED:
     80                 return DisconnectCause.REJECTED;
     81 
     82             case android.telephony.DisconnectCause.BUSY:
     83                 return DisconnectCause.BUSY;
     84 
     85             case android.telephony.DisconnectCause.CALL_BARRED:
     86             case android.telephony.DisconnectCause.CDMA_ACCESS_BLOCKED:
     87             case android.telephony.DisconnectCause.CDMA_NOT_EMERGENCY:
     88             case android.telephony.DisconnectCause.CS_RESTRICTED:
     89             case android.telephony.DisconnectCause.CS_RESTRICTED_EMERGENCY:
     90             case android.telephony.DisconnectCause.CS_RESTRICTED_NORMAL:
     91             case android.telephony.DisconnectCause.EMERGENCY_ONLY:
     92             case android.telephony.DisconnectCause.FDN_BLOCKED:
     93             case android.telephony.DisconnectCause.LIMIT_EXCEEDED:
     94                 return DisconnectCause.RESTRICTED;
     95 
     96             case android.telephony.DisconnectCause.CDMA_ACCESS_FAILURE:
     97             case android.telephony.DisconnectCause.CDMA_CALL_LOST:
     98             case android.telephony.DisconnectCause.CDMA_DROP:
     99             case android.telephony.DisconnectCause.CDMA_INTERCEPT:
    100             case android.telephony.DisconnectCause.CDMA_LOCKED_UNTIL_POWER_CYCLE:
    101             case android.telephony.DisconnectCause.CDMA_PREEMPTED:
    102             case android.telephony.DisconnectCause.CDMA_REORDER:
    103             case android.telephony.DisconnectCause.CDMA_RETRY_ORDER:
    104             case android.telephony.DisconnectCause.CDMA_SO_REJECT:
    105             case android.telephony.DisconnectCause.CONGESTION:
    106             case android.telephony.DisconnectCause.ICC_ERROR:
    107             case android.telephony.DisconnectCause.INVALID_CREDENTIALS:
    108             case android.telephony.DisconnectCause.INVALID_NUMBER:
    109             case android.telephony.DisconnectCause.LOST_SIGNAL:
    110             case android.telephony.DisconnectCause.NO_PHONE_NUMBER_SUPPLIED:
    111             case android.telephony.DisconnectCause.NUMBER_UNREACHABLE:
    112             case android.telephony.DisconnectCause.OUTGOING_FAILURE:
    113             case android.telephony.DisconnectCause.OUT_OF_NETWORK:
    114             case android.telephony.DisconnectCause.OUT_OF_SERVICE:
    115             case android.telephony.DisconnectCause.POWER_OFF:
    116             case android.telephony.DisconnectCause.SERVER_ERROR:
    117             case android.telephony.DisconnectCause.SERVER_UNREACHABLE:
    118             case android.telephony.DisconnectCause.TIMED_OUT:
    119             case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER:
    120             case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING:
    121             case android.telephony.DisconnectCause.ERROR_UNSPECIFIED:
    122                 return DisconnectCause.ERROR;
    123 
    124             case android.telephony.DisconnectCause.DIALED_MMI:
    125             case android.telephony.DisconnectCause.EXITED_ECM:
    126             case android.telephony.DisconnectCause.MMI:
    127             case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY:
    128                 return DisconnectCause.OTHER;
    129 
    130             case android.telephony.DisconnectCause.NOT_VALID:
    131             case android.telephony.DisconnectCause.NOT_DISCONNECTED:
    132                 return DisconnectCause.UNKNOWN;
    133 
    134             default:
    135                 Log.w("DisconnectCauseUtil.toTelecomDisconnectCauseCode",
    136                         "Unrecognized Telephony DisconnectCause "
    137                         + telephonyDisconnectCause);
    138                 return DisconnectCause.UNKNOWN;
    139         }
    140     }
    141 
    142     /**
    143      * Returns a label for to the disconnect cause to be shown to the user.
    144      */
    145     private static CharSequence toTelecomDisconnectCauseLabel(
    146             Context context, int telephonyDisconnectCause) {
    147         if (context == null ) {
    148             return "";
    149         }
    150 
    151         Integer resourceId = null;
    152         switch (telephonyDisconnectCause) {
    153             case android.telephony.DisconnectCause.BUSY:
    154                 resourceId = R.string.callFailed_userBusy;
    155                 break;
    156 
    157             case android.telephony.DisconnectCause.CONGESTION:
    158                 resourceId = R.string.callFailed_congestion;
    159                 break;
    160 
    161             case android.telephony.DisconnectCause.TIMED_OUT:
    162                 resourceId = R.string.callFailed_timedOut;
    163                 break;
    164 
    165             case android.telephony.DisconnectCause.SERVER_UNREACHABLE:
    166                 resourceId = R.string.callFailed_server_unreachable;
    167                 break;
    168 
    169             case android.telephony.DisconnectCause.NUMBER_UNREACHABLE:
    170                 resourceId = R.string.callFailed_number_unreachable;
    171                 break;
    172 
    173             case android.telephony.DisconnectCause.INVALID_CREDENTIALS:
    174                 resourceId = R.string.callFailed_invalid_credentials;
    175                 break;
    176 
    177             case android.telephony.DisconnectCause.SERVER_ERROR:
    178                 resourceId = R.string.callFailed_server_error;
    179                 break;
    180 
    181             case android.telephony.DisconnectCause.OUT_OF_NETWORK:
    182                 resourceId = R.string.callFailed_out_of_network;
    183                 break;
    184 
    185             case android.telephony.DisconnectCause.LOST_SIGNAL:
    186             case android.telephony.DisconnectCause.CDMA_DROP:
    187                 resourceId = R.string.callFailed_noSignal;
    188                 break;
    189 
    190             case android.telephony.DisconnectCause.LIMIT_EXCEEDED:
    191                 resourceId = R.string.callFailed_limitExceeded;
    192                 break;
    193 
    194             case android.telephony.DisconnectCause.POWER_OFF:
    195                 resourceId = R.string.callFailed_powerOff;
    196                 break;
    197 
    198             case android.telephony.DisconnectCause.ICC_ERROR:
    199                 resourceId = R.string.callFailed_simError;
    200                 break;
    201 
    202             case android.telephony.DisconnectCause.OUT_OF_SERVICE:
    203                 resourceId = R.string.callFailed_outOfService;
    204                 break;
    205 
    206             case android.telephony.DisconnectCause.INVALID_NUMBER:
    207             case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER:
    208                 resourceId = R.string.callFailed_unobtainable_number;
    209                 break;
    210 
    211             default:
    212                 break;
    213         }
    214         return resourceId == null ? "" : context.getResources().getString(resourceId);
    215     }
    216 
    217     /**
    218      * Returns a description of the disconnect cause to be shown to the user.
    219      */
    220     private static CharSequence toTelecomDisconnectCauseDescription(
    221             Context context, int telephonyDisconnectCause) {
    222         if (context == null ) {
    223             return "";
    224         }
    225 
    226         Integer resourceId = null;
    227         switch (telephonyDisconnectCause) {
    228             case android.telephony.DisconnectCause.CALL_BARRED:
    229                 resourceId = R.string.callFailed_cb_enabled;
    230                 break;
    231 
    232             case android.telephony.DisconnectCause.FDN_BLOCKED:
    233                 resourceId = R.string.callFailed_fdn_only;
    234                 break;
    235 
    236             case android.telephony.DisconnectCause.CS_RESTRICTED:
    237                 resourceId = R.string.callFailed_dsac_restricted;
    238                 break;
    239 
    240             case android.telephony.DisconnectCause.CS_RESTRICTED_EMERGENCY:
    241                 resourceId = R.string.callFailed_dsac_restricted_emergency;
    242                 break;
    243 
    244             case android.telephony.DisconnectCause.CS_RESTRICTED_NORMAL:
    245                 resourceId = R.string.callFailed_dsac_restricted_normal;
    246                 break;
    247 
    248             case android.telephony.DisconnectCause.OUTGOING_FAILURE:
    249                 // We couldn't successfully place the call; there was some
    250                 // failure in the telephony layer.
    251                 // TODO: Need UI spec for this failure case; for now just
    252                 // show a generic error.
    253                 resourceId = R.string.incall_error_call_failed;
    254                 break;
    255 
    256             case android.telephony.DisconnectCause.POWER_OFF:
    257                 // Radio is explictly powered off, presumably because the
    258                 // device is in airplane mode.
    259                 //
    260                 // TODO: For now this UI is ultra-simple: we simply display
    261                 // a message telling the user to turn off airplane mode.
    262                 // But it might be nicer for the dialog to offer the option
    263                 // to turn the radio on right there (and automatically retry
    264                 // the call once network registration is complete.)
    265                 resourceId = R.string.incall_error_power_off;
    266                 break;
    267 
    268             case android.telephony.DisconnectCause.EMERGENCY_ONLY:
    269                 // Only emergency numbers are allowed, but we tried to dial
    270                 // a non-emergency number.
    271                 resourceId = R.string.incall_error_emergency_only;
    272                 break;
    273 
    274             case android.telephony.DisconnectCause.OUT_OF_SERVICE:
    275                 // No network connection.
    276                 resourceId = R.string.incall_error_out_of_service;
    277                 break;
    278 
    279             case android.telephony.DisconnectCause.NO_PHONE_NUMBER_SUPPLIED:
    280                 // The supplied Intent didn't contain a valid phone number.
    281                 // (This is rare and should only ever happen with broken
    282                 // 3rd-party apps.) For now just show a generic error.
    283                 resourceId = R.string.incall_error_no_phone_number_supplied;
    284                 break;
    285 
    286             case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING:
    287                 // TODO: Need to bring up the "Missing Voicemail Number" dialog, which
    288                 // will ultimately take us to the Call Settings.
    289                 resourceId = R.string.incall_error_missing_voicemail_number;
    290                 break;
    291 
    292             case android.telephony.DisconnectCause.OUTGOING_CANCELED:
    293                 // We don't want to show any dialog for the canceled case since the call was
    294                 // either canceled by the user explicitly (end-call button pushed immediately)
    295                 // or some other app canceled the call and immediately issued a new CALL to
    296                 // replace it.
    297             default:
    298                 break;
    299         }
    300         return resourceId == null ? "" : context.getResources().getString(resourceId);
    301     }
    302 
    303     private static String toTelecomDisconnectReason(int telephonyDisconnectCause, String reason) {
    304         String causeAsString = android.telephony.DisconnectCause.toString(telephonyDisconnectCause);
    305         if (reason == null) {
    306             return causeAsString;
    307         } else {
    308             return reason + ", " + causeAsString;
    309         }
    310     }
    311 
    312     /**
    313      * Returns the tone to play for the disconnect cause, or UNKNOWN if none should be played.
    314      */
    315     private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause) {
    316         switch (telephonyDisconnectCause) {
    317             case android.telephony.DisconnectCause.BUSY:
    318                 return ToneGenerator.TONE_SUP_BUSY;
    319 
    320             case android.telephony.DisconnectCause.CONGESTION:
    321                 return ToneGenerator.TONE_SUP_CONGESTION;
    322 
    323             case android.telephony.DisconnectCause.CDMA_REORDER:
    324                 return ToneGenerator.TONE_CDMA_REORDER;
    325 
    326             case android.telephony.DisconnectCause.CDMA_INTERCEPT:
    327                 return ToneGenerator.TONE_CDMA_ABBR_INTERCEPT;
    328 
    329             case android.telephony.DisconnectCause.CDMA_DROP:
    330             case android.telephony.DisconnectCause.OUT_OF_SERVICE:
    331                 return ToneGenerator.TONE_CDMA_CALLDROP_LITE;
    332 
    333             case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER:
    334                 return ToneGenerator.TONE_SUP_ERROR;
    335 
    336             case android.telephony.DisconnectCause.ERROR_UNSPECIFIED:
    337             case android.telephony.DisconnectCause.LOCAL:
    338             case android.telephony.DisconnectCause.NORMAL:
    339                 return ToneGenerator.TONE_PROP_PROMPT;
    340 
    341             case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY:
    342                 // Do not play any tones if disconnected because of a successful merge.
    343             default:
    344                 return ToneGenerator.TONE_UNKNOWN;
    345         }
    346     }
    347 }
    348