diff options
author | Rowan Decker <smasher816@gmail.com> | 2012-12-17 19:44:38 +0100 |
---|---|---|
committer | Rowan Decker <smasher816@gmail.com> | 2012-12-30 19:22:59 +0100 |
commit | 9f1827b6358cd490116549ad1c447da16544c226 (patch) | |
tree | 4c7ccaaf2b1ea4b6d6fac7b912bd1adcac92b20a /core/java/com/android | |
parent | 6e7ad8adea65fdb92fa0838aba038f5561f83135 (diff) | |
download | frameworks_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')
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 |