frameworks/base
Revisão | abf94441542ac8dcd3eb1236a98ef5bcb0de52c8 (tree) |
---|---|
Hora | 2016-10-03 22:57:35 |
Autor | Michael Bestas <mikeioannina@gmai...> |
Commiter | Steve Kondik |
Forward port CM Screen Security settings (1/2)
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>
@@ -4256,6 +4256,9 @@ public final class Settings { | ||
4256 | 4256 | MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_ENABLED); |
4257 | 4257 | MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_VISIBLE); |
4258 | 4258 | 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); | |
4259 | 4262 | |
4260 | 4263 | MOVED_TO_GLOBAL = new HashSet<String>(); |
4261 | 4264 | MOVED_TO_GLOBAL.add(Settings.Global.ADB_ENABLED); |
@@ -5068,6 +5071,24 @@ public final class Settings { | ||
5068 | 5071 | LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled"; |
5069 | 5072 | |
5070 | 5073 | /** |
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 | + /** | |
5071 | 5092 | * This preference allows the device to be locked given time after screen goes off, |
5072 | 5093 | * subject to current DeviceAdmin policy limits. |
5073 | 5094 | * @hide |
@@ -35,6 +35,7 @@ interface ILockSettings { | ||
35 | 35 | VerifyCredentialResponse checkPassword(in String password, int userId); |
36 | 36 | VerifyCredentialResponse verifyPassword(in String password, long challenge, int userId); |
37 | 37 | VerifyCredentialResponse verifyTiedProfileChallenge(String password, boolean isPattern, long challenge, int userId); |
38 | + byte getLockPatternSize(int userId); | |
38 | 39 | boolean checkVoldPassword(int userId); |
39 | 40 | boolean havePattern(int userId); |
40 | 41 | boolean havePassword(int userId); |
@@ -97,6 +97,11 @@ public class LockPatternUtils { | ||
97 | 97 | */ |
98 | 98 | public static final int MIN_LOCK_PASSWORD_SIZE = 4; |
99 | 99 | |
100 | + /* | |
101 | + * The default size of the pattern lockscreen. Ex: 3x3 | |
102 | + */ | |
103 | + public static final byte PATTERN_SIZE_DEFAULT = 3; | |
104 | + | |
100 | 105 | /** |
101 | 106 | * The minimum number of dots the user must include in a wrong pattern |
102 | 107 | * attempt for it to be counted against the counts that affect |
@@ -315,7 +320,7 @@ public class LockPatternUtils { | ||
315 | 320 | throwIfCalledOnMainThread(); |
316 | 321 | try { |
317 | 322 | VerifyCredentialResponse response = |
318 | - getLockSettings().verifyPattern(patternToString(pattern), challenge, userId); | |
323 | + getLockSettings().verifyPattern(patternToString(pattern, userId), challenge, userId); | |
319 | 324 | if (response == null) { |
320 | 325 | // Shouldn't happen |
321 | 326 | return null; |
@@ -344,7 +349,7 @@ public class LockPatternUtils { | ||
344 | 349 | throwIfCalledOnMainThread(); |
345 | 350 | try { |
346 | 351 | VerifyCredentialResponse response = |
347 | - getLockSettings().checkPattern(patternToString(pattern), userId); | |
352 | + getLockSettings().checkPattern(patternToString(pattern, userId), userId); | |
348 | 353 | |
349 | 354 | if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { |
350 | 355 | return true; |
@@ -614,7 +619,7 @@ public class LockPatternUtils { | ||
614 | 619 | + MIN_LOCK_PATTERN_SIZE + " dots long."); |
615 | 620 | } |
616 | 621 | |
617 | - getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId); | |
622 | + getLockSettings().setLockPattern(patternToString(pattern, userId), savedPattern, userId); | |
618 | 623 | DevicePolicyManager dpm = getDevicePolicyManager(); |
619 | 624 | |
620 | 625 | // Update the device encryption password. |
@@ -623,7 +628,7 @@ public class LockPatternUtils { | ||
623 | 628 | if (!shouldEncryptWithCredentials(true)) { |
624 | 629 | clearEncryptionPassword(); |
625 | 630 | } else { |
626 | - String stringPattern = patternToString(pattern); | |
631 | + String stringPattern = patternToString(pattern, userId); | |
627 | 632 | updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern); |
628 | 633 | } |
629 | 634 | } |
@@ -1025,17 +1030,18 @@ public class LockPatternUtils { | ||
1025 | 1030 | * @param string The pattern serialized with {@link #patternToString} |
1026 | 1031 | * @return The pattern. |
1027 | 1032 | */ |
1028 | - public static List<LockPatternView.Cell> stringToPattern(String string) { | |
1033 | + public static List<LockPatternView.Cell> stringToPattern(String string, byte gridSize) { | |
1029 | 1034 | if (string == null) { |
1030 | 1035 | return null; |
1031 | 1036 | } |
1032 | - | |
1033 | 1037 | List<LockPatternView.Cell> result = Lists.newArrayList(); |
1034 | 1038 | |
1039 | + LockPatternView.Cell.updateSize(gridSize); | |
1040 | + | |
1035 | 1041 | final byte[] bytes = string.getBytes(); |
1036 | 1042 | for (int i = 0; i < bytes.length; i++) { |
1037 | 1043 | 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)); | |
1039 | 1045 | } |
1040 | 1046 | return result; |
1041 | 1047 | } |
@@ -1045,16 +1051,26 @@ public class LockPatternUtils { | ||
1045 | 1051 | * @param pattern The pattern. |
1046 | 1052 | * @return The pattern in string form. |
1047 | 1053 | */ |
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) { | |
1049 | 1064 | if (pattern == null) { |
1050 | 1065 | return ""; |
1051 | 1066 | } |
1052 | 1067 | final int patternSize = pattern.size(); |
1068 | + LockPatternView.Cell.updateSize(gridSize); | |
1053 | 1069 | |
1054 | 1070 | byte[] res = new byte[patternSize]; |
1055 | 1071 | for (int i = 0; i < patternSize; i++) { |
1056 | 1072 | 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'); | |
1058 | 1074 | } |
1059 | 1075 | return new String(res); |
1060 | 1076 | } |
@@ -1064,7 +1080,6 @@ public class LockPatternUtils { | ||
1064 | 1080 | return ""; |
1065 | 1081 | } |
1066 | 1082 | final int patternSize = pattern.length(); |
1067 | - | |
1068 | 1083 | byte[] res = new byte[patternSize]; |
1069 | 1084 | final byte[] bytes = pattern.getBytes(); |
1070 | 1085 | for (int i = 0; i < patternSize; i++) { |
@@ -1080,7 +1095,7 @@ public class LockPatternUtils { | ||
1080 | 1095 | * @param pattern the gesture pattern. |
1081 | 1096 | * @return the hash of the pattern in a byte array. |
1082 | 1097 | */ |
1083 | - public static byte[] patternToHash(List<LockPatternView.Cell> pattern) { | |
1098 | + public static byte[] patternToHash(List<LockPatternView.Cell> pattern, byte gridSize) { | |
1084 | 1099 | if (pattern == null) { |
1085 | 1100 | return null; |
1086 | 1101 | } |
@@ -1089,7 +1104,7 @@ public class LockPatternUtils { | ||
1089 | 1104 | byte[] res = new byte[patternSize]; |
1090 | 1105 | for (int i = 0; i < patternSize; i++) { |
1091 | 1106 | LockPatternView.Cell cell = pattern.get(i); |
1092 | - res[i] = (byte) (cell.getRow() * 3 + cell.getColumn()); | |
1107 | + res[i] = (byte) (cell.getRow() * gridSize + cell.getColumn()); | |
1093 | 1108 | } |
1094 | 1109 | try { |
1095 | 1110 | MessageDigest md = MessageDigest.getInstance("SHA-1"); |
@@ -1257,6 +1272,40 @@ public class LockPatternUtils { | ||
1257 | 1272 | } |
1258 | 1273 | |
1259 | 1274 | /** |
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 | + /** | |
1260 | 1309 | * Set and store the lockout deadline, meaning the user can't attempt his/her unlock |
1261 | 1310 | * pattern until the deadline has passed. |
1262 | 1311 | * @return the chosen deadline. |
@@ -51,6 +51,7 @@ import android.view.animation.AnimationUtils; | ||
51 | 51 | import android.view.animation.Interpolator; |
52 | 52 | |
53 | 53 | import com.android.internal.R; |
54 | +import com.android.internal.widget.LockPatternUtils; | |
54 | 55 | |
55 | 56 | import java.util.ArrayList; |
56 | 57 | import java.util.HashMap; |
@@ -58,7 +59,7 @@ import java.util.List; | ||
58 | 59 | |
59 | 60 | /** |
60 | 61 | * 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. | |
62 | 63 | * |
63 | 64 | * Is also capable of displaying a static pattern in "in progress", "wrong" or |
64 | 65 | * "correct" states. |
@@ -70,7 +71,7 @@ public class LockPatternView extends View { | ||
70 | 71 | private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h) |
71 | 72 | |
72 | 73 | private static final boolean PROFILE_DRAWING = false; |
73 | - private final CellState[][] mCellStates; | |
74 | + private CellState[][] mCellStates; | |
74 | 75 | |
75 | 76 | private final int mDotSize; |
76 | 77 | private final int mDotSizeActivated; |
@@ -88,6 +89,8 @@ public class LockPatternView extends View { | ||
88 | 89 | */ |
89 | 90 | private static final int MILLIS_PER_CIRCLE_ANIMATING = 700; |
90 | 91 | |
92 | + private byte mPatternSize = LockPatternUtils.PATTERN_SIZE_DEFAULT; | |
93 | + | |
91 | 94 | /** |
92 | 95 | * This can be used to avoid updating the display for very small motions or noisy panels. |
93 | 96 | * 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 { | ||
98 | 101 | private static final String TAG = "LockPatternView"; |
99 | 102 | |
100 | 103 | private OnPatternListener mOnPatternListener; |
101 | - private final ArrayList<Cell> mPattern = new ArrayList<Cell>(9); | |
104 | + private ArrayList<Cell> mPattern = new ArrayList<Cell>(mPatternSize * mPatternSize); | |
102 | 105 | |
103 | 106 | /** |
104 | 107 | * Lookup table for the circles of the pattern we are currently drawing. |
@@ -106,7 +109,7 @@ public class LockPatternView extends View { | ||
106 | 109 | * in which case we use this to hold the cells we are drawing for the in |
107 | 110 | * progress animation. |
108 | 111 | */ |
109 | - private final boolean[][] mPatternDrawLookup = new boolean[3][3]; | |
112 | + private boolean[][] mPatternDrawLookup = new boolean[mPatternSize][mPatternSize]; | |
110 | 113 | |
111 | 114 | /** |
112 | 115 | * the in progress point: |
@@ -123,6 +126,8 @@ public class LockPatternView extends View { | ||
123 | 126 | private boolean mInStealthMode = false; |
124 | 127 | private boolean mEnableHapticFeedback = true; |
125 | 128 | private boolean mPatternInProgress = false; |
129 | + private boolean mVisibleDots = true; | |
130 | + private boolean mShowErrorPath = true; | |
126 | 131 | |
127 | 132 | private float mHitFactor = 0.6f; |
128 | 133 |
@@ -143,32 +148,26 @@ public class LockPatternView extends View { | ||
143 | 148 | private PatternExploreByTouchHelper mExploreByTouchHelper; |
144 | 149 | private AudioManager mAudioManager; |
145 | 150 | |
151 | + private LockPatternUtils mLockPatternUtils; | |
152 | + | |
146 | 153 | /** |
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. | |
148 | 155 | */ |
149 | 156 | public static final class Cell { |
150 | 157 | final int row; |
151 | 158 | final int column; |
152 | 159 | |
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); | |
164 | 163 | } |
165 | 164 | |
166 | 165 | /** |
167 | 166 | * @param row The row of the cell. |
168 | 167 | * @param column The column of the cell. |
169 | 168 | */ |
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); | |
172 | 171 | this.row = row; |
173 | 172 | this.column = column; |
174 | 173 | } |
@@ -181,17 +180,30 @@ public class LockPatternView extends View { | ||
181 | 180 | return column; |
182 | 181 | } |
183 | 182 | |
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); | |
186 | 189 | return sCells[row][column]; |
187 | 190 | } |
188 | 191 | |
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 | + } | |
192 | 198 | } |
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)); | |
195 | 207 | } |
196 | 208 | } |
197 | 209 |
@@ -317,9 +329,9 @@ public class LockPatternView extends View { | ||
317 | 329 | mPaint.setAntiAlias(true); |
318 | 330 | mPaint.setDither(true); |
319 | 331 | |
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++) { | |
323 | 335 | mCellStates[i][j] = new CellState(); |
324 | 336 | mCellStates[i][j].radius = mDotSize/2; |
325 | 337 | mCellStates[i][j].row = i; |
@@ -356,6 +368,13 @@ public class LockPatternView extends View { | ||
356 | 368 | } |
357 | 369 | |
358 | 370 | /** |
371 | + * @return the current pattern lockscreen size. | |
372 | + */ | |
373 | + public byte getLockPatternSize() { | |
374 | + return mPatternSize; | |
375 | + } | |
376 | + | |
377 | + /** | |
359 | 378 | * Set whether the view is in stealth mode. If true, there will be no |
360 | 379 | * visible feedback as the user enters the pattern. |
361 | 380 | * |
@@ -365,6 +384,22 @@ public class LockPatternView extends View { | ||
365 | 384 | mInStealthMode = inStealthMode; |
366 | 385 | } |
367 | 386 | |
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 | + | |
368 | 403 | /** |
369 | 404 | * Set whether the view will use tactile feedback. If true, there will be |
370 | 405 | * tactile feedback as the user enters the pattern. |
@@ -376,6 +411,35 @@ public class LockPatternView extends View { | ||
376 | 411 | } |
377 | 412 | |
378 | 413 | /** |
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 | + /** | |
379 | 443 | * Set the call back for pattern detection. |
380 | 444 | * @param onPatternListener The call back. |
381 | 445 | */ |
@@ -590,8 +654,8 @@ public class LockPatternView extends View { | ||
590 | 654 | * Clear the pattern lookup table. |
591 | 655 | */ |
592 | 656 | 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++) { | |
595 | 659 | mPatternDrawLookup[i][j] = false; |
596 | 660 | } |
597 | 661 | } |
@@ -615,11 +679,11 @@ public class LockPatternView extends View { | ||
615 | 679 | @Override |
616 | 680 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
617 | 681 | final int width = w - mPaddingLeft - mPaddingRight; |
618 | - mSquareWidth = width / 3.0f; | |
682 | + mSquareWidth = width / (float) mPatternSize; | |
619 | 683 | |
620 | 684 | if (DEBUG_A11Y) Log.v(TAG, "onSizeChanged(" + w + "," + h + ")"); |
621 | 685 | final int height = h - mPaddingTop - mPaddingBottom; |
622 | - mSquareHeight = height / 3.0f; | |
686 | + mSquareHeight = height / (float) mPatternSize; | |
623 | 687 | mExploreByTouchHelper.invalidateRoot(); |
624 | 688 | } |
625 | 689 |
@@ -675,7 +739,6 @@ public class LockPatternView extends View { | ||
675 | 739 | if (cell != null) { |
676 | 740 | |
677 | 741 | // check for gaps in existing pattern |
678 | - Cell fillInGapCell = null; | |
679 | 742 | final ArrayList<Cell> pattern = mPattern; |
680 | 743 | if (!pattern.isEmpty()) { |
681 | 744 | final Cell lastCell = pattern.get(pattern.size() - 1); |
@@ -685,21 +748,19 @@ public class LockPatternView extends View { | ||
685 | 748 | int fillInRow = lastCell.row; |
686 | 749 | int fillInColumn = lastCell.column; |
687 | 750 | |
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 | + } | |
694 | 761 | } |
695 | - | |
696 | - fillInGapCell = Cell.of(fillInRow, fillInColumn); | |
697 | 762 | } |
698 | 763 | |
699 | - if (fillInGapCell != null && | |
700 | - !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) { | |
701 | - addCellToPattern(fillInGapCell); | |
702 | - } | |
703 | 764 | addCellToPattern(cell); |
704 | 765 | if (mEnableHapticFeedback) { |
705 | 766 | performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, |
@@ -797,7 +858,7 @@ public class LockPatternView extends View { | ||
797 | 858 | if (mPatternDrawLookup[rowHit][columnHit]) { |
798 | 859 | return null; |
799 | 860 | } |
800 | - return Cell.of(rowHit, columnHit); | |
861 | + return Cell.of(rowHit, columnHit, mPatternSize); | |
801 | 862 | } |
802 | 863 | |
803 | 864 | /** |
@@ -811,7 +872,7 @@ public class LockPatternView extends View { | ||
811 | 872 | float hitSize = squareHeight * mHitFactor; |
812 | 873 | |
813 | 874 | float offset = mPaddingTop + (squareHeight - hitSize) / 2f; |
814 | - for (int i = 0; i < 3; i++) { | |
875 | + for (int i = 0; i < mPatternSize; i++) { | |
815 | 876 | |
816 | 877 | final float hitTop = offset + squareHeight * i; |
817 | 878 | if (y >= hitTop && y <= hitTop + hitSize) { |
@@ -831,7 +892,7 @@ public class LockPatternView extends View { | ||
831 | 892 | float hitSize = squareWidth * mHitFactor; |
832 | 893 | |
833 | 894 | float offset = mPaddingLeft + (squareWidth - hitSize) / 2f; |
834 | - for (int i = 0; i < 3; i++) { | |
895 | + for (int i = 0; i < mPatternSize; i++) { | |
835 | 896 | |
836 | 897 | final float hitLeft = offset + squareWidth * i; |
837 | 898 | if (x >= hitLeft && x <= hitLeft + hitSize) { |
@@ -985,8 +1046,8 @@ public class LockPatternView extends View { | ||
985 | 1046 | } |
986 | 1047 | |
987 | 1048 | 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++) { | |
990 | 1051 | CellState state = mCellStates[i][j]; |
991 | 1052 | if (state.lineAnimator != null) { |
992 | 1053 | state.lineAnimator.cancel(); |
@@ -1089,20 +1150,21 @@ public class LockPatternView extends View { | ||
1089 | 1150 | currentPath.rewind(); |
1090 | 1151 | |
1091 | 1152 | // 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 | + } | |
1106 | 1168 | } |
1107 | 1169 | } |
1108 | 1170 | } |
@@ -1110,8 +1172,8 @@ public class LockPatternView extends View { | ||
1110 | 1172 | // TODO: the path should be created and cached every time we hit-detect a cell |
1111 | 1173 | // only the last segment of the path should be computed here |
1112 | 1174 | // 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)); | |
1115 | 1177 | if (drawPath) { |
1116 | 1178 | mPathPaint.setColor(getCurrentColor(true /* partOfPattern */)); |
1117 | 1179 |
@@ -1169,7 +1231,9 @@ public class LockPatternView extends View { | ||
1169 | 1231 | } |
1170 | 1232 | |
1171 | 1233 | private int getCurrentColor(boolean partOfPattern) { |
1172 | - if (!partOfPattern || mInStealthMode || mPatternInProgress) { | |
1234 | + if (!partOfPattern || (mInStealthMode && mPatternDisplayMode != DisplayMode.Wrong) | |
1235 | + || (mPatternDisplayMode == DisplayMode.Wrong && !mShowErrorPath) | |
1236 | + || mPatternInProgress) { | |
1173 | 1237 | // unselected circle |
1174 | 1238 | return mRegularColor; |
1175 | 1239 | } else if (mPatternDisplayMode == DisplayMode.Wrong) { |
@@ -1197,9 +1261,9 @@ public class LockPatternView extends View { | ||
1197 | 1261 | protected Parcelable onSaveInstanceState() { |
1198 | 1262 | Parcelable superState = super.onSaveInstanceState(); |
1199 | 1263 | 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); | |
1203 | 1267 | } |
1204 | 1268 | |
1205 | 1269 | @Override |
@@ -1208,11 +1272,14 @@ public class LockPatternView extends View { | ||
1208 | 1272 | super.onRestoreInstanceState(ss.getSuperState()); |
1209 | 1273 | setPattern( |
1210 | 1274 | DisplayMode.Correct, |
1211 | - LockPatternUtils.stringToPattern(ss.getSerializedPattern())); | |
1275 | + LockPatternUtils.stringToPattern(ss.getSerializedPattern(), ss.getPatternSize())); | |
1212 | 1276 | mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()]; |
1277 | + mPatternSize = ss.getPatternSize(); | |
1213 | 1278 | mInputEnabled = ss.isInputEnabled(); |
1214 | 1279 | mInStealthMode = ss.isInStealthMode(); |
1215 | 1280 | mEnableHapticFeedback = ss.isTactileFeedbackEnabled(); |
1281 | + mVisibleDots = ss.isVisibleDots(); | |
1282 | + mShowErrorPath = ss.isShowErrorPath(); | |
1216 | 1283 | } |
1217 | 1284 | |
1218 | 1285 | /** |
@@ -1222,21 +1289,28 @@ public class LockPatternView extends View { | ||
1222 | 1289 | |
1223 | 1290 | private final String mSerializedPattern; |
1224 | 1291 | private final int mDisplayMode; |
1292 | + private final byte mPatternSize; | |
1225 | 1293 | private final boolean mInputEnabled; |
1226 | 1294 | private final boolean mInStealthMode; |
1227 | 1295 | private final boolean mTactileFeedbackEnabled; |
1296 | + private final boolean mVisibleDots; | |
1297 | + private final boolean mShowErrorPath; | |
1228 | 1298 | |
1229 | 1299 | /** |
1230 | 1300 | * Constructor called from {@link LockPatternView#onSaveInstanceState()} |
1231 | 1301 | */ |
1232 | 1302 | 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) { | |
1234 | 1305 | super(superState); |
1235 | 1306 | mSerializedPattern = serializedPattern; |
1236 | 1307 | mDisplayMode = displayMode; |
1308 | + mPatternSize = patternSize; | |
1237 | 1309 | mInputEnabled = inputEnabled; |
1238 | 1310 | mInStealthMode = inStealthMode; |
1239 | 1311 | mTactileFeedbackEnabled = tactileFeedbackEnabled; |
1312 | + mVisibleDots = visibleDots; | |
1313 | + mShowErrorPath = showErrorPath; | |
1240 | 1314 | } |
1241 | 1315 | |
1242 | 1316 | /** |
@@ -1246,9 +1320,12 @@ public class LockPatternView extends View { | ||
1246 | 1320 | super(in); |
1247 | 1321 | mSerializedPattern = in.readString(); |
1248 | 1322 | mDisplayMode = in.readInt(); |
1323 | + mPatternSize = (byte) in.readByte(); | |
1249 | 1324 | mInputEnabled = (Boolean) in.readValue(null); |
1250 | 1325 | mInStealthMode = (Boolean) in.readValue(null); |
1251 | 1326 | mTactileFeedbackEnabled = (Boolean) in.readValue(null); |
1327 | + mVisibleDots = (Boolean) in.readValue(null); | |
1328 | + mShowErrorPath = (Boolean) in.readValue(null); | |
1252 | 1329 | } |
1253 | 1330 | |
1254 | 1331 | public String getSerializedPattern() { |
@@ -1259,6 +1336,10 @@ public class LockPatternView extends View { | ||
1259 | 1336 | return mDisplayMode; |
1260 | 1337 | } |
1261 | 1338 | |
1339 | + public byte getPatternSize() { | |
1340 | + return mPatternSize; | |
1341 | + } | |
1342 | + | |
1262 | 1343 | public boolean isInputEnabled() { |
1263 | 1344 | return mInputEnabled; |
1264 | 1345 | } |
@@ -1271,14 +1352,25 @@ public class LockPatternView extends View { | ||
1271 | 1352 | return mTactileFeedbackEnabled; |
1272 | 1353 | } |
1273 | 1354 | |
1355 | + public boolean isVisibleDots() { | |
1356 | + return mVisibleDots; | |
1357 | + } | |
1358 | + | |
1359 | + public boolean isShowErrorPath() { | |
1360 | + return mShowErrorPath; | |
1361 | + } | |
1362 | + | |
1274 | 1363 | @Override |
1275 | 1364 | public void writeToParcel(Parcel dest, int flags) { |
1276 | 1365 | super.writeToParcel(dest, flags); |
1277 | 1366 | dest.writeString(mSerializedPattern); |
1278 | 1367 | dest.writeInt(mDisplayMode); |
1368 | + dest.writeByte(mPatternSize); | |
1279 | 1369 | dest.writeValue(mInputEnabled); |
1280 | 1370 | dest.writeValue(mInStealthMode); |
1281 | 1371 | dest.writeValue(mTactileFeedbackEnabled); |
1372 | + dest.writeValue(mVisibleDots); | |
1373 | + dest.writeValue(mShowErrorPath); | |
1282 | 1374 | } |
1283 | 1375 | |
1284 | 1376 | @SuppressWarnings({ "unused", "hiding" }) // Found using reflection |
@@ -135,6 +135,15 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit | ||
135 | 135 | mLockPatternView = (LockPatternView) findViewById(R.id.lockPatternView); |
136 | 136 | mLockPatternView.setSaveEnabled(false); |
137 | 137 | 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); | |
138 | 147 | |
139 | 148 | // vibrate mode will be the same for the life of this screen |
140 | 149 | mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); |
@@ -736,6 +736,9 @@ class DatabaseHelper extends SQLiteOpenHelper { | ||
736 | 736 | Secure.LOCK_PATTERN_ENABLED, |
737 | 737 | Secure.LOCK_PATTERN_VISIBLE, |
738 | 738 | Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED, |
739 | + Secure.LOCK_PATTERN_SIZE, | |
740 | + Secure.LOCK_DOTS_VISIBLE, | |
741 | + Secure.LOCK_SHOW_ERROR_PATH, | |
739 | 742 | "lockscreen.password_type", |
740 | 743 | "lockscreen.lockoutattemptdeadline", |
741 | 744 | "lockscreen.patterneverchosen", |
@@ -2071,7 +2074,8 @@ class DatabaseHelper extends SQLiteOpenHelper { | ||
2071 | 2074 | try { |
2072 | 2075 | LockPatternUtils lpu = new LockPatternUtils(mContext); |
2073 | 2076 | List<LockPatternView.Cell> cellPattern = |
2074 | - LockPatternUtils.stringToPattern(lockPattern); | |
2077 | + LockPatternUtils.stringToPattern(lockPattern, | |
2078 | + lpu.getLockPatternSize(mUserHandle)); | |
2075 | 2079 | lpu.saveLockPattern(cellPattern, null, UserHandle.USER_SYSTEM); |
2076 | 2080 | } catch (IllegalArgumentException e) { |
2077 | 2081 | // Don't want corrupted lock pattern to hang the reboot process |
@@ -931,6 +931,10 @@ public class LockSettingsService extends ILockSettings.Stub { | ||
931 | 931 | && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId); |
932 | 932 | } |
933 | 933 | |
934 | + public byte getLockPatternSize(int userId) { | |
935 | + return mStorage.getLockPatternSize(userId); | |
936 | + } | |
937 | + | |
934 | 938 | // This method should be called by LockPatternUtil only, all internal methods in this class |
935 | 939 | // should call setLockPatternInternal. |
936 | 940 | @Override |
@@ -1285,8 +1289,10 @@ public class LockSettingsService extends ILockSettings.Stub { | ||
1285 | 1289 | |
1286 | 1290 | @Override |
1287 | 1291 | public byte[] toHash(String pattern, int userId) { |
1292 | + final byte lockPatternSize = getLockPatternSize(userId); | |
1288 | 1293 | return LockPatternUtils.patternToHash( |
1289 | - LockPatternUtils.stringToPattern(pattern)); | |
1294 | + LockPatternUtils.stringToPattern(pattern, lockPatternSize), | |
1295 | + lockPatternSize); | |
1290 | 1296 | } |
1291 | 1297 | |
1292 | 1298 | @Override |
@@ -1595,7 +1601,10 @@ public class LockSettingsService extends ILockSettings.Stub { | ||
1595 | 1601 | Secure.LOCK_PATTERN_ENABLED, |
1596 | 1602 | Secure.LOCK_BIOMETRIC_WEAK_FLAGS, |
1597 | 1603 | 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, | |
1599 | 1608 | }; |
1600 | 1609 | |
1601 | 1610 | // Reading these settings needs the contacts permission |
@@ -16,8 +16,6 @@ | ||
16 | 16 | |
17 | 17 | package com.android.server; |
18 | 18 | |
19 | -import com.android.internal.annotations.VisibleForTesting; | |
20 | - | |
21 | 19 | import android.content.ContentValues; |
22 | 20 | import android.content.Context; |
23 | 21 | import android.content.pm.UserInfo; |
@@ -25,12 +23,17 @@ import android.database.Cursor; | ||
25 | 23 | import android.database.sqlite.SQLiteDatabase; |
26 | 24 | import android.database.sqlite.SQLiteOpenHelper; |
27 | 25 | import android.os.Environment; |
26 | +import android.os.RemoteException; | |
28 | 27 | import android.os.UserManager; |
28 | +import android.provider.Settings; | |
29 | 29 | import android.util.ArrayMap; |
30 | 30 | import android.util.Log; |
31 | 31 | import android.util.Slog; |
32 | 32 | import android.util.SparseArray; |
33 | 33 | |
34 | +import com.android.internal.annotations.VisibleForTesting; | |
35 | +import com.android.internal.widget.LockPatternUtils; | |
36 | + | |
34 | 37 | import java.io.File; |
35 | 38 | import java.io.IOException; |
36 | 39 | import java.io.RandomAccessFile; |
@@ -359,6 +362,8 @@ class LockSettingsStorage { | ||
359 | 362 | mStoredCredentialType.put(userId, hash == null ? CredentialHash.TYPE_NONE |
360 | 363 | : CredentialHash.TYPE_PATTERN); |
361 | 364 | writeFile(getLockPatternFilename(userId), hash); |
365 | + | |
366 | + writeFile(getLockPatternFilename(userId), hash); | |
362 | 367 | clearPasswordHash(userId); |
363 | 368 | } |
364 | 369 |
@@ -377,9 +382,22 @@ class LockSettingsStorage { | ||
377 | 382 | writeFile(getLockPasswordFilename(userId), null); |
378 | 383 | } |
379 | 384 | |
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 | + | |
380 | 397 | @VisibleForTesting |
381 | 398 | String getLockPatternFilename(int userId) { |
382 | - return getLockCredentialFilePathForUser(userId, LOCK_PATTERN_FILE); | |
399 | + String baseFileName = LOCK_PATTERN_FILE; | |
400 | + return getLockCredentialFilePathForUser(userId, baseFileName); | |
383 | 401 | } |
384 | 402 | |
385 | 403 | @VisibleForTesting |