Merge "Controls - Prevent action while locked" into sc-dev

This commit is contained in:
Matt Pietal
2021-02-11 15:25:43 +00:00
committed by Android (Google) Code Review
2 changed files with 138 additions and 5 deletions

View File

@@ -30,6 +30,7 @@ import android.service.controls.actions.CommandAction
import android.service.controls.actions.FloatAction
import android.util.Log
import android.view.HapticFeedbackConstants
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
@@ -71,7 +72,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
}
override fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) {
bouncerOrRun(Action(cvh.cws.ci.controlId, {
bouncerOrRun(createAction(cvh.cws.ci.controlId, {
cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
cvh.action(BooleanAction(templateId, !isChecked))
}, true /* blockable */))
@@ -79,7 +80,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
override fun touch(cvh: ControlViewHolder, templateId: String, control: Control) {
val blockable = cvh.usePanel()
bouncerOrRun(Action(cvh.cws.ci.controlId, {
bouncerOrRun(createAction(cvh.cws.ci.controlId, {
cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
if (cvh.usePanel()) {
showDialog(cvh, control.getAppIntent().getIntent())
@@ -98,13 +99,13 @@ class ControlActionCoordinatorImpl @Inject constructor(
}
override fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) {
bouncerOrRun(Action(cvh.cws.ci.controlId, {
bouncerOrRun(createAction(cvh.cws.ci.controlId, {
cvh.action(FloatAction(templateId, newValue))
}, false /* blockable */))
}
override fun longPress(cvh: ControlViewHolder) {
bouncerOrRun(Action(cvh.cws.ci.controlId, {
bouncerOrRun(createAction(cvh.cws.ci.controlId, {
// Long press snould only be called when there is valid control state, otherwise ignore
cvh.cws.control?.let {
cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
@@ -114,6 +115,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
}
override fun runPendingAction(controlId: String) {
if (!keyguardStateController.isUnlocked()) return
if (pendingAction?.controlId == controlId) {
pendingAction?.invoke()
pendingAction = null
@@ -135,7 +137,8 @@ class ControlActionCoordinatorImpl @Inject constructor(
false
}
private fun bouncerOrRun(action: Action) {
@VisibleForTesting
fun bouncerOrRun(action: Action) {
if (keyguardStateController.isShowing()) {
var closeDialog = !keyguardStateController.isUnlocked()
if (closeDialog) {
@@ -190,6 +193,10 @@ class ControlActionCoordinatorImpl @Inject constructor(
}
}
@VisibleForTesting
fun createAction(controlId: String, f: () -> Unit, blockable: Boolean) =
Action(controlId, f, blockable)
inner class Action(val controlId: String, val f: () -> Unit, val blockable: Boolean) {
fun invoke() {
if (!blockable || shouldRunAction(controlId)) {

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2021 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.ui
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.globalactions.GlobalActionsComponent
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.wm.shell.TaskViewFactory
import dagger.Lazy
import java.util.Optional
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Answers
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
class ControlActionCoordinatorImplTest : SysuiTestCase() {
@Mock
private lateinit var uiController: ControlsUiController
@Mock
private lateinit var lazyUiController: Lazy<ControlsUiController>
@Mock
private lateinit var keyguardStateController: KeyguardStateController
@Mock
private lateinit var bgExecutor: DelayableExecutor
@Mock
private lateinit var uiExecutor: DelayableExecutor
@Mock
private lateinit var activityStarter: ActivityStarter
@Mock
private lateinit var globalActionsComponent: GlobalActionsComponent
@Mock
private lateinit var taskViewFactory: Optional<TaskViewFactory>
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private lateinit var cvh: ControlViewHolder
companion object {
fun <T> any(): T = Mockito.any<T>()
private val ID = "id"
}
private lateinit var coordinator: ControlActionCoordinatorImpl
private lateinit var action: ControlActionCoordinatorImpl.Action
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
coordinator = spy(ControlActionCoordinatorImpl(
mContext,
bgExecutor,
uiExecutor,
activityStarter,
keyguardStateController,
globalActionsComponent,
taskViewFactory,
getFakeBroadcastDispatcher(),
lazyUiController
))
`when`(cvh.cws.ci.controlId).thenReturn(ID)
action = spy(coordinator.Action(ID, {}, false))
doReturn(action).`when`(coordinator).createAction(any(), any(), anyBoolean())
}
@Test
fun testToggleRunsWhenUnlocked() {
`when`(keyguardStateController.isShowing()).thenReturn(false)
coordinator.toggle(cvh, "", true)
verify(coordinator).bouncerOrRun(action)
verify(action).invoke()
}
@Test
fun testToggleDoesNotRunWhenLockedThenRunsWhenUnlocked() {
`when`(keyguardStateController.isShowing()).thenReturn(true)
`when`(keyguardStateController.isUnlocked()).thenReturn(false)
coordinator.toggle(cvh, "", true)
verify(coordinator).bouncerOrRun(action)
verify(activityStarter).dismissKeyguardThenExecute(any(), any(), anyBoolean())
verify(action, never()).invoke()
// Simulate a refresh call from a Publisher, which will trigger a call to runPendingAction
reset(action)
coordinator.runPendingAction(ID)
verify(action, never()).invoke()
`when`(keyguardStateController.isUnlocked()).thenReturn(true)
reset(action)
coordinator.runPendingAction(ID)
verify(action).invoke()
}
}