summaryrefslogtreecommitdiffstats
path: root/core/java/com/android
diff options
context:
space:
mode:
authorRowan Decker <smasher816@gmail.com>2012-12-17 19:44:38 +0100
committerRowan Decker <smasher816@gmail.com>2012-12-30 19:22:59 +0100
commit9f1827b6358cd490116549ad1c447da16544c226 (patch)
tree4c7ccaaf2b1ea4b6d6fac7b912bd1adcac92b20a /core/java/com/android
parent6e7ad8adea65fdb92fa0838aba038f5561f83135 (diff)
downloadframeworks_base-9f1827b6358cd490116549ad1c447da16544c226.zip
frameworks_base-9f1827b6358cd490116549ad1c447da16544c226.tar.gz
frameworks_base-9f1827b6358cd490116549ad1c447da16544c226.tar.bz2
Framwork: Add support for variable size pattern lockscreen (Part 1/2)
Part 2: http://review.cyanogenmod.org/#/c/28534/2 Forward port of: http://review.cyanogenmod.org/#/c/20613/ The default size has been replaced with a constant PATTERN_SIZE_DEFAULT=3 It now parses the longInt as a byte, no longer requiring a get/set Int function. Negative numbers and sizes over 127 do not make sense, so a byte works well. In addition the logging has been removed. Patch Set 1-2: Initial port Patch Set 3-5: New implementation using seperate file for non standard sizes Patch Set 6: Use AOSP code style Patch Set 7-9: Remove static code Patch Set 10: Correct a comment Change-Id: Ia06fc5a7dc2819f78843fddcf1470d85ebe2ad13
Diffstat (limited to 'core/java/com/android')
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl1
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java40
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java143
-rw-r--r--core/java/com/android/internal/widget/LockSettingsService.java33
4 files changed, 157 insertions, 60 deletions
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index c72c770..59a21fc 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -24,6 +24,7 @@ interface ILockSettings {
boolean getBoolean(in String key, in boolean defaultValue, in int userId);
long getLong(in String key, in long defaultValue, in int userId);
String getString(in String key, in String defaultValue, in int userId);
+ byte getLockPatternSize(int userId);
void setLockPattern(in byte[] hash, int userId);
boolean checkPattern(in byte[] hash, int userId);
void setLockPassword(in byte[] hash, int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 5453a0b..797b58f 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -103,6 +103,11 @@ public class LockPatternUtils {
public static final int MIN_LOCK_PATTERN_SIZE = 4;
/**
+ * The default size of the pattern lockscreen. Ex: 3x3
+ */
+ public static final byte PATTERN_SIZE_DEFAULT = 3;
+
+ /**
* The minimum number of dots the user must include in a wrong pattern
* attempt for it to be counted against the counts that affect
* {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
@@ -515,7 +520,7 @@ public class LockPatternUtils {
*/
public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
// Compute the hash
- final byte[] hash = LockPatternUtils.patternToHash(pattern);
+ final byte[] hash = patternToHash(pattern);
try {
getLockSettings().setLockPattern(hash, getCurrentOrCallingUserId());
DevicePolicyManager dpm = getDevicePolicyManager();
@@ -759,13 +764,16 @@ public class LockPatternUtils {
* @param string The pattern serialized with {@link #patternToString}
* @return The pattern.
*/
- public static List<LockPatternView.Cell> stringToPattern(String string) {
+ public List<LockPatternView.Cell> stringToPattern(String string) {
List<LockPatternView.Cell> result = Lists.newArrayList();
+ final byte size = getLockPatternSize();
+ LockPatternView.Cell.updateSize(size);
+
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 / size, b % size, size));
}
return result;
}
@@ -775,7 +783,7 @@ public class LockPatternUtils {
* @param pattern The pattern.
* @return The pattern in string form.
*/
- public static String patternToString(List<LockPatternView.Cell> pattern) {
+ public String patternToString(List<LockPatternView.Cell> pattern) {
if (pattern == null) {
return "";
}
@@ -784,7 +792,7 @@ public class LockPatternUtils {
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() * getLockPatternSize() + cell.getColumn());
}
return new String(res);
}
@@ -796,7 +804,7 @@ public class LockPatternUtils {
* @param pattern the gesture pattern.
* @return the hash of the pattern in a byte array.
*/
- private static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
+ private byte[] patternToHash(List<LockPatternView.Cell> pattern) {
if (pattern == null) {
return null;
}
@@ -805,7 +813,7 @@ public class LockPatternUtils {
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() * getLockPatternSize() + cell.getColumn());
}
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
@@ -974,6 +982,24 @@ public class LockPatternUtils {
}
/**
+ * @return the pattern lockscreen size
+ */
+ public byte getLockPatternSize() {
+ try {
+ return getLockSettings().getLockPatternSize(getCurrentOrCallingUserId());
+ } catch (RemoteException re) {
+ return PATTERN_SIZE_DEFAULT;
+ }
+ }
+
+ /**
+ * Set the pattern lockscreen size
+ */
+ public void setLockPatternSize(long size) {
+ setLong(Settings.Secure.LOCK_PATTERN_SIZE, size);
+ }
+
+ /**
* 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.
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 7a76ab0..703f544 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -38,13 +38,14 @@ import android.view.View;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.R;
+import com.android.internal.widget.LockPatternUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Displays and detects the user's unlock attempt, which is a drag of a finger
- * across 9 regions of the screen.
+ * across regions of the screen.
*
* Is also capable of displaying a static pattern in "in progress", "wrong" or
* "correct" states.
@@ -72,8 +73,10 @@ public class LockPatternView extends View {
*/
private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
+ private byte mPatternSize = LockPatternUtils.PATTERN_SIZE_DEFAULT;
+
private OnPatternListener mOnPatternListener;
- private ArrayList<Cell> mPattern = new ArrayList<Cell>(9);
+ private ArrayList<Cell> mPattern = new ArrayList<Cell>(mPatternSize * mPatternSize);
/**
* Lookup table for the circles of the pattern we are currently drawing.
@@ -81,7 +84,7 @@ public class LockPatternView extends View {
* 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[mPatternSize][mPatternSize];
/**
* the in progress point:
@@ -125,30 +128,27 @@ public class LockPatternView extends View {
private final Matrix mArrowMatrix = new Matrix();
private final Matrix mCircleMatrix = new Matrix();
+ private LockPatternUtils mLockPatternUtils;
/**
- * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
+ * Represents a cell in the 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
+ 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(LockPatternUtils.PATTERN_SIZE_DEFAULT);
}
/**
* @param row The row of the cell.
* @param column The column of the cell.
*/
- private Cell(int row, int column) {
- checkRange(row, column);
+ private Cell(int row, int column, byte size) {
+ checkRange(row, column, size);
this.row = row;
this.column = column;
}
@@ -165,17 +165,26 @@ public class LockPatternView extends View {
* @param row The row of the cell.
* @param column The column of the cell.
*/
- public static synchronized Cell of(int row, int column) {
- checkRange(row, column);
+ public static synchronized Cell of(int row, int column, byte size) {
+ checkRange(row, column, size);
return sCells[row][column];
}
- private static void checkRange(int row, int column) {
- if (row < 0 || row > 2) {
- throw new IllegalArgumentException("row must be in range 0-2");
+ public static void updateSize(byte size) {
+ sCells = new Cell[size][size];
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < size; j++) {
+ sCells[i][j] = new Cell(i, j, size);
+ }
+ }
+ }
+
+ private static void checkRange(int row, int column, byte size) {
+ if (row < 0 || row > size - 1) {
+ throw new IllegalArgumentException("row must be in range 0-" + (size - 1));
}
- if (column < 0 || column > 2) {
- throw new IllegalArgumentException("column must be in range 0-2");
+ if (column < 0 || column > size - 1) {
+ throw new IllegalArgumentException("column must be in range 0-" + (size - 1));
}
}
@@ -304,6 +313,13 @@ public class LockPatternView extends View {
}
/**
+ * @return the current pattern lockscreen size.
+ */
+ public int getLockPatternSize() {
+ return mPatternSize;
+ }
+
+ /**
* Set whether the view is in stealth mode. If true, there will be no
* visible feedback as the user enters the pattern.
*
@@ -324,6 +340,26 @@ public class LockPatternView extends View {
}
/**
+ * Set the pattern size of the lockscreen
+ *
+ * @param size The pattern size.
+ */
+ public void setLockPatternSize(byte size) {
+ mPatternSize = size;
+ Cell.updateSize(size);
+ mPattern = new ArrayList<Cell>(size * size);
+ mPatternDrawLookup = new boolean[size][size];
+ }
+
+ /**
+ * Set the LockPatternUtil instance used to encode a pattern to a string
+ * @param utils The instance.
+ */
+ public void setLockPatternUtils(LockPatternUtils utils) {
+ mLockPatternUtils = utils;
+ }
+
+ /**
* Set the call back for pattern detection.
* @param onPatternListener The call back.
*/
@@ -420,8 +456,8 @@ public class LockPatternView extends View {
* 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 < mPatternSize; i++) {
+ for (int j = 0; j < mPatternSize; j++) {
mPatternDrawLookup[i][j] = false;
}
}
@@ -445,10 +481,10 @@ public class LockPatternView extends View {
@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) mPatternSize;
final int height = h - mPaddingTop - mPaddingBottom;
- mSquareHeight = height / 3.0f;
+ mSquareHeight = height / (float) mPatternSize;
}
private int resolveMeasured(int measureSpec, int desired)
@@ -471,14 +507,14 @@ public class LockPatternView extends View {
@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 side-by-side target bitmaps
+ return mPatternSize * 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 side-by-side target bitmaps
+ return mPatternSize * mBitmapWidth;
}
@Override
@@ -515,7 +551,6 @@ public class LockPatternView extends View {
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);
@@ -525,21 +560,19 @@ public class LockPatternView extends View {
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, mPatternSize);
+ 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,
@@ -572,7 +605,7 @@ public class LockPatternView extends View {
if (mPatternDrawLookup[rowHit][columnHit]) {
return null;
}
- return Cell.of(rowHit, columnHit);
+ return Cell.of(rowHit, columnHit, mPatternSize);
}
/**
@@ -586,7 +619,7 @@ public class LockPatternView extends View {
float hitSize = squareHeight * mHitFactor;
float offset = mPaddingTop + (squareHeight - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < mPatternSize; i++) {
final float hitTop = offset + squareHeight * i;
if (y >= hitTop && y <= hitTop + hitSize) {
@@ -606,7 +639,7 @@ public class LockPatternView extends View {
float hitSize = squareWidth * mHitFactor;
float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < mPatternSize; i++) {
final float hitLeft = offset + squareWidth * i;
if (x >= hitLeft && x <= hitLeft + hitSize) {
@@ -918,10 +951,10 @@ public class LockPatternView extends View {
final int paddingTop = mPaddingTop;
final int paddingLeft = mPaddingLeft;
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < mPatternSize; 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 < mPatternSize; j++) {
float leftX = paddingLeft + j * squareWidth;
drawCircle(canvas, (int) leftX, (int) topY, drawLookup[i][j]);
}
@@ -1082,8 +1115,8 @@ public class LockPatternView extends View {
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
return new SavedState(superState,
- LockPatternUtils.patternToString(mPattern),
- mPatternDisplayMode.ordinal(),
+ mLockPatternUtils.patternToString(mPattern),
+ mPatternDisplayMode.ordinal(), mPatternSize,
mInputEnabled, mInStealthMode, mEnableHapticFeedback);
}
@@ -1093,8 +1126,9 @@ public class LockPatternView extends View {
super.onRestoreInstanceState(ss.getSuperState());
setPattern(
DisplayMode.Correct,
- LockPatternUtils.stringToPattern(ss.getSerializedPattern()));
+ mLockPatternUtils.stringToPattern(ss.getSerializedPattern()));
mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];
+ mPatternSize = ss.getPatternSize();
mInputEnabled = ss.isInputEnabled();
mInStealthMode = ss.isInStealthMode();
mEnableHapticFeedback = ss.isTactileFeedbackEnabled();
@@ -1107,6 +1141,7 @@ public class LockPatternView extends View {
private final String mSerializedPattern;
private final int mDisplayMode;
+ private final byte mPatternSize;
private final boolean mInputEnabled;
private final boolean mInStealthMode;
private final boolean mTactileFeedbackEnabled;
@@ -1115,10 +1150,12 @@ public class LockPatternView extends View {
* Constructor called from {@link LockPatternView#onSaveInstanceState()}
*/
private SavedState(Parcelable superState, String serializedPattern, int displayMode,
- boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) {
+ byte patternSize, boolean inputEnabled, boolean inStealthMode,
+ boolean tactileFeedbackEnabled) {
super(superState);
mSerializedPattern = serializedPattern;
mDisplayMode = displayMode;
+ mPatternSize = patternSize;
mInputEnabled = inputEnabled;
mInStealthMode = inStealthMode;
mTactileFeedbackEnabled = tactileFeedbackEnabled;
@@ -1131,6 +1168,7 @@ public class LockPatternView extends View {
super(in);
mSerializedPattern = in.readString();
mDisplayMode = in.readInt();
+ mPatternSize = (byte) in.readByte();
mInputEnabled = (Boolean) in.readValue(null);
mInStealthMode = (Boolean) in.readValue(null);
mTactileFeedbackEnabled = (Boolean) in.readValue(null);
@@ -1144,6 +1182,10 @@ public class LockPatternView extends View {
return mDisplayMode;
}
+ public byte getPatternSize() {
+ return mPatternSize;
+ }
+
public boolean isInputEnabled() {
return mInputEnabled;
}
@@ -1161,6 +1203,7 @@ public class LockPatternView extends View {
super.writeToParcel(dest, flags);
dest.writeString(mSerializedPattern);
dest.writeInt(mDisplayMode);
+ dest.writeByte(mPatternSize);
dest.writeValue(mInputEnabled);
dest.writeValue(mInStealthMode);
dest.writeValue(mTactileFeedbackEnabled);
diff --git a/core/java/com/android/internal/widget/LockSettingsService.java b/core/java/com/android/internal/widget/LockSettingsService.java
index 4ecbd16..4973627 100644
--- a/core/java/com/android/internal/widget/LockSettingsService.java
+++ b/core/java/com/android/internal/widget/LockSettingsService.java
@@ -32,6 +32,8 @@ import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.Slog;
+import com.android.internal.widget.LockPatternUtils;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -166,15 +168,38 @@ public class LockSettingsService extends ILockSettings.Stub {
return readFromDb(key, defaultValue, userId);
}
+ @Override
+ public byte getLockPatternSize(int userId) {
+ try {
+ long size = getLong(Settings.Secure.LOCK_PATTERN_SIZE, -1, userId);
+ if (size > 0 && size < 128) {
+ return (byte) size;
+ }
+ } catch (RemoteException re) {
+ //Any invalid size handled below
+ }
+ return LockPatternUtils.PATTERN_SIZE_DEFAULT;
+ }
+
+ private boolean isDefaultSize(int userId) {
+ return getLockPatternSize(userId) == LockPatternUtils.PATTERN_SIZE_DEFAULT;
+ }
+
private String getLockPatternFilename(int userId) {
+ return getLockPatternFilename(userId, isDefaultSize(userId));
+ }
+
+ private String getLockPatternFilename(int userId, boolean defaultSize) {
String dataSystemDirectory =
android.os.Environment.getDataDirectory().getAbsolutePath() +
SYSTEM_DIRECTORY;
+ String patternFile = (defaultSize ? "" : "cm_") + LOCK_PATTERN_FILE;
+
if (userId == 0) {
// Leave it in the same place for user 0
- return dataSystemDirectory + LOCK_PATTERN_FILE;
+ return dataSystemDirectory + patternFile;
} else {
- return new File(Environment.getUserSystemDirectory(userId), LOCK_PATTERN_FILE)
+ return new File(Environment.getUserSystemDirectory(userId), patternFile)
.getAbsolutePath();
}
}
@@ -210,7 +235,9 @@ public class LockSettingsService extends ILockSettings.Stub {
public void setLockPattern(byte[] hash, int userId) throws RemoteException {
checkWritePermission(userId);
- writeFile(getLockPatternFilename(userId), hash);
+ boolean defaultSize = isDefaultSize(userId);
+ writeFile(getLockPatternFilename(userId, defaultSize), hash);
+ writeFile(getLockPatternFilename(userId, !defaultSize), null);
}
@Override