Merge changes from topic "tangor-keyguard-notifs" into tm-qpr-dev
* changes: Filter out seen notifications from keyguard Convert KeyguardCoordinator to Kotlin
This commit is contained in:
committed by
Android (Google) Code Review
commit
c3de18645f
@@ -90,7 +90,8 @@ object Flags {
|
||||
// TODO(b/257315550): Tracking Bug
|
||||
val NO_HUN_FOR_OLD_WHEN = unreleasedFlag(118, "no_hun_for_old_when")
|
||||
|
||||
// next id: 119
|
||||
val FILTER_UNSEEN_NOTIFS_ON_KEYGUARD =
|
||||
unreleasedFlag(254647461, "filter_unseen_notifs_on_keyguard", teamfood = true)
|
||||
|
||||
// 200 - keyguard/lockscreen
|
||||
// ** Flag retired **
|
||||
|
||||
@@ -40,4 +40,8 @@ class NotifPipelineFlags @Inject constructor(
|
||||
val isSemiStableSortEnabled: Boolean by lazy {
|
||||
featureFlags.isEnabled(Flags.SEMI_STABLE_SORT)
|
||||
}
|
||||
|
||||
val shouldFilterUnseenNotifsOnKeyguard: Boolean by lazy {
|
||||
featureFlags.isEnabled(Flags.FILTER_UNSEEN_NOTIFS_ON_KEYGUARD)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.collection.coordinator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
|
||||
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
|
||||
import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider;
|
||||
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section
|
||||
* headers on the lockscreen.
|
||||
*/
|
||||
@CoordinatorScope
|
||||
public class KeyguardCoordinator implements Coordinator {
|
||||
private static final String TAG = "KeyguardCoordinator";
|
||||
private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
|
||||
private final SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
|
||||
private final StatusBarStateController mStatusBarStateController;
|
||||
|
||||
@Inject
|
||||
public KeyguardCoordinator(
|
||||
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider,
|
||||
SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider,
|
||||
StatusBarStateController statusBarStateController) {
|
||||
mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider;
|
||||
mSectionHeaderVisibilityProvider = sectionHeaderVisibilityProvider;
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach(NotifPipeline pipeline) {
|
||||
|
||||
setupInvalidateNotifListCallbacks();
|
||||
// Filter at the "finalize" stage so that views remain bound by PreparationCoordinator
|
||||
pipeline.addFinalizeFilter(mNotifFilter);
|
||||
mKeyguardNotificationVisibilityProvider
|
||||
.addOnStateChangedListener(this::invalidateListFromFilter);
|
||||
updateSectionHeadersVisibility();
|
||||
}
|
||||
|
||||
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
|
||||
@Override
|
||||
public boolean shouldFilterOut(@NonNull NotificationEntry entry, long now) {
|
||||
return mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(b/206118999): merge this class with SensitiveContentCoordinator which also depends on
|
||||
// these same updates
|
||||
private void setupInvalidateNotifListCallbacks() {
|
||||
|
||||
}
|
||||
|
||||
private void invalidateListFromFilter(String reason) {
|
||||
updateSectionHeadersVisibility();
|
||||
mNotifFilter.invalidateList(reason);
|
||||
}
|
||||
|
||||
private void updateSectionHeadersVisibility() {
|
||||
boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
|
||||
boolean neverShowSections = mSectionHeaderVisibilityProvider.getNeverShowSectionHeaders();
|
||||
boolean showSections = !onKeyguard && !neverShowSections;
|
||||
mSectionHeaderVisibilityProvider.setSectionHeadersVisible(showSections);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.collection.coordinator
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardRepository
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.notification.NotifPipelineFlags
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
|
||||
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
|
||||
import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
|
||||
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section
|
||||
* headers on the lockscreen.
|
||||
*/
|
||||
@CoordinatorScope
|
||||
class KeyguardCoordinator
|
||||
@Inject
|
||||
constructor(
|
||||
private val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider,
|
||||
private val keyguardRepository: KeyguardRepository,
|
||||
private val notifPipelineFlags: NotifPipelineFlags,
|
||||
@Application private val scope: CoroutineScope,
|
||||
private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
|
||||
private val statusBarStateController: StatusBarStateController,
|
||||
) : Coordinator {
|
||||
|
||||
private val unseenNotifications = mutableSetOf<NotificationEntry>()
|
||||
|
||||
override fun attach(pipeline: NotifPipeline) {
|
||||
setupInvalidateNotifListCallbacks()
|
||||
// Filter at the "finalize" stage so that views remain bound by PreparationCoordinator
|
||||
pipeline.addFinalizeFilter(notifFilter)
|
||||
keyguardNotificationVisibilityProvider.addOnStateChangedListener(::invalidateListFromFilter)
|
||||
updateSectionHeadersVisibility()
|
||||
if (notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard) {
|
||||
attachUnseenFilter(pipeline)
|
||||
}
|
||||
}
|
||||
|
||||
private fun attachUnseenFilter(pipeline: NotifPipeline) {
|
||||
pipeline.addFinalizeFilter(unseenNotifFilter)
|
||||
pipeline.addCollectionListener(collectionListener)
|
||||
scope.launch { clearUnseenWhenKeyguardIsDismissed() }
|
||||
}
|
||||
|
||||
private suspend fun clearUnseenWhenKeyguardIsDismissed() {
|
||||
// Use collectLatest so that the suspending block is cancelled if isKeyguardShowing changes
|
||||
// during the timeout period
|
||||
keyguardRepository.isKeyguardShowing.collectLatest { isKeyguardShowing ->
|
||||
if (!isKeyguardShowing) {
|
||||
unseenNotifFilter.invalidateList("keyguard no longer showing")
|
||||
delay(SEEN_TIMEOUT)
|
||||
unseenNotifications.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val collectionListener =
|
||||
object : NotifCollectionListener {
|
||||
override fun onEntryAdded(entry: NotificationEntry) {
|
||||
if (keyguardRepository.isKeyguardShowing()) {
|
||||
unseenNotifications.add(entry)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEntryUpdated(entry: NotificationEntry) {
|
||||
if (keyguardRepository.isKeyguardShowing()) {
|
||||
unseenNotifications.add(entry)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
|
||||
unseenNotifications.remove(entry)
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal val unseenNotifFilter =
|
||||
object : NotifFilter("$TAG-unseen") {
|
||||
override fun shouldFilterOut(entry: NotificationEntry, now: Long): Boolean =
|
||||
when {
|
||||
// Don't apply filter if the keyguard isn't currently showing
|
||||
!keyguardRepository.isKeyguardShowing() -> false
|
||||
// Don't apply the filter if the notification is unseen
|
||||
unseenNotifications.contains(entry) -> false
|
||||
// Don't apply the filter to (non-promoted) group summaries
|
||||
// - summary will be pruned if necessary, depending on if children are filtered
|
||||
entry.parent?.summary == entry -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
private val notifFilter: NotifFilter =
|
||||
object : NotifFilter(TAG) {
|
||||
override fun shouldFilterOut(entry: NotificationEntry, now: Long): Boolean =
|
||||
keyguardNotificationVisibilityProvider.shouldHideNotification(entry)
|
||||
}
|
||||
|
||||
// TODO(b/206118999): merge this class with SensitiveContentCoordinator which also depends on
|
||||
// these same updates
|
||||
private fun setupInvalidateNotifListCallbacks() {}
|
||||
|
||||
private fun invalidateListFromFilter(reason: String) {
|
||||
updateSectionHeadersVisibility()
|
||||
notifFilter.invalidateList(reason)
|
||||
}
|
||||
|
||||
private fun updateSectionHeadersVisibility() {
|
||||
val onKeyguard = statusBarStateController.state == StatusBarState.KEYGUARD
|
||||
val neverShowSections = sectionHeaderVisibilityProvider.neverShowSectionHeaders
|
||||
val showSections = !onKeyguard && !neverShowSections
|
||||
sectionHeaderVisibilityProvider.sectionHeadersVisible = showSections
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "KeyguardCoordinator"
|
||||
private val SEEN_TIMEOUT = 5.seconds
|
||||
}
|
||||
}
|
||||
@@ -13,57 +13,55 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
@file:OptIn(ExperimentalCoroutinesApi::class)
|
||||
|
||||
package com.android.systemui.statusbar.notification.collection.coordinator
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.notification.NotifPipelineFlags
|
||||
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
|
||||
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
|
||||
import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
|
||||
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.withArgCaptor
|
||||
import java.util.function.Consumer
|
||||
import org.junit.Before
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestCoroutineScheduler
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.verify
|
||||
import java.util.function.Consumer
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class KeyguardCoordinatorTest : SysuiTestCase() {
|
||||
private val notifPipeline: NotifPipeline = mock()
|
||||
|
||||
private val keyguardNotifVisibilityProvider: KeyguardNotificationVisibilityProvider = mock()
|
||||
private val keyguardRepository = FakeKeyguardRepository()
|
||||
private val notifPipelineFlags: NotifPipelineFlags = mock()
|
||||
private val notifPipeline: NotifPipeline = mock()
|
||||
private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider = mock()
|
||||
private val statusBarStateController: StatusBarStateController = mock()
|
||||
|
||||
private lateinit var onStateChangeListener: Consumer<String>
|
||||
private lateinit var keyguardFilter: NotifFilter
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
val keyguardCoordinator = KeyguardCoordinator(
|
||||
keyguardNotifVisibilityProvider,
|
||||
sectionHeaderVisibilityProvider,
|
||||
statusBarStateController
|
||||
)
|
||||
keyguardCoordinator.attach(notifPipeline)
|
||||
onStateChangeListener = withArgCaptor {
|
||||
verify(keyguardNotifVisibilityProvider).addOnStateChangedListener(capture())
|
||||
}
|
||||
keyguardFilter = withArgCaptor {
|
||||
verify(notifPipeline).addFinalizeFilter(capture())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetSectionHeadersVisibleInShade() {
|
||||
fun testSetSectionHeadersVisibleInShade() = runKeyguardCoordinatorTest {
|
||||
clearInvocations(sectionHeaderVisibilityProvider)
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
|
||||
onStateChangeListener.accept("state change")
|
||||
@@ -71,10 +69,176 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetSectionHeadersNotVisibleOnKeyguard() {
|
||||
fun testSetSectionHeadersNotVisibleOnKeyguard() = runKeyguardCoordinatorTest {
|
||||
clearInvocations(sectionHeaderVisibilityProvider)
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
onStateChangeListener.accept("state change")
|
||||
verify(sectionHeaderVisibilityProvider).sectionHeadersVisible = eq(false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unseenFilterSuppressesSeenNotifWhileKeyguardShowing() {
|
||||
whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
|
||||
|
||||
// GIVEN: Keyguard is not showing, and a notification is present
|
||||
keyguardRepository.setKeyguardShowing(false)
|
||||
runKeyguardCoordinatorTest {
|
||||
val fakeEntry = NotificationEntryBuilder().build()
|
||||
collectionListener.onEntryAdded(fakeEntry)
|
||||
|
||||
// WHEN: The keyguard is now showing
|
||||
keyguardRepository.setKeyguardShowing(true)
|
||||
testScheduler.runCurrent()
|
||||
|
||||
// THEN: The notification is recognized as "seen" and is filtered out.
|
||||
assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isTrue()
|
||||
|
||||
// WHEN: The keyguard goes away
|
||||
keyguardRepository.setKeyguardShowing(false)
|
||||
testScheduler.runCurrent()
|
||||
|
||||
// THEN: The notification is shown regardless
|
||||
assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unseenFilterAllowsNewNotif() {
|
||||
whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
|
||||
|
||||
// GIVEN: Keyguard is showing, no notifications present
|
||||
keyguardRepository.setKeyguardShowing(true)
|
||||
runKeyguardCoordinatorTest {
|
||||
// WHEN: A new notification is posted
|
||||
val fakeEntry = NotificationEntryBuilder().build()
|
||||
collectionListener.onEntryAdded(fakeEntry)
|
||||
|
||||
// THEN: The notification is recognized as "unseen" and is not filtered out.
|
||||
assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unseenFilterSeenGroupSummaryWithUnseenChild() {
|
||||
whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
|
||||
|
||||
// GIVEN: Keyguard is not showing, and a notification is present
|
||||
keyguardRepository.setKeyguardShowing(false)
|
||||
runKeyguardCoordinatorTest {
|
||||
// WHEN: A new notification is posted
|
||||
val fakeSummary = NotificationEntryBuilder().build()
|
||||
val fakeChild = NotificationEntryBuilder()
|
||||
.setGroup(context, "group")
|
||||
.setGroupSummary(context, false)
|
||||
.build()
|
||||
GroupEntryBuilder()
|
||||
.setSummary(fakeSummary)
|
||||
.addChild(fakeChild)
|
||||
.build()
|
||||
|
||||
collectionListener.onEntryAdded(fakeSummary)
|
||||
collectionListener.onEntryAdded(fakeChild)
|
||||
|
||||
// WHEN: Keyguard is now showing, both notifications are marked as seen
|
||||
keyguardRepository.setKeyguardShowing(true)
|
||||
testScheduler.runCurrent()
|
||||
|
||||
// WHEN: The child notification is now unseen
|
||||
collectionListener.onEntryUpdated(fakeChild)
|
||||
|
||||
// THEN: The summary is not filtered out, because the child is unseen
|
||||
assertThat(unseenFilter.shouldFilterOut(fakeSummary, 0L)).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unseenNotificationIsMarkedAsSeenWhenKeyguardGoesAway() {
|
||||
whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
|
||||
|
||||
// GIVEN: Keyguard is showing, unseen notification is present
|
||||
keyguardRepository.setKeyguardShowing(true)
|
||||
runKeyguardCoordinatorTest {
|
||||
val fakeEntry = NotificationEntryBuilder().build()
|
||||
collectionListener.onEntryAdded(fakeEntry)
|
||||
|
||||
// WHEN: Keyguard is no longer showing for 5 seconds
|
||||
keyguardRepository.setKeyguardShowing(false)
|
||||
testScheduler.runCurrent()
|
||||
testScheduler.advanceTimeBy(5.seconds.inWholeMilliseconds)
|
||||
testScheduler.runCurrent()
|
||||
|
||||
// WHEN: Keyguard is shown again
|
||||
keyguardRepository.setKeyguardShowing(true)
|
||||
testScheduler.runCurrent()
|
||||
|
||||
// THEN: The notification is now recognized as "seen" and is filtered out.
|
||||
assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unseenNotificationIsNotMarkedAsSeenIfTimeThresholdNotMet() {
|
||||
whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
|
||||
|
||||
// GIVEN: Keyguard is showing, unseen notification is present
|
||||
keyguardRepository.setKeyguardShowing(true)
|
||||
runKeyguardCoordinatorTest {
|
||||
val fakeEntry = NotificationEntryBuilder().build()
|
||||
collectionListener.onEntryAdded(fakeEntry)
|
||||
|
||||
// WHEN: Keyguard is no longer showing for <5 seconds
|
||||
keyguardRepository.setKeyguardShowing(false)
|
||||
testScheduler.runCurrent()
|
||||
testScheduler.advanceTimeBy(1.seconds.inWholeMilliseconds)
|
||||
|
||||
// WHEN: Keyguard is shown again
|
||||
keyguardRepository.setKeyguardShowing(true)
|
||||
testScheduler.runCurrent()
|
||||
|
||||
// THEN: The notification is not recognized as "seen" and is not filtered out.
|
||||
assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
private fun runKeyguardCoordinatorTest(
|
||||
testBlock: suspend KeyguardCoordinatorTestScope.() -> Unit
|
||||
) {
|
||||
val testScope = TestScope(UnconfinedTestDispatcher())
|
||||
val keyguardCoordinator =
|
||||
KeyguardCoordinator(
|
||||
keyguardNotifVisibilityProvider,
|
||||
keyguardRepository,
|
||||
notifPipelineFlags,
|
||||
testScope.backgroundScope,
|
||||
sectionHeaderVisibilityProvider,
|
||||
statusBarStateController,
|
||||
)
|
||||
keyguardCoordinator.attach(notifPipeline)
|
||||
KeyguardCoordinatorTestScope(keyguardCoordinator, testScope).run {
|
||||
testScheduler.advanceUntilIdle()
|
||||
testScope.runTest(dispatchTimeoutMs = 1.seconds.inWholeMilliseconds) { testBlock() }
|
||||
}
|
||||
}
|
||||
|
||||
private inner class KeyguardCoordinatorTestScope(
|
||||
private val keyguardCoordinator: KeyguardCoordinator,
|
||||
private val scope: TestScope,
|
||||
) : CoroutineScope by scope {
|
||||
val testScheduler: TestCoroutineScheduler
|
||||
get() = scope.testScheduler
|
||||
|
||||
val onStateChangeListener: Consumer<String> =
|
||||
withArgCaptor {
|
||||
verify(keyguardNotifVisibilityProvider).addOnStateChangedListener(capture())
|
||||
}
|
||||
|
||||
val unseenFilter: NotifFilter
|
||||
get() = keyguardCoordinator.unseenNotifFilter
|
||||
|
||||
// TODO(254647461): Remove lazy once Flags.FILTER_UNSEEN_NOTIFS_ON_KEYGUARD is enabled and
|
||||
// removed
|
||||
val collectionListener: NotifCollectionListener by lazy {
|
||||
withArgCaptor { verify(notifPipeline).addCollectionListener(capture()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user