Merge "Transition away notifications when entering glanceable hub" into main
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index cceb767..6cc680b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -25,10 +25,14 @@
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION
import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.repository.communalRepository
+import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -43,6 +47,7 @@
import com.android.systemui.util.ui.value
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -55,7 +60,9 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ private val keyguardInteractor = kosmos.keyguardInteractor
private val keyguardRepository = kosmos.fakeKeyguardRepository
+ private val communalRepository = kosmos.communalRepository
private val screenOffAnimationController = kosmos.screenOffAnimationController
private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository
private val notificationsKeyguardInteractor = kosmos.notificationsKeyguardInteractor
@@ -220,7 +227,25 @@
}
@Test
- fun alpha_glanceableHubOpen_isZero() =
+ fun alpha_idleOnHub_isZero() =
+ testScope.runTest {
+ val alpha by collectLastValue(underTest.alpha)
+
+ // Hub transition state is idle with hub open.
+ communalRepository.setTransitionState(
+ flowOf(ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal))
+ )
+ runCurrent()
+
+ // Set keyguard alpha to 1.0f.
+ keyguardInteractor.setAlpha(1.0f)
+
+ // Alpha property remains 0 regardless.
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ fun alpha_transitionToHub_isZero() =
testScope.runTest {
val alpha by collectLastValue(underTest.alpha)
@@ -234,7 +259,7 @@
}
@Test
- fun alpha_glanceableHubClosed_isOne() =
+ fun alpha_transitionFromHubToLockscreen_isOne() =
testScope.runTest {
val alpha by collectLastValue(underTest.alpha)
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c630a7f..e8201ecb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1728,6 +1728,10 @@
<dimen name="communal_grid_height">630dp</dimen>
<!-- Number of columns for each communal card -->
<integer name="communal_grid_columns_per_card">6</integer>
+ <!-- Width of area on right edge of screen in which swipes will open the communal hub -->
+ <dimen name="communal_right_edge_swipe_region_width">16dp</dimen>
+ <!-- Height of area at top of communal hub where swipes should open the notification shade -->
+ <dimen name="communal_top_edge_swipe_region_height">32dp</dimen>
<dimen name="drag_and_drop_icon_size">70dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index 3292ea8..4df5d50 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -95,6 +95,7 @@
companion object {
const val TAG = "FromGlanceableHubTransitionInteractor"
- val DEFAULT_DURATION = 500.milliseconds
+ val DEFAULT_DURATION = 400.milliseconds
+ val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt
index bc51821..6aa2eca 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.FromGlanceableHubTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import javax.inject.Inject
@@ -37,7 +37,7 @@
) {
private val transitionAnimation =
animationFlow.setup(
- duration = FromLockscreenTransitionInteractor.TO_GLANCEABLE_HUB_DURATION,
+ duration = FromGlanceableHubTransitionInteractor.TO_LOCKSCREEN_DURATION,
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.LOCKSCREEN,
)
@@ -45,10 +45,20 @@
// TODO(b/315205222): implement full animation spec instead of just a simple fade.
val keyguardAlpha: Flow<Float> =
transitionAnimation.sharedFlow(
- duration = FromLockscreenTransitionInteractor.TO_GLANCEABLE_HUB_DURATION,
+ duration = FromGlanceableHubTransitionInteractor.TO_LOCKSCREEN_DURATION,
onStep = { it },
onFinish = { 1f },
onCancel = { 0f },
name = "GLANCEABLE_HUB->LOCKSCREEN: keyguardAlpha",
)
+
+ // TODO(b/315205216): implement full animation spec instead of just a simple fade.
+ val notificationAlpha: Flow<Float> =
+ transitionAnimation.sharedFlow(
+ duration = FromGlanceableHubTransitionInteractor.TO_LOCKSCREEN_DURATION,
+ onStep = { it },
+ onFinish = { 1f },
+ onCancel = { 0f },
+ name = "GLANCEABLE_HUB->LOCKSCREEN: notificationAlpha",
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index ea66702..709e184 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -21,6 +21,7 @@
import android.view.View.VISIBLE
import com.android.systemui.Flags.newAodTransition
import com.android.systemui.common.shared.model.NotificationContainerBounds
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -56,6 +57,7 @@
private val deviceEntryInteractor: DeviceEntryInteractor,
private val dozeParameters: DozeParameters,
private val keyguardInteractor: KeyguardInteractor,
+ communalInteractor: CommunalInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
@@ -88,11 +90,23 @@
/** An observable for the alpha level for the entire keyguard root view. */
val alpha: Flow<Float> =
- merge(
- aodAlphaViewModel.alpha,
- lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha,
- glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
- )
+ combine(
+ communalInteractor.isIdleOnCommunal,
+ merge(
+ aodAlphaViewModel.alpha,
+ lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha,
+ glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
+ )
+ ) { isIdleOnCommunal, alpha ->
+ if (isIdleOnCommunal) {
+ // Keyguard should not show while the communal hub is fully visible. This check
+ // is added since at the moment, closing the notification shade will cause the
+ // keyguard alpha to be set back to 1.
+ 0f
+ } else {
+ alpha
+ }
+ }
.distinctUntilChanged()
/** Specific alpha value for elements visible during [KeyguardState.LOCKSCREEN] */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt
index 3ea83ae..3afa49e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt
@@ -51,4 +51,14 @@
onCancel = { 1f },
name = "LOCKSCREEN->GLANCEABLE_HUB: keyguardAlpha",
)
+
+ // TODO(b/315205216): implement full animation spec instead of just a simple fade.
+ val notificationAlpha: Flow<Float> =
+ transitionAnimation.sharedFlow(
+ duration = FromLockscreenTransitionInteractor.TO_GLANCEABLE_HUB_DURATION,
+ onStep = { 1f - it },
+ onFinish = { 0f },
+ onCancel = { 1f },
+ name = "LOCKSCREEN->GLANCEABLE_HUB: notificationAlpha",
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 782d651..3362ebc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -55,7 +55,15 @@
* The width of the area in which a right edge swipe can open the hub, in pixels. Read from
* resources when [initView] is called.
*/
- private var edgeSwipeRegionWidth: Int = 0
+ // TODO(b/320786721): support RTL layouts
+ private var rightEdgeSwipeRegionWidth: Int = 0
+
+ /**
+ * The height of the area in which a top edge swipe while the hub is open will not intercept
+ * touches, in pixels. This allows the top edge swipe to instead open the notification shade.
+ * Read from resources when [initView] is called.
+ */
+ private var topEdgeSwipeRegionWidth: Int = 0
/**
* True if we are currently tracking a gesture for opening the hub that started in the edge
@@ -63,6 +71,9 @@
*/
private var isTrackingOpenGesture = false
+ /** True if we are currently tracking a touch on the hub while it's open. */
+ private var isTrackingHubTouch = false
+
/**
* True if the hub UI is fully open, meaning it should receive touch input.
*
@@ -113,8 +124,14 @@
communalContainerView = containerView
- edgeSwipeRegionWidth =
- communalContainerView.resources.getDimensionPixelSize(R.dimen.communal_grid_gutter_size)
+ rightEdgeSwipeRegionWidth =
+ communalContainerView.resources.getDimensionPixelSize(
+ R.dimen.communal_right_edge_swipe_region_width
+ )
+ topEdgeSwipeRegionWidth =
+ communalContainerView.resources.getDimensionPixelSize(
+ R.dimen.communal_top_edge_swipe_region_height
+ )
collectFlow(
communalContainerView,
@@ -157,17 +174,38 @@
// fully showing state
val hubOccluded = anyBouncerShowing || shadeShowing
- // If the hub is fully visible, send all touch events to it.
- val communalVisible = hubShowing && !hubOccluded
- if (communalVisible) {
+ // If the hub is fully visible, send all touch events to it, other than top and bottom edge
+ // swipes.
+ if (hubShowing && isDown) {
+ val y = ev.rawY
+ val topSwipe: Boolean = y <= topEdgeSwipeRegionWidth
+
+ // TODO(b/315207481): allow bottom edge swipes to open the bouncer
+ if (topSwipe) {
+ // Don't intercept touches at the top edge so that swipes can open the notification
+ // shade.
+ return false
+ }
+
+ if (!hubOccluded) {
+ isTrackingHubTouch = true
+ dispatchTouchEvent(ev)
+ // Return true regardless of dispatch result as some touches at the start of a
+ // gesture may return false from dispatchTouchEvent.
+ return true
+ }
+ } else if (isTrackingHubTouch) {
+ if (isUp || isCancel) {
+ isTrackingHubTouch = false
+ }
dispatchTouchEvent(ev)
// Return true regardless of dispatch result as some touches at the start of a gesture
// may return false from dispatchTouchEvent.
return true
}
- if (edgeSwipeRegionWidth == 0) {
- // If the edge region width has not been read yet or whatever reason, don't bother
+ 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
}
@@ -175,7 +213,7 @@
if (!isTrackingOpenGesture && isDown) {
val x = ev.rawX
val inOpeningSwipeRegion: Boolean =
- x >= communalContainerView.width - edgeSwipeRegionWidth
+ x >= communalContainerView.width - rightEdgeSwipeRegionWidth
if (inOpeningSwipeRegion && !hubOccluded) {
isTrackingOpenGesture = true
dispatchTouchEvent(ev)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 9a8cc0a..1143481 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -355,6 +355,12 @@
private float mMaxAlphaForExpansion = 1.0f;
private float mMaxAlphaForUnhide = 1.0f;
+ /**
+ * Maximum alpha when to and from or sitting idle on the glanceable hub. Will be 1.0f when the
+ * hub is not visible or transitioning.
+ */
+ private float mMaxAlphaForGlanceableHub = 1.0f;
+
private final NotificationListViewBinder mViewBinder;
private void updateResources() {
@@ -1285,9 +1291,19 @@
updateAlpha();
}
+ /**
+ * Sets the max alpha value for notifications when idle on the glanceable hub or when
+ * transitioning to/from the glanceable hub.
+ */
+ public void setMaxAlphaForGlanceableHub(float alpha) {
+ mMaxAlphaForGlanceableHub = alpha;
+ updateAlpha();
+ }
+
private void updateAlpha() {
if (mView != null) {
- mView.setAlpha(Math.min(mMaxAlphaForExpansion, mMaxAlphaForUnhide));
+ mView.setAlpha(Math.min(mMaxAlphaForExpansion,
+ Math.min(mMaxAlphaForUnhide, mMaxAlphaForGlanceableHub)));
}
}
@@ -1779,6 +1795,7 @@
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("mMaxAlphaForExpansion=" + mMaxAlphaForExpansion);
pw.println("mMaxAlphaForUnhide=" + mMaxAlphaForUnhide);
+ pw.println("mMaxAlphaForGlanceableHub=" + mMaxAlphaForGlanceableHub);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index 12927b8..f842e30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -18,7 +18,6 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
-import android.animation.ValueAnimator
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.dagger.qualifiers.Main
@@ -125,7 +124,14 @@
launch { viewModel.translationY.collect { controller.setTranslationY(it) } }
- launch { viewModel.alpha.collect { controller.setMaxAlphaForExpansion(it) } }
+ launch {
+ viewModel.expansionAlpha.collect { controller.setMaxAlphaForExpansion(it) }
+ }
+ launch {
+ viewModel.glanceableHubAlpha.collect {
+ controller.setMaxAlphaForGlanceableHub(it)
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index a48fb45..99cd89b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -20,6 +20,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import com.android.systemui.common.shared.model.NotificationContainerBounds
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -27,6 +28,8 @@
import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
+import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -61,8 +64,11 @@
private val keyguardInteractor: KeyguardInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val shadeInteractor: ShadeInteractor,
+ communalInteractor: CommunalInteractor,
occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel,
+ glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel,
+ lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel
) {
private val statesForConstrainedNotifications =
setOf(
@@ -87,6 +93,20 @@
.distinctUntilChanged()
.onStart { emit(false) }
+ private val lockscreenToGlanceableHubRunning =
+ keyguardTransitionInteractor
+ .transition(KeyguardState.LOCKSCREEN, KeyguardState.GLANCEABLE_HUB)
+ .map { it.transitionState == STARTED || it.transitionState == RUNNING }
+ .distinctUntilChanged()
+ .onStart { emit(false) }
+
+ private val glanceableHubToLockscreenRunning =
+ keyguardTransitionInteractor
+ .transition(KeyguardState.GLANCEABLE_HUB, KeyguardState.LOCKSCREEN)
+ .map { it.transitionState == STARTED || it.transitionState == RUNNING }
+ .distinctUntilChanged()
+ .onStart { emit(false) }
+
val shadeCollapseFadeInComplete = MutableStateFlow(false)
val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
@@ -144,6 +164,24 @@
initialValue = false,
)
+ /** Are we purely on the glanceable hub without the shade/qs? */
+ internal val isOnGlanceableHubWithoutShade: Flow<Boolean> =
+ combine(
+ communalInteractor.isIdleOnCommunal,
+ // Shade with notifications
+ shadeInteractor.shadeExpansion.map { it > 0f },
+ // Shade without notifications, quick settings only (pull down from very top on
+ // lockscreen)
+ shadeInteractor.qsExpansion.map { it > 0f },
+ ) { isIdleOnCommunal, isShadeVisible, qsExpansion ->
+ isIdleOnCommunal && !(isShadeVisible || qsExpansion)
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
+
/** Fade in only for use after the shade collapses */
val shadeCollpaseFadeIn: Flow<Boolean> =
flow {
@@ -201,7 +239,7 @@
initialValue = NotificationContainerBounds(),
)
- val alpha: Flow<Float> =
+ val expansionAlpha: Flow<Float> =
// Due to issues with the legacy shade, some shade expansion events are sent incorrectly,
// such as when the shade resets. This can happen while the LOCKSCREEN<->OCCLUDED transition
// is running. Therefore use a series of flatmaps to prevent unwanted interruptions while
@@ -235,6 +273,43 @@
}
/**
+ * Returns a flow of the expected alpha while running a LOCKSCREEN<->GLANCEABLE_HUB transition
+ * or idle on the glanceable hub.
+ *
+ * Must return 1.0f when not controlling the alpha since notifications does a min of all the
+ * alpha sources.
+ */
+ val glanceableHubAlpha: Flow<Float> =
+ isOnGlanceableHubWithoutShade.flatMapLatest { isOnGlanceableHubWithoutShade ->
+ combineTransform(
+ lockscreenToGlanceableHubRunning,
+ glanceableHubToLockscreenRunning,
+ merge(
+ lockscreenToGlanceableHubTransitionViewModel.notificationAlpha,
+ glanceableHubToLockscreenTransitionViewModel.notificationAlpha,
+ )
+ .onStart {
+ // Transition flows don't emit a value on start, kick things off so the
+ // combine starts.
+ emit(1f)
+ }
+ ) { lockscreenToGlanceableHubRunning, glanceableHubToLockscreenRunning, alpha ->
+ if (isOnGlanceableHubWithoutShade) {
+ // Notifications should not be visible on the glanceable hub.
+ // TODO(b/321075734): implement a way to actually set the notifications to gone
+ // while on the hub instead of just adjusting alpha
+ emit(0f)
+ } else if (lockscreenToGlanceableHubRunning || glanceableHubToLockscreenRunning) {
+ emit(alpha)
+ } else {
+ // Not on the hub and no transitions running, return full visibility so we don't
+ // block the notifications from showing.
+ emit(1f)
+ }
+ }
+ }
+
+ /**
* Under certain scenarios, such as swiping up on the lockscreen, the container will need to be
* translated as the keyguard fades out.
*/
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 81ff817..c1f5d85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -94,7 +94,8 @@
.thenReturn(bouncerShowingFlow)
whenever(shadeInteractor.isAnyFullyExpanded).thenReturn(shadeShowingFlow)
- overrideResource(R.dimen.communal_grid_gutter_size, SWIPE_REGION_WIDTH)
+ overrideResource(R.dimen.communal_right_edge_swipe_region_width, RIGHT_SWIPE_REGION_WIDTH)
+ overrideResource(R.dimen.communal_top_edge_swipe_region_height, TOP_SWIPE_REGION_WIDTH)
}
@Test
@@ -135,7 +136,7 @@
initAndAttachContainerView()
// Touch events are intercepted.
- assertThat(underTest.onTouchEvent(DOWN_IN_SWIPE_REGION_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(DOWN_IN_RIGHT_SWIPE_REGION_EVENT)).isTrue()
}
@Test
@@ -147,7 +148,7 @@
// Initial touch down is intercepted, and so are touches outside of the region, until an up
// event is received.
- assertThat(underTest.onTouchEvent(DOWN_IN_SWIPE_REGION_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(DOWN_IN_RIGHT_SWIPE_REGION_EVENT)).isTrue()
assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse()
@@ -168,6 +169,17 @@
}
@Test
+ fun onTouchEvent_topSwipeWhenHubOpen_returnsFalse() {
+ // Communal is open.
+ communalRepository.setDesiredScene(CommunalSceneKey.Communal)
+
+ initAndAttachContainerView()
+
+ // Touch event in the top swipe reqgion is not intercepted.
+ assertThat(underTest.onTouchEvent(DOWN_IN_TOP_SWIPE_REGION_EVENT)).isFalse()
+ }
+
+ @Test
fun onTouchEvent_communalAndBouncerShowing_doesNotIntercept() {
// Communal is open.
communalRepository.setDesiredScene(CommunalSceneKey.Communal)
@@ -213,11 +225,29 @@
companion object {
private const val CONTAINER_WIDTH = 100
private const val CONTAINER_HEIGHT = 100
- private const val SWIPE_REGION_WIDTH = 20
+ private const val RIGHT_SWIPE_REGION_WIDTH = 20
+ private const val TOP_SWIPE_REGION_WIDTH = 20
- private val DOWN_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
- private val DOWN_IN_SWIPE_REGION_EVENT =
+ private val DOWN_EVENT =
+ MotionEvent.obtain(
+ 0L,
+ 0L,
+ MotionEvent.ACTION_DOWN,
+ CONTAINER_WIDTH.toFloat(),
+ CONTAINER_HEIGHT.toFloat(),
+ 0
+ )
+ private val DOWN_IN_RIGHT_SWIPE_REGION_EVENT =
MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, CONTAINER_WIDTH.toFloat(), 0f, 0)
+ private val DOWN_IN_TOP_SWIPE_REGION_EVENT =
+ MotionEvent.obtain(
+ 0L,
+ 0L,
+ MotionEvent.ACTION_DOWN,
+ 0f,
+ TOP_SWIPE_REGION_WIDTH.toFloat(),
+ 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)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index a824bc4..06298b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -25,6 +25,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -33,20 +36,19 @@
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
-import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.largeScreenHeaderHelper
import com.android.systemui.shade.mockLargeScreenHeaderHelper
import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -68,6 +70,7 @@
val keyguardInteractor = kosmos.keyguardInteractor
val keyguardRootViewModel = kosmos.keyguardRootViewModel
val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ val communalInteractor = kosmos.communalInteractor
val shadeRepository = kosmos.shadeRepository
val sharedNotificationContainerInteractor = kosmos.sharedNotificationContainerInteractor
val largeScreenHeaderHelper = kosmos.mockLargeScreenHeaderHelper
@@ -214,6 +217,61 @@
}
@Test
+ fun glanceableHubAlpha() =
+ testScope.runTest {
+ val alpha by collectLastValue(underTest.glanceableHubAlpha)
+
+ // Start on lockscreen
+ showLockscreen()
+ assertThat(alpha).isEqualTo(1f)
+
+ // Start transitioning to glanceable hub
+ val progress = 0.6f
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GLANCEABLE_HUB,
+ value = 0f,
+ )
+ )
+ runCurrent()
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.RUNNING,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GLANCEABLE_HUB,
+ value = progress,
+ )
+ )
+ runCurrent()
+ // Expected alpha is inverse of progress as notifications are fading away
+ assertThat(alpha).isEqualTo(1 - progress)
+
+ // Finish transition to glanceable hub
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.FINISHED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GLANCEABLE_HUB,
+ value = 1f,
+ )
+ )
+ val idleTransitionState =
+ MutableStateFlow<ObservableCommunalTransitionState>(
+ ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+ )
+ communalInteractor.setTransitionState(idleTransitionState)
+ runCurrent()
+ assertThat(alpha).isEqualTo(0f)
+
+ // While state is GLANCEABLE_HUB, verify alpha is restored to full if glanceable hub is
+ // not fully visible.
+ shadeRepository.setLockscreenShadeExpansion(0.1f)
+ assertThat(alpha).isEqualTo(1f)
+ }
+
+ @Test
fun validateMarginTop() =
testScope.runTest {
overrideResource(R.bool.config_use_large_screen_shade_header, false)
@@ -302,6 +360,43 @@
}
@Test
+ fun isOnGlanceableHubWithoutShade() =
+ testScope.runTest {
+ val isOnGlanceableHubWithoutShade by
+ collectLastValue(underTest.isOnGlanceableHubWithoutShade)
+
+ // Start on lockscreen
+ showLockscreen()
+ assertThat(isOnGlanceableHubWithoutShade).isFalse()
+
+ // Move to glanceable hub
+ val idleTransitionState =
+ MutableStateFlow<ObservableCommunalTransitionState>(
+ ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+ )
+ communalInteractor.setTransitionState(idleTransitionState)
+ runCurrent()
+ assertThat(isOnGlanceableHubWithoutShade).isTrue()
+
+ // While state is GLANCEABLE_HUB, validate variations of both shade and qs expansion
+ shadeRepository.setLockscreenShadeExpansion(0.1f)
+ shadeRepository.setQsExpansion(0f)
+ assertThat(isOnGlanceableHubWithoutShade).isFalse()
+
+ shadeRepository.setLockscreenShadeExpansion(0.1f)
+ shadeRepository.setQsExpansion(0.1f)
+ assertThat(isOnGlanceableHubWithoutShade).isFalse()
+
+ shadeRepository.setLockscreenShadeExpansion(0f)
+ shadeRepository.setQsExpansion(0.1f)
+ assertThat(isOnGlanceableHubWithoutShade).isFalse()
+
+ shadeRepository.setLockscreenShadeExpansion(0f)
+ shadeRepository.setQsExpansion(0f)
+ assertThat(isOnGlanceableHubWithoutShade).isTrue()
+ }
+
+ @Test
fun boundsOnLockscreenNotInSplitShade() =
testScope.runTest {
val bounds by collectLastValue(underTest.bounds)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index 5564767..d376f12 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.ui.viewmodel
+import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
@@ -33,6 +34,7 @@
deviceEntryInteractor = deviceEntryInteractor,
dozeParameters = dozeParameters,
keyguardInteractor = keyguardInteractor,
+ communalInteractor = communalInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
notificationsKeyguardInteractor = notificationsKeyguardInteractor,
aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 5ef9a8e..db40509 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -16,8 +16,11 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.lockscreenToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.occludedToLockscreenTransitionViewModel
import com.android.systemui.kosmos.Kosmos
@@ -33,7 +36,10 @@
keyguardInteractor = keyguardInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
shadeInteractor = shadeInteractor,
+ communalInteractor = communalInteractor,
occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
lockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel,
+ glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
+ lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel
)
}