blob: 39df5a2f375d9c22ddcaec2f3463b0f72e7eebc4 [file] [log] [blame]
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001/*
2 * Copyright (C) 2008 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 Millerdcb3d842012-08-23 19:18:12 -070017package com.android.internal.policy.impl.keyguard;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080018
Jim Millerb0304762012-03-13 20:01:25 -070019import android.app.admin.DevicePolicyManager;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080020import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080024import android.database.ContentObserver;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080025import static android.os.BatteryManager.BATTERY_STATUS_FULL;
26import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
Jim Miller16464b82011-10-20 21:10:13 -070027import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
28import static android.os.BatteryManager.EXTRA_STATUS;
29import static android.os.BatteryManager.EXTRA_PLUGGED;
30import static android.os.BatteryManager.EXTRA_LEVEL;
31import static android.os.BatteryManager.EXTRA_HEALTH;
Jim Miller47088bb2009-11-24 00:40:16 -080032import android.media.AudioManager;
Jim Miller79a444a2011-02-15 15:02:11 -080033import android.os.BatteryManager;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080034import android.os.Handler;
35import android.os.Message;
36import android.provider.Settings;
Dianne Hackbornb7e787f2009-05-07 15:55:42 -070037
Wink Savillea639b312012-07-10 12:37:54 -070038import com.android.internal.telephony.IccCardConstants;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080039import com.android.internal.telephony.TelephonyIntents;
Jim Millerc23024d2010-02-24 15:37:00 -080040
41import android.telephony.TelephonyManager;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080042import android.util.Log;
43import com.android.internal.R;
44import com.google.android.collect.Lists;
45
Jim Millerdcb3d842012-08-23 19:18:12 -070046import java.lang.ref.WeakReference;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080047import java.util.ArrayList;
48
49/**
50 * Watches for updates that may be interesting to the keyguard, and provides
51 * the up to date information as well as a registration for callbacks that care
52 * to be updated.
53 *
54 * Note: under time crunch, this has been extended to include some stuff that
55 * doesn't really belong here. see {@link #handleBatteryUpdate} where it shutdowns
Jim Miller258341c2012-08-30 16:50:10 -070056 * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()}
57 * and {@link #clearFailedUnlockAttempts()}. Maybe we should rename this 'KeyguardContext'...
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080058 */
59public class KeyguardUpdateMonitor {
60
Jim Millerbbf1a742012-07-17 18:30:30 -070061 private static final String TAG = "KeyguardUpdateMonitor";
62 private static final boolean DEBUG = false;
63 private static final boolean DEBUG_SIM_STATES = DEBUG || false;
Uriel Rodriguezaa249062012-06-13 17:30:13 -040064 private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3;
Jim Millerbbf1a742012-07-17 18:30:30 -070065 private static final int LOW_BATTERY_THRESHOLD = 20;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080066
Jim Millerbbf1a742012-07-17 18:30:30 -070067 // Callback messages
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080068 private static final int MSG_TIME_UPDATE = 301;
69 private static final int MSG_BATTERY_UPDATE = 302;
70 private static final int MSG_CARRIER_INFO_UPDATE = 303;
71 private static final int MSG_SIM_STATE_CHANGE = 304;
Jim Miller47088bb2009-11-24 00:40:16 -080072 private static final int MSG_RINGER_MODE_CHANGED = 305;
Jim Millerc23024d2010-02-24 15:37:00 -080073 private static final int MSG_PHONE_STATE_CHANGED = 306;
Jeff Sharkey054340d2011-09-01 22:28:03 -070074 private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307;
Nick Pelly24d7b5f2011-10-11 12:51:09 -070075 private static final int MSG_DEVICE_PROVISIONED = 308;
Jim Millerb0304762012-03-13 20:01:25 -070076 protected static final int MSG_DPM_STATE_CHANGED = 309;
Jim Millerbbf1a742012-07-17 18:30:30 -070077 protected static final int MSG_USER_SWITCHED = 310;
78 protected static final int MSG_USER_REMOVED = 311;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080079
Jim Millerdcb3d842012-08-23 19:18:12 -070080 private static KeyguardUpdateMonitor sInstance;
81
Jim Millerbbf1a742012-07-17 18:30:30 -070082 private final Context mContext;
83
84 // Telephony state
85 private IccCardConstants.State mSimState = IccCardConstants.State.READY;
86 private CharSequence mTelephonyPlmn;
87 private CharSequence mTelephonySpn;
88 private int mRingMode;
89 private int mPhoneState;
90
Jim Millerdcb3d842012-08-23 19:18:12 -070091 // Device provisioning state
Jim Millerbbf1a742012-07-17 18:30:30 -070092 private boolean mDeviceProvisioned;
93
Jim Millerdcb3d842012-08-23 19:18:12 -070094 // Battery status
Jim Millerbbf1a742012-07-17 18:30:30 -070095 private BatteryStatus mBatteryStatus;
96
Jim Millerdcb3d842012-08-23 19:18:12 -070097 // Password attempts
Jim Millerbbf1a742012-07-17 18:30:30 -070098 private int mFailedAttempts = 0;
99 private int mFailedBiometricUnlockAttempts = 0;
100
101 private boolean mClockVisible;
102
Jim Millerdcb3d842012-08-23 19:18:12 -0700103 private ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
104 mCallbacks = Lists.newArrayList();
Jim Millerbbf1a742012-07-17 18:30:30 -0700105 private ContentObserver mContentObserver;
106
107 private final Handler mHandler = new Handler() {
108 @Override
109 public void handleMessage(Message msg) {
110 switch (msg.what) {
111 case MSG_TIME_UPDATE:
112 handleTimeUpdate();
113 break;
114 case MSG_BATTERY_UPDATE:
115 handleBatteryUpdate((BatteryStatus) msg.obj);
116 break;
117 case MSG_CARRIER_INFO_UPDATE:
118 handleCarrierInfoUpdate();
119 break;
120 case MSG_SIM_STATE_CHANGE:
121 handleSimStateChange((SimArgs) msg.obj);
122 break;
123 case MSG_RINGER_MODE_CHANGED:
124 handleRingerModeChange(msg.arg1);
125 break;
126 case MSG_PHONE_STATE_CHANGED:
127 handlePhoneStateChanged((String)msg.obj);
128 break;
129 case MSG_CLOCK_VISIBILITY_CHANGED:
130 handleClockVisibilityChanged();
131 break;
132 case MSG_DEVICE_PROVISIONED:
133 handleDeviceProvisioned();
134 break;
135 case MSG_DPM_STATE_CHANGED:
136 handleDevicePolicyManagerStateChanged();
137 break;
138 case MSG_USER_SWITCHED:
139 handleUserSwitched(msg.arg1);
140 break;
141 case MSG_USER_REMOVED:
142 handleUserRemoved(msg.arg1);
143 break;
144 }
145 }
146 };
147
148 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
149
150 public void onReceive(Context context, Intent intent) {
151 final String action = intent.getAction();
152 if (DEBUG) Log.d(TAG, "received broadcast " + action);
153
154 if (Intent.ACTION_TIME_TICK.equals(action)
155 || Intent.ACTION_TIME_CHANGED.equals(action)
156 || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
157 mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE));
158 } else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
159 mTelephonyPlmn = getTelephonyPlmnFrom(intent);
160 mTelephonySpn = getTelephonySpnFrom(intent);
161 mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE));
162 } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
163 final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
164 final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
165 final int level = intent.getIntExtra(EXTRA_LEVEL, 0);
166 final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
167 final Message msg = mHandler.obtainMessage(
168 MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health));
169 mHandler.sendMessage(msg);
170 } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
171 if (DEBUG_SIM_STATES) {
172 Log.v(TAG, "action " + action + " state" +
173 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE));
174 }
175 mHandler.sendMessage(mHandler.obtainMessage(
176 MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent)));
177 } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
178 mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED,
179 intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0));
180 } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
181 String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
182 mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
183 } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
184 .equals(action)) {
185 mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED));
186 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
187 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
Jim Millerdcb3d842012-08-23 19:18:12 -0700188 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
Jim Millerbbf1a742012-07-17 18:30:30 -0700189 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
190 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
Jim Millerdcb3d842012-08-23 19:18:12 -0700191 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
Jim Millerbbf1a742012-07-17 18:30:30 -0700192 }
193 }
194 };
Jim Miller2de5ee82012-06-14 22:22:50 -0700195
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800196 /**
Jim Miller47088bb2009-11-24 00:40:16 -0800197 * When we receive a
198 * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
Wink Saville37c124c2009-04-02 01:37:02 -0700199 * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800200 * we need a single object to pass to the handler. This class helps decode
Jim Miller47088bb2009-11-24 00:40:16 -0800201 * the intent and provide a {@link SimCard.State} result.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800202 */
203 private static class SimArgs {
Wink Savillea639b312012-07-10 12:37:54 -0700204 public final IccCardConstants.State simState;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800205
Wink Savillea639b312012-07-10 12:37:54 -0700206 SimArgs(IccCardConstants.State state) {
Jim Miller90d5d462011-11-17 16:57:01 -0800207 simState = state;
208 }
209
210 static SimArgs fromIntent(Intent intent) {
Wink Savillea639b312012-07-10 12:37:54 -0700211 IccCardConstants.State state;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800212 if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
213 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
214 }
Wink Savillea639b312012-07-10 12:37:54 -0700215 String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
216 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
John Wangb0b24b32011-06-10 17:23:51 -0700217 final String absentReason = intent
Wink Savillea639b312012-07-10 12:37:54 -0700218 .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
John Wangb0b24b32011-06-10 17:23:51 -0700219
Wink Savillea639b312012-07-10 12:37:54 -0700220 if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
John Wangb0b24b32011-06-10 17:23:51 -0700221 absentReason)) {
Wink Savillea639b312012-07-10 12:37:54 -0700222 state = IccCardConstants.State.PERM_DISABLED;
John Wangb0b24b32011-06-10 17:23:51 -0700223 } else {
Wink Savillea639b312012-07-10 12:37:54 -0700224 state = IccCardConstants.State.ABSENT;
John Wangb0b24b32011-06-10 17:23:51 -0700225 }
Wink Savillea639b312012-07-10 12:37:54 -0700226 } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
227 state = IccCardConstants.State.READY;
228 } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800229 final String lockedReason = intent
Wink Savillea639b312012-07-10 12:37:54 -0700230 .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
231 if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
232 state = IccCardConstants.State.PIN_REQUIRED;
233 } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
234 state = IccCardConstants.State.PUK_REQUIRED;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800235 } else {
Wink Savillea639b312012-07-10 12:37:54 -0700236 state = IccCardConstants.State.UNKNOWN;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800237 }
Wink Savillea639b312012-07-10 12:37:54 -0700238 } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
239 state = IccCardConstants.State.NETWORK_LOCKED;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800240 } else {
Wink Savillea639b312012-07-10 12:37:54 -0700241 state = IccCardConstants.State.UNKNOWN;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800242 }
Jim Miller90d5d462011-11-17 16:57:01 -0800243 return new SimArgs(state);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800244 }
245
246 public String toString() {
247 return simState.toString();
248 }
249 }
250
Jim Millerbbf1a742012-07-17 18:30:30 -0700251 /* package */ static class BatteryStatus {
Jim Miller16464b82011-10-20 21:10:13 -0700252 public final int status;
253 public final int level;
254 public final int plugged;
255 public final int health;
256 public BatteryStatus(int status, int level, int plugged, int health) {
257 this.status = status;
258 this.level = level;
259 this.plugged = plugged;
260 this.health = health;
261 }
262
Jim Millerbbf1a742012-07-17 18:30:30 -0700263 /**
264 * Determine whether the device is plugged in (USB or power).
265 * @return true if the device is plugged in.
266 */
267 boolean isPluggedIn() {
268 return plugged == BatteryManager.BATTERY_PLUGGED_AC
Jim Millerdcb3d842012-08-23 19:18:12 -0700269 || plugged == BatteryManager.BATTERY_PLUGGED_USB;
Jim Millerbbf1a742012-07-17 18:30:30 -0700270 }
271
272 /**
273 * Whether or not the device is charged. Note that some devices never return 100% for
274 * battery level, so this allows either battery level or status to determine if the
275 * battery is charged.
276 * @return true if the device is charged
277 */
278 public boolean isCharged() {
279 return status == BATTERY_STATUS_FULL || level >= 100;
280 }
281
282 /**
283 * Whether battery is low and needs to be charged.
284 * @return true if battery is low
285 */
286 public boolean isBatteryLow() {
287 return level < LOW_BATTERY_THRESHOLD;
288 }
289
Jim Miller16464b82011-10-20 21:10:13 -0700290 }
291
Jim Millerdcb3d842012-08-23 19:18:12 -0700292 public static KeyguardUpdateMonitor getInstance(Context context) {
293 if (sInstance == null) {
294 sInstance = new KeyguardUpdateMonitor(context);
295 }
296 return sInstance;
297 }
298
299 private KeyguardUpdateMonitor(Context context) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800300 mContext = context;
Jim Miller47088bb2009-11-24 00:40:16 -0800301
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800302 mDeviceProvisioned = Settings.Secure.getInt(
303 mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
Jim Miller47088bb2009-11-24 00:40:16 -0800304
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800305 // Since device can't be un-provisioned, we only need to register a content observer
306 // to update mDeviceProvisioned when we are...
307 if (!mDeviceProvisioned) {
Jim Millerbbf1a742012-07-17 18:30:30 -0700308 watchForDeviceProvisioning();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800309 }
Jim Miller47088bb2009-11-24 00:40:16 -0800310
Jim Millerbbf1a742012-07-17 18:30:30 -0700311 // Take a guess at initial SIM state, battery status and PLMN until we get an update
312 mSimState = IccCardConstants.State.NOT_READY;
Jim Miller16464b82011-10-20 21:10:13 -0700313 mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800314 mTelephonyPlmn = getDefaultPlmn();
315
Jim Millerbbf1a742012-07-17 18:30:30 -0700316 // Watch for interesting updates
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800317 final IntentFilter filter = new IntentFilter();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800318 filter.addAction(Intent.ACTION_TIME_TICK);
319 filter.addAction(Intent.ACTION_TIME_CHANGED);
320 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
321 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
322 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
Jim Millerc23024d2010-02-24 15:37:00 -0800323 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Wink Savillea639b312012-07-10 12:37:54 -0700324 filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
Jim Miller47088bb2009-11-24 00:40:16 -0800325 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
Jim Millerb0304762012-03-13 20:01:25 -0700326 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700327 filter.addAction(Intent.ACTION_USER_SWITCHED);
328 filter.addAction(Intent.ACTION_USER_REMOVED);
Jim Millerbbf1a742012-07-17 18:30:30 -0700329 context.registerReceiver(mBroadcastReceiver, filter);
330 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800331
Jim Millerbbf1a742012-07-17 18:30:30 -0700332 private void watchForDeviceProvisioning() {
333 mContentObserver = new ContentObserver(mHandler) {
334 @Override
335 public void onChange(boolean selfChange) {
336 super.onChange(selfChange);
337 mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(),
338 Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
339 if (mDeviceProvisioned) {
340 mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800341 }
Jim Millerbbf1a742012-07-17 18:30:30 -0700342 if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800343 }
Jim Millerbbf1a742012-07-17 18:30:30 -0700344 };
345
346 mContext.getContentResolver().registerContentObserver(
347 Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED),
348 false, mContentObserver);
349
350 // prevent a race condition between where we check the flag and where we register the
351 // observer by grabbing the value once again...
352 boolean provisioned = Settings.Secure.getInt(mContext.getContentResolver(),
353 Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
354 if (provisioned != mDeviceProvisioned) {
355 mDeviceProvisioned = provisioned;
356 if (mDeviceProvisioned) {
357 mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
358 }
359 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800360 }
361
Jim Millerbbf1a742012-07-17 18:30:30 -0700362 /**
363 * Handle {@link #MSG_DPM_STATE_CHANGED}
364 */
Jim Millerb0304762012-03-13 20:01:25 -0700365 protected void handleDevicePolicyManagerStateChanged() {
Jim Millerdcb3d842012-08-23 19:18:12 -0700366 for (int i = mCallbacks.size() - 1; i >= 0; i--) {
367 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
368 if (cb != null) {
369 cb.onDevicePolicyManagerStateChanged();
370 }
Jim Millerb0304762012-03-13 20:01:25 -0700371 }
372 }
373
Jim Millerbbf1a742012-07-17 18:30:30 -0700374 /**
375 * Handle {@link #MSG_USER_SWITCHED}
376 */
377 protected void handleUserSwitched(int userId) {
378 for (int i = 0; i < mCallbacks.size(); i++) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700379 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
380 if (cb != null) {
381 cb.onUserSwitched(userId);
382 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700383 }
384 }
385
Jim Millerbbf1a742012-07-17 18:30:30 -0700386 /**
387 * Handle {@link #MSG_USER_SWITCHED}
388 */
389 protected void handleUserRemoved(int userId) {
390 for (int i = 0; i < mCallbacks.size(); i++) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700391 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
392 if (cb != null) {
393 cb.onUserRemoved(userId);
394 }
Jim Millerbbf1a742012-07-17 18:30:30 -0700395 }
396 }
397
398 /**
399 * Handle {@link #MSG_DEVICE_PROVISIONED}
400 */
Nick Pelly24d7b5f2011-10-11 12:51:09 -0700401 protected void handleDeviceProvisioned() {
Jim Millerbbf1a742012-07-17 18:30:30 -0700402 for (int i = 0; i < mCallbacks.size(); i++) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700403 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
404 if (cb != null) {
405 cb.onDeviceProvisioned();
406 }
Nick Pelly24d7b5f2011-10-11 12:51:09 -0700407 }
408 if (mContentObserver != null) {
409 // We don't need the observer anymore...
410 mContext.getContentResolver().unregisterContentObserver(mContentObserver);
411 mContentObserver = null;
412 }
413 }
414
Jim Millerbbf1a742012-07-17 18:30:30 -0700415 /**
416 * Handle {@link #MSG_PHONE_STATE_CHANGED}
417 */
Jim Millerc23024d2010-02-24 15:37:00 -0800418 protected void handlePhoneStateChanged(String newState) {
419 if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")");
Jim Miller3f5f83b2011-09-26 15:17:05 -0700420 if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) {
421 mPhoneState = TelephonyManager.CALL_STATE_IDLE;
422 } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) {
423 mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK;
424 } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) {
425 mPhoneState = TelephonyManager.CALL_STATE_RINGING;
426 }
Jim Millerbbf1a742012-07-17 18:30:30 -0700427 for (int i = 0; i < mCallbacks.size(); i++) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700428 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
429 if (cb != null) {
430 cb.onPhoneStateChanged(mPhoneState);
431 }
Jim Millerc23024d2010-02-24 15:37:00 -0800432 }
433 }
434
Jim Millerbbf1a742012-07-17 18:30:30 -0700435 /**
436 * Handle {@link #MSG_RINGER_MODE_CHANGED}
437 */
Jim Miller47088bb2009-11-24 00:40:16 -0800438 protected void handleRingerModeChange(int mode) {
439 if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")");
Jim Miller3f5f83b2011-09-26 15:17:05 -0700440 mRingMode = mode;
Jim Millerbbf1a742012-07-17 18:30:30 -0700441 for (int i = 0; i < mCallbacks.size(); i++) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700442 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
443 if (cb != null) {
444 cb.onRingerModeChanged(mode);
445 }
Jim Miller47088bb2009-11-24 00:40:16 -0800446 }
447 }
448
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800449 /**
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800450 * Handle {@link #MSG_TIME_UPDATE}
451 */
452 private void handleTimeUpdate() {
453 if (DEBUG) Log.d(TAG, "handleTimeUpdate");
Jim Millerbbf1a742012-07-17 18:30:30 -0700454 for (int i = 0; i < mCallbacks.size(); i++) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700455 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
456 if (cb != null) {
457 cb.onTimeChanged();
458 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800459 }
460 }
461
462 /**
463 * Handle {@link #MSG_BATTERY_UPDATE}
464 */
Jim Millerbbf1a742012-07-17 18:30:30 -0700465 private void handleBatteryUpdate(BatteryStatus status) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800466 if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
Jim Millerbbf1a742012-07-17 18:30:30 -0700467 final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);
468 mBatteryStatus = status;
Jim Miller16464b82011-10-20 21:10:13 -0700469 if (batteryUpdateInteresting) {
Jim Millerbbf1a742012-07-17 18:30:30 -0700470 for (int i = 0; i < mCallbacks.size(); i++) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700471 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
472 if (cb != null) {
473 cb.onRefreshBatteryInfo(status);
474 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800475 }
476 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800477 }
478
479 /**
480 * Handle {@link #MSG_CARRIER_INFO_UPDATE}
481 */
482 private void handleCarrierInfoUpdate() {
483 if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn
484 + ", spn = " + mTelephonySpn);
485
Jim Millerbbf1a742012-07-17 18:30:30 -0700486 for (int i = 0; i < mCallbacks.size(); i++) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700487 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
488 if (cb != null) {
489 cb.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
490 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800491 }
492 }
493
494 /**
495 * Handle {@link #MSG_SIM_STATE_CHANGE}
496 */
497 private void handleSimStateChange(SimArgs simArgs) {
Wink Savillea639b312012-07-10 12:37:54 -0700498 final IccCardConstants.State state = simArgs.simState;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800499
500 if (DEBUG) {
501 Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " "
502 + "state resolved to " + state.toString());
503 }
504
Wink Savillea639b312012-07-10 12:37:54 -0700505 if (state != IccCardConstants.State.UNKNOWN && state != mSimState) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800506 mSimState = state;
Jim Millerbbf1a742012-07-17 18:30:30 -0700507 for (int i = 0; i < mCallbacks.size(); i++) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700508 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
509 if (cb != null) {
510 cb.onSimStateChanged(state);
511 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800512 }
513 }
514 }
515
Jim Millerbbf1a742012-07-17 18:30:30 -0700516 /**
517 * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED}
518 */
Jeff Sharkey054340d2011-09-01 22:28:03 -0700519 private void handleClockVisibilityChanged() {
520 if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()");
Jim Millerbbf1a742012-07-17 18:30:30 -0700521 for (int i = 0; i < mCallbacks.size(); i++) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700522 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
523 if (cb != null) {
524 cb.onClockVisibilityChanged();
525 }
Jeff Sharkey054340d2011-09-01 22:28:03 -0700526 }
527 }
528
Jim Miller16464b82011-10-20 21:10:13 -0700529 private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
Jim Millerbbf1a742012-07-17 18:30:30 -0700530 final boolean nowPluggedIn = current.isPluggedIn();
531 final boolean wasPluggedIn = old.isPluggedIn();
Jim Miller79a444a2011-02-15 15:02:11 -0800532 final boolean stateChangedWhilePluggedIn =
Jim Miller16464b82011-10-20 21:10:13 -0700533 wasPluggedIn == true && nowPluggedIn == true
534 && (old.status != current.status);
535
536 // change in plug state is always interesting
537 if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800538 return true;
539 }
540
541 // change in battery level while plugged in
Jim Miller16464b82011-10-20 21:10:13 -0700542 if (nowPluggedIn && old.level != current.level) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800543 return true;
544 }
545
Jim Miller16464b82011-10-20 21:10:13 -0700546 // change where battery needs charging
Jim Millerbbf1a742012-07-17 18:30:30 -0700547 if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) {
Jim Miller16464b82011-10-20 21:10:13 -0700548 return true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800549 }
550 return false;
551 }
552
553 /**
Wink Savillea639b312012-07-10 12:37:54 -0700554 * @param intent The intent with action {@link TelephonyIntents#SPN_STRINGS_UPDATED_ACTION}
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800555 * @return The string to use for the plmn, or null if it should not be shown.
556 */
557 private CharSequence getTelephonyPlmnFrom(Intent intent) {
Wink Savillea639b312012-07-10 12:37:54 -0700558 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
559 final String plmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN);
Jim Millerbbf1a742012-07-17 18:30:30 -0700560 return (plmn != null) ? plmn : getDefaultPlmn();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800561 }
562 return null;
563 }
564
565 /**
566 * @return The default plmn (no service)
567 */
568 private CharSequence getDefaultPlmn() {
Jim Millerbbf1a742012-07-17 18:30:30 -0700569 return mContext.getResources().getText(R.string.lockscreen_carrier_default);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800570 }
571
572 /**
573 * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
574 * @return The string to use for the plmn, or null if it should not be shown.
575 */
576 private CharSequence getTelephonySpnFrom(Intent intent) {
Wink Savillea639b312012-07-10 12:37:54 -0700577 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
578 final String spn = intent.getStringExtra(TelephonyIntents.EXTRA_SPN);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800579 if (spn != null) {
580 return spn;
581 }
582 }
583 return null;
584 }
585
586 /**
Jim Millerbbf1a742012-07-17 18:30:30 -0700587 * Remove the given observer's callback.
588 *
589 * @param observer The observer to remove
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800590 */
591 public void removeCallback(Object observer) {
Jim Millerbbf1a742012-07-17 18:30:30 -0700592 mCallbacks.remove(observer);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800593 }
594
595 /**
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800596 * Register to receive notifications about general keyguard information
597 * (see {@link InfoCallback}.
598 * @param callback The callback.
599 */
Jim Millerbbf1a742012-07-17 18:30:30 -0700600 public void registerCallback(KeyguardUpdateMonitorCallback callback) {
601 if (!mCallbacks.contains(callback)) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700602 mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback));
Jim Miller3f5f83b2011-09-26 15:17:05 -0700603 // Notify listener of the current state
Jim Millerbbf1a742012-07-17 18:30:30 -0700604 callback.onRefreshBatteryInfo(mBatteryStatus);
Jim Miller3f5f83b2011-09-26 15:17:05 -0700605 callback.onTimeChanged();
606 callback.onRingerModeChanged(mRingMode);
607 callback.onPhoneStateChanged(mPhoneState);
John Wang61e15952011-09-21 10:54:35 -0700608 callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
Jim Miller305c78c2011-10-16 14:54:38 -0700609 callback.onClockVisibilityChanged();
John Wang61e15952011-09-21 10:54:35 -0700610 callback.onSimStateChanged(mSimState);
Jim Miller42b432d2010-02-12 18:56:03 -0800611 } else {
Jim Millerbbf1a742012-07-17 18:30:30 -0700612 if (DEBUG) Log.e(TAG, "Object tried to add another callback",
613 new Exception("Called by"));
Jim Miller42b432d2010-02-12 18:56:03 -0800614 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700615
616 // Clean up any unused references
617 for (int i = mCallbacks.size() - 1; i >= 0; i--) {
618 if (mCallbacks.get(i).get() == null) {
619 mCallbacks.remove(i);
620 }
621 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800622 }
623
Jeff Sharkey054340d2011-09-01 22:28:03 -0700624 public void reportClockVisible(boolean visible) {
625 mClockVisible = visible;
626 mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
627 }
628
Wink Savillea639b312012-07-10 12:37:54 -0700629 public IccCardConstants.State getSimState() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800630 return mSimState;
631 }
632
633 /**
Jim Miller90d5d462011-11-17 16:57:01 -0800634 * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800635 * have the information earlier than waiting for the intent
636 * broadcast from the telephony code.
Jim Miller90d5d462011-11-17 16:57:01 -0800637 *
638 * NOTE: Because handleSimStateChange() invokes callbacks immediately without going
639 * through mHandler, this *must* be called from the UI thread.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800640 */
John Wang0f7b3f82011-05-31 11:20:55 -0700641 public void reportSimUnlocked() {
Wink Savillea639b312012-07-10 12:37:54 -0700642 handleSimStateChange(new SimArgs(IccCardConstants.State.READY));
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800643 }
644
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800645 public CharSequence getTelephonyPlmn() {
646 return mTelephonyPlmn;
647 }
648
649 public CharSequence getTelephonySpn() {
650 return mTelephonySpn;
651 }
652
653 /**
654 * @return Whether the device is provisioned (whether they have gone through
655 * the setup wizard)
656 */
657 public boolean isDeviceProvisioned() {
658 return mDeviceProvisioned;
659 }
660
Jim Miller258341c2012-08-30 16:50:10 -0700661 public int getFailedUnlockAttempts() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800662 return mFailedAttempts;
663 }
664
Jim Miller258341c2012-08-30 16:50:10 -0700665 public void clearFailedUnlockAttempts() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800666 mFailedAttempts = 0;
Brian Colonnaea8441e2012-04-25 17:51:49 -0400667 mFailedBiometricUnlockAttempts = 0;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800668 }
669
Jim Miller258341c2012-08-30 16:50:10 -0700670 public void reportFailedUnlockAttempt() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800671 mFailedAttempts++;
672 }
Jim Miller1c188282011-08-08 22:27:58 -0700673
Jeff Sharkey054340d2011-09-01 22:28:03 -0700674 public boolean isClockVisible() {
675 return mClockVisible;
676 }
677
Brian Colonna267cb2b2011-09-26 13:52:25 -0400678 public int getPhoneState() {
679 return mPhoneState;
680 }
Steven Rossb9430d22011-11-23 07:54:09 -0500681
Brian Colonnaea8441e2012-04-25 17:51:49 -0400682 public void reportFailedBiometricUnlockAttempt() {
683 mFailedBiometricUnlockAttempts++;
Steven Rossb9430d22011-11-23 07:54:09 -0500684 }
685
Brian Colonnaea8441e2012-04-25 17:51:49 -0400686 public boolean getMaxBiometricUnlockAttemptsReached() {
687 return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP;
Steven Rossb9430d22011-11-23 07:54:09 -0500688 }
Jim Millerb0304762012-03-13 20:01:25 -0700689
690 public boolean isSimLocked() {
Jim Millerdcb3d842012-08-23 19:18:12 -0700691 return isSimLocked(mSimState);
692 }
693
694 public static boolean isSimLocked(IccCardConstants.State state) {
695 return state == IccCardConstants.State.PIN_REQUIRED
696 || state == IccCardConstants.State.PUK_REQUIRED
697 || state == IccCardConstants.State.PERM_DISABLED;
698 }
699
700 public boolean isSimPinSecure() {
701 return isSimPinSecure(mSimState);
702 }
703
704 public static boolean isSimPinSecure(IccCardConstants.State state) {
705 final IccCardConstants.State simState = state;
706 return (simState == IccCardConstants.State.PIN_REQUIRED
707 || simState == IccCardConstants.State.PUK_REQUIRED
708 || simState == IccCardConstants.State.PERM_DISABLED);
Jim Millerb0304762012-03-13 20:01:25 -0700709 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800710}