summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author William Xiao <wxyz@google.com> 2024-05-08 17:05:48 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-05-08 17:05:48 +0000
commitb2f78516b8f9426984e69ac4f3802daa1115e0c0 (patch)
treef5e5d731a2ec8c670990e1357cef354254cb0f5c
parent29bf3d33e4bebfc54fbfae58d9e2c6ce67bb3ea4 (diff)
parent69a87b54db27c8e6ba0abe50d0dbafe0df76aaf9 (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
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt64
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt37
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt1
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)