Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Framwork: Add support for variable size pattern lockscreen (Part 1/2)

Changes LockPatternView to use PATTERN_SIZE instead of the hardcoded value '3'.
Adds methods to set and get PATTERN_SIZE via LockPatternUtils and device settings.

With this patch the pattern lockscreen can go from 3x3 to any sane size such as 6x6.
LockPatternView can be taken by itself if settings are not desired, for an easy way to change the hardcoded size.

Patch Set 3: Rebased,
should fix cherry-pick after the "widgets before unlock" commit.

Patch Set 4+5: Fix whitespace
Patch Set 6: Missed one Gremlin. (Fixed for real)

Patch Set 7: Rebased

Patch Set 8: Added missing hide statements

Change-Id: Ibc0d5bfcee9673b1bf049bd69be80d2312602a47
  • Loading branch information...
commit 0f4e7b7602eb7609941ed69e84e3d67259472c4d 1 parent 0f1f6f1
Rowan Decker authored July 26, 2012 Gerrit Code Review committed September 01, 2012
17  core/java/android/provider/Settings.java
@@ -805,6 +805,7 @@ public String getString(ContentResolver cr, String name) {
805 805
             MOVED_TO_SECURE.add(Secure.LOCK_SHOW_ERROR_PATH);
806 806
             MOVED_TO_SECURE.add(Secure.LOCK_DOTS_VISIBLE);
807 807
             MOVED_TO_SECURE.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
  808
+            MOVED_TO_SECURE.add(Secure.LOCK_PATTERN_SIZE);
808 809
             MOVED_TO_SECURE.add(Secure.LOGGING_ID);
809 810
             MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_ENABLED);
810 811
             MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_LAST_UPDATE);
@@ -1358,6 +1359,14 @@ public static void setShowGTalkServiceStatus(ContentResolver cr, boolean flag) {
1358 1359
         public static final String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED =
1359 1360
             "lock_pattern_tactile_feedback_enabled";
1360 1361
 
  1362
+         /**
  1363
+         * @deprecated Use {@link android.provider.Settings.Secure#LOCK_PATTERN_SIZE}
  1364
+         * instead
  1365
+         * @hide
  1366
+         */
  1367
+        @Deprecated
  1368
+        public static final String LOCK_PATTERN_SIZE =
  1369
+            "lock_pattern_size";
1361 1370
 
1362 1371
         /**
1363 1372
          * A formatted string of the next alarm that is set, or the empty string
@@ -3113,6 +3122,7 @@ public static void setShowGTalkServiceStatus(ContentResolver cr, boolean flag) {
3113 3122
             MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_SHOW_ERROR_PATH);
3114 3123
             MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_DOTS_VISIBLE);
3115 3124
             MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
  3125
+            MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_SIZE);
3116 3126
             MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_BEFORE_UNLOCK);
3117 3127
         }
3118 3128
 
@@ -3598,6 +3608,13 @@ public static final String getBluetoothInputDevicePriorityKey(String address) {
3598 3608
         public static final String LOCK_SHOW_ERROR_PATH = "lock_pattern_show_error_path";
3599 3609
 
3600 3610
         /**
  3611
+         * Size of pattern lockscreen
  3612
+         * @hide
  3613
+         */
  3614
+        public static final String LOCK_PATTERN_SIZE = "lock_pattern_size";
  3615
+
  3616
+
  3617
+        /**
3601 3618
          * This preference allows the device to be locked given time after screen goes off,
3602 3619
          * subject to current DeviceAdmin policy limits.
3603 3620
          * @hide
2  core/java/com/android/internal/widget/ILockSettings.aidl
@@ -20,9 +20,11 @@ package com.android.internal.widget;
20 20
 interface ILockSettings {
21 21
     void setBoolean(in String key, in boolean value, in int userId);
22 22
     void setLong(in String key, in long value, in int userId);
  23
+    void setInteger(in String key, in int value, in int userId);
23 24
     void setString(in String key, in String value, in int userId);
24 25
     boolean getBoolean(in String key, in boolean defaultValue, in int userId);
25 26
     long getLong(in String key, in long defaultValue, in int userId);
  27
+    int getInteger(in String key, in int defaultValue, in int userId);
26 28
     String getString(in String key, in String defaultValue, in int userId);
27 29
     void setLockPattern(in byte[] hash, int userId);
28 30
     boolean checkPattern(in byte[] hash, int userId);
50  core/java/com/android/internal/widget/LockPatternUtils.java
@@ -144,6 +144,8 @@
144 144
     private ILockSettings mLockSettingsService;
145 145
     private int mCurrentUserId = 0;
146 146
 
  147
+    private static int PATTERN_SIZE = 3;
  148
+
147 149
     public DevicePolicyManager getDevicePolicyManager() {
148 150
         if (mDevicePolicyManager == null) {
149 151
             mDevicePolicyManager =
@@ -704,7 +706,7 @@ public boolean usingBiometricWeak() {
704 706
         final byte[] bytes = string.getBytes();
705 707
         for (int i = 0; i < bytes.length; i++) {
706 708
             byte b = bytes[i];
707  
-            result.add(LockPatternView.Cell.of(b / 3, b % 3));
  709
+            result.add(LockPatternView.Cell.of(b / PATTERN_SIZE, b % PATTERN_SIZE));
708 710
         }
709 711
         return result;
710 712
     }
@@ -723,7 +725,7 @@ public static String patternToString(List<LockPatternView.Cell> pattern) {
723 725
         byte[] res = new byte[patternSize];
724 726
         for (int i = 0; i < patternSize; i++) {
725 727
             LockPatternView.Cell cell = pattern.get(i);
726  
-            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
  728
+            res[i] = (byte) (cell.getRow() * PATTERN_SIZE + cell.getColumn());
727 729
         }
728 730
         return new String(res);
729 731
     }
@@ -744,7 +746,7 @@ public static String patternToString(List<LockPatternView.Cell> pattern) {
744 746
         byte[] res = new byte[patternSize];
745 747
         for (int i = 0; i < patternSize; i++) {
746 748
             LockPatternView.Cell cell = pattern.get(i);
747  
-            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
  749
+            res[i] = (byte) (cell.getRow() * PATTERN_SIZE + cell.getColumn());
748 750
         }
749 751
         try {
750 752
             MessageDigest md = MessageDigest.getInstance("SHA-1");
@@ -935,6 +937,30 @@ public boolean isShowErrorPath() {
935 937
     }
936 938
 
937 939
     /**
  940
+     * @return the pattern lockscreen size
  941
+     */
  942
+    public int getLockPatternSize() {
  943
+        return getInteger(Settings.Secure.LOCK_PATTERN_SIZE, 3);
  944
+    }
  945
+
  946
+    /**
  947
+     * Set the pattern lockscreen size
  948
+     */
  949
+    public void setLockPatternSize(int size) {
  950
+        setInteger(Settings.Secure.LOCK_PATTERN_SIZE, size);
  951
+        PATTERN_SIZE = size;
  952
+    }
  953
+
  954
+    /**
  955
+     * Update PATTERN_SIZE for this LockPatternUtils instance
  956
+     * This must be called before patternToHash, patternToString, etc
  957
+     * will work correctly with a non-standard size
  958
+     */
  959
+    public void updateLockPatternSize() {
  960
+        PATTERN_SIZE = getLockPatternSize();
  961
+    }
  962
+
  963
+    /**
938 964
      * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
939 965
      * pattern until the deadline has passed.
940 966
      * @return the chosen deadline.
@@ -1204,6 +1230,24 @@ private void setLong(String secureSettingKey, long value) {
1204 1230
         }
1205 1231
     }
1206 1232
 
  1233
+    private int getInteger(String secureSettingKey, int defaultValue) {
  1234
+        try {
  1235
+            return getLockSettings().getInteger(secureSettingKey, defaultValue,
  1236
+                    getCurrentOrCallingUserId());
  1237
+        } catch (RemoteException re) {
  1238
+            return defaultValue;
  1239
+        }
  1240
+    }
  1241
+
  1242
+    private void setInteger(String secureSettingKey, int value) {
  1243
+        try {
  1244
+            getLockSettings().setInteger(secureSettingKey, value, getCurrentOrCallingUserId());
  1245
+        } catch (RemoteException re) {
  1246
+            // What can we do?
  1247
+            Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
  1248
+        }
  1249
+    }
  1250
+
1207 1251
     private String getString(String secureSettingKey) {
1208 1252
         try {
1209 1253
             return getLockSettings().getString(secureSettingKey, null,
105  core/java/com/android/internal/widget/LockPatternView.java
@@ -47,7 +47,7 @@
47 47
 
48 48
 /**
49 49
  * Displays and detects the user's unlock attempt, which is a drag of a finger
50  
- * across 9 regions of the screen.
  50
+ * across PATTERN_SIZE regions of the screen.
51 51
  *
52 52
  * Is also capable of displaying a static pattern in "in progress", "wrong" or
53 53
  * "correct" states.
@@ -77,7 +77,7 @@
77 77
     private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
78 78
 
79 79
     private OnPatternListener mOnPatternListener;
80  
-    private ArrayList<Cell> mPattern = new ArrayList<Cell>(9);
  80
+    private ArrayList<Cell> mPattern = new ArrayList<Cell>(PATTERN_SIZE*PATTERN_SIZE);
81 81
 
82 82
     /**
83 83
      * Lookup table for the circles of the pattern we are currently drawing.
@@ -85,7 +85,7 @@
85 85
      * in which case we use this to hold the cells we are drawing for the in
86 86
      * progress animation.
87 87
      */
88  
-    private boolean[][] mPatternDrawLookup = new boolean[3][3];
  88
+    private boolean[][] mPatternDrawLookup = new boolean[PATTERN_SIZE][PATTERN_SIZE];
89 89
 
90 90
     /**
91 91
      * the in progress point:
@@ -134,22 +134,19 @@
134 134
     private final Matrix mArrowMatrix = new Matrix();
135 135
     private final Matrix mCircleMatrix = new Matrix();
136 136
 
  137
+    private static int PATTERN_SIZE = 3;
137 138
 
138 139
     /**
139  
-     * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
  140
+     * Represents a cell in the PATTERN_SIZE X PATTERN_SIZE matrix of the unlock pattern view.
140 141
      */
141 142
     public static class Cell {
142 143
         int row;
143 144
         int column;
144 145
 
145  
-        // keep # objects limited to 9
146  
-        static Cell[][] sCells = new Cell[3][3];
  146
+        // keep # objects limited to PATTERN_SIZE
  147
+        static Cell[][] sCells;
147 148
         static {
148  
-            for (int i = 0; i < 3; i++) {
149  
-                for (int j = 0; j < 3; j++) {
150  
-                    sCells[i][j] = new Cell(i, j);
151  
-                }
152  
-            }
  149
+            updateSize();
153 150
         }
154 151
 
155 152
         /**
@@ -179,12 +176,21 @@ public static synchronized Cell of(int row, int column) {
179 176
             return sCells[row][column];
180 177
         }
181 178
 
  179
+        public static void updateSize() {
  180
+           sCells = new Cell[PATTERN_SIZE][PATTERN_SIZE];
  181
+           for (int i = 0; i < PATTERN_SIZE; i++) {
  182
+                for (int j = 0; j < PATTERN_SIZE; j++) {
  183
+                    sCells[i][j] = new Cell(i, j);
  184
+                }
  185
+            }
  186
+        }
  187
+
182 188
         private static void checkRange(int row, int column) {
183  
-            if (row < 0 || row > 2) {
184  
-                throw new IllegalArgumentException("row must be in range 0-2");
  189
+            if (row < 0 || row > PATTERN_SIZE-1) {
  190
+                throw new IllegalArgumentException("row must be in range 0-" + (PATTERN_SIZE-1));
185 191
             }
186  
-            if (column < 0 || column > 2) {
187  
-                throw new IllegalArgumentException("column must be in range 0-2");
  192
+            if (column < 0 || column > PATTERN_SIZE-1) {
  193
+                throw new IllegalArgumentException("column must be in range 0-" + (PATTERN_SIZE-1));
188 194
             }
189 195
         }
190 196
 
@@ -321,6 +327,13 @@ public boolean isTactileFeedbackEnabled() {
321 327
     }
322 328
 
323 329
     /**
  330
+     * @return the current pattern lockscreen size
  331
+     */
  332
+    public int getLockPatternSize() {
  333
+        return PATTERN_SIZE;
  334
+    }
  335
+
  336
+    /**
324 337
      * Set whether the view is in stealth mode.  If true, there will be no
325 338
      * visible feedback as the user enters the pattern.
326 339
      *
@@ -357,6 +370,18 @@ public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) {
357 370
     }
358 371
 
359 372
     /**
  373
+     * Set the PATTERN_SIZE size of the lockscreen
  374
+     *
  375
+     * @param size
  376
+     */
  377
+    public void setLockPatternSize(int size) {
  378
+        PATTERN_SIZE = size;
  379
+        mPattern = new ArrayList<Cell>(PATTERN_SIZE*PATTERN_SIZE);
  380
+        mPatternDrawLookup = new boolean[PATTERN_SIZE][PATTERN_SIZE];
  381
+        Cell.updateSize();
  382
+    }
  383
+
  384
+    /**
360 385
      * Set the call back for pattern detection.
361 386
      * @param onPatternListener The call back.
362 387
      */
@@ -453,8 +478,8 @@ private void resetPattern() {
453 478
      * Clear the pattern lookup table.
454 479
      */
455 480
     private void clearPatternDrawLookup() {
456  
-        for (int i = 0; i < 3; i++) {
457  
-            for (int j = 0; j < 3; j++) {
  481
+        for (int i = 0; i < PATTERN_SIZE; i++) {
  482
+            for (int j = 0; j < PATTERN_SIZE; j++) {
458 483
                 mPatternDrawLookup[i][j] = false;
459 484
             }
460 485
         }
@@ -478,13 +503,13 @@ public void enableInput() {
478 503
     @Override
479 504
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
480 505
         final int width = w - mPaddingLeft - mPaddingRight;
481  
-        mSquareWidth = width / 3.0f;
  506
+        mSquareWidth = width / (float)PATTERN_SIZE;
482 507
 
483 508
         final int height = h - mPaddingTop - mPaddingBottom;
484  
-        mSquareHeight = height / 3.0f;
  509
+        mSquareHeight = height / (float)PATTERN_SIZE;
485 510
 
486 511
         // Try to set a message size relative to square size
487  
-        mMsgPaint.setTextSize(mSquareHeight / 6);
  512
+        mMsgPaint.setTextSize(mSquareHeight / (PATTERN_SIZE*2));
488 513
     }
489 514
 
490 515
     private int resolveMeasured(int measureSpec, int desired)
@@ -507,14 +532,14 @@ private int resolveMeasured(int measureSpec, int desired)
507 532
 
508 533
     @Override
509 534
     protected int getSuggestedMinimumWidth() {
510  
-        // View should be large enough to contain 3 side-by-side target bitmaps
511  
-        return 3 * mBitmapWidth;
  535
+        // View should be large enough to contain PATTERN_SIZE side-by-side target bitmaps
  536
+        return PATTERN_SIZE * mBitmapWidth;
512 537
     }
513 538
 
514 539
     @Override
515 540
     protected int getSuggestedMinimumHeight() {
516  
-        // View should be large enough to contain 3 side-by-side target bitmaps
517  
-        return 3 * mBitmapWidth;
  541
+        // View should be large enough to contain PATTERN_SIZE side-by-side target bitmaps
  542
+        return PATTERN_SIZE * mBitmapWidth;
518 543
     }
519 544
 
520 545
     @Override
@@ -551,7 +576,6 @@ private Cell detectAndAddHit(float x, float y) {
551 576
         if (cell != null) {
552 577
 
553 578
             // check for gaps in existing pattern
554  
-            Cell fillInGapCell = null;
555 579
             final ArrayList<Cell> pattern = mPattern;
556 580
             if (!pattern.isEmpty()) {
557 581
                 final Cell lastCell = pattern.get(pattern.size() - 1);
@@ -561,21 +585,19 @@ private Cell detectAndAddHit(float x, float y) {
561 585
                 int fillInRow = lastCell.row;
562 586
                 int fillInColumn = lastCell.column;
563 587
 
564  
-                if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) {
565  
-                    fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1);
566  
-                }
567  
-
568  
-                if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) {
569  
-                    fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1);
  588
+                if (!( (dRow!=0) && (dColumn!=0) && (Math.abs(dRow)!=Math.abs(dColumn)) )) {
  589
+                    while (true) {
  590
+                        fillInRow += Integer.signum(dRow);
  591
+                        fillInColumn += Integer.signum(dColumn);
  592
+                        if ( (fillInRow==cell.row) && (fillInColumn==cell.column) ) break;
  593
+                        Cell fillInGapCell = Cell.of(fillInRow, fillInColumn);
  594
+                        if ( !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
  595
+                            addCellToPattern(fillInGapCell);
  596
+                          }
  597
+                       }
570 598
                 }
571  
-
572  
-                fillInGapCell = Cell.of(fillInRow, fillInColumn);
573 599
             }
574 600
 
575  
-            if (fillInGapCell != null &&
576  
-                    !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
577  
-                addCellToPattern(fillInGapCell);
578  
-            }
579 601
             addCellToPattern(cell);
580 602
             if (mEnableHapticFeedback) {
581 603
                 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
@@ -591,6 +613,7 @@ private void addCellToPattern(Cell newCell) {
591 613
         mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true;
592 614
         mPattern.add(newCell);
593 615
         notifyCellAdded();
  616
+        Log.v("SMASHER816", "("+newCell.column+", "+newCell.row+")");
594 617
     }
595 618
 
596 619
     // helper method to find which cell a point maps to
@@ -622,7 +645,7 @@ private int getRowHit(float y) {
622 645
         float hitSize = squareHeight * mHitFactor;
623 646
 
624 647
         float offset = mPaddingTop + (squareHeight - hitSize) / 2f;
625  
-        for (int i = 0; i < 3; i++) {
  648
+        for (int i = 0; i < PATTERN_SIZE; i++) {
626 649
 
627 650
             final float hitTop = offset + squareHeight * i;
628 651
             if (y >= hitTop && y <= hitTop + hitSize) {
@@ -642,7 +665,7 @@ private int getColumnHit(float x) {
642 665
         float hitSize = squareWidth * mHitFactor;
643 666
 
644 667
         float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;
645  
-        for (int i = 0; i < 3; i++) {
  668
+        for (int i = 0; i < PATTERN_SIZE; i++) {
646 669
 
647 670
             final float hitLeft = offset + squareWidth * i;
648 671
             if (x >= hitLeft && x <= hitLeft + hitSize) {
@@ -954,10 +977,10 @@ protected void onDraw(Canvas canvas) {
954 977
         final int paddingTop = mPaddingTop;
955 978
         final int paddingLeft = mPaddingLeft;
956 979
 
957  
-        for (int i = 0; i < 3; i++) {
  980
+        for (int i = 0; i < PATTERN_SIZE; i++) {
958 981
             float topY = paddingTop + i * squareHeight;
959 982
             //float centerY = mPaddingTop + i * mSquareHeight + (mSquareHeight / 2);
960  
-            for (int j = 0; j < 3; j++) {
  983
+            for (int j = 0; j < PATTERN_SIZE; j++) {
961 984
                 float leftX = paddingLeft + j * squareWidth;
962 985
                 drawCircle(canvas, (int) leftX, (int) topY, drawLookup[i][j]);
963 986
             }
15  core/java/com/android/internal/widget/LockSettingsService.java
@@ -134,6 +134,13 @@ public void setLong(String key, long value, int userId) throws RemoteException {
134 134
     }
135 135
 
136 136
     @Override
  137
+    public void setInteger(String key, int value, int userId) throws RemoteException {
  138
+        checkWritePermission(userId);
  139
+
  140
+        writeToDb(key, Integer.toString(value), userId);
  141
+    }
  142
+
  143
+    @Override
137 144
     public void setString(String key, String value, int userId) throws RemoteException {
138 145
         checkWritePermission(userId);
139 146
 
@@ -158,6 +165,14 @@ public long getLong(String key, long defaultValue, int userId) throws RemoteExce
158 165
     }
159 166
 
160 167
     @Override
  168
+    public int getInteger(String key, int defaultValue, int userId) throws RemoteException {
  169
+        //checkReadPermission(userId);
  170
+
  171
+        String value = readFromDb(key, null, userId);
  172
+        return TextUtils.isEmpty(value) ? defaultValue : Integer.parseInt(value);
  173
+    }
  174
+
  175
+    @Override
161 176
     public String getString(String key, String defaultValue, int userId) throws RemoteException {
162 177
         //checkReadPermission(userId);
163 178
 
7  policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -36,7 +36,7 @@
36 36
 import java.util.List;
37 37
 
38 38
 /**
39  
- * This is the screen that shows the 9 circle unlock widget and instructs
  39
+ * This is the screen that shows the circle unlock widget and instructs
40 40
  * the user how to unlock their device, or make an emergency call.
41 41
  */
42 42
 class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient
@@ -197,10 +197,14 @@ private void updateFooter(FooterMode mode) {
197 197
         // vibrate mode will be the same for the life of this screen
198 198
         mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
199 199
 
  200
+        mLockPatternView.setLockPatternSize(mLockPatternUtils.getLockPatternSize());
  201
+
200 202
         // assume normal footer mode for now
201 203
         updateFooter(FooterMode.Normal);
202 204
 
203 205
         setFocusableInTouchMode(true);
  206
+
  207
+        mLockPatternUtils.updateLockPatternSize();
204 208
     }
205 209
 
206 210
     public void setEnableFallback(boolean state) {
@@ -348,6 +352,7 @@ public void onPatternCellAdded(List<Cell> pattern) {
348 352
         }
349 353
 
350 354
         public void onPatternDetected(List<LockPatternView.Cell> pattern) {
  355
+            mLockPatternUtils.updateLockPatternSize();
351 356
             if (mLockPatternUtils.checkPattern(pattern)) {
352 357
                 mLockPatternView
353 358
                         .setDisplayMode(LockPatternView.DisplayMode.Correct);

Git Notes

review

Code-Review+2: Steve Kondik <shade@chemlab.org>
Verified+1: Steve Kondik <shade@chemlab.org>
Submitted-by: Steve Kondik <shade@chemlab.org>
Submitted-at: Sat, 01 Sep 2012 11:21:59 +0400
Reviewed-on: http://review.cyanogenmod.com/20613
Project: CyanogenMod/android_frameworks_base
Branch: refs/heads/jellybean

0 notes on commit 0f4e7b7

Please sign in to comment.
Something went wrong with that request. Please try again.