Merge tag 'android-14.0.0_r31' into leaf-3.2

Android 14.0.0 Release 31 (AP1A.240405.002.A1)

* tag 'android-14.0.0_r31':
  Restrict WifiDialogActivity

Change-Id: Iaa34cd9f4d23aa1bc2d008e677fa7bbcd287b194
diff --git a/Android.bp b/Android.bp
index 9b4cfde..b747baa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -103,6 +103,9 @@
         "settings-logtags",
         "settings-telephony-protos-lite",
         "statslog-settings",
+        "SystemUISharedLib",
+        "vendor.lineage.fastcharge-V1.0-java",
+        "vendor.lineage.touch-V1.0-java",
     ],
 
     plugins: ["androidx.room_room-compiler-plugin"],
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2d3b3fd..253d196 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -230,6 +230,13 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="org.leafos.settings.BootCompletedReceiver"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+
         <activity android:name=".SubSettings"
                   android:exported="false"
                   android:theme="@style/Theme.SubSettings"
@@ -468,6 +475,17 @@
         </activity>
 
         <activity
+            android:name=".network.NetworkSetupActivity"
+            android:exported="true">
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.NETWORK_PROVIDER_SETUP" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+                android:value="true" />
+        </activity>
+
+        <activity
             android:name=".wifi.WifiPickerActivity"
             android:permission="android.permission.CHANGE_WIFI_STATE"
             android:exported="true">
@@ -2744,6 +2762,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" />
@@ -5028,6 +5050,18 @@
             android:authorities="${applicationId}.androidx-startup"
             tools:node="remove" />
 
+        <activity android:name=".backup.transport.TransportActivity"
+                  android:label="@string/backup_transport_title"
+                  android:icon="@drawable/ic_settings_backup"
+                  android:exported="false">
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="settings"
+                      android:host="com.android.settings.backup.transport" />
+            </intent-filter>
+        </activity>
+
         <!-- This is the longest AndroidManifest.xml ever. -->
     </application>
 </manifest>
diff --git a/res/drawable-nodpi/swipe_to_screenshot.png b/res/drawable-nodpi/swipe_to_screenshot.png
new file mode 100644
index 0000000..853c09e
--- /dev/null
+++ b/res/drawable-nodpi/swipe_to_screenshot.png
Binary files differ
diff --git a/res/drawable/ic_launcher_settings.xml b/res/drawable/ic_launcher_settings.xml
index 9ede59d..808f7fd 100644
--- a/res/drawable/ic_launcher_settings.xml
+++ b/res/drawable/ic_launcher_settings.xml
@@ -2,4 +2,5 @@
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
     <background android:drawable="@color/icon_launcher_setting_color"/>
     <foreground android:drawable="@mipmap/ic_launcher_settings"/>
+    <monochrome android:drawable="@drawable/ic_monochrome" />
 </adaptive-icon>
diff --git a/res/drawable/ic_monochrome.xml b/res/drawable/ic_monochrome.xml
new file mode 100644
index 0000000..8be11ed
--- /dev/null
+++ b/res/drawable/ic_monochrome.xml
@@ -0,0 +1,174 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
+    android:viewportWidth="432"
+    android:viewportHeight="432"
+    android:width="108dp"
+    android:height="108dp">
+    <path
+        android:pathData="M199.5 137L232.5 137L235 138L239 162L252.5 169L265.5 164L265.5 165L251.5 170L238 161.5L235 142L232 142.5L234 143.5L228 144.5L232 145.5L230 146.5L230.5 148L228 148.5L230 149.5L228 150Q229.3 153.3 224.5 152L224.5 153L227 153.5L224 154.5L226 155.5L220 156.5L224 157L222.5 160L216 160.5L222 161.5L220 162Q221.3 165.3 216.5 164L216.5 165L219 165.5L216 166.5L216.5 168L212 168.5L215 169.5L212 170.5L214 171.5L208 172.5L212 173.5L210 174.5L210.5 176L204 176.5L209 177.5L206 178.5L206.5 180L202 180.5L205 181.5L204 184L198 184.5L202 185.5L200 186Q201.3 189.3 196.5 188L196.5 189L198 189.5L196 190Q197.4 194 190.5 192L190.5 193L194 193.5L192 194Q193.3 197.3 188.5 196L188.5 197L190 197.5L188 198L187.5 200L180.5 200L180.5 201L186 201.5L184 202L183.5 204L176.5 204L176.5 205L181 205.5L178.5 208L172 208.5L177 209.5L172 210.5L174 211.5L168 212.5L172 213.5L168 214.5L168.5 216L162 216.5L167 217.5L164 218Q165.4 222 158.5 220L158.5 221L162 221.5L157 224L155.5 227L140 239.5L157.5 270L160 270.5L157.5 271L142 246.5L139 238.5L157 223.5L157 208.5L154.5 206L139 193.5L142 185.5L157.5 161L161.5 161L180.5 169Q185.5 163.8 193 162L197 138L199.5 137ZM233 140L233 141L235 141L233 140Z"
+        android:fillColor="#0A0A0A"
+        android:fillAlpha="0.972549"
+        android:strokeColor="#0A0A0A"
+        android:strokeAlpha="0.972549"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M271.5 161L274 161.5L267.5 164L268.5 162L271.5 161Z"
+        android:fillColor="#0A0A0A"
+        android:fillAlpha="0.972549"
+        android:strokeColor="#0A0A0A"
+        android:strokeAlpha="0.972549"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M209.5 188L214 188.5L209.5 189L209.5 188Z"
+        android:fillColor="#0A0A0A"
+        android:fillAlpha="0.972549"
+        android:strokeColor="#0A0A0A"
+        android:strokeAlpha="0.972549"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M218.5 188L223 188.5L218.5 189L218.5 188Z"
+        android:fillColor="#0A0A0A"
+        android:fillAlpha="0.972549"
+        android:strokeColor="#0A0A0A"
+        android:strokeAlpha="0.972549"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M205.5 189L208 189.5Q199.6 191.6 195 197.5L190 205.5L188 216.5L190 226.5L198.5 238L201 239.5L199.5 239L193 233.5L188 223.5L187 213.5Q189.3 199.8 198.5 193L205.5 189Z"
+        android:fillColor="#0A0A0A"
+        android:fillAlpha="0.972549"
+        android:strokeColor="#0A0A0A"
+        android:strokeAlpha="0.972549"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M224.5 189Q234.4 191.1 239 198.5L242 203.5L240 202.5L234.5 195L224.5 190L224.5 189Z"
+        android:fillColor="#0A0A0A"
+        android:fillAlpha="0.972549"
+        android:strokeColor="#0A0A0A"
+        android:strokeAlpha="0.972549"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M203.5 241L208 242.5L205.5 243L203.5 241Z"
+        android:fillColor="#0A0A0A"
+        android:fillAlpha="0.972549"
+        android:strokeColor="#0A0A0A"
+        android:strokeAlpha="0.972549"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M179.5 262L181 262.5L178.5 264L179.5 262Z"
+        android:fillColor="#0A0A0A"
+        android:fillAlpha="0.972549"
+        android:strokeColor="#0A0A0A"
+        android:strokeAlpha="0.972549"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M176.5 263L175.5 265L169.5 267L169.5 266L176.5 263Z"
+        android:fillColor="#0A0A0A"
+        android:fillAlpha="0.972549"
+        android:strokeColor="#0A0A0A"
+        android:strokeAlpha="0.972549"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M166.5 267L168 267.5L161.5 271L162.5 269L166.5 267Z"
+        android:fillColor="#0A0A0A"
+        android:fillAlpha="0.972549"
+        android:strokeColor="#0A0A0A"
+        android:strokeAlpha="0.972549"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M274.5 161L275.5 163Q272.7 163.7 274.5 161Z"
+        android:fillColor="#050505"
+        android:fillAlpha="0.9882353"
+        android:strokeColor="#050505"
+        android:strokeAlpha="0.9882353"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M276.5 164Q280.2 166 278.5 168Q280.8 167.3 280 169.5L292 189.5L292 191.5L293 193.5L291 194.5L291.5 196L288 196.5Q290.3 197.8 287.5 199L286 198.5L284 201.5L275 208.5L275 223.5L278.5 228L280 227.5Q277.8 228.8 280.5 230L283.5 232L285 231.5Q282.3 233.3 286.5 235L288 235.5L284 236.5L289 237.5L286.5 240L280 240.5L285 241.5L282 242.5L284 243.5L280 244.5L282 245.5L280 246Q281.4 250 274.5 248L274.5 249L278 249.5L276 250.5L276.5 252L272 252.5L275 253.5L272 254.5L272.5 256L268 256.5L271 257.5L268 258.5L268.5 260L264 260.5L267 261.5L264 262.5L264.5 264L259.5 265L252.5 262L249 263.5L249.5 265L247.5 265L238 270.5Q240.5 272 237 273.5L238 277.5L236 280.5Q237.5 286.5 234.5 288L232 288.5L235 289.5L232 290.5L234 291.5L228 292.5L232 293.5L201.5 294L199.5 295L196 291.5L197 290.5L196 287.5L196.5 286Q193.5 286.5 195 279.5L193 270L189 269L188.5 267L186.5 267L184 265.5Q183.1 262.1 188.5 264L188.5 262L191 261.5L188 260.5L194 259.5L192 258.5L197 257.5L192 256.5L199 255.5L198.5 254L200.5 254L202 253.5L200 252.5L204 252Q202.8 249 206.5 250L206.5 249L202 248.5L209 247.5L208.5 246L211 245.5L208 244.5L209.5 243L212.5 244L227.5 242L238 233.5Q244.8 226.8 244 212.5L243 210L247 209.5L243 208.5L249 207.5L248.5 206L250 205.5L248 204.5L252 204Q250.9 201.3 253.5 202L253.5 201L248 200.5L255 199.5L254.5 198Q255.8 200.3 257 197.5L254 196.5L258 195.5L256 194.5L260 193.5L256 192.5L261 191.5L260.5 190L263 189.5L260 188.5L264 188Q262.9 185.3 265.5 186L265.5 185L262 184.5L267 183.5L266.5 182L268 181.5L264 180.5L270 179.5L268 178.5L271 177.5L268 176.5L272 176Q270.9 173.3 273.5 174L273.5 173L272 172.5L275 171.5L272 170.5L276 169.5L272 168.5L277 167.5L276.5 164Z"
+        android:fillColor="#050505"
+        android:fillAlpha="0.9882353"
+        android:strokeColor="#050505"
+        android:strokeAlpha="0.9882353"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M241.5 204Q243.8 203.3 243 205.5L241.5 204Z"
+        android:fillColor="#050505"
+        android:fillAlpha="0.9882353"
+        android:strokeColor="#050505"
+        android:strokeAlpha="0.9882353"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M177.5 263L176.5 265L177.5 263Z"
+        android:fillColor="#050505"
+        android:fillAlpha="0.9882353"
+        android:strokeColor="#050505"
+        android:strokeAlpha="0.9882353"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M181.5 263Q183.8 262.3 183 264.5L181.5 263Z"
+        android:fillColor="#050505"
+        android:fillAlpha="0.9882353"
+        android:strokeColor="#050505"
+        android:strokeAlpha="0.9882353"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M232.5 140L235 140.5L232.5 141L232.5 140Z"
+        android:fillColor="#080808"
+        android:fillAlpha="0.9960784"
+        android:strokeColor="#080808"
+        android:strokeAlpha="0.9960784"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M232.5 142Q236.3 140.8 235 144.5L236 145.5L237 158.5L239.5 163L253.5 170L268.5 163L273.5 162L276 163L277 165.5L276.5 168L272 168.5L276 169.5L272 170.5L275 171.5L272 172.5L274 173.5L272 174Q273.3 177.3 268.5 176L268.5 177L271 177.5L268 178.5L270 179.5L264 180.5L268 181.5L266 182.5L266.5 184L262 184.5L266 185.5L264 186Q265.3 189.3 260.5 188L260.5 189L263 189.5L260 190.5L260.5 192L256 192.5L260 193.5L256 194.5L258 195.5L254 196.5L257 197.5L254.5 200L248 200.5L254 201.5L252 202Q253.3 205.3 248.5 204L248.5 205L250 205.5L248 206.5L248.5 208Q241.2 210.6 243 204.5L233.5 193Q226 186 209.5 188Q198.6 190.6 193 198.5Q187.1 205.1 187 217.5L191 230.5L198.5 239L209 243.5L208.5 245L211 245.5L208 246.5L208.5 248L202 248.5L207 249.5L204 250Q205.3 253.3 200.5 252L200.5 253L202 253.5Q199.2 257.2 192 256.5L197 257.5L192 258.5L194 259.5L188 260.5L191 261.5L188 262.5L188.5 264Q182.2 264.8 179.5 262L161.5 270L157.5 270L140 239.5L157 225.5Q156.3 223.3 158.5 224L158.5 222L160.5 222L162 221.5L158 220.5L164 220Q162.8 217 166.5 218L166.5 217L162 216.5L169 215.5L168.5 214L172 213.5L168 212.5L174 211.5L172 210.5L177 209.5L172 208.5L179 207.5L178.5 206Q179.8 208.3 181 205.5L176 204.5L184 204Q182.9 201.3 185.5 202L185.5 201L180 200.5L188 200Q186.9 197.3 189.5 198L189.5 197L188 196.5L192 196Q190.9 193.3 193.5 194L193.5 193L190 192.5L196 192Q194.9 189.3 197.5 190L197.5 189L196 188.5L200 188Q198.9 185.3 201.5 186L201.5 185L198 184.5L204 184L205 181.5L202 180.5L207 179.5L206.5 178L209 177.5L204 176.5L211 175.5L210.5 174L212 173.5L208 172.5L214 171.5L212 170.5L215 169.5L212 168.5L217 167.5L216.5 166L219 165.5L216 164.5L220 164Q218.9 161.3 221.5 162L221.5 161L216 160.5L223 159.5L222.5 158L224 158.5Q224.9 155.5 220.5 157L220.5 156L226 155.5L224 154.5L227 153.5L224 152.5L228 152Q226.9 149.3 229.5 150L229.5 149L228 148.5L231 147.5L230.5 146L232 145.5L228 144.5L234 143.5L232.5 142Z"
+        android:fillColor="#080808"
+        android:fillAlpha="0.9960784"
+        android:strokeColor="#080808"
+        android:strokeAlpha="0.9960784"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M244.5 209L247 209.5L244.5 210L244.5 209Z"
+        android:fillColor="#080808"
+        android:fillAlpha="0.9960784"
+        android:strokeColor="#080808"
+        android:strokeAlpha="0.9960784"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M291.5 190L293 192.5L292 192.5L291.5 190Z"
+        android:fillColor="#030303"
+        android:fillAlpha="0.9686275"
+        android:strokeColor="#030303"
+        android:strokeAlpha="0.9686275"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M276.5 225L279 226Q277.9 228.7 280.5 228L284 230Q282.9 232.7 285.5 232L293 238.5L293 241.5L274.5 271L270.5 271L252 262.5L253.5 263L259.5 265L265 263.5L264.5 262L267 261.5L264 260.5L269 259.5L268.5 258L271 257.5L268 256.5L273 255.5L272.5 254L275 253.5L272 252.5L277 251.5L276.5 250L278 249.5L274 248.5L280 248Q278.9 245.3 281.5 246L281.5 245L280 244.5L284 243.5L282 242.5L285 241.5L280 240.5L287 239.5L286.5 238Q287.8 240.3 289 237.5L284 236.5L288 235.5L285.5 234L284 234.5L285 233.5L281.5 230L276.5 225Z"
+        android:fillColor="#030303"
+        android:fillAlpha="0.9686275"
+        android:strokeColor="#030303"
+        android:strokeAlpha="0.9686275"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M249.5 263L251 263.5L238.5 271L239.5 269L249.5 263Z"
+        android:fillColor="#030303"
+        android:fillAlpha="0.9686275"
+        android:strokeColor="#030303"
+        android:strokeAlpha="0.9686275"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M238.5 272L238 273.5L237.5 276L237 273.5L238.5 272Z"
+        android:fillColor="#030303"
+        android:fillAlpha="0.9686275"
+        android:strokeColor="#030303"
+        android:strokeAlpha="0.9686275"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M237.5 278L238 279.5L235 294L232.5 295L201.5 295L201.5 294L232 293.5L228 292.5L234 291.5L232 290.5L235 289.5L232 288.5L235 287.5L234.5 286L236 286.5Q234.9 280.4 237.5 278Z"
+        android:fillColor="#030303"
+        android:fillAlpha="0.9686275"
+        android:strokeColor="#030303"
+        android:strokeAlpha="0.9686275"
+        android:strokeWidth="1" />
+    <path
+        android:pathData="M196.5 288L197 290.5L196 290.5L196.5 288Z"
+        android:fillColor="#030303"
+        android:fillAlpha="0.9686275"
+        android:strokeColor="#030303"
+        android:strokeAlpha="0.9686275"
+        android:strokeWidth="1" />
+</vector>
diff --git a/res/drawable/ic_network_setup.xml b/res/drawable/ic_network_setup.xml
new file mode 100644
index 0000000..4944cbc
--- /dev/null
+++ b/res/drawable/ic_network_setup.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2021 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="?android:attr/colorPrimary"
+        android:pathData="M12,2A8,8 0 0,0 4,10C4,14.03 7,17.42 11,17.93V19H10A1,1 0 0,0 9,20H2V22H9A1,1 0 0,0 10,23H14A1,1 0 0,0 15,22H22V20H15A1,1 0 0,0 14,19H13V17.93C17,17.43 20,14.03 20,10A8,8 0 0,0 12,2M12,4C12,4 12.74,5.28 13.26,7H10.74C11.26,5.28 12,4 12,4M9.77,4.43C9.5,4.93 9.09,5.84 8.74,7H6.81C7.5,5.84 8.5,4.93 9.77,4.43M14.23,4.44C15.5,4.94 16.5,5.84 17.19,7H15.26C14.91,5.84 14.5,4.93 14.23,4.44M6.09,9H8.32C8.28,9.33 8.25,9.66 8.25,10C8.25,10.34 8.28,10.67 8.32,11H6.09C6.03,10.67 6,10.34 6,10C6,9.66 6.03,9.33 6.09,9M10.32,9H13.68C13.72,9.33 13.75,9.66 13.75,10C13.75,10.34 13.72,10.67 13.68,11H10.32C10.28,10.67 10.25,10.34 10.25,10C10.25,9.66 10.28,9.33 10.32,9M15.68,9H17.91C17.97,9.33 18,9.66 18,10C18,10.34 17.97,10.67 17.91,11H15.68C15.72,10.67 15.75,10.34 15.75,10C15.75,9.66 15.72,9.33 15.68,9M6.81,13H8.74C9.09,14.16 9.5,15.07 9.77,15.56C8.5,15.06 7.5,14.16 6.81,13M10.74,13H13.26C12.74,14.72 12,16 12,16C12,16 11.26,14.72 10.74,13M15.26,13H17.19C16.5,14.16 15.5,15.07 14.23,15.57C14.5,15.07 14.91,14.16 15.26,13Z" />
+</vector>
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/drawable/ic_settings_backup_restore.xml b/res/drawable/ic_settings_backup_restore.xml
new file mode 100644
index 0000000..245b0fc
--- /dev/null
+++ b/res/drawable/ic_settings_backup_restore.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2017 The Android Open Source 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"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:pathData="M14,12c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2 0.9,2 2,2 2,-0.9 2,-2zM12,3c-4.97,0 -9,4.03 -9,9L0,12l4,4 4,-4L5,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.51,0 -2.91,-0.49 -4.06,-1.3l-1.42,1.44C8.04,20.3 9.94,21 12,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9z"
+        android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/res/drawable/leaf_logo.xml b/res/drawable/leaf_logo.xml
new file mode 100644
index 0000000..14088d7
--- /dev/null
+++ b/res/drawable/leaf_logo.xml
@@ -0,0 +1,3 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" android:viewportWidth="140.2" android:viewportHeight="76.8" android:width="140.2dp" android:height="76.8dp">
+    <path android:pathData="M28.88 31.84C35.54 40 45.19 48.78 51 58.5c5.14 10.73 14.22 25.34 -3.33 13.65 -13.43 -6.58 -29.21 -10 -38.22 -22.22C0.3 42.26 -2.77 -3.82 2.74 0.25 24.46 11 48 9.35 60.23 23.48a40.75 40.75 0 0 1 8.15 14.85c2.81 7.88 5.2 -7.21 7.53 -9.22C79.66 22.69 85.58 18 92.06 14.8c14.06 -5.15 29.14 -7 42.88 -13.31 2.26 -1 4.25 -1.55 4.8 -0.43 1.28 18.32 0.77 39.76 -12.86 53.37C114.91 65.51 98 67.91 84.12 76.7c-3.83 1 -0.62 -5.45 0.17 -8 5.56 -16 17.39 -24.86 29.34 -37.27C85.69 39.75 77.73 81 73.41 67.29c-1.25 -2 -0.53 -7.12 -3.5 -7.3 -3.17 0.58 -2.27 13.27 -8.27 7.83C53.88 54 43.86 37.9 28.88 31.84Z" android:fillColor="?android:attr/colorAccent"/>
+</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/layout/dialog_time.xml b/res/layout/dialog_time.xml
new file mode 100644
index 0000000..3572317
--- /dev/null
+++ b/res/layout/dialog_time.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2023 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:paddingLeft="16dp"
+    android:paddingRight="16dp"
+    android:orientation="vertical">
+
+    <TimePicker
+        android:id="@+id/time_picker"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:paddingTop="8dp" />
+
+</LinearLayout>
diff --git a/res/layout/leaf_logo_header.xml b/res/layout/leaf_logo_header.xml
new file mode 100644
index 0000000..4a88bbb
--- /dev/null
+++ b/res/layout/leaf_logo_header.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The LeafOS 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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingLeft="16dp">
+
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginEnd="16dp"
+        android:src="@drawable/leaf_logo" />
+
+</LinearLayout>
diff --git a/res/layout/preference_charging_limit.xml b/res/layout/preference_charging_limit.xml
new file mode 100644
index 0000000..9c2b4fe
--- /dev/null
+++ b/res/layout/preference_charging_limit.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2023 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical"
+    android:paddingVertical="6dip"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:background="?android:attr/selectableItemBackground"
+    android:orientation="vertical">
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textColor="?android:attr/textColorPrimary"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+
+        <TextView
+            android:id="@+id/value"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true"
+            android:layout_centerVertical="true"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"
+            android:singleLine="true" />
+
+    </RelativeLayout>
+
+    <SeekBar
+        android:id="@+id/seekbar_widget"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingVertical="15dip"
+        android:min="70"
+        android:max="100" />
+
+</LinearLayout>
diff --git a/res/layout/preference_dialog_seekbar_material.xml b/res/layout/preference_dialog_seekbar_material.xml
index 09b963a..e7c9132 100644
--- a/res/layout/preference_dialog_seekbar_material.xml
+++ b/res/layout/preference_dialog_seekbar_material.xml
@@ -26,6 +26,17 @@
         android:layout_height="wrap_content"
         android:paddingTop="?android:attr/dialogPreferredPadding" />
 
+     <TextView
+          android:id="@+id/text"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:focusable="false"
+          android:paddingTop="?android:attr/dialogPreferredPadding"
+          android:paddingStart="?android:attr/dialogPreferredPadding"
+          android:paddingEnd="?android:attr/dialogPreferredPadding"
+          style="@style/TextAppearance.DialogMessage"
+          android:visibility="gone"/>
+
     <SeekBar
         android:id="@+id/seekbar"
         android:layout_width="match_parent"
diff --git a/res/raw/swipe_to_screenshot.mp4 b/res/raw/swipe_to_screenshot.mp4
new file mode 100644
index 0000000..5d3b21c
--- /dev/null
+++ b/res/raw/swipe_to_screenshot.mp4
Binary files differ
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index d270183..662d338 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -3785,7 +3785,7 @@
     <string name="memory_usage" msgid="5594133403819880617">"Memory usage"</string>
     <string name="app_list_memory_use" msgid="3178720339027577869">"App usage"</string>
     <string name="memory_details" msgid="6133226869214421347">"Details"</string>
-    <string name="memory_use_summary" msgid="3915964794146424142">"<xliff:g id="SIZE">%1$s</xliff:g> avg memory used in last 3 hours"</string>
+    <string name="memory_use_summary" msgid="3915964794146424142">"<xliff:g id="SIZE">%1$s</xliff:g> average memory used in last 3 hours"</string>
     <string name="no_memory_use_summary" msgid="6708111974923274436">"No memory used in last 3 hours"</string>
     <string name="sort_avg_use" msgid="4416841047669186903">"Sort by avg. use"</string>
     <string name="sort_max_use" msgid="3370552820889448484">"Sort by max. use"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index d3bf696..260014e 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -3785,7 +3785,7 @@
     <string name="memory_usage" msgid="5594133403819880617">"Memory usage"</string>
     <string name="app_list_memory_use" msgid="3178720339027577869">"App usage"</string>
     <string name="memory_details" msgid="6133226869214421347">"Details"</string>
-    <string name="memory_use_summary" msgid="3915964794146424142">"<xliff:g id="SIZE">%1$s</xliff:g> avg memory used in last 3 hours"</string>
+    <string name="memory_use_summary" msgid="3915964794146424142">"<xliff:g id="SIZE">%1$s</xliff:g> average memory used in last 3 hours"</string>
     <string name="no_memory_use_summary" msgid="6708111974923274436">"No memory used in last 3 hours"</string>
     <string name="sort_avg_use" msgid="4416841047669186903">"Sort by avg use"</string>
     <string name="sort_max_use" msgid="3370552820889448484">"Sort by max use"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index acc8f9a..7436a9e 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -3785,7 +3785,7 @@
     <string name="memory_usage" msgid="5594133403819880617">"Memory usage"</string>
     <string name="app_list_memory_use" msgid="3178720339027577869">"App usage"</string>
     <string name="memory_details" msgid="6133226869214421347">"Details"</string>
-    <string name="memory_use_summary" msgid="3915964794146424142">"<xliff:g id="SIZE">%1$s</xliff:g> avg memory used in last 3 hours"</string>
+    <string name="memory_use_summary" msgid="3915964794146424142">"<xliff:g id="SIZE">%1$s</xliff:g> average memory used in last 3 hours"</string>
     <string name="no_memory_use_summary" msgid="6708111974923274436">"No memory used in last 3 hours"</string>
     <string name="sort_avg_use" msgid="4416841047669186903">"Sort by avg. use"</string>
     <string name="sort_max_use" msgid="3370552820889448484">"Sort by max. use"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index ce743ee..d17f2da 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -3785,7 +3785,7 @@
     <string name="memory_usage" msgid="5594133403819880617">"Memory usage"</string>
     <string name="app_list_memory_use" msgid="3178720339027577869">"App usage"</string>
     <string name="memory_details" msgid="6133226869214421347">"Details"</string>
-    <string name="memory_use_summary" msgid="3915964794146424142">"<xliff:g id="SIZE">%1$s</xliff:g> avg memory used in last 3 hours"</string>
+    <string name="memory_use_summary" msgid="3915964794146424142">"<xliff:g id="SIZE">%1$s</xliff:g> average memory used in last 3 hours"</string>
     <string name="no_memory_use_summary" msgid="6708111974923274436">"No memory used in last 3 hours"</string>
     <string name="sort_avg_use" msgid="4416841047669186903">"Sort by avg. use"</string>
     <string name="sort_max_use" msgid="3370552820889448484">"Sort by max. use"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 2811357..832610f 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -3785,7 +3785,7 @@
     <string name="memory_usage" msgid="5594133403819880617">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎‏‎Memory usage‎‏‎‎‏‎"</string>
     <string name="app_list_memory_use" msgid="3178720339027577869">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‎‏‎App usage‎‏‎‎‏‎"</string>
     <string name="memory_details" msgid="6133226869214421347">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎Details‎‏‎‎‏‎"</string>
-    <string name="memory_use_summary" msgid="3915964794146424142">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="SIZE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ avg memory used in last 3 hours‎‏‎‎‏‎"</string>
+    <string name="memory_use_summary" msgid="3915964794146424142">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="SIZE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ average memory used in last 3 hours‎‏‎‎‏‎"</string>
     <string name="no_memory_use_summary" msgid="6708111974923274436">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‎‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‎No memory used in last 3 hours‎‏‎‎‏‎"</string>
     <string name="sort_avg_use" msgid="4416841047669186903">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‏‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‏‏‎Sort by avg use‎‏‎‎‏‎"</string>
     <string name="sort_max_use" msgid="3370552820889448484">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎Sort by max use‎‏‎‎‏‎"</string>
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
new file mode 100644
index 0000000..6c9e6a9
--- /dev/null
+++ b/res/values/cm_strings.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017-2021 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- FastCharge feature -->
+    <string name="fast_charging_title">Fast charging</string>
+    <string name="fast_charging_summary">Disable to reduce the heat produced by the device while charging or to extend the lifespan of the battery</string>
+
+    <!-- High touch sensitivity -->
+    <string name="high_touch_sensitivity_title">High touch sensitivity</string>
+    <string name="high_touch_sensitivity_summary">Increase touchscreen sensitivity so it can be used while wearing gloves</string>
+
+    <!-- Navigation bar hint -->
+    <string name="show_navbar_gesture_bar_title">Gesture bar</string>
+    <string name="show_navbar_gesture_bar_summary">Show gesture bar at the bottom of the screen</string>
+
+    <!-- Black theme for dark mode -->
+    <string name="berry_black_theme_title">Pure black</string>
+    <string name="berry_black_theme_summary">Pure black background for dark theme</string>
+
+    <!-- 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>
+
+    <!-- Whether a visible red line will be drawn after the user has drawn the unlock pattern incorrectly -->
+    <string name="lockpattern_settings_enable_error_path_title">Show pattern error</string>
+    <!-- Whether the dots will be drawn when using the lockscreen pattern -->
+    <string name="lockpattern_settings_enable_dots_title">Show pattern dots</string>
+
+    <!-- Max refresh rate -->
+    <string name="max_refresh_rate_title">Peak refresh rate</string>
+
+    <!-- Min refresh rate -->
+    <string name="min_refresh_rate_title">Minimum refresh rate</string>
+
+    <!-- PIN scramble -->
+    <string name="unlock_scramble_pin_layout_title">Scramble layout</string>
+    <string name="unlock_scramble_pin_layout_summary">Scramble PIN layout when unlocking device</string>
+
+    <!-- Hotspot extras -->
+    <string name="tethering_allow_vpn_upstreams_title">Allow clients to use VPNs</string>
+    <string name="tethering_allow_vpn_upstreams_summary">Permit hotspot clients to use this device\u2019s VPN connections for upstream connectivity</string>
+
+    <!-- Display : Rotation -->
+    <string name="display_rotation_title">Rotation settings</string>
+    <string name="display_rotation_enabled">Auto-rotation is enabled</string>
+    <string name="display_rotation_disabled">Auto-rotation is disabled</string>
+    <string name="display_rotation_unit">degrees</string>
+    <string name="display_rotation_category_title">Rotation modes</string>
+    <string name="display_rotation_0_title">0 degrees</string>
+    <string name="display_rotation_90_title">90 degrees</string>
+    <string name="display_rotation_180_title">180 degrees</string>
+    <string name="display_rotation_270_title">270 degrees</string>
+
+    <!-- Status bar -->
+    <string name="status_bar_title">Status bar</string>
+    <string name="status_bar_system_icons_summary">Control which status bar icons are shown</string>
+
+    <!-- Display settings screen, peak refresh rate settings summary [CHAR LIMIT=NONE] -->
+    <string name="peak_refresh_rate_summary_custom">Automatically raises the refresh rate from 60 to %1$d Hz for some content. Increases battery usage.</string>
+
+    <!-- Location settings screen, setting check box label if Assisted GPS should be enabled -->
+    <string name="assisted_gps">Use assisted GPS</string>
+    <!-- Location settings screen, setting summary for Assisted GPS switch -->
+    <string name="assisted_gps_summary">Download satellite assistance data from the internet which can greatly improve the GPS startup performance. For emergency calls, assisted GPS is always allowed.</string>
+
+    <!-- Backup Transport selection settings menu and activity title -->
+    <string name="backup_transport_setting_label">Change backup provider</string>
+    <string name="backup_transport_title">Select backup provider</string>
+
+    <!-- Charging control settings -->
+    <string name="charging_control_title">Charging control</string>
+    <string name="charging_control_summary">Customize charging schedule and limits for battery</string>
+    <string name="charging_control_enable_title">Enable charging control</string>
+    <string name="charging_control_mode_title">Charging mode</string>
+    <string name="charging_control_mode_auto_title">Automatic schedule</string>
+    <string name="charging_control_mode_auto_summary">Automatically determine when to start charging based on alarms set</string>
+    <string name="charging_control_mode_custom_title">Custom schedule</string>
+    <string name="charging_control_mode_custom_summary">Set a target time to full charge</string>
+    <string name="charging_control_mode_limit_title">Limit charging</string>
+    <string name="charging_control_mode_limit_summary">Limit charging to a certain percentage</string>
+    <string name="charging_control_start_time_title">Start time</string>
+    <string name="charging_control_start_time_summary">Charging control activates when you start charging after %s</string>
+    <string name="charging_control_target_time_title">Target time to full charge</string>
+    <string name="charging_control_target_time_summary">Battery will be fully charged by %s</string>
+    <string name="charging_control_limit_title">Limit</string>
+    <string name="reset">Reset</string>
+</resources>
diff --git a/res/values/leaf_arrays.xml b/res/values/leaf_arrays.xml
new file mode 100644
index 0000000..d541341
--- /dev/null
+++ b/res/values/leaf_arrays.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The LeafOS 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- QS brightness slider -->
+    <string-array name="qs_brightness_slider_entries" translatable="false">
+        <item>@string/qs_brightness_slider_never</item>
+        <item>@string/qs_brightness_slider_expanded</item>
+        <item>@string/qs_brightness_slider_always</item>
+    </string-array>
+
+    <string-array name="qs_brightness_slider_values" translatable="false">
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+    </string-array>
+
+    <string-array name="qs_brightness_slider_position_entries" translatable="false">
+        <item>@string/qs_brightness_slider_position_top</item>
+        <item>@string/qs_brightness_slider_position_bottom</item>
+    </string-array>
+
+    <string-array name="qs_brightness_slider_position_values" translatable="false">
+        <item>0</item>
+        <item>1</item>
+    </string-array>
+
+    <!-- Brightness slider styles -->
+    <string-array name="brightness_slider_style_entries" translatable="false">
+        <item>@string/brightness_slider_style_default</item>
+        <item>@string/brightness_slider_style_filled</item>
+        <item>@string/brightness_slider_style_thin</item>
+    </string-array>
+
+    <string-array name="brightness_slider_style_values">
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+    </string-array>
+
+    <!-- QS panel style -->
+    <string-array name="qs_style_entries">
+        <item>@string/qs_style_default</item>
+        <item>@string/qs_style_round</item>
+    </string-array>
+
+    <string-array name="qs_style_values">
+        <item>0</item>
+        <item>1</item>
+    </string-array>
+
+    <!-- QS tile shape -->
+    <string-array name="qs_tile_shape_entries">
+        <item>@string/qs_tile_round</item>
+        <item>@string/qs_tile_rect</item>
+        <item>@string/qs_tile_mix</item>
+    </string-array>
+
+    <string-array name="qs_tile_shape_values">
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+    </string-array>
+
+    <!-- Values for the charging control modes -->
+    <string-array name="charging_control_mode_entries" translatable="false">
+        <item>@string/charging_control_mode_auto_title</item>
+        <item>@string/charging_control_mode_custom_title</item>
+    </string-array>
+
+    <string-array name="charging_control_mode_values" translatable="false">
+        <item>1</item>
+        <item>2</item>
+    </string-array>
+
+    <!-- Values for the additional charging control modes if fine-grained control is supported -->
+    <string-array name="charging_control_mode_entries_fine_grained_control" translatable="false">
+        <item>@string/charging_control_mode_limit_title</item>
+    </string-array>
+
+    <string-array name="charging_control_mode_values_fine_grained_control" translatable="false">
+        <item>3</item>
+    </string-array>
+</resources>
diff --git a/res/values/leaf_config.xml b/res/values/leaf_config.xml
new file mode 100644
index 0000000..1a7dc7d
--- /dev/null
+++ b/res/values/leaf_config.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The LeafOS 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Whether to show peak refresh rate in display settings -->
+    <bool name="config_show_peak_refresh_rate_switch">false</bool>
+
+    <!-- Whether to show min refresh rate in display settings -->
+    <bool name="config_show_min_refresh_rate_switch">false</bool>
+</resources>
diff --git a/res/values/leaf_plurals.xml b/res/values/leaf_plurals.xml
new file mode 100644
index 0000000..757ce30
--- /dev/null
+++ b/res/values/leaf_plurals.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <plurals name="wifi_hotspot_client_limit_summary">
+        <item quantity="other">Up to <xliff:g id="device_num">%1$d</xliff:g> devices can connect to this hotspot</item>
+        <item quantity="one">Up to <xliff:g id="device_num">%1$d</xliff:g> device can connect to this hotspot</item>
+    </plurals>
+</resources>
diff --git a/res/values/leaf_strings.xml b/res/values/leaf_strings.xml
new file mode 100644
index 0000000..7e34ca1
--- /dev/null
+++ b/res/values/leaf_strings.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The LeafOS 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- About device -->
+    <string name="build_date">Build date</string>
+    <string name="leaf_version">LeafOS version</string>
+    <string name="leaf_vendor_security_patch">Vendor security patch level</string>
+
+    <!-- AdBlock -->
+    <string name="enable_adblock">Enable AdBlock</string>
+    <string name="enable_adblock_summary">Blocks various ads and trackers system-wide.</string>
+
+    <!-- Back gesture height -->
+    <string name="back_height_low_label">Full</string>
+    <string name="back_height_high_label">Bottom</string>
+    <string name="back_options_dialog_title">Options</string>
+    <string name="back_height_message">Amount of screen height used as touchable region for back gesture.</string>
+
+    <!-- Three-fingers-swipe to screenshot -->
+    <string name="three_finger_gesture">Swipe to screenshot</string>
+    <string name="three_finger_gesture_summary">Swipe down with three fingers to take a screenshot</string>
+
+   <!-- Hide power menu on lockscreen -->
+    <string name="hide_powermenu_lockscreen">Hide power menu on lockscreen</string>
+
+    <!-- QS customization -->
+    <string name="qs_panel_options_title">Quick settings</string>
+    <string name="qs_panel_options_summary">Customize quick settings appearance</string>
+    <string name="category_name_qs_tiles">QS tiles</string>
+
+    <!-- QS tile shape -->
+    <string name="qs_tile_shape">QS tile shape</string>
+    <string name="qs_tile_round">Round</string>
+    <string name="qs_tile_rect">Rounded Rectangle</string>
+    <string name="qs_tile_mix">Round for active tiles and Rounded Rectangle for inactive tiles</string>
+
+    <!-- QS brightness slider -->
+    <string name="category_name_qs_brightness_slider">Brightness slider</string>
+    <string name="qs_brightness_slider_title">Brightness slider</string>
+    <string name="qs_brightness_slider_summary">Adjust brightness slider from the Quick Settings</string>
+    <string name="qs_brightness_slider_never">Never show</string>
+    <string name="qs_brightness_slider_expanded">Show when expanded</string>
+    <string name="qs_brightness_slider_always">Show always</string>
+    <string name="qs_brightness_slider_position_title">Brightness slider position</string>
+    <string name="qs_brightness_slider_position_top">Top</string>
+    <string name="qs_brightness_slider_position_bottom">Bottom</string>
+    <!-- QS auto brightness icon -->
+    <string name="qs_auto_brightness_title">Auto brightness icon</string>
+    <string name="qs_auto_brightness_summary">Show toggle for adaptive brightness near the slider</string>
+    <!-- Brightness slider styles -->
+    <string name="brightness_slider_style_title">Brightness slider style</string>
+    <string name="brightness_slider_style_default">Default</string>
+    <string name="brightness_slider_style_filled">Filled</string>
+    <string name="brightness_slider_style_thin">Thin</string>
+
+    <!-- QS style -->
+    <string name="qs_style_title">QS Panel style</string>
+    <string name="qs_style_default">Large pill</string>
+    <string name="qs_style_round">Small circle</string>
+
+    <!-- QS columns customization -->
+    <string name="qs_columns">QS columns in portrait</string>
+    <string name="qs_columns_min" translatable="false">2</string>
+    <string name="qs_columns_max" translatable="false">5</string>
+    <string name="qs_columns_landscape">QS columns in landscape</string>
+    <string name="qs_columns_landscape_min" translatable="false">@string/qs_columns_min</string>
+    <string name="qs_columns_landscape_max" translatable="false">6</string>
+    <string name="qqs_columns">QQS columns in portrait</string>
+    <string name="qqs_columns_min" translatable="false">@string/qs_columns_min</string>
+    <string name="qqs_columns_max" translatable="false">@string/qs_columns_max</string>
+    <string name="qqs_columns_landscape">QQS columns in landscape</string>
+    <string name="qqs_columns_landscape_min" translatable="false">@string/qs_columns_landscape_min</string>
+    <string name="qqs_columns_landscape_max" translatable="false">@string/qs_columns_landscape_max</string>
+
+    <!-- Annoying Notifications -->
+    <string name="notification_sound_vib_screen_on_title">Annoying Notifications</string>
+    <string name="notification_sound_vib_screen_on_summary">Play sound and vibration for notifications when screen is on</string>
+
+    <!-- Hardware info -->
+    <string name="soc_model">SoC Model</string>
+    <string name="total_ram">Total RAM</string>
+
+    <!-- fingerprint lockout -->
+    <string name="fingerprint_lockout_title">Disable fingerprint lockout</string>
+    <string name="fingerprint_lockout_summary">Deactivates 30 second timeout as well as permanent lockout after multiple failed fingerprint unlock attempts</string>
+
+    <!-- Hotspot -->
+    <string name="wifi_hotspot_hidden_ssid_title">Hidden network</string>
+    <string name="wifi_hotspot_hidden_ssid_summary">Your mobile hotspot\'s name won\'t appear in the list of available WLAN networks.</string>
+    <string name="wifi_hotspot_client_manager_title">Connected devices</string>
+    <string name="wifi_hotspot_client_manager_summary">List and manage devices connected to the hotspot</string>
+    <string name="wifi_hotspot_client_manager_list_only_summary">List devices connected to the hotspot</string>
+    <string name="wifi_hotspot_client_limit_title">Limit of connected devices</string>
+    <string name="wifi_hotspot_blocked_clients_list_title">Blocked Devices</string>
+    <string name="wifi_hotspot_connected_clients_list_title">Connected Devices</string>
+    <string name="wifi_hotspot_block_client_dialog_title">Block device</string>
+    <string name="wifi_hotspot_block_client_dialog_text">This action will disconnect \"<xliff:g id="device_name">%1$s</xliff:g>\" from this device and add it to blocklist</string>
+    <string name="wifi_hotspot_unblock_client_dialog_title">Unblock device</string>
+    <string name="wifi_hotspot_unblock_client_dialog_text">The device \"<xliff:g id="device_name">%1$s</xliff:g>\" will be able to connect to this hotspot</string>
+    <string name="wifi_hotspot_client_manager_footer_text">No clients are currently available. Connected and blocked devices will be listed here when available.</string>
+</resources>
diff --git a/res/values/lineage_config.xml b/res/values/lineage_config.xml
new file mode 100644
index 0000000..083a3d6
--- /dev/null
+++ b/res/values/lineage_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2020-2021 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>
+    <string-array name="config_ignored_backup_transports" translatable="false">
+        <item>com.android.localtransport/.LocalTransport</item>
+    </string-array>
+</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/values/strings.xml b/res/values/strings.xml
index 630aeed..35e75cd 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -9416,7 +9416,7 @@
     <string name="memory_details">Details</string>
 
     <!-- Summary for how much memory an app has used [CHAR LIMIT=NONE] -->
-    <string name="memory_use_summary"><xliff:g id="size" example="30MB">%1$s</xliff:g> avg memory used in last 3 hours</string>
+    <string name="memory_use_summary"><xliff:g id="size" example="30MB">%1$s</xliff:g> average memory used in last 3 hours</string>
 
     <!-- Summary for no memory use for an app [CHAR LIMIT=NONE] -->
     <string name="no_memory_use_summary">No memory used in last 3 hours</string>
diff --git a/res/xml/backup_transport_settings.xml b/res/xml/backup_transport_settings.xml
new file mode 100644
index 0000000..cc8cc9a
--- /dev/null
+++ b/res/xml/backup_transport_settings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Calyx Institute
+  ~
+  ~ 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"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:title="@string/backup_transport_title">
+
+    <!-- content gets filled programmatically -->
+
+</PreferenceScreen>
diff --git a/res/xml/charging_control_settings.xml b/res/xml/charging_control_settings.xml
new file mode 100644
index 0000000..4ffcfbf
--- /dev/null
+++ b/res/xml/charging_control_settings.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2023 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+    android:key="charging_control"
+    android:title="@string/charging_control_title">
+
+    <com.android.settingslib.widget.MainSwitchPreference
+        android:key="charging_control_enabled"
+        android:title="@string/charging_control_enable_title" />
+
+    <ListPreference
+        android:key="charging_control_mode"
+        android:title="@string/charging_control_mode_title"
+        android:entries="@array/charging_control_mode_entries"
+        android:entryValues="@array/charging_control_mode_values"
+        android:dependency="charging_control_enabled" />
+
+    <com.android.settings.lineage.health.StartTimePreference
+        android:key="charging_control_start_time"
+        android:title="@string/charging_control_start_time_title"
+        android:dependency="charging_control_enabled" />
+
+    <com.android.settings.lineage.health.TargetTimePreference
+        android:key="charging_control_target_time"
+        android:title="@string/charging_control_target_time_title"
+        android:dependency="charging_control_enabled" />
+
+    <com.android.settings.lineage.health.ChargingLimitPreference
+        android:key="charging_control_charging_limit"
+        android:title="@string/charging_control_limit_title"
+        android:dependency="charging_control_enabled" />
+
+</PreferenceScreen>
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index 59c0c21..ccfa5b7 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -111,6 +111,13 @@
     <PreferenceCategory
         android:key="advanced_section_header"
         android:title="@string/advanced_section_header">
+
+        <com.android.settings.support.SystemSettingSwitchPreference
+            android:key="notification_sound_vib_screen_on"
+            android:title="@string/notification_sound_vib_screen_on_title"
+            android:summary="@string/notification_sound_vib_screen_on_summary"
+            android:defaultValue="true" />
+
         <com.android.settingslib.RestrictedPreference
             android:key="zen_mode_notifications"
             android:order="17"
diff --git a/res/xml/dark_mode_settings.xml b/res/xml/dark_mode_settings.xml
index 7f13659..ec3fe66 100644
--- a/res/xml/dark_mode_settings.xml
+++ b/res/xml/dark_mode_settings.xml
@@ -62,4 +62,10 @@
         settings:searchable="false"
         settings:controller="com.android.settings.display.darkmode.DarkModeCustomBedtimePreferenceController" />
 
+    <SwitchPreference
+        android:key="berry_black_theme"
+        android:title="@string/berry_black_theme_title"
+        android:summary="@string/berry_black_theme_summary"
+        android:defaultValue="false"
+        settings:controller="org.leafos.settings.display.BerryBlackThemePreferenceController" />
 </PreferenceScreen>
diff --git a/res/xml/display_rotation.xml b/res/xml/display_rotation.xml
new file mode 100644
index 0000000..e6a66d3
--- /dev/null
+++ b/res/xml/display_rotation.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source 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"
+        android:title="@string/display_rotation_title"
+        xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
+
+    <SwitchPreference
+        android:key="accelerometer"
+        android:title="@string/accelerometer_title" />
+
+    <PreferenceCategory
+        android:key="display_rotation_category"
+        android:title="@string/display_rotation_category_title" />
+
+        <SwitchPreference
+            android:key="display_rotation_0"
+            android:title="@string/display_rotation_0_title"
+            android:dependency="accelerometer" />
+
+        <SwitchPreference
+            android:key="display_rotation_90"
+            android:title="@string/display_rotation_90_title"
+            android:dependency="accelerometer" />
+
+        <SwitchPreference
+            android:key="display_rotation_180"
+            android:title="@string/display_rotation_180_title"
+            android:dependency="accelerometer" />
+
+        <SwitchPreference
+            android:key="display_rotation_270"
+            android:title="@string/display_rotation_270_title"
+            android:dependency="accelerometer" />
+
+</PreferenceScreen>
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index 2df360d..88a2883 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -76,6 +76,20 @@
             settings:keywords="@string/keywords_dark_ui_mode"/>
 
         <Preference
+            android:key="qs_panel_options"
+            android:persistent="false"
+            android:title="@string/qs_panel_options_title"
+            android:summary="@string/qs_panel_options_summary"
+            android:fragment="org.leafos.settings.qs.QSPanelSettings" />
+
+        <Preference
+            android:key="status_bar_icon_manager"
+            android:title="@string/status_bar_title"
+            android:summary="@string/status_bar_system_icons_summary">
+            <intent android:action="com.android.settings.action.STATUS_BAR_TUNER" />
+        </Preference>
+
+        <Preference
             android:fragment="com.android.settings.accessibility.TextReadingPreferenceFragment"
             android:key="text_reading_options"
             android:persistent="false"
@@ -114,6 +128,12 @@
             settings:keywords="@string/keywords_auto_rotate"
             settings:controller="com.android.settings.display.AutoRotatePreferenceController"/>
 
+        <Preference
+            android:key="display_rotation"
+            android:fragment="com.android.settings.display.DisplayRotation"
+            android:title="@string/display_rotation_title"
+            settings:controller="com.android.settings.display.DisplayRotationPreferenceController" />
+
         <!--
             Auto-rotation preference that will be shown when device state based auto-rotation
             settings are available.
@@ -138,10 +158,21 @@
             android:summary="@string/display_white_balance_summary"
             settings:controller="com.android.settings.display.DisplayWhiteBalancePreferenceController"/>
 
+        <ListPreference
+            android:key="max_refresh_rate"
+            android:title="@string/max_refresh_rate_title"
+            android:summary="@string/summary_placeholder"
+            settings:controller="com.android.settings.display.PeakRefreshRateListPreferenceController" />
+
+        <ListPreference
+            android:key="min_refresh_rate"
+            android:title="@string/min_refresh_rate_title"
+            android:summary="@string/summary_placeholder"
+            settings:controller="com.android.settings.display.MinRefreshRatePreferenceController" />
+
         <SwitchPreferenceCompat
             android:key="peak_refresh_rate"
             android:title="@string/peak_refresh_rate_title"
-            android:summary="@string/peak_refresh_rate_summary"
             settings:controller="com.android.settings.display.PeakRefreshRatePreferenceController"/>
 
         <SwitchPreferenceCompat
@@ -170,6 +201,13 @@
             android:title="@string/tap_to_wake"
             android:summary="@string/tap_to_wake_summary"/>
 
+        <SwitchPreference
+            android:key="high_touch_sensitivity_enable"
+            android:title="@string/high_touch_sensitivity_title"
+            android:summary="@string/high_touch_sensitivity_summary"
+            android:defaultValue="false"
+            settings:controller="org.leafos.settings.display.HighTouchSensitivityPreferenceController"/>
+
         <ListPreference
             android:key="theme"
             android:title="@string/device_theme"
diff --git a/res/xml/firmware_version.xml b/res/xml/firmware_version.xml
index 41f7733..cc88bc9 100644
--- a/res/xml/firmware_version.xml
+++ b/res/xml/firmware_version.xml
@@ -21,6 +21,11 @@
     android:title="@string/firmware_version"
     settings:keywords="@string/keywords_android_version">
 
+    <com.android.settingslib.widget.LayoutPreference
+        android:key="pref_app_header"
+        android:layout="@layout/leaf_logo_header"
+        settings:allowDividerBelow="true"/>
+
     <!-- Android version -->
     <Preference
         android:key="os_firmware_version"
@@ -30,6 +35,14 @@
         settings:searchable="false"
         settings:controller="com.android.settings.deviceinfo.firmwareversion.FirmwareVersionDetailPreferenceController"/>
 
+    <!-- Leaf version -->
+    <Preference
+        android:key="leaf_version"
+        android:title="@string/leaf_version"
+        android:summary="@string/summary_placeholder"
+        settings:enableCopying="true"
+        settings:controller="com.android.settings.deviceinfo.firmwareversion.LeafVersionDetailPreferenceController"/>
+
     <!-- Security patch -->
     <Preference
         android:key="security_key"
@@ -37,13 +50,13 @@
         settings:enableCopying="true"
         settings:controller="com.android.settings.deviceinfo.firmwareversion.SecurityPatchLevelPreferenceController"/>
 
-    <!-- Mainline module version -->
+    <!-- Vendor security patch -->
     <Preference
-        android:key="module_version"
-        android:title="@string/module_version"
-        android:summary="@string/summary_placeholder"
+        android:key="vendor_security_key"
+        android:title="@string/leaf_vendor_security_patch"
+        android:selectable="false"
         settings:enableCopying="true"
-        settings:controller="com.android.settings.deviceinfo.firmwareversion.MainlineModuleVersionPreferenceController"/>
+        settings:controller="com.android.settings.deviceinfo.firmwareversion.LeafVendorSecurityPatchLevelPreferenceController"/>
 
     <!-- Baseband -->
     <Preference
@@ -63,6 +76,14 @@
         settings:enableCopying="true"
         settings:controller="com.android.settings.deviceinfo.firmwareversion.KernelVersionPreferenceController"/>
 
+    <!-- Build date -->
+    <Preference
+        android:key="os_build_date"
+        android:title="@string/build_date"
+        android:summary="@string/summary_placeholder"
+        settings:enableCopying="true"
+        settings:controller="com.android.settings.deviceinfo.firmwareversion.LeafBuildDatePreferenceController"/>
+
     <!-- Build -->
     <Preference
         android:key="os_build_number"
diff --git a/res/xml/gesture_navigation_settings.xml b/res/xml/gesture_navigation_settings.xml
index a4b5af9..9796d0f 100644
--- a/res/xml/gesture_navigation_settings.xml
+++ b/res/xml/gesture_navigation_settings.xml
@@ -55,8 +55,23 @@
             android:max="2"
             settings:textStart="@string/low_label"
             settings:textEnd="@string/high_label"/>
+
+        <com.android.settings.widget.LabeledSeekBarPreference
+            android:key="gesture_back_height"
+            android:title="@string/back_height_message"
+            android:max="3"
+            android:selectable="true"
+            settings:textStart="@string/back_height_low_label"
+            settings:textEnd="@string/back_height_high_label"/>
     </PreferenceCategory>
 
+    <SwitchPreference
+        android:key="navigation_bar_hint"
+        android:title="@string/show_navbar_gesture_bar_title"
+        android:summary="@string/show_navbar_gesture_bar_summary"
+        android:defaultValue="true"
+        settings:controller="org.leafos.settings.gestures.NavigationHintPreferenceController" />
+
     <com.android.settingslib.widget.FooterPreference
         android:key="gesture_navigation_settings_footer"
         android:title="@string/back_sensitivity_dialog_message"
diff --git a/res/xml/gestures.xml b/res/xml/gestures.xml
index 035c7f7..af416a8 100644
--- a/res/xml/gestures.xml
+++ b/res/xml/gestures.xml
@@ -81,6 +81,12 @@
         android:fragment="com.android.settings.gestures.PowerMenuSettings"
         settings:controller="com.android.settings.gestures.PowerMenuPreferenceController" />
 
+    <Preference
+        android:key="three_finger_gesture_summary"
+        android:title="@string/three_finger_gesture"
+        android:fragment="com.android.settings.gestures.SwipeToScreenshotGestureSettings"
+        settings:controller="com.android.settings.gestures.SwipeToScreenshotPreferenceController" />
+
     <com.android.settingslib.PrimarySwitchPreference
         android:key="gesture_prevent_ringing_summary"
         android:title="@string/gesture_prevent_ringing_screen_title"
diff --git a/res/xml/hardware_info.xml b/res/xml/hardware_info.xml
index e086a48..fc4c7b5 100644
--- a/res/xml/hardware_info.xml
+++ b/res/xml/hardware_info.xml
@@ -30,6 +30,24 @@
         settings:controller="com.android.settings.deviceinfo.hardwareinfo.DeviceModelPreferenceController"
         settings:enableCopying="true"/>
 
+    <!-- SoC Model -->
+    <Preference
+        android:key="hardware_info_soc_model"
+        android:title="@string/soc_model"
+        android:summary="@string/summary_placeholder"
+        android:selectable="false"
+        settings:controller="com.android.settings.deviceinfo.hardwareinfo.SoCModelPreferenceController"
+        settings:enableCopying="true"/>
+
+    <!-- Total RAM -->
+    <Preference
+        android:key="hardware_info_ram"
+        android:title="@string/total_ram"
+        android:summary="@string/summary_placeholder"
+        android:selectable="false"
+        settings:controller="com.android.settings.deviceinfo.hardwareinfo.TotalRAMPreferenceController"
+        settings:enableCopying="true"/>
+
     <!-- SerialNumber -->
     <Preference
         android:key="hardware_info_device_serial"
diff --git a/res/xml/hotspot_client_manager.xml b/res/xml/hotspot_client_manager.xml
new file mode 100644
index 0000000..5e5a869
--- /dev/null
+++ b/res/xml/hotspot_client_manager.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2022 Project Kaleidoscope
+
+  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:app="http://schemas.android.com/apk/res-auto"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <ink.kscope.settings.wifi.tether.preference.WifiTetherClientLimitPreference
+        android:key="client_limit"
+        android:title="@string/wifi_hotspot_client_limit_title" />
+
+    <PreferenceCategory
+        android:key="connected_client_list"
+        android:title="@string/wifi_hotspot_connected_clients_list_title" />
+
+    <PreferenceCategory
+        android:key="blocked_client_list"
+        android:title="@string/wifi_hotspot_blocked_clients_list_title" />
+
+    <com.android.settingslib.widget.FooterPreference
+        android:key="footer"
+        android:title="@string/wifi_hotspot_client_manager_footer_text"
+        android:selectable="false" />
+</PreferenceScreen>
diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml
index fe87efd..6e10504 100644
--- a/res/xml/location_settings.xml
+++ b/res/xml/location_settings.xml
@@ -35,6 +35,12 @@
         settings:controller="com.android.settings.location.RecentLocationAccessSeeAllButtonPreferenceController"
         settings:searchable="false"/>
 
+    <SwitchPreferenceCompat
+        android:key="assisted_gps"
+        android:title="@string/assisted_gps"
+        android:summary="@string/assisted_gps_summary"
+        settings:controller="com.android.settings.location.AgpsPreferenceController"/>
+
     <PreferenceCategory
         android:key="location_advanced_settings"
         android:layout="@layout/preference_category_no_label">
diff --git a/res/xml/more_security_privacy_settings.xml b/res/xml/more_security_privacy_settings.xml
index 5cd60f0..01b08d9 100644
--- a/res/xml/more_security_privacy_settings.xml
+++ b/res/xml/more_security_privacy_settings.xml
@@ -93,6 +93,13 @@
             settings:controller=
                 "com.android.settings.sound.MediaControlsLockScreenPreferenceController" />
 
+       <!-- AdBlock -->
+       <SwitchPreference
+           android:key="adblock_enabled"
+           android:title="@string/enable_adblock"
+           android:summary="@string/enable_adblock_summary"
+           settings:controller="com.android.settings.privacy.AdBlockPreferenceController"/>
+
         <!-- Content Capture -->
         <!-- NOTE: content capture has a different preference, depending whether or not the
              ContentCaptureService implementations defines a custom settings activitiy on its manifest.
diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml
index 29c3c62..0493499 100644
--- a/res/xml/my_device_info.xml
+++ b/res/xml/my_device_info.xml
@@ -21,13 +21,6 @@
     android:key="my_device_info_pref_screen"
     android:title="@string/about_settings">
 
-    <com.android.settingslib.widget.LayoutPreference
-        android:key="my_device_info_header"
-        android:order="0"
-        android:layout="@layout/settings_entity_header"
-        android:selectable="false"
-        settings:isPreferenceVisible="false"/>
-
     <PreferenceCategory
         android:key="basic_info_category"
         android:selectable="false"
diff --git a/res/xml/power_menu_settings.xml b/res/xml/power_menu_settings.xml
index 48cc40c..765c12b 100644
--- a/res/xml/power_menu_settings.xml
+++ b/res/xml/power_menu_settings.xml
@@ -40,6 +40,12 @@
             settings:controller="com.android.settings.gestures.LongPressPowerForAssistantPreferenceController"/>
     </PreferenceCategory>
 
+    <com.android.settings.support.SystemSettingSwitchPreference
+        android:key="powermenu_advanced"
+        android:title="@string/power_menu_advanced_restart_title"
+        android:summary="@string/power_menu_advanced_restart_summary"
+        android:defaultValue="false" />
+
     <com.android.settings.widget.LabeledSeekBarPreference
         android:key="gesture_power_menu_long_press_for_assist_sensitivity"
         android:title="@string/power_menu_long_press_for_assist_sensitivity_title"
diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml
index e62f5c0..527d67e 100644
--- a/res/xml/power_usage_summary.xml
+++ b/res/xml/power_usage_summary.xml
@@ -57,6 +57,19 @@
         android:summary="@string/battery_percentage_description"
         settings:controller="com.android.settings.display.BatteryPercentagePreferenceController" />
 
+    <SwitchPreferenceCompat
+        android:key="fast_charging"
+        android:title="@string/fast_charging_title"
+        android:summary="@string/fast_charging_summary"
+        settings:controller="com.android.settings.fuelgauge.FastChargingPreferenceController"/>
+
+    <Preference
+        android:key="charging_control"
+        android:title="@string/charging_control_title"
+        android:summary="@string/charging_control_summary"
+        android:fragment="com.android.settings.lineage.health.ChargingControlSettings"
+        settings:controller="com.android.settings.lineage.health.ChargingControlPreferenceController" />
+
     <com.android.settingslib.widget.FooterPreference
         android:key="power_usage_footer"
         android:title="@string/battery_footer_summary"
diff --git a/res/xml/privacy_dashboard_settings.xml b/res/xml/privacy_dashboard_settings.xml
index 551501b..0eb6dcc 100644
--- a/res/xml/privacy_dashboard_settings.xml
+++ b/res/xml/privacy_dashboard_settings.xml
@@ -155,4 +155,11 @@
         android:summary="@string/show_clip_access_notification_summary"
         settings:controller="com.android.settings.privacy.ShowClipAccessNotificationPreferenceController"/>
 
+    <!-- AdBlock -->
+    <SwitchPreference
+        android:key="adblock_enabled"
+        android:title="@string/enable_adblock"
+        android:summary="@string/enable_adblock_summary"
+        settings:controller="com.android.settings.privacy.AdBlockPreferenceController"/>
+
 </PreferenceScreen>
diff --git a/res/xml/qs_panel_settings.xml b/res/xml/qs_panel_settings.xml
new file mode 100644
index 0000000..e7d6d15
--- /dev/null
+++ b/res/xml/qs_panel_settings.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The LeafOS 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"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:key="qs_panel_options"
+    android:title="@string/qs_panel_options_title">
+
+    <PreferenceCategory
+        android:title="@string/category_name_qs_brightness_slider">
+
+        <com.android.settings.support.SecureSettingListPreference
+            android:key="qs_show_brightness_slider"
+            android:title="@string/qs_brightness_slider_title"
+            android:entries="@array/qs_brightness_slider_entries"
+            android:entryValues="@array/qs_brightness_slider_values"
+            android:defaultValue="1" />
+
+        <com.android.settings.support.SecureSettingListPreference
+            android:key="qs_brightness_slider_position"
+            android:title="@string/qs_brightness_slider_position_title"
+            android:entries="@array/qs_brightness_slider_position_entries"
+            android:entryValues="@array/qs_brightness_slider_position_values"
+            android:defaultValue="0" />
+
+        <com.android.settings.support.SecureSettingListPreference
+            android:key="brightness_slider_style"
+            android:title="@string/brightness_slider_style_title"
+            android:entries="@array/brightness_slider_style_entries"
+            android:entryValues="@array/brightness_slider_style_values"
+            android:defaultValue="0" />
+
+        <com.android.settings.support.SecureSettingSwitchPreference
+            android:key="qs_show_auto_brightness"
+            android:title="@string/qs_auto_brightness_title"
+            android:summary="@string/qs_auto_brightness_summary"
+            android:defaultValue="true" />
+    </PreferenceCategory>
+
+    <PreferenceCategory
+        android:title="@string/category_name_qs_tiles">
+
+        <com.android.settings.support.SecureSettingListPreference
+            android:key="qs_style_round"
+            android:title="@string/qs_style_title"
+            android:entries="@array/qs_style_entries"
+            android:entryValues="@array/qs_style_values"
+            android:defaultValue="1" />
+
+        <com.android.settings.support.SecureSettingListPreference
+            android:key="qs_tile_shape"
+            android:title="@string/qs_tile_shape"
+            android:entries="@array/qs_tile_shape_entries"
+            android:entryValues="@array/qs_tile_shape_values"
+            android:defaultValue="2" />
+
+        <com.android.settings.support.SecureSettingSeekBarPreference
+            android:key="qqs_num_columns"
+            android:title="@string/qqs_columns"
+            android:min="@string/qqs_columns_min"
+            android:max="@string/qqs_columns_max"
+            android:defaultValue="5"
+            settings:textStart="@string/qqs_columns_min"
+            settings:textEnd="@string/qqs_columns_max" />
+
+        <com.android.settings.support.SecureSettingSeekBarPreference
+            android:key="qqs_num_columns_landscape"
+            android:title="@string/qqs_columns_landscape"
+            android:min="@string/qqs_columns_landscape_min"
+            android:max="@string/qqs_columns_landscape_max"
+            android:defaultValue="6"
+            settings:textStart="@string/qqs_columns_landscape_min"
+            settings:textEnd="@string/qqs_columns_landscape_max" />
+
+        <com.android.settings.support.SecureSettingSeekBarPreference
+            android:key="qs_num_columns"
+            android:title="@string/qs_columns"
+            android:min="@string/qs_columns_min"
+            android:max="@string/qs_columns_max"
+            android:defaultValue="4"
+            settings:textStart="@string/qs_columns_min"
+            settings:textEnd="@string/qs_columns_max" />
+
+        <com.android.settings.support.SecureSettingSeekBarPreference
+            android:key="qs_num_columns_landscape"
+            android:title="@string/qs_columns_landscape"
+            android:min="@string/qs_columns_landscape_min"
+            android:max="@string/qs_columns_landscape_max"
+            android:defaultValue="6"
+            settings:textStart="@string/qs_columns_landscape_min"
+            settings:textEnd="@string/qs_columns_landscape_max" />
+    </PreferenceCategory>
+</PreferenceScreen>
diff --git a/res/xml/screen_lock_settings.xml b/res/xml/screen_lock_settings.xml
index 3f732b9..0bb06e7 100644
--- a/res/xml/screen_lock_settings.xml
+++ b/res/xml/screen_lock_settings.xml
@@ -27,6 +27,14 @@
         android:key="visiblepattern"
         android:title="@string/lockpattern_settings_enable_visible_pattern_title" />
 
+    <SwitchPreference
+        android:key="visible_error_pattern"
+        android:title="@string/lockpattern_settings_enable_error_path_title" />
+
+    <SwitchPreference
+        android:key="visibledots"
+        android:title="@string/lockpattern_settings_enable_dots_title" />
+
     <!-- available in pin -->
     <SwitchPreferenceCompat
         android:key="auto_pin_confirm"
@@ -37,8 +45,7 @@
         android:key="enhancedPinPrivacy"
         android:title="@string/lockpattern_settings_enhanced_pin_privacy_title"
         android:summary="@string/lockpattern_settings_enhanced_pin_privacy_summary" />
-
-
+ 
     <!-- available in pin/pattern/password -->
     <com.android.settings.display.TimeoutListPreference
         android:key="lock_after_timeout"
@@ -52,4 +59,10 @@
         android:key="power_button_instantly_locks"
         android:title="@string/lockpattern_settings_enable_power_button_instantly_locks" />
 
+    <!-- Lineage additions, available in pin/pattern/password/slide -->
+    <SwitchPreferenceCompat
+        android:key="lockscreen_scramble_pin_layout"
+        android:title="@string/unlock_scramble_pin_layout_title"
+        android:summary="@string/unlock_scramble_pin_layout_summary" />
+
 </PreferenceScreen>
diff --git a/res/xml/security_lockscreen_settings.xml b/res/xml/security_lockscreen_settings.xml
index cb1ce44..967bf6c 100644
--- a/res/xml/security_lockscreen_settings.xml
+++ b/res/xml/security_lockscreen_settings.xml
@@ -79,6 +79,11 @@
             android:title="@string/lockscreen_double_line_clock_setting_toggle"
             android:summary="@string/lockscreen_double_line_clock_summary"
             settings:controller="com.android.settings.display.LockscreenClockPreferenceController" />
+
+        <com.android.settings.support.SystemSettingSwitchPreference
+            android:key="hide_powermenu_lockscreen"
+            android:title="@string/hide_powermenu_lockscreen"
+            android:defaultValue="false" />
     </PreferenceCategory>
 
     <PreferenceCategory
@@ -122,6 +127,13 @@
             android:summary="@string/doze_summary"
             settings:controller="com.android.settings.display.AmbientDisplayNotificationsPreferenceController" />
 
+        <Preference
+            android:key="doze_device_settings"
+            android:title="@string/ambient_display_screen_title"
+            settings:controller="com.android.settings.display.LineageDozePreferenceController">
+            <intent android:action="org.lineageos.settings.device.DOZE_SETTINGS" />
+        </Preference>
+
     </PreferenceCategory>
 
     <!-- Work profile settings are at the bottom with high order value to avoid users thinking that
diff --git a/res/xml/security_settings_fingerprint.xml b/res/xml/security_settings_fingerprint.xml
index 0156ef9..df9676c 100644
--- a/res/xml/security_settings_fingerprint.xml
+++ b/res/xml/security_settings_fingerprint.xml
@@ -41,6 +41,12 @@
             android:summary="@string/security_settings_require_screen_on_to_auth_description"
             settings:keywords="@string/security_settings_require_screen_on_to_auth_keywords"
             settings:controller="com.android.settings.biometrics.fingerprint.FingerprintSettingsRequireScreenOnToAuthPreferenceController" />
+
+        <com.android.settings.support.SystemSettingSwitchPreference
+            android:key="fingerprint_lockout"
+            android:title="@string/fingerprint_lockout_title"
+            android:summary="@string/fingerprint_lockout_summary"
+            android:defaultValue="false" />
     </PreferenceCategory>
 
     <PreferenceCategory
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/res/xml/swipe_to_screenshot_gesture_settings.xml b/res/xml/swipe_to_screenshot_gesture_settings.xml
new file mode 100644
index 0000000..90327e6
--- /dev/null
+++ b/res/xml/swipe_to_screenshot_gesture_settings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 The Android Open Source 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"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:key="swipe_to_screenshot_screen"
+    android:title="@string/three_finger_gesture">
+
+    <com.android.settings.widget.VideoPreference
+        android:key="swipe_to_screenshot_video"
+        app:animation="@raw/swipe_to_screenshot"
+        app:preview="@drawable/swipe_to_screenshot" />
+
+    <SwitchPreference
+        android:key="swipe_to_screenshot"
+        android:title="@string/three_finger_gesture"
+        android:summary="@string/three_finger_gesture_summary"
+        app:keywords="@string/keywords_gesture"
+        app:controller="com.android.settings.gestures.SwipeToScreenshotPreferenceController"
+        app:allowDividerAbove="true" />
+
+</PreferenceScreen>
diff --git a/res/xml/tether_prefs.xml b/res/xml/tether_prefs.xml
index 89bd631..481f184 100644
--- a/res/xml/tether_prefs.xml
+++ b/res/xml/tether_prefs.xml
@@ -49,6 +49,12 @@
         android:summary="@string/ethernet_tethering_subtext"
         settings:keywords="@string/keywords_hotspot_tethering" />
 
+    <com.android.settings.support.SecureSettingSwitchPreference
+        android:key="tethering_allow_vpn_upstreams"
+        android:title="@string/tethering_allow_vpn_upstreams_title"
+        android:summary="@string/tethering_allow_vpn_upstreams_summary"
+        android:defaultValue="false" />
+
     <com.android.settingslib.widget.FooterPreference
         android:key="disabled_on_data_saver"
         android:title="@string/tether_settings_disabled_on_data_saver"
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index 4924bf9..332cab0 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -65,4 +65,14 @@
         android:title="@string/wifi_hotspot_instant_title"
         android:summary="@string/summary_placeholder"
         settings:isPreferenceVisible="false"/>
+
+    <SwitchPreference
+        android:key="wifi_tether_hidden_ssid"
+        android:title="@string/wifi_hotspot_hidden_ssid_title"
+        android:summary="@string/wifi_hotspot_hidden_ssid_summary" />
+
+    <Preference
+        android:key="wifi_tether_client_manager"
+        android:title="@string/wifi_hotspot_client_manager_title"
+        android:fragment="ink.kscope.settings.wifi.tether.WifiTetherClientManager" />
 </PreferenceScreen>
diff --git a/src/com/android/settings/SeekBarDialogPreference.java b/src/com/android/settings/SeekBarDialogPreference.java
index d0c8134..22cbcae 100644
--- a/src/com/android/settings/SeekBarDialogPreference.java
+++ b/src/com/android/settings/SeekBarDialogPreference.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2007 The Android Open Source Project
+ *           (C) 2022 Project Kaleidoscope
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,12 +19,15 @@
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.SeekBar;
+import android.widget.TextView;
 
 import com.android.settingslib.CustomDialogPreferenceCompat;
+import com.android.settings.R;
 
 /**
  * Based on frameworks/base/core/java/android/preference/SeekBarDialogPreference.java
@@ -31,6 +35,7 @@
  */
 public class SeekBarDialogPreference extends CustomDialogPreferenceCompat {
     private final Drawable mMyIcon;
+    private TextView mTextView;
 
     public SeekBarDialogPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -64,6 +69,19 @@
         } else {
             iconView.setVisibility(View.GONE);
         }
+
+        mTextView = view.findViewById(R.id.text);
+    }
+
+    public void setText(String text) {
+        if (mTextView != null) {
+            if (TextUtils.isEmpty(text)) {
+                mTextView.setVisibility(View.GONE);
+            } else {
+                mTextView.setVisibility(View.VISIBLE);
+            }
+            mTextView.setText(text);
+        }
     }
 
     protected static SeekBar getSeekBar(View dialogView) {
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index e370f3e..26802b1 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -852,9 +852,11 @@
         }
         mOptionsMenu.findItem(R.id.advanced).setVisible(false);
 
-        mOptionsMenu.findItem(R.id.sort_order_alpha).setVisible(mListType == LIST_TYPE_STORAGE
+        mOptionsMenu.findItem(R.id.sort_order_alpha).setVisible(
+                (mListType == LIST_TYPE_STORAGE || mListType == LIST_TYPE_MAIN)
                 && mSortOrder != R.id.sort_order_alpha);
-        mOptionsMenu.findItem(R.id.sort_order_size).setVisible(mListType == LIST_TYPE_STORAGE
+        mOptionsMenu.findItem(R.id.sort_order_size).setVisible(
+                (mListType == LIST_TYPE_STORAGE || mListType == LIST_TYPE_MAIN)
                 && mSortOrder != R.id.sort_order_size);
 
         mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem
diff --git a/src/com/android/settings/backup/BackupSettingsFragment.java b/src/com/android/settings/backup/BackupSettingsFragment.java
index 7df19f5..7fcbd63 100644
--- a/src/com/android/settings/backup/BackupSettingsFragment.java
+++ b/src/com/android/settings/backup/BackupSettingsFragment.java
@@ -42,6 +42,13 @@
         super.onCreate(savedInstanceState);
     }
 
+    @Override
+    public void onStart() {
+        super.onStart();
+        // update information when we navigate back from TransportActivity
+        displayResourceTilesToScreen(getPreferenceScreen());
+    }
+
     /**
      * Get the tag string for logging.
      */
diff --git a/src/com/android/settings/backup/BackupSettingsPreferenceController.java b/src/com/android/settings/backup/BackupSettingsPreferenceController.java
index 4e0e3b4..3208ae4 100644
--- a/src/com/android/settings/backup/BackupSettingsPreferenceController.java
+++ b/src/com/android/settings/backup/BackupSettingsPreferenceController.java
@@ -30,24 +30,24 @@
         implements PreferenceControllerMixin {
     private static final String BACKUP_SETTINGS = "backup_settings";
     private static final  String MANUFACTURER_SETTINGS = "manufacturer_backup";
-    private Intent mBackupSettingsIntent;
-    private CharSequence mBackupSettingsTitle;
-    private String mBackupSettingsSummary;
+    private final BackupSettingsHelper settingsHelper;
     private Intent mManufacturerIntent;
     private String mManufacturerLabel;
 
     public BackupSettingsPreferenceController(Context context) {
         super(context);
-        BackupSettingsHelper settingsHelper = new BackupSettingsHelper(context);
-        mBackupSettingsIntent = settingsHelper.getIntentForBackupSettings();
-        mBackupSettingsTitle = settingsHelper.getLabelForBackupSettings();
-        mBackupSettingsSummary = settingsHelper.getSummaryForBackupSettings();
+        settingsHelper = new BackupSettingsHelper(context);
         mManufacturerIntent = settingsHelper.getIntentProvidedByManufacturer();
         mManufacturerLabel = settingsHelper.getLabelProvidedByManufacturer();
     }
 
     @Override
     public void displayPreference(PreferenceScreen screen) {
+        // we don't get these in the constructor, so we can get updates for them later
+        Intent mBackupSettingsIntent = settingsHelper.getIntentForBackupSettings();
+        CharSequence mBackupSettingsTitle = settingsHelper.getLabelForBackupSettings();
+        String mBackupSettingsSummary = settingsHelper.getSummaryForBackupSettings();
+
         Preference backupSettings = screen.findPreference(BACKUP_SETTINGS);
         Preference manufacturerSettings = screen.findPreference(MANUFACTURER_SETTINGS);
         backupSettings.setIntent(mBackupSettingsIntent);
diff --git a/src/com/android/settings/backup/transport/Transport.java b/src/com/android/settings/backup/transport/Transport.java
new file mode 100644
index 0000000..d2fd6e0
--- /dev/null
+++ b/src/com/android/settings/backup/transport/Transport.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Calyx Institute
+ *
+ * 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.backup.transport;
+
+class Transport {
+    final String name;
+    final CharSequence dataManagementLabel;
+    final CharSequence destinationString;
+
+    Transport(String name, CharSequence dataManagementLabel, CharSequence destinationString) {
+        this.name = name;
+        this.dataManagementLabel = dataManagementLabel;
+        this.destinationString = destinationString;
+    }
+}
diff --git a/src/com/android/settings/backup/transport/TransportActivity.java b/src/com/android/settings/backup/transport/TransportActivity.java
new file mode 100644
index 0000000..1adcb90
--- /dev/null
+++ b/src/com/android/settings/backup/transport/TransportActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Calyx Institute
+ *
+ * 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.backup.transport;
+
+import android.os.Bundle;
+import androidx.fragment.app.FragmentActivity;
+
+/**
+ * Activity to allow the user to choose the {@link android.app.backup.BackupTransport}.
+ *
+ * Set {@code config_backup_settings_intent} to {@code settings://com.android.settings.backup.transport} to activate.
+ * Don't forget to also set {@code config_backup_settings_label} or else it won't be shown.
+ */
+public class TransportActivity extends FragmentActivity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getSupportFragmentManager().beginTransaction()
+            .replace(android.R.id.content, new TransportFragment())
+            .commit();
+    }
+
+}
diff --git a/src/com/android/settings/backup/transport/TransportFragment.java b/src/com/android/settings/backup/transport/TransportFragment.java
new file mode 100644
index 0000000..6c6a8ce
--- /dev/null
+++ b/src/com/android/settings/backup/transport/TransportFragment.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Calyx Institute
+ *
+ * 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.backup.transport;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import com.android.settings.R;
+import com.android.settings.backup.transport.TransportPreferenceController.OnTransportChangedListener;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TransportFragment extends DashboardFragment implements OnTransportChangedListener {
+
+    private static final String TAG = "TransportFragment";
+
+    /**
+     * Get the tag string for logging.
+     */
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    /**
+     * Get the res id for static preference xml for this fragment.
+     */
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.backup_transport_settings;
+    }
+
+    /**
+     * Get a list of {@link AbstractPreferenceController} for this fragment.
+     */
+    @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        final List<AbstractPreferenceController> controllers = new ArrayList<>();
+        controllers.add(new TransportPreferenceController(context, this));
+        return controllers;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.BACKUP_SETTINGS;
+    }
+
+    @Override
+    public void onTransportChanged(String transportName) {
+        requireActivity().finish();
+    }
+
+}
diff --git a/src/com/android/settings/backup/transport/TransportHelper.java b/src/com/android/settings/backup/transport/TransportHelper.java
new file mode 100644
index 0000000..1ab5a59
--- /dev/null
+++ b/src/com/android/settings/backup/transport/TransportHelper.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 The Calyx Institute
+ *
+ * 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.backup.transport;
+
+import android.app.backup.IBackupManager;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+import androidx.annotation.Nullable;
+
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Helper class for {@link TransportActivity} that interacts with {@link IBackupManager}.
+ */
+class TransportHelper {
+    private static final String TAG = "TransportHelper";
+
+    private final IBackupManager mBackupManager = IBackupManager.Stub.asInterface(
+        ServiceManager.getService(Context.BACKUP_SERVICE));
+
+    private Context mContext;
+
+    TransportHelper(Context context) {
+        mContext = context;
+    }
+
+    List<Transport> getTransports() {
+        String[] backupTransports = getBackupTransports();
+        if (backupTransports == null) return Collections.emptyList();
+        ArrayList<Transport> transports = new ArrayList<>(backupTransports.length);
+        String[] ignoredTransports = mContext.getResources().getStringArray(
+                R.array.config_ignored_backup_transports);
+        for (String name : getBackupTransports()) {
+            boolean ignored = false;
+            for (String ignoredTransport : ignoredTransports) {
+                if (name.equals(ignoredTransport)) ignored = true;
+            }
+            if (ignored) continue;
+            CharSequence label = getLabelFromBackupTransport(name);
+            if (label == null || label.length() == 0) label = name;
+            Transport transport = new Transport(name, label, getSummaryFromBackupTransport(name));
+            transports.add(transport);
+        }
+        return transports;
+    }
+
+    void selectTransport(String name) {
+        try {
+            mBackupManager.selectBackupTransport(name);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error selecting transport: " + name, e);
+        }
+    }
+
+    @Nullable
+    private String[] getBackupTransports() {
+        try {
+            String[] transports = mBackupManager.listAllTransports();
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Received all backup transports: " + Arrays.toString(transports));
+            }
+            return transports;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error getting all backup transports", e);
+        }
+        return null;
+    }
+
+    private CharSequence getLabelFromBackupTransport(String transport) {
+        try {
+            CharSequence label = mBackupManager.getDataManagementLabelForUser(UserHandle.myUserId(), transport);
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Received the backup settings label from " + transport + ": " + label);
+            }
+            return label;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error getting data management label for " + transport, e);
+        }
+        return null;
+    }
+
+    private String getSummaryFromBackupTransport(String transport) {
+        try {
+            String summary = mBackupManager.getDestinationString(transport);
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Received the backup settings summary from " + transport + ": " + summary);
+            }
+            return summary;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error getting data management summary", e);
+        }
+        return null;
+    }
+}
diff --git a/src/com/android/settings/backup/transport/TransportPreferenceController.java b/src/com/android/settings/backup/transport/TransportPreferenceController.java
new file mode 100644
index 0000000..1dc5a51
--- /dev/null
+++ b/src/com/android/settings/backup/transport/TransportPreferenceController.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 The Calyx Institute
+ *
+ * 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.backup.transport;
+
+import android.content.Context;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+public class TransportPreferenceController extends AbstractPreferenceController {
+
+    interface OnTransportChangedListener {
+        void onTransportChanged(String transportName);
+    }
+
+    private final OnTransportChangedListener listener;
+    private final TransportHelper transportHelper;
+
+    public TransportPreferenceController(Context context, OnTransportChangedListener listener) {
+        super(context);
+        this.listener = listener;
+        transportHelper = new TransportHelper(context);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        for (Transport transport : transportHelper.getTransports()) {
+            screen.addPreference(getPreferenceForTransport(transport));
+        }
+    }
+
+    private Preference getPreferenceForTransport(Transport transport) {
+        Preference p = new Preference(mContext);
+        p.setTitle(transport.dataManagementLabel);
+        p.setSummary(transport.destinationString);
+        p.setIconSpaceReserved(false);
+        p.setOnPreferenceClickListener(preference -> {
+            transportHelper.selectTransport(transport.name);
+            listener.onTransportChanged(transport.name);
+            return true;
+        });
+        return p;
+    }
+
+    /**
+     * Returns true if preference is available (should be displayed)
+     */
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    /**
+     * Returns the key for this preference.
+     */
+    @Override
+    public String getPreferenceKey() {
+        return null;
+    }
+}
diff --git a/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java b/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java
index ee0021e..f16dd37 100644
--- a/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java
+++ b/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java
@@ -16,21 +16,47 @@
 
 package com.android.settings.connecteddevice;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.nfc.NfcAdapter;
 import android.os.UserManager;
 
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.core.lifecycle.events.OnStop;
 
 /**
  * Controller that used to show NFC and payment features
  */
-public class NfcAndPaymentFragmentController extends BasePreferenceController {
+public class NfcAndPaymentFragmentController extends BasePreferenceController
+        implements LifecycleObserver, OnResume, OnStop {
     private final NfcAdapter mNfcAdapter;
     private final PackageManager mPackageManager;
     private final UserManager mUserManager;
+    private final IntentFilter mIntentFilter;
+    private Preference mPreference;
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (mPreference == null) {
+                return;
+            }
+
+            final String action = intent.getAction();
+            if (NfcAdapter.ACTION_ADAPTER_STATE_CHANGED.equals(action)) {
+                refreshSummary(mPreference);
+            }
+        }
+    };
 
     public NfcAndPaymentFragmentController(Context context, String preferenceKey) {
         super(context, preferenceKey);
@@ -38,6 +64,15 @@
         mPackageManager = context.getPackageManager();
         mUserManager = context.getSystemService(UserManager.class);
         mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
+
+        mIntentFilter = isNfcAvailable()
+                ? new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED) : null;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(getPreferenceKey());
     }
 
     @Override
@@ -61,4 +96,26 @@
         }
         return null;
     }
+
+    @Override
+    public void onStop() {
+        if (!isNfcAvailable()) {
+            return;
+        }
+
+        mContext.unregisterReceiver(mReceiver);
+    }
+
+    @Override
+    public void onResume() {
+        if (!isNfcAvailable()) {
+            return;
+        }
+
+        mContext.registerReceiver(mReceiver, mIntentFilter);
+    }
+
+    private boolean isNfcAvailable() {
+        return mNfcAdapter != null;
+    }
 }
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index d68f2c8..48c69eb 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -192,6 +192,8 @@
 import com.android.settings.wifi.savedaccesspoints2.SavedAccessPointsWifiSettings2;
 import com.android.settings.wifi.tether.WifiTetherSettings;
 
+import ink.kscope.settings.wifi.tether.WifiTetherClientManager;
+
 public class SettingsGateway {
 
     /**
@@ -372,6 +374,7 @@
             BatteryInfoFragment.class.getName(),
             UserAspectRatioDetails.class.getName(),
             ScreenTimeoutSettings.class.getName(),
+            WifiTetherClientManager.class.getName()
     };
 
     public static final String[] SETTINGS_FOR_RESTRICTED = {
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index 50b6097..37e45d5 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -88,7 +88,6 @@
     @Override
     public void onStart() {
         super.onStart();
-        initHeader();
     }
 
     @Override
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/LeafBuildDatePreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/LeafBuildDatePreferenceController.java
new file mode 100644
index 0000000..b448e32
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/firmwareversion/LeafBuildDatePreferenceController.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ * Copyright (C) 2022 The LeafOS 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.deviceinfo.firmwareversion;
+
+import android.content.Context;
+import android.os.SystemProperties;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+public class LeafBuildDatePreferenceController extends BasePreferenceController {
+
+    private static final String TAG = "LeafBuildDateCtrl";
+
+    private static final String KEY_BUILD_DATE_PROP = "ro.build.date";
+
+    public LeafBuildDatePreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return SystemProperties.get(KEY_BUILD_DATE_PROP,
+                mContext.getString(R.string.unknown));
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/LeafVendorSecurityPatchLevelPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/LeafVendorSecurityPatchLevelPreferenceController.java
new file mode 100644
index 0000000..0775817
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/firmwareversion/LeafVendorSecurityPatchLevelPreferenceController.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ * Copyright (C) 2022 The LeafOS 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.deviceinfo.firmwareversion;
+
+import android.content.Context;
+import android.os.SystemProperties;
+import android.text.format.DateFormat;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+public class LeafVendorSecurityPatchLevelPreferenceController extends BasePreferenceController {
+
+    private static final String TAG = "LeafVendorSecurityPatchCtrl";
+
+    private static final String KEY_AOSP_VENDOR_SECURITY_PATCH =
+            "ro.vendor.build.security_patch";
+
+    public LeafVendorSecurityPatchLevelPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        String patchLevel = SystemProperties.get(KEY_AOSP_VENDOR_SECURITY_PATCH);
+
+        if (!patchLevel.isEmpty()) {
+            try {
+                SimpleDateFormat template = new SimpleDateFormat("yyyy-MM-dd");
+                Date patchLevelDate = template.parse(patchLevel);
+                String format = DateFormat.getBestDateTimePattern(Locale.getDefault(), "dMMMMyyyy");
+                patchLevel = DateFormat.format(format, patchLevelDate).toString();
+            } catch (ParseException e) {
+                // parsing failed, use raw string
+            }
+        } else {
+            patchLevel = mContext.getString(R.string.unknown);
+        }
+
+        return patchLevel;
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/LeafVersionDetailPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/LeafVersionDetailPreferenceController.java
new file mode 100644
index 0000000..9b9f7bb
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/firmwareversion/LeafVersionDetailPreferenceController.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ * Copyright (C) 2022 The LeafOS 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.deviceinfo.firmwareversion;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.slices.Sliceable;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+
+public class LeafVersionDetailPreferenceController extends BasePreferenceController {
+
+    private static final String TAG = "LeafVersionDialogCtrl";
+    private static final int DELAY_TIMER_MILLIS = 500;
+    private static final int ACTIVITY_TRIGGER_COUNT = 3;
+
+    private static final String KEY_LEAF_VERSION_PROP = "ro.leaf.display.version";
+
+    private static final String PLATLOGO_PACKAGE_NAME = "org.leafos.leafparts";
+    private static final String PLATLOGO_ACTIVITY_CLASS =
+            PLATLOGO_PACKAGE_NAME + ".logo.PlatLogoActivity";
+
+    private final UserManager mUserManager;
+    private final long[] mHits = new long[ACTIVITY_TRIGGER_COUNT];
+
+    private RestrictedLockUtils.EnforcedAdmin mFunDisallowedAdmin;
+    private boolean mFunDisallowedBySystem;
+
+    public LeafVersionDetailPreferenceController(Context context, String key) {
+        super(context, key);
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        initializeAdminPermissions();
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public boolean useDynamicSliceSummary() {
+        return true;
+    }
+
+    @Override
+    public boolean isSliceable() {
+        return true;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return SystemProperties.get(KEY_LEAF_VERSION_PROP,
+                mContext.getString(R.string.unknown));
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+            return false;
+        }
+        if (Utils.isMonkeyRunning()) {
+            return false;
+        }
+        arrayCopy();
+        mHits[mHits.length - 1] = SystemClock.uptimeMillis();
+        if (mHits[0] >= (SystemClock.uptimeMillis() - DELAY_TIMER_MILLIS)) {
+            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN)) {
+                if (mFunDisallowedAdmin != null && !mFunDisallowedBySystem) {
+                    RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext,
+                            mFunDisallowedAdmin);
+                }
+                Log.d(TAG, "Sorry, no fun for you!");
+                return true;
+            }
+
+            final Intent intent = new Intent(Intent.ACTION_MAIN)
+                     .setClassName(PLATLOGO_PACKAGE_NAME, PLATLOGO_ACTIVITY_CLASS);
+            try {
+                mContext.startActivity(intent);
+            } catch (Exception e) {
+                Log.e(TAG, "Unable to start activity " + intent.toString());
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Copies the array onto itself to remove the oldest hit.
+     */
+    @VisibleForTesting
+    void arrayCopy() {
+        System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);
+    }
+
+    @VisibleForTesting
+    void initializeAdminPermissions() {
+        mFunDisallowedAdmin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
+                mContext, UserManager.DISALLOW_FUN, UserHandle.myUserId());
+        mFunDisallowedBySystem = RestrictedLockUtilsInternal.hasBaseUserRestriction(
+                mContext, UserManager.DISALLOW_FUN, UserHandle.myUserId());
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/SoCModelPreferenceController.java b/src/com/android/settings/deviceinfo/hardwareinfo/SoCModelPreferenceController.java
new file mode 100644
index 0000000..04bbba2
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/hardwareinfo/SoCModelPreferenceController.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 The Android Open Source 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.deviceinfo.hardwareinfo;
+
+import android.content.Context;
+import android.os.Build;
+import android.os.SystemProperties;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.slices.Sliceable;
+
+public class SoCModelPreferenceController extends BasePreferenceController {
+
+    public SoCModelPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return mContext.getResources().getBoolean(R.bool.config_show_device_model)
+                ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public boolean useDynamicSliceSummary() {
+        return true;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        if (!Build.SOC_MODEL.equals(Build.UNKNOWN)) {
+            if (!Build.SOC_MANUFACTURER.equals(Build.UNKNOWN)) {
+                return Build.SOC_MANUFACTURER + " " + Build.SOC_MODEL;
+            }
+            return Build.SOC_MODEL;
+        }
+        return SystemProperties.get("ro.board.platform");
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/TotalRAMPreferenceController.java b/src/com/android/settings/deviceinfo/hardwareinfo/TotalRAMPreferenceController.java
new file mode 100644
index 0000000..9009610
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/hardwareinfo/TotalRAMPreferenceController.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The LeafOS 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.deviceinfo.hardwareinfo;
+
+import android.content.Context;
+import android.text.format.Formatter;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.applications.ProcStatsData;
+import com.android.settings.applications.ProcessStatsBase;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.utils.ThreadUtils;
+
+public class TotalRAMPreferenceController extends BasePreferenceController implements
+        PreferenceControllerMixin {
+
+    private ProcStatsData mProcStatsData;
+    private PreferenceScreen mPreferenceScreen;
+
+    public TotalRAMPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return mContext.getResources().getBoolean(R.bool.config_show_device_model)
+                ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        mProcStatsData = getProcStatsData();
+        mPreferenceScreen = screen;
+        setDuration();
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        // This is posted on the background thread to speed up fragment launch time for dev options
+        // mProcStasData.refreshStats(true) takes ~20ms to run.
+        ThreadUtils.postOnBackgroundThread(() -> {
+            mProcStatsData.refreshStats(true);
+            final ProcStatsData.MemInfo memInfo = mProcStatsData.getMemInfo();
+            final String totalResult = Formatter.formatShortFileSize(mContext,
+                    (long) memInfo.realTotalRam);
+            ThreadUtils.postOnMainThread(
+                    () -> mPreferenceScreen.findPreference(mPreferenceKey).setSummary(totalResult));
+        });
+    }
+
+    @VisibleForTesting
+    void setDuration() {
+        mProcStatsData.setDuration(ProcessStatsBase.sDurations[0] /* 3 hours */);
+    }
+
+    @VisibleForTesting
+    ProcStatsData getProcStatsData() {
+        return new ProcStatsData(mContext, false);
+    }
+}
diff --git a/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java b/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java
index 2458034..beedea4 100644
--- a/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java
+++ b/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java
@@ -29,6 +29,8 @@
 import com.android.settings.R;
 import com.android.settings.core.TogglePreferenceController;
 
+import org.leafos.settings.util.PackageManagerUtils;
+
 public class AmbientDisplayAlwaysOnPreferenceController extends TogglePreferenceController {
 
     private final int ON = 1;
@@ -47,7 +49,8 @@
     @Override
     public int getAvailabilityStatus() {
         return isAvailable(getConfig())
-                && !SystemProperties.getBoolean(PROP_AWARE_AVAILABLE, false) ?
+                && !SystemProperties.getBoolean(PROP_AWARE_AVAILABLE, false)
+                && !PackageManagerUtils.isCustomDozePresent(mContext.getPackageManager()) ?
                 AVAILABLE : UNSUPPORTED_ON_DEVICE;
     }
 
diff --git a/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java b/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java
index 71d431a..91f745b 100644
--- a/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java
+++ b/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java
@@ -30,6 +30,8 @@
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
+import org.leafos.settings.util.PackageManagerUtils;
+
 public class AmbientDisplayNotificationsPreferenceController extends
         TogglePreferenceController implements Preference.OnPreferenceChangeListener {
 
@@ -81,6 +83,7 @@
     @Override
     public int getAvailabilityStatus() {
         return getAmbientConfig().pulseOnNotificationAvailable()
+                && !PackageManagerUtils.isCustomDozePresent(mContext.getPackageManager())
                 ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
     }
 
diff --git a/src/com/android/settings/display/ColorModePreferenceController.java b/src/com/android/settings/display/ColorModePreferenceController.java
index 6cd4867..14a2241 100644
--- a/src/com/android/settings/display/ColorModePreferenceController.java
+++ b/src/com/android/settings/display/ColorModePreferenceController.java
@@ -28,8 +28,11 @@
 
     @Override
     public int getAvailabilityStatus() {
+        final int[] availableColorModes = mContext.getResources().getIntArray(
+                com.android.internal.R.array.config_availableColorModes);
         return mContext.getSystemService(ColorDisplayManager.class)
                 .isDeviceColorManaged()
+                && availableColorModes.length > 0
                 && !ColorDisplayManager.areAccessibilityTransformsEnabled(mContext) ?
                 AVAILABLE : DISABLED_FOR_USER;
     }
diff --git a/src/com/android/settings/display/DisplayRotation.java b/src/com/android/settings/display/DisplayRotation.java
new file mode 100644
index 0000000..f020a21
--- /dev/null
+++ b/src/com/android/settings/display/DisplayRotation.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 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.display;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import androidx.preference.Preference;
+import androidx.preference.Preference.OnPreferenceChangeListener;
+import androidx.preference.SwitchPreference;
+import android.provider.Settings;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.view.RotationPolicy;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+
+public class DisplayRotation extends SettingsPreferenceFragment implements OnPreferenceChangeListener {
+    private static final String TAG = "DisplayRotation";
+
+    private static final String KEY_ACCELEROMETER = "accelerometer";
+    private static final String ROTATION_0_PREF = "display_rotation_0";
+    private static final String ROTATION_90_PREF = "display_rotation_90";
+    private static final String ROTATION_180_PREF = "display_rotation_180";
+    private static final String ROTATION_270_PREF = "display_rotation_270";
+
+    private SwitchPreference mAccelerometer;
+    private SwitchPreference mRotation0Pref;
+    private SwitchPreference mRotation90Pref;
+    private SwitchPreference mRotation180Pref;
+    private SwitchPreference mRotation270Pref;
+
+    public static final int ROTATION_0_MODE = 1;
+    public static final int ROTATION_90_MODE = 2;
+    public static final int ROTATION_180_MODE = 4;
+    public static final int ROTATION_270_MODE = 8;
+
+    private ContentObserver mAccelerometerRotationObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            updateAccelerometerRotationSwitch();
+        }
+    };
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.VIEW_UNKNOWN;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        addPreferencesFromResource(R.xml.display_rotation);
+
+        mAccelerometer = findPreference(KEY_ACCELEROMETER);
+        mAccelerometer.setPersistent(false);
+
+        mRotation0Pref = findPreference(ROTATION_0_PREF);
+        mRotation90Pref = findPreference(ROTATION_90_PREF);
+        mRotation180Pref = findPreference(ROTATION_180_PREF);
+        mRotation270Pref = findPreference(ROTATION_270_PREF);
+
+        int mode = Settings.System.getIntForUser(getContentResolver(),
+                        Settings.System.ACCELEROMETER_ROTATION_ANGLES,
+                        ROTATION_0_MODE|ROTATION_90_MODE|ROTATION_270_MODE, UserHandle.USER_CURRENT);
+
+        mRotation0Pref.setChecked((mode & ROTATION_0_MODE) != 0);
+        mRotation90Pref.setChecked((mode & ROTATION_90_MODE) != 0);
+        mRotation180Pref.setChecked((mode & ROTATION_180_MODE) != 0);
+        mRotation270Pref.setChecked((mode & ROTATION_270_MODE) != 0);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateState();
+
+        getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), true,
+                mAccelerometerRotationObserver);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        getContentResolver().unregisterContentObserver(mAccelerometerRotationObserver);
+    }
+
+    private void updateState() {
+        updateAccelerometerRotationSwitch();
+    }
+
+    private void updateAccelerometerRotationSwitch() {
+        mAccelerometer.setChecked(!RotationPolicy.isRotationLocked(getActivity()));
+    }
+
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        return false;
+    }
+
+    public boolean onPreferenceTreeClick(Preference preference) {
+        if (preference == mAccelerometer) {
+            RotationPolicy.setRotationLockForAccessibility(getActivity(),
+                !mAccelerometer.isChecked(), /* caller= */ "DisplayRotation");
+        } else if (preference == mRotation0Pref ||
+                preference == mRotation90Pref ||
+                preference == mRotation180Pref ||
+                preference == mRotation270Pref) {
+            int mode = 0;
+            if (mRotation0Pref.isChecked())
+                mode |= ROTATION_0_MODE;
+            if (mRotation90Pref.isChecked())
+                mode |= ROTATION_90_MODE;
+            if (mRotation180Pref.isChecked())
+                mode |= ROTATION_180_MODE;
+            if (mRotation270Pref.isChecked())
+                mode |= ROTATION_270_MODE;
+            if (mode == 0) {
+                mode |= ROTATION_0_MODE;
+                mRotation0Pref.setChecked(true);
+            }
+            Settings.System.putIntForUser(getActivity().getApplicationContext().getContentResolver(),
+                    Settings.System.ACCELEROMETER_ROTATION_ANGLES, mode, UserHandle.USER_CURRENT);
+            return true;
+        }
+        return super.onPreferenceTreeClick(preference);
+    }
+}
diff --git a/src/com/android/settings/display/DisplayRotationPreferenceController.java b/src/com/android/settings/display/DisplayRotationPreferenceController.java
new file mode 100644
index 0000000..31713b7
--- /dev/null
+++ b/src/com/android/settings/display/DisplayRotationPreferenceController.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source 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.display;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+
+import com.android.internal.view.RotationPolicy;
+
+import com.android.settings.R;
+
+public class DisplayRotationPreferenceController extends BasePreferenceController implements
+        PreferenceControllerMixin {
+
+    public DisplayRotationPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        String summary = RotationPolicy.isRotationLocked(mContext) ?
+                            mContext.getString(R.string.display_rotation_disabled) :
+                            mContext.getString(R.string.display_rotation_enabled);
+        preference.setSummary(summary);
+    }
+}
diff --git a/src/com/android/settings/display/LineageDozePreferenceController.java b/src/com/android/settings/display/LineageDozePreferenceController.java
new file mode 100644
index 0000000..6c69e29
--- /dev/null
+++ b/src/com/android/settings/display/LineageDozePreferenceController.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The LeafOS 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.display;
+
+import android.content.Context;
+
+import com.android.settings.core.BasePreferenceController;
+
+import org.leafos.settings.util.PackageManagerUtils;
+
+public class LineageDozePreferenceController extends BasePreferenceController {
+
+    public LineageDozePreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return PackageManagerUtils.isCustomDozePresent(mContext.getPackageManager()) ?
+                AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return "";
+    }
+}
diff --git a/src/com/android/settings/display/MinRefreshRatePreferenceController.java b/src/com/android/settings/display/MinRefreshRatePreferenceController.java
new file mode 100644
index 0000000..caaf11b
--- /dev/null
+++ b/src/com/android/settings/display/MinRefreshRatePreferenceController.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.settings.display;
+
+import static android.provider.Settings.System.MIN_REFRESH_RATE;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.view.Display;
+
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class MinRefreshRatePreferenceController extends BasePreferenceController
+        implements Preference.OnPreferenceChangeListener {
+
+    private static final String KEY_MIN_REFRESH_RATE = "min_refresh_rate";
+
+    private ListPreference mListPreference;
+
+    private List<String> mEntries = new ArrayList<>();
+    private List<String> mValues = new ArrayList<>();
+
+    public MinRefreshRatePreferenceController(Context context) {
+        super(context, KEY_MIN_REFRESH_RATE);
+
+        if (mContext.getResources().getBoolean(R.bool.config_show_min_refresh_rate_switch)) {
+            Display.Mode mode = mContext.getDisplay().getMode();
+            Display.Mode[] modes = mContext.getDisplay().getSupportedModes();
+            for (Display.Mode m : modes) {
+                if (m.getPhysicalWidth() == mode.getPhysicalWidth() &&
+                        m.getPhysicalHeight() == mode.getPhysicalHeight()) {
+                    mEntries.add(String.format("%.02fHz", m.getRefreshRate())
+                            .replaceAll("[\\.,]00", ""));
+                    mValues.add(String.format(Locale.US, "%.02f", m.getRefreshRate()));
+                }
+            }
+        }
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return mEntries.size() > 1 ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_MIN_REFRESH_RATE;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        mListPreference = screen.findPreference(getPreferenceKey());
+        mListPreference.setEntries(mEntries.toArray(new String[mEntries.size()]));
+        mListPreference.setEntryValues(mValues.toArray(new String[mValues.size()]));
+
+        super.displayPreference(screen);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        final float currentValue = Settings.System.getFloat(mContext.getContentResolver(),
+                MIN_REFRESH_RATE, 60.00f);
+        int index = mListPreference.findIndexOfValue(
+                String.format(Locale.US, "%.02f", currentValue));
+        if (index < 0) index = 0;
+        mListPreference.setValueIndex(index);
+        mListPreference.setSummary(mListPreference.getEntries()[index]);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        Settings.System.putFloat(mContext.getContentResolver(), MIN_REFRESH_RATE,
+                Float.valueOf((String) newValue));
+        updateState(preference);
+        return true;
+    }
+
+}
diff --git a/src/com/android/settings/display/PeakRefreshRateListPreferenceController.java b/src/com/android/settings/display/PeakRefreshRateListPreferenceController.java
new file mode 100644
index 0000000..e4f4a07
--- /dev/null
+++ b/src/com/android/settings/display/PeakRefreshRateListPreferenceController.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 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.
+ */
+
+package com.android.settings.display;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Display;
+
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+import java.util.List;
+import java.util.Locale;
+
+public class PeakRefreshRateListPreferenceController extends BasePreferenceController
+        implements LifecycleObserver, OnStart, OnStop, Preference.OnPreferenceChangeListener {
+
+    private static float DEFAULT_REFRESH_RATE = 60f;
+
+    private static final String TAG = "PeakRefreshRatePrefCtr";
+    private static final float INVALIDATE_REFRESH_RATE = -1f;
+
+    private final Handler mHandler;
+    private final IDeviceConfigChange mOnDeviceConfigChange;
+    private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
+    private ListPreference mListPreference;
+
+    private List<String> mEntries = new ArrayList<>();
+    private List<String> mValues = new ArrayList<>();
+
+    private interface IDeviceConfigChange {
+        void onDefaultRefreshRateChanged();
+    }
+
+    public PeakRefreshRateListPreferenceController(Context context, String key) {
+        super(context, key);
+        mHandler = new Handler(context.getMainLooper());
+        mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
+        mOnDeviceConfigChange =
+                new IDeviceConfigChange() {
+                    public void onDefaultRefreshRateChanged() {
+                        updateState(mListPreference);
+                    }
+                };
+
+        final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
+        final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
+
+        if (display == null) {
+            Log.w(TAG, "No valid default display device");
+        } else {
+            Display.Mode mode = display.getMode();
+            Display.Mode[] modes = display.getSupportedModes();
+            for (Display.Mode m : modes) {
+                if (m.getPhysicalWidth() == mode.getPhysicalWidth() &&
+                        m.getPhysicalHeight() == mode.getPhysicalHeight()) {
+                    mEntries.add(String.format("%.02fHz", m.getRefreshRate())
+                            .replaceAll("[\\.,]00", ""));
+                    mValues.add(String.format(Locale.US, "%.02f", m.getRefreshRate()));
+                }
+            }
+        }
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        mListPreference = screen.findPreference(getPreferenceKey());
+        mListPreference.setEntries(mEntries.toArray(new String[mEntries.size()]));
+        mListPreference.setEntryValues(mValues.toArray(new String[mValues.size()]));
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (mContext.getResources().getBoolean(R.bool.config_show_peak_refresh_rate_switch)) {
+            return AVAILABLE;
+        } else {
+            return UNSUPPORTED_ON_DEVICE;
+        }
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        final float currentValue = Settings.System.getFloat(mContext.getContentResolver(),
+                Settings.System.PEAK_REFRESH_RATE, getDefaultPeakRefreshRate());
+        int index = mListPreference.findIndexOfValue(
+                String.format(Locale.US, "%.02f", currentValue));
+        if (index < 0) index = 0;
+        mListPreference.setValueIndex(index);
+        mListPreference.setSummary(mListPreference.getEntries()[index]);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        Settings.System.putFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE,
+                Float.valueOf((String) newValue));
+        updateState(preference);
+        return true;
+    }
+
+    @Override
+    public void onStart() {
+        mDeviceConfigDisplaySettings.startListening();
+    }
+
+    @Override
+    public void onStop() {
+        mDeviceConfigDisplaySettings.stopListening();
+    }
+
+    private float findPeakRefreshRate(Display.Mode[] modes) {
+        float peakRefreshRate = DEFAULT_REFRESH_RATE;
+        for (Display.Mode mode : modes) {
+            if (Math.round(mode.getRefreshRate()) > DEFAULT_REFRESH_RATE) {
+                peakRefreshRate = mode.getRefreshRate();
+            }
+        }
+        return peakRefreshRate;
+    }
+
+    private class DeviceConfigDisplaySettings
+            implements DeviceConfig.OnPropertiesChangedListener, Executor {
+        public void startListening() {
+            DeviceConfig.addOnPropertiesChangedListener(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                    this /* Executor */,
+                    this /* Listener */);
+        }
+
+        public void stopListening() {
+            DeviceConfig.removeOnPropertiesChangedListener(this);
+        }
+
+        public float getDefaultPeakRefreshRate() {
+            float defaultPeakRefreshRate =
+                    DeviceConfig.getFloat(
+                            DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                            DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT,
+                            INVALIDATE_REFRESH_RATE);
+            Log.d(TAG, "DeviceConfig getDefaultPeakRefreshRate : " + defaultPeakRefreshRate);
+
+            return defaultPeakRefreshRate;
+        }
+
+        @Override
+        public void onPropertiesChanged(DeviceConfig.Properties properties) {
+            // Got notified if any property has been changed in NAMESPACE_DISPLAY_MANAGER. The
+            // KEY_PEAK_REFRESH_RATE_DEFAULT value could be added, changed, removed or unchanged.
+            // Just force a UI update for any case.
+            if (mOnDeviceConfigChange != null) {
+                mOnDeviceConfigChange.onDefaultRefreshRateChanged();
+                updateState(mListPreference);
+            }
+        }
+
+        @Override
+        public void execute(Runnable runnable) {
+            if (mHandler != null) {
+                mHandler.post(runnable);
+            }
+        }
+    }
+
+    private float getDefaultPeakRefreshRate() {
+        float defaultPeakRefreshRate = mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate();
+        if (defaultPeakRefreshRate == INVALIDATE_REFRESH_RATE) {
+            defaultPeakRefreshRate = (float) mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_defaultPeakRefreshRate);
+        }
+
+        return defaultPeakRefreshRate;
+    }
+}
diff --git a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java
index dfe571a..6d7101a 100644
--- a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java
+++ b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java
@@ -83,6 +83,10 @@
         mPreference = screen.findPreference(getPreferenceKey());
         mPreference.setSummary(mContext.getString(
                 R.string.peak_refresh_rate_summary, defaultPeakRefreshRate));
+
+        final String summary = mContext.getString(R.string.peak_refresh_rate_summary_custom,
+                (int)mPeakRefreshRate);
+        mPreference.setSummary(summary);
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/FastChargingPreferenceController.java b/src/com/android/settings/fuelgauge/FastChargingPreferenceController.java
new file mode 100644
index 0000000..a4eea6e
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/FastChargingPreferenceController.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package com.android.settings.fuelgauge;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreferenceCompat;
+
+import com.android.settings.core.BasePreferenceController;
+
+import vendor.lineage.fastcharge.V1_0.IFastCharge;
+
+import java.util.NoSuchElementException;
+
+/**
+ * Controller to change and update the fast charging toggle
+ */
+public class FastChargingPreferenceController extends BasePreferenceController
+        implements Preference.OnPreferenceChangeListener {
+
+    private static final String KEY_FAST_CHARGING = "fast_charging";
+    private static final String TAG = "FastChargingPreferenceController";
+
+    private IFastCharge mFastCharge = null;
+
+    public FastChargingPreferenceController(Context context) {
+        super(context, KEY_FAST_CHARGING);
+        try {
+            mFastCharge = IFastCharge.getService();
+        } catch (NoSuchElementException | RemoteException e) {
+            Log.e(TAG, "Failed to get IFastCharge interface", e);
+        }
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return mFastCharge != null ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        boolean fastChargingEnabled = false;
+
+        try {
+            fastChargingEnabled = mFastCharge.isEnabled();
+        } catch (RemoteException e) {
+            Log.e(TAG, "isEnabled failed", e);
+        }
+
+        ((SwitchPreferenceCompat) preference).setChecked(fastChargingEnabled);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean shouldEnableFastCharging = (Boolean) newValue;
+
+        try {
+            mFastCharge.setEnabled(shouldEnableFastCharging);
+            updateState(preference);
+        } catch (RemoteException e) {
+            Log.e(TAG, "setEnabled failed", e);
+        }
+
+        return false;
+    }
+}
diff --git a/src/com/android/settings/gestures/BackGestureIndicatorView.java b/src/com/android/settings/gestures/BackGestureIndicatorView.java
index c60afd0..3bf40ec 100644
--- a/src/com/android/settings/gestures/BackGestureIndicatorView.java
+++ b/src/com/android/settings/gestures/BackGestureIndicatorView.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -37,6 +38,7 @@
     private ImageView mRightIndicator;
     private BackGestureIndicatorDrawable mLeftDrawable;
     private BackGestureIndicatorDrawable mRightDrawable;
+    private int mHeightScale;
 
     public BackGestureIndicatorView(Context context) {
         super(context);
@@ -87,6 +89,10 @@
         indicator.setWidth(width);
     }
 
+    public void setIndicatorHeightScale(int heightScale) {
+        mHeightScale = heightScale;
+    }
+
     public WindowManager.LayoutParams getLayoutParams(
             WindowManager.LayoutParams parentWindowAttributes) {
         int copiedFlags = (parentWindowAttributes.flags
@@ -99,8 +105,33 @@
                         | copiedFlags,
                 PixelFormat.TRANSLUCENT);
 
+        setCurrentGestureHeight(lp);
         lp.setTitle("BackGestureIndicatorView");
         lp.token = getContext().getActivityToken();
         return lp;
     }
+
+    private void setCurrentGestureHeight(WindowManager.LayoutParams lp) {
+        Point displaySize = new Point();
+        getContext().getDisplay().getRealSize(displaySize);
+
+        // mHeightScale cant be range 0 - 3
+        // 0 means full height
+        // 1 measns half of the screen
+        // 2 means lower third of the screen
+        // 3 means lower sicth of the screen
+        if (mHeightScale == 0) {
+            lp.height = displaySize.y;
+            lp.y = 0;
+        } else if (mHeightScale == 1) {
+            lp.height = displaySize.y / 2;
+            lp.y = displaySize.y - lp.height;
+        } else if (mHeightScale == 2) {
+            lp.height = displaySize.y / 3;
+            lp.y = displaySize.y - lp.height;
+        } else {
+            lp.height = displaySize.y / 6;
+            lp.y = displaySize.y - lp.height;
+        }
+    }
 }
diff --git a/src/com/android/settings/gestures/GestureNavigationSettingsFragment.java b/src/com/android/settings/gestures/GestureNavigationSettingsFragment.java
index 546581b..ad461a5 100644
--- a/src/com/android/settings/gestures/GestureNavigationSettingsFragment.java
+++ b/src/com/android/settings/gestures/GestureNavigationSettingsFragment.java
@@ -31,6 +31,8 @@
 import com.android.settings.widget.SeekBarPreference;
 import com.android.settingslib.search.SearchIndexable;
 
+import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen;
+
 /**
  * A fragment to include all the settings related to Gesture Navigation mode.
  */
@@ -44,12 +46,18 @@
 
     private static final String LEFT_EDGE_SEEKBAR_KEY = "gesture_left_back_sensitivity";
     private static final String RIGHT_EDGE_SEEKBAR_KEY = "gesture_right_back_sensitivity";
+    private static final String KEY_BACK_HEIGHT = "gesture_back_height";
+
+    private static final String NAVIGATION_BAR_HINT_KEY = "navigation_bar_hint";
 
     private WindowManager mWindowManager;
     private BackGestureIndicatorView mIndicatorView;
 
     private float[] mBackGestureInsetScales;
     private float mDefaultBackGestureInset;
+    private float[] mBackGestureHeightScales = { 0f, 1f, 2f, 3f };
+    private int mCurrentRightWidth;
+    private int mCurrentLefttWidth;
 
     public GestureNavigationSettingsFragment() {
         super();
@@ -75,6 +83,14 @@
 
         initSeekBarPreference(LEFT_EDGE_SEEKBAR_KEY);
         initSeekBarPreference(RIGHT_EDGE_SEEKBAR_KEY);
+        initSeekBarPreference(KEY_BACK_HEIGHT);
+
+        boolean isTaskbarEnabled = Settings.System.getInt(getContext().getContentResolver(),
+                Settings.System.ENABLE_TASKBAR, isLargeScreen(getContext()) ? 1 : 0) == 1;
+        if (isTaskbarEnabled) {
+            getPreferenceScreen().removePreference(
+                    getPreferenceScreen().findPreference(NAVIGATION_BAR_HINT_KEY));
+        }
     }
 
     @Override
@@ -118,11 +134,41 @@
         pref.setContinuousUpdates(true);
         pref.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_ON_TICKS);
 
-        final String settingsKey = key == LEFT_EDGE_SEEKBAR_KEY
-                ? Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT
-                : Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT;
-        final float initScale = Settings.Secure.getFloat(
-                getContext().getContentResolver(), settingsKey, 1.0f);
+        String settingsKey;
+
+        switch(key) {
+            case LEFT_EDGE_SEEKBAR_KEY:
+                settingsKey = Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT;
+                break;
+            case RIGHT_EDGE_SEEKBAR_KEY:
+                settingsKey = Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT;
+                break;
+            case KEY_BACK_HEIGHT:
+                settingsKey = Settings.System.BACK_GESTURE_HEIGHT;
+                break;
+            default:
+                settingsKey = "";
+                break;
+        }
+        float initScale = 0;
+        if (settingsKey != "") {
+            initScale = Settings.Secure.getFloat(
+                  getContext().getContentResolver(), settingsKey, 1.0f);
+        }
+
+        // needed if we just change the height
+        float currentWidthScale = Settings.Secure.getFloat(
+                getContext().getContentResolver(), Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT, 1.0f);
+        mCurrentRightWidth = (int) (mDefaultBackGestureInset * currentWidthScale);
+        currentWidthScale = Settings.Secure.getFloat(
+                getContext().getContentResolver(), Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT, 1.0f);
+        mCurrentLefttWidth = (int) (mDefaultBackGestureInset * currentWidthScale);
+
+        if (key == KEY_BACK_HEIGHT) {
+            mBackGestureInsetScales = mBackGestureHeightScales;
+            initScale = Settings.System.getInt(
+                    getContext().getContentResolver(), settingsKey, 0);
+        }
 
         // Find the closest value to initScale
         float minDistance = Float.MAX_VALUE;
@@ -137,15 +183,38 @@
         pref.setProgress(minDistanceIndex);
 
         pref.setOnPreferenceChangeListener((p, v) -> {
-            final int width = (int) (mDefaultBackGestureInset * mBackGestureInsetScales[(int) v]);
-            mIndicatorView.setIndicatorWidth(width, key == LEFT_EDGE_SEEKBAR_KEY);
+            if (key != KEY_BACK_HEIGHT) {
+                final int width = (int) (mDefaultBackGestureInset * mBackGestureInsetScales[(int) v]);
+                mIndicatorView.setIndicatorWidth(width, key == LEFT_EDGE_SEEKBAR_KEY);
+                if (key == LEFT_EDGE_SEEKBAR_KEY) {
+                    mCurrentLefttWidth = width;
+                } else {
+                    mCurrentRightWidth = width;
+                }
+            } else {
+                final int heightScale = (int) (mBackGestureInsetScales[(int) v]);
+                mIndicatorView.setIndicatorHeightScale(heightScale);
+                // dont use updateViewLayout else it will animate
+                mWindowManager.removeView(mIndicatorView);
+                mWindowManager.addView(mIndicatorView, mIndicatorView.getLayoutParams(
+                        getActivity().getWindow().getAttributes()));
+                // peek the indicators
+                mIndicatorView.setIndicatorWidth(mCurrentRightWidth, false);
+                mIndicatorView.setIndicatorWidth(mCurrentLefttWidth, true);
+            }
             return true;
         });
 
         pref.setOnPreferenceChangeStopListener((p, v) -> {
-            mIndicatorView.setIndicatorWidth(0, key == LEFT_EDGE_SEEKBAR_KEY);
             final float scale = mBackGestureInsetScales[(int) v];
-            Settings.Secure.putFloat(getContext().getContentResolver(), settingsKey, scale);
+            if (key == KEY_BACK_HEIGHT) {
+                mIndicatorView.setIndicatorWidth(0, false);
+                mIndicatorView.setIndicatorWidth(0, true);
+                Settings.System.putInt(getContext().getContentResolver(), settingsKey, (int) scale);
+            } else {
+                mIndicatorView.setIndicatorWidth(0, key == LEFT_EDGE_SEEKBAR_KEY);
+                Settings.Secure.putFloat(getContext().getContentResolver(), settingsKey, scale);
+            }
             return true;
         });
     }
@@ -168,5 +237,4 @@
                     return SystemNavigationPreferenceController.isGestureAvailable(context);
                 }
             };
-
 }
diff --git a/src/com/android/settings/gestures/GesturesSettingPreferenceController.java b/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
index e8c4b93..606bd17 100644
--- a/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
+++ b/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
@@ -60,6 +60,7 @@
                 new AmbientDisplayConfiguration(context);
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
 
+        controllers.add(new SwipeToScreenshotPreferenceController(context, FAKE_PREF_KEY));
         controllers.add(new SwipeToNotificationPreferenceController(context, FAKE_PREF_KEY));
         controllers.add(new DoubleTwistPreferenceController(context, FAKE_PREF_KEY));
         controllers.add(new DoubleTapPowerPreferenceController(context, FAKE_PREF_KEY));
diff --git a/src/com/android/settings/gestures/SwipeToScreenshotGestureSettings.java b/src/com/android/settings/gestures/SwipeToScreenshotGestureSettings.java
new file mode 100644
index 0000000..ae0f4e3
--- /dev/null
+++ b/src/com/android/settings/gestures/SwipeToScreenshotGestureSettings.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source 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.gestures;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.provider.SearchIndexableResource;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.Arrays;
+import java.util.List;
+
+@SearchIndexable
+public class SwipeToScreenshotGestureSettings extends DashboardFragment {
+
+     private static final String TAG = "SwipeToScreenshotGestureSettings";
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return -1;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.swipe_to_screenshot_gesture_settings;
+    }
+
+    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableResource> getXmlResourcesToIndex(
+                        Context context, boolean enabled) {
+                    final SearchIndexableResource sir = new SearchIndexableResource(context);
+                    sir.xmlResId = R.xml.swipe_to_screenshot_gesture_settings;
+                    return Arrays.asList(sir);
+                }
+            };
+}
diff --git a/src/com/android/settings/gestures/SwipeToScreenshotPreferenceController.java b/src/com/android/settings/gestures/SwipeToScreenshotPreferenceController.java
new file mode 100644
index 0000000..121428e
--- /dev/null
+++ b/src/com/android/settings/gestures/SwipeToScreenshotPreferenceController.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source 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.gestures;
+
+import static android.provider.Settings.System.THREE_FINGER_GESTURE;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+public class SwipeToScreenshotPreferenceController extends GesturePreferenceController {
+
+    private final int ON = 1;
+    private final int OFF = 0;
+
+    private static final String PREF_KEY_VIDEO = "swipe_to_screenshot_video";
+
+    public SwipeToScreenshotPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public boolean isSliceable() {
+        return TextUtils.equals(getPreferenceKey(), "swipe_to_screenshot");
+    }
+
+    @Override
+    protected String getVideoPrefKey() {
+        return PREF_KEY_VIDEO;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        return Settings.System.putInt(mContext.getContentResolver(), THREE_FINGER_GESTURE,
+                isChecked ? ON : OFF);
+    }
+
+    @Override
+    public boolean isChecked() {
+        return Settings.System.getInt(mContext.getContentResolver(), THREE_FINGER_GESTURE, 0) != 0;
+    }
+}
diff --git a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
index c40212b..dc58e38 100644
--- a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
+++ b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
@@ -56,6 +56,8 @@
 import com.android.settingslib.widget.IllustrationPreference;
 import com.android.settingslib.widget.SelectorWithWidgetPreference;
 
+import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -196,6 +198,9 @@
         final Context c = getContext();
         List<CandidateInfoExtra> candidates = new ArrayList<>();
 
+        boolean isTaskbarEnabled = Settings.System.getInt(getContext().getContentResolver(),
+                Settings.System.ENABLE_TASKBAR, isLargeScreen(getContext()) ? 1 : 0) == 1;
+
         if (SystemNavigationPreferenceController.isOverlayPackageAvailable(c,
                 NAV_BAR_MODE_GESTURAL_OVERLAY)) {
             candidates.add(new CandidateInfoExtra(
@@ -203,7 +208,7 @@
                     c.getText(R.string.edge_to_edge_navigation_summary),
                     KEY_SYSTEM_NAV_GESTURAL, true /* enabled */));
         }
-        if (SystemNavigationPreferenceController.isOverlayPackageAvailable(c,
+        if (!isTaskbarEnabled && SystemNavigationPreferenceController.isOverlayPackageAvailable(c,
                 NAV_BAR_MODE_2BUTTON_OVERLAY)) {
             candidates.add(new CandidateInfoExtra(
                     c.getText(R.string.swipe_up_to_switch_apps_title),
diff --git a/src/com/android/settings/lineage/CustomDialogPreference.java b/src/com/android/settings/lineage/CustomDialogPreference.java
new file mode 100644
index 0000000..5c62c41
--- /dev/null
+++ b/src/com/android/settings/lineage/CustomDialogPreference.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.lineage;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.PreferenceDialogFragmentCompat;
+import androidx.preference.DialogPreference;
+
+public class CustomDialogPreference<T extends DialogInterface> extends DialogPreference {
+
+    private CustomPreferenceDialogFragment mFragment;
+
+    public CustomDialogPreference(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public CustomDialogPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public CustomDialogPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public CustomDialogPreference(Context context) {
+        super(context);
+    }
+
+    public boolean isDialogOpen() {
+        return getDialog() != null && getDialog() instanceof Dialog && ((Dialog)getDialog()).isShowing();
+    }
+
+    public T getDialog() {
+        return (T) (mFragment != null ? mFragment.getDialog() : null);
+    }
+
+    protected void onPrepareDialogBuilder(AlertDialog.Builder builder,
+            DialogInterface.OnClickListener listener) {
+    }
+
+    protected void onDialogClosed(boolean positiveResult) {
+    }
+
+    protected void onClick(T dialog, int which) {
+    }
+
+    protected void onBindDialogView(View view) {
+    }
+
+    protected void onStart() {
+    }
+
+    protected void onStop() {
+    }
+
+    protected void onPause() {
+    }
+
+    protected void onResume() {
+    }
+
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        return null;
+    }
+
+    protected View onCreateDialogView(Context context) {
+        return null;
+    }
+
+    private void setFragment(CustomPreferenceDialogFragment fragment) {
+        mFragment = fragment;
+    }
+
+    protected boolean onDismissDialog(T dialog, int which) {
+        return true;
+    }
+
+    public static class CustomPreferenceDialogFragment extends PreferenceDialogFragmentCompat {
+
+        public static CustomPreferenceDialogFragment newInstance(String key) {
+            final CustomPreferenceDialogFragment fragment = new CustomPreferenceDialogFragment();
+            final Bundle b = new Bundle(1);
+            b.putString(ARG_KEY, key);
+            fragment.setArguments(b);
+            return fragment;
+        }
+
+        private CustomDialogPreference getCustomizablePreference() {
+            return (CustomDialogPreference) getPreference();
+        }
+
+        private class OnDismissListener implements View.OnClickListener {
+            private final int mWhich;
+            private final DialogInterface mDialog;
+
+            public OnDismissListener(DialogInterface dialog, int which) {
+                mWhich = which;
+                mDialog = dialog;
+            }
+
+            @Override
+            public void onClick(View view) {
+                CustomPreferenceDialogFragment.this.onClick(mDialog, mWhich);
+                if (getCustomizablePreference().onDismissDialog(mDialog, mWhich)) {
+                    mDialog.dismiss();
+                }
+            }
+        }
+
+        @Override
+        public void onStart() {
+            super.onStart();
+            if (getDialog() instanceof AlertDialog) {
+                AlertDialog a = (AlertDialog)getDialog();
+                if (a.getButton(Dialog.BUTTON_NEUTRAL) != null) {
+                    a.getButton(Dialog.BUTTON_NEUTRAL).setOnClickListener(
+                            new OnDismissListener(a, Dialog.BUTTON_NEUTRAL));
+                }
+                if (a.getButton(Dialog.BUTTON_POSITIVE) != null) {
+                    a.getButton(Dialog.BUTTON_POSITIVE).setOnClickListener(
+                            new OnDismissListener(a, Dialog.BUTTON_POSITIVE));
+                }
+                if (a.getButton(Dialog.BUTTON_NEGATIVE) != null) {
+                    a.getButton(Dialog.BUTTON_NEGATIVE).setOnClickListener(
+                            new OnDismissListener(a, Dialog.BUTTON_NEGATIVE));
+                }
+            }
+            getCustomizablePreference().onStart();
+        }
+
+        @Override
+        public void onStop() {
+            super.onStop();
+            getCustomizablePreference().onStop();
+        }
+
+        @Override
+        public void onPause() {
+            super.onPause();
+            getCustomizablePreference().onPause();
+        }
+
+        @Override
+        public void onResume() {
+            super.onResume();
+            getCustomizablePreference().onResume();
+        }
+
+        @Override
+        protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+            super.onPrepareDialogBuilder(builder);
+            getCustomizablePreference().setFragment(this);
+            getCustomizablePreference().onPrepareDialogBuilder(builder, this);
+        }
+
+        @Override
+        public void onDialogClosed(boolean positiveResult) {
+            getCustomizablePreference().onDialogClosed(positiveResult);
+        }
+
+        @Override
+        protected void onBindDialogView(View view) {
+            super.onBindDialogView(view);
+            getCustomizablePreference().onBindDialogView(view);
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            super.onClick(dialog, which);
+            getCustomizablePreference().onClick(dialog, which);
+        }
+
+        @NonNull
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            getCustomizablePreference().setFragment(this);
+            final Dialog sub = getCustomizablePreference().onCreateDialog(savedInstanceState);
+            if (sub == null) {
+                return super.onCreateDialog(savedInstanceState);
+            }
+            return sub;
+        }
+
+        @Override
+        protected View onCreateDialogView(Context context) {
+            final View v = getCustomizablePreference().onCreateDialogView(context);
+            if (v == null) {
+                return super.onCreateDialogView(context);
+            }
+            return v;
+        }
+    }
+}
diff --git a/src/com/android/settings/lineage/health/ChargingControlPreferenceController.java b/src/com/android/settings/lineage/health/ChargingControlPreferenceController.java
new file mode 100644
index 0000000..e41ea52
--- /dev/null
+++ b/src/com/android/settings/lineage/health/ChargingControlPreferenceController.java
@@ -0,0 +1,64 @@
+/*

+ * Copyright (C) 2022 The PixelExperience Project

+ * Copyright (C) 2023 The lineage Foundation

+ *

+ * 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.lineage.health;

+

+import android.content.Context;

+import android.os.IBinder;

+import android.os.ServiceManager;

+

+import com.android.settings.core.BasePreferenceController;

+import com.android.settings.R;

+

+public class ChargingControlPreferenceController extends BasePreferenceController {

+

+    public static final String KEY = "charging_control";

+

+    private Context mContext;

+

+    public ChargingControlPreferenceController(Context context, String key) {

+        super(context, key);

+

+        mContext = context;

+    }

+

+    public ChargingControlPreferenceController(Context context) {

+        this(context, KEY);

+

+        mContext = context;

+    }

+

+    private boolean isNegated(String key) {

+        return key != null && key.startsWith("!");

+    }

+

+    @Override

+    public int getAvailabilityStatus() {

+        String rService =  "lineagehealth";

+        boolean negated = isNegated(rService);

+        if (negated) {

+           rService = rService.substring(1);

+        }

+        IBinder value = ServiceManager.getService(rService);

+        boolean available = value != null;

+        if (available == negated) {

+            return UNSUPPORTED_ON_DEVICE;

+        }

+        return AVAILABLE;

+    }

+

+}

diff --git a/src/com/android/settings/lineage/health/ChargingControlSettings.java b/src/com/android/settings/lineage/health/ChargingControlSettings.java
new file mode 100644
index 0000000..5a4d7ef
--- /dev/null
+++ b/src/com/android/settings/lineage/health/ChargingControlSettings.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.settings.lineage.health;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+
+import androidx.fragment.app.DialogFragment;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import com.android.internal.lineage.health.HealthInterface;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+import com.android.settings.lineage.CustomDialogPreference;
+import androidx.preference.ListPreference;
+import com.android.settingslib.widget.MainSwitchPreference;
+
+import static com.android.internal.lineage.health.HealthInterface.MODE_AUTO;
+import static com.android.internal.lineage.health.HealthInterface.MODE_MANUAL;
+import static com.android.internal.lineage.health.HealthInterface.MODE_LIMIT;
+
+@SearchIndexable
+public class ChargingControlSettings extends SettingsPreferenceFragment implements
+        Preference.OnPreferenceChangeListener {
+    private static final String TAG = ChargingControlSettings.class.getSimpleName();
+
+    private static final String CHARGING_CONTROL_PREF = "charging_control";
+    private static final String CHARGING_CONTROL_ENABLED_PREF = "charging_control_enabled";
+    private static final String CHARGING_CONTROL_MODE_PREF = "charging_control_mode";
+    private static final String CHARGING_CONTROL_START_TIME_PREF = "charging_control_start_time";
+    private static final String CHARGING_CONTROL_TARGET_TIME_PREF = "charging_control_target_time";
+    private static final String CHARGING_CONTROL_LIMIT_PREF = "charging_control_charging_limit";
+
+    private MainSwitchPreference mChargingControlEnabledPref;
+    private ListPreference mChargingControlModePref;
+    private StartTimePreference mChargingControlStartTimePref;
+    private TargetTimePreference mChargingControlTargetTimePref;
+    private ChargingLimitPreference mChargingControlLimitPref;
+
+    private HealthInterface mHealthInterface;
+
+    private static final int MENU_RESET = Menu.FIRST;
+
+    @Override
+    public void onActivityCreated(final Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        final Resources res = getResources();
+
+        addPreferencesFromResource(R.xml.charging_control_settings);
+        getActivity().getActionBar().setTitle(R.string.charging_control_title);
+
+        mHealthInterface = HealthInterface.getInstance(getActivity());
+
+        final PreferenceScreen prefSet = getPreferenceScreen();
+
+        mChargingControlEnabledPref = prefSet.findPreference(CHARGING_CONTROL_ENABLED_PREF);
+        mChargingControlEnabledPref.setOnPreferenceChangeListener(this);
+        mChargingControlModePref = prefSet.findPreference(CHARGING_CONTROL_MODE_PREF);
+        mChargingControlModePref.setOnPreferenceChangeListener(this);
+        mChargingControlStartTimePref = prefSet.findPreference(CHARGING_CONTROL_START_TIME_PREF);
+        mChargingControlTargetTimePref = prefSet.findPreference(CHARGING_CONTROL_TARGET_TIME_PREF);
+        mChargingControlLimitPref = prefSet.findPreference(CHARGING_CONTROL_LIMIT_PREF);
+
+        if (mChargingControlLimitPref != null) {
+            if (mHealthInterface.allowFineGrainedSettings()) {
+                mChargingControlModePref.setEntries(concatStringArrays(
+                        mChargingControlModePref.getEntries(),
+                        res.getStringArray(
+                                R.array.charging_control_mode_entries_fine_grained_control)));
+                mChargingControlModePref.setEntryValues(concatStringArrays(
+                        mChargingControlModePref.getEntryValues(),
+                        res.getStringArray(
+                                R.array.charging_control_mode_values_fine_grained_control)));
+            }
+        }
+
+        setHasOptionsMenu(true);
+
+        refreshValues();
+
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        refreshUi();
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return -1;
+    }
+
+    @Override
+    public void onDisplayPreferenceDialog(Preference preference) {
+        if (preference.getKey() == null) {
+            // Auto-key preferences that don't have a key, so the dialog can find them.
+            preference.setKey(UUID.randomUUID().toString());
+        }
+        DialogFragment f = null;
+        if (preference instanceof CustomDialogPreference) {
+            f = CustomDialogPreference.CustomPreferenceDialogFragment
+                    .newInstance(preference.getKey());
+        } else {
+            super.onDisplayPreferenceDialog(preference);
+            return;
+        }
+        f.setTargetFragment(this, 0);
+        f.show(getFragmentManager(), "dialog_preference");
+        onDialogShowing();
+    }
+
+    private void refreshValues() {
+        if (mChargingControlEnabledPref != null) {
+            mChargingControlEnabledPref.setChecked(mHealthInterface.getEnabled());
+        }
+
+        if (mChargingControlModePref != null) {
+            final int chargingControlMode = mHealthInterface.getMode();
+            mChargingControlModePref.setValue(Integer.toString(chargingControlMode));
+            refreshUi();
+        }
+
+        if (mChargingControlStartTimePref != null) {
+            mChargingControlStartTimePref.setValue(
+                    mChargingControlStartTimePref.getTimeSetting());
+        }
+
+        if (mChargingControlTargetTimePref != null) {
+            mChargingControlTargetTimePref.setValue(
+                    mChargingControlTargetTimePref.getTimeSetting());
+        }
+
+        if (mChargingControlLimitPref != null) {
+            mChargingControlLimitPref.setValue(
+                    mChargingControlLimitPref.getSetting());
+        }
+    }
+
+    private void refreshUi() {
+        final int chargingControlMode = mHealthInterface.getMode();
+
+        refreshUi(chargingControlMode);
+    }
+
+    private void refreshUi(final int chargingControlMode) {
+        String summary = null;
+        boolean isChargingControlStartTimePrefVisible = false;
+        boolean isChargingControlTargetTimePrefVisible = false;
+        boolean isChargingControlLimitPrefVisible = false;
+
+        final Resources res = getResources();
+
+        switch (chargingControlMode) {
+            case MODE_AUTO:
+                summary = res.getString(R.string.charging_control_mode_auto_summary);
+                break;
+            case MODE_MANUAL:
+                summary = res.getString(R.string.charging_control_mode_custom_summary);
+                isChargingControlStartTimePrefVisible = true;
+                isChargingControlTargetTimePrefVisible = true;
+                break;
+            case MODE_LIMIT:
+                summary = res.getString(R.string.charging_control_mode_limit_summary);
+                isChargingControlLimitPrefVisible = true;
+                break;
+            default:
+                return;
+        }
+
+        mChargingControlModePref.setSummary(summary);
+
+        if (mChargingControlStartTimePref != null) {
+            mChargingControlStartTimePref.setVisible(isChargingControlStartTimePrefVisible);
+        }
+
+        if (mChargingControlTargetTimePref != null) {
+            mChargingControlTargetTimePref.setVisible(isChargingControlTargetTimePrefVisible);
+        }
+
+        if (mChargingControlLimitPref != null) {
+            mChargingControlLimitPref.setVisible(isChargingControlLimitPrefVisible);
+        }
+    }
+
+    @Override
+    public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
+        menu.add(0, MENU_RESET, 0, R.string.reset)
+                .setIcon(R.drawable.ic_settings_backup_restore)
+                .setAlphabeticShortcut('r')
+                .setShowAsActionFlags(
+                        MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(final MenuItem item) {
+        if (item.getItemId() == MENU_RESET) {
+            resetToDefaults();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onPreferenceChange(final Preference preference, final Object objValue) {
+        if (preference == mChargingControlEnabledPref) {
+            mHealthInterface.setEnabled((Boolean) objValue);
+        } else if (preference == mChargingControlModePref) {
+            final int chargingControlMode = Integer.parseInt((String) objValue);
+            mHealthInterface.setMode(chargingControlMode);
+            refreshUi(chargingControlMode);
+        }
+        return true;
+    }
+
+    private void resetToDefaults() {
+        mHealthInterface.reset();
+
+        refreshValues();
+    }
+
+    private CharSequence[] concatStringArrays(CharSequence[] array1, CharSequence[] array2) {
+        return Stream.concat(Arrays.stream(array1), Arrays.stream(array2)).toArray(size ->
+                (CharSequence[]) Array.newInstance(CharSequence.class, size));
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider() {
+        @Override
+        public List<String> getNonIndexableKeys(Context context) {
+            final List<String> result = new ArrayList<String>();
+            if (!HealthInterface.isChargingControlSupported(context)) {
+                result.add(CHARGING_CONTROL_PREF);
+                result.add(CHARGING_CONTROL_ENABLED_PREF);
+                result.add(CHARGING_CONTROL_MODE_PREF);
+                result.add(CHARGING_CONTROL_START_TIME_PREF);
+                result.add(CHARGING_CONTROL_TARGET_TIME_PREF);
+                result.add(CHARGING_CONTROL_LIMIT_PREF);
+            }
+            return result;
+        }
+    };
+
+}
diff --git a/src/com/android/settings/lineage/health/ChargingLimitPreference.java b/src/com/android/settings/lineage/health/ChargingLimitPreference.java
new file mode 100644
index 0000000..8577fb3
--- /dev/null
+++ b/src/com/android/settings/lineage/health/ChargingLimitPreference.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.settings.lineage.health;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.internal.lineage.health.HealthInterface;
+
+import com.android.settings.R;
+
+public class ChargingLimitPreference extends Preference
+        implements SeekBar.OnSeekBarChangeListener {
+    private static final String TAG = ChargingLimitPreference.class.getSimpleName();
+
+    private TextView mChargingLimitValue;
+    private SeekBar mChargingLimitBar;
+
+    private final HealthInterface mHealthInterface;
+
+    public ChargingLimitPreference(final Context context, final AttributeSet attrs) {
+        super(context, attrs);
+
+        setLayoutResource(R.layout.preference_charging_limit);
+
+        mHealthInterface = HealthInterface.getInstance(context);
+    }
+
+    @Override
+    public void onBindViewHolder(final PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        mChargingLimitValue = (TextView) holder.findViewById(R.id.value);
+
+        mChargingLimitBar = (SeekBar) holder.findViewById(R.id.seekbar_widget);
+        mChargingLimitBar.setOnSeekBarChangeListener(this);
+
+        int currLimit = getSetting();
+        mChargingLimitBar.setProgress(currLimit);
+        updateValue(currLimit);
+    }
+
+    @Override
+    public void onStartTrackingTouch(final SeekBar seekBar) {
+    }
+
+    @Override
+    public void onStopTrackingTouch(final SeekBar seekBar) {
+        setSetting(seekBar.getProgress());
+    }
+
+    @Override
+    public void onProgressChanged(final SeekBar seekBar, final int progress,
+            final boolean fromUser) {
+        updateValue(progress);
+    }
+
+    public void setValue(final int value) {
+        if (mChargingLimitBar != null) {
+            mChargingLimitBar.setProgress(value);
+        }
+        updateValue(value);
+    }
+
+    protected int getSetting() {
+        return mHealthInterface.getLimit();
+    }
+
+    protected void setSetting(final int chargingLimit) {
+        mHealthInterface.setLimit(chargingLimit);
+    }
+
+    private void updateValue(final int value) {
+        if (mChargingLimitValue != null) {
+            mChargingLimitValue.setText(String.format("%d%%", value));
+        }
+    }
+}
diff --git a/src/com/android/settings/lineage/health/StartTimePreference.java b/src/com/android/settings/lineage/health/StartTimePreference.java
new file mode 100644
index 0000000..6d12c665
--- /dev/null
+++ b/src/com/android/settings/lineage/health/StartTimePreference.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.settings.lineage.health;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.settings.R;
+
+public class StartTimePreference extends TimePreference {
+    private static final String TAG = StartTimePreference.class.getSimpleName();
+
+    public StartTimePreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected int getSummaryResourceId() {
+        return R.string.charging_control_start_time_summary;
+    }
+
+    @Override
+    protected int getTimeSetting() {
+        return mHealthInterface.getStartTime();
+    }
+
+    @Override
+    protected void setTimeSetting(int secondOfDay) {
+        mHealthInterface.setStartTime(secondOfDay);
+    }
+}
diff --git a/src/com/android/settings/lineage/health/TargetTimePreference.java b/src/com/android/settings/lineage/health/TargetTimePreference.java
new file mode 100644
index 0000000..87351e4
--- /dev/null
+++ b/src/com/android/settings/lineage/health/TargetTimePreference.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.settings.lineage.health;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.settings.R;
+
+public class TargetTimePreference extends TimePreference {
+    private static final String TAG = TargetTimePreference.class.getSimpleName();
+
+    public TargetTimePreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected int getSummaryResourceId() {
+        return R.string.charging_control_target_time_summary;
+    }
+
+    @Override
+    protected int getTimeSetting() {
+        return mHealthInterface.getTargetTime();
+    }
+
+    @Override
+    protected void setTimeSetting(int secondOfDay) {
+        mHealthInterface.setTargetTime(secondOfDay);
+    }
+}
diff --git a/src/com/android/settings/lineage/health/TimePreference.java b/src/com/android/settings/lineage/health/TimePreference.java
new file mode 100644
index 0000000..aae2d7c
--- /dev/null
+++ b/src/com/android/settings/lineage/health/TimePreference.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.settings.lineage.health;
+
+import static java.time.format.FormatStyle.SHORT;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TimePicker;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.lineage.CustomDialogPreference;
+import com.android.settings.R;
+
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+import com.android.internal.lineage.health.HealthInterface;
+
+public abstract class TimePreference extends CustomDialogPreference<AlertDialog> {
+    private static final String TAG = TimePreference.class.getSimpleName();
+    private static final DateTimeFormatter mFormatter = DateTimeFormatter.ofLocalizedTime(SHORT);
+
+    private TimePicker mTimePicker;
+    private LocalTime mLocalTime;
+
+    protected HealthInterface mHealthInterface;
+
+    public TimePreference(final Context context, final AttributeSet attrs) {
+        super(context, attrs);
+
+        setDialogLayoutResource(R.layout.dialog_time);
+        mHealthInterface = HealthInterface.getInstance(context);
+    }
+
+    @Override
+    public void onBindViewHolder(final PreferenceViewHolder holder) {
+        mLocalTime = LocalTime.ofSecondOfDay(getTimeSetting());
+        super.onBindViewHolder(holder);
+    }
+
+    @Override
+    protected void onPrepareDialogBuilder(final AlertDialog.Builder builder,
+            final DialogInterface.OnClickListener listener) {
+        super.onPrepareDialogBuilder(builder, listener);
+
+        builder.setNegativeButton(R.string.cancel, null);
+        builder.setPositiveButton(R.string.dlg_ok, null);
+    }
+
+    @Override
+    protected void onDialogClosed(final boolean positiveResult) {
+        super.onDialogClosed(positiveResult);
+
+        if (positiveResult) {
+            mLocalTime = LocalTime.of(mTimePicker.getHour(),
+                    mTimePicker.getMinute());
+            setTimeSetting(mLocalTime.toSecondOfDay());
+            setSummary(getSummary());
+        }
+    }
+
+    @Override
+    protected void onBindDialogView(View view) {
+        super.onBindDialogView(view);
+
+        mTimePicker = view.findViewById(R.id.time_picker);
+        mTimePicker.setHour(mLocalTime.getHour());
+        mTimePicker.setMinute(mLocalTime.getMinute());
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return String.format(getContext().getString(getSummaryResourceId()),
+                mLocalTime.format(mFormatter));
+    }
+
+    public void setValue(final int value) {
+        mLocalTime = LocalTime.ofSecondOfDay(value);
+        setSummary(getSummary());
+    }
+
+    protected abstract int getSummaryResourceId();
+
+    protected abstract int getTimeSetting();
+
+    protected abstract void setTimeSetting(int secondOfDay);
+}
diff --git a/src/com/android/settings/location/AgpsPreferenceController.java b/src/com/android/settings/location/AgpsPreferenceController.java
new file mode 100755
index 0000000..0b0bb73
--- /dev/null
+++ b/src/com/android/settings/location/AgpsPreferenceController.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.location;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.SwitchPreferenceCompat;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+public class AgpsPreferenceController extends LocationBasePreferenceController {
+    private static final String KEY_ASSISTED_GPS = "assisted_gps";
+
+    private SwitchPreferenceCompat mAgpsPreference;
+
+    public AgpsPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_ASSISTED_GPS;
+    }
+
+    @AvailabilityStatus
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mAgpsPreference = (SwitchPreferenceCompat) screen.findPreference(KEY_ASSISTED_GPS);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        if (mAgpsPreference != null) {
+            mAgpsPreference.setChecked(Settings.Global.getInt(
+                    mContext.getContentResolver(), Settings.Global.ASSISTED_GPS_ENABLED, 1) == 1);
+        }
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (KEY_ASSISTED_GPS.equals(preference.getKey())) {
+            final ContentResolver cr = mContext.getContentResolver();
+            final boolean switchState = mAgpsPreference.isChecked();
+            Settings.Global.putInt(cr, Settings.Global.ASSISTED_GPS_ENABLED,
+                    switchState ? 1 : 0);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onLocationModeChanged(int mode, boolean restricted) {}
+}
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index ff8b4be..aac19a7 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -109,6 +109,7 @@
         use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this);
         use(LocationForWorkPreferenceController.class).init(this);
         use(LocationSettingsFooterPreferenceController.class).init(this);
+        use(AgpsPreferenceController.class).init(this);
     }
 
     @Override
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index f14c32c..acde54c 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -36,16 +36,19 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Log;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
@@ -66,6 +69,7 @@
 import com.android.settings.datausage.DataUsagePreference;
 import com.android.settings.datausage.DataUsageUtils;
 import com.android.settings.location.WifiScanningFragment;
+import com.android.settings.network.MobileDataEnabledListener;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.wifi.AddNetworkFragment;
 import com.android.settings.wifi.AddWifiNetworkPreference;
@@ -93,6 +97,10 @@
 import com.android.wifitrackerlib.WifiEntry.ConnectCallback;
 import com.android.wifitrackerlib.WifiPickerTracker;
 
+import com.google.android.setupcompat.template.FooterButtonStyleUtils;
+import com.google.android.setupcompat.util.WizardManagerHelper;
+import com.google.android.setupdesign.GlifPreferenceLayout;
+
 import java.util.List;
 import java.util.Optional;
 
@@ -105,7 +113,8 @@
 public class NetworkProviderSettings extends RestrictedSettingsFragment
         implements Indexable, WifiPickerTracker.WifiPickerTrackerCallback,
         WifiDialog2.WifiDialog2Listener, DialogInterface.OnDismissListener,
-        AirplaneModeEnabler.OnAirplaneModeChangedListener, InternetUpdater.InternetChangeListener {
+        AirplaneModeEnabler.OnAirplaneModeChangedListener, InternetUpdater.InternetChangeListener,
+        MobileDataEnabledListener.Client {
 
     public static final String ACTION_NETWORK_PROVIDER_SETTINGS =
             "android.settings.NETWORK_PROVIDER_SETTINGS";
@@ -168,6 +177,8 @@
     // Enable the Next button when a Wi-Fi network is connected.
     private boolean mEnableNextOnConnection;
 
+    private boolean mIsInSetupWizard;
+
     // This string extra specifies a network to open the connect dialog on, so the user can enter
     // network credentials.  This is used by quick settings for secured networks, among other
     // things.
@@ -199,6 +210,9 @@
     protected WifiManager mWifiManager;
     private WifiManager.ActionListener mSaveListener;
 
+    int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    MobileDataEnabledListener mDataStateListener;
+
     protected InternetResetHelper mInternetResetHelper;
 
     /**
@@ -262,6 +276,7 @@
 
     public NetworkProviderSettings() {
         super(DISALLOW_CONFIG_WIFI);
+        mSubId = SubscriptionManager.getActiveDataSubscriptionId();
     }
 
     @Override
@@ -272,6 +287,18 @@
             return;
         }
 
+        if (mIsInSetupWizard) {
+            GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
+            layout.setDividerInsets(Integer.MAX_VALUE, 0);
+
+            layout.setIcon(getContext().getDrawable(R.drawable.ic_network_setup));
+            layout.setHeaderText(R.string.provider_internet_settings);
+            FooterButtonStyleUtils.applyPrimaryButtonPartnerResource(activity, getNextButton(),
+                    true);
+
+            return;
+        }
+
         setPinnedHeaderView(com.android.settingslib.widget.progressbar.R.layout.progress_header);
         setProgressBarVisible(false);
 
@@ -295,6 +322,7 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         mAirplaneModeEnabler = new AirplaneModeEnabler(getContext(), this);
+        mDataStateListener = new MobileDataEnabledListener(getContext(), this);
 
         // TODO(b/37429702): Add animations and preference comparator back after initial screen is
         // loaded (ODR).
@@ -342,6 +370,8 @@
                 fixConnectivityItem.setVisible(!mIsGuest && (!isAirplaneModeOn || isWifiEnabled));
             }
         };
+        final Intent intent = this.getIntent();
+        mIsInSetupWizard = WizardManagerHelper.isAnySetupWizard(intent);
     }
 
     private void updateUserType() {
@@ -351,6 +381,17 @@
         mIsGuest = userManager.isGuestUser();
     }
 
+    @Override
+    public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
+            Bundle savedInstanceState) {
+        if (mIsInSetupWizard) {
+            GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
+            return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
+        } else {
+            return super.onCreateRecyclerView(inflater, parent, savedInstanceState);
+        }
+    }
+
     private void addPreferences() {
         addPreferencesFromResource(R.xml.network_provider_settings);
 
@@ -462,6 +503,11 @@
             }
         };
 
+        if (mIsInSetupWizard) {
+            mConfigureWifiSettingsPreference.setVisible(false);
+            mDataUsagePreference.setVisible(false);
+        }
+
         if (savedInstanceState != null) {
             mDialogMode = savedInstanceState.getInt(SAVE_DIALOG_MODE);
             mDialogWifiEntryKey = savedInstanceState.getString(SAVE_DIALOG_WIFIENTRY_KEY);
@@ -501,6 +547,7 @@
             return;
         }
         mAirplaneModeEnabler.start();
+        mDataStateListener.start(mSubId);
     }
 
     private void restrictUi() {
@@ -529,7 +576,8 @@
         }
 
         changeNextButtonState(mWifiPickerTracker != null
-                && mWifiPickerTracker.getConnectedWifiEntry() != null);
+                && mWifiPickerTracker.getConnectedWifiEntry() != null
+                || getDataEnabled());
     }
 
     @Override
@@ -538,6 +586,7 @@
         getView().removeCallbacks(mUpdateWifiEntryPreferencesRunnable);
         getView().removeCallbacks(mHideProgressBarRunnable);
         mAirplaneModeEnabler.stop();
+        mDataStateListener.stop();
         super.onStop();
     }
 
@@ -916,7 +965,8 @@
             setProgressBarVisible(false);
         }
         changeNextButtonState(mWifiPickerTracker != null
-                && mWifiPickerTracker.getConnectedWifiEntry() != null);
+                && mWifiPickerTracker.getConnectedWifiEntry() != null
+                || getDataEnabled());
 
         // Edit the Wi-Fi network of specified SSID.
         if (mOpenSsid != null && mWifiPickerTracker != null) {
@@ -991,7 +1041,9 @@
 
                 if (mClickedConnect) {
                     mClickedConnect = false;
-                    scrollToPreference(connectedWifiPreferenceCategory);
+                    if (!mIsInSetupWizard) {
+                        scrollToPreference(connectedWifiPreferenceCategory);
+                    }
                 }
             }
         } else {
@@ -1112,10 +1164,12 @@
 
     @VisibleForTesting
     void setAdditionalSettingsSummaries() {
-        mConfigureWifiSettingsPreference.setSummary(getString(
-                isWifiWakeupEnabled()
-                        ? R.string.wifi_configure_settings_preference_summary_wakeup_on
-                        : R.string.wifi_configure_settings_preference_summary_wakeup_off));
+        if (!mIsInSetupWizard) {
+            mConfigureWifiSettingsPreference.setSummary(getString(
+                    isWifiWakeupEnabled()
+                            ? R.string.wifi_configure_settings_preference_summary_wakeup_on
+                            : R.string.wifi_configure_settings_preference_summary_wakeup_off));
+        }
 
         final int numSavedNetworks = mWifiPickerTracker == null ? 0 :
                 mWifiPickerTracker.getNumSavedNetworks();
@@ -1163,7 +1217,9 @@
     }
 
     protected void setProgressBarVisible(boolean visible) {
-        showPinnedHeader(visible);
+        if (!mIsInSetupWizard) {
+            showPinnedHeader(visible);
+        }
     }
 
     @VisibleForTesting
@@ -1197,7 +1253,7 @@
      * Renames/replaces "Next" button when appropriate. "Next" button usually exists in
      * Wi-Fi setup screens, not in usual wifi settings screen.
      *
-     * @param enabled true when the device is connected to a wifi network.
+     * @param enabled true when the device is connected to a mobile or wifi network.
      */
     @VisibleForTesting
     void changeNextButtonState(boolean enabled) {
@@ -1467,6 +1523,17 @@
     }
 
     /**
+     * Implementation of {@code MobileDataEnabledListener.Client}
+     */
+    public void onMobileDataEnabledChange() {
+        changeNextButtonState(getDataEnabled());
+    }
+
+    boolean getDataEnabled() {
+        return getContext().getSystemService(TelephonyManager.class).getDataEnabled(mSubId);
+    }
+
+    /**
      * A Wi-Fi preference for the connected Wi-Fi network without internet access.
      *
      * Override the icon color attribute by {@link ConnectedWifiEntryPreference#getIconColorAttr()}
diff --git a/src/com/android/settings/network/NetworkSetupActivity.java b/src/com/android/settings/network/NetworkSetupActivity.java
new file mode 100644
index 0000000..3b5fb82
--- /dev/null
+++ b/src/com/android/settings/network/NetworkSetupActivity.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2021-2024 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.
+ */
+package com.android.settings.network;
+
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+
+import androidx.preference.PreferenceFragmentCompat;
+
+import com.android.settings.ButtonBarHandler;
+import com.android.settings.network.NetworkProviderSettings;
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.SetupWizardUtils;
+import com.android.settings.wifi.p2p.WifiP2pSettings;
+import com.android.settings.wifi.savedaccesspoints2.SavedAccessPointsWifiSettings2;
+
+import com.google.android.setupdesign.util.ThemeHelper;
+
+public class NetworkSetupActivity extends SettingsActivity implements ButtonBarHandler {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setTheme(SetupWizardUtils.getTheme(this, getIntent()));
+        setTheme(R.style.SettingsPreferenceTheme_SetupWizard);
+        ThemeHelper.trySetDynamicColor(this);
+        findViewById(R.id.content_parent).setFitsSystemWindows(false);
+    }
+
+    @Override
+    public Intent getIntent() {
+        Intent modIntent = new Intent(super.getIntent());
+        if (!modIntent.hasExtra(EXTRA_SHOW_FRAGMENT)) {
+            modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getNetworkProviderSettingsClass().getName());
+            modIntent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID,
+                    R.string.provider_internet_settings);
+        }
+        return modIntent;
+    }
+
+    @Override
+    protected boolean isValidFragment(String fragmentName) {
+        final boolean isSavedAccessPointsWifiSettings =
+                SavedAccessPointsWifiSettings2.class.getName().equals(fragmentName);
+
+        if (NetworkProviderSettings.class.getName().equals(fragmentName)
+                || WifiP2pSettings.class.getName().equals(fragmentName)
+                || isSavedAccessPointsWifiSettings) {
+            return true;
+        }
+        return false;
+    }
+
+    /* package */ Class<? extends PreferenceFragmentCompat> getNetworkProviderSettingsClass() {
+        return NetworkProviderSettings.class;
+    }
+}
diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
index 06015d4..6d74a5c 100644
--- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
+++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
@@ -20,6 +20,7 @@
 import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.content.Context;
+import android.provider.Settings;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -40,6 +41,8 @@
 import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
 import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
 
+import com.google.android.setupcompat.util.WizardManagerHelper;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -121,6 +124,14 @@
     public boolean setChecked(boolean isChecked) {
         mNeedDialog = isDialogNeeded();
 
+        // If we are still provisioning we need to allow enabling mobile data first.
+        // By default it is not allowed to use mobile network during provisioning so
+        // we need to allow it.
+        if (!WizardManagerHelper.isDeviceProvisioned(mContext)) {
+            Settings.Global.putInt(mContext.getContentResolver(),
+                    Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, isChecked ? 1 : 0);
+        }
+
         if (!mNeedDialog) {
             // Update data directly if we don't need dialog
             MobileNetworkUtils.setMobileDataEnabled(mContext, mSubId, isChecked, false);
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;
     }
 
diff --git a/src/com/android/settings/privacy/AdBlockPreferenceController.java b/src/com/android/settings/privacy/AdBlockPreferenceController.java
new file mode 100644
index 0000000..0de5ab8
--- /dev/null
+++ b/src/com/android/settings/privacy/AdBlockPreferenceController.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2023 The LeafOS 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.privacy;
+
+import android.content.Context;
+import android.os.SystemProperties;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+public class AdBlockPreferenceController extends TogglePreferenceController implements
+        Preference.OnPreferenceChangeListener {
+
+    private static final String PROP_ADBLOCK_ENABLED = "persist.sys.adblock_enabled";
+    private static final String PROP_ADBLOCK_STATUS = "sys.adblock_status";
+
+    private SwitchPreference mPreference;
+
+    public AdBlockPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        mPreference = (SwitchPreference)preference;
+        super.updateState(preference);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public boolean isSliceable() {
+        return mPreference != null;
+    }
+
+    @Override
+    public boolean isPublicSlice() {
+        return true;
+    }
+
+    @Override
+    public int getSliceHighlightMenuRes() {
+        return R.string.menu_key_display;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return SystemProperties.getBoolean(PROP_ADBLOCK_ENABLED, false);
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        if (!isChecked) {
+            SystemProperties.set(PROP_ADBLOCK_STATUS, "stopped");
+        }
+        SystemProperties.set(PROP_ADBLOCK_ENABLED, isChecked ? "true" : "false");
+        return true;
+    }
+}
diff --git a/src/com/android/settings/security/screenlock/AbstractPatternSwitchPreferenceController.java b/src/com/android/settings/security/screenlock/AbstractPatternSwitchPreferenceController.java
new file mode 100644
index 0000000..e2102aa
--- /dev/null
+++ b/src/com/android/settings/security/screenlock/AbstractPatternSwitchPreferenceController.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source 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.security.screenlock;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+import androidx.preference.TwoStatePreference;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+public abstract class AbstractPatternSwitchPreferenceController
+        extends AbstractPreferenceController
+        implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
+
+    private final String mKey;
+    private final int mUserId;
+    private final LockPatternUtils mLockPatternUtils;
+
+    public AbstractPatternSwitchPreferenceController(Context context, String key,
+            int userId, LockPatternUtils lockPatternUtils) {
+        super(context);
+        mKey = key;
+        mUserId = userId;
+        mLockPatternUtils = lockPatternUtils;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return isPatternLock();
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return mKey;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        ((TwoStatePreference) preference).setChecked(isEnabled(mLockPatternUtils, mUserId));
+    }
+
+    private boolean isPatternLock() {
+        return mLockPatternUtils.getCredentialTypeForUser(mUserId)
+                == LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        setEnabled(mLockPatternUtils, mUserId, (Boolean) newValue);
+        return true;
+    }
+
+    protected abstract boolean isEnabled(LockPatternUtils utils, int userId);
+    protected abstract void setEnabled(LockPatternUtils utils, int userId, boolean enabled);
+}
diff --git a/src/com/android/settings/security/screenlock/PatternDotsVisiblePreferenceController.java b/src/com/android/settings/security/screenlock/PatternDotsVisiblePreferenceController.java
new file mode 100644
index 0000000..8da044d
--- /dev/null
+++ b/src/com/android/settings/security/screenlock/PatternDotsVisiblePreferenceController.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source 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.security.screenlock;
+
+import android.content.Context;
+
+import com.android.internal.widget.LockPatternUtils;
+
+public class PatternDotsVisiblePreferenceController
+        extends AbstractPatternSwitchPreferenceController {
+    private static final String PREF_KEY = "visibledots";
+
+    public PatternDotsVisiblePreferenceController(Context context, int userId,
+            LockPatternUtils lockPatternUtils) {
+        super(context, PREF_KEY, userId, lockPatternUtils);
+    }
+
+    @Override
+    protected boolean isEnabled(LockPatternUtils utils, int userId) {
+        return utils.isVisibleDotsEnabled(userId);
+    }
+
+    @Override
+    protected void setEnabled(LockPatternUtils utils, int userId, boolean enabled) {
+        utils.setVisibleDotsEnabled(enabled, userId);
+    }
+}
diff --git a/src/com/android/settings/security/screenlock/PatternErrorVisiblePreferenceController.java b/src/com/android/settings/security/screenlock/PatternErrorVisiblePreferenceController.java
new file mode 100644
index 0000000..b9a18c1
--- /dev/null
+++ b/src/com/android/settings/security/screenlock/PatternErrorVisiblePreferenceController.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source 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.security.screenlock;
+
+import android.content.Context;
+
+import com.android.internal.widget.LockPatternUtils;
+
+public class PatternErrorVisiblePreferenceController
+        extends AbstractPatternSwitchPreferenceController {
+    private static final String PREF_KEY = "visible_error_pattern";
+
+    public PatternErrorVisiblePreferenceController(Context context, int userId,
+            LockPatternUtils lockPatternUtils) {
+        super(context, PREF_KEY, userId, lockPatternUtils);
+    }
+
+    @Override
+    protected boolean isEnabled(LockPatternUtils utils, int userId) {
+        return utils.isShowErrorPath(userId);
+    }
+
+    @Override
+    protected void setEnabled(LockPatternUtils utils, int userId, boolean enabled) {
+        utils.setShowErrorPath(enabled, userId);
+    }
+}
diff --git a/src/com/android/settings/security/screenlock/PatternVisiblePreferenceController.java b/src/com/android/settings/security/screenlock/PatternVisiblePreferenceController.java
index ea3403b..2f8b641 100644
--- a/src/com/android/settings/security/screenlock/PatternVisiblePreferenceController.java
+++ b/src/com/android/settings/security/screenlock/PatternVisiblePreferenceController.java
@@ -18,52 +18,23 @@
 
 import android.content.Context;
 
-import androidx.preference.Preference;
-import androidx.preference.TwoStatePreference;
-
 import com.android.internal.widget.LockPatternUtils;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
 
-public class PatternVisiblePreferenceController extends AbstractPreferenceController
-        implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
-
+public class PatternVisiblePreferenceController extends AbstractPatternSwitchPreferenceController {
     private static final String PREF_KEY = "visiblepattern";
 
-    private final int mUserId;
-    private final LockPatternUtils mLockPatternUtils;
-
     public PatternVisiblePreferenceController(Context context, int userId,
             LockPatternUtils lockPatternUtils) {
-        super(context);
-        mUserId = userId;
-        mLockPatternUtils = lockPatternUtils;
+        super(context, PREF_KEY, userId, lockPatternUtils);
     }
 
     @Override
-    public boolean isAvailable() {
-        return isPatternLock();
+    protected boolean isEnabled(LockPatternUtils utils, int userId) {
+        return utils.isVisiblePatternEnabled(userId);
     }
 
     @Override
-    public String getPreferenceKey() {
-        return PREF_KEY;
-    }
-
-    @Override
-    public void updateState(Preference preference) {
-        ((TwoStatePreference) preference).setChecked(
-                mLockPatternUtils.isVisiblePatternEnabled(mUserId));
-    }
-
-    private boolean isPatternLock() {
-        return mLockPatternUtils.getCredentialTypeForUser(mUserId)
-                == LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
-    }
-
-    @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-        mLockPatternUtils.setVisiblePatternEnabled((Boolean) newValue, mUserId);
-        return true;
+    protected void setEnabled(LockPatternUtils utils, int userId, boolean enabled) {
+        utils.setVisiblePatternEnabled(enabled, userId);
     }
 }
diff --git a/src/com/android/settings/security/screenlock/PinScramblePreferenceController.java b/src/com/android/settings/security/screenlock/PinScramblePreferenceController.java
new file mode 100644
index 0000000..d6c884f
--- /dev/null
+++ b/src/com/android/settings/security/screenlock/PinScramblePreferenceController.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.security.screenlock;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.provider.Settings;
+import androidx.preference.Preference;
+import androidx.preference.TwoStatePreference;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+public class PinScramblePreferenceController extends AbstractPreferenceController
+        implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
+
+    static final String KEY_LOCKSCREEN_SCRAMBLE_PIN_LAYOUT = "lockscreen_scramble_pin_layout";
+
+    private final int mUserId;
+    private final LockPatternUtils mLockPatternUtils;
+
+    public PinScramblePreferenceController(Context context, int userId,
+            LockPatternUtils lockPatternUtils) {
+        super(context);
+        mUserId = userId;
+        mLockPatternUtils = lockPatternUtils;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return isPinLock();
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_LOCKSCREEN_SCRAMBLE_PIN_LAYOUT;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        ((TwoStatePreference) preference).setChecked(Settings.System.getInt(
+                mContext.getContentResolver(),
+                Settings.System.LOCKSCREEN_PIN_SCRAMBLE_LAYOUT,
+                0) == 1);
+    }
+
+    private boolean isPinLock() {
+        int quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId);
+        boolean hasPin = quality == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC ||
+                quality == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+        return mLockPatternUtils.isSecure(mUserId) && hasPin;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        Settings.System.putInt(
+                mContext.getContentResolver(),
+                Settings.System.LOCKSCREEN_PIN_SCRAMBLE_LAYOUT,
+                (Boolean) newValue ? 1 : 0);
+        return true;
+    }
+}
diff --git a/src/com/android/settings/security/screenlock/ScreenLockSettings.java b/src/com/android/settings/security/screenlock/ScreenLockSettings.java
index 1c66b71..f811872 100644
--- a/src/com/android/settings/security/screenlock/ScreenLockSettings.java
+++ b/src/com/android/settings/security/screenlock/ScreenLockSettings.java
@@ -82,12 +82,18 @@
                 context, MY_USER_ID, lockPatternUtils));
         controllers.add(new PinPrivacyPreferenceController(
                 context, MY_USER_ID, lockPatternUtils));
+        controllers.add(new PatternErrorVisiblePreferenceController(
+                context, MY_USER_ID, lockPatternUtils));
+        controllers.add(new PatternDotsVisiblePreferenceController(
+                context, MY_USER_ID, lockPatternUtils));
         controllers.add(new PowerButtonInstantLockPreferenceController(
                 context, MY_USER_ID, lockPatternUtils));
         controllers.add(new LockAfterTimeoutPreferenceController(
                 context, MY_USER_ID, lockPatternUtils));
         controllers.add(new AutoPinConfirmPreferenceController(
                 context, MY_USER_ID, lockPatternUtils, parent));
+        controllers.add(new PinScramblePreferenceController(
+                context, MY_USER_ID, lockPatternUtils));
         controllers.add(new OwnerInfoPreferenceController(context, parent));
         return controllers;
     }
diff --git a/src/com/android/settings/support/GlobalSettingMainSwitchPreference.java b/src/com/android/settings/support/GlobalSettingMainSwitchPreference.java
new file mode 100644
index 0000000..43383ad
--- /dev/null
+++ b/src/com/android/settings/support/GlobalSettingMainSwitchPreference.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package com.android.settings.support;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.util.AttributeSet;
+
+import androidx.preference.PreferenceDataStore;
+
+import com.android.settingslib.widget.MainSwitchPreference;
+
+public class GlobalSettingMainSwitchPreference extends MainSwitchPreference {
+
+    public GlobalSettingMainSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        setPreferenceDataStore(new DataStore());
+    }
+
+    public GlobalSettingMainSwitchPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setPreferenceDataStore(new DataStore());
+    }
+
+    public GlobalSettingMainSwitchPreference(Context context) {
+        super(context, null);
+        setPreferenceDataStore(new DataStore());
+    }
+
+    private class DataStore extends PreferenceDataStore {
+        @Override
+        public void putBoolean(String key, boolean value) {
+            Settings.Global.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
+        }
+
+        @Override
+        public boolean getBoolean(String key, boolean defaultValue) {
+            return Settings.Global.getInt(getContext().getContentResolver(), key,
+                    defaultValue ? 1 : 0) != 0;
+        }
+    }
+}
diff --git a/src/com/android/settings/support/SecureSettingListPreference.java b/src/com/android/settings/support/SecureSettingListPreference.java
new file mode 100644
index 0000000..6dfc47a
--- /dev/null
+++ b/src/com/android/settings/support/SecureSettingListPreference.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 AICP
+ *
+ * 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.support;
+
+import android.content.Context;
+import androidx.preference.ListPreference;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+
+public class SecureSettingListPreference extends ListPreference {
+    private boolean mAutoSummary = false;
+
+    public SecureSettingListPreference(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        setPreferenceDataStore(new SecureSettingsStore(context.getContentResolver()));
+    }
+
+    public SecureSettingListPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setPreferenceDataStore(new SecureSettingsStore(context.getContentResolver()));
+    }
+
+    public SecureSettingListPreference(Context context) {
+        super(context);
+        setPreferenceDataStore(new SecureSettingsStore(context.getContentResolver()));
+    }
+
+    @Override
+    public void setValue(String value) {
+        super.setValue(value);
+        if (mAutoSummary || TextUtils.isEmpty(getSummary())) {
+            setSummary(getEntry(), true);
+        }
+    }
+
+    @Override
+    public void setSummary(CharSequence summary) {
+        setSummary(summary, false);
+    }
+
+    private void setSummary(CharSequence summary, boolean autoSummary) {
+        mAutoSummary = autoSummary;
+        super.setSummary(summary);
+    }
+
+    @Override
+    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+        // This is what default ListPreference implementation is doing without respecting
+        // real default value:
+        //setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
+        // Instead, we better do
+        setValue(restoreValue ? getPersistedString((String) defaultValue) : (String) defaultValue);
+    }
+
+}
diff --git a/src/com/android/settings/support/SecureSettingMainSwitchPreference.java b/src/com/android/settings/support/SecureSettingMainSwitchPreference.java
new file mode 100644
index 0000000..011c199
--- /dev/null
+++ b/src/com/android/settings/support/SecureSettingMainSwitchPreference.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package com.android.settings.support;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.util.AttributeSet;
+
+import androidx.preference.PreferenceDataStore;
+
+import com.android.settingslib.widget.MainSwitchPreference;
+
+public class SecureSettingMainSwitchPreference extends MainSwitchPreference {
+
+    public SecureSettingMainSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        setPreferenceDataStore(new DataStore());
+    }
+
+    public SecureSettingMainSwitchPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setPreferenceDataStore(new DataStore());
+    }
+
+    public SecureSettingMainSwitchPreference(Context context) {
+        super(context, null);
+        setPreferenceDataStore(new DataStore());
+    }
+
+    private class DataStore extends PreferenceDataStore {
+        @Override
+        public void putBoolean(String key, boolean value) {
+            Settings.Secure.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
+        }
+
+        @Override
+        public boolean getBoolean(String key, boolean defaultValue) {
+            return Settings.Secure.getInt(getContext().getContentResolver(), key,
+                    defaultValue ? 1 : 0) != 0;
+        }
+    }
+}
diff --git a/src/com/android/settings/support/SecureSettingSeekBarPreference.java b/src/com/android/settings/support/SecureSettingSeekBarPreference.java
new file mode 100644
index 0000000..94f218d
--- /dev/null
+++ b/src/com/android/settings/support/SecureSettingSeekBarPreference.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The LeafOS 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.support;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.settings.widget.LabeledSeekBarPreference;
+
+public class SecureSettingSeekBarPreference extends LabeledSeekBarPreference {
+
+    public SecureSettingSeekBarPreference(Context context, AttributeSet attrs, int defStyle,
+            int defStyleRes) {
+        super(context, attrs, defStyle, defStyleRes);
+        setPreferenceDataStore(new SecureSettingsStore(context.getContentResolver()));
+    }
+
+    public SecureSettingSeekBarPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setPreferenceDataStore(new SecureSettingsStore(context.getContentResolver()));
+    }
+
+    public SecureSettingSeekBarPreference(Context context) {
+        super(context, null);
+        setPreferenceDataStore(new SecureSettingsStore(context.getContentResolver()));
+    }
+
+    @Override
+    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+        setProgress(restoreValue ? getPersistedInt((Integer) defaultValue) : (Integer) defaultValue);
+    }
+}
diff --git a/src/com/android/settings/support/SecureSettingSwitchPreference.java b/src/com/android/settings/support/SecureSettingSwitchPreference.java
new file mode 100644
index 0000000..c10fffe
--- /dev/null
+++ b/src/com/android/settings/support/SecureSettingSwitchPreference.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod project
+ *               2020 Android Ice Cold 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.support;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.preference.SwitchPreference;
+
+public class SecureSettingSwitchPreference extends SwitchPreference {
+
+    public SecureSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        setPreferenceDataStore(new SecureSettingsStore(context.getContentResolver()));
+    }
+
+    public SecureSettingSwitchPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setPreferenceDataStore(new SecureSettingsStore(context.getContentResolver()));
+    }
+
+    public SecureSettingSwitchPreference(Context context) {
+        super(context);
+        setPreferenceDataStore(new SecureSettingsStore(context.getContentResolver()));
+    }
+
+    @Override
+    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+        // This is what default TwoStatePreference implementation is doing without respecting
+        // real default value:
+        //setChecked(restoreValue ? getPersistedBoolean(mChecked)
+        //        : (Boolean) defaultValue);
+        // Instead, we better do
+        setChecked(restoreValue ? getPersistedBoolean((Boolean) defaultValue)
+                : (Boolean) defaultValue);
+    }
+}
diff --git a/src/com/android/settings/support/SecureSettingsStore.java b/src/com/android/settings/support/SecureSettingsStore.java
new file mode 100644
index 0000000..3ff9d7d
--- /dev/null
+++ b/src/com/android/settings/support/SecureSettingsStore.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 Android Ice Cold Project
+ *                    CarbonROM
+ *
+ * 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.support;
+
+import android.content.ContentResolver;
+import android.preference.PreferenceDataStore;
+import android.provider.Settings;
+
+public class SecureSettingsStore extends androidx.preference.PreferenceDataStore
+        implements PreferenceDataStore {
+
+    private ContentResolver mContentResolver;
+
+    public SecureSettingsStore(ContentResolver contentResolver) {
+        mContentResolver = contentResolver;
+    }
+
+    public boolean getBoolean(String key, boolean defValue) {
+        return getInt(key, defValue ? 1 : 0) != 0;
+    }
+
+    public float getFloat(String key, float defValue) {
+        return Settings.Secure.getFloat(mContentResolver, key, defValue);
+    }
+
+    public int getInt(String key, int defValue) {
+        return Settings.Secure.getInt(mContentResolver, key, defValue);
+    }
+
+    public long getLong(String key, long defValue) {
+        return Settings.Secure.getLong(mContentResolver, key, defValue);
+    }
+
+    public String getString(String key, String defValue) {
+        String result = Settings.Secure.getString(mContentResolver, key);
+        return result == null ? defValue : result;
+    }
+
+    public void putBoolean(String key, boolean value) {
+        putInt(key, value ? 1 : 0);
+    }
+
+    public void putFloat(String key, float value) {
+        Settings.Secure.putFloat(mContentResolver, key, value);
+    }
+
+    public void putInt(String key, int value) {
+        Settings.Secure.putInt(mContentResolver, key, value);
+    }
+
+    public void putLong(String key, long value) {
+        Settings.Secure.putLong(mContentResolver, key, value);
+    }
+
+    public void putString(String key, String value) {
+        Settings.Secure.putString(mContentResolver, key, value);
+    }
+
+}
diff --git a/src/com/android/settings/support/SystemSettingMainSwitchPreference.java b/src/com/android/settings/support/SystemSettingMainSwitchPreference.java
new file mode 100644
index 0000000..7d5728a
--- /dev/null
+++ b/src/com/android/settings/support/SystemSettingMainSwitchPreference.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package com.android.settings.support;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.util.AttributeSet;
+
+import androidx.preference.PreferenceDataStore;
+
+import com.android.settingslib.widget.MainSwitchPreference;
+
+public class SystemSettingMainSwitchPreference extends MainSwitchPreference {
+
+    public SystemSettingMainSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        setPreferenceDataStore(new DataStore());
+    }
+
+    public SystemSettingMainSwitchPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setPreferenceDataStore(new DataStore());
+    }
+
+    public SystemSettingMainSwitchPreference(Context context) {
+        super(context, null);
+        setPreferenceDataStore(new DataStore());
+    }
+
+    private class DataStore extends PreferenceDataStore {
+        @Override
+        public void putBoolean(String key, boolean value) {
+            Settings.System.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
+        }
+
+        @Override
+        public boolean getBoolean(String key, boolean defaultValue) {
+            return Settings.System.getInt(getContext().getContentResolver(), key,
+                    defaultValue ? 1 : 0) != 0;
+        }
+    }
+}
diff --git a/src/com/android/settings/support/SystemSettingSwitchPreference.java b/src/com/android/settings/support/SystemSettingSwitchPreference.java
new file mode 100644
index 0000000..15ae6ed
--- /dev/null
+++ b/src/com/android/settings/support/SystemSettingSwitchPreference.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ * Copyright (C) 2017 AICP
+ *
+ * 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.support;
+
+import android.content.Context;
+import androidx.preference.SwitchPreference;
+import android.util.AttributeSet;
+
+public class SystemSettingSwitchPreference extends SwitchPreference {
+
+    public SystemSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+    }
+
+    public SystemSettingSwitchPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+    }
+
+    public SystemSettingSwitchPreference(Context context) {
+        super(context);
+        setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+    }
+
+    @Override
+    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+        // This is what default TwoStatePreference implementation is doing without respecting
+        // real default value:
+        //setChecked(restoreValue ? getPersistedBoolean(mChecked)
+        //        : (Boolean) defaultValue);
+        // Instead, we better do
+        setChecked(restoreValue ? getPersistedBoolean((Boolean) defaultValue)
+                : (Boolean) defaultValue);
+    }
+}
diff --git a/src/com/android/settings/support/SystemSettingsStore.java b/src/com/android/settings/support/SystemSettingsStore.java
new file mode 100644
index 0000000..7bd6132
--- /dev/null
+++ b/src/com/android/settings/support/SystemSettingsStore.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 AICP
+ *
+ * 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.support;
+
+import android.content.ContentResolver;
+import android.preference.PreferenceDataStore;
+import android.provider.Settings;
+
+public class SystemSettingsStore extends androidx.preference.PreferenceDataStore
+        implements PreferenceDataStore {
+
+    private ContentResolver mContentResolver;
+
+    public SystemSettingsStore(ContentResolver contentResolver) {
+        mContentResolver = contentResolver;
+    }
+
+    public boolean getBoolean(String key, boolean defValue) {
+        return getInt(key, defValue ? 1 : 0) != 0;
+    }
+
+    public float getFloat(String key, float defValue) {
+        return Settings.System.getFloat(mContentResolver, key, defValue);
+    }
+
+    public int getInt(String key, int defValue) {
+        return Settings.System.getInt(mContentResolver, key, defValue);
+    }
+
+    public long getLong(String key, long defValue) {
+        return Settings.System.getLong(mContentResolver, key, defValue);
+    }
+
+    public String getString(String key, String defValue) {
+        String result = Settings.System.getString(mContentResolver, key);
+        return result == null ? defValue : result;
+    }
+
+    public void putBoolean(String key, boolean value) {
+        putInt(key, value ? 1 : 0);
+    }
+
+    public void putFloat(String key, float value) {
+        Settings.System.putFloat(mContentResolver, key, value);
+    }
+
+    public void putInt(String key, int value) {
+        Settings.System.putInt(mContentResolver, key, value);
+    }
+
+    public void putLong(String key, long value) {
+        Settings.System.putLong(mContentResolver, key, value);
+    }
+
+    public void putString(String key, String value) {
+        Settings.System.putString(mContentResolver, key, value);
+    }
+
+}
diff --git a/src/com/android/settings/widget/EntityHeaderController.java b/src/com/android/settings/widget/EntityHeaderController.java
index c89b7bb..208be15 100644
--- a/src/com/android/settings/widget/EntityHeaderController.java
+++ b/src/com/android/settings/widget/EntityHeaderController.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -76,6 +77,7 @@
     // Required for hearing aid devices.
     private CharSequence mSecondSummary;
     private String mPackageName;
+    private String mPackageNameReal;
     private Intent mAppNotifPrefIntent;
     @UserIdInt
     private int mUid = UserHandle.USER_NULL;
@@ -134,6 +136,7 @@
      */
     public EntityHeaderController setIcon(ApplicationsState.AppEntry appEntry) {
         mIcon = Utils.getBadgedIcon(mAppContext, appEntry.info);
+        mPackageNameReal = appEntry.info.packageName;
         return this;
     }
 
@@ -233,6 +236,18 @@
         if (iconView != null) {
             iconView.setImageDrawable(mIcon);
             iconView.setContentDescription(mIconContentDescription);
+            if (mPackageNameReal != null) {
+                iconView.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        PackageManager pm = v.getContext().getPackageManager();
+                        Intent intent = pm.getLaunchIntentForPackage(mPackageNameReal);
+                        if (intent == null)
+                            return;
+                        v.getContext().startActivity(intent);
+                    }
+                });
+            }
         }
         setText(R.id.entity_header_title, mLabel);
         setText(R.id.entity_header_summary, mSummary);
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index bad29eb..b5cb622 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -48,6 +48,9 @@
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
 
+import ink.kscope.settings.wifi.tether.WifiTetherHiddenSsidPreferenceController;
+import ink.kscope.settings.wifi.tether.WifiTetherClientManagerPreferenceController;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -76,6 +79,12 @@
     static final String KEY_WIFI_HOTSPOT_SPEED = "wifi_hotspot_speed";
     @VisibleForTesting
     static final String KEY_INSTANT_HOTSPOT = "wifi_hotspot_instant";
+    @VisibleForTesting
+    static final String KEY_WIFI_TETHER_HIDDEN_SSID =
+            WifiTetherHiddenSsidPreferenceController.PREF_KEY;
+    @VisibleForTesting
+    static final String KEY_WIFI_TETHER_CLIENT_MANAGER =
+            WifiTetherClientManagerPreferenceController.PREF_KEY;
 
     @VisibleForTesting
     SettingsMainSwitchBar mMainSwitchBar;
@@ -90,6 +99,10 @@
     WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController;
     @VisibleForTesting
     WifiTetherAutoOffPreferenceController mWifiTetherAutoOffPreferenceController;
+    @VisibleForTesting
+    WifiTetherHiddenSsidPreferenceController mHiddenSsidPrefController;
+    @VisibleForTesting
+    WifiTetherClientManagerPreferenceController mClientPrefController;
 
     @VisibleForTesting
     boolean mUnavailable;
@@ -199,6 +212,8 @@
         mMaxCompatibilityPrefController =
                 use(WifiTetherMaximizeCompatibilityPreferenceController.class);
         mWifiTetherAutoOffPreferenceController = use(WifiTetherAutoOffPreferenceController.class);
+        mHiddenSsidPrefController = use(WifiTetherHiddenSsidPreferenceController.class);
+        mClientPrefController = use(WifiTetherClientManagerPreferenceController.class);
     }
 
     @Override
@@ -283,6 +298,8 @@
         controllers.add(
                 new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF));
         controllers.add(new WifiTetherMaximizeCompatibilityPreferenceController(context, listener));
+        controllers.add(new WifiTetherHiddenSsidPreferenceController(context, listener));
+        controllers.add(new WifiTetherClientManagerPreferenceController(context, listener));
         return controllers;
     }
 
@@ -329,6 +346,8 @@
         }
         configBuilder.setAutoShutdownEnabled(
                 mWifiTetherAutoOffPreferenceController.isEnabled());
+        configBuilder.setHiddenSsid(mHiddenSsidPrefController.isHiddenSsidEnabled());
+        mClientPrefController.updateConfig(configBuilder);
         return configBuilder.build();
     }
 
@@ -337,6 +356,7 @@
         use(WifiTetherSecurityPreferenceController.class).updateDisplay();
         use(WifiTetherPasswordPreferenceController.class).updateDisplay();
         use(WifiTetherMaximizeCompatibilityPreferenceController.class).updateDisplay();
+        use(WifiTetherHiddenSsidPreferenceController.class).updateDisplay();
     }
 
     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
@@ -369,6 +389,8 @@
                 keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
                 keys.add(KEY_WIFI_TETHER_AUTO_OFF);
                 keys.add(KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
+                keys.add(KEY_WIFI_TETHER_HIDDEN_SSID);
+                keys.add(KEY_WIFI_TETHER_CLIENT_MANAGER);
             }
 
             // Remove duplicate
diff --git a/src/ink/kscope/settings/wifi/tether/WifiTetherClientManager.java b/src/ink/kscope/settings/wifi/tether/WifiTetherClientManager.java
new file mode 100644
index 0000000..a661f0e
--- /dev/null
+++ b/src/ink/kscope/settings/wifi/tether/WifiTetherClientManager.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2022 Project Kaleidoscope
+ *
+ * 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 ink.kscope.settings.wifi.tether;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.net.MacAddress;
+import android.net.TetheringManager;
+import android.net.TetheredClient;
+import android.net.wifi.SoftApCapability;
+import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settingslib.widget.FooterPreference;
+
+import ink.kscope.settings.wifi.tether.preference.WifiTetherClientLimitPreference;
+
+public class WifiTetherClientManager extends SettingsPreferenceFragment implements
+        Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
+        WifiManager.SoftApCallback, TetheringManager.TetheringEventCallback {
+
+    private static final String TAG = "WifiTetherClientManager";
+
+    private static final String PREF_KEY_CLIENT_LIMIT = "client_limit";
+    private static final String PREF_KEY_BLOCKED_CLIENT_LIST = "blocked_client_list";
+    private static final String PREF_KEY_CONNECTED_CLIENT_LIST = "connected_client_list";
+    private static final String PREF_KEY_FOOTER = "footer";
+
+    private WifiManager mWifiManager;
+    private TetheringManager mTetheringManager;
+
+    private WifiTetherClientLimitPreference mClientLimitPref;
+    private PreferenceCategory mConnectedClientsPref;
+    private PreferenceCategory mBlockedClientsPref;
+    private FooterPreference mFooterPref;
+
+    private boolean mSupportForceDisconnect;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mWifiManager = getSystemService(WifiManager.class);
+        mTetheringManager = getSystemService(TetheringManager.class);
+
+        mWifiManager.registerSoftApCallback(getActivity().getMainExecutor(), this);
+
+        addPreferencesFromResource(R.xml.hotspot_client_manager);
+
+        getActivity().setTitle(R.string.wifi_hotspot_client_manager_title);
+
+        mClientLimitPref = findPreference(PREF_KEY_CLIENT_LIMIT);
+        mConnectedClientsPref = findPreference(PREF_KEY_CONNECTED_CLIENT_LIST);
+        mBlockedClientsPref = findPreference(PREF_KEY_BLOCKED_CLIENT_LIST);
+        mFooterPref = findPreference(PREF_KEY_FOOTER);
+
+        mClientLimitPref.setOnPreferenceChangeListener(this);
+
+        updateBlockedClients();
+        updatePreferenceVisible();
+    }
+
+    @Override
+    public void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {
+        mSupportForceDisconnect =
+                softApCapability.areFeaturesSupported(
+                    SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT);
+        mWifiManager.unregisterSoftApCallback(this);
+
+        if (mSupportForceDisconnect) {
+            mClientLimitPref.setMin(1);
+            mClientLimitPref.setMax(softApCapability.getMaxSupportedClients());
+            final SoftApConfiguration softApConfiguration = mWifiManager.getSoftApConfiguration();
+            final int maxNumberOfClients = softApConfiguration.getMaxNumberOfClients();
+            mClientLimitPref.setValue(maxNumberOfClients, false);
+        }
+        updatePreferenceVisible();
+    }
+
+    private void updatePreferenceVisible() {
+        if (mBlockedClientsPref == null || mClientLimitPref == null ||
+                mConnectedClientsPref == null || mFooterPref == null) return;
+        boolean hasConnectedClient = mConnectedClientsPref.getPreferenceCount() > 0;
+        boolean hasBlockedClient = mBlockedClientsPref.getPreferenceCount() > 0;
+        mClientLimitPref.setVisible(mSupportForceDisconnect);
+        mBlockedClientsPref.setVisible(mSupportForceDisconnect && hasBlockedClient);
+        mConnectedClientsPref.setVisible(hasConnectedClient);
+        mFooterPref.setVisible(!hasBlockedClient && !hasConnectedClient);
+    }
+
+    private void updateBlockedClients() {
+        final SoftApConfiguration softApConfiguration = mWifiManager.getSoftApConfiguration();
+        final List<MacAddress> blockedClientList = softApConfiguration.getBlockedClientList();
+        mBlockedClientsPref.removeAll();
+        for (MacAddress mac : blockedClientList) {
+            BlockedClientPreference preference = new BlockedClientPreference(getActivity(), mac);
+            preference.setOnPreferenceClickListener(this);
+            mBlockedClientsPref.addPreference(preference);
+        }
+        updatePreferenceVisible();
+    }
+
+    @Override
+    public void onClientsChanged(Collection<TetheredClient> clients) {
+        mConnectedClientsPref.removeAll();
+        for (TetheredClient client : clients) {
+            if (client.getTetheringType() != TetheringManager.TETHERING_WIFI) {
+                continue;
+            }
+            ConnectedClientPreference preference =
+                new ConnectedClientPreference(getActivity(), client);
+            preference.setOnPreferenceClickListener(this);
+            mConnectedClientsPref.addPreference(preference);
+        }
+        updatePreferenceVisible();
+    }
+
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        if (mSupportForceDisconnect) {
+            if (preference instanceof ConnectedClientPreference) {
+                showBlockClientDialog(
+                    ((ConnectedClientPreference)preference).getMacAddress(),
+                    preference.getTitle());
+                return true;
+            } else if (preference instanceof BlockedClientPreference) {
+                showUnblockClientDialog(((BlockedClientPreference)preference).getMacAddress());
+                return true;
+            }
+        }
+        return super.onPreferenceTreeClick(preference);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (preference == mClientLimitPref) {
+            int value = (int) newValue;
+            SoftApConfiguration softApConfiguration = mWifiManager.getSoftApConfiguration();
+            SoftApConfiguration newSoftApConfiguration =
+                    new SoftApConfiguration.Builder(softApConfiguration)
+                            .setMaxNumberOfClients(value)
+                            .build();
+            return mWifiManager.setSoftApConfiguration(newSoftApConfiguration);
+        }
+        return false;
+    }
+
+    private void blockClient(MacAddress mac, boolean isBlock) {
+        final SoftApConfiguration softApConfiguration = mWifiManager.getSoftApConfiguration();
+        final List<MacAddress> blockedClientList = softApConfiguration.getBlockedClientList();
+        if (isBlock) {
+            if (blockedClientList.contains(mac)) return;
+            blockedClientList.add(mac);
+        } else {
+            if (!blockedClientList.contains(mac)) return;
+            blockedClientList.remove(mac);
+        }
+        SoftApConfiguration newSoftApConfiguration =
+                new SoftApConfiguration.Builder(softApConfiguration)
+                        .setBlockedClientList(blockedClientList)
+                        .build();
+        mWifiManager.setSoftApConfiguration(newSoftApConfiguration);
+        updateBlockedClients();
+    }
+
+    private void showBlockClientDialog(MacAddress mac, CharSequence deviceName) {
+        final Activity activity = getActivity();
+        new AlertDialog.Builder(activity)
+            .setTitle(R.string.wifi_hotspot_block_client_dialog_title)
+            .setMessage(activity.getString(
+                R.string.wifi_hotspot_block_client_dialog_text, deviceName))
+            .setPositiveButton(android.R.string.ok,
+                (dialog, which) -> {
+                    blockClient(mac, true);
+                })
+            .setNegativeButton(android.R.string.cancel, null)
+            .create().show();
+    }
+
+    private void showUnblockClientDialog(MacAddress mac) {
+        final Activity activity = getActivity();
+        new AlertDialog.Builder(activity)
+            .setTitle(R.string.wifi_hotspot_unblock_client_dialog_title)
+            .setMessage(activity.getString(
+                R.string.wifi_hotspot_unblock_client_dialog_text, mac.toString()))
+            .setPositiveButton(android.R.string.ok,
+                (dialog, which) -> {
+                    blockClient(mac, false);
+                })
+            .setNegativeButton(android.R.string.cancel, null)
+            .create().show();
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mTetheringManager.registerTetheringEventCallback(getActivity().getMainExecutor(), this);
+    }
+
+    @Override
+    public void onStop() {
+        mTetheringManager.unregisterTetheringEventCallback(this);
+        super.onStop();
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.WIFI_TETHER_SETTINGS;
+    }
+
+    private class ConnectedClientPreference extends Preference {
+        private MacAddress mMacAddress;
+
+        public ConnectedClientPreference(Context context, TetheredClient client) {
+            super(context);
+            mMacAddress = client.getMacAddress();
+
+            String hostName = null;
+            String macAddress = client.getMacAddress().toString();
+
+            for (TetheredClient.AddressInfo addressInfo : client.getAddresses()) {
+                if (!TextUtils.isEmpty(addressInfo.getHostname())) {
+                    hostName = addressInfo.getHostname();
+                    break;
+                }
+            }
+
+            setKey(macAddress);
+            if (!TextUtils.isEmpty(hostName)) {
+                setTitle(hostName);
+                setSummary(macAddress);
+            } else {
+                setTitle(macAddress);
+            }
+        }
+
+        public MacAddress getMacAddress() {
+            return mMacAddress;
+        }
+    }
+
+    private class BlockedClientPreference extends Preference {
+        private MacAddress mMacAddress;
+
+        public BlockedClientPreference(Context context, MacAddress mac) {
+            super(context);
+            mMacAddress = mac;
+            setKey(mac.toString());
+            setTitle(mac.toString());
+        }
+
+        public MacAddress getMacAddress() {
+            return mMacAddress;
+        }
+    }
+}
diff --git a/src/ink/kscope/settings/wifi/tether/WifiTetherClientManagerPreferenceController.java b/src/ink/kscope/settings/wifi/tether/WifiTetherClientManagerPreferenceController.java
new file mode 100644
index 0000000..95572ce
--- /dev/null
+++ b/src/ink/kscope/settings/wifi/tether/WifiTetherClientManagerPreferenceController.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 Project Kaleidoscope
+ *
+ * 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 ink.kscope.settings.wifi.tether;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.MacAddress;
+import android.net.wifi.SoftApCapability;
+import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiManager;
+import android.util.FeatureFlagUtils;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.core.FeatureFlags;
+import com.android.settings.wifi.tether.WifiTetherBasePreferenceController;
+
+import java.util.List;
+
+public class WifiTetherClientManagerPreferenceController extends WifiTetherBasePreferenceController
+        implements WifiManager.SoftApCallback {
+
+    public static final String DEDUP_POSTFIX = "_2";
+    public static final String PREF_KEY = "wifi_tether_client_manager";
+
+    private boolean mSupportForceDisconnect;
+
+    public WifiTetherClientManagerPreferenceController(Context context,
+            WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener) {
+        super(context, listener);
+
+        mWifiManager.registerSoftApCallback(context.getMainExecutor(), this);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return FeatureFlagUtils.isEnabled(mContext, FeatureFlags.TETHER_ALL_IN_ONE)
+                ? PREF_KEY + DEDUP_POSTFIX : PREF_KEY;
+    }
+
+    @Override
+    public void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {
+        mSupportForceDisconnect =
+                softApCapability.areFeaturesSupported(
+                    SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT);
+        mWifiManager.unregisterSoftApCallback(this);
+        updateDisplay();
+    }
+
+    @Override
+    public void updateDisplay() {
+        if (mPreference != null) {
+            if (mSupportForceDisconnect) {
+                mPreference.setSummary(R.string.wifi_hotspot_client_manager_summary);
+            } else {
+                mPreference.setSummary(R.string.wifi_hotspot_client_manager_list_only_summary);
+            }
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        return true;
+    }
+
+    public void updateConfig(SoftApConfiguration.Builder builder) {
+        if (builder == null || !mSupportForceDisconnect) return;
+        final SoftApConfiguration softApConfiguration = mWifiManager.getSoftApConfiguration();
+        final int maxNumberOfClients = softApConfiguration.getMaxNumberOfClients();
+        final List<MacAddress> blockedClientList = softApConfiguration.getBlockedClientList();
+        builder.setMaxNumberOfClients(maxNumberOfClients)
+                .setBlockedClientList(blockedClientList);
+    }
+}
diff --git a/src/ink/kscope/settings/wifi/tether/WifiTetherHiddenSsidPreferenceController.java b/src/ink/kscope/settings/wifi/tether/WifiTetherHiddenSsidPreferenceController.java
new file mode 100644
index 0000000..2460877
--- /dev/null
+++ b/src/ink/kscope/settings/wifi/tether/WifiTetherHiddenSsidPreferenceController.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 Project Kaleidoscope
+ *
+ * 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 ink.kscope.settings.wifi.tether;
+
+import android.content.Context;
+import android.net.wifi.SoftApConfiguration;
+import android.util.FeatureFlagUtils;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.R;
+import com.android.settings.core.FeatureFlags;
+import com.android.settings.wifi.tether.WifiTetherBasePreferenceController;
+
+/**
+ * This controller helps to manage the state of hide SSID switch preference.
+ */
+public class WifiTetherHiddenSsidPreferenceController extends
+        WifiTetherBasePreferenceController {
+
+    public static final String DEDUP_POSTFIX = "_2";
+    public static final String PREF_KEY = "wifi_tether_hidden_ssid";
+
+    private boolean mHiddenSsid;
+
+    public WifiTetherHiddenSsidPreferenceController(Context context,
+            WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener) {
+        super(context, listener);
+
+        if (mWifiManager != null) {
+            final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+            if (config != null) {
+                mHiddenSsid = config.isHiddenSsid();
+            }
+        }
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return FeatureFlagUtils.isEnabled(mContext, FeatureFlags.TETHER_ALL_IN_ONE)
+                ? PREF_KEY + DEDUP_POSTFIX : PREF_KEY;
+    }
+
+    @Override
+    public void updateDisplay() {
+        if (mPreference == null) {
+            return;
+        }
+        ((SwitchPreference) mPreference).setChecked(mHiddenSsid);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        mHiddenSsid = (Boolean) newValue;
+        if (mListener != null) {
+            mListener.onTetherConfigUpdated(this);
+        }
+        return true;
+    }
+
+    public boolean isHiddenSsidEnabled() {
+        return mHiddenSsid;
+    }
+}
diff --git a/src/ink/kscope/settings/wifi/tether/preference/WifiTetherClientLimitPreference.java b/src/ink/kscope/settings/wifi/tether/preference/WifiTetherClientLimitPreference.java
new file mode 100644
index 0000000..87d78b3
--- /dev/null
+++ b/src/ink/kscope/settings/wifi/tether/preference/WifiTetherClientLimitPreference.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 Project Kaleidoscope
+ *
+ * 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 ink.kscope.settings.wifi.tether.preference;
+
+import android.content.Context;
+import android.widget.SeekBar;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.settings.R;
+import com.android.settings.SeekBarDialogPreference;
+
+public class WifiTetherClientLimitPreference extends SeekBarDialogPreference implements
+        SeekBar.OnSeekBarChangeListener {
+
+    private Context mContext;
+    private SeekBar mSeekBar;
+    private int mValue;
+    private int mMin;
+    private int mMax;
+
+    public WifiTetherClientLimitPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+    }
+
+    @Override
+    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
+        setText(getSummaryForValue(progress + mMin));
+    }
+
+    @Override
+    protected void onBindDialogView(View view) {
+        super.onBindDialogView(view);
+
+        mSeekBar = getSeekBar(view);
+        mSeekBar.setOnSeekBarChangeListener(this);
+        mSeekBar.setMax(mMax - mMin);
+        mSeekBar.setProgress(mValue - mMin);
+    }
+
+    @Override
+    public void onStartTrackingTouch(SeekBar seekBar) {
+    }
+
+    @Override
+    public void onStopTrackingTouch(SeekBar seekBar) {
+    }
+
+    @Override
+    protected void onDialogClosed(boolean positiveResult) {
+        super.onDialogClosed(positiveResult);
+        if (positiveResult) {
+            setValue(mSeekBar.getProgress() + mMin, true);
+        }
+    }
+
+    private String getSummaryForValue(int value) {
+        return mContext.getResources().getQuantityString(
+            R.plurals.wifi_hotspot_client_limit_summary, value, value);
+    }
+
+    public void setMin(int min) {
+        mMin = min;
+    }
+
+    public void setMax(int max) {
+        mMax = max;
+    }
+
+    public void setValue(int value, boolean callListener) {
+        if (value == 0) value = mMax;
+        mValue = value;
+        String summary = getSummaryForValue(value);
+        setSummary(summary);
+        setText(summary);
+        if (callListener) callChangeListener(value);
+    }
+
+    public int getValue() {
+        return mValue;
+    }
+}
diff --git a/src/org/leafos/settings/BootCompletedReceiver.java b/src/org/leafos/settings/BootCompletedReceiver.java
new file mode 100644
index 0000000..638d676
--- /dev/null
+++ b/src/org/leafos/settings/BootCompletedReceiver.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022 The LeafOS 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 org.leafos.settings;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+
+import org.leafos.settings.display.HighTouchSensitivityPreferenceController;
+
+public class BootCompletedReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(final Context context, Intent intent) {
+        if (Settings.System.getInt(context.getContentResolver(), Settings.System.HIGH_TOUCH_SENSITIVITY_ENABLE, 0) != 0) {
+            HighTouchSensitivityPreferenceController.enableStatic(true);
+        }
+    }
+
+}
diff --git a/src/org/leafos/settings/controller/BaseSecureSwitchPreferenceController.java b/src/org/leafos/settings/controller/BaseSecureSwitchPreferenceController.java
new file mode 100644
index 0000000..6616aa2
--- /dev/null
+++ b/src/org/leafos/settings/controller/BaseSecureSwitchPreferenceController.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The LeafOS 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 org.leafos.settings.controller;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+public class BaseSecureSwitchPreferenceController extends TogglePreferenceController implements
+        Preference.OnPreferenceChangeListener  {
+
+    private SwitchPreference mPreference;
+
+    public BaseSecureSwitchPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        mPreference = (SwitchPreference)preference;
+        super.updateState(preference);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public boolean isSliceable() {
+        return mPreference != null;
+    }
+
+    @Override
+    public boolean isPublicSlice() {
+        return true;
+    }
+
+    @Override
+    public int getSliceHighlightMenuRes() {
+        return R.string.menu_key_display;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return Settings.Secure.getInt(mContext.getContentResolver(), getPreferenceKey(),
+            mPreference.isChecked() ? 1 : 0) != 0;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        Settings.Secure.putInt(mContext.getContentResolver(), getPreferenceKey(), isChecked ? 1 : 0);
+        return true;
+    }
+}
diff --git a/src/org/leafos/settings/controller/BaseSystemSwitchPreferenceController.java b/src/org/leafos/settings/controller/BaseSystemSwitchPreferenceController.java
new file mode 100644
index 0000000..a57b48f
--- /dev/null
+++ b/src/org/leafos/settings/controller/BaseSystemSwitchPreferenceController.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The LeafOS 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 org.leafos.settings.controller;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+public class BaseSystemSwitchPreferenceController extends TogglePreferenceController implements
+        Preference.OnPreferenceChangeListener  {
+
+    private SwitchPreference mPreference;
+
+    public BaseSystemSwitchPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        mPreference = (SwitchPreference)preference;
+        super.updateState(preference);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public boolean isSliceable() {
+        return mPreference != null;
+    }
+
+    @Override
+    public boolean isPublicSlice() {
+        return true;
+    }
+
+    @Override
+    public int getSliceHighlightMenuRes() {
+        return R.string.menu_key_display;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return Settings.System.getInt(mContext.getContentResolver(), getPreferenceKey(),
+                mPreference.isChecked() ? 1 : 0) != 0;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        Settings.System.putInt(mContext.getContentResolver(), getPreferenceKey(), isChecked ? 1 : 0);
+        return true;
+    }
+}
diff --git a/src/org/leafos/settings/display/BerryBlackThemePreferenceController.java b/src/org/leafos/settings/display/BerryBlackThemePreferenceController.java
new file mode 100644
index 0000000..a7d00fc
--- /dev/null
+++ b/src/org/leafos/settings/display/BerryBlackThemePreferenceController.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The LeafOS 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 org.leafos.settings.display;
+
+import android.content.Context;
+
+import org.leafos.settings.controller.BaseSecureSwitchPreferenceController;
+
+public class BerryBlackThemePreferenceController extends BaseSecureSwitchPreferenceController {
+
+    public BerryBlackThemePreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+}
diff --git a/src/org/leafos/settings/display/HighTouchSensitivityPreferenceController.java b/src/org/leafos/settings/display/HighTouchSensitivityPreferenceController.java
new file mode 100644
index 0000000..4cddd93
--- /dev/null
+++ b/src/org/leafos/settings/display/HighTouchSensitivityPreferenceController.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 The LeafOS 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 org.leafos.settings.display;
+
+import android.content.Context;
+import android.os.RemoteException;
+
+import java.util.NoSuchElementException;
+
+import org.leafos.settings.controller.BaseSystemSwitchPreferenceController;
+
+import vendor.lineage.touch.V1_0.IGloveMode;
+
+public class HighTouchSensitivityPreferenceController extends BaseSystemSwitchPreferenceController  {
+
+    private IGloveMode mGloveMode;
+
+    public HighTouchSensitivityPreferenceController(Context context, String key) {
+        super(context, key);
+
+        try {
+            mGloveMode = IGloveMode.getService();
+        } catch (RemoteException ex) {
+            ex.printStackTrace();
+        } catch (NoSuchElementException ex) {
+            // service not available
+        }
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return mGloveMode != null ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        try {
+            mGloveMode.setEnabled(isChecked);
+            return super.setChecked(isChecked);
+        } catch (RemoteException ex) {
+            ex.printStackTrace();
+        }
+        return false;
+    }
+
+    public static void enableStatic(boolean enable) {
+        try {
+            IGloveMode gloveMode = IGloveMode.getService();
+            gloveMode.setEnabled(enable);
+        } catch (RemoteException ex) {
+            ex.printStackTrace();
+        } catch (NoSuchElementException ex) {
+            // service not available
+        }
+    }
+}
diff --git a/src/org/leafos/settings/gestures/NavigationHintPreferenceController.java b/src/org/leafos/settings/gestures/NavigationHintPreferenceController.java
new file mode 100644
index 0000000..756f295
--- /dev/null
+++ b/src/org/leafos/settings/gestures/NavigationHintPreferenceController.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The LeafOS 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 org.leafos.settings.gestures;
+
+import android.content.Context;
+
+import org.leafos.settings.controller.BaseSecureSwitchPreferenceController;
+
+public class NavigationHintPreferenceController extends BaseSecureSwitchPreferenceController {
+
+    public NavigationHintPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+}
diff --git a/src/org/leafos/settings/qs/QSPanelSettings.java b/src/org/leafos/settings/qs/QSPanelSettings.java
new file mode 100644
index 0000000..155081a
--- /dev/null
+++ b/src/org/leafos/settings/qs/QSPanelSettings.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 The LeafOS 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 org.leafos.settings.qs;
+
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.Settings;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+@SearchIndexable
+public class QSPanelSettings extends DashboardFragment {
+
+    private static final String KEY_QS_SHOW_AUTO_BRIGHTNESS = "qs_show_auto_brightness";
+    private static final String TAG = "QSPanelSettings";
+    private static final String[] qsCustPreferences = { "qs_tile_shape",
+            "qqs_num_columns", "qqs_num_columns_landscape",
+            "qs_num_columns", "qs_num_columns_landscape" };
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        PreferenceScreen preferenceScreen = getPreferenceScreen();
+        Preference qsShowAutoBrightnessPreference = preferenceScreen.findPreference(KEY_QS_SHOW_AUTO_BRIGHTNESS);
+
+        if (qsShowAutoBrightnessPreference != null) {
+            boolean automaticBrightnessAvailable = getContext().getResources().getBoolean(
+                    com.android.internal.R.bool.config_automatic_brightness_available);
+            if (!automaticBrightnessAvailable) {
+                qsShowAutoBrightnessPreference.setVisible(false);
+            }
+        }
+
+        boolean qsStyleRound = Settings.Secure.getIntForUser(getContext().getContentResolver(),
+                Settings.Secure.QS_STYLE_ROUND, 1, UserHandle.USER_CURRENT) == 1;
+
+        if (!qsStyleRound) {
+            for (String key : qsCustPreferences) {
+                Preference preference = preferenceScreen.findPreference(key);
+                if (preference != null) {
+                    preference.setEnabled(false);
+                }
+            }
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return METRICS_CATEGORY_UNKNOWN;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.qs_panel_settings;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.qs_panel_settings);
+}
diff --git a/src/org/leafos/settings/util/PackageManagerUtils.java b/src/org/leafos/settings/util/PackageManagerUtils.java
new file mode 100644
index 0000000..1449031
--- /dev/null
+++ b/src/org/leafos/settings/util/PackageManagerUtils.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The LeafOS 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 org.leafos.settings.util;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+
+public class PackageManagerUtils {
+
+    public static String ACTION_DOZE = "org.lineageos.settings.device.DOZE_SETTINGS";
+
+    public static boolean isIntentPresent(PackageManager pm, String name) {
+        Intent intent = new Intent(name);
+        for (ResolveInfo info : pm.queryIntentActivitiesAsUser(intent,
+                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.myUserId())) {
+            if (info.activityInfo != null) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public static boolean isCustomDozePresent(PackageManager pm) {
+        return isIntentPresent(pm, ACTION_DOZE);
+    }
+
+}