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