Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Framwork: Add support for variable size pattern lockscreen (Part 1/2)

Changes LockPatternView to use PATTERN_SIZE instead of the hardcoded value '3'.
Adds methods to set and get PATTERN_SIZE via LockPatternUtils and device settings.

With this patch the pattern lockscreen can go from 3x3 to any sane size such as 6x6.
LockPatternView can be taken by itself if settings are not desired, for an easy way to change the hardcoded size.

Patch Set 3: Rebased,
should fix cherry-pick after the "widgets before unlock" commit.

Patch Set 4+5: Fix whitespace
Patch Set 6: Missed one Gremlin. (Fixed for real)

Patch Set 7: Rebased

Patch Set 8: Added missing hide statements

Change-Id: Ibc0d5bfcee9673b1bf049bd69be80d2312602a47
  • Loading branch information...
commit 0f4e7b7602eb7609941ed69e84e3d67259472c4d 1 parent 0f1f6f1
@smasher816 smasher816 authored Gerrit Code Review committed
View
17 core/java/android/provider/Settings.java
@@ -805,6 +805,7 @@ public String getString(ContentResolver cr, String name) {
MOVED_TO_SECURE.add(Secure.LOCK_SHOW_ERROR_PATH);
MOVED_TO_SECURE.add(Secure.LOCK_DOTS_VISIBLE);
MOVED_TO_SECURE.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
+ MOVED_TO_SECURE.add(Secure.LOCK_PATTERN_SIZE);
MOVED_TO_SECURE.add(Secure.LOGGING_ID);
MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_ENABLED);
MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_LAST_UPDATE);
@@ -1358,6 +1359,14 @@ public static void setShowGTalkServiceStatus(ContentResolver cr, boolean flag) {
public static final String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED =
"lock_pattern_tactile_feedback_enabled";
+ /**
+ * @deprecated Use {@link android.provider.Settings.Secure#LOCK_PATTERN_SIZE}
+ * instead
+ * @hide
+ */
+ @Deprecated
+ public static final String LOCK_PATTERN_SIZE =
+ "lock_pattern_size";
/**
* A formatted string of the next alarm that is set, or the empty string
@@ -3113,6 +3122,7 @@ public static void setShowGTalkServiceStatus(ContentResolver cr, boolean flag) {
MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_SHOW_ERROR_PATH);
MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_DOTS_VISIBLE);
MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_SIZE);
MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_BEFORE_UNLOCK);
}
@@ -3598,6 +3608,13 @@ public static final String getBluetoothInputDevicePriorityKey(String address) {
public static final String LOCK_SHOW_ERROR_PATH = "lock_pattern_show_error_path";
/**
+ * Size of pattern lockscreen
+ * @hide
+ */
+ public static final String LOCK_PATTERN_SIZE = "lock_pattern_size";
+
+
+ /**
* This preference allows the device to be locked given time after screen goes off,
* subject to current DeviceAdmin policy limits.
* @hide
View
2  core/java/com/android/internal/widget/ILockSettings.aidl
@@ -20,9 +20,11 @@ package com.android.internal.widget;
interface ILockSettings {
void setBoolean(in String key, in boolean value, in int userId);
void setLong(in String key, in long value, in int userId);
+ void setInteger(in String key, in int value, in int userId);
void setString(in String key, in String value, in int userId);
boolean getBoolean(in String key, in boolean defaultValue, in int userId);
long getLong(in String key, in long defaultValue, in int userId);
+ int getInteger(in String key, in int defaultValue, in int userId);
String getString(in String key, in String defaultValue, in int userId);
void setLockPattern(in byte[] hash, int userId);
boolean checkPattern(in byte[] hash, int userId);
View
50 core/java/com/android/internal/widget/LockPatternUtils.java
@@ -144,6 +144,8 @@
private ILockSettings mLockSettingsService;
private int mCurrentUserId = 0;
+ private static int PATTERN_SIZE = 3;
+
public DevicePolicyManager getDevicePolicyManager() {
if (mDevicePolicyManager == null) {
mDevicePolicyManager =
@@ -704,7 +706,7 @@ public boolean usingBiometricWeak() {
final byte[] bytes = string.getBytes();
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
- result.add(LockPatternView.Cell.of(b / 3, b % 3));
+ result.add(LockPatternView.Cell.of(b / PATTERN_SIZE, b % PATTERN_SIZE));
}
return result;
}
@@ -723,7 +725,7 @@ public static String patternToString(List<LockPatternView.Cell> pattern) {
byte[] res = new byte[patternSize];
for (int i = 0; i < patternSize; i++) {
LockPatternView.Cell cell = pattern.get(i);
- res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
+ res[i] = (byte) (cell.getRow() * PATTERN_SIZE + cell.getColumn());
}
return new String(res);
}
@@ -744,7 +746,7 @@ public static String patternToString(List<LockPatternView.Cell> pattern) {
byte[] res = new byte[patternSize];
for (int i = 0; i < patternSize; i++) {
LockPatternView.Cell cell = pattern.get(i);
- res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
+ res[i] = (byte) (cell.getRow() * PATTERN_SIZE + cell.getColumn());
}
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
@@ -935,6 +937,30 @@ public boolean isShowErrorPath() {
}
/**
+ * @return the pattern lockscreen size
+ */
+ public int getLockPatternSize() {
+ return getInteger(Settings.Secure.LOCK_PATTERN_SIZE, 3);
+ }
+
+ /**
+ * Set the pattern lockscreen size
+ */
+ public void setLockPatternSize(int size) {
+ setInteger(Settings.Secure.LOCK_PATTERN_SIZE, size);
+ PATTERN_SIZE = size;
+ }
+
+ /**
+ * Update PATTERN_SIZE for this LockPatternUtils instance
+ * This must be called before patternToHash, patternToString, etc
+ * will work correctly with a non-standard size
+ */
+ public void updateLockPatternSize() {
+ PATTERN_SIZE = getLockPatternSize();
+ }
+
+ /**
* Set and store the lockout deadline, meaning the user can't attempt his/her unlock
* pattern until the deadline has passed.
* @return the chosen deadline.
@@ -1204,6 +1230,24 @@ private void setLong(String secureSettingKey, long value) {
}
}
+ private int getInteger(String secureSettingKey, int defaultValue) {
+ try {
+ return getLockSettings().getInteger(secureSettingKey, defaultValue,
+ getCurrentOrCallingUserId());
+ } catch (RemoteException re) {
+ return defaultValue;
+ }
+ }
+
+ private void setInteger(String secureSettingKey, int value) {
+ try {
+ getLockSettings().setInteger(secureSettingKey, value, getCurrentOrCallingUserId());
+ } catch (RemoteException re) {
+ // What can we do?
+ Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
+ }
+ }
+
private String getString(String secureSettingKey) {
try {
return getLockSettings().getString(secureSettingKey, null,
View
105 core/java/com/android/internal/widget/LockPatternView.java
@@ -47,7 +47,7 @@
/**
* Displays and detects the user's unlock attempt, which is a drag of a finger
- * across 9 regions of the screen.
+ * across PATTERN_SIZE regions of the screen.
*
* Is also capable of displaying a static pattern in "in progress", "wrong" or
* "correct" states.
@@ -77,7 +77,7 @@
private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
private OnPatternListener mOnPatternListener;
- private ArrayList<Cell> mPattern = new ArrayList<Cell>(9);
+ private ArrayList<Cell> mPattern = new ArrayList<Cell>(PATTERN_SIZE*PATTERN_SIZE);
/**
* Lookup table for the circles of the pattern we are currently drawing.
@@ -85,7 +85,7 @@
* in which case we use this to hold the cells we are drawing for the in
* progress animation.
*/
- private boolean[][] mPatternDrawLookup = new boolean[3][3];
+ private boolean[][] mPatternDrawLookup = new boolean[PATTERN_SIZE][PATTERN_SIZE];
/**
* the in progress point:
@@ -134,22 +134,19 @@
private final Matrix mArrowMatrix = new Matrix();
private final Matrix mCircleMatrix = new Matrix();
+ private static int PATTERN_SIZE = 3;
/**
- * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
+ * Represents a cell in the PATTERN_SIZE X PATTERN_SIZE matrix of the unlock pattern view.
*/
public static class Cell {
int row;
int column;
- // keep # objects limited to 9
- static Cell[][] sCells = new Cell[3][3];
+ // keep # objects limited to PATTERN_SIZE
+ static Cell[][] sCells;
static {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- sCells[i][j] = new Cell(i, j);
- }
- }
+ updateSize();
}
/**
@@ -179,12 +176,21 @@ public static synchronized Cell of(int row, int column) {
return sCells[row][column];
}
+ public static void updateSize() {
+ sCells = new Cell[PATTERN_SIZE][PATTERN_SIZE];
+ for (int i = 0; i < PATTERN_SIZE; i++) {
+ for (int j = 0; j < PATTERN_SIZE; j++) {
+ sCells[i][j] = new Cell(i, j);
+ }
+ }
+ }
+
private static void checkRange(int row, int column) {
- if (row < 0 || row > 2) {
- throw new IllegalArgumentException("row must be in range 0-2");
+ if (row < 0 || row > PATTERN_SIZE-1) {
+ throw new IllegalArgumentException("row must be in range 0-" + (PATTERN_SIZE-1));
}
- if (column < 0 || column > 2) {
- throw new IllegalArgumentException("column must be in range 0-2");
+ if (column < 0 || column > PATTERN_SIZE-1) {
+ throw new IllegalArgumentException("column must be in range 0-" + (PATTERN_SIZE-1));
}
}
@@ -321,6 +327,13 @@ public boolean isTactileFeedbackEnabled() {
}
/**
+ * @return the current pattern lockscreen size
+ */
+ public int getLockPatternSize() {
+ return PATTERN_SIZE;
+ }
+
+ /**
* Set whether the view is in stealth mode. If true, there will be no
* visible feedback as the user enters the pattern.
*
@@ -357,6 +370,18 @@ public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) {
}
/**
+ * Set the PATTERN_SIZE size of the lockscreen
+ *
+ * @param size
+ */
+ public void setLockPatternSize(int size) {
+ PATTERN_SIZE = size;
+ mPattern = new ArrayList<Cell>(PATTERN_SIZE*PATTERN_SIZE);
+ mPatternDrawLookup = new boolean[PATTERN_SIZE][PATTERN_SIZE];
+ Cell.updateSize();
+ }
+
+ /**
* Set the call back for pattern detection.
* @param onPatternListener The call back.
*/
@@ -453,8 +478,8 @@ private void resetPattern() {
* Clear the pattern lookup table.
*/
private void clearPatternDrawLookup() {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
+ for (int i = 0; i < PATTERN_SIZE; i++) {
+ for (int j = 0; j < PATTERN_SIZE; j++) {
mPatternDrawLookup[i][j] = false;
}
}
@@ -478,13 +503,13 @@ public void enableInput() {
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
final int width = w - mPaddingLeft - mPaddingRight;
- mSquareWidth = width / 3.0f;
+ mSquareWidth = width / (float)PATTERN_SIZE;
final int height = h - mPaddingTop - mPaddingBottom;
- mSquareHeight = height / 3.0f;
+ mSquareHeight = height / (float)PATTERN_SIZE;
// Try to set a message size relative to square size
- mMsgPaint.setTextSize(mSquareHeight / 6);
+ mMsgPaint.setTextSize(mSquareHeight / (PATTERN_SIZE*2));
}
private int resolveMeasured(int measureSpec, int desired)
@@ -507,14 +532,14 @@ private int resolveMeasured(int measureSpec, int desired)
@Override
protected int getSuggestedMinimumWidth() {
- // View should be large enough to contain 3 side-by-side target bitmaps
- return 3 * mBitmapWidth;
+ // View should be large enough to contain PATTERN_SIZE side-by-side target bitmaps
+ return PATTERN_SIZE * mBitmapWidth;
}
@Override
protected int getSuggestedMinimumHeight() {
- // View should be large enough to contain 3 side-by-side target bitmaps
- return 3 * mBitmapWidth;
+ // View should be large enough to contain PATTERN_SIZE side-by-side target bitmaps
+ return PATTERN_SIZE * mBitmapWidth;
}
@Override
@@ -551,7 +576,6 @@ private Cell detectAndAddHit(float x, float y) {
if (cell != null) {
// check for gaps in existing pattern
- Cell fillInGapCell = null;
final ArrayList<Cell> pattern = mPattern;
if (!pattern.isEmpty()) {
final Cell lastCell = pattern.get(pattern.size() - 1);
@@ -561,21 +585,19 @@ private Cell detectAndAddHit(float x, float y) {
int fillInRow = lastCell.row;
int fillInColumn = lastCell.column;
- if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) {
- fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1);
- }
-
- if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) {
- fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1);
+ if (!( (dRow!=0) && (dColumn!=0) && (Math.abs(dRow)!=Math.abs(dColumn)) )) {
+ while (true) {
+ fillInRow += Integer.signum(dRow);
+ fillInColumn += Integer.signum(dColumn);
+ if ( (fillInRow==cell.row) && (fillInColumn==cell.column) ) break;
+ Cell fillInGapCell = Cell.of(fillInRow, fillInColumn);
+ if ( !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
+ addCellToPattern(fillInGapCell);
+ }
+ }
}
-
- fillInGapCell = Cell.of(fillInRow, fillInColumn);
}
- if (fillInGapCell != null &&
- !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
- addCellToPattern(fillInGapCell);
- }
addCellToPattern(cell);
if (mEnableHapticFeedback) {
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
@@ -591,6 +613,7 @@ private void addCellToPattern(Cell newCell) {
mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true;
mPattern.add(newCell);
notifyCellAdded();
+ Log.v("SMASHER816", "("+newCell.column+", "+newCell.row+")");
}
// helper method to find which cell a point maps to
@@ -622,7 +645,7 @@ private int getRowHit(float y) {
float hitSize = squareHeight * mHitFactor;
float offset = mPaddingTop + (squareHeight - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < PATTERN_SIZE; i++) {
final float hitTop = offset + squareHeight * i;
if (y >= hitTop && y <= hitTop + hitSize) {
@@ -642,7 +665,7 @@ private int getColumnHit(float x) {
float hitSize = squareWidth * mHitFactor;
float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < PATTERN_SIZE; i++) {
final float hitLeft = offset + squareWidth * i;
if (x >= hitLeft && x <= hitLeft + hitSize) {
@@ -954,10 +977,10 @@ protected void onDraw(Canvas canvas) {
final int paddingTop = mPaddingTop;
final int paddingLeft = mPaddingLeft;
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < PATTERN_SIZE; i++) {
float topY = paddingTop + i * squareHeight;
//float centerY = mPaddingTop + i * mSquareHeight + (mSquareHeight / 2);
- for (int j = 0; j < 3; j++) {
+ for (int j = 0; j < PATTERN_SIZE; j++) {
float leftX = paddingLeft + j * squareWidth;
drawCircle(canvas, (int) leftX, (int) topY, drawLookup[i][j]);
}
View
15 core/java/com/android/internal/widget/LockSettingsService.java
@@ -134,6 +134,13 @@ public void setLong(String key, long value, int userId) throws RemoteException {
}
@Override
+ public void setInteger(String key, int value, int userId) throws RemoteException {
+ checkWritePermission(userId);
+
+ writeToDb(key, Integer.toString(value), userId);
+ }
+
+ @Override
public void setString(String key, String value, int userId) throws RemoteException {
checkWritePermission(userId);
@@ -158,6 +165,14 @@ public long getLong(String key, long defaultValue, int userId) throws RemoteExce
}
@Override
+ public int getInteger(String key, int defaultValue, int userId) throws RemoteException {
+ //checkReadPermission(userId);
+
+ String value = readFromDb(key, null, userId);
+ return TextUtils.isEmpty(value) ? defaultValue : Integer.parseInt(value);
+ }
+
+ @Override
public String getString(String key, String defaultValue, int userId) throws RemoteException {
//checkReadPermission(userId);
View
7 policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -36,7 +36,7 @@
import java.util.List;
/**
- * This is the screen that shows the 9 circle unlock widget and instructs
+ * This is the screen that shows the circle unlock widget and instructs
* the user how to unlock their device, or make an emergency call.
*/
class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient
@@ -197,10 +197,14 @@ private void updateFooter(FooterMode mode) {
// vibrate mode will be the same for the life of this screen
mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
+ mLockPatternView.setLockPatternSize(mLockPatternUtils.getLockPatternSize());
+
// assume normal footer mode for now
updateFooter(FooterMode.Normal);
setFocusableInTouchMode(true);
+
+ mLockPatternUtils.updateLockPatternSize();
}
public void setEnableFallback(boolean state) {
@@ -348,6 +352,7 @@ public void onPatternCellAdded(List<Cell> pattern) {
}
public void onPatternDetected(List<LockPatternView.Cell> pattern) {
+ mLockPatternUtils.updateLockPatternSize();
if (mLockPatternUtils.checkPattern(pattern)) {
mLockPatternView
.setDisplayMode(LockPatternView.DisplayMode.Correct);
Please sign in to comment.
Something went wrong with that request. Please try again.