diff --git a/res/values/cherish_arrays.xml b/res/values/cherish_arrays.xml
index 6684822..0bc3db5 100644
--- a/res/values/cherish_arrays.xml
+++ b/res/values/cherish_arrays.xml
@@ -465,4 +465,25 @@
- 1
- 2
+
+
+
+ - 5 seconds
+ - 10 seconds
+ - 30 seconds
+ - 1 minute
+ - 5 minutes
+ - 10 minutes
+ - 30 minutes
+
+
+
+ - 5000
+ - 10000
+ - 30000
+ - 60000
+ - 300000
+ - 600000
+ - 1800000
+
diff --git a/res/values/cherish_strings.xml b/res/values/cherish_strings.xml
index cbdc356..6a4cb99 100644
--- a/res/values/cherish_strings.xml
+++ b/res/values/cherish_strings.xml
@@ -696,5 +696,25 @@
Double tap power button (slower single tap response), Disables double power tap for camera.
Jump to camera gesture is now disabled
Long press power button
+
+
+ App lock
+ 1 application is protected
+ %1$d applications are protected
+ Unlock
+ Enable debugging
+ Disable debugging
+ Protected apps
+ Select the apps to protect with biometrics or device credentials
+ Auto lock timeout
+ Duration of time after which an unlocked app in background should be locked
+ Collapse notifications
+
+ Notification content will be hidden and collapsed for selected apps when they are locked.
+ Heads up notifications will be automatically disabled.
+
+ Protect an application first
+ Enable biometrics for unlocking
+ Bubbles will be automatically dismissed after timeout
diff --git a/res/xml/app_lock_settings.xml b/res/xml/app_lock_settings.xml
new file mode 100644
index 0000000..97626fe
--- /dev/null
+++ b/res/xml/app_lock_settings.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/com/cherish/settings/security/applock/AppLockBiometricPreferenceController.kt b/src/com/cherish/settings/security/applock/AppLockBiometricPreferenceController.kt
new file mode 100644
index 0000000..1887b82
--- /dev/null
+++ b/src/com/cherish/settings/security/applock/AppLockBiometricPreferenceController.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 cherishOS 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.cherish.settings.security.applock
+
+import android.app.AppLockManager
+import android.content.Context
+import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricManager.Authenticators
+
+import androidx.preference.Preference
+import androidx.preference.SwitchPreference
+
+import com.android.settings.core.BasePreferenceController
+
+class AppLockBiometricPreferenceController(
+ context: Context,
+ key: String,
+) : BasePreferenceController(context, key),
+ Preference.OnPreferenceChangeListener {
+
+ private val appLockManager = context.getSystemService(AppLockManager::class.java)
+ private val biometricManager = context.getSystemService(BiometricManager::class.java)
+
+ override fun getAvailabilityStatus(): Int {
+ val biometricsAllowed = biometricManager.canAuthenticate(
+ Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS
+ return if (biometricsAllowed)
+ AVAILABLE
+ else
+ UNSUPPORTED_ON_DEVICE
+ }
+
+ override fun updateState(preference: Preference) {
+ (preference as SwitchPreference).setChecked(appLockManager.isBiometricsAllowed())
+ }
+
+ override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean {
+ appLockManager.setBiometricsAllowed(newValue as Boolean)
+ return true
+ }
+}
\ No newline at end of file
diff --git a/src/com/cherish/settings/security/applock/AppLockCredentialActivity.kt b/src/com/cherish/settings/security/applock/AppLockCredentialActivity.kt
new file mode 100644
index 0000000..b946e5d
--- /dev/null
+++ b/src/com/cherish/settings/security/applock/AppLockCredentialActivity.kt
@@ -0,0 +1,204 @@
+/*
+ * 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.cherish.settings.security.applock
+
+import android.app.Activity
+import android.app.AppLockManager
+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
+
+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 title: 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 = getSystemService(AppLockManager::class.java)
+ 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
+ }
+
+ title = 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 authenticators = Authenticators.DEVICE_CREDENTIAL
+ if (biometricsAllowed) {
+ authenticators = authenticators or Authenticators.BIOMETRIC_STRONG
+ }
+
+ val promptInfo = PromptInfo().also {
+ it.title = getString(com.android.internal.R.string.unlock_application, title)
+ it.isDisallowBiometricsIfPolicyExists = true
+ it.authenticators = authenticators
+ }
+
+ 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/cherish/settings/security/applock/AppLockNotificationListFragment.kt b/src/com/cherish/settings/security/applock/AppLockNotificationListFragment.kt
new file mode 100644
index 0000000..2383807
--- /dev/null
+++ b/src/com/cherish/settings/security/applock/AppLockNotificationListFragment.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.cherish.settings.security.applock
+
+import android.app.AppLockManager
+import android.os.Bundle
+import android.view.View
+
+import com.android.settings.R
+import com.cherish.settings.fragment.AppListFragment
+
+class AppLockNotificationListFragment : AppListFragment() {
+
+ private lateinit var appLockManager: AppLockManager
+ private val lockedPackages = mutableListOf()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ appLockManager = requireContext().getSystemService(AppLockManager::class.java)
+ lockedPackages.addAll(appLockManager.packages)
+ }
+
+ override protected fun getTitle(): Int = R.string.app_lock_notifications_title
+
+ override protected fun getInitialCheckedList(): List =
+ appLockManager.packagesWithSecureNotifications
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ setDisplayCategory(CATEGORY_BOTH)
+ setCustomFilter {
+ lockedPackages.contains(it.packageName)
+ }
+ super.onViewCreated(view, savedInstanceState)
+ }
+
+ override protected fun onAppSelected(packageName: String) {
+ appLockManager.setSecureNotification(packageName, true)
+ }
+
+ override protected fun onAppDeselected(packageName: String) {
+ appLockManager.setSecureNotification(packageName, false)
+ }
+}
\ No newline at end of file
diff --git a/src/com/cherish/settings/security/applock/AppLockNotificationPreferenceController.kt b/src/com/cherish/settings/security/applock/AppLockNotificationPreferenceController.kt
new file mode 100644
index 0000000..a5308eb
--- /dev/null
+++ b/src/com/cherish/settings/security/applock/AppLockNotificationPreferenceController.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.cherish.settings.security.applock
+
+import android.app.AppLockManager
+import android.content.Context
+import android.os.UserHandle
+
+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.settingslib.core.lifecycle.Lifecycle
+import com.android.settings.core.BasePreferenceController
+
+class AppLockNotificationPreferenceController(
+ private val context: Context,
+ lifecycle: Lifecycle?,
+) : BasePreferenceController(context, KEY),
+ LifecycleEventObserver {
+
+ private val appLockManager = context.getSystemService(AppLockManager::class.java)
+
+ private var preference: Preference? = null
+
+ init {
+ lifecycle?.addObserver(this)
+ }
+
+ override fun getAvailabilityStatus() =
+ if (appLockManager.packages.isNotEmpty()) 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) {
+ if (getAvailabilityStatus() == AVAILABLE) {
+ preference.setEnabled(true)
+ preference.summary = context.getString(R.string.app_lock_notifications_summary)
+ } else {
+ preference.setEnabled(false)
+ preference.summary = context.getString(R.string.app_lock_notifications_disabled_summary)
+ }
+ }
+
+ companion object {
+ private const val KEY = "app_lock_notifications"
+ }
+}
\ No newline at end of file
diff --git a/src/com/cherish/settings/security/applock/AppLockPackageListFragment.kt b/src/com/cherish/settings/security/applock/AppLockPackageListFragment.kt
new file mode 100644
index 0000000..c274b3b
--- /dev/null
+++ b/src/com/cherish/settings/security/applock/AppLockPackageListFragment.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.cherish.settings.security.applock
+
+import android.app.AppLockManager
+import android.os.Bundle
+import android.view.View
+
+import com.android.settings.R
+import com.cherish.settings.fragment.AppListFragment
+
+class AppLockPackageListFragment : AppListFragment() {
+
+ private lateinit var appLockManager: AppLockManager
+ private lateinit var whiteListedPackages: Array
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ appLockManager = requireContext().getSystemService(AppLockManager::class.java)
+ whiteListedPackages = requireContext().resources.getStringArray(
+ com.android.internal.R.array.config_appLockAllowedSystemApps)
+ }
+
+ override protected fun getTitle(): Int = R.string.app_lock_packages_title
+
+ override protected fun getInitialCheckedList(): List = appLockManager.packages
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ setDisplayCategory(CATEGORY_BOTH)
+ setCustomFilter {
+ !it.applicationInfo.isSystemApp() || whiteListedPackages.contains(it.packageName)
+ }
+ super.onViewCreated(view, savedInstanceState)
+ }
+
+ override protected fun onAppSelected(packageName: String) {
+ appLockManager.addPackage(packageName)
+ }
+
+ override protected fun onAppDeselected(packageName: String) {
+ appLockManager.removePackage(packageName)
+ }
+}
\ No newline at end of file
diff --git a/src/com/cherish/settings/security/applock/AppLockSettingsFragment.kt b/src/com/cherish/settings/security/applock/AppLockSettingsFragment.kt
new file mode 100644
index 0000000..92c85d0
--- /dev/null
+++ b/src/com/cherish/settings/security/applock/AppLockSettingsFragment.kt
@@ -0,0 +1,101 @@
+/*
+ * 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.cherish.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 com.android.settings.R
+import com.android.settings.search.BaseSearchIndexProvider
+import com.android.settingslib.core.AbstractPreferenceController
+import com.android.settingslib.core.lifecycle.Lifecycle
+import com.android.settingslib.search.SearchIndexable
+import com.android.settings.dashboard.DashboardFragment
+
+@SearchIndexable
+class AppLockSettingsFragment : DashboardFragment(),
+ MenuItem.OnMenuItemClickListener {
+
+ private var debugEnabled = SystemProperties.get(DEBUG_PROPERTY, null) == LEVEL_DEBUG
+
+ override protected fun getPreferenceScreenResId() = R.xml.app_lock_settings
+
+ override fun getMetricsCategory() = MetricsProto.MetricsEvent.CHERISH_SETTINGS
+
+ override protected fun getLogTag() = TAG
+
+ override protected fun createPreferenceControllers(context: Context) =
+ buildPreferenceControllers(context, settingsLifecycle)
+
+ 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
+ }
+
+ 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 = object : BaseSearchIndexProvider(
+ R.xml.app_lock_settings
+ ) {
+ override fun createPreferenceControllers(context: Context) =
+ buildPreferenceControllers(context)
+ }
+
+ fun buildPreferenceControllers(
+ context: Context,
+ lifecycle: Lifecycle? = null
+ ): List =
+ listOf(
+ AppLockNotificationPreferenceController(
+ context,
+ lifecycle,
+ )
+ )
+ }
+}
diff --git a/src/com/cherish/settings/security/applock/AppLockSettingsPreferenceController.kt b/src/com/cherish/settings/security/applock/AppLockSettingsPreferenceController.kt
new file mode 100644
index 0000000..bcf0b82
--- /dev/null
+++ b/src/com/cherish/settings/security/applock/AppLockSettingsPreferenceController.kt
@@ -0,0 +1,122 @@
+/*
+ * 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.cherish.settings.security.applock
+
+import android.app.Activity
+import android.app.AppLockManager
+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.core.SubSettingLauncher
+import com.android.settings.password.ConfirmDeviceCredentialActivity
+import com.android.settings.security.SecuritySettings
+import com.android.settingslib.core.lifecycle.Lifecycle
+import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType
+import com.android.settings.core.BasePreferenceController
+
+class AppLockSettingsPreferenceController(
+ context: Context,
+ preferenceKey: String,
+ private val host: SecuritySettings?,
+ lifecycle: Lifecycle?,
+) : BasePreferenceController(context, preferenceKey),
+ LifecycleEventObserver {
+
+ private val lockPatternUtils = LockPatternUtils(context)
+ private val appLockManager = context.getSystemService(AppLockManager::class.java)
+ private var preference: Preference? = null
+ private val securityPromptLauncher: ActivityResultLauncher?
+
+ init {
+ lifecycle?.addObserver(this)
+ securityPromptLauncher = host?.registerForActivityResult(
+ StartActivityForResult()
+ ) {
+ if (it?.resultCode == Activity.RESULT_OK) {
+ SubSettingLauncher(mContext)
+ .setDestination(AppLockSettingsFragment::class.qualifiedName)
+ .setSourceMetricsCategory(host.metricsCategory)
+ .setTransitionType(TransitionType.TRANSITION_SLIDE)
+ .addFlags(
+ Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS or
+ Intent.FLAG_ACTIVITY_NEW_TASK
+ )
+ .launch()
+ }
+ }
+ }
+
+ 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) {
+ if (getAvailabilityStatus() == AVAILABLE) {
+ preference.setEnabled(true)
+ preference.summary = getSummaryForListSize(appLockManager.getPackages().size)
+ } else {
+ preference.setEnabled(false)
+ preference.summary = mContext.getString(R.string.disabled_because_no_backup_security)
+ }
+ }
+
+ private fun getSummaryForListSize(size: Int): CharSequence? =
+ when {
+ size == 0 -> null
+ size == 1 -> mContext.getString(R.string.app_lock_summary_singular)
+ else -> mContext.getString(R.string.app_lock_summary_plural, size)
+ }
+
+ override fun handlePreferenceTreeClick(preference: Preference): Boolean {
+ if (preference.key == preferenceKey && securityPromptLauncher != null) {
+ securityPromptLauncher.launch(
+ ConfirmDeviceCredentialActivity.createIntent(
+ mContext.getString(R.string.app_lock_authentication_dialog_title),
+ null /* details */,
+ )
+ )
+ return true
+ }
+ return super.handlePreferenceTreeClick(preference)
+ }
+}
\ No newline at end of file
diff --git a/src/com/cherish/settings/security/applock/AppLockTimeoutPreferenceController.kt b/src/com/cherish/settings/security/applock/AppLockTimeoutPreferenceController.kt
new file mode 100644
index 0000000..ba23eca
--- /dev/null
+++ b/src/com/cherish/settings/security/applock/AppLockTimeoutPreferenceController.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.cherish.settings.security.applock
+
+import android.app.AppLockManager
+import android.content.Context
+
+import androidx.preference.ListPreference
+import androidx.preference.Preference
+
+import com.android.settings.core.BasePreferenceController
+
+class AppLockTimeoutPreferenceController(
+ context: Context,
+ key: String,
+) : BasePreferenceController(context, key),
+ Preference.OnPreferenceChangeListener {
+
+ private val appLockManager = context.getSystemService(AppLockManager::class.java)
+
+ 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
+ }
+}
\ No newline at end of file