diff options
| author | 2024-05-08 17:05:48 +0000 | |
|---|---|---|
| committer | 2024-05-08 17:05:48 +0000 | |
| commit | b2f78516b8f9426984e69ac4f3802daa1115e0c0 (patch) | |
| tree | f5e5d731a2ec8c670990e1357cef354254cb0f5c | |
| parent | 29bf3d33e4bebfc54fbfae58d9e2c6ce67bb3ea4 (diff) | |
| parent | 69a87b54db27c8e6ba0abe50d0dbafe0df76aaf9 (diff) | |
Merge changes Ic4b0695c,I89c2094f into main
* changes:
Capture touches during hub transition, not only when fully open
Turn off GlanceableHubContainerController when scene container is enabled
5 files changed, 84 insertions, 99 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index 851bfca56359..281857fb0658 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -47,6 +47,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.SceneDataSourceDelegator import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.phone.SystemUIDialogFactory @@ -69,7 +70,6 @@ constructor( private val communalInteractor: CommunalInteractor, private val communalViewModel: CommunalViewModel, private val dialogFactory: SystemUIDialogFactory, - private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val keyguardInteractor: KeyguardInteractor, private val shadeInteractor: ShadeInteractor, private val powerManager: PowerManager, @@ -102,12 +102,9 @@ constructor( private var rightEdgeSwipeRegionWidth: Int = 0 /** - * True if we are currently tracking a gesture for opening the hub that started in the edge - * swipe region. + * True if we are currently tracking a touch intercepted by the hub, either because the hub is + * open or being opened. */ - private var isTrackingOpenGesture = false - - /** True if we are currently tracking a touch on the hub while it's open. */ private var isTrackingHubTouch = false /** @@ -153,7 +150,7 @@ constructor( /** * Creates the container view containing the glanceable hub UI. * - * @throws RuntimeException if [isEnabled] is false or the view is already initialized + * @throws RuntimeException if the view is already initialized */ fun initView( context: Context, @@ -197,6 +194,7 @@ constructor( /** Override for testing. */ @VisibleForTesting internal fun initView(containerView: View): View { + SceneContainerFlag.assertInLegacyMode() if (communalContainerView != null) { throw RuntimeException("Communal view has already been initialized") } @@ -227,7 +225,7 @@ constructor( // BouncerSwipeTouchHandler has a larger gesture area than we want, set an exclusion area so // the gesture area doesn't overlap with widgets. - // TODO(b/323035776): adjust gesture areaa for portrait mode + // TODO(b/323035776): adjust gesture area for portrait mode containerView.repeatWhenAttached { // Run when the touch handling lifecycle is RESUMED, meaning the hub is visible and not // occluded. @@ -261,7 +259,7 @@ constructor( ) collectFlow( containerView, - communalInteractor.isCommunalShowing, + communalInteractor.isCommunalVisible, { hubShowing = it updateTouchHandlingState() @@ -306,6 +304,7 @@ constructor( /** Removes the container view from its parent. */ fun disposeView() { + SceneContainerFlag.assertInLegacyMode() communalContainerView?.let { (it.parent as ViewGroup).removeView(it) lifecycleRegistry.currentState = Lifecycle.State.CREATED @@ -323,71 +322,30 @@ constructor( * to be fully in control of its own touch handling. */ fun onTouchEvent(ev: MotionEvent): Boolean { + SceneContainerFlag.assertInLegacyMode() return communalContainerView?.let { handleTouchEventOnCommunalView(it, ev) } ?: false } private fun handleTouchEventOnCommunalView(view: View, ev: MotionEvent): Boolean { - // If the hub is fully visible, send all touch events to it, other than top and bottom edge - // swipes. - return if (hubShowing) { - handleHubOpenTouch(view, ev) - } else { - handleHubClosedTouch(view, ev) - } - } - - private fun handleHubOpenTouch(view: View, ev: MotionEvent): Boolean { - val isDown = ev.actionMasked == MotionEvent.ACTION_DOWN - val isUp = ev.actionMasked == MotionEvent.ACTION_UP - val isCancel = ev.actionMasked == MotionEvent.ACTION_CANCEL - - val hubOccluded = anyBouncerShowing || shadeShowing - - if (isDown && !hubOccluded) { - // Only intercept down events if the hub isn't occluded by the bouncer or - // notification shade. - isTrackingHubTouch = true - } - - if (isTrackingHubTouch) { - // Tracking a touch on the hub UI itself. - if (isUp || isCancel) { - isTrackingHubTouch = false - } - dispatchTouchEvent(view, ev) - // Return true regardless of dispatch result as some touches at the start of a - // gesture - // may return false from dispatchTouchEvent. - return true - } - - return false - } - - private fun handleHubClosedTouch(view: View, ev: MotionEvent): Boolean { val isDown = ev.actionMasked == MotionEvent.ACTION_DOWN val isUp = ev.actionMasked == MotionEvent.ACTION_UP val isCancel = ev.actionMasked == MotionEvent.ACTION_CANCEL val hubOccluded = anyBouncerShowing || shadeShowing - if (rightEdgeSwipeRegionWidth == 0) { - // If the edge region width has not been read yet for whatever reason, don't bother - // intercepting touches to open the hub. - return false - } - if (isDown && !hubOccluded) { val x = ev.rawX val inOpeningSwipeRegion: Boolean = x >= view.width - rightEdgeSwipeRegionWidth - if (inOpeningSwipeRegion) { - isTrackingOpenGesture = true + if (inOpeningSwipeRegion || hubShowing) { + // Steal touch events when the hub is open, or if the touch started in the opening + // gesture region. + isTrackingHubTouch = true } } - if (isTrackingOpenGesture) { + if (isTrackingHubTouch) { if (isUp || isCancel) { - isTrackingOpenGesture = false + isTrackingHubTouch = false } dispatchTouchEvent(view, ev) // Return true regardless of dispatch result as some touches at the start of a gesture diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 44f86da7431e..b50a3cd442d3 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -52,6 +52,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.keyguard.shared.model.TransitionState; import com.android.systemui.keyguard.shared.model.TransitionStep; import com.android.systemui.res.R; +import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener; import com.android.systemui.statusbar.DragDownHelper; @@ -357,7 +358,9 @@ public class NotificationShadeWindowViewController implements Dumpable { mFalsingCollector.onTouchEvent(ev); mPulsingWakeupGestureHandler.onTouchEvent(ev); - if (mGlanceableHubContainerController.onTouchEvent(ev)) { + if (!SceneContainerFlag.isEnabled() + && mGlanceableHubContainerController.onTouchEvent(ev)) { + // GlanceableHubContainerController is only used pre-flexiglass. return logDownDispatch(ev, "dispatched to glanceable hub container", true); } if (mDreamingWakeupGestureHandler != null @@ -621,6 +624,10 @@ public class NotificationShadeWindowViewController implements Dumpable { * The layout lives in {@link R.id.communal_ui_stub}. */ public void setupCommunalHubLayout() { + if (SceneContainerFlag.isEnabled()) { + // GlanceableHubContainerController is only used pre-flexiglass. + return; + } collectFlow( mView, mGlanceableHubContainerController.communalAvailable(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt index 99204e75e5a3..537049c7b957 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt @@ -18,7 +18,7 @@ package com.android.systemui.shade import android.graphics.Rect import android.os.PowerManager -import android.platform.test.flag.junit.FlagsParameterization +import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.testing.ViewUtils import android.view.MotionEvent @@ -27,6 +27,7 @@ import android.widget.FrameLayout import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.systemui.Flags import com.android.systemui.SysuiTestCase @@ -42,16 +43,11 @@ import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.communal.util.CommunalColors import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.flags.andSceneContainer import com.android.systemui.keyguard.domain.interactor.keyguardInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.res.R -import com.android.systemui.scene.domain.interactor.sceneInteractor -import com.android.systemui.scene.shared.flag.SceneContainerFlag -import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.sceneDataSourceDelegator import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.phone.SystemUIDialogFactory @@ -59,6 +55,7 @@ import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest @@ -71,14 +68,12 @@ import org.mockito.Mock import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations -import platform.test.runner.parameterized.ParameterizedAndroidJunit4 -import platform.test.runner.parameterized.Parameters @ExperimentalCoroutinesApi -@RunWith(ParameterizedAndroidJunit4::class) +@RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest -class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : SysuiTestCase() { +class GlanceableHubContainerControllerTest : SysuiTestCase() { private val kosmos: Kosmos = testKosmos().apply { // UnconfinedTestDispatcher makes testing simpler due to CommunalInteractor flows using @@ -100,10 +95,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu private lateinit var communalRepository: FakeCommunalRepository private lateinit var underTest: GlanceableHubContainerController - init { - mSetFlagsRule.setFlagsParameterization(flags!!) - } - @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -127,7 +118,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu communalInteractor, communalViewModel, dialogFactory, - keyguardTransitionInteractor, keyguardInteractor, shadeInteractor, powerManager, @@ -170,7 +160,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu communalInteractor, communalViewModel, dialogFactory, - keyguardTransitionInteractor, keyguardInteractor, shadeInteractor, powerManager, @@ -216,13 +205,39 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu } @Test + fun onTouchEvent_communalTransitioning_interceptsTouches() = + with(kosmos) { + testScope.runTest { + // Communal is opening. + communalRepository.setTransitionState( + flowOf( + ObservableTransitionState.Transition( + fromScene = CommunalScenes.Blank, + toScene = CommunalScenes.Communal, + currentScene = flowOf(CommunalScenes.Blank), + progress = flowOf(0.5f), + isInitiatedByUserInput = true, + isUserInputOngoing = flowOf(true) + ) + ) + ) + testableLooper.processAllMessages() + + // Touch events are intercepted. + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() + // User activity sent to PowerManager. + verify(powerManager).userActivity(any(), any(), any()) + } + } + + @Test fun onTouchEvent_communalOpen_interceptsTouches() = with(kosmos) { testScope.runTest { // Communal is open. goToScene(CommunalScenes.Communal) - // Touch events are intercepted outside of any gesture areas. + // Touch events are intercepted. assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() // User activity sent to PowerManager. verify(powerManager).userActivity(any(), any(), any()) @@ -289,7 +304,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu communalInteractor, communalViewModel, dialogFactory, - keyguardTransitionInteractor, keyguardInteractor, shadeInteractor, powerManager, @@ -309,7 +323,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu communalInteractor, communalViewModel, dialogFactory, - keyguardTransitionInteractor, keyguardInteractor, shadeInteractor, powerManager, @@ -501,13 +514,6 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu } private fun goToScene(scene: SceneKey) { - if (SceneContainerFlag.isEnabled) { - if (scene == CommunalScenes.Communal) { - kosmos.sceneInteractor.changeScene(Scenes.Communal, "test") - } else { - kosmos.sceneInteractor.changeScene(Scenes.Lockscreen, "test") - } - } communalRepository.changeScene(scene) testableLooper.processAllMessages() } @@ -536,11 +542,5 @@ class GlanceableHubContainerControllerTest(flags: FlagsParameterization?) : Sysu MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, CONTAINER_WIDTH.toFloat(), 0f, 0) private val MOVE_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0) private val UP_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0) - - @JvmStatic - @Parameters(name = "{0}") - fun getParams(): List<FlagsParameterization> { - return FlagsParameterization.allCombinationsOf().andSceneContainer() - } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 112829af2068..a867b0f7df00 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -17,12 +17,15 @@ package com.android.systemui.shade import android.content.Context +import android.platform.test.annotations.RequiresFlagsDisabled import android.platform.test.flag.junit.FlagsParameterization +import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper import android.view.KeyEvent import android.view.MotionEvent import android.view.View import android.view.ViewGroup +import android.view.ViewTreeObserver import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardSecurityContainerController import com.android.keyguard.LegacyLockIconViewController @@ -72,7 +75,6 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat -import java.util.Optional import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.emptyFlow @@ -80,12 +82,12 @@ import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito.anyFloat +import org.mockito.Mockito.atLeast import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.times @@ -93,6 +95,7 @@ import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters +import java.util.Optional import org.mockito.Mockito.`when` as whenever @OptIn(ExperimentalCoroutinesApi::class) @@ -152,6 +155,7 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization?) : private lateinit var underTest: NotificationShadeWindowViewController private lateinit var testScope: TestScope + private lateinit var testableLooper: TestableLooper private lateinit var featureFlagsClassic: FakeFeatureFlagsClassic @@ -181,6 +185,7 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization?) : mSetFlagsRule.enableFlags(Flags.FLAG_REVAMPED_BOUNCER_MESSAGES) testScope = TestScope() + testableLooper = TestableLooper.get(this) falsingCollector = FalsingCollectorFake() fakeClock = FakeSystemClock() underTest = @@ -407,6 +412,7 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization?) : } @Test + @DisableSceneContainer fun handleDispatchTouchEvent_glanceableHubIntercepts_returnsTrue() { whenever(mGlanceableHubContainerController.onTouchEvent(DOWN_EVENT)).thenReturn(true) underTest.setStatusBarViewController(phoneStatusBarViewController) @@ -559,29 +565,42 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization?) : } @Test - @Ignore("b/321332798") + @DisableSceneContainer fun setsUpCommunalHubLayout_whenFlagEnabled() { whenever(mGlanceableHubContainerController.communalAvailable()) - .thenReturn(MutableStateFlow(true)) + .thenReturn(MutableStateFlow(true)) - val mockCommunalView = mock(View::class.java) + val communalView = View(context) whenever(mGlanceableHubContainerController.initView(any<Context>())) - .thenReturn(mockCommunalView) + .thenReturn(communalView) val mockCommunalPlaceholder = mock(View::class.java) val fakeViewIndex = 20 whenever(view.findViewById<View>(R.id.communal_ui_stub)).thenReturn(mockCommunalPlaceholder) whenever(view.indexOfChild(mockCommunalPlaceholder)).thenReturn(fakeViewIndex) whenever(view.context).thenReturn(context) + whenever(view.viewTreeObserver).thenReturn(mock(ViewTreeObserver::class.java)) underTest.setupCommunalHubLayout() - // Communal view added as a child of the container at the proper index, the stub is removed. - verify(view).removeView(mockCommunalPlaceholder) - verify(view).addView(eq(mockCommunalView), eq(fakeViewIndex)) + // Simluate attaching the view so flow collection starts. + val onAttachStateChangeListenerArgumentCaptor = ArgumentCaptor.forClass( + View.OnAttachStateChangeListener::class.java + ) + verify(view, atLeast(1)).addOnAttachStateChangeListener( + onAttachStateChangeListenerArgumentCaptor.capture() + ) + for (listener in onAttachStateChangeListenerArgumentCaptor.allValues) { + listener.onViewAttachedToWindow(view) + } + testableLooper.processAllMessages() + + // Communal view added as a child of the container at the proper index. + verify(view).addView(eq(communalView), eq(fakeViewIndex)) } @Test + @RequiresFlagsDisabled(Flags.FLAG_COMMUNAL_HUB) fun doesNotSetupCommunalHubLayout_whenFlagDisabled() { whenever(mGlanceableHubContainerController.communalAvailable()) .thenReturn(MutableStateFlow(false)) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt index 9f5c6b8faa38..d958bae7ae2a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt @@ -23,6 +23,7 @@ class FakeCommunalRepository( ) : CommunalRepository { override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) { this.currentScene.value = toScene + this._transitionState.value = flowOf(ObservableTransitionState.Idle(toScene)) } private val defaultTransitionState = ObservableTransitionState.Idle(CommunalScenes.Default) |