diff options
7 files changed, 108 insertions, 76 deletions
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 2c4dc806f468..185a06c70f9e 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.Box 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.mutableStateOf 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.FixedSizeEdgeDetector 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 @@ val sceneTransitions = transitions { * 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 @@ fun CommunalContainer( 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 @@ fun CommunalContainer( 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 ce7db80db7da..ea3006f0b502 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.communal.ui.viewmodel.CommunalEditModeViewModel 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 @@ import org.mockito.MockitoAnnotations @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 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { 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 32f4d075a873..9bd083501780 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.communal.ui.viewmodel.CommunalViewModel 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 @@ import org.mockito.MockitoAnnotations @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 @@ class CommunalViewModelTest : SysuiTestCase() { 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 ad02f6280a64..4219d6d6f397 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 @@ package com.android.systemui.communal.ui.view.layout.sections 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 4d8e893cb747..bed42833a1d4 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 @@ abstract class BaseCommunalViewModel( 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 111f8b4ca48f..b6843c529180 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 @@ class CommunalEditModeViewModel @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 11bde6bd7af0..d7dcdb9ea4f0 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 @@ class CommunalViewModel 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 -> |