Forward CommunalContainer touches when hub mode closed

CommunalContainer is currently placed above keyguard in the SysUI
window. Our SceneContainerLayout consumes all touches it receives even
when hub mode is closed and only the edge swipe gesture is active. This
also causes the screen timeout to not be refreshed for touches in hub
mode.

This change forwards touches outside the edge swipe zone to the
ShadeViewController so that some basics like swipe down to open the
notifications or up to show the bouncer will work. We also send a user
activity event to PowerManager to refresh the screen timeout. This is
only intended as a temporary improvement while we figure out the
details of moving CommunalContainer to a lower z-order, where it will
no longer block touches.

Note that taps and gestures on lock screen notifications or in the
notification shade still do not work as those are not handled by
ShadeViewController.

DefaultCommunalHubSection is cleaned up a bit as it causes a circular
dependency otherwise. It is slated for deletion in b/306485186.

Bug: 308813166
Bug: 309170620
Fixed: 309170620
Flag: ACONFIG com.android.systemui.communal_hub DEVELOPMENT
Test: atest CommunalViewModelTest CommunalEditModeViewModelTest
      also manually verified on device that swipe up/down work on lock
      screen with communal_hub flag on
Change-Id: I231b150f42c10f7973a721e0b92e895f36999ff1
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 2c4dc80..185a06c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -7,6 +7,7 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.width
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Close
@@ -19,8 +20,10 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.pointer.pointerInteropFilter
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.ElementKey
@@ -28,6 +31,7 @@
 import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.SceneTransitionLayoutState
 import com.android.compose.animation.scene.Swipe
 import com.android.compose.animation.scene.SwipeDirection
 import com.android.compose.animation.scene.transitions
@@ -56,6 +60,7 @@
  * This is a temporary container to allow the communal UI to use [SceneTransitionLayout] for gesture
  * handling and transitions before the full Flexiglass layout is ready.
  */
+@OptIn(ExperimentalComposeUiApi::class)
 @Composable
 fun CommunalContainer(
     modifier: Modifier = Modifier,
@@ -65,6 +70,7 @@
         viewModel.currentScene
             .transform<CommunalSceneKey, SceneKey> { value -> value.toTransitionSceneKey() }
             .collectAsState(TransitionSceneKey.Blank)
+    val sceneTransitionLayoutState = remember { SceneTransitionLayoutState(currentScene) }
     // Don't show hub mode UI if keyguard is present. This is important since we're in the shade,
     // which can be opened from many locations.
     val isKeyguardShowing by viewModel.isKeyguardVisible.collectAsState(initial = false)
@@ -75,32 +81,59 @@
         return
     }
 
-    SceneTransitionLayout(
-        modifier = modifier.fillMaxSize(),
-        currentScene = currentScene,
-        onChangeScene = { sceneKey -> viewModel.onSceneChanged(sceneKey.toCommunalSceneKey()) },
-        transitions = sceneTransitions,
-        edgeDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize)
-    ) {
-        scene(
-            TransitionSceneKey.Blank,
-            userActions =
-                mapOf(
-                    Swipe(SwipeDirection.Left, fromEdge = Edge.Right) to TransitionSceneKey.Communal
-                )
+    Box(modifier = modifier.fillMaxSize()) {
+        SceneTransitionLayout(
+            modifier = Modifier.fillMaxSize(),
+            currentScene = currentScene,
+            onChangeScene = { sceneKey -> viewModel.onSceneChanged(sceneKey.toCommunalSceneKey()) },
+            transitions = sceneTransitions,
+            state = sceneTransitionLayoutState,
+            edgeDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize)
         ) {
-            BlankScene { showSceneTransitionLayout = false }
+            scene(
+                TransitionSceneKey.Blank,
+                userActions =
+                    mapOf(
+                        Swipe(SwipeDirection.Left, fromEdge = Edge.Right) to
+                            TransitionSceneKey.Communal
+                    )
+            ) {
+                BlankScene { showSceneTransitionLayout = false }
+            }
+
+            scene(
+                TransitionSceneKey.Communal,
+                userActions =
+                    mapOf(
+                        Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to
+                            TransitionSceneKey.Blank
+                    ),
+            ) {
+                CommunalScene(viewModel, modifier = modifier)
+            }
         }
 
-        scene(
-            TransitionSceneKey.Communal,
-            userActions =
-                mapOf(
-                    Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to TransitionSceneKey.Blank
-                ),
-        ) {
-            CommunalScene(viewModel, modifier = modifier)
-        }
+        // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't
+        //  block touches anymore.
+        Box(
+            modifier =
+                Modifier.fillMaxSize()
+                    // Offsetting to the left so that edge swipe to open the hub still works. This
+                    // does mean that the very right edge of the hub won't refresh the screen
+                    // timeout, but should be good enough for a temporary solution.
+                    .offset(x = -ContainerDimensions.EdgeSwipeSize)
+                    .pointerInteropFilter {
+                        viewModel.onUserActivity()
+                        if (
+                            sceneTransitionLayoutState.transitionState.currentScene ==
+                                TransitionSceneKey.Blank
+                        ) {
+                            viewModel.onOuterTouch(it)
+                            return@pointerInteropFilter true
+                        }
+                        false
+                    }
+        )
     }
 }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index ce7db80..ea3006f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.communal.view.viewmodel
 
 import android.app.smartspace.SmartspaceTarget
+import android.os.PowerManager
 import android.provider.Settings
 import android.widget.RemoteViews
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -33,6 +34,7 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.media.controls.ui.MediaHost
+import com.android.systemui.shade.ShadeViewController
 import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -50,6 +52,8 @@
 @RunWith(AndroidJUnit4::class)
 class CommunalEditModeViewModelTest : SysuiTestCase() {
     @Mock private lateinit var mediaHost: MediaHost
+    @Mock private lateinit var shadeViewController: ShadeViewController
+    @Mock private lateinit var powerManager: PowerManager
 
     private lateinit var testScope: TestScope
 
@@ -79,6 +83,8 @@
         underTest =
             CommunalEditModeViewModel(
                 withDeps.communalInteractor,
+                shadeViewController,
+                powerManager,
                 mediaHost,
             )
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 32f4d07..9bd0835 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.communal.view.viewmodel
 
 import android.app.smartspace.SmartspaceTarget
+import android.os.PowerManager
 import android.provider.Settings
 import android.widget.RemoteViews
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -33,6 +34,7 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.media.controls.ui.MediaHost
+import com.android.systemui.shade.ShadeViewController
 import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -50,6 +52,8 @@
 @RunWith(AndroidJUnit4::class)
 class CommunalViewModelTest : SysuiTestCase() {
     @Mock private lateinit var mediaHost: MediaHost
+    @Mock private lateinit var shadeViewController: ShadeViewController
+    @Mock private lateinit var powerManager: PowerManager
 
     private lateinit var testScope: TestScope
 
@@ -80,6 +84,8 @@
             CommunalViewModel(
                 withDeps.communalInteractor,
                 withDeps.tutorialInteractor,
+                shadeViewController,
+                powerManager,
                 mediaHost,
             )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalHubSection.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalHubSection.kt
index ad02f62..4219d6d6 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalHubSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalHubSection.kt
@@ -2,63 +2,16 @@
 
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
-import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.keyguard.shared.model.KeyguardSection
-import com.android.systemui.keyguard.ui.view.layout.sections.removeView
-import com.android.systemui.res.R
 import javax.inject.Inject
 
 /** A keyguard section that hosts the communal hub. */
-class DefaultCommunalHubSection
-@Inject
-constructor(
-    private val viewModel: CommunalViewModel,
-) : KeyguardSection() {
-    private val communalHubViewId = R.id.communal_hub
-
-    override fun addViews(constraintLayout: ConstraintLayout) {
-        constraintLayout.addView(
-            ComposeFacade.createCommunalView(
-                    context = constraintLayout.context,
-                    viewModel = viewModel,
-                )
-                .apply { id = communalHubViewId },
-        )
-    }
+class DefaultCommunalHubSection @Inject constructor() : KeyguardSection() {
+    override fun addViews(constraintLayout: ConstraintLayout) {}
 
     override fun bindData(constraintLayout: ConstraintLayout) {}
 
-    override fun applyConstraints(constraintSet: ConstraintSet) {
-        constraintSet.apply {
-            connect(
-                communalHubViewId,
-                ConstraintSet.START,
-                ConstraintSet.PARENT_ID,
-                ConstraintSet.START,
-            )
-            connect(
-                communalHubViewId,
-                ConstraintSet.TOP,
-                ConstraintSet.PARENT_ID,
-                ConstraintSet.TOP,
-            )
-            connect(
-                communalHubViewId,
-                ConstraintSet.END,
-                ConstraintSet.PARENT_ID,
-                ConstraintSet.END,
-            )
-            connect(
-                communalHubViewId,
-                ConstraintSet.BOTTOM,
-                ConstraintSet.PARENT_ID,
-                ConstraintSet.BOTTOM,
-            )
-        }
-    }
+    override fun applyConstraints(constraintSet: ConstraintSet) {}
 
-    override fun removeViews(constraintLayout: ConstraintLayout) {
-        constraintLayout.removeView(communalHubViewId)
-    }
+    override fun removeViews(constraintLayout: ConstraintLayout) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 4d8e893..bed4283 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -16,16 +16,22 @@
 
 package com.android.systemui.communal.ui.viewmodel
 
+import android.os.PowerManager
+import android.os.SystemClock
+import android.view.MotionEvent
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.shared.model.CommunalSceneKey
 import com.android.systemui.media.controls.ui.MediaHost
+import com.android.systemui.shade.ShadeViewController
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.StateFlow
 
 /** The base view model for the communal hub. */
 abstract class BaseCommunalViewModel(
     private val communalInteractor: CommunalInteractor,
+    private val shadeViewController: ShadeViewController,
+    private val powerManager: PowerManager,
     val mediaHost: MediaHost,
 ) {
     val isKeyguardVisible: Flow<Boolean> = communalInteractor.isKeyguardVisible
@@ -36,6 +42,26 @@
         communalInteractor.onSceneChanged(scene)
     }
 
+    // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't block
+    //  touches anymore.
+    /** Called when a touch is received outside the edge swipe area when hub mode is closed. */
+    fun onOuterTouch(motionEvent: MotionEvent) {
+        // Forward the touch to the shade so that basic gestures like swipe up/down for
+        // shade/bouncer work.
+        shadeViewController.handleExternalTouch(motionEvent)
+    }
+
+    // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't block
+    //  touches anymore.
+    /** Called to refresh the screen timeout when a user touch is received. */
+    fun onUserActivity() {
+        powerManager.userActivity(
+            SystemClock.uptimeMillis(),
+            PowerManager.USER_ACTIVITY_EVENT_TOUCH,
+            0
+        )
+    }
+
     /** A list of all the communal content to be displayed in the communal hub. */
     abstract val communalContent: Flow<List<CommunalContentModel>>
 
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 111f8b4..b6843c5 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -16,11 +16,13 @@
 
 package com.android.systemui.communal.ui.viewmodel
 
+import android.os.PowerManager
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.media.controls.ui.MediaHost
 import com.android.systemui.media.dagger.MediaModule
+import com.android.systemui.shade.ShadeViewController
 import javax.inject.Inject
 import javax.inject.Named
 import kotlinx.coroutines.flow.Flow
@@ -31,8 +33,10 @@
 @Inject
 constructor(
     private val communalInteractor: CommunalInteractor,
+    shadeViewController: ShadeViewController,
+    powerManager: PowerManager,
     @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
-) : BaseCommunalViewModel(communalInteractor, mediaHost) {
+) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) {
 
     override val isEditMode = true
 
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 11bde6b..d7dcdb9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -16,12 +16,14 @@
 
 package com.android.systemui.communal.ui.viewmodel
 
+import android.os.PowerManager
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.CommunalTutorialInteractor
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.media.controls.ui.MediaHost
 import com.android.systemui.media.dagger.MediaModule
+import com.android.systemui.shade.ShadeViewController
 import javax.inject.Inject
 import javax.inject.Named
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -37,8 +39,10 @@
 constructor(
     private val communalInteractor: CommunalInteractor,
     tutorialInteractor: CommunalTutorialInteractor,
+    shadeViewController: ShadeViewController,
+    powerManager: PowerManager,
     @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
-) : BaseCommunalViewModel(communalInteractor, mediaHost) {
+) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) {
     @OptIn(ExperimentalCoroutinesApi::class)
     override val communalContent: Flow<List<CommunalContentModel>> =
         tutorialInteractor.isTutorialAvailable.flatMapLatest { isTutorialMode ->