diff options
Diffstat (limited to 'packages/SystemUI')
3 files changed, 85 insertions, 12 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt index 82bd45ce2279..6322edf5a1b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt @@ -24,6 +24,10 @@ import androidx.annotation.VisibleForTesting import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.data.repository.KeyguardRepository +import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.expansionChanges @@ -40,22 +44,26 @@ import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.headsUpEvents import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow -import javax.inject.Inject -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.launch +import kotlinx.coroutines.yield +import javax.inject.Inject +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds /** * Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section @@ -69,6 +77,7 @@ constructor( private val headsUpManager: HeadsUpManager, private val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider, private val keyguardRepository: KeyguardRepository, + private val keyguardTransitionRepository: KeyguardTransitionRepository, private val notifPipelineFlags: NotifPipelineFlags, @Application private val scope: CoroutineScope, private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider, @@ -99,21 +108,46 @@ constructor( } private suspend fun trackUnseenNotificationsWhileUnlocked() { + // Whether or not we're actively tracking unseen notifications to mark them as seen when + // appropriate. + val isTrackingUnseen: Flow<Boolean> = + keyguardRepository.isKeyguardShowing + // transformLatest so that we can cancel listening to keyguard transitions once + // isKeyguardShowing changes (after a successful transition to the keyguard). + .transformLatest { isShowing -> + if (isShowing) { + // If the keyguard is showing, we're not tracking unseen. + emit(false) + } else { + // If the keyguard stops showing, then start tracking unseen notifications. + emit(true) + // If the screen is turning off, stop tracking, but if that transition is + // cancelled, then start again. + emitAll( + keyguardTransitionRepository.transitions + .map { step -> !step.isScreenTurningOff } + ) + } + } + // Prevent double emit of `false` caused by transition to AOD, followed by keyguard + // showing + .distinctUntilChanged() + // Use collectLatest so that trackUnseenNotifications() is cancelled when the keyguard is // showing again - var clearUnseenOnUnlock = false - keyguardRepository.isKeyguardShowing.collectLatest { isKeyguardShowing -> - if (isKeyguardShowing) { + var clearUnseenOnBeginTracking = false + isTrackingUnseen.collectLatest { trackingUnseen -> + if (!trackingUnseen) { // Wait for the user to spend enough time on the lock screen before clearing unseen // set when unlocked awaitTimeSpentNotDozing(SEEN_TIMEOUT) - clearUnseenOnUnlock = true + clearUnseenOnBeginTracking = true } else { - unseenNotifFilter.invalidateList("keyguard no longer showing") - if (clearUnseenOnUnlock) { - clearUnseenOnUnlock = false + if (clearUnseenOnBeginTracking) { + clearUnseenOnBeginTracking = false unseenNotifications.clear() } + unseenNotifFilter.invalidateList("keyguard no longer showing") trackUnseenNotifications() } } @@ -142,7 +176,10 @@ constructor( } private suspend fun clearUnseenNotificationsWhenShadeIsExpanded() { - statusBarStateController.expansionChanges.collect { isExpanded -> + statusBarStateController.expansionChanges.collectLatest { isExpanded -> + // Give keyguard events time to propagate, in case this expansion is part of the + // keyguard transition and not the user expanding the shade + yield() if (isExpanded) { unseenNotifications.clear() } @@ -276,3 +313,6 @@ constructor( private val SEEN_TIMEOUT = 5.seconds } } + +private val TransitionStep.isScreenTurningOff: Boolean get() = + transitionState == TransitionState.STARTED && to != KeyguardState.GONE
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt index 8109e24a1e52..c2a2a40b7e5d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt @@ -25,6 +25,10 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.advanceTimeBy import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.NotifPipelineFlags @@ -69,6 +73,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() { private val headsUpManager: HeadsUpManager = mock() private val keyguardNotifVisibilityProvider: KeyguardNotificationVisibilityProvider = mock() private val keyguardRepository = FakeKeyguardRepository() + private val keyguardTransitionRepository = FakeKeyguardTransitionRepository() private val notifPipelineFlags: NotifPipelineFlags = mock() private val notifPipeline: NotifPipeline = mock() private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider = mock() @@ -118,6 +123,33 @@ class KeyguardCoordinatorTest : SysuiTestCase() { } @Test + fun unseenFilterStopsMarkingSeenNotifWhenTransitionToAod() { + whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true) + + // GIVEN: Keyguard is not showing, shade is not expanded, and a notification is present + keyguardRepository.setKeyguardShowing(false) + whenever(statusBarStateController.isExpanded).thenReturn(false) + runKeyguardCoordinatorTest { + val fakeEntry = NotificationEntryBuilder().build() + collectionListener.onEntryAdded(fakeEntry) + + // WHEN: The device transitions to AOD + keyguardTransitionRepository.sendTransitionStep( + TransitionStep(to = KeyguardState.AOD, transitionState = TransitionState.STARTED), + ) + testScheduler.runCurrent() + + // WHEN: The shade is expanded + whenever(statusBarStateController.isExpanded).thenReturn(true) + statusBarStateListener.onExpandedChanged(true) + testScheduler.runCurrent() + + // THEN: The notification is still treated as "unseen" and is not filtered out. + assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse() + } + } + + @Test fun unseenFilter_headsUpMarkedAsSeen() { whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true) @@ -373,6 +405,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() { headsUpManager, keyguardNotifVisibilityProvider, keyguardRepository, + keyguardTransitionRepository, notifPipelineFlags, testScope.backgroundScope, sectionHeaderVisibilityProvider, diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt index 0b019d1285e3..30418883eaf8 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt @@ -35,7 +35,7 @@ class UnfoldRemoteFilter( private var inProgress = false - private var processedProgress: Float = 0.0f + private var processedProgress: Float = 1.0f set(newProgress) { if (inProgress) { logCounter({ "$TAG#filtered_progress" }, newProgress) |