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