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