• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

frameworks/base


Commit MetaInfo

Revisãoabf94441542ac8dcd3eb1236a98ef5bcb0de52c8 (tree)
Hora2016-10-03 22:57:35
AutorMichael Bestas <mikeioannina@gmai...>
CommiterSteve Kondik

Mensagem de Log

Forward port CM Screen Security settings (1/2)

  • Variable size pattern lockscreen
  • Toggle dots/error pattern visibility

Change-Id: Ie109e82c1fb2fd96b07e977e1cd76ae3acb865ff

Fix pattern visibility settings (1/2)

Change-Id: Ic627953c5df854c442671a98b5da539b994da18b

LockPatternUtils: Use the actual user id to set pattern size

Ticket: CYNGNOS-2462
Change-Id: Ia68e26ec2dfc23317135d933bc25204c1380bb02

LockSettings: fix build

Change-Id: Ic65b1a2af398faffb83776ee4013d47f79ab6619
Signed-off-by: Roman Birg <roman@cyngn.com>

Mudança Sumário

Diff

--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4256,6 +4256,9 @@ public final class Settings {
42564256 MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_ENABLED);
42574257 MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_VISIBLE);
42584258 MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
4259+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_SIZE);
4260+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_DOTS_VISIBLE);
4261+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_SHOW_ERROR_PATH);
42594262
42604263 MOVED_TO_GLOBAL = new HashSet<String>();
42614264 MOVED_TO_GLOBAL.add(Settings.Global.ADB_ENABLED);
@@ -5068,6 +5071,24 @@ public final class Settings {
50685071 LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
50695072
50705073 /**
5074+ * Determines the width and height of the LockPatternView widget
5075+ * @hide
5076+ */
5077+ public static final String LOCK_PATTERN_SIZE = "lock_pattern_size";
5078+
5079+ /**
5080+ * Whether lock pattern will show dots (0 = false, 1 = true)
5081+ * @hide
5082+ */
5083+ public static final String LOCK_DOTS_VISIBLE = "lock_pattern_dotsvisible";
5084+
5085+ /**
5086+ * Whether lockscreen error pattern is visible (0 = false, 1 = true)
5087+ * @hide
5088+ */
5089+ public static final String LOCK_SHOW_ERROR_PATH = "lock_pattern_show_error_path";
5090+
5091+ /**
50715092 * This preference allows the device to be locked given time after screen goes off,
50725093 * subject to current DeviceAdmin policy limits.
50735094 * @hide
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -35,6 +35,7 @@ interface ILockSettings {
3535 VerifyCredentialResponse checkPassword(in String password, int userId);
3636 VerifyCredentialResponse verifyPassword(in String password, long challenge, int userId);
3737 VerifyCredentialResponse verifyTiedProfileChallenge(String password, boolean isPattern, long challenge, int userId);
38+ byte getLockPatternSize(int userId);
3839 boolean checkVoldPassword(int userId);
3940 boolean havePattern(int userId);
4041 boolean havePassword(int userId);
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -97,6 +97,11 @@ public class LockPatternUtils {
9797 */
9898 public static final int MIN_LOCK_PASSWORD_SIZE = 4;
9999
100+ /*
101+ * The default size of the pattern lockscreen. Ex: 3x3
102+ */
103+ public static final byte PATTERN_SIZE_DEFAULT = 3;
104+
100105 /**
101106 * The minimum number of dots the user must include in a wrong pattern
102107 * attempt for it to be counted against the counts that affect
@@ -315,7 +320,7 @@ public class LockPatternUtils {
315320 throwIfCalledOnMainThread();
316321 try {
317322 VerifyCredentialResponse response =
318- getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
323+ getLockSettings().verifyPattern(patternToString(pattern, userId), challenge, userId);
319324 if (response == null) {
320325 // Shouldn't happen
321326 return null;
@@ -344,7 +349,7 @@ public class LockPatternUtils {
344349 throwIfCalledOnMainThread();
345350 try {
346351 VerifyCredentialResponse response =
347- getLockSettings().checkPattern(patternToString(pattern), userId);
352+ getLockSettings().checkPattern(patternToString(pattern, userId), userId);
348353
349354 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
350355 return true;
@@ -614,7 +619,7 @@ public class LockPatternUtils {
614619 + MIN_LOCK_PATTERN_SIZE + " dots long.");
615620 }
616621
617- getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);
622+ getLockSettings().setLockPattern(patternToString(pattern, userId), savedPattern, userId);
618623 DevicePolicyManager dpm = getDevicePolicyManager();
619624
620625 // Update the device encryption password.
@@ -623,7 +628,7 @@ public class LockPatternUtils {
623628 if (!shouldEncryptWithCredentials(true)) {
624629 clearEncryptionPassword();
625630 } else {
626- String stringPattern = patternToString(pattern);
631+ String stringPattern = patternToString(pattern, userId);
627632 updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
628633 }
629634 }
@@ -1025,17 +1030,18 @@ public class LockPatternUtils {
10251030 * @param string The pattern serialized with {@link #patternToString}
10261031 * @return The pattern.
10271032 */
1028- public static List<LockPatternView.Cell> stringToPattern(String string) {
1033+ public static List<LockPatternView.Cell> stringToPattern(String string, byte gridSize) {
10291034 if (string == null) {
10301035 return null;
10311036 }
1032-
10331037 List<LockPatternView.Cell> result = Lists.newArrayList();
10341038
1039+ LockPatternView.Cell.updateSize(gridSize);
1040+
10351041 final byte[] bytes = string.getBytes();
10361042 for (int i = 0; i < bytes.length; i++) {
10371043 byte b = (byte) (bytes[i] - '1');
1038- result.add(LockPatternView.Cell.of(b / 3, b % 3));
1044+ result.add(LockPatternView.Cell.of(b / gridSize, b % gridSize, gridSize));
10391045 }
10401046 return result;
10411047 }
@@ -1045,16 +1051,26 @@ public class LockPatternUtils {
10451051 * @param pattern The pattern.
10461052 * @return The pattern in string form.
10471053 */
1048- public static String patternToString(List<LockPatternView.Cell> pattern) {
1054+ public String patternToString(List<LockPatternView.Cell> pattern, int userId) {
1055+ return patternToString(pattern, getLockPatternSize(userId));
1056+ }
1057+
1058+ /**
1059+ * Serialize a pattern.
1060+ * @param pattern The pattern.
1061+ * @return The pattern in string form.
1062+ */
1063+ public static String patternToString(List<LockPatternView.Cell> pattern, byte gridSize) {
10491064 if (pattern == null) {
10501065 return "";
10511066 }
10521067 final int patternSize = pattern.size();
1068+ LockPatternView.Cell.updateSize(gridSize);
10531069
10541070 byte[] res = new byte[patternSize];
10551071 for (int i = 0; i < patternSize; i++) {
10561072 LockPatternView.Cell cell = pattern.get(i);
1057- res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
1073+ res[i] = (byte) (cell.getRow() * gridSize + cell.getColumn() + '1');
10581074 }
10591075 return new String(res);
10601076 }
@@ -1064,7 +1080,6 @@ public class LockPatternUtils {
10641080 return "";
10651081 }
10661082 final int patternSize = pattern.length();
1067-
10681083 byte[] res = new byte[patternSize];
10691084 final byte[] bytes = pattern.getBytes();
10701085 for (int i = 0; i < patternSize; i++) {
@@ -1080,7 +1095,7 @@ public class LockPatternUtils {
10801095 * @param pattern the gesture pattern.
10811096 * @return the hash of the pattern in a byte array.
10821097 */
1083- public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
1098+ public static byte[] patternToHash(List<LockPatternView.Cell> pattern, byte gridSize) {
10841099 if (pattern == null) {
10851100 return null;
10861101 }
@@ -1089,7 +1104,7 @@ public class LockPatternUtils {
10891104 byte[] res = new byte[patternSize];
10901105 for (int i = 0; i < patternSize; i++) {
10911106 LockPatternView.Cell cell = pattern.get(i);
1092- res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
1107+ res[i] = (byte) (cell.getRow() * gridSize + cell.getColumn());
10931108 }
10941109 try {
10951110 MessageDigest md = MessageDigest.getInstance("SHA-1");
@@ -1257,6 +1272,40 @@ public class LockPatternUtils {
12571272 }
12581273
12591274 /**
1275+ * @return the pattern lockscreen size
1276+ */
1277+ public byte getLockPatternSize(int userId) {
1278+ long size = getLong(Settings.Secure.LOCK_PATTERN_SIZE, -1, userId);
1279+ if (size > 0 && size < 128) {
1280+ return (byte) size;
1281+ }
1282+ return LockPatternUtils.PATTERN_SIZE_DEFAULT;
1283+ }
1284+
1285+ /**
1286+ * Set the pattern lockscreen size
1287+ */
1288+ public void setLockPatternSize(long size, int userId) {
1289+ setLong(Settings.Secure.LOCK_PATTERN_SIZE, size, userId);
1290+ }
1291+
1292+ public void setVisibleDotsEnabled(boolean enabled, int userId) {
1293+ setBoolean(Settings.Secure.LOCK_DOTS_VISIBLE, enabled, userId);
1294+ }
1295+
1296+ public boolean isVisibleDotsEnabled(int userId) {
1297+ return getBoolean(Settings.Secure.LOCK_DOTS_VISIBLE, true, userId);
1298+ }
1299+
1300+ public void setShowErrorPath(boolean enabled, int userId) {
1301+ setBoolean(Settings.Secure.LOCK_SHOW_ERROR_PATH, enabled, userId);
1302+ }
1303+
1304+ public boolean isShowErrorPath(int userId) {
1305+ return getBoolean(Settings.Secure.LOCK_SHOW_ERROR_PATH, true, userId);
1306+ }
1307+
1308+ /**
12601309 * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
12611310 * pattern until the deadline has passed.
12621311 * @return the chosen deadline.
--- 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;
5151 import android.view.animation.Interpolator;
5252
5353 import com.android.internal.R;
54+import com.android.internal.widget.LockPatternUtils;
5455
5556 import java.util.ArrayList;
5657 import java.util.HashMap;
@@ -58,7 +59,7 @@ import java.util.List;
5859
5960 /**
6061 * Displays and detects the user's unlock attempt, which is a drag of a finger
61- * across 9 regions of the screen.
62+ * across regions of the screen.
6263 *
6364 * Is also capable of displaying a static pattern in "in progress", "wrong" or
6465 * "correct" states.
@@ -70,7 +71,7 @@ public class LockPatternView extends View {
7071 private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
7172
7273 private static final boolean PROFILE_DRAWING = false;
73- private final CellState[][] mCellStates;
74+ private CellState[][] mCellStates;
7475
7576 private final int mDotSize;
7677 private final int mDotSizeActivated;
@@ -88,6 +89,8 @@ public class LockPatternView extends View {
8889 */
8990 private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
9091
92+ private byte mPatternSize = LockPatternUtils.PATTERN_SIZE_DEFAULT;
93+
9194 /**
9295 * This can be used to avoid updating the display for very small motions or noisy panels.
9396 * 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 {
98101 private static final String TAG = "LockPatternView";
99102
100103 private OnPatternListener mOnPatternListener;
101- private final ArrayList<Cell> mPattern = new ArrayList<Cell>(9);
104+ private ArrayList<Cell> mPattern = new ArrayList<Cell>(mPatternSize * mPatternSize);
102105
103106 /**
104107 * Lookup table for the circles of the pattern we are currently drawing.
@@ -106,7 +109,7 @@ public class LockPatternView extends View {
106109 * in which case we use this to hold the cells we are drawing for the in
107110 * progress animation.
108111 */
109- private final boolean[][] mPatternDrawLookup = new boolean[3][3];
112+ private boolean[][] mPatternDrawLookup = new boolean[mPatternSize][mPatternSize];
110113
111114 /**
112115 * the in progress point:
@@ -123,6 +126,8 @@ public class LockPatternView extends View {
123126 private boolean mInStealthMode = false;
124127 private boolean mEnableHapticFeedback = true;
125128 private boolean mPatternInProgress = false;
129+ private boolean mVisibleDots = true;
130+ private boolean mShowErrorPath = true;
126131
127132 private float mHitFactor = 0.6f;
128133
@@ -143,32 +148,26 @@ public class LockPatternView extends View {
143148 private PatternExploreByTouchHelper mExploreByTouchHelper;
144149 private AudioManager mAudioManager;
145150
151+ private LockPatternUtils mLockPatternUtils;
152+
146153 /**
147- * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
154+ * Represents a cell in the matrix of the unlock pattern view.
148155 */
149156 public static final class Cell {
150157 final int row;
151158 final int column;
152159
153- // keep # objects limited to 9
154- private static final Cell[][] sCells = createCells();
155-
156- private static Cell[][] createCells() {
157- Cell[][] res = new Cell[3][3];
158- for (int i = 0; i < 3; i++) {
159- for (int j = 0; j < 3; j++) {
160- res[i][j] = new Cell(i, j);
161- }
162- }
163- return res;
160+ static Cell[][] sCells;
161+ static {
162+ updateSize(LockPatternUtils.PATTERN_SIZE_DEFAULT);
164163 }
165164
166165 /**
167166 * @param row The row of the cell.
168167 * @param column The column of the cell.
169168 */
170- private Cell(int row, int column) {
171- checkRange(row, column);
169+ private Cell(int row, int column, byte size) {
170+ checkRange(row, column, size);
172171 this.row = row;
173172 this.column = column;
174173 }
@@ -181,17 +180,30 @@ public class LockPatternView extends View {
181180 return column;
182181 }
183182
184- public static Cell of(int row, int column) {
185- checkRange(row, column);
183+ /**
184+ * @param row The row of the cell.
185+ * @param column The column of the cell.
186+ */
187+ public static synchronized Cell of(int row, int column, byte size) {
188+ checkRange(row, column, size);
186189 return sCells[row][column];
187190 }
188191
189- private static void checkRange(int row, int column) {
190- if (row < 0 || row > 2) {
191- throw new IllegalArgumentException("row must be in range 0-2");
192+ public static void updateSize(byte size) {
193+ sCells = new Cell[size][size];
194+ for (int i = 0; i < size; i++) {
195+ for (int j = 0; j < size; j++) {
196+ sCells[i][j] = new Cell(i, j, size);
197+ }
192198 }
193- if (column < 0 || column > 2) {
194- throw new IllegalArgumentException("column must be in range 0-2");
199+ }
200+
201+ private static void checkRange(int row, int column, byte size) {
202+ if (row < 0 || row > size - 1) {
203+ throw new IllegalArgumentException("row must be in range 0-" + (size - 1));
204+ }
205+ if (column < 0 || column > size - 1) {
206+ throw new IllegalArgumentException("column must be in range 0-" + (size - 1));
195207 }
196208 }
197209
@@ -317,9 +329,9 @@ public class LockPatternView extends View {
317329 mPaint.setAntiAlias(true);
318330 mPaint.setDither(true);
319331
320- mCellStates = new CellState[3][3];
321- for (int i = 0; i < 3; i++) {
322- for (int j = 0; j < 3; j++) {
332+ mCellStates = new CellState[mPatternSize][mPatternSize];
333+ for (int i = 0; i < mPatternSize; i++) {
334+ for (int j = 0; j < mPatternSize; j++) {
323335 mCellStates[i][j] = new CellState();
324336 mCellStates[i][j].radius = mDotSize/2;
325337 mCellStates[i][j].row = i;
@@ -356,6 +368,13 @@ public class LockPatternView extends View {
356368 }
357369
358370 /**
371+ * @return the current pattern lockscreen size.
372+ */
373+ public byte getLockPatternSize() {
374+ return mPatternSize;
375+ }
376+
377+ /**
359378 * Set whether the view is in stealth mode. If true, there will be no
360379 * visible feedback as the user enters the pattern.
361380 *
@@ -365,6 +384,22 @@ public class LockPatternView extends View {
365384 mInStealthMode = inStealthMode;
366385 }
367386
387+ public void setVisibleDots(boolean visibleDots) {
388+ mVisibleDots = visibleDots;
389+ }
390+
391+ public boolean isVisibleDots() {
392+ return mVisibleDots;
393+ }
394+
395+ public void setShowErrorPath(boolean showErrorPath) {
396+ mShowErrorPath = showErrorPath;
397+ }
398+
399+ public boolean isShowErrorPath() {
400+ return mShowErrorPath;
401+ }
402+
368403 /**
369404 * Set whether the view will use tactile feedback. If true, there will be
370405 * tactile feedback as the user enters the pattern.
@@ -376,6 +411,35 @@ public class LockPatternView extends View {
376411 }
377412
378413 /**
414+ * Set the pattern size of the lockscreen
415+ *
416+ * @param size The pattern size.
417+ */
418+ public void setLockPatternSize(byte size) {
419+ mPatternSize = size;
420+ Cell.updateSize(size);
421+ mCellStates = new CellState[mPatternSize][mPatternSize];
422+ for (int i = 0; i < mPatternSize; i++) {
423+ for (int j = 0; j < mPatternSize; j++) {
424+ mCellStates[i][j] = new CellState();
425+ mCellStates[i][j].radius = mDotSize / 2;
426+ mCellStates[i][j].row = i;
427+ mCellStates[i][j].col = j;
428+ }
429+ }
430+ mPattern = new ArrayList<Cell>(size * size);
431+ mPatternDrawLookup = new boolean[size][size];
432+ }
433+
434+ /**
435+ * Set the LockPatternUtil instance used to encode a pattern to a string
436+ * @param utils The instance.
437+ */
438+ public void setLockPatternUtils(LockPatternUtils utils) {
439+ mLockPatternUtils = utils;
440+ }
441+
442+ /**
379443 * Set the call back for pattern detection.
380444 * @param onPatternListener The call back.
381445 */
@@ -590,8 +654,8 @@ public class LockPatternView extends View {
590654 * Clear the pattern lookup table.
591655 */
592656 private void clearPatternDrawLookup() {
593- for (int i = 0; i < 3; i++) {
594- for (int j = 0; j < 3; j++) {
657+ for (int i = 0; i < mPatternSize; i++) {
658+ for (int j = 0; j < mPatternSize; j++) {
595659 mPatternDrawLookup[i][j] = false;
596660 }
597661 }
@@ -615,11 +679,11 @@ public class LockPatternView extends View {
615679 @Override
616680 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
617681 final int width = w - mPaddingLeft - mPaddingRight;
618- mSquareWidth = width / 3.0f;
682+ mSquareWidth = width / (float) mPatternSize;
619683
620684 if (DEBUG_A11Y) Log.v(TAG, "onSizeChanged(" + w + "," + h + ")");
621685 final int height = h - mPaddingTop - mPaddingBottom;
622- mSquareHeight = height / 3.0f;
686+ mSquareHeight = height / (float) mPatternSize;
623687 mExploreByTouchHelper.invalidateRoot();
624688 }
625689
@@ -675,7 +739,6 @@ public class LockPatternView extends View {
675739 if (cell != null) {
676740
677741 // check for gaps in existing pattern
678- Cell fillInGapCell = null;
679742 final ArrayList<Cell> pattern = mPattern;
680743 if (!pattern.isEmpty()) {
681744 final Cell lastCell = pattern.get(pattern.size() - 1);
@@ -685,21 +748,19 @@ public class LockPatternView extends View {
685748 int fillInRow = lastCell.row;
686749 int fillInColumn = lastCell.column;
687750
688- if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) {
689- fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1);
690- }
691-
692- if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) {
693- fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1);
751+ if (dRow == 0 || dColumn == 0 || Math.abs(dRow) == Math.abs(dColumn)) {
752+ while (true) {
753+ fillInRow += Integer.signum(dRow);
754+ fillInColumn += Integer.signum(dColumn);
755+ if (fillInRow == cell.row && fillInColumn == cell.column) break;
756+ Cell fillInGapCell = Cell.of(fillInRow, fillInColumn, mPatternSize);
757+ if (!mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
758+ addCellToPattern(fillInGapCell);
759+ }
760+ }
694761 }
695-
696- fillInGapCell = Cell.of(fillInRow, fillInColumn);
697762 }
698763
699- if (fillInGapCell != null &&
700- !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
701- addCellToPattern(fillInGapCell);
702- }
703764 addCellToPattern(cell);
704765 if (mEnableHapticFeedback) {
705766 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
@@ -797,7 +858,7 @@ public class LockPatternView extends View {
797858 if (mPatternDrawLookup[rowHit][columnHit]) {
798859 return null;
799860 }
800- return Cell.of(rowHit, columnHit);
861+ return Cell.of(rowHit, columnHit, mPatternSize);
801862 }
802863
803864 /**
@@ -811,7 +872,7 @@ public class LockPatternView extends View {
811872 float hitSize = squareHeight * mHitFactor;
812873
813874 float offset = mPaddingTop + (squareHeight - hitSize) / 2f;
814- for (int i = 0; i < 3; i++) {
875+ for (int i = 0; i < mPatternSize; i++) {
815876
816877 final float hitTop = offset + squareHeight * i;
817878 if (y >= hitTop && y <= hitTop + hitSize) {
@@ -831,7 +892,7 @@ public class LockPatternView extends View {
831892 float hitSize = squareWidth * mHitFactor;
832893
833894 float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;
834- for (int i = 0; i < 3; i++) {
895+ for (int i = 0; i < mPatternSize; i++) {
835896
836897 final float hitLeft = offset + squareWidth * i;
837898 if (x >= hitLeft && x <= hitLeft + hitSize) {
@@ -985,8 +1046,8 @@ public class LockPatternView extends View {
9851046 }
9861047
9871048 private void cancelLineAnimations() {
988- for (int i = 0; i < 3; i++) {
989- for (int j = 0; j < 3; j++) {
1049+ for (int i = 0; i < mPatternSize; i++) {
1050+ for (int j = 0; j < mPatternSize; j++) {
9901051 CellState state = mCellStates[i][j];
9911052 if (state.lineAnimator != null) {
9921053 state.lineAnimator.cancel();
@@ -1089,20 +1150,21 @@ public class LockPatternView extends View {
10891150 currentPath.rewind();
10901151
10911152 // draw the circles
1092- for (int i = 0; i < 3; i++) {
1093- float centerY = getCenterYForRow(i);
1094- for (int j = 0; j < 3; j++) {
1095- CellState cellState = mCellStates[i][j];
1096- float centerX = getCenterXForColumn(j);
1097- float translationY = cellState.translationY;
1098- if (isHardwareAccelerated() && cellState.hwAnimating) {
1099- DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
1100- displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
1101- cellState.hwRadius, cellState.hwPaint);
1102- } else {
1103- drawCircle(canvas, (int) centerX, (int) centerY + translationY,
1104- cellState.radius, drawLookup[i][j], cellState.alpha);
1105-
1153+ if (mVisibleDots) {
1154+ for (int i = 0; i < mPatternSize; i++) {
1155+ float centerY = getCenterYForRow(i);
1156+ for (int j = 0; j < mPatternSize; j++) {
1157+ CellState cellState = mCellStates[i][j];
1158+ float centerX = getCenterXForColumn(j);
1159+ float translationY = cellState.translationY;
1160+ if (isHardwareAccelerated() && cellState.hwAnimating) {
1161+ DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
1162+ displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
1163+ cellState.hwRadius, cellState.hwPaint);
1164+ } else {
1165+ drawCircle(canvas, (int) centerX, (int) centerY + translationY,
1166+ cellState.radius, drawLookup[i][j], cellState.alpha);
1167+ }
11061168 }
11071169 }
11081170 }
@@ -1110,8 +1172,8 @@ public class LockPatternView extends View {
11101172 // TODO: the path should be created and cached every time we hit-detect a cell
11111173 // only the last segment of the path should be computed here
11121174 // draw the path of the pattern (unless we are in stealth mode)
1113- final boolean drawPath = !mInStealthMode;
1114-
1175+ final boolean drawPath = ((!mInStealthMode && mPatternDisplayMode != DisplayMode.Wrong)
1176+ || (mPatternDisplayMode == DisplayMode.Wrong && mShowErrorPath));
11151177 if (drawPath) {
11161178 mPathPaint.setColor(getCurrentColor(true /* partOfPattern */));
11171179
@@ -1169,7 +1231,9 @@ public class LockPatternView extends View {
11691231 }
11701232
11711233 private int getCurrentColor(boolean partOfPattern) {
1172- if (!partOfPattern || mInStealthMode || mPatternInProgress) {
1234+ if (!partOfPattern || (mInStealthMode && mPatternDisplayMode != DisplayMode.Wrong)
1235+ || (mPatternDisplayMode == DisplayMode.Wrong && !mShowErrorPath)
1236+ || mPatternInProgress) {
11731237 // unselected circle
11741238 return mRegularColor;
11751239 } else if (mPatternDisplayMode == DisplayMode.Wrong) {
@@ -1197,9 +1261,9 @@ public class LockPatternView extends View {
11971261 protected Parcelable onSaveInstanceState() {
11981262 Parcelable superState = super.onSaveInstanceState();
11991263 return new SavedState(superState,
1200- LockPatternUtils.patternToString(mPattern),
1201- mPatternDisplayMode.ordinal(),
1202- mInputEnabled, mInStealthMode, mEnableHapticFeedback);
1264+ LockPatternUtils.patternToString(mPattern, mPatternSize),
1265+ mPatternDisplayMode.ordinal(), mPatternSize,
1266+ mInputEnabled, mInStealthMode, mEnableHapticFeedback, mVisibleDots, mShowErrorPath);
12031267 }
12041268
12051269 @Override
@@ -1208,11 +1272,14 @@ public class LockPatternView extends View {
12081272 super.onRestoreInstanceState(ss.getSuperState());
12091273 setPattern(
12101274 DisplayMode.Correct,
1211- LockPatternUtils.stringToPattern(ss.getSerializedPattern()));
1275+ LockPatternUtils.stringToPattern(ss.getSerializedPattern(), ss.getPatternSize()));
12121276 mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];
1277+ mPatternSize = ss.getPatternSize();
12131278 mInputEnabled = ss.isInputEnabled();
12141279 mInStealthMode = ss.isInStealthMode();
12151280 mEnableHapticFeedback = ss.isTactileFeedbackEnabled();
1281+ mVisibleDots = ss.isVisibleDots();
1282+ mShowErrorPath = ss.isShowErrorPath();
12161283 }
12171284
12181285 /**
@@ -1222,21 +1289,28 @@ public class LockPatternView extends View {
12221289
12231290 private final String mSerializedPattern;
12241291 private final int mDisplayMode;
1292+ private final byte mPatternSize;
12251293 private final boolean mInputEnabled;
12261294 private final boolean mInStealthMode;
12271295 private final boolean mTactileFeedbackEnabled;
1296+ private final boolean mVisibleDots;
1297+ private final boolean mShowErrorPath;
12281298
12291299 /**
12301300 * Constructor called from {@link LockPatternView#onSaveInstanceState()}
12311301 */
12321302 private SavedState(Parcelable superState, String serializedPattern, int displayMode,
1233- boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) {
1303+ byte patternSize, boolean inputEnabled, boolean inStealthMode,
1304+ boolean tactileFeedbackEnabled, boolean visibleDots, boolean showErrorPath) {
12341305 super(superState);
12351306 mSerializedPattern = serializedPattern;
12361307 mDisplayMode = displayMode;
1308+ mPatternSize = patternSize;
12371309 mInputEnabled = inputEnabled;
12381310 mInStealthMode = inStealthMode;
12391311 mTactileFeedbackEnabled = tactileFeedbackEnabled;
1312+ mVisibleDots = visibleDots;
1313+ mShowErrorPath = showErrorPath;
12401314 }
12411315
12421316 /**
@@ -1246,9 +1320,12 @@ public class LockPatternView extends View {
12461320 super(in);
12471321 mSerializedPattern = in.readString();
12481322 mDisplayMode = in.readInt();
1323+ mPatternSize = (byte) in.readByte();
12491324 mInputEnabled = (Boolean) in.readValue(null);
12501325 mInStealthMode = (Boolean) in.readValue(null);
12511326 mTactileFeedbackEnabled = (Boolean) in.readValue(null);
1327+ mVisibleDots = (Boolean) in.readValue(null);
1328+ mShowErrorPath = (Boolean) in.readValue(null);
12521329 }
12531330
12541331 public String getSerializedPattern() {
@@ -1259,6 +1336,10 @@ public class LockPatternView extends View {
12591336 return mDisplayMode;
12601337 }
12611338
1339+ public byte getPatternSize() {
1340+ return mPatternSize;
1341+ }
1342+
12621343 public boolean isInputEnabled() {
12631344 return mInputEnabled;
12641345 }
@@ -1271,14 +1352,25 @@ public class LockPatternView extends View {
12711352 return mTactileFeedbackEnabled;
12721353 }
12731354
1355+ public boolean isVisibleDots() {
1356+ return mVisibleDots;
1357+ }
1358+
1359+ public boolean isShowErrorPath() {
1360+ return mShowErrorPath;
1361+ }
1362+
12741363 @Override
12751364 public void writeToParcel(Parcel dest, int flags) {
12761365 super.writeToParcel(dest, flags);
12771366 dest.writeString(mSerializedPattern);
12781367 dest.writeInt(mDisplayMode);
1368+ dest.writeByte(mPatternSize);
12791369 dest.writeValue(mInputEnabled);
12801370 dest.writeValue(mInStealthMode);
12811371 dest.writeValue(mTactileFeedbackEnabled);
1372+ dest.writeValue(mVisibleDots);
1373+ dest.writeValue(mShowErrorPath);
12821374 }
12831375
12841376 @SuppressWarnings({ "unused", "hiding" }) // Found using reflection
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -135,6 +135,15 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
135135 mLockPatternView = (LockPatternView) findViewById(R.id.lockPatternView);
136136 mLockPatternView.setSaveEnabled(false);
137137 mLockPatternView.setOnPatternListener(new UnlockPatternListener());
138+ mLockPatternView.setLockPatternUtils(mLockPatternUtils);
139+ mLockPatternView.setLockPatternSize(mLockPatternUtils.getLockPatternSize(KeyguardUpdateMonitor.getCurrentUser()));
140+
141+ mLockPatternView.setVisibleDots(mLockPatternUtils.isVisibleDotsEnabled(
142+ KeyguardUpdateMonitor.getCurrentUser()));
143+ mLockPatternView.setShowErrorPath(mLockPatternUtils.isShowErrorPath(
144+ KeyguardUpdateMonitor.getCurrentUser()));
145+
146+ setFocusableInTouchMode(true);
138147
139148 // vibrate mode will be the same for the life of this screen
140149 mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -736,6 +736,9 @@ class DatabaseHelper extends SQLiteOpenHelper {
736736 Secure.LOCK_PATTERN_ENABLED,
737737 Secure.LOCK_PATTERN_VISIBLE,
738738 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED,
739+ Secure.LOCK_PATTERN_SIZE,
740+ Secure.LOCK_DOTS_VISIBLE,
741+ Secure.LOCK_SHOW_ERROR_PATH,
739742 "lockscreen.password_type",
740743 "lockscreen.lockoutattemptdeadline",
741744 "lockscreen.patterneverchosen",
@@ -2071,7 +2074,8 @@ class DatabaseHelper extends SQLiteOpenHelper {
20712074 try {
20722075 LockPatternUtils lpu = new LockPatternUtils(mContext);
20732076 List<LockPatternView.Cell> cellPattern =
2074- LockPatternUtils.stringToPattern(lockPattern);
2077+ LockPatternUtils.stringToPattern(lockPattern,
2078+ lpu.getLockPatternSize(mUserHandle));
20752079 lpu.saveLockPattern(cellPattern, null, UserHandle.USER_SYSTEM);
20762080 } catch (IllegalArgumentException e) {
20772081 // Don't want corrupted lock pattern to hang the reboot process
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -931,6 +931,10 @@ public class LockSettingsService extends ILockSettings.Stub {
931931 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
932932 }
933933
934+ public byte getLockPatternSize(int userId) {
935+ return mStorage.getLockPatternSize(userId);
936+ }
937+
934938 // This method should be called by LockPatternUtil only, all internal methods in this class
935939 // should call setLockPatternInternal.
936940 @Override
@@ -1285,8 +1289,10 @@ public class LockSettingsService extends ILockSettings.Stub {
12851289
12861290 @Override
12871291 public byte[] toHash(String pattern, int userId) {
1292+ final byte lockPatternSize = getLockPatternSize(userId);
12881293 return LockPatternUtils.patternToHash(
1289- LockPatternUtils.stringToPattern(pattern));
1294+ LockPatternUtils.stringToPattern(pattern, lockPatternSize),
1295+ lockPatternSize);
12901296 }
12911297
12921298 @Override
@@ -1595,7 +1601,10 @@ public class LockSettingsService extends ILockSettings.Stub {
15951601 Secure.LOCK_PATTERN_ENABLED,
15961602 Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
15971603 Secure.LOCK_PATTERN_VISIBLE,
1598- Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
1604+ Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED,
1605+ Secure.LOCK_PATTERN_SIZE,
1606+ Secure.LOCK_DOTS_VISIBLE,
1607+ Secure.LOCK_SHOW_ERROR_PATH,
15991608 };
16001609
16011610 // Reading these settings needs the contacts permission
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -16,8 +16,6 @@
1616
1717 package com.android.server;
1818
19-import com.android.internal.annotations.VisibleForTesting;
20-
2119 import android.content.ContentValues;
2220 import android.content.Context;
2321 import android.content.pm.UserInfo;
@@ -25,12 +23,17 @@ import android.database.Cursor;
2523 import android.database.sqlite.SQLiteDatabase;
2624 import android.database.sqlite.SQLiteOpenHelper;
2725 import android.os.Environment;
26+import android.os.RemoteException;
2827 import android.os.UserManager;
28+import android.provider.Settings;
2929 import android.util.ArrayMap;
3030 import android.util.Log;
3131 import android.util.Slog;
3232 import android.util.SparseArray;
3333
34+import com.android.internal.annotations.VisibleForTesting;
35+import com.android.internal.widget.LockPatternUtils;
36+
3437 import java.io.File;
3538 import java.io.IOException;
3639 import java.io.RandomAccessFile;
@@ -359,6 +362,8 @@ class LockSettingsStorage {
359362 mStoredCredentialType.put(userId, hash == null ? CredentialHash.TYPE_NONE
360363 : CredentialHash.TYPE_PATTERN);
361364 writeFile(getLockPatternFilename(userId), hash);
365+
366+ writeFile(getLockPatternFilename(userId), hash);
362367 clearPasswordHash(userId);
363368 }
364369
@@ -377,9 +382,22 @@ class LockSettingsStorage {
377382 writeFile(getLockPasswordFilename(userId), null);
378383 }
379384
385+ public byte getLockPatternSize(int userId) {
386+ long size = Long.valueOf(readKeyValue(Settings.Secure.LOCK_PATTERN_SIZE, "-1", userId));
387+ if (size > 0 && size < 128) {
388+ return (byte) size;
389+ }
390+ return LockPatternUtils.PATTERN_SIZE_DEFAULT;
391+ }
392+
393+ public boolean isDefaultSize(int userId) {
394+ return getLockPatternSize(userId) == LockPatternUtils.PATTERN_SIZE_DEFAULT;
395+ }
396+
380397 @VisibleForTesting
381398 String getLockPatternFilename(int userId) {
382- return getLockCredentialFilePathForUser(userId, LOCK_PATTERN_FILE);
399+ String baseFileName = LOCK_PATTERN_FILE;
400+ return getLockCredentialFilePathForUser(userId, baseFileName);
383401 }
384402
385403 @VisibleForTesting