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