Loading core/java/android/provider/Settings.java +8 −0 Original line number Diff line number Diff line Loading @@ -9947,6 +9947,14 @@ public final class Settings { */ public static final String LOCKSCREEN_SHOW_CONTROLS = "lockscreen_show_controls"; /** * Whether trivial home controls can be used without authentication * * @hide */ public static final String LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS = "lockscreen_allow_trivial_controls"; /** * Whether wallet should be accessible from the lockscreen * Loading packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +1 −0 Original line number Diff line number Diff line Loading @@ -193,6 +193,7 @@ public class SecureSettings { Settings.Secure.NOTIFICATION_BUBBLES, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, Settings.Secure.LOCKSCREEN_SHOW_WALLET, Settings.Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, Loading packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +1 −0 Original line number Diff line number Diff line Loading @@ -152,6 +152,7 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.CONTROLS_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.POWER_MENU_LOCKED_SHOW_CONTENT, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_SHOW_CONTROLS, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_SHOW_WALLET, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, BOOLEAN_VALIDATOR); Loading packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +37 −6 Original line number Diff line number Diff line Loading @@ -23,7 +23,11 @@ import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.database.ContentObserver import android.net.Uri import android.os.Handler import android.os.VibrationEffect import android.provider.Settings import android.service.controls.Control import android.service.controls.actions.BooleanAction import android.service.controls.actions.CommandAction Loading @@ -38,6 +42,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.VibratorHelper 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 Loading @@ -51,19 +56,41 @@ class ControlActionCoordinatorImpl @Inject constructor( private val keyguardStateController: KeyguardStateController, private val taskViewFactory: Optional<TaskViewFactory>, private val controlsMetricsLogger: ControlsMetricsLogger, private val vibrator: VibratorHelper private val vibrator: VibratorHelper, private val secureSettings: SecureSettings, @Main mainHandler: Handler ) : ControlActionCoordinator { private var dialog: Dialog? = null private var pendingAction: Action? = null private var actionsInProgress = mutableSetOf<String>() private val isLocked: Boolean get() = !keyguardStateController.isUnlocked() private var mAllowTrivialControls: Boolean = secureSettings.getInt( Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, 0) != 0 override lateinit var activityContext: Context companion object { private const val RESPONSE_TIMEOUT_IN_MILLIS = 3000L } init { val lockScreenShowControlsUri = secureSettings.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS) val controlsContentObserver = object : ContentObserver(mainHandler) { override fun onChange(selfChange: Boolean, uri: Uri?) { super.onChange(selfChange, uri) if (uri == lockScreenShowControlsUri) { mAllowTrivialControls = secureSettings.getInt( Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, 0) != 0 } } } secureSettings.registerContentObserver( lockScreenShowControlsUri, false /* notifyForDescendants */, controlsContentObserver ) } override fun closeDialogs() { dialog?.dismiss() dialog = null Loading @@ -80,7 +107,7 @@ class ControlActionCoordinatorImpl @Inject constructor( }, true /* blockable */ ), isAuthRequired(cvh) isAuthRequired(cvh, mAllowTrivialControls) ) } Loading @@ -100,7 +127,7 @@ class ControlActionCoordinatorImpl @Inject constructor( }, blockable ), isAuthRequired(cvh) isAuthRequired(cvh, mAllowTrivialControls) ) } Loading @@ -120,7 +147,7 @@ class ControlActionCoordinatorImpl @Inject constructor( { cvh.action(FloatAction(templateId, newValue)) }, false /* blockable */ ), isAuthRequired(cvh) isAuthRequired(cvh, mAllowTrivialControls) ) } Loading @@ -139,7 +166,7 @@ class ControlActionCoordinatorImpl @Inject constructor( }, false /* blockable */ ), isAuthRequired(cvh) isAuthRequired(cvh, mAllowTrivialControls) ) } Loading @@ -156,7 +183,11 @@ class ControlActionCoordinatorImpl @Inject constructor( actionsInProgress.remove(controlId) } private fun isAuthRequired(cvh: ControlViewHolder) = cvh.cws.control?.isAuthRequired() ?: true @VisibleForTesting() fun isAuthRequired(cvh: ControlViewHolder, allowTrivialControls: Boolean): Boolean { val isAuthRequired = cvh.cws.control?.isAuthRequired ?: true return isAuthRequired || !allowTrivialControls } private fun shouldRunAction(controlId: String) = if (actionsInProgress.add(controlId)) { Loading packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt +43 −12 Original line number Diff line number Diff line Loading @@ -16,15 +16,22 @@ package com.android.systemui.controls.ui import android.database.ContentObserver import android.net.Uri import android.os.Handler import android.provider.Settings import android.test.suitebuilder.annotation.SmallTest import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.controls.ControlsMetricsLogger import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.settings.SecureSettings import com.android.wm.shell.TaskViewFactory import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith Loading @@ -44,7 +51,6 @@ import java.util.Optional @SmallTest @RunWith(AndroidTestingRunner::class) class ControlActionCoordinatorImplTest : SysuiTestCase() { @Mock private lateinit var vibratorHelper: VibratorHelper @Mock Loading @@ -61,6 +67,10 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { private lateinit var cvh: ControlViewHolder @Mock private lateinit var metricsLogger: ControlsMetricsLogger @Mock private lateinit var secureSettings: SecureSettings @Mock private lateinit var mainHandler: Handler companion object { fun <T> any(): T = Mockito.any<T>() Loading @@ -75,6 +85,10 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) `when`(secureSettings.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)) .thenReturn(Settings.Secure .getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)) coordinator = spy(ControlActionCoordinatorImpl( mContext, bgExecutor, Loading @@ -83,8 +97,12 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { keyguardStateController, taskViewFactory, metricsLogger, vibratorHelper )) vibratorHelper, secureSettings, mainHandler)) verify(secureSettings).registerContentObserver(any(Uri::class.java), anyBoolean(), any(ContentObserver::class.java)) `when`(cvh.cws.ci.controlId).thenReturn(ID) `when`(cvh.cws.control?.isAuthRequired()).thenReturn(true) Loading Loading @@ -126,10 +144,23 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { fun testToggleRunsWhenLockedAndAuthNotRequired() { `when`(keyguardStateController.isShowing()).thenReturn(true) `when`(keyguardStateController.isUnlocked()).thenReturn(false) `when`(cvh.cws.control?.isAuthRequired()).thenReturn(false) doReturn(false).`when`(coordinator).isAuthRequired( any(), anyBoolean()) coordinator.toggle(cvh, "", true) verify(coordinator).bouncerOrRun(action, false /* authRequired */) verify(action).invoke() } @Test fun testIsAuthRequired() { `when`(cvh.cws.control?.isAuthRequired).thenReturn(true) assertThat(coordinator.isAuthRequired(cvh, false)).isTrue() `when`(cvh.cws.control?.isAuthRequired).thenReturn(false) assertThat(coordinator.isAuthRequired(cvh, false)).isTrue() assertThat(coordinator.isAuthRequired(cvh, true)).isFalse() } } Loading
core/java/android/provider/Settings.java +8 −0 Original line number Diff line number Diff line Loading @@ -9947,6 +9947,14 @@ public final class Settings { */ public static final String LOCKSCREEN_SHOW_CONTROLS = "lockscreen_show_controls"; /** * Whether trivial home controls can be used without authentication * * @hide */ public static final String LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS = "lockscreen_allow_trivial_controls"; /** * Whether wallet should be accessible from the lockscreen * Loading
packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +1 −0 Original line number Diff line number Diff line Loading @@ -193,6 +193,7 @@ public class SecureSettings { Settings.Secure.NOTIFICATION_BUBBLES, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, Settings.Secure.LOCKSCREEN_SHOW_WALLET, Settings.Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, Loading
packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +1 −0 Original line number Diff line number Diff line Loading @@ -152,6 +152,7 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.CONTROLS_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.POWER_MENU_LOCKED_SHOW_CONTENT, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_SHOW_CONTROLS, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_SHOW_WALLET, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, BOOLEAN_VALIDATOR); Loading
packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +37 −6 Original line number Diff line number Diff line Loading @@ -23,7 +23,11 @@ import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.database.ContentObserver import android.net.Uri import android.os.Handler import android.os.VibrationEffect import android.provider.Settings import android.service.controls.Control import android.service.controls.actions.BooleanAction import android.service.controls.actions.CommandAction Loading @@ -38,6 +42,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.VibratorHelper 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 Loading @@ -51,19 +56,41 @@ class ControlActionCoordinatorImpl @Inject constructor( private val keyguardStateController: KeyguardStateController, private val taskViewFactory: Optional<TaskViewFactory>, private val controlsMetricsLogger: ControlsMetricsLogger, private val vibrator: VibratorHelper private val vibrator: VibratorHelper, private val secureSettings: SecureSettings, @Main mainHandler: Handler ) : ControlActionCoordinator { private var dialog: Dialog? = null private var pendingAction: Action? = null private var actionsInProgress = mutableSetOf<String>() private val isLocked: Boolean get() = !keyguardStateController.isUnlocked() private var mAllowTrivialControls: Boolean = secureSettings.getInt( Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, 0) != 0 override lateinit var activityContext: Context companion object { private const val RESPONSE_TIMEOUT_IN_MILLIS = 3000L } init { val lockScreenShowControlsUri = secureSettings.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS) val controlsContentObserver = object : ContentObserver(mainHandler) { override fun onChange(selfChange: Boolean, uri: Uri?) { super.onChange(selfChange, uri) if (uri == lockScreenShowControlsUri) { mAllowTrivialControls = secureSettings.getInt( Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, 0) != 0 } } } secureSettings.registerContentObserver( lockScreenShowControlsUri, false /* notifyForDescendants */, controlsContentObserver ) } override fun closeDialogs() { dialog?.dismiss() dialog = null Loading @@ -80,7 +107,7 @@ class ControlActionCoordinatorImpl @Inject constructor( }, true /* blockable */ ), isAuthRequired(cvh) isAuthRequired(cvh, mAllowTrivialControls) ) } Loading @@ -100,7 +127,7 @@ class ControlActionCoordinatorImpl @Inject constructor( }, blockable ), isAuthRequired(cvh) isAuthRequired(cvh, mAllowTrivialControls) ) } Loading @@ -120,7 +147,7 @@ class ControlActionCoordinatorImpl @Inject constructor( { cvh.action(FloatAction(templateId, newValue)) }, false /* blockable */ ), isAuthRequired(cvh) isAuthRequired(cvh, mAllowTrivialControls) ) } Loading @@ -139,7 +166,7 @@ class ControlActionCoordinatorImpl @Inject constructor( }, false /* blockable */ ), isAuthRequired(cvh) isAuthRequired(cvh, mAllowTrivialControls) ) } Loading @@ -156,7 +183,11 @@ class ControlActionCoordinatorImpl @Inject constructor( actionsInProgress.remove(controlId) } private fun isAuthRequired(cvh: ControlViewHolder) = cvh.cws.control?.isAuthRequired() ?: true @VisibleForTesting() fun isAuthRequired(cvh: ControlViewHolder, allowTrivialControls: Boolean): Boolean { val isAuthRequired = cvh.cws.control?.isAuthRequired ?: true return isAuthRequired || !allowTrivialControls } private fun shouldRunAction(controlId: String) = if (actionsInProgress.add(controlId)) { Loading
packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt +43 −12 Original line number Diff line number Diff line Loading @@ -16,15 +16,22 @@ package com.android.systemui.controls.ui import android.database.ContentObserver import android.net.Uri import android.os.Handler import android.provider.Settings import android.test.suitebuilder.annotation.SmallTest import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.controls.ControlsMetricsLogger import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.settings.SecureSettings import com.android.wm.shell.TaskViewFactory import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith Loading @@ -44,7 +51,6 @@ import java.util.Optional @SmallTest @RunWith(AndroidTestingRunner::class) class ControlActionCoordinatorImplTest : SysuiTestCase() { @Mock private lateinit var vibratorHelper: VibratorHelper @Mock Loading @@ -61,6 +67,10 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { private lateinit var cvh: ControlViewHolder @Mock private lateinit var metricsLogger: ControlsMetricsLogger @Mock private lateinit var secureSettings: SecureSettings @Mock private lateinit var mainHandler: Handler companion object { fun <T> any(): T = Mockito.any<T>() Loading @@ -75,6 +85,10 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) `when`(secureSettings.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)) .thenReturn(Settings.Secure .getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)) coordinator = spy(ControlActionCoordinatorImpl( mContext, bgExecutor, Loading @@ -83,8 +97,12 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { keyguardStateController, taskViewFactory, metricsLogger, vibratorHelper )) vibratorHelper, secureSettings, mainHandler)) verify(secureSettings).registerContentObserver(any(Uri::class.java), anyBoolean(), any(ContentObserver::class.java)) `when`(cvh.cws.ci.controlId).thenReturn(ID) `when`(cvh.cws.control?.isAuthRequired()).thenReturn(true) Loading Loading @@ -126,10 +144,23 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { fun testToggleRunsWhenLockedAndAuthNotRequired() { `when`(keyguardStateController.isShowing()).thenReturn(true) `when`(keyguardStateController.isUnlocked()).thenReturn(false) `when`(cvh.cws.control?.isAuthRequired()).thenReturn(false) doReturn(false).`when`(coordinator).isAuthRequired( any(), anyBoolean()) coordinator.toggle(cvh, "", true) verify(coordinator).bouncerOrRun(action, false /* authRequired */) verify(action).invoke() } @Test fun testIsAuthRequired() { `when`(cvh.cws.control?.isAuthRequired).thenReturn(true) assertThat(coordinator.isAuthRequired(cvh, false)).isTrue() `when`(cvh.cws.control?.isAuthRequired).thenReturn(false) assertThat(coordinator.isAuthRequired(cvh, false)).isTrue() assertThat(coordinator.isAuthRequired(cvh, true)).isFalse() } }