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