blob: e89caf776955b96c11de7ebac04ea4eb8aa9d40a [file] [log] [blame]
Jim Miller109f1fd2012-09-19 20:44:16 -07001/*
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
Jim Miller5ecd8112013-01-09 18:50:26 -080017package com.android.keyguard;
Jim Millerf9cb7ba2012-09-17 22:31:56 -070018
Jason Monk9ff69bd2014-12-02 16:43:17 -050019import java.util.List;
20import java.util.Locale;
Sanket Padaweb8726b72015-04-01 14:02:16 -070021import java.util.Objects;
Jason Monk9ff69bd2014-12-02 16:43:17 -050022
Jim Millerf9cb7ba2012-09-17 22:31:56 -070023import android.content.Context;
Jason Monkde3260b2015-02-24 08:55:26 -050024import android.content.Intent;
25import android.content.IntentFilter;
Etan Cohen47051d82015-07-06 16:19:04 -070026import android.content.res.Resources;
Jorim Jaggi25807932014-04-24 23:29:46 +020027import android.content.res.TypedArray;
Jason Monk83bc2aaf2014-12-05 10:16:24 -050028import android.net.ConnectivityManager;
Etan Cohen47051d82015-07-06 16:19:04 -070029import android.net.wifi.WifiManager;
30import android.telephony.ServiceState;
Jason Monk9ff69bd2014-12-02 16:43:17 -050031import android.telephony.SubscriptionInfo;
Jim Millerf9cb7ba2012-09-17 22:31:56 -070032import android.text.TextUtils;
Jason Monk9ff69bd2014-12-02 16:43:17 -050033import android.text.method.SingleLineTransformationMethod;
Jim Millerf9cb7ba2012-09-17 22:31:56 -070034import android.util.AttributeSet;
Jason Monk9ff69bd2014-12-02 16:43:17 -050035import android.util.Log;
Victoria Lease1d80e972013-11-01 16:34:03 -070036import android.view.View;
Jim Millerf9cb7ba2012-09-17 22:31:56 -070037import android.widget.TextView;
38
Jim Millerf9cb7ba2012-09-17 22:31:56 -070039import com.android.internal.telephony.IccCardConstants;
40import com.android.internal.telephony.IccCardConstants.State;
Jason Monkde3260b2015-02-24 08:55:26 -050041import com.android.internal.telephony.TelephonyIntents;
Jason Monk726fb282015-03-31 12:56:11 -040042import com.android.settingslib.WirelessUtils;
Jim Millerf9cb7ba2012-09-17 22:31:56 -070043
44public class CarrierText extends TextView {
Jason Monk9ff69bd2014-12-02 16:43:17 -050045 private static final boolean DEBUG = KeyguardConstants.DEBUG;
46 private static final String TAG = "CarrierText";
47
Jim Millere9be1402012-11-01 16:14:20 -070048 private static CharSequence mSeparator;
49
Adrian Roosc2e01682015-01-15 23:20:20 +010050 private final boolean mIsEmergencyCallCapable;
51
Jason Monk9ff69bd2014-12-02 16:43:17 -050052 private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Jim Millerf9cb7ba2012-09-17 22:31:56 -070053
Etan Cohen47051d82015-07-06 16:19:04 -070054 private WifiManager mWifiManager;
55
Jim Millerf9cb7ba2012-09-17 22:31:56 -070056 private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
Jim Millerf9cb7ba2012-09-17 22:31:56 -070057 @Override
Jason Monk9ff69bd2014-12-02 16:43:17 -050058 public void onRefreshCarrierInfo() {
59 updateCarrierText();
Jim Millerf9cb7ba2012-09-17 22:31:56 -070060 }
Jim Miller20daffd2013-10-07 14:59:53 -070061
62 public void onScreenTurnedOff(int why) {
63 setSelected(false);
64 };
65
66 public void onScreenTurnedOn() {
67 setSelected(true);
68 };
Jim Millerf9cb7ba2012-09-17 22:31:56 -070069 };
70 /**
71 * The status of this lock screen. Primarily used for widgets on LockScreen.
72 */
Jim Miller109f1fd2012-09-19 20:44:16 -070073 private static enum StatusMode {
Jim Millerf9cb7ba2012-09-17 22:31:56 -070074 Normal, // Normal case (sim card present, it's not locked)
75 NetworkLocked, // SIM card is 'network locked'.
76 SimMissing, // SIM card is missing.
77 SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access
78 SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
79 SimLocked, // SIM card is currently locked
Jim Miller109f1fd2012-09-19 20:44:16 -070080 SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
81 SimNotReady; // SIM is not ready yet. May never be on devices w/o a SIM.
Jim Millerf9cb7ba2012-09-17 22:31:56 -070082 }
83
84 public CarrierText(Context context) {
85 this(context, null);
86 }
87
88 public CarrierText(Context context, AttributeSet attrs) {
89 super(context, attrs);
Adrian Roosc2e01682015-01-15 23:20:20 +010090 mIsEmergencyCallCapable = context.getResources().getBoolean(
91 com.android.internal.R.bool.config_voice_capable);
Jorim Jaggi25807932014-04-24 23:29:46 +020092 boolean useAllCaps;
93 TypedArray a = context.getTheme().obtainStyledAttributes(
94 attrs, R.styleable.CarrierText, 0, 0);
95 try {
96 useAllCaps = a.getBoolean(R.styleable.CarrierText_allCaps, false);
97 } finally {
98 a.recycle();
99 }
Victoria Lease1d80e972013-11-01 16:34:03 -0700100 setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps));
Etan Cohen47051d82015-07-06 16:19:04 -0700101
102 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700103 }
104
Jason Monk9ff69bd2014-12-02 16:43:17 -0500105 protected void updateCarrierText() {
106 boolean allSimsMissing = true;
Etan Cohen47051d82015-07-06 16:19:04 -0700107 boolean anySimReadyAndInService = false;
Jason Monk9ff69bd2014-12-02 16:43:17 -0500108 CharSequence displayText = null;
109
110 List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
111 final int N = subs.size();
112 if (DEBUG) Log.d(TAG, "updateCarrierText(): " + N);
113 for (int i = 0; i < N; i++) {
Etan Cohen47051d82015-07-06 16:19:04 -0700114 int subId = subs.get(i).getSubscriptionId();
115 State simState = mKeyguardUpdateMonitor.getSimState(subId);
Jason Monk9ff69bd2014-12-02 16:43:17 -0500116 CharSequence carrierName = subs.get(i).getCarrierName();
117 CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName);
Etan Cohen47051d82015-07-06 16:19:04 -0700118 if (DEBUG) {
119 Log.d(TAG, "Handling (subId=" + subId + "): " + simState + " " + carrierName);
120 }
Jason Monk9ff69bd2014-12-02 16:43:17 -0500121 if (carrierTextForSimState != null) {
122 allSimsMissing = false;
123 displayText = concatenate(displayText, carrierTextForSimState);
124 }
Etan Cohen47051d82015-07-06 16:19:04 -0700125 if (simState == IccCardConstants.State.READY) {
126 ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId);
127 if (ss != null && ss.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
128 // hack for WFC (IWLAN) not turning off immediately once
129 // Wi-Fi is disassociated or disabled
130 if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
131 || (mWifiManager.isWifiEnabled()
132 && mWifiManager.getConnectionInfo() != null
133 && mWifiManager.getConnectionInfo().getBSSID() != null)) {
134 if (DEBUG) {
135 Log.d(TAG, "SIM ready and in service: subId=" + subId + ", ss=" + ss);
136 }
137 anySimReadyAndInService = true;
138 }
139 }
140 }
Jason Monk9ff69bd2014-12-02 16:43:17 -0500141 }
142 if (allSimsMissing) {
143 if (N != 0) {
144 // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
145 // This depends on mPlmn containing the text "Emergency calls only" when the radio
146 // has some connectivity. Otherwise, it should be null or empty and just show
147 // "No SIM card"
148 // Grab the first subscripton, because they all should contain the emergency text,
149 // described above.
150 displayText = makeCarrierStringOnEmergencyCapable(
151 getContext().getText(R.string.keyguard_missing_sim_message_short),
152 subs.get(0).getCarrierName());
153 } else {
154 // We don't have a SubscriptionInfo to get the emergency calls only from.
Jason Monkde3260b2015-02-24 08:55:26 -0500155 // Grab it from the old sticky broadcast if possible instead. We can use it
156 // here because no subscriptions are active, so we don't have
157 // to worry about MSIM clashing.
158 CharSequence text =
159 getContext().getText(com.android.internal.R.string.emergency_calls_only);
160 Intent i = getContext().registerReceiver(null,
161 new IntentFilter(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION));
162 if (i != null) {
163 String spn = "";
164 String plmn = "";
165 if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
166 spn = i.getStringExtra(TelephonyIntents.EXTRA_SPN);
167 }
168 if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
169 plmn = i.getStringExtra(TelephonyIntents.EXTRA_PLMN);
170 }
171 if (DEBUG) Log.d(TAG, "Getting plmn/spn sticky brdcst " + plmn + "/" + spn);
Sanket Padaweb8726b72015-04-01 14:02:16 -0700172 if (Objects.equals(plmn, spn)) {
173 text = plmn;
174 } else {
175 text = concatenate(plmn, spn);
176 }
Jason Monkde3260b2015-02-24 08:55:26 -0500177 }
Jason Monk9ff69bd2014-12-02 16:43:17 -0500178 displayText = makeCarrierStringOnEmergencyCapable(
Jason Monkde3260b2015-02-24 08:55:26 -0500179 getContext().getText(R.string.keyguard_missing_sim_message_short), text);
Jason Monk9ff69bd2014-12-02 16:43:17 -0500180 }
181 }
Etan Cohen47051d82015-07-06 16:19:04 -0700182
183 // APM (airplane mode) != no carrier state. There are carrier services
184 // (e.g. WFC = Wi-Fi calling) which may operate in APM.
185 if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) {
Jason Monk726fb282015-03-31 12:56:11 -0400186 displayText = getContext().getString(R.string.airplane_mode);
187 }
Jason Monk9ff69bd2014-12-02 16:43:17 -0500188 setText(displayText);
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700189 }
190
191 @Override
192 protected void onFinishInflate() {
193 super.onFinishInflate();
Jason Monk9ff69bd2014-12-02 16:43:17 -0500194 mSeparator = getResources().getString(
195 com.android.internal.R.string.kg_text_message_separator);
Jim Miller20daffd2013-10-07 14:59:53 -0700196 final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
197 setSelected(screenOn); // Allow marquee to work.
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700198 }
199
Jim Miller0928e012012-11-06 18:43:22 -0800200 @Override
201 protected void onAttachedToWindow() {
202 super.onAttachedToWindow();
Jason Monk83bc2aaf2014-12-05 10:16:24 -0500203 if (ConnectivityManager.from(mContext).isNetworkSupported(
204 ConnectivityManager.TYPE_MOBILE)) {
205 mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
206 mKeyguardUpdateMonitor.registerCallback(mCallback);
207 } else {
208 // Don't listen and clear out the text when the device isn't a phone.
209 mKeyguardUpdateMonitor = null;
210 setText("");
211 }
Jim Miller0928e012012-11-06 18:43:22 -0800212 }
213
214 @Override
215 protected void onDetachedFromWindow() {
216 super.onDetachedFromWindow();
Jason Monk83bc2aaf2014-12-05 10:16:24 -0500217 if (mKeyguardUpdateMonitor != null) {
218 mKeyguardUpdateMonitor.removeCallback(mCallback);
219 }
Jim Miller0928e012012-11-06 18:43:22 -0800220 }
221
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700222 /**
223 * Top-level function for creating carrier text. Makes text based on simState, PLMN
224 * and SPN as well as device capabilities, such as being emergency call capable.
225 *
226 * @param simState
Jason Monk9ff69bd2014-12-02 16:43:17 -0500227 * @param text
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700228 * @param spn
Jason Monk9ff69bd2014-12-02 16:43:17 -0500229 * @return Carrier text if not in missing state, null otherwise.
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700230 */
231 private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
Jason Monk9ff69bd2014-12-02 16:43:17 -0500232 CharSequence text) {
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700233 CharSequence carrierText = null;
234 StatusMode status = getStatusForIccState(simState);
235 switch (status) {
236 case Normal:
Jason Monk9ff69bd2014-12-02 16:43:17 -0500237 carrierText = text;
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700238 break;
239
Jim Miller109f1fd2012-09-19 20:44:16 -0700240 case SimNotReady:
Jason Monk9ff69bd2014-12-02 16:43:17 -0500241 // Null is reserved for denoting missing, in this case we have nothing to display.
242 carrierText = ""; // nothing to display yet.
Jim Miller109f1fd2012-09-19 20:44:16 -0700243 break;
244
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700245 case NetworkLocked:
246 carrierText = makeCarrierStringOnEmergencyCapable(
Jason Monk9ff69bd2014-12-02 16:43:17 -0500247 mContext.getText(R.string.keyguard_network_locked_message), text);
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700248 break;
249
250 case SimMissing:
Jason Monk9ff69bd2014-12-02 16:43:17 -0500251 carrierText = null;
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700252 break;
253
254 case SimPermDisabled:
255 carrierText = getContext().getText(
Jim Miller5ecd8112013-01-09 18:50:26 -0800256 R.string.keyguard_permanent_disabled_sim_message_short);
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700257 break;
258
259 case SimMissingLocked:
Jason Monk9ff69bd2014-12-02 16:43:17 -0500260 carrierText = null;
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700261 break;
262
263 case SimLocked:
264 carrierText = makeCarrierStringOnEmergencyCapable(
Jim Miller5ecd8112013-01-09 18:50:26 -0800265 getContext().getText(R.string.keyguard_sim_locked_message),
Jason Monk9ff69bd2014-12-02 16:43:17 -0500266 text);
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700267 break;
268
269 case SimPukLocked:
270 carrierText = makeCarrierStringOnEmergencyCapable(
Jim Miller5ecd8112013-01-09 18:50:26 -0800271 getContext().getText(R.string.keyguard_sim_puk_locked_message),
Jason Monk9ff69bd2014-12-02 16:43:17 -0500272 text);
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700273 break;
274 }
275
276 return carrierText;
277 }
278
279 /*
280 * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
281 */
282 private CharSequence makeCarrierStringOnEmergencyCapable(
283 CharSequence simMessage, CharSequence emergencyCallMessage) {
Adrian Roosc2e01682015-01-15 23:20:20 +0100284 if (mIsEmergencyCallCapable) {
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700285 return concatenate(simMessage, emergencyCallMessage);
286 }
287 return simMessage;
288 }
289
290 /**
291 * Determine the current status of the lock screen given the SIM state and other stuff.
292 */
293 private StatusMode getStatusForIccState(IccCardConstants.State simState) {
294 // Since reading the SIM may take a while, we assume it is present until told otherwise.
295 if (simState == null) {
296 return StatusMode.Normal;
297 }
298
299 final boolean missingAndNotProvisioned =
300 !KeyguardUpdateMonitor.getInstance(mContext).isDeviceProvisioned()
301 && (simState == IccCardConstants.State.ABSENT ||
302 simState == IccCardConstants.State.PERM_DISABLED);
303
304 // Assume we're NETWORK_LOCKED if not provisioned
305 simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
306 switch (simState) {
307 case ABSENT:
308 return StatusMode.SimMissing;
309 case NETWORK_LOCKED:
310 return StatusMode.SimMissingLocked;
311 case NOT_READY:
Jim Miller109f1fd2012-09-19 20:44:16 -0700312 return StatusMode.SimNotReady;
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700313 case PIN_REQUIRED:
314 return StatusMode.SimLocked;
315 case PUK_REQUIRED:
316 return StatusMode.SimPukLocked;
317 case READY:
318 return StatusMode.Normal;
319 case PERM_DISABLED:
320 return StatusMode.SimPermDisabled;
321 case UNKNOWN:
322 return StatusMode.SimMissing;
323 }
324 return StatusMode.SimMissing;
325 }
326
327 private static CharSequence concatenate(CharSequence plmn, CharSequence spn) {
328 final boolean plmnValid = !TextUtils.isEmpty(plmn);
329 final boolean spnValid = !TextUtils.isEmpty(spn);
330 if (plmnValid && spnValid) {
Sanket Padaweb8726b72015-04-01 14:02:16 -0700331 return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString();
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700332 } else if (plmnValid) {
333 return plmn;
334 } else if (spnValid) {
335 return spn;
336 } else {
337 return "";
338 }
339 }
340
341 private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
342 String plmn, String spn) {
343 int carrierHelpTextId = 0;
344 StatusMode status = getStatusForIccState(simState);
345 switch (status) {
346 case NetworkLocked:
Jim Miller5ecd8112013-01-09 18:50:26 -0800347 carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled;
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700348 break;
349
350 case SimMissing:
Jim Miller5ecd8112013-01-09 18:50:26 -0800351 carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long;
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700352 break;
353
354 case SimPermDisabled:
Jim Miller5ecd8112013-01-09 18:50:26 -0800355 carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions;
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700356 break;
357
358 case SimMissingLocked:
Jim Miller5ecd8112013-01-09 18:50:26 -0800359 carrierHelpTextId = R.string.keyguard_missing_sim_instructions;
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700360 break;
361
362 case Normal:
363 case SimLocked:
364 case SimPukLocked:
365 break;
366 }
367
368 return mContext.getText(carrierHelpTextId);
369 }
Victoria Lease1d80e972013-11-01 16:34:03 -0700370
371 private class CarrierTextTransformationMethod extends SingleLineTransformationMethod {
372 private final Locale mLocale;
373 private final boolean mAllCaps;
374
375 public CarrierTextTransformationMethod(Context context, boolean allCaps) {
376 mLocale = context.getResources().getConfiguration().locale;
377 mAllCaps = allCaps;
378 }
379
380 @Override
381 public CharSequence getTransformation(CharSequence source, View view) {
382 source = super.getTransformation(source, view);
383
384 if (mAllCaps && source != null) {
385 source = source.toString().toUpperCase(mLocale);
386 }
387
388 return source;
389 }
390 }
Jim Millerf9cb7ba2012-09-17 22:31:56 -0700391}