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.keyguard; 18 19 import android.app.ActivityManagerNative; 20 import android.app.IUserSwitchObserver; 21 import android.app.PendingIntent; 22 import android.app.admin.DevicePolicyManager; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.database.ContentObserver; 28 import android.graphics.Bitmap; 29 30 import static android.os.BatteryManager.BATTERY_STATUS_FULL; 31 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; 32 import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN; 33 import static android.os.BatteryManager.EXTRA_STATUS; 34 import static android.os.BatteryManager.EXTRA_PLUGGED; 35 import static android.os.BatteryManager.EXTRA_LEVEL; 36 import static android.os.BatteryManager.EXTRA_HEALTH; 37 import android.media.AudioManager; 38 import android.media.IRemoteControlDisplay; 39 import android.os.BatteryManager; 40 import android.os.Bundle; 41 import android.os.Handler; 42 import android.os.IRemoteCallback; 43 import android.os.Message; 44 import android.os.RemoteException; 45 import android.os.UserHandle; 46 import android.provider.Settings; 47 48 import com.android.internal.telephony.IccCardConstants; 49 import com.android.internal.telephony.TelephonyIntents; 50 51 import android.telephony.TelephonyManager; 52 import android.util.Log; 53 import com.google.android.collect.Lists; 54 55 import java.lang.ref.WeakReference; 56 import java.util.ArrayList; 57 58 /** 59 * Watches for updates that may be interesting to the keyguard, and provides 60 * the up to date information as well as a registration for callbacks that care 61 * to be updated. 62 * 63 * Note: under time crunch, this has been extended to include some stuff that 64 * doesn't really belong here. see {@link #handleBatteryUpdate} where it shutdowns 65 * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()} 66 * and {@link #clearFailedUnlockAttempts()}. Maybe we should rename this 'KeyguardContext'... 67 */ 68 public class KeyguardUpdateMonitor { 69 70 private static final String TAG = "KeyguardUpdateMonitor"; 71 private static final boolean DEBUG = false; 72 private static final boolean DEBUG_SIM_STATES = DEBUG || false; 73 private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3; 74 private static final int LOW_BATTERY_THRESHOLD = 20; 75 76 // Callback messages 77 private static final int MSG_TIME_UPDATE = 301; 78 private static final int MSG_BATTERY_UPDATE = 302; 79 private static final int MSG_CARRIER_INFO_UPDATE = 303; 80 private static final int MSG_SIM_STATE_CHANGE = 304; 81 private static final int MSG_RINGER_MODE_CHANGED = 305; 82 private static final int MSG_PHONE_STATE_CHANGED = 306; 83 private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307; 84 private static final int MSG_DEVICE_PROVISIONED = 308; 85 private static final int MSG_DPM_STATE_CHANGED = 309; 86 private static final int MSG_USER_SWITCHING = 310; 87 private static final int MSG_USER_REMOVED = 311; 88 private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312; 89 protected static final int MSG_BOOT_COMPLETED = 313; 90 private static final int MSG_USER_SWITCH_COMPLETE = 314; 91 private static final int MSG_SET_CURRENT_CLIENT_ID = 315; 92 protected static final int MSG_SET_PLAYBACK_STATE = 316; 93 protected static final int MSG_USER_INFO_CHANGED = 317; 94 protected static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318; 95 private static final int MSG_SCREEN_TURNED_ON = 319; 96 private static final int MSG_SCREEN_TURNED_OFF = 320; 97 98 private static KeyguardUpdateMonitor sInstance; 99 100 private final Context mContext; 101 102 // Telephony state 103 private IccCardConstants.State mSimState = IccCardConstants.State.READY; 104 private CharSequence mTelephonyPlmn; 105 private CharSequence mTelephonySpn; 106 private int mRingMode; 107 private int mPhoneState; 108 private boolean mKeyguardIsVisible; 109 private boolean mBootCompleted; 110 111 // Device provisioning state 112 private boolean mDeviceProvisioned; 113 114 // Battery status 115 private BatteryStatus mBatteryStatus; 116 117 // Password attempts 118 private int mFailedAttempts = 0; 119 private int mFailedBiometricUnlockAttempts = 0; 120 121 private boolean mAlternateUnlockEnabled; 122 123 private boolean mClockVisible; 124 125 private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>> 126 mCallbacks = Lists.newArrayList(); 127 private ContentObserver mDeviceProvisionedObserver; 128 129 private boolean mSwitchingUser; 130 131 private boolean mScreenOn; 132 133 private final Handler mHandler = new Handler() { 134 @Override 135 public void handleMessage(Message msg) { 136 switch (msg.what) { 137 case MSG_TIME_UPDATE: 138 handleTimeUpdate(); 139 break; 140 case MSG_BATTERY_UPDATE: 141 handleBatteryUpdate((BatteryStatus) msg.obj); 142 break; 143 case MSG_CARRIER_INFO_UPDATE: 144 handleCarrierInfoUpdate(); 145 break; 146 case MSG_SIM_STATE_CHANGE: 147 handleSimStateChange((SimArgs) msg.obj); 148 break; 149 case MSG_RINGER_MODE_CHANGED: 150 handleRingerModeChange(msg.arg1); 151 break; 152 case MSG_PHONE_STATE_CHANGED: 153 handlePhoneStateChanged((String)msg.obj); 154 break; 155 case MSG_CLOCK_VISIBILITY_CHANGED: 156 handleClockVisibilityChanged(); 157 break; 158 case MSG_DEVICE_PROVISIONED: 159 handleDeviceProvisioned(); 160 break; 161 case MSG_DPM_STATE_CHANGED: 162 handleDevicePolicyManagerStateChanged(); 163 break; 164 case MSG_USER_SWITCHING: 165 handleUserSwitching(msg.arg1, (IRemoteCallback)msg.obj); 166 break; 167 case MSG_USER_SWITCH_COMPLETE: 168 handleUserSwitchComplete(msg.arg1); 169 break; 170 case MSG_USER_REMOVED: 171 handleUserRemoved(msg.arg1); 172 break; 173 case MSG_KEYGUARD_VISIBILITY_CHANGED: 174 handleKeyguardVisibilityChanged(msg.arg1); 175 break; 176 case MSG_BOOT_COMPLETED: 177 handleBootCompleted(); 178 break; 179 case MSG_SET_CURRENT_CLIENT_ID: 180 handleSetGenerationId(msg.arg1, msg.arg2 != 0, (PendingIntent) msg.obj); 181 break; 182 case MSG_SET_PLAYBACK_STATE: 183 handleSetPlaybackState(msg.arg1, msg.arg2, (Long) msg.obj); 184 break; 185 case MSG_USER_INFO_CHANGED: 186 handleUserInfoChanged(msg.arg1); 187 break; 188 case MSG_REPORT_EMERGENCY_CALL_ACTION: 189 handleReportEmergencyCallAction(); 190 break; 191 case MSG_SCREEN_TURNED_OFF: 192 handleScreenTurnedOff(msg.arg1); 193 break; 194 case MSG_SCREEN_TURNED_ON: 195 handleScreenTurnedOn(); 196 break; 197 } 198 } 199 }; 200 201 private AudioManager mAudioManager; 202 203 static class DisplayClientState { 204 public int clientGeneration; 205 public boolean clearing; 206 public PendingIntent intent; 207 public int playbackState; 208 public long playbackEventTime; 209 } 210 211 private DisplayClientState mDisplayClientState = new DisplayClientState(); 212 213 /** 214 * This currently implements the bare minimum required to enable showing and hiding 215 * KeyguardTransportControl. There's a lot of client state to maintain which is why 216 * KeyguardTransportControl maintains an independent connection while it's showing. 217 */ 218 private final IRemoteControlDisplay.Stub mRemoteControlDisplay = 219 new IRemoteControlDisplay.Stub() { 220 221 public void setPlaybackState(int generationId, int state, long stateChangeTimeMs, 222 long currentPosMs, float speed) { 223 Message msg = mHandler.obtainMessage(MSG_SET_PLAYBACK_STATE, 224 generationId, state, stateChangeTimeMs); 225 mHandler.sendMessage(msg); 226 } 227 228 public void setMetadata(int generationId, Bundle metadata) { 229 230 } 231 232 public void setTransportControlInfo(int generationId, int flags, int posCapabilities) { 233 234 } 235 236 public void setArtwork(int generationId, Bitmap bitmap) { 237 238 } 239 240 public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) { 241 242 } 243 244 public void setEnabled(boolean enabled) { 245 // no-op: this RemoteControlDisplay is not subject to being disabled. 246 } 247 248 public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent, 249 boolean clearing) throws RemoteException { 250 Message msg = mHandler.obtainMessage(MSG_SET_CURRENT_CLIENT_ID, 251 clientGeneration, (clearing ? 1 : 0), mediaIntent); 252 mHandler.sendMessage(msg); 253 } 254 }; 255 256 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 257 258 public void onReceive(Context context, Intent intent) { 259 final String action = intent.getAction(); 260 if (DEBUG) Log.d(TAG, "received broadcast " + action); 261 262 if (Intent.ACTION_TIME_TICK.equals(action) 263 || Intent.ACTION_TIME_CHANGED.equals(action) 264 || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { 265 mHandler.sendEmptyMessage(MSG_TIME_UPDATE); 266 } else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) { 267 mTelephonyPlmn = getTelephonyPlmnFrom(intent); 268 mTelephonySpn = getTelephonySpnFrom(intent); 269 mHandler.sendEmptyMessage(MSG_CARRIER_INFO_UPDATE); 270 } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { 271 final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN); 272 final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0); 273 final int level = intent.getIntExtra(EXTRA_LEVEL, 0); 274 final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN); 275 final Message msg = mHandler.obtainMessage( 276 MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health)); 277 mHandler.sendMessage(msg); 278 } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) { 279 if (DEBUG_SIM_STATES) { 280 Log.v(TAG, "action " + action + " state" + 281 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)); 282 } 283 mHandler.sendMessage(mHandler.obtainMessage( 284 MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent))); 285 } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { 286 mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, 287 intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0)); 288 } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { 289 String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); 290 mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state)); 291 } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED 292 .equals(action)) { 293 mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED); 294 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 295 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED, 296 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); 297 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { 298 dispatchBootCompleted(); 299 } 300 } 301 }; 302 303 private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() { 304 305 public void onReceive(Context context, Intent intent) { 306 final String action = intent.getAction(); 307 if (Intent.ACTION_USER_INFO_CHANGED.equals(action)) { 308 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_INFO_CHANGED, 309 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()), 0)); 310 } 311 } 312 }; 313 314 /** 315 * When we receive a 316 * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, 317 * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange}, 318 * we need a single object to pass to the handler. This class helps decode 319 * the intent and provide a {@link SimCard.State} result. 320 */ 321 private static class SimArgs { 322 public final IccCardConstants.State simState; 323 324 SimArgs(IccCardConstants.State state) { 325 simState = state; 326 } 327 328 static SimArgs fromIntent(Intent intent) { 329 IccCardConstants.State state; 330 if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { 331 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); 332 } 333 String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); 334 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { 335 final String absentReason = intent 336 .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); 337 338 if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals( 339 absentReason)) { 340 state = IccCardConstants.State.PERM_DISABLED; 341 } else { 342 state = IccCardConstants.State.ABSENT; 343 } 344 } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { 345 state = IccCardConstants.State.READY; 346 } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { 347 final String lockedReason = intent 348 .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); 349 if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { 350 state = IccCardConstants.State.PIN_REQUIRED; 351 } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { 352 state = IccCardConstants.State.PUK_REQUIRED; 353 } else { 354 state = IccCardConstants.State.UNKNOWN; 355 } 356 } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { 357 state = IccCardConstants.State.NETWORK_LOCKED; 358 } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra) 359 || IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) { 360 // This is required because telephony doesn't return to "READY" after 361 // these state transitions. See bug 7197471. 362 state = IccCardConstants.State.READY; 363 } else { 364 state = IccCardConstants.State.UNKNOWN; 365 } 366 return new SimArgs(state); 367 } 368 369 public String toString() { 370 return simState.toString(); 371 } 372 } 373 374 /* package */ static class BatteryStatus { 375 public final int status; 376 public final int level; 377 public final int plugged; 378 public final int health; 379 public BatteryStatus(int status, int level, int plugged, int health) { 380 this.status = status; 381 this.level = level; 382 this.plugged = plugged; 383 this.health = health; 384 } 385 386 /** 387 * Determine whether the device is plugged in (USB, power, or wireless). 388 * @return true if the device is plugged in. 389 */ 390 boolean isPluggedIn() { 391 return plugged == BatteryManager.BATTERY_PLUGGED_AC 392 || plugged == BatteryManager.BATTERY_PLUGGED_USB 393 || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS; 394 } 395 396 /** 397 * Whether or not the device is charged. Note that some devices never return 100% for 398 * battery level, so this allows either battery level or status to determine if the 399 * battery is charged. 400 * @return true if the device is charged 401 */ 402 public boolean isCharged() { 403 return status == BATTERY_STATUS_FULL || level >= 100; 404 } 405 406 /** 407 * Whether battery is low and needs to be charged. 408 * @return true if battery is low 409 */ 410 public boolean isBatteryLow() { 411 return level < LOW_BATTERY_THRESHOLD; 412 } 413 414 } 415 416 public static KeyguardUpdateMonitor getInstance(Context context) { 417 if (sInstance == null) { 418 sInstance = new KeyguardUpdateMonitor(context); 419 } 420 return sInstance; 421 } 422 423 protected void handleScreenTurnedOn() { 424 final int count = mCallbacks.size(); 425 for (int i = 0; i < count; i++) { 426 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 427 if (cb != null) { 428 cb.onScreenTurnedOn(); 429 } 430 } 431 } 432 433 protected void handleScreenTurnedOff(int arg1) { 434 final int count = mCallbacks.size(); 435 for (int i = 0; i < count; i++) { 436 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 437 if (cb != null) { 438 cb.onScreenTurnedOff(arg1); 439 } 440 } 441 } 442 443 /** 444 * IMPORTANT: Must be called from UI thread. 445 */ 446 public void dispatchSetBackground(Bitmap bmp) { 447 if (DEBUG) Log.d(TAG, "dispatchSetBackground"); 448 final int count = mCallbacks.size(); 449 for (int i = 0; i < count; i++) { 450 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 451 if (cb != null) { 452 cb.onSetBackground(bmp); 453 } 454 } 455 } 456 457 protected void handleSetGenerationId(int clientGeneration, boolean clearing, PendingIntent p) { 458 mDisplayClientState.clientGeneration = clientGeneration; 459 mDisplayClientState.clearing = clearing; 460 mDisplayClientState.intent = p; 461 if (DEBUG) 462 Log.v(TAG, "handleSetGenerationId(g=" + clientGeneration + ", clear=" + clearing + ")"); 463 for (int i = 0; i < mCallbacks.size(); i++) { 464 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 465 if (cb != null) { 466 cb.onMusicClientIdChanged(clientGeneration, clearing, p); 467 } 468 } 469 } 470 471 protected void handleSetPlaybackState(int generationId, int playbackState, long eventTime) { 472 if (DEBUG) 473 Log.v(TAG, "handleSetPlaybackState(gen=" + generationId 474 + ", state=" + playbackState + ", t=" + eventTime + ")"); 475 mDisplayClientState.playbackState = playbackState; 476 mDisplayClientState.playbackEventTime = eventTime; 477 if (generationId == mDisplayClientState.clientGeneration) { 478 for (int i = 0; i < mCallbacks.size(); i++) { 479 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 480 if (cb != null) { 481 cb.onMusicPlaybackStateChanged(playbackState, eventTime); 482 } 483 } 484 } else { 485 Log.w(TAG, "Ignoring generation id " + generationId + " because it's not current"); 486 } 487 } 488 489 private void handleUserInfoChanged(int userId) { 490 for (int i = 0; i < mCallbacks.size(); i++) { 491 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 492 if (cb != null) { 493 cb.onUserInfoChanged(userId); 494 } 495 } 496 } 497 498 private KeyguardUpdateMonitor(Context context) { 499 mContext = context; 500 501 mDeviceProvisioned = isDeviceProvisionedInSettingsDb(); 502 // Since device can't be un-provisioned, we only need to register a content observer 503 // to update mDeviceProvisioned when we are... 504 if (!mDeviceProvisioned) { 505 watchForDeviceProvisioning(); 506 } 507 508 // Take a guess at initial SIM state, battery status and PLMN until we get an update 509 mSimState = IccCardConstants.State.NOT_READY; 510 mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0); 511 mTelephonyPlmn = getDefaultPlmn(); 512 513 // Watch for interesting updates 514 final IntentFilter filter = new IntentFilter(); 515 filter.addAction(Intent.ACTION_TIME_TICK); 516 filter.addAction(Intent.ACTION_TIME_CHANGED); 517 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 518 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 519 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 520 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 521 filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); 522 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 523 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 524 filter.addAction(Intent.ACTION_USER_REMOVED); 525 context.registerReceiver(mBroadcastReceiver, filter); 526 527 final IntentFilter bootCompleteFilter = new IntentFilter(); 528 bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 529 bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED); 530 context.registerReceiver(mBroadcastReceiver, bootCompleteFilter); 531 532 final IntentFilter userInfoFilter = new IntentFilter(Intent.ACTION_USER_INFO_CHANGED); 533 context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, userInfoFilter, 534 null, null); 535 536 try { 537 ActivityManagerNative.getDefault().registerUserSwitchObserver( 538 new IUserSwitchObserver.Stub() { 539 @Override 540 public void onUserSwitching(int newUserId, IRemoteCallback reply) { 541 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING, 542 newUserId, 0, reply)); 543 mSwitchingUser = true; 544 } 545 @Override 546 public void onUserSwitchComplete(int newUserId) throws RemoteException { 547 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE, 548 newUserId)); 549 mSwitchingUser = false; 550 } 551 }); 552 } catch (RemoteException e) { 553 // TODO Auto-generated catch block 554 e.printStackTrace(); 555 } 556 } 557 558 private boolean isDeviceProvisionedInSettingsDb() { 559 return Settings.Global.getInt(mContext.getContentResolver(), 560 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 561 } 562 563 private void watchForDeviceProvisioning() { 564 mDeviceProvisionedObserver = new ContentObserver(mHandler) { 565 @Override 566 public void onChange(boolean selfChange) { 567 super.onChange(selfChange); 568 mDeviceProvisioned = isDeviceProvisionedInSettingsDb(); 569 if (mDeviceProvisioned) { 570 mHandler.sendEmptyMessage(MSG_DEVICE_PROVISIONED); 571 } 572 if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned); 573 } 574 }; 575 576 mContext.getContentResolver().registerContentObserver( 577 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), 578 false, mDeviceProvisionedObserver); 579 580 // prevent a race condition between where we check the flag and where we register the 581 // observer by grabbing the value once again... 582 boolean provisioned = isDeviceProvisionedInSettingsDb(); 583 if (provisioned != mDeviceProvisioned) { 584 mDeviceProvisioned = provisioned; 585 if (mDeviceProvisioned) { 586 mHandler.sendEmptyMessage(MSG_DEVICE_PROVISIONED); 587 } 588 } 589 } 590 591 /** 592 * Handle {@link #MSG_DPM_STATE_CHANGED} 593 */ 594 protected void handleDevicePolicyManagerStateChanged() { 595 for (int i = mCallbacks.size() - 1; i >= 0; i--) { 596 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 597 if (cb != null) { 598 cb.onDevicePolicyManagerStateChanged(); 599 } 600 } 601 } 602 603 /** 604 * Handle {@link #MSG_USER_SWITCHING} 605 */ 606 protected void handleUserSwitching(int userId, IRemoteCallback reply) { 607 for (int i = 0; i < mCallbacks.size(); i++) { 608 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 609 if (cb != null) { 610 cb.onUserSwitching(userId); 611 } 612 } 613 try { 614 reply.sendResult(null); 615 } catch (RemoteException e) { 616 } 617 } 618 619 /** 620 * Handle {@link #MSG_USER_SWITCH_COMPLETE} 621 */ 622 protected void handleUserSwitchComplete(int userId) { 623 for (int i = 0; i < mCallbacks.size(); i++) { 624 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 625 if (cb != null) { 626 cb.onUserSwitchComplete(userId); 627 } 628 } 629 } 630 631 /** 632 * This is exposed since {@link Intent#ACTION_BOOT_COMPLETED} is not sticky. If 633 * keyguard crashes sometime after boot, then it will never receive this 634 * broadcast and hence not handle the event. This method is ultimately called by 635 * PhoneWindowManager in this case. 636 */ 637 protected void dispatchBootCompleted() { 638 mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); 639 } 640 641 /** 642 * Handle {@link #MSG_BOOT_COMPLETED} 643 */ 644 protected void handleBootCompleted() { 645 if (mBootCompleted) return; 646 mBootCompleted = true; 647 mAudioManager = new AudioManager(mContext); 648 mAudioManager.registerRemoteControlDisplay(mRemoteControlDisplay); 649 for (int i = 0; i < mCallbacks.size(); i++) { 650 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 651 if (cb != null) { 652 cb.onBootCompleted(); 653 } 654 } 655 } 656 657 /** 658 * We need to store this state in the KeyguardUpdateMonitor since this class will not be 659 * destroyed. 660 */ 661 public boolean hasBootCompleted() { 662 return mBootCompleted; 663 } 664 665 /** 666 * Handle {@link #MSG_USER_REMOVED} 667 */ 668 protected void handleUserRemoved(int userId) { 669 for (int i = 0; i < mCallbacks.size(); i++) { 670 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 671 if (cb != null) { 672 cb.onUserRemoved(userId); 673 } 674 } 675 } 676 677 /** 678 * Handle {@link #MSG_DEVICE_PROVISIONED} 679 */ 680 protected void handleDeviceProvisioned() { 681 for (int i = 0; i < mCallbacks.size(); i++) { 682 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 683 if (cb != null) { 684 cb.onDeviceProvisioned(); 685 } 686 } 687 if (mDeviceProvisionedObserver != null) { 688 // We don't need the observer anymore... 689 mContext.getContentResolver().unregisterContentObserver(mDeviceProvisionedObserver); 690 mDeviceProvisionedObserver = null; 691 } 692 } 693 694 /** 695 * Handle {@link #MSG_PHONE_STATE_CHANGED} 696 */ 697 protected void handlePhoneStateChanged(String newState) { 698 if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")"); 699 if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) { 700 mPhoneState = TelephonyManager.CALL_STATE_IDLE; 701 } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) { 702 mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK; 703 } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) { 704 mPhoneState = TelephonyManager.CALL_STATE_RINGING; 705 } 706 for (int i = 0; i < mCallbacks.size(); i++) { 707 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 708 if (cb != null) { 709 cb.onPhoneStateChanged(mPhoneState); 710 } 711 } 712 } 713 714 /** 715 * Handle {@link #MSG_RINGER_MODE_CHANGED} 716 */ 717 protected void handleRingerModeChange(int mode) { 718 if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); 719 mRingMode = mode; 720 for (int i = 0; i < mCallbacks.size(); i++) { 721 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 722 if (cb != null) { 723 cb.onRingerModeChanged(mode); 724 } 725 } 726 } 727 728 /** 729 * Handle {@link #MSG_TIME_UPDATE} 730 */ 731 private void handleTimeUpdate() { 732 if (DEBUG) Log.d(TAG, "handleTimeUpdate"); 733 for (int i = 0; i < mCallbacks.size(); i++) { 734 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 735 if (cb != null) { 736 cb.onTimeChanged(); 737 } 738 } 739 } 740 741 /** 742 * Handle {@link #MSG_BATTERY_UPDATE} 743 */ 744 private void handleBatteryUpdate(BatteryStatus status) { 745 if (DEBUG) Log.d(TAG, "handleBatteryUpdate"); 746 final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status); 747 mBatteryStatus = status; 748 if (batteryUpdateInteresting) { 749 for (int i = 0; i < mCallbacks.size(); i++) { 750 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 751 if (cb != null) { 752 cb.onRefreshBatteryInfo(status); 753 } 754 } 755 } 756 } 757 758 /** 759 * Handle {@link #MSG_CARRIER_INFO_UPDATE} 760 */ 761 private void handleCarrierInfoUpdate() { 762 if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn 763 + ", spn = " + mTelephonySpn); 764 765 for (int i = 0; i < mCallbacks.size(); i++) { 766 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 767 if (cb != null) { 768 cb.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); 769 } 770 } 771 } 772 773 /** 774 * Handle {@link #MSG_SIM_STATE_CHANGE} 775 */ 776 private void handleSimStateChange(SimArgs simArgs) { 777 final IccCardConstants.State state = simArgs.simState; 778 779 if (DEBUG) { 780 Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " " 781 + "state resolved to " + state.toString()); 782 } 783 784 if (state != IccCardConstants.State.UNKNOWN && state != mSimState) { 785 mSimState = state; 786 for (int i = 0; i < mCallbacks.size(); i++) { 787 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 788 if (cb != null) { 789 cb.onSimStateChanged(state); 790 } 791 } 792 } 793 } 794 795 /** 796 * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED} 797 */ 798 private void handleClockVisibilityChanged() { 799 if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()"); 800 for (int i = 0; i < mCallbacks.size(); i++) { 801 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 802 if (cb != null) { 803 cb.onClockVisibilityChanged(); 804 } 805 } 806 } 807 808 /** 809 * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED} 810 */ 811 private void handleKeyguardVisibilityChanged(int showing) { 812 if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")"); 813 boolean isShowing = (showing == 1); 814 mKeyguardIsVisible = isShowing; 815 for (int i = 0; i < mCallbacks.size(); i++) { 816 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 817 if (cb != null) { 818 cb.onKeyguardVisibilityChangedRaw(isShowing); 819 } 820 } 821 } 822 823 /** 824 * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION} 825 */ 826 private void handleReportEmergencyCallAction() { 827 for (int i = 0; i < mCallbacks.size(); i++) { 828 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); 829 if (cb != null) { 830 cb.onEmergencyCallAction(); 831 } 832 } 833 } 834 835 public boolean isKeyguardVisible() { 836 return mKeyguardIsVisible; 837 } 838 839 public boolean isSwitchingUser() { 840 return mSwitchingUser; 841 } 842 843 private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) { 844 final boolean nowPluggedIn = current.isPluggedIn(); 845 final boolean wasPluggedIn = old.isPluggedIn(); 846 final boolean stateChangedWhilePluggedIn = 847 wasPluggedIn == true && nowPluggedIn == true 848 && (old.status != current.status); 849 850 // change in plug state is always interesting 851 if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) { 852 return true; 853 } 854 855 // change in battery level while plugged in 856 if (nowPluggedIn && old.level != current.level) { 857 return true; 858 } 859 860 // change where battery needs charging 861 if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) { 862 return true; 863 } 864 return false; 865 } 866 867 /** 868 * @param intent The intent with action {@link TelephonyIntents#SPN_STRINGS_UPDATED_ACTION} 869 * @return The string to use for the plmn, or null if it should not be shown. 870 */ 871 private CharSequence getTelephonyPlmnFrom(Intent intent) { 872 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) { 873 final String plmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN); 874 return (plmn != null) ? plmn : getDefaultPlmn(); 875 } 876 return null; 877 } 878 879 /** 880 * @return The default plmn (no service) 881 */ 882 private CharSequence getDefaultPlmn() { 883 return mContext.getResources().getText(R.string.keyguard_carrier_default); 884 } 885 886 /** 887 * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION} 888 * @return The string to use for the plmn, or null if it should not be shown. 889 */ 890 private CharSequence getTelephonySpnFrom(Intent intent) { 891 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) { 892 final String spn = intent.getStringExtra(TelephonyIntents.EXTRA_SPN); 893 if (spn != null) { 894 return spn; 895 } 896 } 897 return null; 898 } 899 900 /** 901 * Remove the given observer's callback. 902 * 903 * @param callback The callback to remove 904 */ 905 public void removeCallback(KeyguardUpdateMonitorCallback callback) { 906 if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback); 907 for (int i = mCallbacks.size() - 1; i >= 0; i--) { 908 if (mCallbacks.get(i).get() == callback) { 909 mCallbacks.remove(i); 910 } 911 } 912 } 913 914 /** 915 * Register to receive notifications about general keyguard information 916 * (see {@link InfoCallback}. 917 * @param callback The callback to register 918 */ 919 public void registerCallback(KeyguardUpdateMonitorCallback callback) { 920 if (DEBUG) Log.v(TAG, "*** register callback for " + callback); 921 // Prevent adding duplicate callbacks 922 for (int i = 0; i < mCallbacks.size(); i++) { 923 if (mCallbacks.get(i).get() == callback) { 924 if (DEBUG) Log.e(TAG, "Object tried to add another callback", 925 new Exception("Called by")); 926 return; 927 } 928 } 929 mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback)); 930 removeCallback(null); // remove unused references 931 sendUpdates(callback); 932 } 933 934 private void sendUpdates(KeyguardUpdateMonitorCallback callback) { 935 // Notify listener of the current state 936 callback.onRefreshBatteryInfo(mBatteryStatus); 937 callback.onTimeChanged(); 938 callback.onRingerModeChanged(mRingMode); 939 callback.onPhoneStateChanged(mPhoneState); 940 callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); 941 callback.onClockVisibilityChanged(); 942 callback.onSimStateChanged(mSimState); 943 callback.onMusicClientIdChanged( 944 mDisplayClientState.clientGeneration, 945 mDisplayClientState.clearing, 946 mDisplayClientState.intent); 947 callback.onMusicPlaybackStateChanged(mDisplayClientState.playbackState, 948 mDisplayClientState.playbackEventTime); 949 } 950 951 public void sendKeyguardVisibilityChanged(boolean showing) { 952 if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")"); 953 Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED); 954 message.arg1 = showing ? 1 : 0; 955 message.sendToTarget(); 956 } 957 958 public void reportClockVisible(boolean visible) { 959 mClockVisible = visible; 960 mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget(); 961 } 962 963 public IccCardConstants.State getSimState() { 964 return mSimState; 965 } 966 967 /** 968 * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we 969 * have the information earlier than waiting for the intent 970 * broadcast from the telephony code. 971 * 972 * NOTE: Because handleSimStateChange() invokes callbacks immediately without going 973 * through mHandler, this *must* be called from the UI thread. 974 */ 975 public void reportSimUnlocked() { 976 handleSimStateChange(new SimArgs(IccCardConstants.State.READY)); 977 } 978 979 /** 980 * Report that the emergency call button has been pressed and the emergency dialer is 981 * about to be displayed. 982 * 983 * @param bypassHandler runs immediately. 984 * 985 * NOTE: Must be called from UI thread if bypassHandler == true. 986 */ 987 public void reportEmergencyCallAction(boolean bypassHandler) { 988 if (!bypassHandler) { 989 mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget(); 990 } else { 991 handleReportEmergencyCallAction(); 992 } 993 } 994 995 public CharSequence getTelephonyPlmn() { 996 return mTelephonyPlmn; 997 } 998 999 public CharSequence getTelephonySpn() { 1000 return mTelephonySpn; 1001 } 1002 1003 /** 1004 * @return Whether the device is provisioned (whether they have gone through 1005 * the setup wizard) 1006 */ 1007 public boolean isDeviceProvisioned() { 1008 return mDeviceProvisioned; 1009 } 1010 1011 public int getFailedUnlockAttempts() { 1012 return mFailedAttempts; 1013 } 1014 1015 public void clearFailedUnlockAttempts() { 1016 mFailedAttempts = 0; 1017 mFailedBiometricUnlockAttempts = 0; 1018 } 1019 1020 public void reportFailedUnlockAttempt() { 1021 mFailedAttempts++; 1022 } 1023 1024 public boolean isClockVisible() { 1025 return mClockVisible; 1026 } 1027 1028 public int getPhoneState() { 1029 return mPhoneState; 1030 } 1031 1032 public void reportFailedBiometricUnlockAttempt() { 1033 mFailedBiometricUnlockAttempts++; 1034 } 1035 1036 public boolean getMaxBiometricUnlockAttemptsReached() { 1037 return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP; 1038 } 1039 1040 public boolean isAlternateUnlockEnabled() { 1041 return mAlternateUnlockEnabled; 1042 } 1043 1044 public void setAlternateUnlockEnabled(boolean enabled) { 1045 mAlternateUnlockEnabled = enabled; 1046 } 1047 1048 public boolean isSimLocked() { 1049 return isSimLocked(mSimState); 1050 } 1051 1052 public static boolean isSimLocked(IccCardConstants.State state) { 1053 return state == IccCardConstants.State.PIN_REQUIRED 1054 || state == IccCardConstants.State.PUK_REQUIRED 1055 || state == IccCardConstants.State.PERM_DISABLED; 1056 } 1057 1058 public boolean isSimPinSecure() { 1059 return isSimPinSecure(mSimState); 1060 } 1061 1062 public static boolean isSimPinSecure(IccCardConstants.State state) { 1063 final IccCardConstants.State simState = state; 1064 return (simState == IccCardConstants.State.PIN_REQUIRED 1065 || simState == IccCardConstants.State.PUK_REQUIRED 1066 || simState == IccCardConstants.State.PERM_DISABLED); 1067 } 1068 1069 public DisplayClientState getCachedDisplayClientState() { 1070 return mDisplayClientState; 1071 } 1072 1073 // TODO: use these callbacks elsewhere in place of the existing notifyScreen*() 1074 // (KeyguardViewMediator, KeyguardHostView) 1075 public void dispatchScreenTurnedOn() { 1076 synchronized (this) { 1077 mScreenOn = true; 1078 } 1079 mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_ON); 1080 } 1081 1082 public void dispatchScreenTurndOff(int why) { 1083 synchronized(this) { 1084 mScreenOn = false; 1085 } 1086 mHandler.sendMessage(mHandler.obtainMessage(MSG_SCREEN_TURNED_OFF, why, 0)); 1087 } 1088 1089 public boolean isScreenOn() { 1090 return mScreenOn; 1091 } 1092 } 1093