From fb1033cbb8eba35495f80d3a2be4f95b1c5d0627 Mon Sep 17 00:00:00 2001 From: William Xiao Date: Mon, 21 Oct 2024 13:37:39 -0700 Subject: Route dream touch handling to scene container We want to reuse the existing dream touch handling logic with the scene container, so route touches there from the various touch handlers as needed. There are still a few issues with the interactions themselves, but verified the touches are sent and received as expected. Bug: 371340996 Fixed: 371340996 Test: atest BouncerFullscreenSwipeTouchHandlerTest BouncerSwipeTouchHandlerTest ShadeTouchHandlerTest Flag: com.android.systemui.scene_container Change-Id: I20630441584e67caa18afb166e4059f386687a37 --- .../BouncerFullscreenSwipeTouchHandlerTest.java | 67 ++++++++++++++++- .../touch/BouncerSwipeTouchHandlerTest.java | 68 ++++++++++++++++- .../ambient/touch/ShadeTouchHandlerTest.kt | 85 +++++++++++++++++++--- .../ambient/touch/BouncerSwipeTouchHandler.kt | 48 ++++++++---- .../systemui/ambient/touch/ShadeTouchHandler.kt | 23 +++++- .../systemui/ambient/touch/dagger/ShadeModule.java | 9 +++ .../systemui/dreams/DreamOverlayService.java | 9 +-- .../systemui/dreams/dagger/DreamOverlayModule.java | 9 +++ .../dreams/touch/CommunalTouchHandler.java | 19 ++++- 9 files changed, 298 insertions(+), 39 deletions(-) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java index 58c3fec5b45e..bd33e52689c2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java @@ -20,7 +20,9 @@ import static com.google.common.truth.Truth.assertThat; import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -29,11 +31,12 @@ import android.content.pm.UserInfo; import android.graphics.Rect; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.FlagsParameterization; +import android.view.GestureDetector; import android.view.GestureDetector.OnGestureListener; import android.view.MotionEvent; import android.view.VelocityTracker; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; @@ -42,9 +45,12 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.ambient.touch.scrim.ScrimController; import com.android.systemui.ambient.touch.scrim.ScrimManager; import com.android.systemui.communal.ui.viewmodel.CommunalViewModel; +import com.android.systemui.flags.SceneContainerFlagParameterizationKt; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.kosmos.KosmosJavaAdapter; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.scene.domain.interactor.SceneInteractor; +import com.android.systemui.scene.ui.view.WindowRootView; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.CentralSurfaces; @@ -58,10 +64,14 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import java.util.List; import java.util.Optional; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(ParameterizedAndroidJunit4.class) @EnableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) @DisableFlags(Flags.FLAG_COMMUNAL_BOUNCER_DO_NOT_MODIFY_PLUGIN_OPEN) public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase { @@ -114,6 +124,11 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase { @Mock KeyguardInteractor mKeyguardInteractor; + @Mock + WindowRootView mWindowRootView; + + private SceneInteractor mSceneInteractor; + private static final float TOUCH_REGION = .3f; private static final float MIN_BOUNCER_HEIGHT = .05f; @@ -124,9 +139,21 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase { /* flags= */ 0 ); + @Parameters(name = "{0}") + public static List getParams() { + return SceneContainerFlagParameterizationKt.parameterizeSceneContainerFlag(); + } + + public BouncerFullscreenSwipeTouchHandlerTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setup() { mKosmos = new KosmosJavaAdapter(this); + mSceneInteractor = spy(mKosmos.getSceneInteractor()); + MockitoAnnotations.initMocks(this); mTouchHandler = new BouncerSwipeTouchHandler( mKosmos.getTestScope(), @@ -142,7 +169,9 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase { MIN_BOUNCER_HEIGHT, mUiEventLogger, mActivityStarter, - mKeyguardInteractor); + mKeyguardInteractor, + mSceneInteractor, + Optional.of(() -> mWindowRootView)); when(mScrimManager.getCurrentController()).thenReturn(mScrimController); when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator); @@ -152,6 +181,38 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase { when(mKeyguardInteractor.isKeyguardDismissible()).thenReturn(MutableStateFlow(false)); } + /** + * Makes sure that touches go to the scene container when the flag is on. + */ + @Test + @EnableFlags(Flags.FLAG_SCENE_CONTAINER) + public void testSwipeUp_sendsTouchesToWindowRootView() { + mTouchHandler.onGlanceableTouchAvailable(true); + mTouchHandler.onSessionStart(mTouchSession); + ArgumentCaptor gestureListenerCaptor = + ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); + verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); + + final OnGestureListener gestureListener = gestureListenerCaptor.getValue(); + + final int screenHeight = 100; + final float distanceY = screenHeight * 0.42f; + + final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, + 0, screenHeight, 0); + final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, + 0, screenHeight - distanceY, 0); + + assertThat(gestureListener.onScroll(event1, event2, 0, + distanceY)) + .isTrue(); + + // Ensure only called once + verify(mSceneInteractor).onRemoteUserInputStarted(any()); + verify(mWindowRootView).dispatchTouchEvent(event1); + verify(mWindowRootView).dispatchTouchEvent(event2); + } + /** * Ensures expansion does not happen for full vertical swipes when touch is not available. */ diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java index 95681671b545..494e0b4deef4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java @@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @@ -37,12 +38,12 @@ import android.graphics.Rect; import android.graphics.Region; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.FlagsParameterization; import android.view.GestureDetector; import android.view.GestureDetector.OnGestureListener; import android.view.MotionEvent; import android.view.VelocityTracker; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; @@ -52,9 +53,12 @@ import com.android.systemui.ambient.touch.scrim.ScrimController; import com.android.systemui.ambient.touch.scrim.ScrimManager; import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants; import com.android.systemui.communal.ui.viewmodel.CommunalViewModel; +import com.android.systemui.flags.SceneContainerFlagParameterizationKt; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.kosmos.KosmosJavaAdapter; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.scene.domain.interactor.SceneInteractor; +import com.android.systemui.scene.ui.view.WindowRootView; import com.android.systemui.shade.ShadeExpansionChangeEvent; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.statusbar.NotificationShadeWindowController; @@ -70,10 +74,14 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import java.util.List; import java.util.Optional; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(ParameterizedAndroidJunit4.class) @DisableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { private KosmosJavaAdapter mKosmos; @@ -121,6 +129,9 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { @Mock Region mRegion; + @Mock + WindowRootView mWindowRootView; + @Mock CommunalViewModel mCommunalViewModel; @@ -130,6 +141,8 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { @Captor ArgumentCaptor mRectCaptor; + private SceneInteractor mSceneInteractor; + private static final float TOUCH_REGION = .3f; private static final int SCREEN_WIDTH_PX = 1024; private static final int SCREEN_HEIGHT_PX = 100; @@ -142,9 +155,21 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { /* flags= */ 0 ); + @Parameters(name = "{0}") + public static List getParams() { + return SceneContainerFlagParameterizationKt.parameterizeSceneContainerFlag(); + } + + public BouncerSwipeTouchHandlerTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setup() { mKosmos = new KosmosJavaAdapter(this); + mSceneInteractor = spy(mKosmos.getSceneInteractor()); + MockitoAnnotations.initMocks(this); mTouchHandler = new BouncerSwipeTouchHandler( mKosmos.getTestScope(), @@ -160,7 +185,10 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { MIN_BOUNCER_HEIGHT, mUiEventLogger, mActivityStarter, - mKeyguardInteractor); + mKeyguardInteractor, + mSceneInteractor, + Optional.of(() -> mWindowRootView) + ); when(mScrimManager.getCurrentController()).thenReturn(mScrimController); when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator); @@ -367,6 +395,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { * Makes sure the expansion amount is proportional to (1 - scroll). */ @Test + @DisableFlags(Flags.FLAG_SCENE_CONTAINER) public void testSwipeUp_setsCorrectExpansionAmount() { mTouchHandler.onSessionStart(mTouchSession); ArgumentCaptor gestureListenerCaptor = @@ -379,6 +408,36 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { verifyScroll(.7f, gestureListener); } + /** + * Makes sure that touches go to the scene container when the flag is on. + */ + @Test + @EnableFlags(Flags.FLAG_SCENE_CONTAINER) + public void testSwipeUp_sendsTouchesToWindowRootView() { + mTouchHandler.onSessionStart(mTouchSession); + ArgumentCaptor gestureListenerCaptor = + ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); + verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); + + final OnGestureListener gestureListener = gestureListenerCaptor.getValue(); + + final float distanceY = SCREEN_HEIGHT_PX * 0.42f; + + final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, + 0, SCREEN_HEIGHT_PX, 0); + final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, + 0, SCREEN_HEIGHT_PX - distanceY, 0); + + assertThat(gestureListener.onScroll(event1, event2, 0, + distanceY)) + .isTrue(); + + // Ensure only called once + verify(mSceneInteractor).onRemoteUserInputStarted(any()); + verify(mWindowRootView).dispatchTouchEvent(event1); + verify(mWindowRootView).dispatchTouchEvent(event2); + } + /** * Verifies that swiping up when the lock pattern is not secure dismissed dream and consumes * the gesture. @@ -476,6 +535,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { * Tests that ending an upward swipe before the set threshold leads to bouncer collapsing down. */ @Test + @DisableFlags(Flags.FLAG_SCENE_CONTAINER) public void testSwipeUpPositionBelowThreshold_collapsesBouncer() { final float swipeUpPercentage = .3f; final float expansion = 1 - swipeUpPercentage; @@ -499,6 +559,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { * Tests that ending an upward swipe above the set threshold will continue the expansion. */ @Test + @DisableFlags(Flags.FLAG_SCENE_CONTAINER) public void testSwipeUpPositionAboveThreshold_expandsBouncer() { final float swipeUpPercentage = .7f; final float expansion = 1 - swipeUpPercentage; @@ -528,6 +589,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { * Tests that swiping up with a speed above the set threshold will continue the expansion. */ @Test + @DisableFlags(Flags.FLAG_SCENE_CONTAINER) public void testSwipeUpVelocityAboveMin_expandsBouncer() { when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn((float) 0); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.kt index 38ea44976175..ad636cf613ad 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.kt @@ -18,9 +18,9 @@ package com.android.systemui.ambient.touch import android.app.DreamManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization import android.view.GestureDetector import android.view.MotionEvent -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.SysuiTestCase @@ -28,14 +28,20 @@ import com.android.systemui.ambient.touch.TouchHandler.TouchSession import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED +import com.android.systemui.flags.andSceneContainer import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.data.repository.sceneContainerRepository +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.ui.view.WindowRootView import com.android.systemui.shade.ShadeViewController import com.android.systemui.shared.system.InputChannelCompat import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.testKosmos import com.google.common.truth.Truth +import com.google.common.truth.Truth.assertThat import java.util.Optional +import javax.inject.Provider import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -47,22 +53,29 @@ import org.mockito.kotlin.never import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @SmallTest -@RunWith(AndroidJUnit4::class) -class ShadeTouchHandlerTest : SysuiTestCase() { +@RunWith(ParameterizedAndroidJunit4::class) +class ShadeTouchHandlerTest(flags: FlagsParameterization) : SysuiTestCase() { private var kosmos = testKosmos() private var mCentralSurfaces = mock() private var mShadeViewController = mock() private var mDreamManager = mock() private var mTouchSession = mock() private var communalViewModel = mock() + private var windowRootView = mock() private lateinit var mTouchHandler: ShadeTouchHandler private var mGestureListenerCaptor = argumentCaptor() private var mInputListenerCaptor = argumentCaptor() + init { + mSetFlagsRule.setFlagsParameterization(flags) + } + @Before fun setup() { mTouchHandler = @@ -73,7 +86,9 @@ class ShadeTouchHandlerTest : SysuiTestCase() { mDreamManager, communalViewModel, kosmos.communalSettingsInteractor, - TOUCH_HEIGHT + kosmos.sceneInteractor, + Optional.of(Provider { windowRootView }), + TOUCH_HEIGHT, ) } @@ -97,7 +112,7 @@ class ShadeTouchHandlerTest : SysuiTestCase() { // Verifies that a swipe down forwards captured touches to central surfaces for handling. @Test - @DisableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) + @DisableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX, Flags.FLAG_SCENE_CONTAINER) @EnableFlags(Flags.FLAG_COMMUNAL_HUB) fun testSwipeDown_communalEnabled_sentToCentralSurfaces() { kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) @@ -110,7 +125,11 @@ class ShadeTouchHandlerTest : SysuiTestCase() { // Verifies that a swipe down forwards captured touches to the shade view for handling. @Test - @DisableFlags(Flags.FLAG_COMMUNAL_HUB, Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) + @DisableFlags( + Flags.FLAG_COMMUNAL_HUB, + Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX, + Flags.FLAG_SCENE_CONTAINER, + ) fun testSwipeDown_communalDisabled_sentToShadeView() { swipe(Direction.DOWN) @@ -121,7 +140,7 @@ class ShadeTouchHandlerTest : SysuiTestCase() { // Verifies that a swipe down while dreaming forwards captured touches to the shade view for // handling. @Test - @DisableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) + @DisableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX, Flags.FLAG_SCENE_CONTAINER) fun testSwipeDown_dreaming_sentToShadeView() { whenever(mDreamManager.isDreaming).thenReturn(true) swipe(Direction.DOWN) @@ -130,9 +149,34 @@ class ShadeTouchHandlerTest : SysuiTestCase() { verify(mShadeViewController, times(2)).handleExternalTouch(any()) } - // Verifies that a swipe up is not forwarded to central surfaces. + // Verifies that a swipe down forwards captured touches to the window root view for handling. @Test + @EnableFlags(Flags.FLAG_COMMUNAL_HUB, Flags.FLAG_SCENE_CONTAINER) + fun testSwipeDown_sceneContainerEnabled_sentToWindowRootView() { + swipe(Direction.DOWN) + + // Both motion events are sent for central surfaces to process. + assertThat(kosmos.sceneContainerRepository.isRemoteUserInputOngoing.value).isTrue() + verify(windowRootView, times(2)).dispatchTouchEvent(any()) + } + + // Verifies that a swipe down while dreaming forwards captured touches to the window root view + // for handling. + @Test + @EnableFlags(Flags.FLAG_SCENE_CONTAINER) @DisableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) + fun testSwipeDown_dreaming_sentToWindowRootView() { + whenever(mDreamManager.isDreaming).thenReturn(true) + swipe(Direction.DOWN) + + // Both motion events are sent for the shade view to process. + assertThat(kosmos.sceneContainerRepository.isRemoteUserInputOngoing.value).isTrue() + verify(windowRootView, times(2)).dispatchTouchEvent(any()) + } + + // Verifies that a swipe up is not forwarded to central surfaces. + @Test + @DisableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX, Flags.FLAG_SCENE_CONTAINER) @EnableFlags(Flags.FLAG_COMMUNAL_HUB) fun testSwipeUp_communalEnabled_touchesNotSent() { kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) @@ -146,7 +190,11 @@ class ShadeTouchHandlerTest : SysuiTestCase() { // Verifies that a swipe up is not forwarded to the shade view. @Test - @DisableFlags(Flags.FLAG_COMMUNAL_HUB, Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) + @DisableFlags( + Flags.FLAG_COMMUNAL_HUB, + Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX, + Flags.FLAG_SCENE_CONTAINER, + ) fun testSwipeUp_communalDisabled_touchesNotSent() { swipe(Direction.UP) @@ -155,6 +203,17 @@ class ShadeTouchHandlerTest : SysuiTestCase() { verify(mShadeViewController, never()).handleExternalTouch(any()) } + // Verifies that a swipe up is not forwarded to the window root view. + @Test + @EnableFlags(Flags.FLAG_COMMUNAL_HUB, Flags.FLAG_SCENE_CONTAINER) + fun testSwipeUp_sceneContainerEnabled_touchesNotSent() { + swipe(Direction.UP) + + // Motion events are not sent for window root view to process as the swipe is going in the + // wrong direction. + verify(windowRootView, never()).dispatchTouchEvent(any()) + } + @Test @DisableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) fun testCancelMotionEvent_popsTouchSession() { @@ -243,10 +302,16 @@ class ShadeTouchHandlerTest : SysuiTestCase() { private enum class Direction { DOWN, - UP + UP, } companion object { private const val TOUCH_HEIGHT = 20 + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List { + return FlagsParameterization.allCombinationsOf().andSceneContainer() + } } } diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt index fd06bb174ea3..a55f9ffd1c5a 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt @@ -38,6 +38,9 @@ import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.ui.view.WindowRootView import com.android.systemui.shade.ShadeExpansionChangeEvent import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.phone.CentralSurfaces @@ -45,6 +48,7 @@ import com.android.wm.shell.animation.FlingAnimationUtils import java.util.Optional import javax.inject.Inject import javax.inject.Named +import javax.inject.Provider import kotlin.math.abs import kotlin.math.hypot import kotlin.math.max @@ -74,6 +78,8 @@ constructor( private val uiEventLogger: UiEventLogger, private val activityStarter: ActivityStarter, private val keyguardInteractor: KeyguardInteractor, + private val sceneInteractor: SceneInteractor, + private val windowRootViewProvider: Optional>, ) : TouchHandler { /** An interface for creating ValueAnimators. */ interface ValueAnimatorCreator { @@ -100,6 +106,8 @@ constructor( currentScrimController = controller } + private val windowRootView by lazy { windowRootViewProvider.get().get() } + /** Determines whether the touch handler should process touches in fullscreen swiping mode */ private var touchAvailable = false @@ -109,7 +117,7 @@ constructor( e1: MotionEvent?, e2: MotionEvent, distanceX: Float, - distanceY: Float + distanceY: Float, ): Boolean { if (capture == null) { capture = @@ -128,6 +136,11 @@ constructor( expanded = false // Since the user is dragging the bouncer up, set scrimmed to false. currentScrimController?.show() + + if (SceneContainerFlag.isEnabled) { + sceneInteractor.onRemoteUserInputStarted("bouncer touch handler") + e1?.apply { windowRootView.dispatchTouchEvent(e1) } + } } } if (capture != true) { @@ -152,20 +165,27 @@ constructor( /* cancelAction= */ null, /* dismissShade= */ true, /* afterKeyguardGone= */ true, - /* deferred= */ false + /* deferred= */ false, ) return true } - // For consistency, we adopt the expansion definition found in the - // PanelViewController. In this case, expansion refers to the view above the - // bouncer. As that view's expansion shrinks, the bouncer appears. The bouncer - // is fully hidden at full expansion (1) and fully visible when fully collapsed - // (0). - touchSession?.apply { - val screenTravelPercentage = - (abs((this@outer.y - e2.y).toDouble()) / getBounds().height()).toFloat() - setPanelExpansion(1 - screenTravelPercentage) + if (SceneContainerFlag.isEnabled) { + windowRootView.dispatchTouchEvent(e2) + } else { + // For consistency, we adopt the expansion definition found in the + // PanelViewController. In this case, expansion refers to the view above the + // bouncer. As that view's expansion shrinks, the bouncer appears. The + // bouncer + // is fully hidden at full expansion (1) and fully visible when fully + // collapsed + // (0). + touchSession?.apply { + val screenTravelPercentage = + (abs((this@outer.y - e2.y).toDouble()) / getBounds().height()) + .toFloat() + setPanelExpansion(1 - screenTravelPercentage) + } } } @@ -194,7 +214,7 @@ constructor( ShadeExpansionChangeEvent( /* fraction= */ currentExpansion, /* expanded= */ expanded, - /* tracking= */ true + /* tracking= */ true, ) currentScrimController?.expand(event) } @@ -347,7 +367,7 @@ constructor( currentHeight, targetHeight, velocity, - viewHeight + viewHeight, ) } else { // Shows the bouncer, i.e., fully collapses the space above the bouncer. @@ -356,7 +376,7 @@ constructor( currentHeight, targetHeight, velocity, - viewHeight + viewHeight, ) } animator.start() diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.kt b/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.kt index 9da9a3a98ef5..3cf94ba558fe 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/ShadeTouchHandler.kt @@ -27,11 +27,15 @@ import com.android.systemui.ambient.touch.TouchHandler.TouchSession import com.android.systemui.ambient.touch.dagger.ShadeModule import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.ui.viewmodel.CommunalViewModel +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.ui.view.WindowRootView import com.android.systemui.shade.ShadeViewController import com.android.systemui.statusbar.phone.CentralSurfaces import java.util.Optional import javax.inject.Inject import javax.inject.Named +import javax.inject.Provider import kotlin.math.abs import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -49,8 +53,10 @@ constructor( private val dreamManager: DreamManager, private val communalViewModel: CommunalViewModel, private val communalSettingsInteractor: CommunalSettingsInteractor, + private val sceneInteractor: SceneInteractor, + private val windowRootViewProvider: Optional>, @param:Named(ShadeModule.NOTIFICATION_SHADE_GESTURE_INITIATION_HEIGHT) - private val initiationHeight: Int + private val initiationHeight: Int, ) : TouchHandler { /** * Tracks whether or not we are capturing a given touch. Will be null before and after a touch. @@ -60,6 +66,8 @@ constructor( /** Determines whether the touch handler should process touches in fullscreen swiping mode */ private var touchAvailable = false + private val windowRootView by lazy { windowRootViewProvider.get().get() } + init { if (Flags.hubmodeFullscreenVerticalSwipeFix()) { scope.launch { @@ -100,7 +108,7 @@ constructor( e1: MotionEvent?, e2: MotionEvent, distanceX: Float, - distanceY: Float + distanceY: Float, ): Boolean { if (capture == null) { // Only capture swipes that are going downwards. @@ -110,6 +118,10 @@ constructor( if (Flags.hubmodeFullscreenVerticalSwipeFix()) touchAvailable else true if (capture == true) { + if (SceneContainerFlag.isEnabled) { + sceneInteractor.onRemoteUserInputStarted("shade touch handler") + } + // Send the initial touches over, as the input listener has already // processed these touches. e1?.apply { sendTouchEvent(this) } @@ -123,7 +135,7 @@ constructor( e1: MotionEvent?, e2: MotionEvent, velocityX: Float, - velocityY: Float + velocityY: Float, ): Boolean { return capture == true } @@ -132,6 +144,11 @@ constructor( } private fun sendTouchEvent(event: MotionEvent) { + if (SceneContainerFlag.isEnabled) { + windowRootView.dispatchTouchEvent(event) + return + } + if (communalSettingsInteractor.isCommunalFlagEnabled() && !dreamManager.isDreaming) { // Send touches to central surfaces only when on the glanceable hub while not dreaming. // While sending touches where while dreaming will open the shade, the shade diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/ShadeModule.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/ShadeModule.java index bc2f35467312..1c781d608b04 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/ShadeModule.java +++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/ShadeModule.java @@ -22,8 +22,10 @@ import com.android.systemui.ambient.touch.ShadeTouchHandler; import com.android.systemui.ambient.touch.TouchHandler; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.res.R; +import com.android.systemui.scene.ui.view.WindowRootView; import dagger.Binds; +import dagger.BindsOptionalOf; import dagger.Module; import dagger.Provides; import dagger.multibindings.IntoSet; @@ -50,6 +52,13 @@ public abstract class ShadeModule { public abstract TouchHandler providesNotificationShadeTouchHandler( ShadeTouchHandler touchHandler); + /** + * Window root view is used to send touches to the scene container. Declaring as optional as it + * may not be present on all SysUI variants. + */ + @BindsOptionalOf + abstract WindowRootView bindWindowRootView(); + /** * Provides the height of the gesture area for notification swipe down. */ diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index 7a6ca0859a09..1ffbbd2a9f32 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -65,7 +65,6 @@ import com.android.systemui.dreams.dagger.DreamOverlayComponent; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.navigationbar.gestural.domain.GestureInteractor; import com.android.systemui.navigationbar.gestural.domain.TaskMatcher; -import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.shade.ShadeExpansionChangeEvent; import com.android.systemui.touch.TouchInsetManager; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -503,10 +502,10 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ mDreamOverlayContainerViewController = dreamOverlayComponent.getDreamOverlayContainerViewController(); - if (!SceneContainerFlag.isEnabled()) { - mTouchMonitor = ambientTouchComponent.getTouchMonitor(); - mTouchMonitor.init(); - } + // Touch monitor are also used with SceneContainer. See individual touch handlers for + // handling of SceneContainer. + mTouchMonitor = ambientTouchComponent.getTouchMonitor(); + mTouchMonitor.init(); mStateController.setShouldShowComplications(shouldShowComplications()); diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java index 12984efb52c2..85fb90d32d98 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java @@ -30,8 +30,10 @@ import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarViewController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.DreamOverlayContainerView; import com.android.systemui.res.R; +import com.android.systemui.scene.ui.view.WindowRootView; import com.android.systemui.touch.TouchInsetManager; +import dagger.BindsOptionalOf; import dagger.Module; import dagger.Provides; @@ -54,6 +56,13 @@ public abstract class DreamOverlayModule { public static final String DREAM_IN_TRANSLATION_Y_DURATION = "dream_in_complications_translation_y_duration"; + /** + * Window root view is used to send touches to the scene container. Declaring as optional as it + * may not be present on all SysUI variants. + */ + @BindsOptionalOf + abstract WindowRootView bindWindowRootView(); + /** */ @Provides @DreamOverlayComponent.DreamOverlayScope diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java index 5ba780f9c99d..42a68771cdcf 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java @@ -31,6 +31,9 @@ import com.android.systemui.ambient.touch.TouchHandler; import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor; import com.android.systemui.communal.domain.interactor.CommunalInteractor; import com.android.systemui.dreams.touch.dagger.CommunalTouchModule; +import com.android.systemui.scene.domain.interactor.SceneInteractor; +import com.android.systemui.scene.shared.flag.SceneContainerFlag; +import com.android.systemui.scene.ui.view.WindowRootView; import com.android.systemui.statusbar.phone.CentralSurfaces; import kotlinx.coroutines.Job; @@ -42,6 +45,7 @@ import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Provider; /** {@link TouchHandler} responsible for handling touches to open communal hub. **/ public class CommunalTouchHandler implements TouchHandler { @@ -51,6 +55,8 @@ public class CommunalTouchHandler implements TouchHandler { private final CommunalInteractor mCommunalInteractor; private final ConfigurationInteractor mConfigurationInteractor; + private final SceneInteractor mSceneInteractor; + private final WindowRootView mWindowRootView; private Boolean mIsEnabled = false; private ArrayList mFlows = new ArrayList<>(); @@ -69,12 +75,16 @@ public class CommunalTouchHandler implements TouchHandler { @Named(CommunalTouchModule.COMMUNAL_GESTURE_INITIATION_WIDTH) int initiationWidth, CommunalInteractor communalInteractor, ConfigurationInteractor configurationInteractor, + SceneInteractor sceneInteractor, + Optional> windowRootViewProvider, Lifecycle lifecycle) { mInitiationWidth = initiationWidth; mCentralSurfaces = centralSurfaces; mLifecycle = lifecycle; mCommunalInteractor = communalInteractor; mConfigurationInteractor = configurationInteractor; + mSceneInteractor = sceneInteractor; + mWindowRootView = windowRootViewProvider.get().get(); mFlows.add(collectFlow( mLifecycle, @@ -125,8 +135,15 @@ public class CommunalTouchHandler implements TouchHandler { private void handleSessionStart(CentralSurfaces surfaces, TouchSession session) { // Notification shade window has its own logic to be visible if the hub is open, no need to // do anything here other than send touch events over. + if (SceneContainerFlag.isEnabled()) { + mSceneInteractor.onRemoteUserInputStarted("communal touch handler"); + } session.registerInputListener(ev -> { - surfaces.handleCommunalHubTouch((MotionEvent) ev); + if (SceneContainerFlag.isEnabled()) { + mWindowRootView.dispatchTouchEvent((MotionEvent) ev); + } else { + surfaces.handleCommunalHubTouch((MotionEvent) ev); + } if (ev != null && ((MotionEvent) ev).getAction() == MotionEvent.ACTION_UP) { var unused = session.pop(); } -- cgit v1.2.3-59-g8ed1b