summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Bestas <mikeioannina@gmail.com>2015-04-03 14:33:37 -0700
committerRoman Birg <roman@cyngn.com>2015-12-11 11:42:41 -0600
commit0cf7d4373afc1bbc0b9a42954d6dbd162aa361a4 (patch)
tree307f858411925cd08f8edf6fd848d3986d4aab43
parenta037ad401e4a78ce22a9ec2dada8ff3593aa8fa4 (diff)
downloadframeworks_base-0cf7d4373afc1bbc0b9a42954d6dbd162aa361a4.zip
frameworks_base-0cf7d4373afc1bbc0b9a42954d6dbd162aa361a4.tar.gz
frameworks_base-0cf7d4373afc1bbc0b9a42954d6dbd162aa361a4.tar.bz2
Forward port CM Screen Security settings (1/2)
* Variable size pattern lockscreen * Toggle dots/error pattern visibility Change-Id: Ie109e82c1fb2fd96b07e977e1cd76ae3acb865ff
-rw-r--r--core/java/android/provider/Settings.java21
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl1
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java65
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java209
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java6
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java5
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java13
-rw-r--r--services/core/java/com/android/server/LockSettingsStorage.java23
8 files changed, 271 insertions, 72 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a3de3d1..e107fd1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4004,6 +4004,9 @@ public final class Settings {
MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_ENABLED);
MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_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_DOTS_VISIBLE);
+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_SHOW_ERROR_PATH);
MOVED_TO_GLOBAL = new HashSet<String>();
MOVED_TO_GLOBAL.add(Settings.Global.ADB_ENABLED);
@@ -4774,6 +4777,24 @@ public final class Settings {
LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
/**
+ * Determines the width and height of the LockPatternView widget
+ * @hide
+ */
+ public static final String LOCK_PATTERN_SIZE = "lock_pattern_size";
+
+ /**
+ * Whether lock pattern will show dots (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String LOCK_DOTS_VISIBLE = "lock_pattern_dotsvisible";
+
+ /**
+ * Whether lockscreen error pattern is visible (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String LOCK_SHOW_ERROR_PATH = "lock_pattern_show_error_path";
+
+ /**
* This preference allows the device to be locked given time after screen goes off,
* subject to current DeviceAdmin policy limits.
* @hide
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 00e41bd..cc951a5 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -33,6 +33,7 @@ interface ILockSettings {
void setLockPassword(in String password, in String savedPassword, int userId);
VerifyCredentialResponse checkPassword(in String password, int userId);
VerifyCredentialResponse verifyPassword(in String password, long challenge, int userId);
+ byte getLockPatternSize(int userId);
boolean checkVoldPassword(int userId);
boolean havePattern(int userId);
boolean havePassword(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 345b99f..5e5f039 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -91,6 +91,11 @@ public class LockPatternUtils {
*/
public static final int MIN_LOCK_PASSWORD_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
@@ -847,17 +852,18 @@ public class LockPatternUtils {
* @param string The pattern serialized with {@link #patternToString}
* @return The pattern.
*/
- public static List<LockPatternView.Cell> stringToPattern(String string) {
+ public static List<LockPatternView.Cell> stringToPattern(String string, byte gridSize) {
if (string == null) {
return null;
}
-
List<LockPatternView.Cell> result = Lists.newArrayList();
+ LockPatternView.Cell.updateSize(gridSize);
+
final byte[] bytes = string.getBytes();
for (int i = 0; i < bytes.length; i++) {
byte b = (byte) (bytes[i] - '1');
- result.add(LockPatternView.Cell.of(b / 3, b % 3));
+ result.add(LockPatternView.Cell.of(b / gridSize, b % gridSize, gridSize));
}
return result;
}
@@ -867,16 +873,26 @@ 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) {
+ return patternToString(pattern, getLockPatternSize());
+ }
+
+ /**
+ * Serialize a pattern.
+ * @param pattern The pattern.
+ * @return The pattern in string form.
+ */
+ public static String patternToString(List<LockPatternView.Cell> pattern, byte gridSize) {
if (pattern == null) {
return "";
}
final int patternSize = pattern.size();
+ LockPatternView.Cell.updateSize(gridSize);
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() + '1');
+ res[i] = (byte) (cell.getRow() * gridSize + cell.getColumn() + '1');
}
return new String(res);
}
@@ -886,7 +902,6 @@ public class LockPatternUtils {
return "";
}
final int patternSize = pattern.length();
-
byte[] res = new byte[patternSize];
final byte[] bytes = pattern.getBytes();
for (int i = 0; i < patternSize; i++) {
@@ -902,7 +917,7 @@ public class LockPatternUtils {
* @param pattern the gesture pattern.
* @return the hash of the pattern in a byte array.
*/
- public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
+ public static byte[] patternToHash(List<LockPatternView.Cell> pattern, byte gridSize) {
if (pattern == null) {
return null;
}
@@ -911,7 +926,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() * gridSize + cell.getColumn());
}
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
@@ -1065,6 +1080,40 @@ public class LockPatternUtils {
}
/**
+ * @return the pattern lockscreen size
+ */
+ public byte getLockPatternSize() {
+ long size = getLong(Settings.Secure.LOCK_PATTERN_SIZE, -1, UserHandle.USER_CURRENT);
+ if (size > 0 && size < 128) {
+ return (byte) size;
+ }
+ return LockPatternUtils.PATTERN_SIZE_DEFAULT;
+ }
+
+ /**
+ * Set the pattern lockscreen size
+ */
+ public void setLockPatternSize(long size) {
+ setLong(Settings.Secure.LOCK_PATTERN_SIZE, size, UserHandle.USER_CURRENT);
+ }
+
+ public void setVisibleDotsEnabled(boolean enabled) {
+ setBoolean(Settings.Secure.LOCK_DOTS_VISIBLE, enabled, UserHandle.USER_CURRENT);
+ }
+
+ public boolean isVisibleDotsEnabled() {
+ return getBoolean(Settings.Secure.LOCK_DOTS_VISIBLE, true, UserHandle.USER_CURRENT);
+ }
+
+ public void setShowErrorPath(boolean enabled) {
+ setBoolean(Settings.Secure.LOCK_SHOW_ERROR_PATH, enabled, UserHandle.USER_CURRENT);
+ }
+
+ public boolean isShowErrorPath() {
+ return getBoolean(Settings.Secure.LOCK_SHOW_ERROR_PATH, true, UserHandle.USER_CURRENT);
+ }
+
+ /**
* 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 9211eaa..a3cd8ad 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -51,6 +51,7 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import com.android.internal.R;
+import com.android.internal.widget.LockPatternUtils;
import java.util.ArrayList;
import java.util.HashMap;
@@ -58,7 +59,7 @@ 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.
@@ -70,7 +71,7 @@ public class LockPatternView extends View {
private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
private static final boolean PROFILE_DRAWING = false;
- private final CellState[][] mCellStates;
+ private CellState[][] mCellStates;
private final int mDotSize;
private final int mDotSizeActivated;
@@ -88,6 +89,8 @@ public class LockPatternView extends View {
*/
private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
+ private byte mPatternSize = LockPatternUtils.PATTERN_SIZE_DEFAULT;
+
/**
* This can be used to avoid updating the display for very small motions or noisy panels.
* It didn't seem to have much impact on the devices tested, so currently set to 0.
@@ -98,7 +101,7 @@ public class LockPatternView extends View {
private static final String TAG = "LockPatternView";
private OnPatternListener mOnPatternListener;
- private final 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.
@@ -106,7 +109,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 final boolean[][] mPatternDrawLookup = new boolean[3][3];
+ private boolean[][] mPatternDrawLookup = new boolean[mPatternSize][mPatternSize];
/**
* the in progress point:
@@ -123,6 +126,8 @@ public class LockPatternView extends View {
private boolean mInStealthMode = false;
private boolean mEnableHapticFeedback = true;
private boolean mPatternInProgress = false;
+ private boolean mVisibleDots = true;
+ private boolean mShowErrorPath = true;
private float mHitFactor = 0.6f;
@@ -143,32 +148,26 @@ public class LockPatternView extends View {
private PatternExploreByTouchHelper mExploreByTouchHelper;
private AudioManager mAudioManager;
+ 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 final class Cell {
final int row;
final int column;
- // keep # objects limited to 9
- private static final Cell[][] sCells = createCells();
-
- private static Cell[][] createCells() {
- Cell[][] res = new Cell[3][3];
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- res[i][j] = new Cell(i, j);
- }
- }
- return res;
+ static Cell[][] sCells;
+ static {
+ 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;
}
@@ -181,17 +180,30 @@ public class LockPatternView extends View {
return column;
}
- public static Cell of(int row, int column) {
- checkRange(row, column);
+ /**
+ * @param row The row of the cell.
+ * @param column The column of the cell.
+ */
+ 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));
}
}
@@ -317,9 +329,9 @@ public class LockPatternView extends View {
mPaint.setAntiAlias(true);
mPaint.setDither(true);
- mCellStates = new CellState[3][3];
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
+ mCellStates = new CellState[mPatternSize][mPatternSize];
+ for (int i = 0; i < mPatternSize; i++) {
+ for (int j = 0; j < mPatternSize; j++) {
mCellStates[i][j] = new CellState();
mCellStates[i][j].radius = mDotSize/2;
mCellStates[i][j].row = i;
@@ -355,6 +367,13 @@ public class LockPatternView extends View {
}
/**
+ * @return the current pattern lockscreen size.
+ */
+ public byte 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.
*
@@ -364,6 +383,22 @@ public class LockPatternView extends View {
mInStealthMode = inStealthMode;
}
+ public void setVisibleDots(boolean visibleDots) {
+ mVisibleDots = visibleDots;
+ }
+
+ public boolean isVisibleDots() {
+ return mVisibleDots;
+ }
+
+ public void setShowErrorPath(boolean showErrorPath) {
+ mShowErrorPath = showErrorPath;
+ }
+
+ public boolean isShowErrorPath() {
+ return mShowErrorPath;
+ }
+
/**
* Set whether the view will use tactile feedback. If true, there will be
* tactile feedback as the user enters the pattern.
@@ -375,6 +410,35 @@ 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);
+ mCellStates = new CellState[mPatternSize][mPatternSize];
+ for (int i = 0; i < mPatternSize; i++) {
+ for (int j = 0; j < mPatternSize; j++) {
+ mCellStates[i][j] = new CellState();
+ mCellStates[i][j].radius = mDotSize / 2;
+ mCellStates[i][j].row = i;
+ mCellStates[i][j].col = j;
+ }
+ }
+ 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.
*/
@@ -589,8 +653,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;
}
}
@@ -614,11 +678,11 @@ 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;
if (DEBUG_A11Y) Log.v(TAG, "onSizeChanged(" + w + "," + h + ")");
final int height = h - mPaddingTop - mPaddingBottom;
- mSquareHeight = height / 3.0f;
+ mSquareHeight = height / (float) mPatternSize;
mExploreByTouchHelper.invalidateRoot();
}
@@ -674,7 +738,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);
@@ -684,21 +747,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,
@@ -796,7 +857,7 @@ public class LockPatternView extends View {
if (mPatternDrawLookup[rowHit][columnHit]) {
return null;
}
- return Cell.of(rowHit, columnHit);
+ return Cell.of(rowHit, columnHit, mPatternSize);
}
/**
@@ -810,7 +871,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) {
@@ -830,7 +891,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) {
@@ -984,8 +1045,8 @@ public class LockPatternView extends View {
}
private void cancelLineAnimations() {
- 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++) {
CellState state = mCellStates[i][j];
if (state.lineAnimator != null) {
state.lineAnimator.cancel();
@@ -1088,9 +1149,9 @@ public class LockPatternView extends View {
currentPath.rewind();
// draw the circles
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < mPatternSize; i++) {
float centerY = getCenterYForRow(i);
- for (int j = 0; j < 3; j++) {
+ for (int j = 0; j < mPatternSize; j++) {
CellState cellState = mCellStates[i][j];
float centerX = getCenterXForColumn(j);
float translationY = cellState.translationY;
@@ -1109,8 +1170,10 @@ public class LockPatternView extends View {
// TODO: the path should be created and cached every time we hit-detect a cell
// only the last segment of the path should be computed here
// draw the path of the pattern (unless we are in stealth mode)
- final boolean drawPath = !mInStealthMode;
-
+ // draw the path of the pattern (unless the user is in progress, and
+ // we are in stealth mode)
+ final boolean drawPath = ((!mInStealthMode && mPatternDisplayMode != DisplayMode.Wrong)
+ || (mPatternDisplayMode == DisplayMode.Wrong && mShowErrorPath));
if (drawPath) {
mPathPaint.setColor(getCurrentColor(true /* partOfPattern */));
@@ -1196,9 +1259,9 @@ public class LockPatternView extends View {
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
return new SavedState(superState,
- LockPatternUtils.patternToString(mPattern),
- mPatternDisplayMode.ordinal(),
- mInputEnabled, mInStealthMode, mEnableHapticFeedback);
+ LockPatternUtils.patternToString(mPattern, mPatternSize),
+ mPatternDisplayMode.ordinal(), mPatternSize,
+ mInputEnabled, mInStealthMode, mEnableHapticFeedback, mVisibleDots, mShowErrorPath);
}
@Override
@@ -1207,11 +1270,14 @@ public class LockPatternView extends View {
super.onRestoreInstanceState(ss.getSuperState());
setPattern(
DisplayMode.Correct,
- LockPatternUtils.stringToPattern(ss.getSerializedPattern()));
+ LockPatternUtils.stringToPattern(ss.getSerializedPattern(), ss.getPatternSize()));
mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];
+ mPatternSize = ss.getPatternSize();
mInputEnabled = ss.isInputEnabled();
mInStealthMode = ss.isInStealthMode();
mEnableHapticFeedback = ss.isTactileFeedbackEnabled();
+ mVisibleDots = ss.isVisibleDots();
+ mShowErrorPath = ss.isShowErrorPath();
}
/**
@@ -1221,21 +1287,28 @@ 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;
+ private final boolean mVisibleDots;
+ private final boolean mShowErrorPath;
/**
* 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, boolean visibleDots, boolean showErrorPath) {
super(superState);
mSerializedPattern = serializedPattern;
mDisplayMode = displayMode;
+ mPatternSize = patternSize;
mInputEnabled = inputEnabled;
mInStealthMode = inStealthMode;
mTactileFeedbackEnabled = tactileFeedbackEnabled;
+ mVisibleDots = visibleDots;
+ mShowErrorPath = showErrorPath;
}
/**
@@ -1245,9 +1318,12 @@ 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);
+ mVisibleDots = (Boolean) in.readValue(null);
+ mShowErrorPath = (Boolean) in.readValue(null);
}
public String getSerializedPattern() {
@@ -1258,6 +1334,10 @@ public class LockPatternView extends View {
return mDisplayMode;
}
+ public byte getPatternSize() {
+ return mPatternSize;
+ }
+
public boolean isInputEnabled() {
return mInputEnabled;
}
@@ -1270,14 +1350,25 @@ public class LockPatternView extends View {
return mTactileFeedbackEnabled;
}
+ public boolean isVisibleDots() {
+ return mVisibleDots;
+ }
+
+ public boolean isShowErrorPath() {
+ return mShowErrorPath;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(mSerializedPattern);
dest.writeInt(mDisplayMode);
+ dest.writeByte(mPatternSize);
dest.writeValue(mInputEnabled);
dest.writeValue(mInStealthMode);
dest.writeValue(mTactileFeedbackEnabled);
+ dest.writeValue(mVisibleDots);
+ dest.writeValue(mShowErrorPath);
}
@SuppressWarnings({ "unused", "hiding" }) // Found using reflection
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 9a91ca4..9fc253b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -132,10 +132,16 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
mLockPatternView = (LockPatternView) findViewById(R.id.lockPatternView);
mLockPatternView.setSaveEnabled(false);
mLockPatternView.setOnPatternListener(new UnlockPatternListener());
+ mLockPatternView.setLockPatternUtils(mLockPatternUtils);
+ mLockPatternView.setLockPatternSize(mLockPatternUtils.getLockPatternSize());
+
+ mLockPatternView.setVisibleDots(mLockPatternUtils.isVisibleDotsEnabled());
+ mLockPatternView.setShowErrorPath(mLockPatternUtils.isShowErrorPath());
// stealth mode will be the same for the life of this screen
mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
KeyguardUpdateMonitor.getCurrentUser()));
+ setFocusableInTouchMode(true);
// vibrate mode will be the same for the life of this screen
mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 3af1d36..b3ec295 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -721,6 +721,9 @@ class DatabaseHelper extends SQLiteOpenHelper {
Secure.LOCK_PATTERN_ENABLED,
Secure.LOCK_PATTERN_VISIBLE,
Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED,
+ Secure.LOCK_PATTERN_SIZE,
+ Secure.LOCK_DOTS_VISIBLE,
+ Secure.LOCK_SHOW_ERROR_PATH,
"lockscreen.password_type",
"lockscreen.lockoutattemptdeadline",
"lockscreen.patterneverchosen",
@@ -2241,7 +2244,7 @@ class DatabaseHelper extends SQLiteOpenHelper {
try {
LockPatternUtils lpu = new LockPatternUtils(mContext);
List<LockPatternView.Cell> cellPattern =
- LockPatternUtils.stringToPattern(lockPattern);
+ LockPatternUtils.stringToPattern(lockPattern, lpu.getLockPatternSize());
lpu.saveLockPattern(cellPattern, null, UserHandle.USER_OWNER);
} catch (IllegalArgumentException e) {
// Don't want corrupted lock pattern to hang the reboot process
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 1dbb054..bb0615d 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -446,6 +446,10 @@ public class LockSettingsService extends ILockSettings.Stub {
}
+ public byte getLockPatternSize(int userId) {
+ return mStorage.getLockPatternSize(userId);
+ }
+
@Override
public void setLockPattern(String pattern, String savedCredential, int userId)
throws RemoteException {
@@ -563,8 +567,10 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public byte[] toHash(String pattern, int userId) {
+ final byte lockPatternSize = getLockPatternSize(userId);
return LockPatternUtils.patternToHash(
- LockPatternUtils.stringToPattern(pattern));
+ LockPatternUtils.stringToPattern(pattern, lockPatternSize),
+ lockPatternSize);
}
@Override
@@ -803,7 +809,10 @@ public class LockSettingsService extends ILockSettings.Stub {
Secure.LOCK_PATTERN_ENABLED,
Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
Secure.LOCK_PATTERN_VISIBLE,
- Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
+ Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED,
+ Secure.LOCK_PATTERN_SIZE,
+ Secure.LOCK_DOTS_VISIBLE,
+ Secure.LOCK_SHOW_ERROR_PATH,
};
// Reading these settings needs the contacts permission
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index de48e71..72e05c1 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -16,6 +16,8 @@
package com.android.server;
+import android.os.RemoteException;
+import android.provider.Settings;
import com.android.internal.annotations.VisibleForTesting;
import android.content.ContentValues;
@@ -29,6 +31,7 @@ import android.os.UserManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.widget.LockPatternUtils;
import java.io.File;
import java.io.IOException;
@@ -328,7 +331,10 @@ class LockSettingsStorage {
mStoredCredentialType = hash == null
? CredentialHash.TYPE_NONE
: CredentialHash.TYPE_PATTERN;
- writeFile(getLockPatternFilename(userId), hash);
+
+ boolean defaultSize = isDefaultSize(userId);
+ writeFile(getLockPatternFilename(userId, defaultSize), hash);
+
clearPasswordHash(userId);
}
@@ -348,9 +354,22 @@ class LockSettingsStorage {
writeFile(getLockPasswordFilename(userId), null);
}
+ public byte getLockPatternSize(int userId) {
+ long size = Long.valueOf(readKeyValue(Settings.Secure.LOCK_PATTERN_SIZE, "-1", userId));
+ if (size > 0 && size < 128) {
+ return (byte) size;
+ }
+ return LockPatternUtils.PATTERN_SIZE_DEFAULT;
+ }
+
+ public boolean isDefaultSize(int userId) {
+ return getLockPatternSize(userId) == LockPatternUtils.PATTERN_SIZE_DEFAULT;
+ }
+
@VisibleForTesting
String getLockPatternFilename(int userId) {
- return getLockCredentialFilePathForUser(userId, LOCK_PATTERN_FILE);
+ String baseFileName = LOCK_PATTERN_FILE;
+ return getLockCredentialFilePathForUser(userId, baseFileName);
}
@VisibleForTesting