Merge "Special interval value to always run benchmarks." into mnc-dr-dev
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 1f23c0a..7fef5e1 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.security.keystore.AndroidKeyStoreProvider;
@@ -705,15 +706,23 @@
     public void addLockoutResetCallback(final LockoutResetCallback callback) {
         if (mService != null) {
             try {
+                final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
                 mService.addLockoutResetCallback(
                         new IFingerprintServiceLockoutResetCallback.Stub() {
 
                     @Override
                     public void onLockoutReset(long deviceId) throws RemoteException {
+                        final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
+                                PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
+                        wakeLock.acquire();
                         mHandler.post(new Runnable() {
                             @Override
                             public void run() {
-                                callback.onLockoutReset();
+                                try {
+                                    callback.onLockoutReset();
+                                } finally {
+                                    wakeLock.release();
+                                }
                             }
                         });
                     }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
index c9a5d59..e027a2b3 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
@@ -23,6 +23,8 @@
  * Callback when lockout period expired and clients are allowed to authenticate again.
  * @hide
  */
-oneway interface IFingerprintServiceLockoutResetCallback {
+interface IFingerprintServiceLockoutResetCallback {
+
+    /** Method is synchronous so wakelock is held when this is called from a WAKEUP alarm. */
     void onLockoutReset(long deviceId);
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 4ac2958..a873ef8 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1174,7 +1174,7 @@
      * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
      */
     public void requireCredentialEntry(int userId) {
-        requireStrongAuth(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+        requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
     }
 
     /**
@@ -1251,7 +1251,7 @@
                 value = { STRONG_AUTH_NOT_REQUIRED,
                         STRONG_AUTH_REQUIRED_AFTER_BOOT,
                         STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
-                        STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST})
+                        SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
         @Retention(RetentionPolicy.SOURCE)
         public @interface StrongAuthFlags {}
 
@@ -1266,14 +1266,14 @@
         public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
 
         /**
-         * Strong authentication is required because a device admin has temporarily requested it.
+         * Strong authentication is required because a device admin has requested it.
          */
         public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
 
         /**
-         * Strong authentication is required because the user has temporarily requested it.
+         * Some authentication is required because the user has temporarily disabled trust.
          */
-        public static final int STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+        public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
 
         /**
          * Strong authentication is required because the user has been locked out after too many
@@ -1289,6 +1289,7 @@
         public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
 
         private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
+                | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
                 | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
 
         private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 030501b..8e58d14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -166,13 +166,10 @@
         if (mAccessibilityController == null) {
             return;
         }
-        boolean trustManagedOrFingerprintAllowed = mUnlockMethodCache.isTrustManaged()
-                || KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed();
-
         boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
-        boolean clickToForceLock = trustManagedOrFingerprintAllowed
+        boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
                 && !mAccessibilityController.isAccessibilityEnabled();
-        boolean longClickToForceLock = trustManagedOrFingerprintAllowed
+        boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
                 && !clickToForceLock;
         setClickable(clickToForceLock || clickToUnlock);
         setLongClickable(longClickToForceLock);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 638cd1c..548125d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -289,6 +289,7 @@
     private DozeServiceHost mDozeServiceHost;
     private boolean mWakeUpComingFromTouch;
     private PointF mWakeUpTouchLocation;
+    private boolean mScreenTurningOn;
 
     int mPixelFormat;
     Object mQueueLock = new Object();
@@ -3921,6 +3922,7 @@
     }
 
     public void onScreenTurningOn() {
+        mScreenTurningOn = true;
         mNotificationPanel.onScreenTurningOn();
         if (mLaunchCameraOnScreenTurningOn) {
             mNotificationPanel.launchCamera(false);
@@ -3933,6 +3935,7 @@
     }
 
     public void onScreenTurnedOn() {
+        mScreenTurningOn = false;
         mDozeScrimController.onScreenTurnedOn();
     }
 
@@ -4108,7 +4111,7 @@
                 mScrimController.dontAnimateBouncerChangesUntilNextFrame();
                 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
             }
-            if (mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
+            if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
                 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */);
             } else {
                 // We need to defer the camera launch until the screen comes on, since otherwise
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 0023258..ea7d85e 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -21,10 +21,15 @@
 import android.app.ActivityManager.RunningAppProcessInfo;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
 import android.app.AppOpsManager;
 import android.app.IUserSwitchObserver;
+import android.app.PendingIntent;
 import android.content.ComponentName;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
@@ -85,6 +90,8 @@
     private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon";
     private static final int MSG_USER_SWITCHING = 10;
     private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
+    private static final String ACTION_LOCKOUT_RESET =
+            "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
 
     private ClientMonitor mAuthClient = null;
     private ClientMonitor mEnrollClient = null;
@@ -118,9 +125,19 @@
     private long mHalDeviceId;
     private int mFailedAttempts;
     private IFingerprintDaemon mDaemon;
-    private PowerManager mPowerManager;
+    private final PowerManager mPowerManager;
+    private final AlarmManager mAlarmManager;
 
-    private final Runnable mLockoutReset = new Runnable() {
+    private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
+                resetFailedAttempts();
+            }
+        }
+    };
+
+    private final Runnable mResetFailedAttemptsRunnable = new Runnable() {
         @Override
         public void run() {
             resetFailedAttempts();
@@ -133,7 +150,10 @@
         mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
                 com.android.internal.R.string.config_keyguardComponent)).getPackageName();
         mAppOps = context.getSystemService(AppOpsManager.class);
-        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mPowerManager = mContext.getSystemService(PowerManager.class);
+        mAlarmManager = mContext.getSystemService(AlarmManager.class);
+        mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
+                RESET_FINGERPRINT_LOCKOUT, null /* handler */);
     }
 
     @Override
@@ -262,14 +282,28 @@
         return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
     }
 
+    private void scheduleLockoutReset() {
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent());
+    }
+
+    private void cancelLockoutReset() {
+        mAlarmManager.cancel(getLockoutResetIntent());
+    }
+
+    private PendingIntent getLockoutResetIntent() {
+        return PendingIntent.getBroadcast(mContext, 0,
+                new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT);
+    }
+
     private void resetFailedAttempts() {
         if (DEBUG && inLockoutMode()) {
             Slog.v(TAG, "Reset fingerprint lockout");
         }
         mFailedAttempts = 0;
-        // If we're asked to reset failed attempts externally (i.e. from Keyguard), the runnable
-        // may still be in the queue; remove it.
-        mHandler.removeCallbacks(mLockoutReset);
+        // If we're asked to reset failed attempts externally (i.e. from Keyguard), the alarm might
+        // still be pending; remove it.
+        cancelLockoutReset();
         notifyLockoutResetMonitors();
     }
 
@@ -277,8 +311,7 @@
         mFailedAttempts++;
         if (inLockoutMode()) {
             // Failing multiple times will continue to push out the lockout time.
-            mHandler.removeCallbacks(mLockoutReset);
-            mHandler.postDelayed(mLockoutReset, FAIL_LOCKOUT_TIMEOUT_MS);
+            scheduleLockoutReset();
             if (clientMonitor != null
                     && !clientMonitor.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
                 Slog.w(TAG, "Cannot send lockout message to client");
@@ -683,7 +716,7 @@
                     FingerprintUtils.vibrateFingerprintSuccess(getContext());
                 }
                 result |= true; // we have a valid fingerprint
-                mHandler.post(mLockoutReset);
+                resetFailedAttempts();
             }
             return result;
         }
@@ -1016,7 +1049,7 @@
         public void resetTimeout(byte [] token) {
             checkPermission(RESET_FINGERPRINT_LOCKOUT);
             // TODO: confirm security token when we move timeout management into the HAL layer.
-            mHandler.post(mLockoutReset);
+            mHandler.post(mResetFailedAttemptsRunnable);
         }
 
         @Override