Merge "Clear set of "unseen" notifications when unlocked" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9d2413c996
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
||||
Reference in New Issue
Block a user