Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt +22 −1 Original line number Diff line number Diff line Loading @@ -18,9 +18,12 @@ package com.android.systemui.statusbar.notification.stack.ui.viewbinder import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.view.View import android.view.WindowInsets import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.scene.shared.flag.SceneContainerFlags import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController Loading @@ -30,6 +33,9 @@ import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificat import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch /** Binds the shared notification container to its view-model. */ Loading Loading @@ -65,6 +71,8 @@ object SharedNotificationContainerBinder { } } val burnInParams = MutableStateFlow(BurnInParameters()) /* * For animation sensitive coroutines, immediately run just like applicationScope does * instead of doing a post() to the main thread. This extra delay can cause visible jitter. Loading Loading @@ -122,7 +130,11 @@ object SharedNotificationContainerBinder { } } launch { viewModel.translationY.collect { controller.setTranslationY(it) } } launch { burnInParams .flatMapLatest { params -> viewModel.translationY(params) } .collect { y -> controller.setTranslationY(y) } } launch { viewModel.expansionAlpha.collect { controller.setMaxAlphaForExpansion(it) } Loading @@ -137,11 +149,20 @@ object SharedNotificationContainerBinder { controller.setOnHeightChangedRunnable(Runnable { viewModel.notificationStackChanged() }) view.setOnApplyWindowInsetsListener { v: View, insets: WindowInsets -> val insetTypes = WindowInsets.Type.systemBars() or WindowInsets.Type.displayCutout() burnInParams.update { current -> current.copy(topInset = insets.getInsetsIgnoringVisibility(insetTypes).top) } insets } return object : DisposableHandle { override fun dispose() { disposableHandle.dispose() disposableHandleMainImmediate.dispose() controller.setOnHeightChangedRunnable(null) view.setOnApplyWindowInsetsListener(null) } } } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt +11 −6 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState 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.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel Loading Loading @@ -65,10 +67,11 @@ constructor( keyguardTransitionInteractor: KeyguardTransitionInteractor, private val shadeInteractor: ShadeInteractor, communalInteractor: CommunalInteractor, occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel, private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel, lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel, glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel, lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel, private val aodBurnInViewModel: AodBurnInViewModel, ) { private val statesForConstrainedNotifications = setOf( Loading Loading @@ -313,20 +316,22 @@ constructor( * Under certain scenarios, such as swiping up on the lockscreen, the container will need to be * translated as the keyguard fades out. */ val translationY: Flow<Float> = combine( fun translationY(params: BurnInParameters): Flow<Float> { return combine( aodBurnInViewModel.translationY(params).onStart { emit(0f) }, isOnLockscreenWithoutShade, merge( keyguardInteractor.keyguardTranslationY, occludedToLockscreenTransitionViewModel.lockscreenTranslationY, ) ) { isOnLockscreenWithoutShade, translationY -> ) { burnInY, isOnLockscreenWithoutShade, translationY -> if (isOnLockscreenWithoutShade) { translationY burnInY + translationY } else { 0f } } } /** * When on keyguard, there is limited space to display notifications so calculate how many could Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt +29 −3 Original line number Diff line number Diff line Loading @@ -38,6 +38,9 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel import com.android.systemui.kosmos.testScope import com.android.systemui.res.R Loading @@ -45,6 +48,7 @@ import com.android.systemui.shade.data.repository.shadeRepository 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.any import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi Loading @@ -55,15 +59,22 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock @SmallTest @RunWith(AndroidJUnit4::class) class SharedNotificationContainerViewModelTest : SysuiTestCase() { val aodBurnInViewModel = mock(AodBurnInViewModel::class.java) lateinit var translationYFlow: MutableStateFlow<Float> val kosmos = testKosmos().apply { fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) } } init { kosmos.aodBurnInViewModel = aodBurnInViewModel } val testScope = kosmos.testScope val configurationRepository = kosmos.fakeConfigurationRepository val keyguardRepository = kosmos.fakeKeyguardRepository Loading @@ -75,11 +86,14 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { val sharedNotificationContainerInteractor = kosmos.sharedNotificationContainerInteractor val largeScreenHeaderHelper = kosmos.mockLargeScreenHeaderHelper val underTest = kosmos.sharedNotificationContainerViewModel lateinit var underTest: SharedNotificationContainerViewModel @Before fun setUp() { overrideResource(R.bool.config_use_split_notification_shade, false) translationYFlow = MutableStateFlow(0f) whenever(aodBurnInViewModel.translationY(any())).thenReturn(translationYFlow) underTest = kosmos.sharedNotificationContainerViewModel } @Test Loading Loading @@ -578,10 +592,22 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { assertThat(maxNotifications).isEqualTo(-1) } @Test fun translationYUpdatesOnKeyguardForBurnIn() = testScope.runTest { val translationY by collectLastValue(underTest.translationY(BurnInParameters())) showLockscreen() assertThat(translationY).isEqualTo(0) translationYFlow.value = 150f assertThat(translationY).isEqualTo(150f) } @Test fun translationYUpdatesOnKeyguard() = testScope.runTest { val translationY by collectLastValue(underTest.translationY) val translationY by collectLastValue(underTest.translationY(BurnInParameters())) configurationRepository.setDimensionPixelSize( R.dimen.keyguard_translate_distance_on_swipe_up, Loading @@ -601,7 +627,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { @Test fun translationYDoesNotUpdateWhenShadeIsExpanded() = testScope.runTest { val translationY by collectLastValue(underTest.translationY) val translationY by collectLastValue(underTest.translationY(BurnInParameters())) configurationRepository.setDimensionPixelSize( R.dimen.keyguard_translate_distance_on_swipe_up, Loading packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt +1 −1 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodBurnInViewModel by Fixture { var Kosmos.aodBurnInViewModel by Fixture { AodBurnInViewModel( burnInInteractor = burnInInteractor, configurationInteractor = configurationInteractor, Loading packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt +3 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ 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.aodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.lockscreenToOccludedTransitionViewModel Loading @@ -40,6 +41,7 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture { occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel, lockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel, glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel, lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel, aodBurnInViewModel = aodBurnInViewModel, ) } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt +22 −1 Original line number Diff line number Diff line Loading @@ -18,9 +18,12 @@ package com.android.systemui.statusbar.notification.stack.ui.viewbinder import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.view.View import android.view.WindowInsets import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.scene.shared.flag.SceneContainerFlags import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController Loading @@ -30,6 +33,9 @@ import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificat import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch /** Binds the shared notification container to its view-model. */ Loading Loading @@ -65,6 +71,8 @@ object SharedNotificationContainerBinder { } } val burnInParams = MutableStateFlow(BurnInParameters()) /* * For animation sensitive coroutines, immediately run just like applicationScope does * instead of doing a post() to the main thread. This extra delay can cause visible jitter. Loading Loading @@ -122,7 +130,11 @@ object SharedNotificationContainerBinder { } } launch { viewModel.translationY.collect { controller.setTranslationY(it) } } launch { burnInParams .flatMapLatest { params -> viewModel.translationY(params) } .collect { y -> controller.setTranslationY(y) } } launch { viewModel.expansionAlpha.collect { controller.setMaxAlphaForExpansion(it) } Loading @@ -137,11 +149,20 @@ object SharedNotificationContainerBinder { controller.setOnHeightChangedRunnable(Runnable { viewModel.notificationStackChanged() }) view.setOnApplyWindowInsetsListener { v: View, insets: WindowInsets -> val insetTypes = WindowInsets.Type.systemBars() or WindowInsets.Type.displayCutout() burnInParams.update { current -> current.copy(topInset = insets.getInsetsIgnoringVisibility(insetTypes).top) } insets } return object : DisposableHandle { override fun dispose() { disposableHandle.dispose() disposableHandleMainImmediate.dispose() controller.setOnHeightChangedRunnable(null) view.setOnApplyWindowInsetsListener(null) } } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt +11 −6 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState 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.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel Loading Loading @@ -65,10 +67,11 @@ constructor( keyguardTransitionInteractor: KeyguardTransitionInteractor, private val shadeInteractor: ShadeInteractor, communalInteractor: CommunalInteractor, occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel, private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel, lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel, glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel, lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel, private val aodBurnInViewModel: AodBurnInViewModel, ) { private val statesForConstrainedNotifications = setOf( Loading Loading @@ -313,20 +316,22 @@ constructor( * Under certain scenarios, such as swiping up on the lockscreen, the container will need to be * translated as the keyguard fades out. */ val translationY: Flow<Float> = combine( fun translationY(params: BurnInParameters): Flow<Float> { return combine( aodBurnInViewModel.translationY(params).onStart { emit(0f) }, isOnLockscreenWithoutShade, merge( keyguardInteractor.keyguardTranslationY, occludedToLockscreenTransitionViewModel.lockscreenTranslationY, ) ) { isOnLockscreenWithoutShade, translationY -> ) { burnInY, isOnLockscreenWithoutShade, translationY -> if (isOnLockscreenWithoutShade) { translationY burnInY + translationY } else { 0f } } } /** * When on keyguard, there is limited space to display notifications so calculate how many could Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt +29 −3 Original line number Diff line number Diff line Loading @@ -38,6 +38,9 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel import com.android.systemui.kosmos.testScope import com.android.systemui.res.R Loading @@ -45,6 +48,7 @@ import com.android.systemui.shade.data.repository.shadeRepository 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.any import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi Loading @@ -55,15 +59,22 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock @SmallTest @RunWith(AndroidJUnit4::class) class SharedNotificationContainerViewModelTest : SysuiTestCase() { val aodBurnInViewModel = mock(AodBurnInViewModel::class.java) lateinit var translationYFlow: MutableStateFlow<Float> val kosmos = testKosmos().apply { fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) } } init { kosmos.aodBurnInViewModel = aodBurnInViewModel } val testScope = kosmos.testScope val configurationRepository = kosmos.fakeConfigurationRepository val keyguardRepository = kosmos.fakeKeyguardRepository Loading @@ -75,11 +86,14 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { val sharedNotificationContainerInteractor = kosmos.sharedNotificationContainerInteractor val largeScreenHeaderHelper = kosmos.mockLargeScreenHeaderHelper val underTest = kosmos.sharedNotificationContainerViewModel lateinit var underTest: SharedNotificationContainerViewModel @Before fun setUp() { overrideResource(R.bool.config_use_split_notification_shade, false) translationYFlow = MutableStateFlow(0f) whenever(aodBurnInViewModel.translationY(any())).thenReturn(translationYFlow) underTest = kosmos.sharedNotificationContainerViewModel } @Test Loading Loading @@ -578,10 +592,22 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { assertThat(maxNotifications).isEqualTo(-1) } @Test fun translationYUpdatesOnKeyguardForBurnIn() = testScope.runTest { val translationY by collectLastValue(underTest.translationY(BurnInParameters())) showLockscreen() assertThat(translationY).isEqualTo(0) translationYFlow.value = 150f assertThat(translationY).isEqualTo(150f) } @Test fun translationYUpdatesOnKeyguard() = testScope.runTest { val translationY by collectLastValue(underTest.translationY) val translationY by collectLastValue(underTest.translationY(BurnInParameters())) configurationRepository.setDimensionPixelSize( R.dimen.keyguard_translate_distance_on_swipe_up, Loading @@ -601,7 +627,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { @Test fun translationYDoesNotUpdateWhenShadeIsExpanded() = testScope.runTest { val translationY by collectLastValue(underTest.translationY) val translationY by collectLastValue(underTest.translationY(BurnInParameters())) configurationRepository.setDimensionPixelSize( R.dimen.keyguard_translate_distance_on_swipe_up, Loading
packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt +1 −1 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodBurnInViewModel by Fixture { var Kosmos.aodBurnInViewModel by Fixture { AodBurnInViewModel( burnInInteractor = burnInInteractor, configurationInteractor = configurationInteractor, Loading
packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt +3 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ 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.aodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.lockscreenToOccludedTransitionViewModel Loading @@ -40,6 +41,7 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture { occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel, lockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel, glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel, lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel, aodBurnInViewModel = aodBurnInViewModel, ) }