summaryrefslogtreecommitdiffstats
path: root/packages/Keyguard
diff options
context:
space:
mode:
authorJorim Jaggi <jjaggi@google.com>2015-08-13 01:09:21 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2015-08-13 01:09:21 +0000
commitdeb6a3acbdbf81a995cc3c1eb2475b041564d44d (patch)
tree7e99b0056b85682e7d05f57942566b93b56dc9e8 /packages/Keyguard
parent40bc20660d3dc65f66e4409893f1ba6bf729d97f (diff)
parent73d9e1ce0bc8e4478b165fd5f550c99830fbcb57 (diff)
downloadframeworks_base-deb6a3acbdbf81a995cc3c1eb2475b041564d44d.zip
frameworks_base-deb6a3acbdbf81a995cc3c1eb2475b041564d44d.tar.gz
frameworks_base-deb6a3acbdbf81a995cc3c1eb2475b041564d44d.tar.bz2
am 73d9e1ce: am 69082a29: Merge "Require strong authentication after a timeout" into mnc-dr-dev
* commit '73d9e1ce0bc8e4478b165fd5f550c99830fbcb57': Require strong authentication after a timeout
Diffstat (limited to 'packages/Keyguard')
-rw-r--r--packages/Keyguard/res/values/strings.xml9
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java40
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java2
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java5
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java2
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java13
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java9
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java74
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java6
-rw-r--r--packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java19
10 files changed, 132 insertions, 47 deletions
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 41b1059..d1e84f5 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -316,6 +316,15 @@
<!-- An explanation text that the password needs to be entered since the device has just been restarted. [CHAR LIMIT=80] -->
<string name="kg_prompt_reason_restart_password">Password required when you restart device.</string>
+ <!-- An explanation text that the pattern needs to be solved since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_timeout_pattern">Pattern required for additional security.</string>
+
+ <!-- An explanation text that the pin needs to be entered since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_timeout_pin">PIN required for additional security.</string>
+
+ <!-- An explanation text that the password needs to be entered since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_timeout_password">Password required for additional security.</string>
+
<!-- An explanation text that the pattern needs to be solved since profiles have just been switched. [CHAR LIMIT=80] -->
<string name="kg_prompt_reason_switch_profiles_pattern">Pattern required when you switch profiles.</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 32892cf..ec2a173 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -163,8 +163,9 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
* Show a string explaining why the security view needs to be solved.
*
* @param reason a flag indicating which string should be shown, see
- * {@link KeyguardSecurityView#PROMPT_REASON_NONE}
- * and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
+ * {@link KeyguardSecurityView#PROMPT_REASON_NONE},
+ * {@link KeyguardSecurityView#PROMPT_REASON_RESTART} and
+ * {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}.
*/
public void showPromptReason(int reason) {
mSecurityContainer.showPromptReason(reason);
@@ -213,9 +214,12 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
/**
* Authentication has happened and it's time to dismiss keyguard. This function
* should clean up and inform KeyguardViewMediator.
+ *
+ * @param strongAuth whether the user has authenticated with strong authentication like
+ * pattern, password or PIN but not by trust agents or fingerprint
*/
@Override
- public void finish() {
+ public void finish(boolean strongAuth) {
// If there's a pending runnable because the user interacted with a widget
// and we're leaving keyguard, then run it.
boolean deferKeyguardDone = false;
@@ -226,9 +230,9 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
}
if (mViewMediatorCallback != null) {
if (deferKeyguardDone) {
- mViewMediatorCallback.keyguardDonePending();
+ mViewMediatorCallback.keyguardDonePending(strongAuth);
} else {
- mViewMediatorCallback.keyguardDone(true);
+ mViewMediatorCallback.keyguardDone(strongAuth);
}
}
}
@@ -285,32 +289,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
}
/**
- * Verify that the user can get past the keyguard securely. This is called,
- * for example, when the phone disables the keyguard but then wants to launch
- * something else that requires secure access.
- *
- * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)}
- */
- public void verifyUnlock() {
- SecurityMode securityMode = mSecurityContainer.getSecurityMode();
- if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
- if (mViewMediatorCallback != null) {
- mViewMediatorCallback.keyguardDone(true);
- }
- } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
- && securityMode != KeyguardSecurityModel.SecurityMode.PIN
- && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
- // can only verify unlock when in pattern/password mode
- if (mViewMediatorCallback != null) {
- mViewMediatorCallback.keyguardDone(false);
- }
- } else {
- // otherwise, go to the unlock screen, see if they can verify it
- mSecurityContainer.verifyUnlock();
- }
- }
-
- /**
* Called before this view is being removed.
*/
public void cleanUp() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
index 2db87b3..3a7e6d0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -115,6 +115,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
switch (reason) {
case PROMPT_REASON_RESTART:
return R.string.kg_prompt_reason_restart_password;
+ case PROMPT_REASON_TIMEOUT:
+ return R.string.kg_prompt_reason_timeout_password;
default:
return 0;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index a96c79f..9a91ca4 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -332,7 +332,12 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_restart_pattern,
true /* important */);
break;
+ case PROMPT_REASON_TIMEOUT:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern,
+ true /* important */);
+ break;
default:
+ break;
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 07947b1..4cd4845 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -98,6 +98,8 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
switch (reason) {
case PROMPT_REASON_RESTART:
return R.string.kg_prompt_reason_restart_pin;
+ case PROMPT_REASON_TIMEOUT:
+ return R.string.kg_prompt_reason_timeout_pin;
default:
return 0;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 8fc3cde..77215a7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -54,7 +54,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
public boolean dismiss(boolean authenticated);
public void userActivity();
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
- public void finish();
+
+ /**
+ * @param strongAuth wheher the user has authenticated with strong authentication like
+ * pattern, password or PIN but not by trust agents or fingerprint
+ */
+ public void finish(boolean strongAuth);
public void reset();
}
@@ -282,7 +287,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
showWipeDialog(failedAttempts, userType);
}
}
- monitor.reportFailedUnlockAttempt();
+ monitor.reportFailedStrongAuthUnlockAttempt();
mLockPatternUtils.reportFailedPasswordAttempt(KeyguardUpdateMonitor.getCurrentUser());
if (timeoutMs > 0) {
showTimeoutDialog(timeoutMs);
@@ -308,6 +313,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
boolean showNextSecurityScreenOrFinish(boolean authenticated) {
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
boolean finish = false;
+ boolean strongAuth = false;
if (mUpdateMonitor.getUserCanSkipBouncer(
KeyguardUpdateMonitor.getCurrentUser())) {
finish = true;
@@ -323,6 +329,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
case Pattern:
case Password:
case PIN:
+ strongAuth = true;
finish = true;
break;
@@ -346,7 +353,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
}
}
if (finish) {
- mSecurityCallback.finish();
+ mSecurityCallback.finish(strongAuth);
}
return finish;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
index 7e82c63..38302fb 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
@@ -22,9 +22,18 @@ public interface KeyguardSecurityView {
static public final int VIEW_REVEALED = 2;
int PROMPT_REASON_NONE = 0;
+
+ /**
+ * Strong auth is required because the device has just booted.
+ */
int PROMPT_REASON_RESTART = 1;
/**
+ * Strong auth is required because the user hasn't used strong auth since a while.
+ */
+ int PROMPT_REASON_TIMEOUT = 2;
+
+ /**
* Interface back to keyguard to tell it when security
* @param callback
*/
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0ee68fd..3232f65 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -64,6 +64,7 @@ import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
+import android.util.ArraySet;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
@@ -103,6 +104,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
= "com.android.facelock.FACE_UNLOCK_STOPPED";
private static final String FINGERPRINT_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
+ 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";
+
/**
* Mode in which we don't need to wake up the device when we get a fingerprint.
*/
@@ -126,6 +133,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
* */
private static final int FP_ONLY_WAKE = 3;
+ /**
+ * Milliseconds after unlocking with fingerprint times out, i.e. the user has to use a
+ * strong auth method like password, PIN or pattern.
+ */
+ private static final long FINGERPRINT_UNLOCK_TIMEOUT_MS = 72 * 60 * 60 * 1000;
+
// Callback messages
private static final int MSG_TIME_UPDATE = 301;
private static final int MSG_BATTERY_UPDATE = 302;
@@ -173,7 +186,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
// Password attempts
private SparseIntArray mFailedAttempts = new SparseIntArray();
- private boolean mClockVisible;
+ /** Tracks whether strong authentication hasn't been used since quite some time per user. */
+ private ArraySet<Integer> mStrongAuthTimedOut = new ArraySet<>();
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
mCallbacks = Lists.newArrayList();
@@ -184,6 +198,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private boolean mDeviceInteractive;
private boolean mScreenOn;
private SubscriptionManager mSubscriptionManager;
+ private AlarmManager mAlarmManager;
private List<SubscriptionInfo> mSubscriptionInfo;
private boolean mFingerprintDetectionRunning;
private TrustManager mTrustManager;
@@ -549,7 +564,39 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
public boolean isUnlockingWithFingerprintAllowed() {
- return mUserHasAuthenticatedSinceBoot;
+ return mUserHasAuthenticatedSinceBoot && !hasFingerprintUnlockTimedOut(sCurrentUser);
+ }
+
+ /**
+ * @return true if the user hasn't use strong authentication (pattern, PIN, password) since a
+ * while and thus can't unlock with fingerprint, false otherwise
+ */
+ public boolean hasFingerprintUnlockTimedOut(int userId) {
+ return mStrongAuthTimedOut.contains(userId);
+ }
+
+ public void reportSuccessfulStrongAuthUnlockAttempt() {
+ mStrongAuthTimedOut.remove(sCurrentUser);
+ scheduleStrongAuthTimeout();
+ }
+
+ private void scheduleStrongAuthTimeout() {
+ long when = SystemClock.elapsedRealtime() + FINGERPRINT_UNLOCK_TIMEOUT_MS;
+ 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);
+ notifyStrongAuthTimedOutChanged(sCurrentUser);
+ }
+
+ private void notifyStrongAuthTimedOutChanged(int userId) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onStrongAuthTimeoutExpiredChanged(userId);
+ }
+ }
}
static class DisplayClientState {
@@ -639,6 +686,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
};
+ 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);
+ mStrongAuthTimedOut.add(userId);
+ notifyStrongAuthTimedOutChanged(userId);
+ }
+ }
+ };
+
private FingerprintManager.AuthenticationCallback mAuthenticationCallback
= new AuthenticationCallback() {
@@ -871,7 +929,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mContext = context;
mSubscriptionManager = SubscriptionManager.from(context);
mPowerManager = context.getSystemService(PowerManager.class);
+ mAlarmManager = context.getSystemService(AlarmManager.class);
mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
+
// Since device can't be un-provisioned, we only need to register a content observer
// to update mDeviceProvisioned when we are...
if (!mDeviceProvisioned) {
@@ -932,6 +992,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
e.printStackTrace();
}
+ 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);
@@ -955,7 +1019,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private void startListeningForFingerprint() {
if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
int userId = ActivityManager.getCurrentUser();
- if (isUnlockWithFingerPrintPossible(userId)) {
+ if (isUnlockWithFingerprintPossible(userId)) {
mUserHasAuthenticatedSinceBoot = mTrustManager.hasUserAuthenticatedSinceBoot(
ActivityManager.getCurrentUser());
if (mFingerprintCancelSignal != null) {
@@ -967,7 +1031,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
- public boolean isUnlockWithFingerPrintPossible(int userId) {
+ public boolean isUnlockWithFingerprintPossible(int userId) {
return mFpm != null && mFpm.isHardwareDetected() && !isFingerprintDisabled(userId)
&& mFpm.getEnrolledFingerprints(userId).size() > 0;
}
@@ -1433,7 +1497,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
return mFailedAttempts.get(sCurrentUser, 0);
}
- public void reportFailedUnlockAttempt() {
+ public void reportFailedStrongAuthUnlockAttempt() {
mFailedAttempts.put(sCurrentUser, getFailedUnlockAttempts() + 1);
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 6cda2b7..52412f7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -217,4 +217,10 @@ public class KeyguardUpdateMonitorCallback {
* Called when the fingerprint running state changed.
*/
public void onFingerprintRunningStateChanged(boolean running) { }
+
+ /**
+ * Called when the state that the user hasn't used strong authentication since quite some time
+ * has changed.
+ */
+ public void onStrongAuthTimeoutExpiredChanged(int userId) { }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
index ff463c6..8ab3011 100644
--- a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
@@ -28,12 +28,11 @@ public interface ViewMediatorCallback {
/**
* Report that the keyguard is done.
- * @param authenticated Whether the user securely got past the keyguard.
- * the only reason for this to be false is if the keyguard was instructed
- * to appear temporarily to verify the user is supposed to get past the
- * keyguard, and the user fails to do so.
+ *
+ * @param strongAuth whether the user has authenticated with strong authentication like
+ * pattern, password or PIN but not by trust agents or fingerprint
*/
- void keyguardDone(boolean authenticated);
+ void keyguardDone(boolean strongAuth);
/**
* Report that the keyguard is done drawing.
@@ -48,8 +47,11 @@ public interface ViewMediatorCallback {
/**
* Report that the keyguard is dismissable, pending the next keyguardDone call.
+ *
+ * @param strongAuth whether the user has authenticated with strong authentication like
+ * pattern, password or PIN but not by trust agents or fingerprint
*/
- void keyguardDonePending();
+ void keyguardDonePending(boolean strongAuth);
/**
* Report when keyguard is actually gone
@@ -85,8 +87,9 @@ public interface ViewMediatorCallback {
/**
* @return one of the reasons why the bouncer needs to be shown right now and the user can't use
* his normal unlock method like fingerprint or trust agents. See
- * {@link KeyguardSecurityView#PROMPT_REASON_NONE}
- * and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}.
+ * {@link KeyguardSecurityView#PROMPT_REASON_NONE},
+ * {@link KeyguardSecurityView#PROMPT_REASON_RESTART} and
+ * {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}.
*/
int getBouncerPromptReason();
}