Merge "Strong auth timeout refactor"
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0a7bdbf..80d4a26 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -26,7 +26,6 @@
 import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE;
 import static android.os.BatteryManager.EXTRA_PLUGGED;
 import static android.os.BatteryManager.EXTRA_STATUS;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
 
 import android.app.ActivityManager;
 import android.app.AlarmManager;
@@ -106,12 +105,6 @@
     private static final String ACTION_FACE_UNLOCK_STOPPED
             = "com.android.facelock.FACE_UNLOCK_STOPPED";
 
-    private static final String ACTION_STRONG_AUTH_TIMEOUT =
-            "com.android.systemui.ACTION_STRONG_AUTH_TIMEOUT";
-    private static final String USER_ID = "com.android.systemui.USER_ID";
-
-    private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
-
     // Callback messages
     private static final int MSG_TIME_UPDATE = 301;
     private static final int MSG_BATTERY_UPDATE = 302;
@@ -203,7 +196,6 @@
     private boolean mDeviceInteractive;
     private boolean mScreenOn;
     private SubscriptionManager mSubscriptionManager;
-    private AlarmManager mAlarmManager;
     private List<SubscriptionInfo> mSubscriptionInfo;
     private TrustManager mTrustManager;
     private UserManager mUserManager;
@@ -588,26 +580,12 @@
     }
 
     public void reportSuccessfulStrongAuthUnlockAttempt() {
-        scheduleStrongAuthTimeout();
         if (mFpm != null) {
             byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
             mFpm.resetTimeout(token);
         }
     }
 
-    private void scheduleStrongAuthTimeout() {
-        final DevicePolicyManager dpm =
-                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null,
-                sCurrentUser);
-        Intent intent = new Intent(ACTION_STRONG_AUTH_TIMEOUT);
-        intent.putExtra(USER_ID, sCurrentUser);
-        PendingIntent sender = PendingIntent.getBroadcast(mContext,
-                sCurrentUser, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, sender);
-        notifyStrongAuthStateChanged(sCurrentUser);
-    }
-
     private void notifyStrongAuthStateChanged(int userId) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -723,17 +701,6 @@
         }
     };
 
-    private final BroadcastReceiver mStrongAuthTimeoutReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (ACTION_STRONG_AUTH_TIMEOUT.equals(intent.getAction())) {
-                int userId = intent.getIntExtra(USER_ID, -1);
-                mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, userId);
-                notifyStrongAuthStateChanged(userId);
-            }
-        }
-    };
-
     private final FingerprintManager.LockoutResetCallback mLockoutResetCallback
             = new FingerprintManager.LockoutResetCallback() {
         @Override
@@ -1034,7 +1001,6 @@
     private KeyguardUpdateMonitor(Context context) {
         mContext = context;
         mSubscriptionManager = SubscriptionManager.from(context);
-        mAlarmManager = context.getSystemService(AlarmManager.class);
         mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
         mStrongAuthTracker = new StrongAuthTracker(context);
 
@@ -1094,10 +1060,6 @@
             e.rethrowAsRuntimeException();
         }
 
-        IntentFilter strongAuthTimeoutFilter = new IntentFilter();
-        strongAuthTimeoutFilter.addAction(ACTION_STRONG_AUTH_TIMEOUT);
-        context.registerReceiver(mStrongAuthTimeoutReceiver, strongAuthTimeoutFilter,
-                PERMISSION_SELF, null /* handler */);
         mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
         mTrustManager.registerTrustListener(this);
         mLockPatternUtils = new LockPatternUtils(context);
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 51503c0..2d40e8e 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -1196,9 +1196,11 @@
         VerifyCredentialResponse response = verifyCredential(userId, storedHash, credentialToVerify,
                 hasChallenge, challenge, progressCallback);
 
-        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK
-                && shouldReEnrollBaseZero) {
-            setLockCredentialInternal(credential, storedHash.type, credentialToVerify, userId);
+        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+            mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
+            if (shouldReEnrollBaseZero) {
+                setLockCredentialInternal(credential, storedHash.type, credentialToVerify, userId);
+            }
         }
 
         return response;
diff --git a/services/core/java/com/android/server/LockSettingsStrongAuth.java b/services/core/java/com/android/server/LockSettingsStrongAuth.java
index 551ceb8..1314110 100644
--- a/services/core/java/com/android/server/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/LockSettingsStrongAuth.java
@@ -16,23 +16,30 @@
 
 package com.android.server;
 
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
+
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
 
+import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
+import android.app.admin.DevicePolicyManager;
 import android.app.trust.IStrongAuthTracker;
 import android.content.Context;
+import android.os.Binder;
 import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.Slog;
 import android.util.SparseIntArray;
 
 import java.util.ArrayList;
 
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
-
 /**
  * Keeps track of requests for strong authentication.
  */
@@ -45,12 +52,22 @@
     private static final int MSG_UNREGISTER_TRACKER = 3;
     private static final int MSG_REMOVE_USER = 4;
 
+    private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
+            "LockSettingsStrongAuth.timeoutForUser";
+
     private final ArrayList<IStrongAuthTracker> mStrongAuthTrackers = new ArrayList<>();
     private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
+    private final ArrayMap<Integer, StrongAuthTimeoutAlarmListener>
+            mStrongAuthTimeoutAlarmListenerForUser = new ArrayMap<>();
     private final int mDefaultStrongAuthFlags;
+    private final Context mContext;
+
+    private AlarmManager mAlarmManager;
 
     public LockSettingsStrongAuth(Context context) {
+        mContext = context;
         mDefaultStrongAuthFlags = StrongAuthTracker.getDefaultFlags(context);
+        mAlarmManager = context.getSystemService(AlarmManager.class);
     }
 
     private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
@@ -151,6 +168,46 @@
         requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
     }
 
+    public void reportSuccessfulStrongAuthUnlock(int userId) {
+        scheduleStrongAuthTimeout(userId);
+    }
+
+    private void scheduleStrongAuthTimeout(int userId) {
+        final DevicePolicyManager dpm =
+                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null, userId);
+        // cancel current alarm listener for the user (if there was one)
+        StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
+        if (alarm != null) {
+            mAlarmManager.cancel(alarm);
+        } else {
+            alarm = new StrongAuthTimeoutAlarmListener(userId);
+            mStrongAuthTimeoutAlarmListenerForUser.put(userId, alarm);
+        }
+        // schedule a new alarm listener for the user
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, STRONG_AUTH_TIMEOUT_ALARM_TAG,
+                    alarm, mHandler);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private class StrongAuthTimeoutAlarmListener implements OnAlarmListener {
+
+        private final int mUserId;
+
+        public StrongAuthTimeoutAlarmListener(int userId) {
+            mUserId = userId;
+        }
+
+        @Override
+        public void onAlarm() {
+            requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, mUserId);
+        }
+    }
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {