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