Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9cf90b56 authored by Steve Elliott's avatar Steve Elliott Committed by Automerger Merge Worker
Browse files

Merge "Clear set of "unseen" notifications when unlocked" into tm-qpr-dev am: 9d2413c9

parents 58e7fdf7 9d2413c9
Loading
Loading
Loading
Loading
+35 −1
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
 * limitations under the License.
 */

@file:OptIn(ExperimentalCoroutinesApi::class)

package com.android.systemui.statusbar.notification.collection.coordinator

import android.os.UserHandle
@@ -39,14 +41,20 @@ 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.collectLatest
import kotlinx.coroutines.flow.conflate
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

/**
@@ -93,14 +101,39 @@ constructor(
    private suspend fun trackUnseenNotificationsWhileUnlocked() {
        // Use collectLatest so that trackUnseenNotifications() is cancelled when the keyguard is
        // showing again
        var clearUnseenOnUnlock = false
        keyguardRepository.isKeyguardShowing.collectLatest { isKeyguardShowing ->
            if (!isKeyguardShowing) {
            if (isKeyguardShowing) {
                // Wait for the user to spend enough time on the lock screen before clearing unseen
                // set when unlocked
                awaitTimeSpentNotDozing(SEEN_TIMEOUT)
                clearUnseenOnUnlock = true
            } else {
                unseenNotifFilter.invalidateList("keyguard no longer showing")
                if (clearUnseenOnUnlock) {
                    clearUnseenOnUnlock = false
                    unseenNotifications.clear()
                }
                trackUnseenNotifications()
            }
        }
    }

    private suspend fun awaitTimeSpentNotDozing(duration: Duration) {
        keyguardRepository.isDozing
            // Use transformLatest so that the timeout delay is cancelled if the device enters doze,
            // and is restarted when doze ends.
            .transformLatest { isDozing ->
                if (!isDozing) {
                    delay(duration)
                    // Signal timeout has completed
                    emit(Unit)
                }
            }
            // Suspend until the first emission
            .first()
    }

    private suspend fun trackUnseenNotifications() {
        coroutineScope {
            launch { clearUnseenNotificationsWhenShadeIsExpanded() }
@@ -240,5 +273,6 @@ constructor(

    companion object {
        private const val TAG = "KeyguardCoordinator"
        private val SEEN_TIMEOUT = 5.seconds
    }
}
+8 −4
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.provider.Settings
import android.testing.AndroidTestingRunner
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.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
@@ -311,17 +312,20 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
    fun unseenNotificationIsMarkedAsSeenWhenKeyguardGoesAway() {
        whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)

        // GIVEN: Keyguard is showing, unseen notification is present
        // GIVEN: Keyguard is showing, not dozing, unseen notification is present
        keyguardRepository.setKeyguardShowing(true)
        keyguardRepository.setDozing(false)
        runKeyguardCoordinatorTest {
            val fakeEntry = NotificationEntryBuilder().build()
            collectionListener.onEntryAdded(fakeEntry)

            // WHEN: five seconds have passed
            testScheduler.advanceTimeBy(5.seconds)
            testScheduler.runCurrent()

            // WHEN: Keyguard is no longer showing
            keyguardRepository.setKeyguardShowing(false)

            // When: Shade is expanded
            statusBarStateListener.onExpandedChanged(true)
            testScheduler.runCurrent()

            // WHEN: Keyguard is shown again
            keyguardRepository.setKeyguardShowing(true)
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.coroutines

import kotlin.time.Duration
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineScheduler

/**
 * Moves the virtual clock of this dispatcher forward by the specified [Duration].
 *
 * @see [TestCoroutineScheduler.advanceTimeBy]
 */
fun TestCoroutineScheduler.advanceTimeBy(duration: Duration) {
    advanceTimeBy(duration.inWholeMilliseconds)
}