Extract isShowingOnLockscreen from NotificationListViewModel to NotificationStackInteractor
Bug: 309146176
Flag: None
Test: atest SystemUITests
Change-Id: I511f21fe44a11eba45649951aeeabc87e8185f93
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractor.kt
new file mode 100644
index 0000000..9cd46f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractor.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+
+/** Interactor exposing states related to the stack's context */
+@SysUISingleton
+class NotificationStackInteractor
+@Inject
+constructor(
+ keyguardInteractor: KeyguardInteractor,
+ powerInteractor: PowerInteractor,
+) {
+ val isShowingOnLockscreen: Flow<Boolean> =
+ combine(
+ // Non-notification UI elements of the notification list should not be visible
+ // on the lockscreen (incl. AOD and bouncer), except if the shade is opened on
+ // top. See b/219680200 for the footer and b/228790482, b/267060171 for the
+ // empty shade.
+ // TODO(b/323187006): There's a plan to eventually get rid of StatusBarState
+ // entirely, so this will have to be replaced at some point.
+ keyguardInteractor.statusBarState.map { it == StatusBarState.KEYGUARD },
+ // The StatusBarState is unfortunately not updated quickly enough when the power
+ // button is pressed, so this is necessary in addition to the KEYGUARD check to
+ // cover the transition to AOD while going to sleep (b/190227875).
+ powerInteractor.isAsleep,
+ ) { (isOnKeyguard, isAsleep) ->
+ isOnKeyguard || isAsleep
+ }
+ .distinctUntilChanged()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index 7b50256..c85a18a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.shared.model.StatusBarState
-import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.domain.interactor.RemoteInputInteractor
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
@@ -26,6 +23,7 @@
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackInteractor
import com.android.systemui.statusbar.policy.domain.interactor.UserSetupInteractor
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
import com.android.systemui.util.kotlin.combine
@@ -51,8 +49,7 @@
val footer: Optional<FooterViewModel>,
val logger: Optional<NotificationLoggerViewModel>,
activeNotificationsInteractor: ActiveNotificationsInteractor,
- keyguardInteractor: KeyguardInteractor,
- powerInteractor: PowerInteractor,
+ notificationStackInteractor: NotificationStackInteractor,
remoteInputInteractor: RemoteInputInteractor,
seenNotificationsInteractor: SeenNotificationsInteractor,
shadeInteractor: ShadeInteractor,
@@ -71,7 +68,7 @@
} else {
combine(
activeNotificationsInteractor.areAnyNotificationsPresent,
- isShowingOnLockscreen,
+ notificationStackInteractor.isShowingOnLockscreen,
) { hasNotifications, isShowingOnLockscreen ->
hasNotifications || !isShowingOnLockscreen
}
@@ -86,7 +83,7 @@
combine(
activeNotificationsInteractor.areAnyNotificationsPresent,
shadeInteractor.isQsFullscreen,
- isShowingOnLockscreen,
+ notificationStackInteractor.isShowingOnLockscreen,
) { hasNotifications, isQsFullScreen, isShowingOnLockscreen ->
when {
hasNotifications -> false
@@ -109,7 +106,7 @@
combine(
activeNotificationsInteractor.areAnyNotificationsPresent,
userSetupInteractor.isUserSetUp,
- isShowingOnLockscreen,
+ notificationStackInteractor.isShowingOnLockscreen,
shadeInteractor.qsExpansion,
shadeInteractor.isQsFullscreen,
remoteInputInteractor.isRemoteInputActive,
@@ -177,29 +174,6 @@
SHOW_WITH_ANIMATION(visible = true, canAnimate = true)
}
- private val isShowingOnLockscreen: Flow<Boolean> by lazy {
- if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
- flowOf(false)
- } else {
- combine(
- // Non-notification UI elements of the notification list should not be visible
- // on the lockscreen (incl. AOD and bouncer), except if the shade is opened on
- // top. See b/219680200 for the footer and b/228790482, b/267060171 for the
- // empty shade.
- // TODO(b/323187006): There's a plan to eventually get rid of StatusBarState
- // entirely, so this will have to be replaced at some point.
- keyguardInteractor.statusBarState.map { it == StatusBarState.KEYGUARD },
- // The StatusBarState is unfortunately not updated quickly enough when the power
- // button is pressed, so this is necessary in addition to the KEYGUARD check to
- // cover the transition to AOD while going to sleep (b/190227875).
- powerInteractor.isAsleep,
- ) { (isOnKeyguard, isAsleep) ->
- isOnKeyguard || isAsleep
- }
- .distinctUntilChanged()
- }
- }
-
// TODO(b/308591475): This should be tracked separately by the empty shade.
val areNotificationsHiddenInShade: Flow<Boolean> by lazy {
if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt
new file mode 100644
index 0000000..1c6bda9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.stack.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.data.repository.fakePowerRepository
+import com.android.systemui.power.shared.model.WakefulnessState
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NotificationStackInteractorTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ val underTest
+ get() = kosmos.notificationStackInteractor
+
+ @Test
+ fun testIsShowingOnLockscreen_falseWhenViewingShade() =
+ kosmos.testScope.runTest {
+ val onLockscreen by collectLastValue(underTest.isShowingOnLockscreen)
+
+ // WHEN shade is open
+ kosmos.fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
+ runCurrent()
+
+ // THEN notifications are not showing on lockscreen
+ assertThat(onLockscreen).isFalse()
+ }
+
+ @Test
+ fun testIsShowingOnLockscreen_trueWhenViewingKeyguard() =
+ kosmos.testScope.runTest {
+ val onLockscreen by collectLastValue(underTest.isShowingOnLockscreen)
+
+ // WHEN on keyguard
+ kosmos.fakeKeyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+ runCurrent()
+
+ // THEN notifications are showing on lockscreen
+ assertThat(onLockscreen).isTrue()
+ }
+
+ @Test
+ fun testIsShowingOnLockscreen_trueWhenStartingToSleep() =
+ kosmos.testScope.runTest {
+ val onLockscreen by collectLastValue(underTest.isShowingOnLockscreen)
+
+ // WHEN shade is open
+ kosmos.fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
+ // AND device is starting to go to sleep
+ kosmos.fakePowerRepository.updateWakefulness(WakefulnessState.STARTING_TO_SLEEP)
+ runCurrent()
+
+ // THEN notifications are showing on lockscreen
+ assertThat(onLockscreen).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorKosmos.kt
new file mode 100644
index 0000000..db6ba62
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.domain.interactor
+
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.power.domain.interactor.powerInteractor
+
+val Kosmos.notificationStackInteractor by Fixture {
+ NotificationStackInteractor(
+ keyguardInteractor = keyguardInteractor,
+ powerInteractor = powerInteractor,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
index 25e3eac..f1767eb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
@@ -16,16 +16,15 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.domain.interactor.remoteInputInteractor
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.footerViewModel
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.notificationShelfViewModel
+import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackInteractor
import com.android.systemui.statusbar.policy.domain.interactor.userSetupInteractor
import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
import java.util.Optional
@@ -37,8 +36,7 @@
Optional.of(footerViewModel),
Optional.of(notificationListLoggerViewModel),
activeNotificationsInteractor,
- keyguardInteractor,
- powerInteractor,
+ notificationStackInteractor,
remoteInputInteractor,
seenNotificationsInteractor,
shadeInteractor,