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 17package com.android.keyguard; 18 19import android.content.Context; 20import android.text.method.SingleLineTransformationMethod; 21import android.text.TextUtils; 22import android.util.AttributeSet; 23import android.view.View; 24import android.widget.TextView; 25 26import com.android.internal.telephony.IccCardConstants; 27import com.android.internal.telephony.IccCardConstants.State; 28import com.android.internal.widget.LockPatternUtils; 29 30import java.util.Locale; 31 32public 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