KeyguardUpdateMonitor.java revision 5d2404da57926736317c1a08d989cd55784ef8a1
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.ActivityManagerNative; 20import android.app.IUserSwitchObserver; 21import android.app.admin.DevicePolicyManager; 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.database.ContentObserver; 27import static android.os.BatteryManager.BATTERY_STATUS_FULL; 28import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; 29import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN; 30import static android.os.BatteryManager.EXTRA_STATUS; 31import static android.os.BatteryManager.EXTRA_PLUGGED; 32import static android.os.BatteryManager.EXTRA_LEVEL; 33import static android.os.BatteryManager.EXTRA_HEALTH; 34import android.media.AudioManager; 35import android.os.BatteryManager; 36import android.os.Handler; 37import android.os.IRemoteCallback; 38import android.os.Message; 39import android.os.RemoteException; 40import android.provider.Settings; 41 42import com.android.internal.telephony.IccCardConstants; 43import com.android.internal.telephony.TelephonyIntents; 44 45import android.telephony.TelephonyManager; 46import android.util.Log; 47import com.android.internal.R; 48import com.google.android.collect.Lists; 49 50import java.lang.ref.WeakReference; 51import java.util.ArrayList; 52 53/** 54 * Watches for updates that may be interesting to the keyguard, and provides 55 * the up to date information as well as a registration for callbacks that care 56 * to be updated. 57 * 58 * Note: under time crunch, this has been extended to include some stuff that 59 * doesn't really belong here. see {@link #handleBatteryUpdate} where it shutdowns 60 * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()} 61 * and {@link #clearFailedUnlockAttempts()}. Maybe we should rename this 'KeyguardContext'... 62 */ 63public class KeyguardUpdateMonitor { 64 65 private static final String TAG = "KeyguardUpdateMonitor"; 66 private static final boolean DEBUG = false; 67 private static final boolean DEBUG_SIM_STATES = DEBUG || false; 68 private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3; 69 private static final int LOW_BATTERY_THRESHOLD = 20; 70 71 // Callback messages 72 private static final int MSG_TIME_UPDATE = 301; 73 private static final int MSG_BATTERY_UPDATE = 302; 74 private static final int MSG_CARRIER_INFO_UPDATE = 303; 75 private static final int MSG_SIM_STATE_CHANGE = 304; 76 private static final int MSG_RINGER_MODE_CHANGED = 305; 77 private static final int MSG_PHONE_STATE_CHANGED = 306; 78 private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307; 79 private static final int MSG_DEVICE_PROVISIONED = 308; 80 private static final int MSG_DPM_STATE_CHANGED = 309; 81 private static final int MSG_USER_SWITCHED = 310; 82 private static final int MSG_USER_REMOVED = 311; 83 private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312; 84 85 private static KeyguardUpdateMonitor sInstance; 86 87 private final Context mContext; 88 89 // Telephony state 90 private IccCardConstants.State mSimState = IccCardConstants.State.READY; 91 private CharSequence mTelephonyPlmn; 92 private CharSequence mTelephonySpn; 93 private int mRingMode; 94 private int mPhoneState; 95 private boolean mKeyguardIsVisible; 96 97 // Device provisioning state 98 private boolean mDeviceProvisioned; 99 100 // Battery status 101 private BatteryStatus mBatteryStatus; 102 103 // Password attempts 104 private int mFailedAttempts = 0; 105 private int mFailedBiometricUnlockAttempts = 0; 106 107 private boolean mAlternateUnlockEnabled; 108 109 private boolean mClockVisible; 110 111 private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>> 112 mCallbacks = Lists.newArrayList(); 113 private ContentObserver mContentObserver; 114 115 private final Handler mHandler = new Handler() { 116 @Override 117 public void handleMessage(Message msg) { 118 switch (msg.what) { 119 case MSG_TIME_UPDATE: 120 handleTimeUpdate(); 121 break; 122 case MSG_BATTERY_UPDATE: 123 handleBatteryUpdate((BatteryStatus) msg.obj); 124 break; 125 case MSG_CARRIER_INFO_UPDATE: 126 handleCarrierInfoUpdate(); 127 break; 128 case MSG_SIM_STATE_CHANGE: 129 handleSimStateChange((SimArgs) msg.obj); 130 break; 131 case MSG_RINGER_MODE_CHANGED: 132 handleRingerModeChange(msg.arg1); 133 break; 134 case MSG_PHONE_STATE_CHANGED: 135 handlePhoneStateChanged((String)msg.obj); 136 break; 137 case MSG_CLOCK_VISIBILITY_CHANGED: 138 handleClockVisibilityChanged(); 139 break; 140 case MSG_DEVICE_PROVISIONED: 141 handleDeviceProvisioned(); 142 break; 143 case MSG_DPM_STATE_CHANGED: 144 handleDevicePolicyManagerStateChanged(); 145 break; 146 case MSG_USER_SWITCHED: 147 handleUserSwitched(msg.arg1, (IRemoteCallback)msg.obj); 148 break; 149 case MSG_USER_REMOVED: 150 handleUserRemoved(msg.arg1); 151 break; 152 case MSG_KEYGUARD_VISIBILITY_CHANGED: 153 handleKeyguardVisibilityChanged(msg.arg1); 154 break; 155 156 } 157 } 158 }; 159 160 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 161 162 public void onReceive(Context context, Intent intent) { 163 final String action = intent.getAction(); 164 if (DEBUG) Log.d(TAG, "received broadcast " + action); 165 166 if (Intent.ACTION_TIME_TICK.equals(action) 167 || Intent.ACTION_TIME_CHANGED.equals(action) 168 || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { 169 mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE)); 170 } else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) { 171 mTelephonyPlmn = getTelephonyPlmnFrom(intent); 172 mTelephonySpn = getTelephonySpnFrom(intent); 173 mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE)); 174 } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { 175 final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN); 176 final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0); 177 final int level = intent.getIntExtra(EXTRA_LEVEL, 0); 178 final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN); 179 final Message msg = mHandler.obtainMessage( 180 MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health)); 181 mHandler.sendMessage(msg); 182 } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) { 183 if (DEBUG_SIM_STATES) { 184 Log.v(TAG, "action " + action + " state" + 185 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)); 186 } 187 mHandler.sendMessage(mHandler.obtainMessage( 188 MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent))); 189 } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { 190 mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, 191 intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0)); 192 } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { 193 String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); 194 mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state)); 195 } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED 196 .equals(action)) { 197 mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED)); 198 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 199 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED, 200 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); 201 } 202 } 203 }; 204 private boolean mIsFirstBoot; 205 206 /** 207 * When we receive a 208 * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, 209 * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, 210 * we need a single object to pass to the handler. This class helps decode 211 * the intent and provide a {@link SimCard.State} result. 212 */ 213 private static class SimArgs { 214 public final IccCardConstants.State simState; 215 216 SimArgs(IccCardConstants.State state) { 217 simState = state; 218 } 219 220 static SimArgs fromIntent(Intent intent) { 221 IccCardConstants.State state; 222 if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { 223 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); 224 } 225 String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); 226 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { 227 final String absentReason = intent 228 .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); 229 230 if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals( 231 absentReason)) { 232 state = IccCardConstants.State.PERM_DISABLED; 233 } else { 234 state = IccCardConstants.State.ABSENT; 235 } 236 } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { 237 state = IccCardConstants.State.READY; 238 } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { 239 final String lockedReason = intent 240 .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); 241 if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { 242 state = IccCardConstants.State.PIN_REQUIRED; 243 } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { 244 state = IccCardConstants.State.PUK_REQUIRED; 245 } else { 246 state = IccCardConstants.State.UNKNOWN; 247 } 248 } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { 249 state = IccCardConstants.State.NETWORK_LOCKED; 250 } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra) 251 || IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) { 252 // This is required because telephony doesn't return to "READY" after 253 // these state transitions. See bug 7197471. 254 state = IccCardConstants.State.READY; 255 } else { 256 state = IccCardConstants.State.UNKNOWN; 257 } 258 return new SimArgs(state); 259 } 260 261 public String toString() { 262 return simState.toString(); 263 } 264 } 265 266 /* package */ static class BatteryStatus { 267 public final int status; 268 public final int level; 269 public final int plugged; 270 public final int health; 271 public BatteryStatus(int status, int level, int plugged, int health) { 272 this.status = status; 273 this.level = level; 274 this.plugged = plugged; 275 this.health = health; 276 } 277 278 /** 279 * Determine whether the device is plugged in (USB, power, or wireless). 280 * @return true if the device is plugged in. 281 */ 282 boolean isPluggedIn() { 283 return plugged == BatteryManager.BATTERY_PLUGGED_AC 284 || plugged == BatteryManager.BATTERY_PLUGGED_USB 285 || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS; 286 } 287 288 /** 289 * Whether or not the device is charged. Note that some devices never return 100% for 290 * battery level, so this allows either battery level or status to determine if the 291 * battery is charged. 292 * @return true if the device is charged 293 */ 294 public boolean isCharged() { 295 return status == BATTERY_STATUS_FULL || level >= 100; 296 } 297 298 /** 299 * Whether battery is low and needs to be charged. 300 * @return true if battery is low 301 */ 302 public boolean isBatteryLow() { 303 return level < LOW_BATTERY_THRESHOLD; 304 } 305 306 } 307 308 public static KeyguardUpdateMonitor getInstance(Context context) { 309 if (sInstance == null) { 310 sInstance = new KeyguardUpdateMonitor(context); 311 } 312 return sInstance; 313 } 314 315 private KeyguardUpdateMonitor(Context context) { 316 mContext = context; 317 318 mDeviceProvisioned = Settings.Global.getInt( 319 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0; 320 321 // Since device can't be un-provisioned, we only need to register a content observer 322 // to update mDeviceProvisioned when we are... 323 if (!mDeviceProvisioned) { 324 watchForDeviceProvisioning(); 325 } 326 327 // Take a guess at initial SIM state, battery status and PLMN until we get an update 328 mSimState = IccCardConstants.State.NOT_READY; 329 mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0); 330 mTelephonyPlmn = getDefaultPlmn(); 331 332 // Watch for interesting updates 333 final IntentFilter filter = new IntentFilter(); 334 filter.addAction(Intent.ACTION_TIME_TICK); 335 filter.addAction(Intent.ACTION_TIME_CHANGED); 336 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 337 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 338 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 339 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 340 filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); 341 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 342 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 343 filter.addAction(Intent.ACTION_USER_REMOVED); 344 context.registerReceiver(mBroadcastReceiver, filter); 345 346 try { 347 ActivityManagerNative.getDefault().registerUserSwitchObserver( 348 new IUserSwitchObserver.Stub() { 349 @Override 350 public void onUserSwitching(int newUserId, IRemoteCallback reply) { 351 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, 352 newUserId, 0, reply)); 353 } 354 @Override 355 public void onUserSwitchComplete(int newUserId) throws RemoteException { 356 } 357 }); 358 } catch (RemoteException e) { 359 // TODO Auto-generated catch block 360 e.printStackTrace(); 361 } 362 } 363 364 private void watchForDeviceProvisioning() { 365 mContentObserver = new ContentObserver(mHandler) { 366 @Override 367 public void onChange(boolean selfChange) { 368 super.onChange(selfChange); 369 mDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(), 370 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 371 if (mDeviceProvisioned) { 372 mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED)); 373 } 374 if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned); 375 } 376 }; 377 378 mContext.getContentResolver().registerContentObserver( 379 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), 380 false, mContentObserver); 381 382 // prevent a race condition between where we check the flag and where we register the 383 // observer by grabbing the value once again... 384 boolean provisioned = Settings.Global.getInt(mContext.getContentResolver(), 385 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 386 if (provisioned != mDeviceProvisioned) { 387 mDeviceProvisioned = provisioned; 388 if (mDeviceProvisioned) { 389 mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED)); 390 } 391 } 392 } 393 394 /** 395 * Handle {@link #MSG_DPM_STATE_CHANGED} 396 */ 397 protected void handleDevicePolicyManagerStateChanged() { 398 for (int i = mCallbacks.size() - 1; i >= 0; i--) { 399 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 400 if (cb != null) { 401 cb.onDevicePolicyManagerStateChanged(); 402 } 403 } 404 } 405 406 /** 407 * Handle {@link #MSG_USER_SWITCHED} 408 */ 409 protected void handleUserSwitched(int userId, IRemoteCallback reply) { 410 for (int i = 0; i < mCallbacks.size(); i++) { 411 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 412 if (cb != null) { 413 cb.onUserSwitched(userId); 414 } 415 } 416 setAlternateUnlockEnabled(false); 417 try { 418 reply.sendResult(null); 419 } catch (RemoteException e) { 420 } 421 } 422 423 /** 424 * Handle {@link #MSG_USER_SWITCHED} 425 */ 426 protected void handleUserRemoved(int userId) { 427 for (int i = 0; i < mCallbacks.size(); i++) { 428 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 429 if (cb != null) { 430 cb.onUserRemoved(userId); 431 } 432 } 433 } 434 435 /** 436 * Handle {@link #MSG_DEVICE_PROVISIONED} 437 */ 438 protected void handleDeviceProvisioned() { 439 for (int i = 0; i < mCallbacks.size(); i++) { 440 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 441 if (cb != null) { 442 cb.onDeviceProvisioned(); 443 } 444 } 445 if (mContentObserver != null) { 446 // We don't need the observer anymore... 447 mContext.getContentResolver().unregisterContentObserver(mContentObserver); 448 mContentObserver = null; 449 } 450 } 451 452 /** 453 * Handle {@link #MSG_PHONE_STATE_CHANGED} 454 */ 455 protected void handlePhoneStateChanged(String newState) { 456 if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")"); 457 if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) { 458 mPhoneState = TelephonyManager.CALL_STATE_IDLE; 459 } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) { 460 mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK; 461 } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) { 462 mPhoneState = TelephonyManager.CALL_STATE_RINGING; 463 } 464 for (int i = 0; i < mCallbacks.size(); i++) { 465 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 466 if (cb != null) { 467 cb.onPhoneStateChanged(mPhoneState); 468 } 469 } 470 } 471 472 /** 473 * Handle {@link #MSG_RINGER_MODE_CHANGED} 474 */ 475 protected void handleRingerModeChange(int mode) { 476 if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); 477 mRingMode = mode; 478 for (int i = 0; i < mCallbacks.size(); i++) { 479 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 480 if (cb != null) { 481 cb.onRingerModeChanged(mode); 482 } 483 } 484 } 485 486 /** 487 * Handle {@link #MSG_TIME_UPDATE} 488 */ 489 private void handleTimeUpdate() { 490 if (DEBUG) Log.d(TAG, "handleTimeUpdate"); 491 for (int i = 0; i < mCallbacks.size(); i++) { 492 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 493 if (cb != null) { 494 cb.onTimeChanged(); 495 } 496 } 497 } 498 499 /** 500 * Handle {@link #MSG_BATTERY_UPDATE} 501 */ 502 private void handleBatteryUpdate(BatteryStatus status) { 503 if (DEBUG) Log.d(TAG, "handleBatteryUpdate"); 504 final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status); 505 mBatteryStatus = status; 506 if (batteryUpdateInteresting) { 507 for (int i = 0; i < mCallbacks.size(); i++) { 508 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 509 if (cb != null) { 510 cb.onRefreshBatteryInfo(status); 511 } 512 } 513 } 514 } 515 516 /** 517 * Handle {@link #MSG_CARRIER_INFO_UPDATE} 518 */ 519 private void handleCarrierInfoUpdate() { 520 if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn 521 + ", spn = " + mTelephonySpn); 522 523 for (int i = 0; i < mCallbacks.size(); i++) { 524 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 525 if (cb != null) { 526 cb.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); 527 } 528 } 529 } 530 531 /** 532 * Handle {@link #MSG_SIM_STATE_CHANGE} 533 */ 534 private void handleSimStateChange(SimArgs simArgs) { 535 final IccCardConstants.State state = simArgs.simState; 536 537 if (DEBUG) { 538 Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " " 539 + "state resolved to " + state.toString()); 540 } 541 542 if (state != IccCardConstants.State.UNKNOWN && state != mSimState) { 543 mSimState = state; 544 for (int i = 0; i < mCallbacks.size(); i++) { 545 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 546 if (cb != null) { 547 cb.onSimStateChanged(state); 548 } 549 } 550 } 551 } 552 553 /** 554 * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED} 555 */ 556 private void handleClockVisibilityChanged() { 557 if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()"); 558 for (int i = 0; i < mCallbacks.size(); i++) { 559 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 560 if (cb != null) { 561 cb.onClockVisibilityChanged(); 562 } 563 } 564 } 565 566 /** 567 * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED} 568 */ 569 private void handleKeyguardVisibilityChanged(int showing) { 570 if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")"); 571 boolean isShowing = (showing == 1); 572 mKeyguardIsVisible = isShowing; 573 for (int i = 0; i < mCallbacks.size(); i++) { 574 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 575 if (cb != null) { 576 cb.onKeyguardVisibilityChanged(isShowing); 577 } 578 } 579 } 580 581 public boolean isKeyguardVisible() { 582 return mKeyguardIsVisible; 583 } 584 585 private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) { 586 final boolean nowPluggedIn = current.isPluggedIn(); 587 final boolean wasPluggedIn = old.isPluggedIn(); 588 final boolean stateChangedWhilePluggedIn = 589 wasPluggedIn == true && nowPluggedIn == true 590 && (old.status != current.status); 591 592 // change in plug state is always interesting 593 if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) { 594 return true; 595 } 596 597 // change in battery level while plugged in 598 if (nowPluggedIn && old.level != current.level) { 599 return true; 600 } 601 602 // change where battery needs charging 603 if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) { 604 return true; 605 } 606 return false; 607 } 608 609 /** 610 * @param intent The intent with action {@link TelephonyIntents#SPN_STRINGS_UPDATED_ACTION} 611 * @return The string to use for the plmn, or null if it should not be shown. 612 */ 613 private CharSequence getTelephonyPlmnFrom(Intent intent) { 614 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) { 615 final String plmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN); 616 return (plmn != null) ? plmn : getDefaultPlmn(); 617 } 618 return null; 619 } 620 621 /** 622 * @return The default plmn (no service) 623 */ 624 private CharSequence getDefaultPlmn() { 625 return mContext.getResources().getText(R.string.lockscreen_carrier_default); 626 } 627 628 /** 629 * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} 630 * @return The string to use for the plmn, or null if it should not be shown. 631 */ 632 private CharSequence getTelephonySpnFrom(Intent intent) { 633 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) { 634 final String spn = intent.getStringExtra(TelephonyIntents.EXTRA_SPN); 635 if (spn != null) { 636 return spn; 637 } 638 } 639 return null; 640 } 641 642 /** 643 * Remove the given observer's callback. 644 * 645 * @param callback The callback to remove 646 */ 647 public void removeCallback(KeyguardUpdateMonitorCallback callback) { 648 if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback); 649 for (int i = mCallbacks.size() - 1; i >= 0; i--) { 650 if (mCallbacks.get(i).get() == callback) { 651 mCallbacks.remove(i); 652 } 653 } 654 } 655 656 /** 657 * Register to receive notifications about general keyguard information 658 * (see {@link InfoCallback}. 659 * @param callback The callback to register 660 */ 661 public void registerCallback(KeyguardUpdateMonitorCallback callback) { 662 if (DEBUG) Log.v(TAG, "*** register callback for " + callback); 663 // Prevent adding duplicate callbacks 664 for (int i = 0; i < mCallbacks.size(); i++) { 665 if (mCallbacks.get(i).get() == callback) { 666 if (DEBUG) Log.e(TAG, "Object tried to add another callback", 667 new Exception("Called by")); 668 return; 669 } 670 } 671 mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback)); 672 removeCallback(null); // remove unused references 673 sendUpdates(callback); 674 } 675 676 private void sendUpdates(KeyguardUpdateMonitorCallback callback) { 677 // Notify listener of the current state 678 callback.onRefreshBatteryInfo(mBatteryStatus); 679 callback.onTimeChanged(); 680 callback.onRingerModeChanged(mRingMode); 681 callback.onPhoneStateChanged(mPhoneState); 682 callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); 683 callback.onClockVisibilityChanged(); 684 callback.onSimStateChanged(mSimState); 685 } 686 687 public void sendKeyguardVisibilityChanged(boolean showing) { 688 if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")"); 689 Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED); 690 message.arg1 = showing ? 1 : 0; 691 message.sendToTarget(); 692 } 693 694 public void reportClockVisible(boolean visible) { 695 mClockVisible = visible; 696 mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget(); 697 } 698 699 public IccCardConstants.State getSimState() { 700 return mSimState; 701 } 702 703 /** 704 * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we 705 * have the information earlier than waiting for the intent 706 * broadcast from the telephony code. 707 * 708 * NOTE: Because handleSimStateChange() invokes callbacks immediately without going 709 * through mHandler, this *must* be called from the UI thread. 710 */ 711 public void reportSimUnlocked() { 712 handleSimStateChange(new SimArgs(IccCardConstants.State.READY)); 713 } 714 715 public CharSequence getTelephonyPlmn() { 716 return mTelephonyPlmn; 717 } 718 719 public CharSequence getTelephonySpn() { 720 return mTelephonySpn; 721 } 722 723 /** 724 * @return Whether the device is provisioned (whether they have gone through 725 * the setup wizard) 726 */ 727 public boolean isDeviceProvisioned() { 728 return mDeviceProvisioned; 729 } 730 731 public int getFailedUnlockAttempts() { 732 return mFailedAttempts; 733 } 734 735 public void clearFailedUnlockAttempts() { 736 mFailedAttempts = 0; 737 mFailedBiometricUnlockAttempts = 0; 738 } 739 740 public void reportFailedUnlockAttempt() { 741 mFailedAttempts++; 742 } 743 744 public boolean isClockVisible() { 745 return mClockVisible; 746 } 747 748 public int getPhoneState() { 749 return mPhoneState; 750 } 751 752 public void reportFailedBiometricUnlockAttempt() { 753 mFailedBiometricUnlockAttempts++; 754 } 755 756 public boolean getMaxBiometricUnlockAttemptsReached() { 757 return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP; 758 } 759 760 public boolean isAlternateUnlockEnabled() { 761 return mAlternateUnlockEnabled; 762 } 763 764 public void setAlternateUnlockEnabled(boolean enabled) { 765 mAlternateUnlockEnabled = enabled; 766 } 767 768 public boolean isSimLocked() { 769 return isSimLocked(mSimState); 770 } 771 772 public static boolean isSimLocked(IccCardConstants.State state) { 773 return state == IccCardConstants.State.PIN_REQUIRED 774 || state == IccCardConstants.State.PUK_REQUIRED 775 || state == IccCardConstants.State.PERM_DISABLED; 776 } 777 778 public boolean isSimPinSecure() { 779 return isSimPinSecure(mSimState); 780 } 781 782 public static boolean isSimPinSecure(IccCardConstants.State state) { 783 final IccCardConstants.State simState = state; 784 return (simState == IccCardConstants.State.PIN_REQUIRED 785 || simState == IccCardConstants.State.PUK_REQUIRED 786 || simState == IccCardConstants.State.PERM_DISABLED); 787 } 788 789 public void setIsFirstBoot(boolean b) { 790 mIsFirstBoot = b; 791 } 792 793 public boolean getIsFirstBoot() { 794 return mIsFirstBoot; 795 } 796} 797