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