Merge "Fix 5185505: Add support for weak biometric sensors to lockscreen."

This commit is contained in:
Jim Miller
2011-09-09 00:58:01 -07:00
committed by Android (Google) Code Review
8 changed files with 307 additions and 6 deletions

View File

@@ -150,6 +150,8 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
core/java/com/android/internal/backup/IBackupTransport.aidl \
core/java/com/android/internal/policy/IFaceLockCallback.aidl \
core/java/com/android/internal/policy/IFaceLockInterface.aidl \
core/java/com/android/internal/os/IDropBoxManagerService.aidl \
core/java/com/android/internal/os/IResultReceiver.aidl \
core/java/com/android/internal/statusbar/IStatusBar.aidl \

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.policy;
import android.os.IBinder;
/** {@hide} */
oneway interface IFaceLockCallback {
void unlock();
void cancel();
void sleepDevice();
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.policy;
import android.os.IBinder;
import com.android.internal.policy.IFaceLockCallback;
/** {@hide} */
interface IFaceLockInterface {
void startUi(IBinder containingWindowToken, int x, int y, int width, int height);
void stopUi();
void registerCallback(IFaceLockCallback cb);
}

View File

@@ -106,8 +106,11 @@ public class LockPatternUtils {
private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
private final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
private final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
= "lockscreen.biometric_weak_fallback";
private final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
@@ -373,6 +376,7 @@ public class LockPatternUtils {
setLockPatternEnabled(false);
saveLockPattern(null);
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
}
/**
@@ -400,6 +404,15 @@ public class LockPatternUtils {
* @param pattern The new pattern to save.
*/
public void saveLockPattern(List<LockPatternView.Cell> pattern) {
this.saveLockPattern(pattern, false);
}
/**
* Save a lock pattern.
* @param pattern The new pattern to save.
* @param isFallback Specifies if this is a fallback to biometric weak
*/
public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
// Compute the hash
final byte[] hash = LockPatternUtils.patternToHash(pattern);
try {
@@ -417,7 +430,13 @@ public class LockPatternUtils {
if (pattern != null) {
keyStore.password(patternToString(pattern));
setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
if (!isFallback) {
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
} else {
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
setLong(PASSWORD_TYPE_ALTERNATE_KEY,
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
}
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern
.size(), 0, 0, 0, 0, 0, 0);
} else {
@@ -493,6 +512,18 @@ public class LockPatternUtils {
* @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
*/
public void saveLockPassword(String password, int quality) {
this.saveLockPassword(password, quality, false);
}
/**
* Save a lock password. Does not ensure that the password is as good
* as the requested mode, but will adjust the mode to be as good as the
* pattern.
* @param password The password to save
* @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
* @param isFallback Specifies if this is a fallback to biometric weak
*/
public void saveLockPassword(String password, int quality, boolean isFallback) {
// Compute the hash
final byte[] hash = passwordToHash(password);
try {
@@ -515,7 +546,12 @@ public class LockPatternUtils {
keyStore.password(password);
int computedQuality = computePasswordQuality(password);
setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
if (!isFallback) {
setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
} else {
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality));
}
if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
int letters = 0;
int uppercase = 0;
@@ -590,7 +626,22 @@ public class LockPatternUtils {
* @return stored password quality
*/
public int getKeyguardStoredPasswordQuality() {
return (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
int quality =
(int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
// If the user has chosen to use weak biometric sensor, then return the backup locking
// method and treat biometric as a special case.
if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
quality =
(int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
}
return quality;
}
public boolean usingBiometricWeak() {
int quality =
(int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
}
/**
@@ -725,6 +776,15 @@ public class LockPatternUtils {
== DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
}
/**
* @return Whether biometric weak lock is enabled.
*/
public boolean isBiometricEnabled() {
// TODO: check if it's installed
return getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
== DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
}
/**
* Set whether the lock pattern is enabled.
*/
@@ -863,7 +923,8 @@ public class LockPatternUtils {
|| mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
|| mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
|| isPassword && savedPasswordExists();
|| isPassword && savedPasswordExists()
|| usingBiometricWeak() && isBiometricEnabled();
return secure;
}

View File

@@ -127,6 +127,15 @@ public abstract class KeyguardViewBase extends FrameLayout {
*/
abstract public void cleanUp();
/**
* These were added to support FaceLock because the KeyguardViewManager needs to tell the
* LockPatternKeyguardView when to bind and and unbind with FaceLock service. Although
* implemented in LockPatternKeyguardView, these are not implemented in anything else
* derived from KeyguardViewBase
*/
abstract public void bindToFaceLock();
abstract public void stopAndUnbindFromFaceLock();
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (shouldEventKeepScreenOnWhileKeyguardShowing(event)) {

View File

@@ -31,6 +31,8 @@ import android.view.ViewManager;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.graphics.Color;
/**
* Manages creating, showing, hiding and resetting the keyguard. Calls back
* via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke
@@ -160,6 +162,7 @@ public class KeyguardViewManager implements KeyguardWindowController {
mKeyguardView.onScreenTurnedOn();
}
}
mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
mKeyguardHost.setVisibility(View.VISIBLE);
mKeyguardView.requestFocus();
@@ -195,6 +198,9 @@ public class KeyguardViewManager implements KeyguardWindowController {
if (mKeyguardView != null) {
mKeyguardView.onScreenTurnedOff();
}
// When screen is turned off, need to unbind from FaceLock service if we are using FaceLock
mKeyguardView.stopAndUnbindFromFaceLock();
}
public synchronized void onScreenTurnedOn() {
@@ -203,6 +209,9 @@ public class KeyguardViewManager implements KeyguardWindowController {
if (mKeyguardView != null) {
mKeyguardView.onScreenTurnedOn();
}
// When screen is turned on, need to bind to FaceLock service if we are using FaceLock
mKeyguardView.bindToFaceLock();
}
public synchronized void verifyUnlock() {
@@ -238,6 +247,11 @@ public class KeyguardViewManager implements KeyguardWindowController {
*/
public synchronized void hide() {
if (DEBUG) Log.d(TAG, "hide()");
// When view is hidden, need to unbind from FaceLock service if we are using FaceLock
// e.g., when device becomes unlocked
mKeyguardView.stopAndUnbindFromFaceLock();
if (mKeyguardHost != null) {
mKeyguardHost.setVisibility(View.GONE);
// Don't do this right away, so we can let the view continue to animate

View File

@@ -18,6 +18,8 @@ package com.android.internal.policy.impl;
import com.android.internal.R;
import com.android.internal.policy.impl.LockPatternKeyguardView.UnlockMode;
import com.android.internal.policy.IFaceLockCallback;
import com.android.internal.policy.IFaceLockInterface;
import com.android.internal.telephony.IccCard;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockScreenWidgetCallback;
@@ -32,16 +34,20 @@ import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.telephony.TelephonyManager;
@@ -56,6 +62,7 @@ import android.view.accessibility.AccessibilityManager;
import java.io.IOException;
/**
* The host view for all of the screens of the pattern unlock screen. There are
* two {@link Mode}s of operation, lock and unlock. This will show the appropriate
@@ -93,6 +100,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
private boolean mShowLockBeforeUnlock = false;
// The following were added to support FaceLock
private IFaceLockInterface mFaceLockService;
private boolean mBoundToFaceLockService = false;
private boolean mFaceLockServiceRunning = false;
private View mFaceLockAreaView;
/**
* The current {@link KeyguardScreen} will use this to communicate back to us.
*/
@@ -580,6 +593,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
}
private boolean isSecure() {
// TODO: make this work with SIM and Account cases below.
boolean usingBiometric = mLockPatternUtils.usingBiometricWeak();
if (usingBiometric && mLockPatternUtils.isBiometricEnabled())
return true;
UnlockMode unlockMode = getUnlockMode();
boolean secure = false;
switch (unlockMode) {
@@ -687,6 +704,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
mKeyguardScreenCallback,
mUpdateMonitor.getFailedAttempts());
view.setEnableFallback(mEnableFallback);
// TODO(bcolonna): For pattern unlock, it can give us the view where the pattern is
// displayed and FaceLock can draw in that area.
// For other views it's not so simple and we should probably change how the FaceLock
// area is determined.
mFaceLockAreaView = view.getUnlockAreaView();
unlockView = view;
} else if (unlockMode == UnlockMode.SimPuk) {
unlockView = new SimPukUnlockScreen(
@@ -912,5 +935,142 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
return mBitmap.getHeight();
}
}
}
// Everything below pertains to FaceLock - might want to separate this out
// Binds to FaceLock service, but does not tell it to start
public void bindToFaceLock() {
if (mLockPatternUtils.usingBiometricWeak()) {
if (!mBoundToFaceLockService) {
if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
mContext.bindService(new Intent(IFaceLockInterface.class.getName()),
mFaceLockConnection,
Context.BIND_AUTO_CREATE);
if (DEBUG) Log.d(TAG, "after bind to FaceLock service");
mBoundToFaceLockService = true;
} else {
// On startup I've seen onScreenTurnedOn() get called twice without
// onScreenTurnedOff() being called in between, which can cause this (bcolonna)
if (DEBUG) Log.w(TAG, "Attempt to bind to FaceLock when already bound");
}
}
}
// Tells FaceLock to stop and then unbinds from the FaceLock service
public void stopAndUnbindFromFaceLock() {
if (mLockPatternUtils.usingBiometricWeak()) {
stopFaceLock();
if (mBoundToFaceLockService) {
if (DEBUG) Log.d(TAG, "before unbind from FaceLock service");
mContext.unbindService(mFaceLockConnection);
if (DEBUG) Log.d(TAG, "after unbind from FaceLock service");
mBoundToFaceLockService = false;
} else {
// This could probably happen after the session when someone activates FaceLock
// because it wasn't active when the phone was turned on
if (DEBUG) Log.w(TAG, "Attempt to unbind from FaceLock when not bound");
}
}
}
private ServiceConnection mFaceLockConnection = new ServiceConnection() {
// Completes connection, registers callback and starts FaceLock when service is bound
@Override
public void onServiceConnected(ComponentName className, IBinder iservice) {
mFaceLockService = IFaceLockInterface.Stub.asInterface(iservice);
if (DEBUG) Log.d(TAG, "Connected to FaceLock service");
try {
mFaceLockService.registerCallback(mFaceLockCallback);
} catch (RemoteException e) {
throw new RuntimeException("Remote exception");
}
// TODO(bcolonna): Need to set location properly (only works for pattern view now)
if (mFaceLockAreaView != null) {
int[] unlockLocationOnScreen = new int[2];
mFaceLockAreaView.getLocationOnScreen(unlockLocationOnScreen);
int x = unlockLocationOnScreen[0];
int y = unlockLocationOnScreen[1];
int w = mFaceLockAreaView.getWidth();
int h = mFaceLockAreaView.getHeight();
if (DEBUG) Log.d(TAG, "(x,y) (wxh): (" + x + "," + y + ") (" + w + "x" + h + ")");
startFaceLock(mFaceLockAreaView.getWindowToken(), x, y, w, h);
}
}
// Cleans up if FaceLock service unexpectedly disconnects
@Override
public void onServiceDisconnected(ComponentName className) {
mFaceLockService = null;
if (DEBUG) Log.w(TAG, "Unexpected disconnect from FaceLock service");
}
};
// Tells the FaceLock service to start displaying its UI and perform recognition
public void startFaceLock(IBinder windowToken, int x, int y, int h, int w)
{
if (mLockPatternUtils.usingBiometricWeak()) {
if (!mFaceLockServiceRunning) {
if (DEBUG) Log.d(TAG, "Starting FaceLock");
try {
mFaceLockService.startUi(windowToken, x, y, h, w);
} catch (RemoteException e) {
throw new RuntimeException("Remote exception");
}
mFaceLockServiceRunning = true;
} else {
if (DEBUG) Log.w(TAG, "startFaceLock() attempted while running");
}
}
}
// Tells the FaceLock service to stop displaying its UI and stop recognition
public void stopFaceLock()
{
if (mLockPatternUtils.usingBiometricWeak()) {
// Note that attempting to stop FaceLock when it's not running is not an issue.
// FaceLock can return, which stops it and then we try to stop it when the
// screen is turned off. That's why we check.
if (mFaceLockServiceRunning) {
try {
if (DEBUG) Log.d(TAG, "Stopping FaceLock");
mFaceLockService.stopUi();
} catch (RemoteException e) {
throw new RuntimeException("Remote exception");
}
mFaceLockServiceRunning = false;
}
}
}
// Implements the FaceLock service callback interface defined in AIDL
private final IFaceLockCallback mFaceLockCallback = new IFaceLockCallback.Stub() {
// Stops the FaceLock UI and indicates that the phone should be unlocked
@Override
public void unlock() {
if (DEBUG) Log.d(TAG, "FaceLock unlock");
stopFaceLock();
mKeyguardScreenCallback.keyguardDone(true);
mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
}
// Stops the FaceLock UI and exposes the backup method without unlocking
@Override
public void cancel() {
// In this case, either the user has cancelled out, or FaceLock failed to recognize them
if (DEBUG) Log.d(TAG, "FaceLock cancel");
stopFaceLock();
}
// Stops the FaceLock UI and puts the phone to sleep
@Override
public void sleepDevice() {
// In this case, it appears the phone has been turned on accidentally
if (DEBUG) Log.d(TAG, "FaceLock accidental turn on");
stopFaceLock();
// TODO(bcolonna): how do we put the phone back to sleep (i.e., turn off the screen)
}
};
}

View File

@@ -199,7 +199,11 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient
setFocusableInTouchMode(true);
}
// TODO(bcolonna): This is to tell FaceLock where to draw...but this covers up the wireless
// service text, so we will want to change the way the area is specified
public View getUnlockAreaView() {
return mLockPatternView;
}
public void setEnableFallback(boolean state) {
if (DEBUG) Log.d(TAG, "setEnableFallback(" + state + ")");