Merge "Move trigger for dialog to change controls settings" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
7dc6120c1a
@@ -19,7 +19,7 @@ package com.android.systemui.controls.dagger
|
||||
import android.content.Context
|
||||
import com.android.internal.widget.LockPatternUtils
|
||||
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
|
||||
import com.android.systemui.controls.ControlsSettingsRepository
|
||||
import com.android.systemui.controls.settings.ControlsSettingsRepository
|
||||
import com.android.systemui.controls.controller.ControlsController
|
||||
import com.android.systemui.controls.controller.ControlsTileResourceConfiguration
|
||||
import com.android.systemui.controls.controller.ControlsTileResourceConfigurationImpl
|
||||
|
||||
@@ -20,8 +20,8 @@ import android.app.Activity
|
||||
import android.content.pm.PackageManager
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.controls.ControlsMetricsLoggerImpl
|
||||
import com.android.systemui.controls.ControlsSettingsRepository
|
||||
import com.android.systemui.controls.ControlsSettingsRepositoryImpl
|
||||
import com.android.systemui.controls.settings.ControlsSettingsRepository
|
||||
import com.android.systemui.controls.settings.ControlsSettingsRepositoryImpl
|
||||
import com.android.systemui.controls.controller.ControlsBindingController
|
||||
import com.android.systemui.controls.controller.ControlsBindingControllerImpl
|
||||
import com.android.systemui.controls.controller.ControlsController
|
||||
@@ -34,6 +34,8 @@ import com.android.systemui.controls.management.ControlsListingController
|
||||
import com.android.systemui.controls.management.ControlsListingControllerImpl
|
||||
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
|
||||
import com.android.systemui.controls.management.ControlsRequestDialog
|
||||
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
|
||||
import com.android.systemui.controls.settings.ControlsSettingsDialogManagerImpl
|
||||
import com.android.systemui.controls.ui.ControlActionCoordinator
|
||||
import com.android.systemui.controls.ui.ControlActionCoordinatorImpl
|
||||
import com.android.systemui.controls.ui.ControlsActivity
|
||||
@@ -89,6 +91,11 @@ abstract class ControlsModule {
|
||||
manager: ControlsSettingsRepositoryImpl
|
||||
): ControlsSettingsRepository
|
||||
|
||||
@Binds
|
||||
abstract fun provideDialogManager(
|
||||
manager: ControlsSettingsDialogManagerImpl
|
||||
): ControlsSettingsDialogManager
|
||||
|
||||
@Binds
|
||||
abstract fun provideMetricsLogger(logger: ControlsMetricsLoggerImpl): ControlsMetricsLogger
|
||||
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.systemui.controls.settings
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
import android.content.DialogInterface
|
||||
import android.content.SharedPreferences
|
||||
import android.provider.Settings
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.controls.settings.ControlsSettingsDialogManager.Companion.MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG
|
||||
import com.android.systemui.controls.settings.ControlsSettingsDialogManager.Companion.PREFS_SETTINGS_DIALOG_ATTEMPTS
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.settings.UserFileManager
|
||||
import com.android.systemui.settings.UserTracker
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialog
|
||||
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
|
||||
import com.android.systemui.util.settings.SecureSettings
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Manager to display a dialog to prompt user to enable controls related Settings:
|
||||
*
|
||||
* * [Settings.Secure.LOCKSCREEN_SHOW_CONTROLS]
|
||||
* * [Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS]
|
||||
*/
|
||||
interface ControlsSettingsDialogManager {
|
||||
|
||||
/**
|
||||
* Shows the corresponding dialog. In order for a dialog to appear, the following must be true
|
||||
*
|
||||
* * At least one of the Settings in [ControlsSettingsRepository] are `false`.
|
||||
* * The dialog has not been seen by the user too many times (as defined by
|
||||
* [MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG]).
|
||||
*
|
||||
* When the dialogs are shown, the following outcomes are possible:
|
||||
* * User cancels the dialog by clicking outside or going back: we register that the dialog was
|
||||
* seen but the settings don't change.
|
||||
* * User responds negatively to the dialog: we register that the user doesn't want to change
|
||||
* the settings (dialog will not appear again) and the settings don't change.
|
||||
* * User responds positively to the dialog: the settings are set to `true` and the dialog will
|
||||
* not appear again.
|
||||
* * SystemUI closes the dialogs (for example, the activity showing it is closed). In this case,
|
||||
* we don't modify anything.
|
||||
*
|
||||
* Of those four scenarios, only the first three will cause [onAttemptCompleted] to be called.
|
||||
* It will also be called if the dialogs are not shown.
|
||||
*/
|
||||
fun maybeShowDialog(activityContext: Context, onAttemptCompleted: () -> Unit)
|
||||
|
||||
/**
|
||||
* Closes the dialog without registering anything from the user. The state of the settings after
|
||||
* this is called will be the same as before the dialogs were shown.
|
||||
*/
|
||||
fun closeDialog()
|
||||
|
||||
companion object {
|
||||
@VisibleForTesting internal const val MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG = 2
|
||||
@VisibleForTesting
|
||||
internal const val PREFS_SETTINGS_DIALOG_ATTEMPTS = "show_settings_attempts"
|
||||
}
|
||||
}
|
||||
|
||||
@SysUISingleton
|
||||
class ControlsSettingsDialogManagerImpl
|
||||
@VisibleForTesting
|
||||
internal constructor(
|
||||
private val secureSettings: SecureSettings,
|
||||
private val userFileManager: UserFileManager,
|
||||
private val controlsSettingsRepository: ControlsSettingsRepository,
|
||||
private val userTracker: UserTracker,
|
||||
private val activityStarter: ActivityStarter,
|
||||
private val dialogProvider: (context: Context, theme: Int) -> AlertDialog
|
||||
) : ControlsSettingsDialogManager {
|
||||
|
||||
@Inject
|
||||
constructor(
|
||||
secureSettings: SecureSettings,
|
||||
userFileManager: UserFileManager,
|
||||
controlsSettingsRepository: ControlsSettingsRepository,
|
||||
userTracker: UserTracker,
|
||||
activityStarter: ActivityStarter
|
||||
) : this(
|
||||
secureSettings,
|
||||
userFileManager,
|
||||
controlsSettingsRepository,
|
||||
userTracker,
|
||||
activityStarter,
|
||||
{ context, theme -> SettingsDialog(context, theme) }
|
||||
)
|
||||
|
||||
private var dialog: AlertDialog? = null
|
||||
private set
|
||||
|
||||
private val showDeviceControlsInLockscreen: Boolean
|
||||
get() = controlsSettingsRepository.canShowControlsInLockscreen.value
|
||||
|
||||
private val allowTrivialControls: Boolean
|
||||
get() = controlsSettingsRepository.allowActionOnTrivialControlsInLockscreen.value
|
||||
|
||||
override fun maybeShowDialog(activityContext: Context, onAttemptCompleted: () -> Unit) {
|
||||
closeDialog()
|
||||
|
||||
val prefs =
|
||||
userFileManager.getSharedPreferences(
|
||||
DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
|
||||
MODE_PRIVATE,
|
||||
userTracker.userId
|
||||
)
|
||||
val attempts = prefs.getInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, 0)
|
||||
if (
|
||||
attempts >= MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG ||
|
||||
(showDeviceControlsInLockscreen && allowTrivialControls)
|
||||
) {
|
||||
onAttemptCompleted()
|
||||
return
|
||||
}
|
||||
|
||||
val listener = DialogListener(prefs, attempts, onAttemptCompleted)
|
||||
val d =
|
||||
dialogProvider(activityContext, R.style.Theme_SystemUI_Dialog).apply {
|
||||
setIcon(R.drawable.ic_warning)
|
||||
setOnCancelListener(listener)
|
||||
setNeutralButton(R.string.controls_settings_dialog_neutral_button, listener)
|
||||
setPositiveButton(R.string.controls_settings_dialog_positive_button, listener)
|
||||
if (showDeviceControlsInLockscreen) {
|
||||
setTitle(R.string.controls_settings_trivial_controls_dialog_title)
|
||||
setMessage(R.string.controls_settings_trivial_controls_dialog_message)
|
||||
} else {
|
||||
setTitle(R.string.controls_settings_show_controls_dialog_title)
|
||||
setMessage(R.string.controls_settings_show_controls_dialog_message)
|
||||
}
|
||||
}
|
||||
|
||||
SystemUIDialog.registerDismissListener(d) { dialog = null }
|
||||
SystemUIDialog.setDialogSize(d)
|
||||
SystemUIDialog.setShowForAllUsers(d, true)
|
||||
dialog = d
|
||||
d.show()
|
||||
}
|
||||
|
||||
private fun turnOnSettingSecurely(settings: List<String>) {
|
||||
val action =
|
||||
ActivityStarter.OnDismissAction {
|
||||
settings.forEach { setting ->
|
||||
secureSettings.putIntForUser(setting, 1, userTracker.userId)
|
||||
}
|
||||
true
|
||||
}
|
||||
activityStarter.dismissKeyguardThenExecute(
|
||||
action,
|
||||
/* cancel */ null,
|
||||
/* afterKeyguardGone */ true
|
||||
)
|
||||
}
|
||||
|
||||
override fun closeDialog() {
|
||||
dialog?.dismiss()
|
||||
}
|
||||
|
||||
private inner class DialogListener(
|
||||
private val prefs: SharedPreferences,
|
||||
private val attempts: Int,
|
||||
private val onComplete: () -> Unit
|
||||
) : DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
|
||||
override fun onClick(dialog: DialogInterface?, which: Int) {
|
||||
if (dialog == null) return
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
val settings = mutableListOf(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)
|
||||
if (!showDeviceControlsInLockscreen) {
|
||||
settings.add(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS)
|
||||
}
|
||||
turnOnSettingSecurely(settings)
|
||||
}
|
||||
if (attempts != MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG) {
|
||||
prefs
|
||||
.edit()
|
||||
.putInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG)
|
||||
.apply()
|
||||
}
|
||||
onComplete()
|
||||
}
|
||||
|
||||
override fun onCancel(dialog: DialogInterface?) {
|
||||
if (dialog == null) return
|
||||
if (attempts < MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG) {
|
||||
prefs.edit().putInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, attempts + 1).apply()
|
||||
}
|
||||
onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
private fun AlertDialog.setNeutralButton(
|
||||
msgId: Int,
|
||||
listener: DialogInterface.OnClickListener
|
||||
) {
|
||||
setButton(DialogInterface.BUTTON_NEUTRAL, context.getText(msgId), listener)
|
||||
}
|
||||
|
||||
private fun AlertDialog.setPositiveButton(
|
||||
msgId: Int,
|
||||
listener: DialogInterface.OnClickListener
|
||||
) {
|
||||
setButton(DialogInterface.BUTTON_POSITIVE, context.getText(msgId), listener)
|
||||
}
|
||||
|
||||
private fun AlertDialog.setMessage(msgId: Int) {
|
||||
setMessage(context.getText(msgId))
|
||||
}
|
||||
|
||||
/** This is necessary because the constructors are `protected`. */
|
||||
private class SettingsDialog(context: Context, theme: Int) : AlertDialog(context, theme)
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.systemui.controls
|
||||
package com.android.systemui.controls.settings
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.systemui.controls
|
||||
package com.android.systemui.controls.settings
|
||||
|
||||
import android.provider.Settings
|
||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||
@@ -19,15 +19,12 @@ package com.android.systemui.controls.ui
|
||||
import android.annotation.AnyThread
|
||||
import android.annotation.MainThread
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.os.UserHandle
|
||||
import android.os.VibrationEffect
|
||||
import android.provider.Settings.Secure
|
||||
import android.service.controls.Control
|
||||
import android.service.controls.actions.BooleanAction
|
||||
import android.service.controls.actions.CommandAction
|
||||
@@ -35,39 +32,36 @@ import android.service.controls.actions.FloatAction
|
||||
import android.util.Log
|
||||
import android.view.HapticFeedbackConstants
|
||||
import com.android.internal.annotations.VisibleForTesting
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.broadcast.BroadcastSender
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.controls.ControlsSettingsRepository
|
||||
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
|
||||
import com.android.systemui.controls.settings.ControlsSettingsRepository
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.settings.UserContextProvider
|
||||
import com.android.systemui.statusbar.VibratorHelper
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialog
|
||||
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_FILE
|
||||
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_SETTINGS_DIALOG_ATTEMPTS
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||
import com.android.systemui.util.settings.SecureSettings
|
||||
import com.android.wm.shell.TaskViewFactory
|
||||
import java.util.Optional
|
||||
import javax.inject.Inject
|
||||
|
||||
@SysUISingleton
|
||||
class ControlActionCoordinatorImpl @Inject constructor(
|
||||
private val context: Context,
|
||||
private val bgExecutor: DelayableExecutor,
|
||||
@Main private val uiExecutor: DelayableExecutor,
|
||||
private val activityStarter: ActivityStarter,
|
||||
private val broadcastSender: BroadcastSender,
|
||||
private val keyguardStateController: KeyguardStateController,
|
||||
private val taskViewFactory: Optional<TaskViewFactory>,
|
||||
private val controlsMetricsLogger: ControlsMetricsLogger,
|
||||
private val vibrator: VibratorHelper,
|
||||
private val secureSettings: SecureSettings,
|
||||
private val userContextProvider: UserContextProvider,
|
||||
private val controlsSettingsRepository: ControlsSettingsRepository,
|
||||
private val context: Context,
|
||||
private val bgExecutor: DelayableExecutor,
|
||||
@Main private val uiExecutor: DelayableExecutor,
|
||||
private val activityStarter: ActivityStarter,
|
||||
private val broadcastSender: BroadcastSender,
|
||||
private val keyguardStateController: KeyguardStateController,
|
||||
private val taskViewFactory: Optional<TaskViewFactory>,
|
||||
private val controlsMetricsLogger: ControlsMetricsLogger,
|
||||
private val vibrator: VibratorHelper,
|
||||
private val controlsSettingsRepository: ControlsSettingsRepository,
|
||||
private val controlsSettingsDialogManager: ControlsSettingsDialogManager,
|
||||
private val featureFlags: FeatureFlags,
|
||||
) : ControlActionCoordinator {
|
||||
private var dialog: Dialog? = null
|
||||
private var pendingAction: Action? = null
|
||||
@@ -76,16 +70,16 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
||||
get() = !keyguardStateController.isUnlocked()
|
||||
private val allowTrivialControls: Boolean
|
||||
get() = controlsSettingsRepository.allowActionOnTrivialControlsInLockscreen.value
|
||||
private val showDeviceControlsInLockscreen: Boolean
|
||||
get() = controlsSettingsRepository.canShowControlsInLockscreen.value
|
||||
override lateinit var activityContext: Context
|
||||
|
||||
companion object {
|
||||
private const val RESPONSE_TIMEOUT_IN_MILLIS = 3000L
|
||||
private const val MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG = 2
|
||||
}
|
||||
|
||||
override fun closeDialogs() {
|
||||
if (!featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
|
||||
controlsSettingsDialogManager.closeDialog()
|
||||
}
|
||||
val isActivityFinishing =
|
||||
(activityContext as? Activity)?.let { it.isFinishing || it.isDestroyed }
|
||||
if (isActivityFinishing == true) {
|
||||
@@ -253,71 +247,9 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
||||
if (action.authIsRequired) {
|
||||
return
|
||||
}
|
||||
val prefs = userContextProvider.userContext.getSharedPreferences(
|
||||
PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
|
||||
val attempts = prefs.getInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, 0)
|
||||
if (attempts >= MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG ||
|
||||
(showDeviceControlsInLockscreen && allowTrivialControls)) {
|
||||
return
|
||||
if (!featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
|
||||
controlsSettingsDialogManager.maybeShowDialog(activityContext) {}
|
||||
}
|
||||
val builder = AlertDialog
|
||||
.Builder(activityContext, R.style.Theme_SystemUI_Dialog)
|
||||
.setIcon(R.drawable.ic_warning)
|
||||
.setOnCancelListener {
|
||||
if (attempts < MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG) {
|
||||
prefs.edit().putInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, attempts + 1)
|
||||
.commit()
|
||||
}
|
||||
true
|
||||
}
|
||||
.setNeutralButton(R.string.controls_settings_dialog_neutral_button) { _, _ ->
|
||||
if (attempts != MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG) {
|
||||
prefs.edit().putInt(PREFS_SETTINGS_DIALOG_ATTEMPTS,
|
||||
MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG)
|
||||
.commit()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
if (showDeviceControlsInLockscreen) {
|
||||
dialog = builder
|
||||
.setTitle(R.string.controls_settings_trivial_controls_dialog_title)
|
||||
.setMessage(R.string.controls_settings_trivial_controls_dialog_message)
|
||||
.setPositiveButton(R.string.controls_settings_dialog_positive_button) { _, _ ->
|
||||
if (attempts != MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG) {
|
||||
prefs.edit().putInt(PREFS_SETTINGS_DIALOG_ATTEMPTS,
|
||||
MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG)
|
||||
.commit()
|
||||
}
|
||||
secureSettings.putIntForUser(Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, 1,
|
||||
UserHandle.USER_CURRENT)
|
||||
true
|
||||
}
|
||||
.create()
|
||||
} else {
|
||||
dialog = builder
|
||||
.setTitle(R.string.controls_settings_show_controls_dialog_title)
|
||||
.setMessage(R.string.controls_settings_show_controls_dialog_message)
|
||||
.setPositiveButton(R.string.controls_settings_dialog_positive_button) { _, _ ->
|
||||
if (attempts != MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG) {
|
||||
prefs.edit().putInt(PREFS_SETTINGS_DIALOG_ATTEMPTS,
|
||||
MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG)
|
||||
.commit()
|
||||
}
|
||||
secureSettings.putIntForUser(Secure.LOCKSCREEN_SHOW_CONTROLS,
|
||||
1, UserHandle.USER_CURRENT)
|
||||
secureSettings.putIntForUser(Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS,
|
||||
1, UserHandle.USER_CURRENT)
|
||||
true
|
||||
}
|
||||
.create()
|
||||
}
|
||||
|
||||
SystemUIDialog.registerDismissListener(dialog)
|
||||
SystemUIDialog.setDialogSize(dialog)
|
||||
|
||||
dialog?.create()
|
||||
dialog?.show()
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -32,8 +32,10 @@ import androidx.activity.ComponentActivity
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.controls.management.ControlsAnimations
|
||||
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
@@ -47,7 +49,9 @@ class ControlsActivity @Inject constructor(
|
||||
private val uiController: ControlsUiController,
|
||||
private val broadcastDispatcher: BroadcastDispatcher,
|
||||
private val dreamManager: IDreamManager,
|
||||
private val featureFlags: FeatureFlags
|
||||
private val featureFlags: FeatureFlags,
|
||||
private val controlsSettingsDialogManager: ControlsSettingsDialogManager,
|
||||
private val keyguardStateController: KeyguardStateController
|
||||
) : ComponentActivity() {
|
||||
|
||||
private lateinit var parent: ViewGroup
|
||||
@@ -92,7 +96,13 @@ class ControlsActivity @Inject constructor(
|
||||
|
||||
parent = requireViewById<ViewGroup>(R.id.global_actions_controls)
|
||||
parent.alpha = 0f
|
||||
uiController.show(parent, { finishOrReturnToDream() }, this)
|
||||
if (featureFlags.isEnabled(Flags.USE_APP_PANELS) && !keyguardStateController.isUnlocked) {
|
||||
controlsSettingsDialogManager.maybeShowDialog(this) {
|
||||
uiController.show(parent, { finishOrReturnToDream() }, this)
|
||||
}
|
||||
} else {
|
||||
uiController.show(parent, { finishOrReturnToDream() }, this)
|
||||
}
|
||||
|
||||
ControlsAnimations.enterAnimation(parent).start()
|
||||
}
|
||||
@@ -124,6 +134,7 @@ class ControlsActivity @Inject constructor(
|
||||
mExitToDream = false
|
||||
|
||||
uiController.hide()
|
||||
controlsSettingsDialogManager.closeDialog()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
||||
@@ -49,7 +49,7 @@ import com.android.systemui.Dumpable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.controls.ControlsServiceInfo
|
||||
import com.android.systemui.controls.ControlsSettingsRepository
|
||||
import com.android.systemui.controls.settings.ControlsSettingsRepository
|
||||
import com.android.systemui.controls.CustomIconCache
|
||||
import com.android.systemui.controls.controller.ControlsController
|
||||
import com.android.systemui.controls.controller.StructureInfo
|
||||
|
||||
@@ -68,7 +68,6 @@ public class DeviceControlsControllerImpl @Inject constructor(
|
||||
|
||||
internal const val PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted"
|
||||
const val PREFS_CONTROLS_FILE = "controls_prefs"
|
||||
internal const val PREFS_SETTINGS_DIALOG_ATTEMPTS = "show_settings_attempts"
|
||||
private const val SEEDING_MAX = 2
|
||||
}
|
||||
|
||||
|
||||
@@ -16,21 +16,19 @@
|
||||
|
||||
package com.android.systemui.controls.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.test.suitebuilder.annotation.SmallTest
|
||||
import android.testing.AndroidTestingRunner
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.broadcast.BroadcastSender
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.controls.FakeControlsSettingsRepository
|
||||
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
|
||||
import com.android.systemui.controls.settings.FakeControlsSettingsRepository
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.settings.UserContextProvider
|
||||
import com.android.systemui.statusbar.VibratorHelper
|
||||
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||
import com.android.systemui.util.settings.SecureSettings
|
||||
import com.android.wm.shell.TaskViewFactory
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -40,8 +38,8 @@ import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.anyBoolean
|
||||
import org.mockito.Mockito.doNothing
|
||||
import org.mockito.Mockito.doReturn
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.reset
|
||||
import org.mockito.Mockito.spy
|
||||
@@ -71,9 +69,9 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
|
||||
@Mock
|
||||
private lateinit var metricsLogger: ControlsMetricsLogger
|
||||
@Mock
|
||||
private lateinit var secureSettings: SecureSettings
|
||||
private lateinit var featureFlags: FeatureFlags
|
||||
@Mock
|
||||
private lateinit var userContextProvider: UserContextProvider
|
||||
private lateinit var controlsSettingsDialogManager: ControlsSettingsDialogManager
|
||||
|
||||
companion object {
|
||||
fun <T> any(): T = Mockito.any<T>()
|
||||
@@ -103,23 +101,16 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
|
||||
taskViewFactory,
|
||||
metricsLogger,
|
||||
vibratorHelper,
|
||||
secureSettings,
|
||||
userContextProvider,
|
||||
controlsSettingsRepository
|
||||
controlsSettingsRepository,
|
||||
controlsSettingsDialogManager,
|
||||
featureFlags
|
||||
))
|
||||
|
||||
val userContext = mock(Context::class.java)
|
||||
val pref = mock(SharedPreferences::class.java)
|
||||
`when`(userContextProvider.userContext).thenReturn(userContext)
|
||||
`when`(userContext.getSharedPreferences(
|
||||
DeviceControlsControllerImpl.PREFS_CONTROLS_FILE, Context.MODE_PRIVATE))
|
||||
.thenReturn(pref)
|
||||
// Just return 2 so we don't test any Dialog logic which requires a launched activity.
|
||||
`when`(pref.getInt(DeviceControlsControllerImpl.PREFS_SETTINGS_DIALOG_ATTEMPTS, 0))
|
||||
.thenReturn(2)
|
||||
coordinator.activityContext = mContext
|
||||
|
||||
`when`(cvh.cws.ci.controlId).thenReturn(ID)
|
||||
`when`(cvh.cws.control?.isAuthRequired()).thenReturn(true)
|
||||
`when`(featureFlags.isEnabled(Flags.USE_APP_PANELS)).thenReturn(false)
|
||||
|
||||
action = spy(coordinator.Action(ID, {}, false, true))
|
||||
doReturn(action).`when`(coordinator).createAction(any(), any(), anyBoolean(), anyBoolean())
|
||||
}
|
||||
@@ -160,14 +151,30 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
|
||||
doReturn(action).`when`(coordinator).createAction(any(), any(), anyBoolean(), anyBoolean())
|
||||
|
||||
`when`(keyguardStateController.isShowing()).thenReturn(true)
|
||||
`when`(keyguardStateController.isUnlocked()).thenReturn(false)
|
||||
|
||||
coordinator.toggle(cvh, "", true)
|
||||
|
||||
verify(coordinator).bouncerOrRun(action)
|
||||
verify(controlsSettingsDialogManager).maybeShowDialog(any(), any())
|
||||
verify(action).invoke()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToggleWhenLockedDoesNotTriggerDialog_featureFlagEnabled() {
|
||||
`when`(featureFlags.isEnabled(Flags.USE_APP_PANELS)).thenReturn(true)
|
||||
action = spy(coordinator.Action(ID, {}, false, false))
|
||||
doReturn(action).`when`(coordinator).createAction(any(), any(), anyBoolean(), anyBoolean())
|
||||
|
||||
`when`(keyguardStateController.isShowing()).thenReturn(true)
|
||||
`when`(keyguardStateController.isUnlocked()).thenReturn(false)
|
||||
doNothing().`when`(controlsSettingsDialogManager).maybeShowDialog(any(), any())
|
||||
|
||||
coordinator.toggle(cvh, "", true)
|
||||
|
||||
verify(coordinator).bouncerOrRun(action)
|
||||
verify(controlsSettingsDialogManager, never()).maybeShowDialog(any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToggleDoesNotRunsWhenLockedAndAuthRequired() {
|
||||
action = spy(coordinator.Action(ID, {}, false, true))
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.android.internal.widget.LockPatternUtils
|
||||
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
|
||||
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.controls.FakeControlsSettingsRepository
|
||||
import com.android.systemui.controls.settings.FakeControlsSettingsRepository
|
||||
import com.android.systemui.controls.controller.ControlsController
|
||||
import com.android.systemui.controls.controller.ControlsTileResourceConfiguration
|
||||
import com.android.systemui.controls.management.ControlsListingController
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.systemui.controls.settings
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.content.SharedPreferences
|
||||
import android.database.ContentObserver
|
||||
import android.provider.Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS
|
||||
import android.provider.Settings.Secure.LOCKSCREEN_SHOW_CONTROLS
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.controls.settings.ControlsSettingsDialogManager.Companion.PREFS_SETTINGS_DIALOG_ATTEMPTS
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.settings.UserFileManager
|
||||
import com.android.systemui.settings.UserTracker
|
||||
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
|
||||
import com.android.systemui.util.FakeSharedPreferences
|
||||
import com.android.systemui.util.TestableAlertDialog
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.nullable
|
||||
import com.android.systemui.util.settings.FakeSettings
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers.anyBoolean
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.anyInt
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@TestableLooper.RunWithLooper
|
||||
class ControlsSettingsDialogManagerImplTest : SysuiTestCase() {
|
||||
|
||||
companion object {
|
||||
private const val SETTING_SHOW = LOCKSCREEN_SHOW_CONTROLS
|
||||
private const val SETTING_ACTION = LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS
|
||||
private const val MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG = 2
|
||||
}
|
||||
|
||||
@Mock private lateinit var userFileManager: UserFileManager
|
||||
@Mock private lateinit var userTracker: UserTracker
|
||||
@Mock private lateinit var activityStarter: ActivityStarter
|
||||
@Mock private lateinit var completedRunnable: () -> Unit
|
||||
|
||||
private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
|
||||
private lateinit var sharedPreferences: FakeSharedPreferences
|
||||
private lateinit var secureSettings: FakeSettings
|
||||
|
||||
private lateinit var underTest: ControlsSettingsDialogManagerImpl
|
||||
|
||||
private var dialog: TestableAlertDialog? = null
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
controlsSettingsRepository = FakeControlsSettingsRepository()
|
||||
sharedPreferences = FakeSharedPreferences()
|
||||
secureSettings = FakeSettings()
|
||||
|
||||
`when`(userTracker.userId).thenReturn(0)
|
||||
secureSettings.userId = userTracker.userId
|
||||
`when`(
|
||||
userFileManager.getSharedPreferences(
|
||||
eq(DeviceControlsControllerImpl.PREFS_CONTROLS_FILE),
|
||||
anyInt(),
|
||||
anyInt()
|
||||
)
|
||||
)
|
||||
.thenReturn(sharedPreferences)
|
||||
|
||||
`when`(activityStarter.dismissKeyguardThenExecute(any(), nullable(), anyBoolean()))
|
||||
.thenAnswer { (it.arguments[0] as ActivityStarter.OnDismissAction).onDismiss() }
|
||||
|
||||
attachRepositoryToSettings()
|
||||
underTest =
|
||||
ControlsSettingsDialogManagerImpl(
|
||||
secureSettings,
|
||||
userFileManager,
|
||||
controlsSettingsRepository,
|
||||
userTracker,
|
||||
activityStarter
|
||||
) { context, _ -> TestableAlertDialog(context).also { dialog = it } }
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
underTest.closeDialog()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogNotShownIfPrefsAtMaximum() {
|
||||
sharedPreferences.putAttempts(MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
|
||||
assertThat(dialog?.isShowing ?: false).isFalse()
|
||||
verify(completedRunnable).invoke()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogNotShownIfSettingsAreTrue() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, true)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
|
||||
assertThat(dialog?.isShowing ?: false).isFalse()
|
||||
verify(completedRunnable).invoke()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogShownIfAllowTrivialControlsFalse() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
|
||||
assertThat(dialog?.isShowing ?: false).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogDispossedAfterClosing() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
underTest.closeDialog()
|
||||
|
||||
assertThat(dialog?.isShowing ?: false).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogNeutralButtonDoesntChangeSetting() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
clickButton(DialogInterface.BUTTON_NEUTRAL)
|
||||
|
||||
assertThat(secureSettings.getBool(SETTING_ACTION, false)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogNeutralButtonPutsMaxAttempts() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
clickButton(DialogInterface.BUTTON_NEUTRAL)
|
||||
|
||||
assertThat(sharedPreferences.getInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, 0))
|
||||
.isEqualTo(MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogNeutralButtonCallsOnComplete() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
clickButton(DialogInterface.BUTTON_NEUTRAL)
|
||||
|
||||
verify(completedRunnable).invoke()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogPositiveButtonChangesSetting() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
clickButton(DialogInterface.BUTTON_POSITIVE)
|
||||
|
||||
assertThat(secureSettings.getBool(SETTING_ACTION, false)).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogPositiveButtonPutsMaxAttempts() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
clickButton(DialogInterface.BUTTON_POSITIVE)
|
||||
|
||||
assertThat(sharedPreferences.getInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, 0))
|
||||
.isEqualTo(MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogPositiveButtonCallsOnComplete() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
clickButton(DialogInterface.BUTTON_POSITIVE)
|
||||
|
||||
verify(completedRunnable).invoke()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogCancelDoesntChangeSetting() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
dialog?.cancel()
|
||||
|
||||
assertThat(secureSettings.getBool(SETTING_ACTION, false)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogCancelPutsOneExtraAttempt() {
|
||||
val attempts = 0
|
||||
sharedPreferences.putAttempts(attempts)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
dialog?.cancel()
|
||||
|
||||
assertThat(sharedPreferences.getInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, 0))
|
||||
.isEqualTo(attempts + 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogCancelCallsOnComplete() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
dialog?.cancel()
|
||||
|
||||
verify(completedRunnable).invoke()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun closeDialogDoesNotCallOnComplete() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, true)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
underTest.closeDialog()
|
||||
|
||||
verify(completedRunnable, never()).invoke()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogPositiveWithBothSettingsFalseTogglesBothSettings() {
|
||||
sharedPreferences.putAttempts(0)
|
||||
secureSettings.putBool(SETTING_SHOW, false)
|
||||
secureSettings.putBool(SETTING_ACTION, false)
|
||||
|
||||
underTest.maybeShowDialog(context, completedRunnable)
|
||||
clickButton(DialogInterface.BUTTON_POSITIVE)
|
||||
|
||||
assertThat(secureSettings.getBool(SETTING_SHOW)).isTrue()
|
||||
assertThat(secureSettings.getBool(SETTING_ACTION)).isTrue()
|
||||
}
|
||||
|
||||
private fun clickButton(which: Int) {
|
||||
dialog?.clickButton(which)
|
||||
}
|
||||
|
||||
private fun attachRepositoryToSettings() {
|
||||
secureSettings.registerContentObserver(
|
||||
SETTING_SHOW,
|
||||
object : ContentObserver(null) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
controlsSettingsRepository.setCanShowControlsInLockscreen(
|
||||
secureSettings.getBool(SETTING_SHOW, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
secureSettings.registerContentObserver(
|
||||
SETTING_ACTION,
|
||||
object : ContentObserver(null) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
controlsSettingsRepository.setAllowActionOnTrivialControlsInLockscreen(
|
||||
secureSettings.getBool(SETTING_ACTION, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun SharedPreferences.putAttempts(value: Int) {
|
||||
edit().putInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, value).commit()
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.systemui.controls
|
||||
package com.android.systemui.controls.settings
|
||||
|
||||
import android.content.pm.UserInfo
|
||||
import android.provider.Settings
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.systemui.controls
|
||||
package com.android.systemui.controls.settings
|
||||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
@@ -35,10 +35,10 @@ import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.controls.ControlsServiceInfo
|
||||
import com.android.systemui.controls.CustomIconCache
|
||||
import com.android.systemui.controls.FakeControlsSettingsRepository
|
||||
import com.android.systemui.controls.controller.ControlsController
|
||||
import com.android.systemui.controls.controller.StructureInfo
|
||||
import com.android.systemui.controls.management.ControlsListingController
|
||||
import com.android.systemui.controls.settings.FakeControlsSettingsRepository
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.settings.UserFileManager
|
||||
|
||||
Reference in New Issue
Block a user