Loading packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +12 −5 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 */)) Loading @@ -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()) Loading @@ -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) Loading @@ -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 Loading @@ -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) { Loading Loading @@ -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)) { Loading packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt 0 → 100644 +126 −0 Original line number Diff line number Diff line /* * 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() } } Loading
packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +12 −5 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 */)) Loading @@ -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()) Loading @@ -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) Loading @@ -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 Loading @@ -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) { Loading Loading @@ -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)) { Loading
packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt 0 → 100644 +126 −0 Original line number Diff line number Diff line /* * 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() } }