KeyguardUpdateMonitor.java revision 5737534abab477cf32b4dd0aa7a72f70ede0502c
1/* 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 17package com.android.internal.policy.impl.keyguard; 18 19import android.app.admin.DevicePolicyManager; 20import android.content.BroadcastReceiver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.database.ContentObserver; 25import static android.os.BatteryManager.BATTERY_STATUS_FULL; 26import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; 27import 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; 32import android.media.AudioManager; 33import android.os.BatteryManager; 34import android.os.Handler; 35import android.os.Message; 36import android.provider.Settings; 37 38import com.android.internal.telephony.IccCardConstants; 39import com.android.internal.telephony.TelephonyIntents; 40 41import android.telephony.TelephonyManager; 42import android.util.Log; 43import com.android.internal.R; 44import com.google.android.collect.Lists; 45 46import java.lang.ref.WeakReference; 47import 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 56 * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()} 57 * and {@link #clearFailedUnlockAttempts()}. Maybe we should rename this 'KeyguardContext'... 58 */ 59public class KeyguardUpdateMonitor { 60 61 private static final String TAG = "KeyguardUpdateMonitor"; 62 private static final boolean DEBUG = false; 63 private static final boolean DEBUG_SIM_STATES = DEBUG || false; 64 private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3; 65 private static final int LOW_BATTERY_THRESHOLD = 20; 66 67 // Callback messages 68 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; 72 private static final int MSG_RINGER_MODE_CHANGED = 305; 73 private static final int MSG_PHONE_STATE_CHANGED = 306; 74 private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307; 75 private static final int MSG_DEVICE_PROVISIONED = 308; 76 private static final int MSG_DPM_STATE_CHANGED = 309; 77 private static final int MSG_USER_SWITCHED = 310; 78 private static final int MSG_USER_REMOVED = 311; 79 80 private static KeyguardUpdateMonitor sInstance; 81 82 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 91 // Device provisioning state 92 private boolean mDeviceProvisioned; 93 94 // Battery status 95 private BatteryStatus mBatteryStatus; 96 97 // Password attempts 98 private int mFailedAttempts = 0; 99 private int mFailedBiometricUnlockAttempts = 0; 100 101 private boolean mClockVisible; 102 103 private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>> 104 mCallbacks = Lists.newArrayList(); 105 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, 188 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); 189 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 190 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED, 191 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); 192 } 193 } 194 }; 195 196 /** 197 * When we receive a 198 * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, 199 * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, 200 * we need a single object to pass to the handler. This class helps decode 201 * the intent and provide a {@link SimCard.State} result. 202 */ 203 private static class SimArgs { 204 public final IccCardConstants.State simState; 205 206 SimArgs(IccCardConstants.State state) { 207 simState = state; 208 } 209 210 static SimArgs fromIntent(Intent intent) { 211 IccCardConstants.State state; 212 if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { 213 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); 214 } 215 String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); 216 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { 217 final String absentReason = intent 218 .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); 219 220 if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals( 221 absentReason)) { 222 state = IccCardConstants.State.PERM_DISABLED; 223 } else { 224 state = IccCardConstants.State.ABSENT; 225 } 226 } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { 227 state = IccCardConstants.State.READY; 228 } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { 229 final String lockedReason = intent 230 .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; 235 } else { 236 state = IccCardConstants.State.UNKNOWN; 237 } 238 } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { 239 state = IccCardConstants.State.NETWORK_LOCKED; 240 } else { 241 state = IccCardConstants.State.UNKNOWN; 242 } 243 return new SimArgs(state); 244 } 245 246 public String toString() { 247 return simState.toString(); 248 } 249 } 250 251 /* package */ static class BatteryStatus { 252 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 263 /** 264 * Determine whether the device is plugged in (USB, power, or wireless). 265 * @return true if the device is plugged in. 266 */ 267 boolean isPluggedIn() { 268 return plugged == BatteryManager.BATTERY_PLUGGED_AC 269 || plugged == BatteryManager.BATTERY_PLUGGED_USB 270 || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS; 271 } 272 273 /** 274 * Whether or not the device is charged. Note that some devices never return 100% for 275 * battery level, so this allows either battery level or status to determine if the 276 * battery is charged. 277 * @return true if the device is charged 278 */ 279 public boolean isCharged() { 280 return status == BATTERY_STATUS_FULL || level >= 100; 281 } 282 283 /** 284 * Whether battery is low and needs to be charged. 285 * @return true if battery is low 286 */ 287 public boolean isBatteryLow() { 288 return level < LOW_BATTERY_THRESHOLD; 289 } 290 291 } 292 293 public static KeyguardUpdateMonitor getInstance(Context context) { 294 if (sInstance == null) { 295 sInstance = new KeyguardUpdateMonitor(context); 296 } 297 return sInstance; 298 } 299 300 private KeyguardUpdateMonitor(Context context) { 301 mContext = context; 302 303 mDeviceProvisioned = Settings.Secure.getInt( 304 mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; 305 306 // Since device can't be un-provisioned, we only need to register a content observer 307 // to update mDeviceProvisioned when we are... 308 if (!mDeviceProvisioned) { 309 watchForDeviceProvisioning(); 310 } 311 312 // Take a guess at initial SIM state, battery status and PLMN until we get an update 313 mSimState = IccCardConstants.State.NOT_READY; 314 mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0); 315 mTelephonyPlmn = getDefaultPlmn(); 316 317 // Watch for interesting updates 318 final IntentFilter filter = new IntentFilter(); 319 filter.addAction(Intent.ACTION_TIME_TICK); 320 filter.addAction(Intent.ACTION_TIME_CHANGED); 321 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 322 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 323 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 324 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 325 filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); 326 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 327 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 328 filter.addAction(Intent.ACTION_USER_SWITCHED); 329 filter.addAction(Intent.ACTION_USER_REMOVED); 330 context.registerReceiver(mBroadcastReceiver, filter); 331 } 332 333 private void watchForDeviceProvisioning() { 334 mContentObserver = new ContentObserver(mHandler) { 335 @Override 336 public void onChange(boolean selfChange) { 337 super.onChange(selfChange); 338 mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), 339 Settings.Secure.DEVICE_PROVISIONED, 0) != 0; 340 if (mDeviceProvisioned) { 341 mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED)); 342 } 343 if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned); 344 } 345 }; 346 347 mContext.getContentResolver().registerContentObserver( 348 Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED), 349 false, mContentObserver); 350 351 // prevent a race condition between where we check the flag and where we register the 352 // observer by grabbing the value once again... 353 boolean provisioned = Settings.Secure.getInt(mContext.getContentResolver(), 354 Settings.Secure.DEVICE_PROVISIONED, 0) != 0; 355 if (provisioned != mDeviceProvisioned) { 356 mDeviceProvisioned = provisioned; 357 if (mDeviceProvisioned) { 358 mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED)); 359 } 360 } 361 } 362 363 /** 364 * Handle {@link #MSG_DPM_STATE_CHANGED} 365 */ 366 protected void handleDevicePolicyManagerStateChanged() { 367 for (int i = mCallbacks.size() - 1; i >= 0; i--) { 368 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 369 if (cb != null) { 370 cb.onDevicePolicyManagerStateChanged(); 371 } 372 } 373 } 374 375 /** 376 * Handle {@link #MSG_USER_SWITCHED} 377 */ 378 protected void handleUserSwitched(int userId) { 379 for (int i = 0; i < mCallbacks.size(); i++) { 380 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 381 if (cb != null) { 382 cb.onUserSwitched(userId); 383 } 384 } 385 } 386 387 /** 388 * Handle {@link #MSG_USER_SWITCHED} 389 */ 390 protected void handleUserRemoved(int userId) { 391 for (int i = 0; i < mCallbacks.size(); i++) { 392 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 393 if (cb != null) { 394 cb.onUserRemoved(userId); 395 } 396 } 397 } 398 399 /** 400 * Handle {@link #MSG_DEVICE_PROVISIONED} 401 */ 402 protected void handleDeviceProvisioned() { 403 for (int i = 0; i < mCallbacks.size(); i++) { 404 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 405 if (cb != null) { 406 cb.onDeviceProvisioned(); 407 } 408 } 409 if (mContentObserver != null) { 410 // We don't need the observer anymore... 411 mContext.getContentResolver().unregisterContentObserver(mContentObserver); 412 mContentObserver = null; 413 } 414 } 415 416 /** 417 * Handle {@link #MSG_PHONE_STATE_CHANGED} 418 */ 419 protected void handlePhoneStateChanged(String newState) { 420 if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")"); 421 if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) { 422 mPhoneState = TelephonyManager.CALL_STATE_IDLE; 423 } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) { 424 mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK; 425 } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) { 426 mPhoneState = TelephonyManager.CALL_STATE_RINGING; 427 } 428 for (int i = 0; i < mCallbacks.size(); i++) { 429 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 430 if (cb != null) { 431 cb.onPhoneStateChanged(mPhoneState); 432 } 433 } 434 } 435 436 /** 437 * Handle {@link #MSG_RINGER_MODE_CHANGED} 438 */ 439 protected void handleRingerModeChange(int mode) { 440 if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); 441 mRingMode = mode; 442 for (int i = 0; i < mCallbacks.size(); i++) { 443 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 444 if (cb != null) { 445 cb.onRingerModeChanged(mode); 446 } 447 } 448 } 449 450 /** 451 * Handle {@link #MSG_TIME_UPDATE} 452 */ 453 private void handleTimeUpdate() { 454 if (DEBUG) Log.d(TAG, "handleTimeUpdate"); 455 for (int i = 0; i < mCallbacks.size(); i++) { 456 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 457 if (cb != null) { 458 cb.onTimeChanged(); 459 } 460 } 461 } 462 463 /** 464 * Handle {@link #MSG_BATTERY_UPDATE} 465 */ 466 private void handleBatteryUpdate(BatteryStatus status) { 467 if (DEBUG) Log.d(TAG, "handleBatteryUpdate"); 468 final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status); 469 mBatteryStatus = status; 470 if (batteryUpdateInteresting) { 471 for (int i = 0; i < mCallbacks.size(); i++) { 472 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 473 if (cb != null) { 474 cb.onRefreshBatteryInfo(status); 475 } 476 } 477 } 478 } 479 480 /** 481 * Handle {@link #MSG_CARRIER_INFO_UPDATE} 482 */ 483 private void handleCarrierInfoUpdate() { 484 if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn 485 + ", spn = " + mTelephonySpn); 486 487 for (int i = 0; i < mCallbacks.size(); i++) { 488 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 489 if (cb != null) { 490 cb.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); 491 } 492 } 493 } 494 495 /** 496 * Handle {@link #MSG_SIM_STATE_CHANGE} 497 */ 498 private void handleSimStateChange(SimArgs simArgs) { 499 final IccCardConstants.State state = simArgs.simState; 500 501 if (DEBUG) { 502 Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " " 503 + "state resolved to " + state.toString()); 504 } 505 506 if (state != IccCardConstants.State.UNKNOWN && state != mSimState) { 507 mSimState = state; 508 for (int i = 0; i < mCallbacks.size(); i++) { 509 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 510 if (cb != null) { 511 cb.onSimStateChanged(state); 512 } 513 } 514 } 515 } 516 517 /** 518 * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED} 519 */ 520 private void handleClockVisibilityChanged() { 521 if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()"); 522 for (int i = 0; i < mCallbacks.size(); i++) { 523 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 524 if (cb != null) { 525 cb.onClockVisibilityChanged(); 526 } 527 } 528 } 529 530 private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) { 531 final boolean nowPluggedIn = current.isPluggedIn(); 532 final boolean wasPluggedIn = old.isPluggedIn(); 533 final boolean stateChangedWhilePluggedIn = 534 wasPluggedIn == true && nowPluggedIn == true 535 && (old.status != current.status); 536 537 // change in plug state is always interesting 538 if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) { 539 return true; 540 } 541 542 // change in battery level while plugged in 543 if (nowPluggedIn && old.level != current.level) { 544 return true; 545 } 546 547 // change where battery needs charging 548 if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) { 549 return true; 550 } 551 return false; 552 } 553 554 /** 555 * @param intent The intent with action {@link TelephonyIntents#SPN_STRINGS_UPDATED_ACTION} 556 * @return The string to use for the plmn, or null if it should not be shown. 557 */ 558 private CharSequence getTelephonyPlmnFrom(Intent intent) { 559 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) { 560 final String plmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN); 561 return (plmn != null) ? plmn : getDefaultPlmn(); 562 } 563 return null; 564 } 565 566 /** 567 * @return The default plmn (no service) 568 */ 569 private CharSequence getDefaultPlmn() { 570 return mContext.getResources().getText(R.string.lockscreen_carrier_default); 571 } 572 573 /** 574 * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} 575 * @return The string to use for the plmn, or null if it should not be shown. 576 */ 577 private CharSequence getTelephonySpnFrom(Intent intent) { 578 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) { 579 final String spn = intent.getStringExtra(TelephonyIntents.EXTRA_SPN); 580 if (spn != null) { 581 return spn; 582 } 583 } 584 return null; 585 } 586 587 /** 588 * Remove the given observer's callback. 589 * 590 * @param callback The callback to remove 591 */ 592 public void removeCallback(KeyguardUpdateMonitorCallback callback) { 593 if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback); 594 for (int i = mCallbacks.size() - 1; i >= 0; i--) { 595 if (mCallbacks.get(i).get() == callback) { 596 mCallbacks.remove(i); 597 } 598 } 599 } 600 601 /** 602 * Register to receive notifications about general keyguard information 603 * (see {@link InfoCallback}. 604 * @param callback The callback to register 605 */ 606 public void registerCallback(KeyguardUpdateMonitorCallback callback) { 607 if (DEBUG) Log.v(TAG, "*** register callback for " + callback); 608 // Prevent adding duplicate callbacks 609 for (int i = 0; i < mCallbacks.size(); i++) { 610 if (mCallbacks.get(i).get() == callback) { 611 if (DEBUG) Log.e(TAG, "Object tried to add another callback", 612 new Exception("Called by")); 613 return; 614 } 615 } 616 mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback)); 617 removeCallback(null); // remove unused references 618 sendUpdates(callback); 619 } 620 621 private void sendUpdates(KeyguardUpdateMonitorCallback callback) { 622 // Notify listener of the current state 623 callback.onRefreshBatteryInfo(mBatteryStatus); 624 callback.onTimeChanged(); 625 callback.onRingerModeChanged(mRingMode); 626 callback.onPhoneStateChanged(mPhoneState); 627 callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); 628 callback.onClockVisibilityChanged(); 629 callback.onSimStateChanged(mSimState); 630 } 631 632 public void reportClockVisible(boolean visible) { 633 mClockVisible = visible; 634 mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget(); 635 } 636 637 public IccCardConstants.State getSimState() { 638 return mSimState; 639 } 640 641 /** 642 * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we 643 * have the information earlier than waiting for the intent 644 * broadcast from the telephony code. 645 * 646 * NOTE: Because handleSimStateChange() invokes callbacks immediately without going 647 * through mHandler, this *must* be called from the UI thread. 648 */ 649 public void reportSimUnlocked() { 650 handleSimStateChange(new SimArgs(IccCardConstants.State.READY)); 651 } 652 653 public CharSequence getTelephonyPlmn() { 654 return mTelephonyPlmn; 655 } 656 657 public CharSequence getTelephonySpn() { 658 return mTelephonySpn; 659 } 660 661 /** 662 * @return Whether the device is provisioned (whether they have gone through 663 * the setup wizard) 664 */ 665 public boolean isDeviceProvisioned() { 666 return mDeviceProvisioned; 667 } 668 669 public int getFailedUnlockAttempts() { 670 return mFailedAttempts; 671 } 672 673 public void clearFailedUnlockAttempts() { 674 mFailedAttempts = 0; 675 mFailedBiometricUnlockAttempts = 0; 676 } 677 678 public void reportFailedUnlockAttempt() { 679 mFailedAttempts++; 680 } 681 682 public boolean isClockVisible() { 683 return mClockVisible; 684 } 685 686 public int getPhoneState() { 687 return mPhoneState; 688 } 689 690 public void reportFailedBiometricUnlockAttempt() { 691 mFailedBiometricUnlockAttempts++; 692 } 693 694 public boolean getMaxBiometricUnlockAttemptsReached() { 695 return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP; 696 } 697 698 public boolean isSimLocked() { 699 return isSimLocked(mSimState); 700 } 701 702 public static boolean isSimLocked(IccCardConstants.State state) { 703 return state == IccCardConstants.State.PIN_REQUIRED 704 || state == IccCardConstants.State.PUK_REQUIRED 705 || state == IccCardConstants.State.PERM_DISABLED; 706 } 707 708 public boolean isSimPinSecure() { 709 return isSimPinSecure(mSimState); 710 } 711 712 public static boolean isSimPinSecure(IccCardConstants.State state) { 713 final IccCardConstants.State simState = state; 714 return (simState == IccCardConstants.State.PIN_REQUIRED 715 || simState == IccCardConstants.State.PUK_REQUIRED 716 || simState == IccCardConstants.State.PERM_DISABLED); 717 } 718} 719