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