Home | History | Annotate | Download | only in keyguard
      1 /*
      2  * Copyright (C) 2012 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.keyguard;
     18 
     19 import android.content.Context;
     20 import android.text.method.SingleLineTransformationMethod;
     21 import android.text.TextUtils;
     22 import android.util.AttributeSet;
     23 import android.view.View;
     24 import android.widget.TextView;
     25 
     26 import com.android.internal.telephony.IccCardConstants;
     27 import com.android.internal.telephony.IccCardConstants.State;
     28 import com.android.internal.widget.LockPatternUtils;
     29 
     30 import java.util.Locale;
     31 
     32 public class CarrierText extends TextView {
     33     private static CharSequence mSeparator;
     34 
     35     private LockPatternUtils mLockPatternUtils;
     36 
     37     private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
     38         private CharSequence mPlmn;
     39         private CharSequence mSpn;
     40         private State mSimState;
     41 
     42         @Override
     43         public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
     44             mPlmn = plmn;
     45             mSpn = spn;
     46             updateCarrierText(mSimState, mPlmn, mSpn);
     47         }
     48 
     49         @Override
     50         public void onSimStateChanged(IccCardConstants.State simState) {
     51             mSimState = simState;
     52             updateCarrierText(mSimState, mPlmn, mSpn);
     53         }
     54 
     55         public void onScreenTurnedOff(int why) {
     56             setSelected(false);
     57         };
     58 
     59         public void onScreenTurnedOn() {
     60             setSelected(true);
     61         };
     62     };
     63     /**
     64      * The status of this lock screen. Primarily used for widgets on LockScreen.
     65      */
     66     private static enum StatusMode {
     67         Normal, // Normal case (sim card present, it's not locked)
     68         NetworkLocked, // SIM card is 'network locked'.
     69         SimMissing, // SIM card is missing.
     70         SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access
     71         SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
     72         SimLocked, // SIM card is currently locked
     73         SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
     74         SimNotReady; // SIM is not ready yet. May never be on devices w/o a SIM.
     75     }
     76 
     77     public CarrierText(Context context) {
     78         this(context, null);
     79     }
     80 
     81     public CarrierText(Context context, AttributeSet attrs) {
     82         super(context, attrs);
     83         mLockPatternUtils = new LockPatternUtils(mContext);
     84         boolean useAllCaps = mContext.getResources().getBoolean(R.bool.kg_use_all_caps);
     85         setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps));
     86     }
     87 
     88     protected void updateCarrierText(State simState, CharSequence plmn, CharSequence spn) {
     89         setText(getCarrierTextForSimState(simState, plmn, spn));
     90     }
     91 
     92     @Override
     93     protected void onFinishInflate() {
     94         super.onFinishInflate();
     95         mSeparator = getResources().getString(R.string.kg_text_message_separator);
     96         final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
     97         setSelected(screenOn); // Allow marquee to work.
     98     }
     99 
    100     @Override
    101     protected void onAttachedToWindow() {
    102         super.onAttachedToWindow();
    103         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback);
    104     }
    105 
    106     @Override
    107     protected void onDetachedFromWindow() {
    108         super.onDetachedFromWindow();
    109         KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
    110     }
    111 
    112     /**
    113      * Top-level function for creating carrier text. Makes text based on simState, PLMN
    114      * and SPN as well as device capabilities, such as being emergency call capable.
    115      *
    116      * @param simState
    117      * @param plmn
    118      * @param spn
    119      * @return
    120      */
    121     private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
    122             CharSequence plmn, CharSequence spn) {
    123         CharSequence carrierText = null;
    124         StatusMode status = getStatusForIccState(simState);
    125         switch (status) {
    126             case Normal:
    127                 carrierText = concatenate(plmn, spn);
    128                 break;
    129 
    130             case SimNotReady:
    131                 carrierText = null; // nothing to display yet.
    132                 break;
    133 
    134             case NetworkLocked:
    135                 carrierText = makeCarrierStringOnEmergencyCapable(
    136                         mContext.getText(R.string.keyguard_network_locked_message), plmn);
    137                 break;
    138 
    139             case SimMissing:
    140                 // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
    141                 // This depends on mPlmn containing the text "Emergency calls only" when the radio
    142                 // has some connectivity. Otherwise, it should be null or empty and just show
    143                 // "No SIM card"
    144                 carrierText =  makeCarrierStringOnEmergencyCapable(
    145                         getContext().getText(R.string.keyguard_missing_sim_message_short),
    146                         plmn);
    147                 break;
    148 
    149             case SimPermDisabled:
    150                 carrierText = getContext().getText(
    151                         R.string.keyguard_permanent_disabled_sim_message_short);
    152                 break;
    153 
    154             case SimMissingLocked:
    155                 carrierText =  makeCarrierStringOnEmergencyCapable(
    156                         getContext().getText(R.string.keyguard_missing_sim_message_short),
    157                         plmn);
    158                 break;
    159 
    160             case SimLocked:
    161                 carrierText = makeCarrierStringOnEmergencyCapable(
    162                         getContext().getText(R.string.keyguard_sim_locked_message),
    163                         plmn);
    164                 break;
    165 
    166             case SimPukLocked:
    167                 carrierText = makeCarrierStringOnEmergencyCapable(
    168                         getContext().getText(R.string.keyguard_sim_puk_locked_message),
    169                         plmn);
    170                 break;
    171         }
    172 
    173         return carrierText;
    174     }
    175 
    176     /*
    177      * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
    178      */
    179     private CharSequence makeCarrierStringOnEmergencyCapable(
    180             CharSequence simMessage, CharSequence emergencyCallMessage) {
    181         if (mLockPatternUtils.isEmergencyCallCapable()) {
    182             return concatenate(simMessage, emergencyCallMessage);
    183         }
    184         return simMessage;
    185     }
    186 
    187     /**
    188      * Determine the current status of the lock screen given the SIM state and other stuff.
    189      */
    190     private StatusMode getStatusForIccState(IccCardConstants.State simState) {
    191         // Since reading the SIM may take a while, we assume it is present until told otherwise.
    192         if (simState == null) {
    193             return StatusMode.Normal;
    194         }
    195 
    196         final boolean missingAndNotProvisioned =
    197                 !KeyguardUpdateMonitor.getInstance(mContext).isDeviceProvisioned()
    198                 && (simState == IccCardConstants.State.ABSENT ||
    199                         simState == IccCardConstants.State.PERM_DISABLED);
    200 
    201         // Assume we're NETWORK_LOCKED if not provisioned
    202         simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
    203         switch (simState) {
    204             case ABSENT:
    205                 return StatusMode.SimMissing;
    206             case NETWORK_LOCKED:
    207                 return StatusMode.SimMissingLocked;
    208             case NOT_READY:
    209                 return StatusMode.SimNotReady;
    210             case PIN_REQUIRED:
    211                 return StatusMode.SimLocked;
    212             case PUK_REQUIRED:
    213                 return StatusMode.SimPukLocked;
    214             case READY:
    215                 return StatusMode.Normal;
    216             case PERM_DISABLED:
    217                 return StatusMode.SimPermDisabled;
    218             case UNKNOWN:
    219                 return StatusMode.SimMissing;
    220         }
    221         return StatusMode.SimMissing;
    222     }
    223 
    224     private static CharSequence concatenate(CharSequence plmn, CharSequence spn) {
    225         final boolean plmnValid = !TextUtils.isEmpty(plmn);
    226         final boolean spnValid = !TextUtils.isEmpty(spn);
    227         if (plmnValid && spnValid) {
    228             return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString();
    229         } else if (plmnValid) {
    230             return plmn;
    231         } else if (spnValid) {
    232             return spn;
    233         } else {
    234             return "";
    235         }
    236     }
    237 
    238     private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
    239             String plmn, String spn) {
    240         int carrierHelpTextId = 0;
    241         StatusMode status = getStatusForIccState(simState);
    242         switch (status) {
    243             case NetworkLocked:
    244                 carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled;
    245                 break;
    246 
    247             case SimMissing:
    248                 carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long;
    249                 break;
    250 
    251             case SimPermDisabled:
    252                 carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions;
    253                 break;
    254 
    255             case SimMissingLocked:
    256                 carrierHelpTextId = R.string.keyguard_missing_sim_instructions;
    257                 break;
    258 
    259             case Normal:
    260             case SimLocked:
    261             case SimPukLocked:
    262                 break;
    263         }
    264 
    265         return mContext.getText(carrierHelpTextId);
    266     }
    267 
    268     private class CarrierTextTransformationMethod extends SingleLineTransformationMethod {
    269         private final Locale mLocale;
    270         private final boolean mAllCaps;
    271 
    272         public CarrierTextTransformationMethod(Context context, boolean allCaps) {
    273             mLocale = context.getResources().getConfiguration().locale;
    274             mAllCaps = allCaps;
    275         }
    276 
    277         @Override
    278         public CharSequence getTransformation(CharSequence source, View view) {
    279             source = super.getTransformation(source, view);
    280 
    281             if (mAllCaps && source != null) {
    282                 source = source.toString().toUpperCase(mLocale);
    283             }
    284 
    285             return source;
    286         }
    287     }
    288 }
    289