Settings: Forward port lock pattern grid size (2/2)

Author: d34d <clark@cyngn.com>
Date:   Tue Dec 29 11:51:21 2015 -0800

    Fingerprint: Forward challenge extras

    The forward port of custom pattern sizes introduced a bug that would
    cause an NPE when trying to add a fingerprint for security. This patch
    forwards the extras associated with the challenge that would have
    normally been passed directly in to the ChooseLockPattern fragment.

    Change-Id: I3ad994b2604ff45b573c011c3588afe8b35bfdd3
    TICKET: CYNGNOS-1490

Author: Roman Birg <roman@cyngn.com>
Date:   Mon Mar 21 15:17:16 2016 -0700

    Settings: forward decrypt required on boot flag

    This wasn't being pass forward and all of the defaults had it set to
    true.

    Ticket: CYNGNOS-2270

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

Author: Roman Birg <roman@cyngn.com>
Date:   Fri Dec 11 11:37:00 2015 -0600

    Settings: allow rotation while setting new pattern

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

Author: Roman Birg <roman@cyngn.com>
Date:   Mon Apr 6 12:20:33 2015 -0700

    Settings: handle decrypting larger pattern sizes

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

Author: Roman Birg <roman@cyngn.com>
Date:   Tue Apr 28 14:02:21 2015 -0700

    CryptKeeper: pattern unlock displays incorrect pw when correct

    fakeUnlockAttempt() gets called when the user inputs any pattern length
    < 4 which queues up the 'incorrect error' message. The message needs to
    be cleared before trying to actually check the password so it never goes
    through in case the password was correct.

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

Author: Roman Birg <roman@cyngn.com>
Date:   Fri May 1 17:07:47 2015 -0700

    Settings: fix non lock pattern CryptKeeper crash

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

Author: Roman Birg <roman@cyngn.com>
Date:   Tue May 19 14:06:51 2015 -0700

    CryptKeeper: layout whole screen in bounds

    Add flags to make the screen layout properly on devices with the
    navigation bar visible

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

Author: Roman Birg <roman@cyngn.com>
Date:   Wed May 20 10:31:13 2015 -0700

    CryptKeeper improvements

    - Status text was used enough to warrant it being a field variable
      instead of looking for the view every time

    - Display proper text after changing pattern sizes (to input a pattern,
      not a password)

    - Disable changing pattern sizes while validaing pattern

    REFS: LETTUCE-557, LETTUCE-352
    Change-Id: Ib4ecf04a58da8d1648d514d9650d69c33d9587a7
    Signed-off-by: Roman Birg <roman@cyngn.com>

Author: Alberto97 <albertop2197@gmail.com>
Date:   Mon Nov 21 20:47:25 2016 +0100

    Settings: Use GLIF Theme for missing Settings > Screen lock Activities

    Icons by Asher

    Change-Id: Icf1627b41ef604302a5819ad3b1bdfd6d8479202

Author: LuK1337 <priv.luk@gmail.com>
Date:   Mon May 10 22:00:01 2021 +0200

    Settings: Remove hardcoded extras from ChooseLockPatternSize

    Change-Id: I860d87842de0dbb9f87394a0c1fc5043fd16b07b

Author: LuK1337 <priv.luk@gmail.com>
Date:   Tue May 11 11:32:38 2021 +0200

    Settings: Make setup wizard go through ChooseLockPatternSize if needed

    Change-Id: Idfd3670d4b541b3618c4416b3b9dbf7d88ae3ed1

Author: LuK1337 <priv.luk@gmail.com>
Date:   Mon May 10 22:29:49 2021 +0200

    Settings: Make FRP go through ChooseLockPatternSize if needed

    Change-Id: I70b0ddb20033dd5505c391763a0a58fd2f9c8004

Change-Id: I7078d703c218cd096d9b77c003a94b52fbce6322
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index eaaf327..93281d9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2751,6 +2751,10 @@
             android:label="@string/lockpassword_choose_lock_generic_header"
             android:excludeFromRecents="true" />
 
+        <activity android:name=".password.ChooseLockPatternSize"
+            android:exported="false"
+            android:theme="@style/GlifTheme.Light" />
+
         <activity android:name=".password.SetupChooseLockPattern"
             android:exported="false"
             android:theme="@style/GlifTheme.Light" />
diff --git a/res/drawable/ic_security_pattern_3x3.xml b/res/drawable/ic_security_pattern_3x3.xml
new file mode 100644
index 0000000..b8e4df4
--- /dev/null
+++ b/res/drawable/ic_security_pattern_3x3.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2016 The CyanogenMod Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M4,17.268C3.402,17.613 3,18.26 3,19C3,20.105 3.895,21 5,21C5.74,21 6.387,20.598 6.732,20L9.268,20C9.613,20.598 10.26,21 11,21C12.105,21 13,20.105 13,19C13,17.895 12.105,17 11,17C10.26,17 9.613,17.402 9.268,18L6.732,18C6.557,17.696 6.304,17.443 6,17.268L6,14.732C6.598,14.387 7,13.74 7,13C7,11.895 6.105,11 5,11C3.895,11 3,11.895 3,13C3,13.74 3.402,14.387 4,14.732L4,17.268ZM21,11L21,9.5C21,8.67 20.33,8 19.5,8C20.33,8 21,7.33 21,6.5L21,5C21,3.89 20.1,3 19,3L15,3L15,5L19,5L19,7L17,7L17,9L19,9L19,11L15,11L15,13L19,13C20.1,13 21,12.11 21,11ZM5,9C6.105,9 7,8.105 7,7C7,5.895 6.105,5 5,5C3.895,5 3,5.895 3,7C3,8.105 3.895,9 5,9ZM11,9C12.105,9 13,8.105 13,7C13,5.895 12.105,5 11,5C9.895,5 9,5.895 9,7C9,8.105 9.895,9 11,9ZM11,15C12.105,15 13,14.105 13,13C13,11.895 12.105,11 11,11C9.895,11 9,11.895 9,13C9,14.105 9.895,15 11,15ZM17,21C18.105,21 19,20.105 19,19C19,17.895 18.105,17 17,17C15.895,17 15,17.895 15,19C15,20.105 15.895,21 17,21Z"
+        android:strokeColor="#00000000"
+        android:fillColor="#777777"
+        android:strokeWidth="1"/>
+</vector>
diff --git a/res/drawable/ic_security_pattern_4x4.xml b/res/drawable/ic_security_pattern_4x4.xml
new file mode 100644
index 0000000..92c580f
--- /dev/null
+++ b/res/drawable/ic_security_pattern_4x4.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2016 The CyanogenMod Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M4,17.268C3.402,17.613 3,18.26 3,19C3,20.105 3.895,21 5,21C5.74,21 6.387,20.598 6.732,20L9.268,20C9.613,20.598 10.26,21 11,21C12.105,21 13,20.105 13,19C13,17.895 12.105,17 11,17C10.26,17 9.613,17.402 9.268,18L6.732,18C6.557,17.696 6.304,17.443 6,17.268L6,14.732C6.598,14.387 7,13.74 7,13C7,11.895 6.105,11 5,11C3.895,11 3,11.895 3,13C3,13.74 3.402,14.387 4,14.732L4,17.268ZM21,13L21,3L19,3L19,7L17,7L17,3L15,3L15,9L19,9L19,13L21,13ZM5,9C6.105,9 7,8.105 7,7C7,5.895 6.105,5 5,5C3.895,5 3,5.895 3,7C3,8.105 3.895,9 5,9ZM11,9C12.105,9 13,8.105 13,7C13,5.895 12.105,5 11,5C9.895,5 9,5.895 9,7C9,8.105 9.895,9 11,9ZM11,15C12.105,15 13,14.105 13,13C13,11.895 12.105,11 11,11C9.895,11 9,11.895 9,13C9,14.105 9.895,15 11,15ZM17,21C18.105,21 19,20.105 19,19C19,17.895 18.105,17 17,17C15.895,17 15,17.895 15,19C15,20.105 15.895,21 17,21Z"
+        android:strokeColor="#00000000"
+        android:fillColor="#777777"
+        android:strokeWidth="1"/>
+</vector>
diff --git a/res/drawable/ic_security_pattern_5x5.xml b/res/drawable/ic_security_pattern_5x5.xml
new file mode 100644
index 0000000..7b4daba
--- /dev/null
+++ b/res/drawable/ic_security_pattern_5x5.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2016 The CyanogenMod Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M4,17.268C3.402,17.613 3,18.26 3,19C3,20.105 3.895,21 5,21C5.74,21 6.387,20.598 6.732,20L9.268,20C9.613,20.598 10.26,21 11,21C12.105,21 13,20.105 13,19C13,17.895 12.105,17 11,17C10.26,17 9.613,17.402 9.268,18L6.732,18C6.557,17.696 6.304,17.443 6,17.268L6,14.732C6.598,14.387 7,13.74 7,13C7,11.895 6.105,11 5,11C3.895,11 3,11.895 3,13C3,13.74 3.402,14.387 4,14.732L4,17.268ZM21,11L21,9C21,7.89 20.1,7 19,7L17,7L17,5L21,5L21,3L15,3L15,9L19,9L19,11L15,11L15,13L19,13C20.1,13 21,12.11 21,11ZM5,9C6.105,9 7,8.105 7,7C7,5.895 6.105,5 5,5C3.895,5 3,5.895 3,7C3,8.105 3.895,9 5,9ZM11,9C12.105,9 13,8.105 13,7C13,5.895 12.105,5 11,5C9.895,5 9,5.895 9,7C9,8.105 9.895,9 11,9ZM11,15C12.105,15 13,14.105 13,13C13,11.895 12.105,11 11,11C9.895,11 9,11.895 9,13C9,14.105 9.895,15 11,15ZM17,21C18.105,21 19,20.105 19,19C19,17.895 18.105,17 17,17C15.895,17 15,17.895 15,19C15,20.105 15.895,21 17,21Z"
+        android:strokeColor="#00000000"
+        android:fillColor="#777777"
+        android:strokeWidth="1"/>
+</vector>
diff --git a/res/drawable/ic_security_pattern_6x6.xml b/res/drawable/ic_security_pattern_6x6.xml
new file mode 100644
index 0000000..1861284
--- /dev/null
+++ b/res/drawable/ic_security_pattern_6x6.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2016 The CyanogenMod Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M17,13L19,13C20.1,13 21,12.11 21,11L21,9C21,7.89 20.1,7 19,7L17,7L17,5L21,5L21,3L17,3C15.9,3 15,3.89 15,5L15,11C15,12.11 15.9,13 17,13L17,13ZM4,17.268C3.402,17.613 3,18.26 3,19C3,20.105 3.895,21 5,21C5.74,21 6.387,20.598 6.732,20L9.268,20C9.613,20.598 10.26,21 11,21C12.105,21 13,20.105 13,19C13,17.895 12.105,17 11,17C10.26,17 9.613,17.402 9.268,18L6.732,18C6.557,17.696 6.304,17.443 6,17.268L6,14.732C6.598,14.387 7,13.74 7,13C7,11.895 6.105,11 5,11C3.895,11 3,11.895 3,13C3,13.74 3.402,14.387 4,14.732L4,17.268ZM17,9L19,9L19,11L17,11L17,9ZM5,9C6.105,9 7,8.105 7,7C7,5.895 6.105,5 5,5C3.895,5 3,5.895 3,7C3,8.105 3.895,9 5,9ZM11,9C12.105,9 13,8.105 13,7C13,5.895 12.105,5 11,5C9.895,5 9,5.895 9,7C9,8.105 9.895,9 11,9ZM11,15C12.105,15 13,14.105 13,13C13,11.895 12.105,11 11,11C9.895,11 9,11.895 9,13C9,14.105 9.895,15 11,15ZM17,21C18.105,21 19,20.105 19,19C19,17.895 18.105,17 17,17C15.895,17 15,17.895 15,19C15,20.105 15.895,21 17,21Z"
+        android:strokeColor="#00000000"
+        android:fillColor="#777777"
+        android:strokeWidth="1"/>
+</vector>
diff --git a/res/layout/crypt_keeper_pattern_sizes.xml b/res/layout/crypt_keeper_pattern_sizes.xml
new file mode 100644
index 0000000..adbbfa0
--- /dev/null
+++ b/res/layout/crypt_keeper_pattern_sizes.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The CyanogenMod Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <Button
+            android:id="@+id/lock_pattern_size_3"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:textSize="14sp"
+            android:fontFamily="sans-serif"
+            android:text="@string/lock_pattern_size_3"
+            android:textColor="@android:color/white"
+            android:layout_weight="1"
+            style="?android:attr/borderlessButtonStyle"/>
+
+    <Button
+            android:id="@+id/lock_pattern_size_4"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:textSize="14sp"
+            android:fontFamily="sans-serif"
+            android:text="@string/lock_pattern_size_4"
+            android:textColor="@android:color/white"
+            android:layout_weight="1"
+            style="?android:attr/borderlessButtonStyle"/>
+
+    <Button
+            android:id="@+id/lock_pattern_size_5"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:textSize="14sp"
+            android:fontFamily="sans-serif"
+            android:text="@string/lock_pattern_size_5"
+            android:textColor="@android:color/white"
+            android:layout_weight="1"
+            style="?android:attr/borderlessButtonStyle"/>
+
+    <Button
+            android:id="@+id/lock_pattern_size_6"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:textSize="14sp"
+            android:fontFamily="sans-serif"
+            android:text="@string/lock_pattern_size_6"
+            android:textColor="@android:color/white"
+            android:layout_weight="1"
+            style="?android:attr/borderlessButtonStyle"/>
+
+</merge >
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
index 67b8572..f7e11e2 100644
--- a/res/values/cm_strings.xml
+++ b/res/values/cm_strings.xml
@@ -34,4 +34,11 @@
     <!-- Advanced restart options -->
     <string name="power_menu_advanced_restart_title">Advanced restart</string>
     <string name="power_menu_advanced_restart_summary">When unlocked, include options in the power menu for restarting into recovery or bootloader</string>
+
+    <!-- Lock screen pattern size -->
+    <string name="lock_pattern_size_3" translatable="false">3 \u00d7 3</string>
+    <string name="lock_pattern_size_4" translatable="false">4 \u00d7 4</string>
+    <string name="lock_pattern_size_5" translatable="false">5 \u00d7 5</string>
+    <string name="lock_pattern_size_6" translatable="false">6 \u00d7 6</string>
+    <string name="lock_settings_picker_pattern_size_message">Choose a pattern size</string>
 </resources>
diff --git a/res/values/lineage_styles.xml b/res/values/lineage_styles.xml
new file mode 100644
index 0000000..1ce2e23
--- /dev/null
+++ b/res/values/lineage_styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 The LineageOS Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <style name="LockPatternSizeHeaderStyle" parent="android:style/TextAppearance.Material.Subhead">
+        <item name="android:paddingTop">16dp</item>
+        <item name="android:textColor">@color/primary_dark_material_light</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+    </style>
+</resources>
diff --git a/res/xml/security_settings_pattern_size.xml b/res/xml/security_settings_pattern_size.xml
new file mode 100644
index 0000000..bb0cb23
--- /dev/null
+++ b/res/xml/security_settings_pattern_size.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2012-2013 The CyanogenMod Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <Preference
+        android:icon="@drawable/ic_security_pattern_3x3"
+        android:key="lock_pattern_size_3"
+        android:title="@string/lock_pattern_size_3"
+        android:persistent="false"/>
+
+    <Preference
+        android:icon="@drawable/ic_security_pattern_4x4"
+        android:key="lock_pattern_size_4"
+        android:title="@string/lock_pattern_size_4"
+        android:persistent="false"/>
+
+    <Preference
+        android:icon="@drawable/ic_security_pattern_5x5"
+        android:key="lock_pattern_size_5"
+        android:title="@string/lock_pattern_size_5"
+        android:persistent="false"/>
+
+    <Preference
+        android:icon="@drawable/ic_security_pattern_6x6"
+        android:key="lock_pattern_size_6"
+        android:title="@string/lock_pattern_size_6"
+        android:persistent="false"/>
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 800adb0..dd34cda 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -1059,7 +1059,8 @@
                     mUserId);
 
             mSaveAndFinishWorker.start(mLockPatternUtils,
-                    mChosenPassword, mCurrentCredential, mUserId);
+                    mChosenPassword, mCurrentCredential, mUserId,
+                    mLockPatternUtils.getLockPatternSize(mUserId));
         }
 
         @Override
diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java
index 20d1e7d..53a3226 100644
--- a/src/com/android/settings/password/ChooseLockPattern.java
+++ b/src/com/android/settings/password/ChooseLockPattern.java
@@ -102,7 +102,8 @@
         private final Intent mIntent;
 
         public IntentBuilder(Context context) {
-            mIntent = new Intent(context, ChooseLockPattern.class);
+            mIntent = new Intent(context, ChooseLockPatternSize.class);
+            mIntent.putExtra("className", ChooseLockPattern.class.getName());
             mIntent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, false);
         }
 
@@ -211,19 +212,14 @@
         protected FooterButton mSkipOrClearButton;
         protected FooterButton mNextButton;
         @VisibleForTesting protected LockscreenCredential mChosenPattern;
+        private byte mPatternSize = LockPatternUtils.PATTERN_SIZE_DEFAULT;
         private ColorStateList mDefaultHeaderColorList;
         private View mSudContent;
 
         /**
          * The patten used during the help screen to show how to draw a pattern.
          */
-        private final List<LockPatternView.Cell> mAnimatePattern =
-                Collections.unmodifiableList(Lists.newArrayList(
-                        LockPatternView.Cell.of(0, 0),
-                        LockPatternView.Cell.of(0, 1),
-                        LockPatternView.Cell.of(1, 1),
-                        LockPatternView.Cell.of(2, 1)
-                ));
+        private List<LockPatternView.Cell> mAnimatePattern;
 
         @Override
         public void onActivityResult(int requestCode, int resultCode,
@@ -268,12 +264,13 @@
                     mLockPatternView.removeCallbacks(mClearPatternRunnable);
                 }
 
-                public void onPatternDetected(List<LockPatternView.Cell> pattern) {
+                public void onPatternDetected(List<LockPatternView.Cell> pattern,
+                        byte patternSize) {
                     if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
                         if (mChosenPattern == null) throw new IllegalStateException(
                                 "null chosen pattern in stage 'need to confirm");
                         try (LockscreenCredential confirmPattern =
-                                LockscreenCredential.createPattern(pattern)) {
+                                LockscreenCredential.createPattern(pattern, patternSize)) {
                             if (mChosenPattern.equals(confirmPattern)) {
                                 updateStage(Stage.ChoiceConfirmed);
                             } else {
@@ -284,7 +281,8 @@
                         if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
                             updateStage(Stage.ChoiceTooShort);
                         } else {
-                            mChosenPattern = LockscreenCredential.createPattern(pattern);
+                            mChosenPattern = LockscreenCredential.createPattern(
+                                    pattern, patternSize);
                             updateStage(Stage.FirstChoiceValid);
                         }
                     } else {
@@ -534,6 +532,16 @@
             mSudContent.setPadding(mSudContent.getPaddingLeft(), 0, mSudContent.getPaddingRight(),
                     0);
 
+            mPatternSize = getActivity().getIntent().getByteExtra("pattern_size",
+                    LockPatternUtils.PATTERN_SIZE_DEFAULT);
+            LockPatternView.Cell.updateSize(mPatternSize);
+            mAnimatePattern = Collections.unmodifiableList(Lists.newArrayList(
+                    LockPatternView.Cell.of(0, 0, mPatternSize),
+                    LockPatternView.Cell.of(0, 1, mPatternSize),
+                    LockPatternView.Cell.of(1, 1, mPatternSize),
+                    LockPatternView.Cell.of(2, 1, mPatternSize)
+                    ));
+
             return layout;
         }
 
@@ -547,6 +555,8 @@
             mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
             mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);
             mLockPatternView.setFadePattern(false);
+            mLockPatternView.setLockPatternUtils(mLockPatternUtils);
+            mLockPatternView.setLockPatternSize(mPatternSize);
 
             mFooterText = (TextView) view.findViewById(R.id.footerText);
 
@@ -593,6 +603,9 @@
                 // restore from previous state
                 mChosenPattern = savedInstanceState.getParcelable(KEY_PATTERN_CHOICE);
                 mCurrentCredential = savedInstanceState.getParcelable(KEY_CURRENT_PATTERN);
+                mLockPatternView.setPattern(DisplayMode.Correct,
+                        LockPatternUtils.byteArrayToPattern(
+                                mChosenPattern.getCredential(), mPatternSize));
 
                 updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
 
@@ -851,7 +864,7 @@
                 }
             }
             mSaveAndFinishWorker.start(mLockPatternUtils,
-                    mChosenPattern, mCurrentCredential, mUserId);
+                    mChosenPattern, mCurrentCredential, mUserId, mPatternSize);
         }
 
         @Override
diff --git a/src/com/android/settings/password/ChooseLockPatternSize.java b/src/com/android/settings/password/ChooseLockPatternSize.java
new file mode 100644
index 0000000..af1c4b7
--- /dev/null
+++ b/src/com/android/settings/password/ChooseLockPatternSize.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2012-2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.password;
+
+import android.content.Intent;
+import android.content.res.Resources.Theme;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.preference.Preference;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.SetupWizardUtils;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.utils.SettingsDividerItemDecoration;
+
+import com.google.android.setupdesign.GlifPreferenceLayout;
+
+public class ChooseLockPatternSize extends SettingsActivity {
+
+    @Override
+    public Intent getIntent() {
+        Intent modIntent = new Intent(super.getIntent());
+        modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ChooseLockPatternSizeFragment.class.getName());
+        return modIntent;
+    }
+
+    @Override
+    protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
+        resid = SetupWizardUtils.getTheme(this, getIntent());
+        super.onApplyThemeResource(theme, resid, first);
+    }
+
+    @Override
+    protected boolean isValidFragment(String fragmentName) {
+        if (ChooseLockPatternSizeFragment.class.getName().equals(fragmentName)) return true;
+        return false;
+    }
+
+    @Override
+    protected boolean isToolbarEnabled() {
+        return false;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        findViewById(R.id.content_parent).setFitsSystemWindows(false);
+    }
+
+    public static class ChooseLockPatternSizeFragment extends SettingsPreferenceFragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            if (!(getActivity() instanceof ChooseLockPatternSize)) {
+                throw new SecurityException("Fragment contained in wrong activity");
+            }
+            addPreferencesFromResource(R.xml.security_settings_pattern_size);
+        }
+
+        @Override
+        public boolean onPreferenceTreeClick(Preference preference) {
+            final String key = preference.getKey();
+
+            byte patternSize;
+            if ("lock_pattern_size_4".equals(key)) {
+                patternSize = 4;
+            } else if ("lock_pattern_size_5".equals(key)) {
+                patternSize = 5;
+            } else if ("lock_pattern_size_6".equals(key)) {
+                patternSize = 6;
+            } else {
+                patternSize = 3;
+            }
+
+            Bundle extras = getActivity().getIntent().getExtras();
+            Intent intent = new Intent();
+            intent.setClassName(getActivity(), extras.getString("className"));
+            intent.putExtras(extras);
+            intent.putExtra("pattern_size", patternSize);
+            intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+            startActivity(intent);
+
+            finish();
+            return true;
+        }
+
+        @Override
+        public void onViewCreated(View view, Bundle savedInstanceState) {
+            super.onViewCreated(view, savedInstanceState);
+            GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
+            layout.setDividerItemDecoration(new SettingsDividerItemDecoration(getContext()));
+
+            layout.setIcon(getContext().getDrawable(R.drawable.ic_lock));
+
+            if (getActivity() != null) {
+                getActivity().setTitle(R.string.lock_settings_picker_pattern_size_message);
+            }
+
+            layout.setHeaderText(R.string.lock_settings_picker_pattern_size_message);
+
+            // Use the dividers in SetupWizardRecyclerLayout. Suppress the dividers in
+            // PreferenceFragment.
+            setDivider(null);
+        }
+
+        @Override
+        public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
+                Bundle savedInstanceState) {
+            GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
+            return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
+        }
+
+        @Override
+        public int getMetricsCategory() {
+            return MetricsEvent.LOCKSCREEN;
+        }
+    }
+}
diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java
index 21fd94c..a290760 100644
--- a/src/com/android/settings/password/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java
@@ -473,6 +473,9 @@
         intent.setClassName(SETTINGS_PACKAGE_NAME, activityClass.getName());
         intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
                 SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);
+        if (userId == LockPatternUtils.USER_FRP) {
+            intent.putExtra("className", ConfirmLockPattern.class.getName());
+        }
 
         Intent inIntent = mFragment != null ? mFragment.getActivity().getIntent() :
                 mActivity.getIntent();
@@ -553,7 +556,9 @@
                         ? ConfirmLockPassword.InternalActivity.class
                         : ConfirmLockPassword.class);
             case KeyguardManager.PATTERN:
-                return Optional.of(returnCredentials || forceVerifyPath
+                return Optional.of(userId == LockPatternUtils.USER_FRP
+                        ? ChooseLockPatternSize.class
+                        : returnCredentials || forceVerifyPath
                         ? ConfirmLockPattern.InternalActivity.class
                         : ConfirmLockPattern.class);
         }
diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java
index b139ae9..ae547a0 100644
--- a/src/com/android/settings/password/ConfirmLockPassword.java
+++ b/src/com/android/settings/password/ConfirmLockPassword.java
@@ -628,7 +628,8 @@
                                 mLockPatternUtils,
                                 mRemoteLockscreenValidationFragment.getLockscreenCredential(),
                                 /* currentCredential= */ null,
-                                mEffectiveUserId);
+                                mEffectiveUserId,
+                                mLockPatternUtils.getLockPatternSize(mEffectiveUserId));
                     } else {
                         mCredentialCheckResultTracker.setResult(/* matched= */ true, new Intent(),
                                 /* timeoutMs= */ 0, mEffectiveUserId);
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index 6e3ad30..dc98886 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -114,6 +114,7 @@
         private DisappearAnimationUtils mDisappearAnimationUtils;
 
         private boolean mIsManagedProfile;
+        private byte mPatternSize;
 
         // required constructor for fragments
         public ConfirmLockPatternFragment() {
@@ -140,6 +141,7 @@
             mSudContent.setPadding(mSudContent.getPaddingLeft(), 0, mSudContent.getPaddingRight(),
                     0);
             mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId);
+            mPatternSize = mLockPatternUtils.getLockPatternSize(mEffectiveUserId);
 
             // make it so unhandled touch events within the unlock screen go to the
             // lock pattern view.
@@ -154,6 +156,7 @@
                 mDetailsText = intent.getCharSequenceExtra(
                         ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT);
                 mCheckBoxLabel = intent.getCharSequenceExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL);
+                mPatternSize = intent.getByteExtra("pattern_size", mPatternSize);
             }
             if (TextUtils.isEmpty(mHeaderText) && mIsManagedProfile) {
                 mHeaderText = mDevicePolicyManager.getOrganizationNameForUser(mUserId);
@@ -161,6 +164,7 @@
 
             mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
                     mEffectiveUserId));
+            mLockPatternView.setLockPatternSize(mPatternSize);
             mLockPatternView.setOnPatternListener(mConfirmExistingLockPatternListener);
             mLockPatternView.setOnTouchListener((v, event) -> {
                 if (event.getAction() == MotionEvent.ACTION_DOWN) {
@@ -496,14 +500,15 @@
 
             }
 
-            public void onPatternDetected(List<LockPatternView.Cell> pattern) {
+            public void onPatternDetected(List<LockPatternView.Cell> pattern, byte patternSize) {
                 if (mPendingLockCheck != null || mDisappearing) {
                     return;
                 }
 
                 mLockPatternView.setEnabled(false);
 
-                final LockscreenCredential credential = LockscreenCredential.createPattern(pattern);
+                final LockscreenCredential credential = LockscreenCredential.createPattern(pattern,
+                        patternSize);
 
                 if (mRemoteValidation) {
                     validateGuess(credential);
@@ -642,7 +647,8 @@
                                 mLockPatternUtils,
                                 mRemoteLockscreenValidationFragment.getLockscreenCredential(),
                                 /* currentCredential= */ null,
-                                mEffectiveUserId);
+                                mEffectiveUserId,
+                                mLockPatternUtils.getLockPatternSize(mEffectiveUserId));
                     } else {
                         mCredentialCheckResultTracker.setResult(/* matched= */ true, new Intent(),
                                 /* timeoutMs= */ 0, mEffectiveUserId);
diff --git a/src/com/android/settings/password/SaveAndFinishWorker.java b/src/com/android/settings/password/SaveAndFinishWorker.java
index 40054b7..5592071 100644
--- a/src/com/android/settings/password/SaveAndFinishWorker.java
+++ b/src/com/android/settings/password/SaveAndFinishWorker.java
@@ -53,6 +53,7 @@
     private LockscreenCredential mUnificationProfileCredential;
     private LockscreenCredential mChosenCredential;
     private LockscreenCredential mCurrentCredential;
+    private byte mPatternSize;
 
     private boolean mBlocking;
 
@@ -76,9 +77,10 @@
 
     @VisibleForTesting
     void prepare(LockPatternUtils utils, LockscreenCredential chosenCredential,
-            LockscreenCredential currentCredential, int userId) {
+            LockscreenCredential currentCredential, int userId, byte patternSize) {
         mUtils = utils;
         mUserId = userId;
+        mPatternSize = patternSize;
         // This will be a no-op for non managed profiles.
         mWasSecureBefore = mUtils.isSecure(mUserId);
         mFinished = false;
@@ -90,8 +92,8 @@
     }
 
     public void start(LockPatternUtils utils, LockscreenCredential chosenCredential,
-            LockscreenCredential currentCredential, int userId) {
-        prepare(utils, chosenCredential, currentCredential, userId);
+            LockscreenCredential currentCredential, int userId, byte patternSize) {
+        prepare(utils, chosenCredential, currentCredential, userId, patternSize);
         if (mBlocking) {
             finish(saveAndVerifyInBackground().second);
         } else {
@@ -107,6 +109,7 @@
     @VisibleForTesting
     Pair<Boolean, Intent> saveAndVerifyInBackground() {
         final int userId = mUserId;
+        mUtils.setLockPatternSize(mPatternSize, userId);
         try {
             if (!mUtils.setLockCredential(mChosenCredential, mCurrentCredential, userId)) {
                 return Pair.create(false, null);
diff --git a/src/com/android/settings/password/SetupChooseLockPattern.java b/src/com/android/settings/password/SetupChooseLockPattern.java
index e233f44..8330adf 100644
--- a/src/com/android/settings/password/SetupChooseLockPattern.java
+++ b/src/com/android/settings/password/SetupChooseLockPattern.java
@@ -47,7 +47,8 @@
 public class SetupChooseLockPattern extends ChooseLockPattern {
 
     public static Intent modifyIntentForSetup(Context context, Intent chooseLockPatternIntent) {
-        chooseLockPatternIntent.setClass(context, SetupChooseLockPattern.class);
+        chooseLockPatternIntent.setClass(context, ChooseLockPatternSize.class);
+        chooseLockPatternIntent.putExtra("className", SetupChooseLockPattern.class.getName());
         return chooseLockPatternIntent;
     }