1 /* 2 * Copyright (C) 2007 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 android.app; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SystemApi; 24 import android.annotation.SystemService; 25 import android.app.trust.ITrustManager; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.PackageManager; 29 import android.content.pm.ResolveInfo; 30 import android.os.Binder; 31 import android.os.Handler; 32 import android.os.IBinder; 33 import android.os.RemoteException; 34 import android.os.ServiceManager; 35 import android.os.ServiceManager.ServiceNotFoundException; 36 import android.os.UserHandle; 37 import android.provider.Settings; 38 import android.service.persistentdata.IPersistentDataBlockService; 39 import android.util.Log; 40 import android.view.IOnKeyguardExitResult; 41 import android.view.IWindowManager; 42 import android.view.WindowManager.LayoutParams; 43 import android.view.WindowManagerGlobal; 44 45 import com.android.internal.policy.IKeyguardDismissCallback; 46 import com.android.internal.widget.LockPatternUtils; 47 48 import java.util.List; 49 50 /** 51 * Class that can be used to lock and unlock the keyboard. The 52 * actual class to control the keyboard locking is 53 * {@link android.app.KeyguardManager.KeyguardLock}. 54 */ 55 @SystemService(Context.KEYGUARD_SERVICE) 56 public class KeyguardManager { 57 58 private static final String TAG = "KeyguardManager"; 59 60 private final Context mContext; 61 private final IWindowManager mWM; 62 private final IActivityManager mAm; 63 private final ITrustManager mTrustManager; 64 65 /** 66 * Intent used to prompt user for device credentials. 67 * @hide 68 */ 69 public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL = 70 "android.app.action.CONFIRM_DEVICE_CREDENTIAL"; 71 72 /** 73 * Intent used to prompt user for device credentials. 74 * @hide 75 */ 76 public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER = 77 "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER"; 78 79 /** 80 * Intent used to prompt user for factory reset credentials. 81 * @hide 82 */ 83 public static final String ACTION_CONFIRM_FRP_CREDENTIAL = 84 "android.app.action.CONFIRM_FRP_CREDENTIAL"; 85 86 /** 87 * A CharSequence dialog title to show to the user when used with a 88 * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}. 89 * @hide 90 */ 91 public static final String EXTRA_TITLE = "android.app.extra.TITLE"; 92 93 /** 94 * A CharSequence description to show to the user when used with 95 * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}. 96 * @hide 97 */ 98 public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION"; 99 100 /** 101 * A CharSequence description to show to the user on the alternate button when used with 102 * {@link #ACTION_CONFIRM_FRP_CREDENTIAL}. 103 * @hide 104 */ 105 public static final String EXTRA_ALTERNATE_BUTTON_LABEL = 106 "android.app.extra.ALTERNATE_BUTTON_LABEL"; 107 108 /** 109 * Result code returned by the activity started by 110 * {@link #createConfirmFactoryResetCredentialIntent} indicating that the user clicked the 111 * alternate button. 112 * 113 * @hide 114 */ 115 public static final int RESULT_ALTERNATE = 1; 116 117 /** 118 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 119 * for the current user of the device. The caller is expected to launch this activity using 120 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 121 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 122 * 123 * @return the intent for launching the activity or null if no password is required. 124 **/ 125 public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) { 126 if (!isDeviceSecure()) return null; 127 Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL); 128 intent.putExtra(EXTRA_TITLE, title); 129 intent.putExtra(EXTRA_DESCRIPTION, description); 130 131 // explicitly set the package for security 132 intent.setPackage(getSettingsPackageForIntent(intent)); 133 return intent; 134 } 135 136 /** 137 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 138 * for the given user. The caller is expected to launch this activity using 139 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 140 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 141 * 142 * @return the intent for launching the activity or null if no password is required. 143 * 144 * @hide 145 */ 146 public Intent createConfirmDeviceCredentialIntent( 147 CharSequence title, CharSequence description, int userId) { 148 if (!isDeviceSecure(userId)) return null; 149 Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER); 150 intent.putExtra(EXTRA_TITLE, title); 151 intent.putExtra(EXTRA_DESCRIPTION, description); 152 intent.putExtra(Intent.EXTRA_USER_ID, userId); 153 154 // explicitly set the package for security 155 intent.setPackage(getSettingsPackageForIntent(intent)); 156 157 return intent; 158 } 159 160 /** 161 * Get an intent to prompt the user to confirm credentials (pin, pattern or password) 162 * for the previous owner of the device. The caller is expected to launch this activity using 163 * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for 164 * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. 165 * 166 * @param alternateButtonLabel if not empty, a button is provided with the given label. Upon 167 * clicking this button, the activity returns 168 * {@link #RESULT_ALTERNATE} 169 * 170 * @return the intent for launching the activity or null if the previous owner of the device 171 * did not set a credential. 172 * @throws UnsupportedOperationException if the device does not support factory reset 173 * credentials 174 * @throws IllegalStateException if the device has already been provisioned 175 * @hide 176 */ 177 @SystemApi 178 public Intent createConfirmFactoryResetCredentialIntent( 179 CharSequence title, CharSequence description, CharSequence alternateButtonLabel) { 180 if (!LockPatternUtils.frpCredentialEnabled(mContext)) { 181 Log.w(TAG, "Factory reset credentials not supported."); 182 throw new UnsupportedOperationException("not supported on this device"); 183 } 184 185 // Cannot verify credential if the device is provisioned 186 if (Settings.Global.getInt(mContext.getContentResolver(), 187 Settings.Global.DEVICE_PROVISIONED, 0) != 0) { 188 Log.e(TAG, "Factory reset credential cannot be verified after provisioning."); 189 throw new IllegalStateException("must not be provisioned yet"); 190 } 191 192 // Make sure we have a credential 193 try { 194 IPersistentDataBlockService pdb = IPersistentDataBlockService.Stub.asInterface( 195 ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE)); 196 if (pdb == null) { 197 Log.e(TAG, "No persistent data block service"); 198 throw new UnsupportedOperationException("not supported on this device"); 199 } 200 // The following will throw an UnsupportedOperationException if the device does not 201 // support factory reset credentials (or something went wrong retrieving it). 202 if (!pdb.hasFrpCredentialHandle()) { 203 Log.i(TAG, "The persistent data block does not have a factory reset credential."); 204 return null; 205 } 206 } catch (RemoteException e) { 207 throw e.rethrowFromSystemServer(); 208 } 209 210 Intent intent = new Intent(ACTION_CONFIRM_FRP_CREDENTIAL); 211 intent.putExtra(EXTRA_TITLE, title); 212 intent.putExtra(EXTRA_DESCRIPTION, description); 213 intent.putExtra(EXTRA_ALTERNATE_BUTTON_LABEL, alternateButtonLabel); 214 215 // explicitly set the package for security 216 intent.setPackage(getSettingsPackageForIntent(intent)); 217 218 return intent; 219 } 220 221 private String getSettingsPackageForIntent(Intent intent) { 222 List<ResolveInfo> resolveInfos = mContext.getPackageManager() 223 .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY); 224 for (int i = 0; i < resolveInfos.size(); i++) { 225 return resolveInfos.get(i).activityInfo.packageName; 226 } 227 228 return "com.android.settings"; 229 } 230 231 /** 232 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 233 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 234 * instead; this allows you to seamlessly hide the keyguard as your application 235 * moves in and out of the foreground and does not require that any special 236 * permissions be requested. 237 * 238 * Handle returned by {@link KeyguardManager#newKeyguardLock} that allows 239 * you to disable / reenable the keyguard. 240 */ 241 @Deprecated 242 public class KeyguardLock { 243 private final IBinder mToken = new Binder(); 244 private final String mTag; 245 246 KeyguardLock(String tag) { 247 mTag = tag; 248 } 249 250 /** 251 * Disable the keyguard from showing. If the keyguard is currently 252 * showing, hide it. The keyguard will be prevented from showing again 253 * until {@link #reenableKeyguard()} is called. 254 * 255 * A good place to call this is from {@link android.app.Activity#onResume()} 256 * 257 * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager} 258 * is enabled that requires a password. 259 * 260 * @see #reenableKeyguard() 261 */ 262 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) 263 public void disableKeyguard() { 264 try { 265 mWM.disableKeyguard(mToken, mTag); 266 } catch (RemoteException ex) { 267 } 268 } 269 270 /** 271 * Reenable the keyguard. The keyguard will reappear if the previous 272 * call to {@link #disableKeyguard()} caused it to be hidden. 273 * 274 * A good place to call this is from {@link android.app.Activity#onPause()} 275 * 276 * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager} 277 * is enabled that requires a password. 278 * 279 * @see #disableKeyguard() 280 */ 281 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) 282 public void reenableKeyguard() { 283 try { 284 mWM.reenableKeyguard(mToken); 285 } catch (RemoteException ex) { 286 } 287 } 288 } 289 290 /** 291 * @deprecated Use {@link KeyguardDismissCallback} 292 * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify 293 * caller of result. 294 */ 295 @Deprecated 296 public interface OnKeyguardExitResult { 297 298 /** 299 * @param success True if the user was able to authenticate, false if 300 * not. 301 */ 302 void onKeyguardExitResult(boolean success); 303 } 304 305 /** 306 * Callback passed to 307 * {@link KeyguardManager#requestDismissKeyguard(Activity, KeyguardDismissCallback)} 308 * to notify caller of result. 309 */ 310 public static abstract class KeyguardDismissCallback { 311 312 /** 313 * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not 314 * available, not showing or when the activity requesting the Keyguard dismissal isn't 315 * showing or isn't showing behind Keyguard. 316 */ 317 public void onDismissError() { } 318 319 /** 320 * Called when dismissing Keyguard has succeeded and the device is now unlocked. 321 */ 322 public void onDismissSucceeded() { } 323 324 /** 325 * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the 326 * operation or the bouncer was hidden for some other reason. 327 */ 328 public void onDismissCancelled() { } 329 } 330 331 KeyguardManager(Context context) throws ServiceNotFoundException { 332 mContext = context; 333 mWM = WindowManagerGlobal.getWindowManagerService(); 334 mAm = ActivityManager.getService(); 335 mTrustManager = ITrustManager.Stub.asInterface( 336 ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE)); 337 } 338 339 /** 340 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 341 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 342 * instead; this allows you to seamlessly hide the keyguard as your application 343 * moves in and out of the foreground and does not require that any special 344 * permissions be requested. 345 * 346 * Enables you to lock or unlock the keyboard. Get an instance of this class by 347 * calling {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. 348 * This class is wrapped by {@link android.app.KeyguardManager KeyguardManager}. 349 * @param tag A tag that informally identifies who you are (for debugging who 350 * is disabling he keyguard). 351 * 352 * @return A {@link KeyguardLock} handle to use to disable and reenable the 353 * keyguard. 354 */ 355 @Deprecated 356 public KeyguardLock newKeyguardLock(String tag) { 357 return new KeyguardLock(tag); 358 } 359 360 /** 361 * Return whether the keyguard is currently locked. 362 * 363 * @return true if keyguard is locked. 364 */ 365 public boolean isKeyguardLocked() { 366 try { 367 return mWM.isKeyguardLocked(); 368 } catch (RemoteException ex) { 369 return false; 370 } 371 } 372 373 /** 374 * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card 375 * is currently locked. 376 * 377 * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states. 378 * 379 * @return true if a PIN, pattern or password is set or a SIM card is locked. 380 */ 381 public boolean isKeyguardSecure() { 382 try { 383 return mWM.isKeyguardSecure(); 384 } catch (RemoteException ex) { 385 return false; 386 } 387 } 388 389 /** 390 * @deprecated Use {@link #isKeyguardLocked()} instead. 391 * 392 * If keyguard screen is showing or in restricted key input mode (i.e. in 393 * keyguard password emergency screen). When in such mode, certain keys, 394 * such as the Home key and the right soft keys, don't work. 395 * 396 * @return true if in keyguard restricted input mode. 397 */ 398 public boolean inKeyguardRestrictedInputMode() { 399 return isKeyguardLocked(); 400 } 401 402 /** 403 * Returns whether the device is currently locked and requires a PIN, pattern or 404 * password to unlock. 405 * 406 * @return true if unlocking the device currently requires a PIN, pattern or 407 * password. 408 */ 409 public boolean isDeviceLocked() { 410 return isDeviceLocked(mContext.getUserId()); 411 } 412 413 /** 414 * Per-user version of {@link #isDeviceLocked()}. 415 * 416 * @hide 417 */ 418 public boolean isDeviceLocked(int userId) { 419 try { 420 return mTrustManager.isDeviceLocked(userId); 421 } catch (RemoteException e) { 422 return false; 423 } 424 } 425 426 /** 427 * Returns whether the device is secured with a PIN, pattern or 428 * password. 429 * 430 * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure. 431 * 432 * @return true if a PIN, pattern or password was set. 433 */ 434 public boolean isDeviceSecure() { 435 return isDeviceSecure(mContext.getUserId()); 436 } 437 438 /** 439 * Per-user version of {@link #isDeviceSecure()}. 440 * 441 * @hide 442 */ 443 public boolean isDeviceSecure(int userId) { 444 try { 445 return mTrustManager.isDeviceSecure(userId); 446 } catch (RemoteException e) { 447 return false; 448 } 449 } 450 451 /** @removed */ 452 @Deprecated 453 public void dismissKeyguard(@NonNull Activity activity, 454 @Nullable KeyguardDismissCallback callback, @Nullable Handler handler) { 455 requestDismissKeyguard(activity, callback); 456 } 457 458 /** 459 * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to 460 * be dismissed. 461 * <p> 462 * If the Keyguard is not secure or the device is currently in a trusted state, calling this 463 * method will immediately dismiss the Keyguard without any user interaction. 464 * <p> 465 * If the Keyguard is secure and the device is not in a trusted state, this will bring up the 466 * UI so the user can enter their credentials. 467 * <p> 468 * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true, 469 * the screen will turn on when the keyguard is dismissed. 470 * 471 * @param activity The activity requesting the dismissal. The activity must be either visible 472 * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in 473 * which it would be visible if Keyguard would not be hiding it. If that's not 474 * the case, the request will fail immediately and 475 * {@link KeyguardDismissCallback#onDismissError} will be invoked. 476 * @param callback The callback to be called if the request to dismiss Keyguard was successful 477 * or {@code null} if the caller isn't interested in knowing the result. The 478 * callback will not be invoked if the activity was destroyed before the 479 * callback was received. 480 */ 481 public void requestDismissKeyguard(@NonNull Activity activity, 482 @Nullable KeyguardDismissCallback callback) { 483 requestDismissKeyguard(activity, null /* message */, callback); 484 } 485 486 /** 487 * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to 488 * be dismissed. 489 * <p> 490 * If the Keyguard is not secure or the device is currently in a trusted state, calling this 491 * method will immediately dismiss the Keyguard without any user interaction. 492 * <p> 493 * If the Keyguard is secure and the device is not in a trusted state, this will bring up the 494 * UI so the user can enter their credentials. 495 * <p> 496 * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true, 497 * the screen will turn on when the keyguard is dismissed. 498 * 499 * @param activity The activity requesting the dismissal. The activity must be either visible 500 * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in 501 * which it would be visible if Keyguard would not be hiding it. If that's not 502 * the case, the request will fail immediately and 503 * {@link KeyguardDismissCallback#onDismissError} will be invoked. 504 * @param message A message that will be shown in the keyguard explaining why the user 505 * would want to dismiss it. 506 * @param callback The callback to be called if the request to dismiss Keyguard was successful 507 * or {@code null} if the caller isn't interested in knowing the result. The 508 * callback will not be invoked if the activity was destroyed before the 509 * callback was received. 510 * @hide 511 */ 512 @RequiresPermission(Manifest.permission.SHOW_KEYGUARD_MESSAGE) 513 @SystemApi 514 public void requestDismissKeyguard(@NonNull Activity activity, @Nullable CharSequence message, 515 @Nullable KeyguardDismissCallback callback) { 516 try { 517 mAm.dismissKeyguard(activity.getActivityToken(), new IKeyguardDismissCallback.Stub() { 518 @Override 519 public void onDismissError() throws RemoteException { 520 if (callback != null && !activity.isDestroyed()) { 521 activity.mHandler.post(callback::onDismissError); 522 } 523 } 524 525 @Override 526 public void onDismissSucceeded() throws RemoteException { 527 if (callback != null && !activity.isDestroyed()) { 528 activity.mHandler.post(callback::onDismissSucceeded); 529 } 530 } 531 532 @Override 533 public void onDismissCancelled() throws RemoteException { 534 if (callback != null && !activity.isDestroyed()) { 535 activity.mHandler.post(callback::onDismissCancelled); 536 } 537 } 538 }, message); 539 } catch (RemoteException e) { 540 throw e.rethrowFromSystemServer(); 541 } 542 } 543 544 /** 545 * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD} 546 * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} 547 * instead; this allows you to seamlessly hide the keyguard as your application 548 * moves in and out of the foreground and does not require that any special 549 * permissions be requested. 550 * 551 * Exit the keyguard securely. The use case for this api is that, after 552 * disabling the keyguard, your app, which was granted permission to 553 * disable the keyguard and show a limited amount of information deemed 554 * safe without the user getting past the keyguard, needs to navigate to 555 * something that is not safe to view without getting past the keyguard. 556 * 557 * This will, if the keyguard is secure, bring up the unlock screen of 558 * the keyguard. 559 * 560 * @param callback Let's you know whether the operation was succesful and 561 * it is safe to launch anything that would normally be considered safe 562 * once the user has gotten past the keyguard. 563 */ 564 @Deprecated 565 @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD) 566 public void exitKeyguardSecurely(final OnKeyguardExitResult callback) { 567 try { 568 mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() { 569 public void onKeyguardExitResult(boolean success) throws RemoteException { 570 if (callback != null) { 571 callback.onKeyguardExitResult(success); 572 } 573 } 574 }); 575 } catch (RemoteException e) { 576 577 } 578 } 579 } 580