diff --git a/Android.bp b/Android.bp
index 1d1f79c5ce78808a317ebb4e201afa519816159b..6f76617db10d8fe8943b95837075d6cb36e42bd9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -57,8 +57,12 @@ java_defaults {
         "framework-lmodroid",
     ],
     static_libs: [
-        "VendorSupport-preference",
+        "androidx.fragment_fragment",
+        "androidx.fragment_fragment-ktx",
+        "androidx.preference_preference-ktx",
+        "kotlinx_coroutines_android",
         "SystemUISharedLib",
+        "VendorSupport-preference",
         "vendor.lineage.fastcharge-V1.0-java",
     ],
 }
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c2032f7d9e0d819b92e650c3a4511ca641ea7d7f..dabf60481bf045ba16a3aa0f3d203b2262355b91 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -25,6 +25,9 @@
     <!-- LiveDisplay -->
     <uses-permission android:name="lineageos.permission.MANAGE_LIVEDISPLAY" />
 
+    <!-- App lock -->
+    <uses-permission android:name="com.android.permission.MANAGE_APP_LOCK" />
+
     <application>
         <activity android:name=".backup.transport.TransportActivity"
                   android:label="@string/backup_transport_title"
@@ -42,6 +45,27 @@
             android:exported="false"
             android:theme="@style/GlifTheme.Light" />
 
+        <!-- App lock -->
+        <activity android:name=".security.applock.AppLockCredentialActivity"
+            android:exported="false"
+            android:permission="com.android.permission.MANAGE_APP_LOCK"
+            android:excludeFromRecents="true"
+            android:stateNotNeeded="true"
+            android:taskAffinity="com.android.settings.applock"
+            android:launchMode="singleInstance"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar">
+            <intent-filter>
+                <action android:name="com.libremobileos.applock.action.UNLOCK_APP" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".security.applock.AppLockSubSettings"
+            android:exported="false"
+            android:excludeFromRecents="true"
+            android:taskAffinity="com.android.settings.applock"
+            android:launchMode="singleTask" />
+
     </application>
 
 </manifest>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index ab792b9c4a04974168b7080b2949d9b3d75eb569..cf65dde7ab6e6f9f70e974bd5a690d59d2993681 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -347,4 +347,25 @@
         <item>2000</item>
         <item>5000</item>
     </string-array>
+
+    <!-- App lock timeout -->
+    <string-array name="app_lock_timeout_entries">
+        <item>@string/app_lock_timeout_5sec</item>
+        <item>@string/app_lock_timeout_10sec</item>
+        <item>@string/app_lock_timeout_30sec</item>
+        <item>@string/app_lock_timeout_1min</item>
+        <item>@string/app_lock_timeout_5min</item>
+        <item>@string/app_lock_timeout_10min</item>
+        <item>@string/app_lock_timeout_30min</item>
+    </string-array>
+
+    <string-array name="app_lock_timeout_values" translatable="false">
+        <item>5000</item>
+        <item>10000</item>
+        <item>30000</item>
+        <item>60000</item>
+        <item>300000</item>
+        <item>600000</item>
+        <item>1800000</item>
+    </string-array>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index aa8df05397591ce3e9d2ab2339c2ef72c7734d59..0f16600c074e632a729ba2e18c387a5e083db905 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -29,6 +29,40 @@
     <string name="long_screen_settings_summary">Force legacy apps to use full screen aspect ratio</string>
     <string name="long_screen_settings_no_apps">No apps</string>
 
+    <!-- App lock -->
+    <string name="app_lock_title">App lock</string>
+    <plurals name="app_lock_summary">
+        <item quantity="one"><xliff:g example="1" id="Number of applications">%1$d</xliff:g> application is protected</item>
+        <item quantity="other"><xliff:g example="10" id="Number of applications">%1$d</xliff:g> applications are protected</item>
+    </plurals>
+    <string name="app_lock_authentication_dialog_title">Unlock</string>
+    <string name="enable_debugging">Enable debugging</string>
+    <string name="disable_debugging">Disable debugging</string>
+    <string name="app_lock_packages_title">Protected apps</string>
+    <string name="app_lock_packages_summary">Select the apps to protect with biometrics or device credentials</string>
+    <string name="app_lock_timeout_title">Auto lock timeout</string>
+    <string name="app_lock_timeout_summary">Duration of time after which an unlocked app in background should be locked</string>
+    <string name="app_lock_notifications_title">Redact notifications</string>
+    <string name="app_lock_notifications_summary">
+          Notification content will be hidden and collapsed for selected apps when they are locked.
+          Heads up notifications will be automatically disabled.
+    </string>
+    <string name="app_lock_notifications_disabled_summary">Protect an application first</string>
+    <string name="app_lock_biometrics_allowed_title">Enable biometrics for unlocking</string>
+    <string name="app_lock_footer_text">Bubbles will be automatically dismissed after timeout</string>
+    <string name="enable_protection">Enable protection</string>
+    <string name="hide_from_launcher_title">Hide from launcher</string>
+    <string name="hide_from_launcher_summary">
+        Prevent this application from showing up in launcher. Requires a launcher restart for changes to take effect.
+    </string>
+    <string name="app_lock_timeout_5sec">5 seconds</string>
+    <string name="app_lock_timeout_10sec">10 seconds</string>
+    <string name="app_lock_timeout_30sec">30 seconds</string>
+    <string name="app_lock_timeout_1min">1 minute</string>
+    <string name="app_lock_timeout_5min">5 minutes</string>
+    <string name="app_lock_timeout_10min">10 minutes</string>
+    <string name="app_lock_timeout_30min">30 minutes</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>
@@ -519,4 +553,5 @@
 
     <!-- Warning message for the sd card setup -->
     <string name="storage_warning_internal">Warning: This option may not work properly or lead to data loss and is therefore not recommended!</string>
+
 </resources>
diff --git a/res/xml/app_lock_package_config_settings.xml b/res/xml/app_lock_package_config_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6d14e45482a5d6d92872cacdbb89dcc916f955f9
--- /dev/null
+++ b/res/xml/app_lock_package_config_settings.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 FlamingoOS 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">
+
+    <com.android.settingslib.widget.LayoutPreference
+        android:key="header_view"
+        android:layout="@layout/settings_entity_header"
+        android:selectable="false" />
+
+    <com.android.settingslib.widget.MainSwitchPreference
+        android:key="main_switch"
+        android:title="@string/enable_protection" />
+
+    <SwitchPreference
+        android:key="redact_notifications"
+        android:title="@string/app_lock_notifications_title"
+        android:summary="@string/app_lock_notifications_summary"
+        android:dependency="main_switch" />
+
+    <SwitchPreference
+        android:key="hide_from_launcher"
+        android:title="@string/hide_from_launcher_title"
+        android:summary="@string/hide_from_launcher_summary"
+        android:dependency="main_switch" />
+
+    <com.android.settingslib.widget.FooterPreference
+        android:title="@string/app_lock_footer_text"
+        android:selectable="false"
+        android:dependency="main_switch"
+        settings:searchable="false" />
+
+</PreferenceScreen>
diff --git a/res/xml/app_lock_package_list_settings.xml b/res/xml/app_lock_package_list_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..13994b3681f146fa994d2e970de50479f1dc7bb0
--- /dev/null
+++ b/res/xml/app_lock_package_list_settings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 FlamingoOS 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:title="@string/app_lock_packages_title">
+</PreferenceScreen>
diff --git a/res/xml/app_lock_settings.xml b/res/xml/app_lock_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7cb08b39fcffb68943a9761b997ca6edb71f2821
--- /dev/null
+++ b/res/xml/app_lock_settings.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 FlamingoOS 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:title="@string/app_lock_title">
+
+    <Preference
+        android:key="app_lock_packages"
+        android:title="@string/app_lock_packages_title"
+        android:summary="@string/app_lock_packages_summary"
+        android:fragment="com.android.settings.security.applock.AppLockPackageListFragment" />
+
+    <ListPreference
+        android:key="app_lock_timeout"
+        android:title="@string/app_lock_timeout_title"
+        android:summary="@string/app_lock_timeout_summary"
+        android:entries="@array/app_lock_timeout_entries"
+        android:entryValues="@array/app_lock_timeout_values"
+        android:defaultValue="0"
+        android:persistent="false"
+        settings:controller="com.android.settings.security.applock.AppLockTimeoutPreferenceController" />
+
+    <SwitchPreference
+        android:key="app_lock_biometrics_allowed"
+        android:title="@string/app_lock_biometrics_allowed_title"
+        android:persistent="false" />
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/security/applock/AppLockBiometricPreferenceController.kt b/src/com/android/settings/security/applock/AppLockBiometricPreferenceController.kt
new file mode 100644
index 0000000000000000000000000000000000000000..62022131e66cdfdf1a48f9381fd45f5dd71cb3ee
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockBiometricPreferenceController.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import android.content.Context
+import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG
+
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+
+import com.libremobileos.applock.AppLockManager
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+private const val KEY = "app_lock_biometrics_allowed"
+
+class AppLockBiometricPreferenceController(
+    context: Context,
+    private val coroutineScope: CoroutineScope
+) : AppLockTogglePreferenceController(context, KEY) {
+
+    private val appLockManager by lazy { AppLockManager.getInstance(context) }
+    private val biometricManager = context.getSystemService(BiometricManager::class.java)
+
+    private var preference: Preference? = null
+    private var isBiometricsAllowed = false
+
+    init {
+        coroutineScope.launch {
+            isBiometricsAllowed = withContext(Dispatchers.Default) {
+                appLockManager.isBiometricsAllowed()
+            }
+            preference?.let {
+                updateState(it)
+            }
+        }
+    }
+
+    override fun getAvailabilityStatus(): Int {
+        val result = biometricManager.canAuthenticate(BIOMETRIC_STRONG)
+        return if (result == BiometricManager.BIOMETRIC_SUCCESS) AVAILABLE else CONDITIONALLY_UNAVAILABLE
+    }
+
+    override fun isChecked() = isBiometricsAllowed
+
+    override fun setChecked(checked: Boolean): Boolean {
+        if (isBiometricsAllowed == checked) return false
+        isBiometricsAllowed = checked
+        coroutineScope.launch(Dispatchers.Default) {
+            appLockManager.setBiometricsAllowed(isBiometricsAllowed)
+        }
+        return true
+    }
+
+    override fun displayPreference(screen: PreferenceScreen) {
+        super.displayPreference(screen)
+        preference = screen.findPreference(preferenceKey)
+    }
+}
diff --git a/src/com/android/settings/security/applock/AppLockCredentialActivity.kt b/src/com/android/settings/security/applock/AppLockCredentialActivity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5cdf62086cfc6ec1fcb965704ce544b2e8f87fa3
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockCredentialActivity.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.hardware.biometrics.BiometricConstants
+import android.hardware.biometrics.BiometricManager.Authenticators
+import android.hardware.biometrics.BiometricPrompt
+import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback
+import android.hardware.biometrics.PromptInfo
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.os.UserHandle.USER_NULL
+import android.os.UserManager
+import android.util.Log
+import android.view.WindowManager
+
+import androidx.fragment.app.commit
+import androidx.fragment.app.FragmentActivity
+
+import com.android.internal.widget.LockPatternUtils
+import com.android.settings.R
+import com.android.settings.password.BiometricFragment
+import com.android.settings.password.ConfirmDeviceCredentialUtils
+
+import com.libremobileos.applock.AppLockManager
+
+class AppLockCredentialActivity : FragmentActivity() {
+
+    private val handler = Handler(Looper.getMainLooper())
+
+    private lateinit var lockPatternUtils: LockPatternUtils
+    private lateinit var userManager: UserManager
+    private lateinit var appLockManager: AppLockManager
+
+    private var packageName: String? = null
+    private var label: String? = null
+    private var userId: Int = USER_NULL
+    private var biometricFragment: BiometricFragment? = null
+    private var goingToBackground = false
+    private var waitingForBiometricCallback = false
+
+    private val authenticationCallback = object : AuthenticationCallback() {
+        override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
+            if (!goingToBackground) {
+                waitingForBiometricCallback = false
+                if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED
+                        || errorCode == BiometricPrompt.BIOMETRIC_ERROR_CANCELED) {
+                    finish()
+                }
+            } else if (waitingForBiometricCallback) { // goingToBackground is true
+                waitingForBiometricCallback = false
+                finish()
+            }
+        }
+
+        override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
+            waitingForBiometricCallback = false
+            appLockManager.unlockPackage(packageName)
+            ConfirmDeviceCredentialUtils.checkForPendingIntent(this@AppLockCredentialActivity)
+            setResult(Activity.RESULT_OK)
+            finish()
+        }
+
+        override fun onAuthenticationFailed() {
+            waitingForBiometricCallback = false
+        }
+
+        override fun onSystemEvent(event: Int) {
+            if (event == BiometricConstants.BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL) {
+                finish()
+            }
+        }
+    }
+
+    override protected fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        window.apply {
+            addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
+            statusBarColor = Color.TRANSPARENT
+        }
+
+        appLockManager = AppLockManager.getInstance(this)
+        userManager = UserManager.get(this)
+        lockPatternUtils = LockPatternUtils(this)
+
+        packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)
+        if (packageName == null) {
+            Log.e(TAG, "Failed to get package name, aborting unlock")
+            finish()
+            return
+        }
+
+        label = intent.getStringExtra(AppLockManager.EXTRA_PACKAGE_LABEL)
+
+        userId = intent.getIntExtra(Intent.EXTRA_USER_ID, USER_NULL)
+        if (userId == USER_NULL) {
+            Log.e(TAG, "Invalid user id, aborting")
+            finish()
+            return
+        }
+
+        val biometricsAllowed = intent.getBooleanExtra(
+            AppLockManager.EXTRA_ALLOW_BIOMETRICS,
+            AppLockManager.DEFAULT_BIOMETRICS_ALLOWED
+        )
+        var allowedAuthenticators = Authenticators.DEVICE_CREDENTIAL
+        if (biometricsAllowed) {
+            allowedAuthenticators = allowedAuthenticators or Authenticators.BIOMETRIC_STRONG
+        }
+
+        val promptInfo = PromptInfo().apply {
+            title = getString(com.android.internal.R.string.unlock_application, label)
+            isDisallowBiometricsIfPolicyExists = true
+            authenticators = allowedAuthenticators
+            isAllowBackgroundAuthentication = true
+        }
+
+        if (isBiometricAllowed()) {
+            // Don't need to check if biometrics / pin/pattern/pass are enrolled. It will go to
+            // onAuthenticationError and do the right thing automatically.
+            showBiometricPrompt(promptInfo)
+            waitingForBiometricCallback = true
+        } else {
+            finish()
+        }
+    }
+
+    override protected fun onStart() {
+        super.onStart()
+        // Translucent activity that is "visible", so it doesn't complain about finish()
+        // not being called before onResume().
+        setVisible(true)
+    }
+
+    override fun onPause() {
+        super.onPause()
+        if (!isChangingConfigurations()) {
+            goingToBackground = true
+            if (!waitingForBiometricCallback) {
+                finish()
+            }
+        } else {
+            goingToBackground = false
+        }
+    }
+
+    // User could be locked while Effective user is unlocked even though the effective owns the
+    // credential. Otherwise, biometric can't unlock fbe/keystore through
+    // verifyTiedProfileChallenge. In such case, we also wanna show the user message that
+    // biometric is disabled due to device restart.
+    private fun isStrongAuthRequired() =
+        !lockPatternUtils.isBiometricAllowedForUser(userId) ||
+            !userManager.isUserUnlocked(userId)
+
+    private fun isBiometricAllowed() =
+        !isStrongAuthRequired() && !lockPatternUtils.hasPendingEscrowToken(userId)
+
+    private fun showBiometricPrompt(promptInfo: PromptInfo) {
+        biometricFragment = supportFragmentManager.findFragmentByTag(TAG_BIOMETRIC_FRAGMENT)
+            as? BiometricFragment
+        var newFragment = false
+        if (biometricFragment == null) {
+            biometricFragment = BiometricFragment.newInstance(promptInfo)
+            newFragment = true
+        }
+        biometricFragment?.also {
+            it.setCallbacks({
+                handler.post(it)
+            }, authenticationCallback)
+            it.setUser(userId)
+        }
+        if (newFragment) {
+            biometricFragment?.let {
+                supportFragmentManager.commit {
+                    add(it, TAG_BIOMETRIC_FRAGMENT)
+                }
+            }
+        }
+    }
+
+    companion object {
+        private const val TAG = "AppLockCredentialActivity"
+        private const val TAG_BIOMETRIC_FRAGMENT = "fragment"
+    }
+}
diff --git a/src/com/android/settings/security/applock/AppLockHideAppPC.kt b/src/com/android/settings/security/applock/AppLockHideAppPC.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c85a333bca8b19ed5632f948b9ad2f213af7874c
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockHideAppPC.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import android.content.Context
+
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+
+import com.libremobileos.applock.AppLockManager
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+private const val KEY = "hide_from_launcher"
+
+class AppLockHideAppPC(
+    context: Context,
+    private val packageName: String,
+    private val coroutineScope: CoroutineScope
+) : AppLockTogglePreferenceController(context, KEY) {
+
+    private val appLockManager by lazy { AppLockManager.getInstance(context) }
+    private var hideFromLauncher = AppLockManager.DEFAULT_HIDE_IN_LAUNCHER
+    private var preference: Preference? = null
+
+    init {
+        coroutineScope.launch {
+            hideFromLauncher = withContext(Dispatchers.Default) {
+                appLockManager.hiddenPackages.any { it == packageName }
+            }
+            preference?.let {
+                updateState(it)
+            }
+        }
+    }
+
+    override fun getAvailabilityStatus() = AVAILABLE
+
+    override fun isChecked() = hideFromLauncher
+
+    override fun setChecked(checked: Boolean): Boolean {
+        if (hideFromLauncher == checked) return false
+        hideFromLauncher = checked
+        coroutineScope.launch(Dispatchers.Default) {
+            appLockManager.setPackageHidden(packageName, hideFromLauncher)
+        }
+        return true
+    }
+
+    override fun displayPreference(screen: PreferenceScreen) {
+        super.displayPreference(screen)
+        preference = screen.findPreference(preferenceKey)
+    }
+}
diff --git a/src/com/android/settings/security/applock/AppLockNotificationRedactionPC.kt b/src/com/android/settings/security/applock/AppLockNotificationRedactionPC.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0ea2a7d5e13c0aa5be5b19e6dc77af38364ab077
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockNotificationRedactionPC.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import android.content.Context
+
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+
+import com.libremobileos.applock.AppLockManager
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+private const val KEY = "redact_notifications"
+
+class AppLockNotificationRedactionPC(
+    context: Context,
+    private val packageName: String,
+    private val coroutineScope: CoroutineScope
+) : AppLockTogglePreferenceController(context, KEY) {
+
+    private val appLockManager by lazy {
+        AppLockManager.getInstance(context)
+    }
+    private var shouldRedactNotification = AppLockManager.DEFAULT_REDACT_NOTIFICATION
+    private var preference: Preference? = null
+
+    init {
+        coroutineScope.launch {
+            shouldRedactNotification = withContext(Dispatchers.Default) {
+                appLockManager.packageData.find {
+                    it.packageName == packageName
+                }?.shouldRedactNotification == true
+            }
+            preference?.let {
+                updateState(it)
+            }
+        }
+    }
+
+    override fun getAvailabilityStatus() = AVAILABLE
+
+    override fun isChecked() = shouldRedactNotification
+
+    override fun setChecked(checked: Boolean): Boolean {
+        if (shouldRedactNotification == checked) return false
+        shouldRedactNotification = checked
+        coroutineScope.launch(Dispatchers.Default) {
+            appLockManager.setShouldRedactNotification(packageName, checked)
+        }
+        return true
+    }
+
+    override fun displayPreference(screen: PreferenceScreen) {
+        super.displayPreference(screen)
+        preference = screen.findPreference(preferenceKey)
+    }
+}
diff --git a/src/com/android/settings/security/applock/AppLockPackageConfigFragment.kt b/src/com/android/settings/security/applock/AppLockPackageConfigFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c2b139a8583591e1fe59756c2e64fe5c53ebc956
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockPackageConfigFragment.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import android.content.Context
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.os.Bundle
+
+import androidx.lifecycle.lifecycleScope
+
+import com.android.internal.logging.nano.MetricsProto
+
+import com.android.settings.R
+import com.android.settings.dashboard.DashboardFragment
+import com.android.settings.widget.EntityHeaderController
+import com.android.settingslib.applications.ApplicationsState.AppEntry
+import com.android.settingslib.core.AbstractPreferenceController
+import com.android.settingslib.widget.LayoutPreference
+
+private val TAG = AppLockPackageConfigFragment::class.simpleName
+private const val KEY_HEADER = "header_view"
+
+class AppLockPackageConfigFragment : DashboardFragment() {
+
+    private lateinit var packageInfo: PackageInfo
+
+    override fun onAttach(context: Context) {
+        packageInfo = arguments?.getParcelable(PACKAGE_INFO, PackageInfo::class.java)!!
+        super.onAttach(context)
+    }
+
+    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+        super.onCreatePreferences(savedInstanceState, rootKey)
+        val appEntry = AppEntry(requireContext(), packageInfo.applicationInfo, 0)
+        val header = preferenceScreen.findPreference<LayoutPreference>(KEY_HEADER)
+        EntityHeaderController.newInstance(
+            requireActivity(),
+            this,
+            header?.findViewById(R.id.entity_header)
+        ).setRecyclerView(listView, settingsLifecycle)
+            .setPackageName(packageInfo.packageName)
+            .setButtonActions(
+                EntityHeaderController.ActionType.ACTION_NONE,
+                EntityHeaderController.ActionType.ACTION_NONE
+            )
+            .bindHeaderButtons()
+            .setLabel(appEntry)
+            .setIcon(appEntry)
+            .done(requireActivity(), false /* rebindActions */)
+    }
+
+    override protected fun createPreferenceControllers(
+        context: Context
+    ) : List<AbstractPreferenceController> = listOf(
+        AppLockPackageProtectionPC(context, packageInfo.packageName, lifecycleScope),
+        AppLockNotificationRedactionPC(context, packageInfo.packageName, lifecycleScope),
+        AppLockHideAppPC(context, packageInfo.packageName, lifecycleScope)
+    )
+
+    override fun getMetricsCategory(): Int = MetricsProto.MetricsEvent.LMODROID
+
+    override protected fun getPreferenceScreenResId() = R.xml.app_lock_package_config_settings
+
+    override protected fun getLogTag() = TAG
+}
diff --git a/src/com/android/settings/security/applock/AppLockPackageListFragment.kt b/src/com/android/settings/security/applock/AppLockPackageListFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..080038f86f982238c1b08ca1a1327278a7c82244
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockPackageListFragment.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import android.content.Context
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.PackageInfoFlags
+import android.os.Bundle
+import android.view.View
+
+import androidx.lifecycle.lifecycleScope
+import androidx.preference.Preference
+import androidx.preference.forEach
+
+import com.android.internal.logging.nano.MetricsProto
+
+import com.android.settings.R
+import com.android.settings.core.SubSettingLauncher
+import com.android.settings.dashboard.DashboardFragment
+import com.android.settingslib.PrimarySwitchPreference
+import com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_SMALL
+
+import com.libremobileos.applock.AppLockManager
+
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+private val TAG = AppLockPackageListFragment::class.simpleName
+internal const val PACKAGE_INFO = "package_info"
+
+class AppLockPackageListFragment : DashboardFragment() {
+
+    private lateinit var appLockManager: AppLockManager
+    private lateinit var pm: PackageManager
+    private lateinit var whiteListedPackages: Array<String>
+
+    override fun onAttach(context: Context) {
+        super.onAttach(context)
+        appLockManager = AppLockManager.getInstance(context)
+        pm = context.packageManager
+        whiteListedPackages = resources.getStringArray(
+            com.android.internal.R.array.config_appLockAllowedSystemApps)
+    }
+
+    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+        super.onCreatePreferences(savedInstanceState, rootKey)
+        lifecycleScope.launch {
+            val selectedPackages = getSelectedPackages()
+            val preferences = withContext(Dispatchers.Default) {
+                pm.getInstalledPackages(
+                    PackageInfoFlags.of(PackageManager.MATCH_ALL.toLong())
+                ).filter {
+                    !it.applicationInfo.isSystemApp() || whiteListedPackages.contains(it.packageName)
+                }.sortedWith { first, second ->
+                    getLabel(first).compareTo(getLabel(second))
+                }
+            }.map { packageInfo ->
+                createPreference(packageInfo, selectedPackages.contains(packageInfo.packageName))
+            }
+            preferenceScreen?.let {
+                preferences.forEach { pref ->
+                    it.addPreference(pref)
+                }
+            }
+        }
+    }
+
+    override fun onResume() {
+        super.onResume()
+        lifecycleScope.launch {
+            val selectedPackages = getSelectedPackages()
+            preferenceScreen?.forEach {
+                if (it is PrimarySwitchPreference) {
+                    it.isChecked = selectedPackages.contains(it.key)
+                }
+            }
+        }
+    }
+
+    private suspend fun getSelectedPackages(): Set<String> {
+        return withContext(Dispatchers.IO) {
+            appLockManager.packageData.map { it.packageName }.toSet()
+        }
+    }
+
+    private fun getLabel(packageInfo: PackageInfo) =
+        packageInfo.applicationInfo.loadLabel(pm).toString()
+
+    private fun createPreference(packageInfo: PackageInfo, isProtected: Boolean): Preference {
+        val label = getLabel(packageInfo)
+        return PrimarySwitchPreference(requireContext()).apply {
+            key = packageInfo.packageName
+            title = label
+            icon = packageInfo.applicationInfo.loadIcon(pm)
+            setIconSize(ICON_SIZE_SMALL)
+            isChecked = isProtected
+            setOnPreferenceChangeListener { _, newValue ->
+                lifecycleScope.launch(Dispatchers.IO) {
+                    if (newValue as Boolean) {
+                        appLockManager.addPackage(packageInfo.packageName)
+                    } else {
+                        appLockManager.removePackage(packageInfo.packageName)
+                    }
+                }
+                return@setOnPreferenceChangeListener true
+            }
+            setOnPreferenceClickListener {
+                SubSettingLauncher(requireContext())
+                    .setDestination(AppLockPackageConfigFragment::class.qualifiedName)
+                    .setSourceMetricsCategory(metricsCategory)
+                    .setTitleText(label)
+                    .setArguments(
+                        Bundle(1).apply {
+                            putParcelable(PACKAGE_INFO, packageInfo)
+                        }
+                    )
+                    .launch()
+                true
+            }
+        }
+    }
+
+    override fun getMetricsCategory(): Int = MetricsProto.MetricsEvent.LMODROID
+
+    override protected fun getPreferenceScreenResId() = R.xml.app_lock_package_list_settings
+
+    override protected fun getLogTag() = TAG
+}
diff --git a/src/com/android/settings/security/applock/AppLockPackageProtectionPC.kt b/src/com/android/settings/security/applock/AppLockPackageProtectionPC.kt
new file mode 100644
index 0000000000000000000000000000000000000000..08704a318e06349bb7b151c2a27c0a192e555f35
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockPackageProtectionPC.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import android.content.Context
+
+import androidx.lifecycle.lifecycleScope
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+
+import com.libremobileos.applock.AppLockManager
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+private const val KEY = "main_switch"
+
+class AppLockPackageProtectionPC(
+    context: Context,
+    private val packageName: String,
+    private val coroutineScope: CoroutineScope
+) : AppLockTogglePreferenceController(context, KEY) {
+
+    private val appLockManager by lazy { AppLockManager.getInstance(context) }
+    private var isProtected = false
+    private var preference: Preference? = null
+
+    init {
+        coroutineScope.launch {
+            isProtected = withContext(Dispatchers.Default) {
+                appLockManager.packageData.any {
+                    it.packageName == packageName
+                }
+            }
+            preference?.let {
+                updateState(it)
+            }
+        }
+    }
+
+    override fun getAvailabilityStatus() = AVAILABLE
+
+    override fun isChecked() = isProtected
+
+    override fun setChecked(checked: Boolean): Boolean {
+        if (isProtected == checked) return false
+        isProtected = checked
+        coroutineScope.launch(Dispatchers.Default) {
+            if (isProtected) {
+                appLockManager.addPackage(packageName)
+            } else {
+                appLockManager.removePackage(packageName)
+            }
+        }
+        return true
+    }
+
+    override fun displayPreference(screen: PreferenceScreen) {
+        super.displayPreference(screen)
+        preference = screen.findPreference(preferenceKey)
+    }
+}
diff --git a/src/com/android/settings/security/applock/AppLockSettingsFragment.kt b/src/com/android/settings/security/applock/AppLockSettingsFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b1233ca67b03ef6b4770afdd06a90b624d0a7e1e
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockSettingsFragment.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import android.content.Context
+import android.os.SystemProperties
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+
+import com.android.internal.logging.nano.MetricsProto
+import androidx.lifecycle.lifecycleScope
+
+import com.android.settings.R
+import com.android.settings.dashboard.DashboardFragment
+import com.android.settings.search.BaseSearchIndexProvider
+import com.android.settingslib.core.AbstractPreferenceController
+import com.android.settingslib.search.SearchIndexable
+
+@SearchIndexable
+class AppLockSettingsFragment : DashboardFragment(),
+    MenuItem.OnMenuItemClickListener {
+
+    private var debugEnabled = SystemProperties.get(DEBUG_PROPERTY, null) == LEVEL_DEBUG
+    private var handledClick = false
+
+    override protected fun getPreferenceScreenResId() = R.xml.app_lock_settings
+
+    override fun getMetricsCategory() = MetricsProto.MetricsEvent.LMODROID
+
+    override protected fun getLogTag() = TAG
+
+    override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
+        super.onCreateOptionsMenu(menu, menuInflater)
+        menu.add(
+            0 /* groupId */,
+            MENU_ITEM_DEBUG_ID,
+            0 /* order */,
+            getDebugMenuItemTitle(),
+        ).setOnMenuItemClickListener(this)
+    }
+
+    private fun getDebugMenuItemTitle(): Int =
+        if (debugEnabled) R.string.disable_debugging else R.string.enable_debugging
+
+    override fun onMenuItemClick(item: MenuItem): Boolean {
+        if (item.itemId == MENU_ITEM_DEBUG_ID) {
+            debugEnabled = !debugEnabled
+            SystemProperties.set(DEBUG_PROPERTY, if (debugEnabled) LEVEL_DEBUG else null)
+            item.setTitle(getDebugMenuItemTitle())
+            return true
+        }
+        return false
+    }
+
+    override protected fun createPreferenceControllers(
+        context: Context
+    ) : List<AbstractPreferenceController> = listOf(
+        AppLockBiometricPreferenceController(context, lifecycleScope)
+    )
+
+    companion object {
+        private const val TAG = "AppLockSettingsFragment"
+
+        private const val DEBUG_PROPERTY = "log.tag.AppLockManagerService"
+        private const val LEVEL_DEBUG = "DEBUG"
+        private const val MENU_ITEM_DEBUG_ID = 101
+
+        @JvmField
+        val SEARCH_INDEX_DATA_PROVIDER = BaseSearchIndexProvider(R.xml.app_lock_settings)
+    }
+}
diff --git a/src/com/android/settings/security/applock/AppLockSettingsPreferenceController.kt b/src/com/android/settings/security/applock/AppLockSettingsPreferenceController.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0e611b12e726717a062aec853ee7ca836c7fb2bf
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockSettingsPreferenceController.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import android.app.Activity
+import android.app.KeyguardManager
+import android.content.Context
+import android.content.Intent
+import android.os.UserHandle
+
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
+import androidx.lifecycle.Lifecycle.Event
+import androidx.lifecycle.LifecycleEventObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+
+import com.android.internal.widget.LockPatternUtils
+import com.android.settings.R
+import com.android.settings.SettingsPreferenceFragment
+import com.android.settings.Utils.SETTINGS_PACKAGE_NAME
+import com.android.settings.core.SubSettingLauncher
+import com.android.settings.password.ConfirmDeviceCredentialActivity
+import com.android.settingslib.core.lifecycle.Lifecycle
+import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE
+import com.android.settings.core.BasePreferenceController
+
+import com.android.settings.SettingsActivity
+import com.android.settings.core.SettingsBaseActivity
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider
+
+import com.libremobileos.applock.AppLockManager
+
+class AppLockSettingsPreferenceController(
+    context: Context,
+    preferenceKey: String,
+    private val host: SettingsPreferenceFragment?,
+    lifecycle: Lifecycle?,
+) : BasePreferenceController(context, preferenceKey),
+    LifecycleEventObserver {
+
+    private val lockPatternUtils = LockPatternUtils(context)
+    private val appLockManager by lazy { AppLockManager.getInstance(context) }
+    private var preference: Preference? = null
+    private val securityPromptLauncher: ActivityResultLauncher<Intent>?
+
+    init {
+        lifecycle?.addObserver(this)
+        securityPromptLauncher = host?.registerForActivityResult(
+            StartActivityForResult()
+        ) {
+            if (it?.resultCode == Activity.RESULT_OK) {
+                val intent = SubSettingLauncher(mContext)
+                    .setDestination(AppLockSettingsFragment::class.qualifiedName)
+                    .setSourceMetricsCategory(host.metricsCategory)
+                    .setTransitionType(TRANSITION_SLIDE)
+                    .toIntent()
+                intent.setClass(mContext, AppLockSubSettings::class.java)
+                mContext.startActivity(intent)
+            }
+        }
+    }
+
+    override fun getAvailabilityStatus() =
+        if (lockPatternUtils.isSecure(UserHandle.myUserId()))
+            AVAILABLE
+        else
+            DISABLED_DEPENDENT_SETTING
+
+    override fun onStateChanged(owner: LifecycleOwner, event: Event) {
+        if (event == Event.ON_START) {
+            preference?.let {
+                updateState(it)
+            }
+        }
+    }
+
+    override fun displayPreference(screen: PreferenceScreen) {
+        super.displayPreference(screen)
+        preference = screen.findPreference(preferenceKey)
+    }
+
+    override fun updateState(preference: Preference) {
+        preference.apply {
+            if (getAvailabilityStatus() == AVAILABLE) {
+                setEnabled(true)
+                summary = getSummaryForListSize(appLockManager.packageData.size)
+            } else {
+                setEnabled(false)
+                summary = mContext.getString(R.string.disabled_because_no_backup_security)
+            }
+        }
+    }
+
+    private fun getSummaryForListSize(size: Int): CharSequence? =
+        if (size == 0) {
+            null
+        } else {
+            mContext.resources.getQuantityString(R.plurals.app_lock_summary, size, size)
+        }
+
+    override fun handlePreferenceTreeClick(preference: Preference): Boolean {
+        if (preference.key == preferenceKey && securityPromptLauncher != null) {
+            val title = mContext.getString(R.string.app_lock_authentication_dialog_title)
+            val intent = Intent().apply {
+                setClassName(SETTINGS_PACKAGE_NAME,
+                        ConfirmDeviceCredentialActivity::class.qualifiedName)
+                putExtra(KeyguardManager.EXTRA_TITLE, title)
+            }
+            securityPromptLauncher.launch(intent)
+            return true
+        }
+        return super.handlePreferenceTreeClick(preference)
+    }
+
+}
diff --git a/src/com/android/settings/security/applock/AppLockSubSettings.kt b/src/com/android/settings/security/applock/AppLockSubSettings.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e376f1696d03a6f4f71f1fb2c90188981071d2e3
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockSubSettings.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import com.android.settings.SettingsActivity
+
+class AppLockSubSettings : SettingsActivity() {
+
+    override protected fun isValidFragment(fragmentName: String): Boolean {
+        return AppLockSettingsFragment::class.qualifiedName == fragmentName
+    }
+}
diff --git a/src/com/android/settings/security/applock/AppLockTimeoutPreferenceController.kt b/src/com/android/settings/security/applock/AppLockTimeoutPreferenceController.kt
new file mode 100644
index 0000000000000000000000000000000000000000..30a91b3d43d2fff446cfa4bd3b157fca367ad4a0
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockTimeoutPreferenceController.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock
+
+import android.content.Context
+
+import androidx.preference.ListPreference
+import androidx.preference.Preference
+
+import com.android.settings.core.BasePreferenceController
+
+import com.libremobileos.applock.AppLockManager
+
+class AppLockTimeoutPreferenceController(
+    context: Context,
+    key: String,
+) : BasePreferenceController(context, key),
+    Preference.OnPreferenceChangeListener {
+
+    private val appLockManager by lazy { AppLockManager.getInstance(context) }
+
+    override fun getAvailabilityStatus() = AVAILABLE
+
+    override fun updateState(preference: Preference) {
+        (preference as ListPreference).value = appLockManager.timeout.takeIf {
+            it != -1L
+        }?.toString()
+    }
+
+    override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean {
+        appLockManager.timeout = (newValue as String).toLong()
+        return true
+    }
+}
diff --git a/src/com/android/settings/security/applock/AppLockTogglePreferenceController.kt b/src/com/android/settings/security/applock/AppLockTogglePreferenceController.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3564110e43fc25228a23a2089d890b6995c0107b
--- /dev/null
+++ b/src/com/android/settings/security/applock/AppLockTogglePreferenceController.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 FlamingoOS 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.applock;
+
+import android.content.Context
+import android.widget.Switch
+
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+
+import com.android.settings.R
+import com.android.settings.core.TogglePreferenceController
+import com.android.settingslib.widget.MainSwitchPreference
+import com.android.settingslib.widget.OnMainSwitchChangeListener
+
+abstract class AppLockTogglePreferenceController(
+    context: Context,
+    key: String,
+) : TogglePreferenceController(context, key),
+    OnMainSwitchChangeListener {
+
+    override fun displayPreference(screen: PreferenceScreen) {
+        super.displayPreference(screen)
+        val preference = screen.findPreference<Preference>(preferenceKey) ?: return
+        if (preference is MainSwitchPreference) {
+            preference.addOnSwitchChangeListener(this)
+        }
+    }
+
+    override fun onSwitchChanged(switchView: Switch, isChecked: Boolean) {
+        setChecked(isChecked)
+    }
+
+    override fun getSliceHighlightMenuRes() = R.string.menu_key_security
+}
\ No newline at end of file