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