Merge "Log when notifications in the RankingMap are not in the Collection" into tm-qpr-dev am: d7a0392228 am: e882bf483c
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19744601 Change-Id: I5588ae6143f0f8e72e3e08c4534347619c483162 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -88,9 +88,9 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.En
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.EntryUpdatedEvent;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.InitEntryEvent;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.InternalNotifUpdater;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionInconsistencyTracker;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLogger;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLoggerKt;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifEvent;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
|
||||
@@ -112,7 +112,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -151,6 +150,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable {
|
||||
private final Executor mBgExecutor;
|
||||
private final LogBufferEulogizer mEulogizer;
|
||||
private final DumpManager mDumpManager;
|
||||
private final NotifCollectionInconsistencyTracker mInconsistencyTracker;
|
||||
|
||||
private final Map<String, NotificationEntry> mNotificationSet = new ArrayMap<>();
|
||||
private final Collection<NotificationEntry> mReadOnlyNotificationSet =
|
||||
@@ -162,7 +162,6 @@ public class NotifCollection implements Dumpable, PipelineDumpable {
|
||||
private final List<NotifLifetimeExtender> mLifetimeExtenders = new ArrayList<>();
|
||||
private final List<NotifDismissInterceptor> mDismissInterceptors = new ArrayList<>();
|
||||
|
||||
private Set<String> mNotificationsWithoutRankings = Collections.emptySet();
|
||||
|
||||
private Queue<NotifEvent> mEventQueue = new ArrayDeque<>();
|
||||
|
||||
@@ -188,6 +187,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable {
|
||||
mBgExecutor = bgExecutor;
|
||||
mEulogizer = logBufferEulogizer;
|
||||
mDumpManager = dumpManager;
|
||||
mInconsistencyTracker = new NotifCollectionInconsistencyTracker(mLogger);
|
||||
}
|
||||
|
||||
/** Initializes the NotifCollection and registers it to receive notification events. */
|
||||
@@ -199,6 +199,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable {
|
||||
mAttached = true;
|
||||
mDumpManager.registerDumpable(TAG, this);
|
||||
groupCoalescer.setNotificationHandler(mNotifHandler);
|
||||
mInconsistencyTracker.attach(mNotificationSet::keySet, groupCoalescer::getCoalescedKeySet);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -598,14 +599,9 @@ public class NotifCollection implements Dumpable, PipelineDumpable {
|
||||
}
|
||||
}
|
||||
}
|
||||
NotifCollectionLoggerKt.maybeLogInconsistentRankings(
|
||||
mLogger,
|
||||
mNotificationsWithoutRankings,
|
||||
currentEntriesWithoutRankings,
|
||||
rankingMap
|
||||
);
|
||||
mNotificationsWithoutRankings = currentEntriesWithoutRankings == null
|
||||
? Collections.emptySet() : currentEntriesWithoutRankings.keySet();
|
||||
|
||||
mInconsistencyTracker.logNewMissingNotifications(rankingMap);
|
||||
mInconsistencyTracker.logNewInconsistentRankings(currentEntriesWithoutRankings, rankingMap);
|
||||
if (currentEntriesWithoutRankings != null && mNotifPipelineFlags.removeUnrankedNotifs()) {
|
||||
for (NotificationEntry entry : currentEntriesWithoutRankings.values()) {
|
||||
entry.mCancellationReason = REASON_UNKNOWN;
|
||||
@@ -864,10 +860,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable {
|
||||
true,
|
||||
"\t\t"));
|
||||
|
||||
pw.println("\n\tmNotificationsWithoutRankings: " + mNotificationsWithoutRankings.size());
|
||||
for (String key : mNotificationsWithoutRankings) {
|
||||
pw.println("\t * : " + key);
|
||||
}
|
||||
mInconsistencyTracker.dump(pw);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -39,9 +39,11 @@ import com.android.systemui.util.time.SystemClock;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -118,6 +120,11 @@ public class GroupCoalescer implements Dumpable, PipelineDumpable {
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
/** @return the set of notification keys currently in the coalescer */
|
||||
public Set<String> getCoalescedKeySet() {
|
||||
return Collections.unmodifiableSet(mCoalescedEvents.keySet());
|
||||
}
|
||||
|
||||
private final NotificationHandler mListener = new NotificationHandler() {
|
||||
@Override
|
||||
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.notifcollection
|
||||
|
||||
import android.service.notification.NotificationListenerService.RankingMap
|
||||
import android.util.ArrayMap
|
||||
import com.android.internal.annotations.VisibleForTesting
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||
import java.io.PrintWriter
|
||||
|
||||
class NotifCollectionInconsistencyTracker(val logger: NotifCollectionLogger) {
|
||||
fun attach(
|
||||
collectedKeySetAccessor: () -> Set<String>,
|
||||
coalescedKeySetAccessor: () -> Set<String>,
|
||||
) {
|
||||
if (attached) {
|
||||
throw RuntimeException("attach() called twice")
|
||||
}
|
||||
attached = true
|
||||
this.collectedKeySetAccessor = collectedKeySetAccessor
|
||||
this.coalescedKeySetAccessor = coalescedKeySetAccessor
|
||||
}
|
||||
|
||||
fun logNewMissingNotifications(rankingMap: RankingMap) {
|
||||
val currentCollectedKeys = collectedKeySetAccessor()
|
||||
val currentCoalescedKeys = coalescedKeySetAccessor()
|
||||
val newMissingNotifications = rankingMap.orderedKeys.asSequence()
|
||||
.filter { it !in currentCollectedKeys }
|
||||
.filter { it !in currentCoalescedKeys }
|
||||
.toSet()
|
||||
maybeLogMissingNotifications(missingNotifications, newMissingNotifications)
|
||||
missingNotifications = newMissingNotifications
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun maybeLogMissingNotifications(
|
||||
oldMissingKeys: Set<String>,
|
||||
newMissingKeys: Set<String>,
|
||||
) {
|
||||
if (oldMissingKeys.isEmpty() && newMissingKeys.isEmpty()) return
|
||||
if (oldMissingKeys == newMissingKeys) return
|
||||
(oldMissingKeys - newMissingKeys).sorted().let { justFound ->
|
||||
if (justFound.isNotEmpty()) {
|
||||
logger.logFoundNotifications(justFound, newMissingKeys.size)
|
||||
}
|
||||
}
|
||||
(newMissingKeys - oldMissingKeys).sorted().let { goneMissing ->
|
||||
if (goneMissing.isNotEmpty()) {
|
||||
logger.logMissingNotifications(goneMissing, newMissingKeys.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun logNewInconsistentRankings(
|
||||
currentEntriesWithoutRankings: ArrayMap<String, NotificationEntry>?,
|
||||
rankingMap: RankingMap,
|
||||
) {
|
||||
maybeLogInconsistentRankings(
|
||||
notificationsWithoutRankings,
|
||||
currentEntriesWithoutRankings ?: emptyMap(),
|
||||
rankingMap
|
||||
)
|
||||
notificationsWithoutRankings = currentEntriesWithoutRankings?.keys ?: emptySet()
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun maybeLogInconsistentRankings(
|
||||
oldKeysWithoutRankings: Set<String>,
|
||||
newEntriesWithoutRankings: Map<String, NotificationEntry>,
|
||||
rankingMap: RankingMap,
|
||||
) {
|
||||
if (oldKeysWithoutRankings.isEmpty() && newEntriesWithoutRankings.isEmpty()) return
|
||||
if (oldKeysWithoutRankings == newEntriesWithoutRankings.keys) return
|
||||
val newlyConsistent: List<String> = oldKeysWithoutRankings
|
||||
.mapNotNull { key ->
|
||||
key.takeIf { key !in newEntriesWithoutRankings }
|
||||
.takeIf { key in rankingMap.orderedKeys }
|
||||
}.sorted()
|
||||
if (newlyConsistent.isNotEmpty()) {
|
||||
val totalInconsistent: Int = newEntriesWithoutRankings.size
|
||||
logger.logRecoveredRankings(newlyConsistent, totalInconsistent)
|
||||
}
|
||||
val newlyInconsistent: List<NotificationEntry> = newEntriesWithoutRankings
|
||||
.mapNotNull { (key, entry) ->
|
||||
entry.takeIf { key !in oldKeysWithoutRankings }
|
||||
}.sortedBy { it.key }
|
||||
if (newlyInconsistent.isNotEmpty()) {
|
||||
val totalInconsistent: Int = newEntriesWithoutRankings.size
|
||||
logger.logMissingRankings(newlyInconsistent, totalInconsistent, rankingMap)
|
||||
}
|
||||
}
|
||||
|
||||
fun dump(pw: PrintWriter) {
|
||||
pw.println("notificationsWithoutRankings: ${notificationsWithoutRankings.size}")
|
||||
for (key in notificationsWithoutRankings) {
|
||||
pw.println("\t * : $key")
|
||||
}
|
||||
pw.println("missingNotifications: ${missingNotifications.size}")
|
||||
for (key in missingNotifications) {
|
||||
pw.println("\t * : $key")
|
||||
}
|
||||
}
|
||||
|
||||
private var attached: Boolean = false
|
||||
private lateinit var collectedKeySetAccessor: (() -> Set<String>)
|
||||
private lateinit var coalescedKeySetAccessor: (() -> Set<String>)
|
||||
private var notificationsWithoutRankings = emptySet<String>()
|
||||
private var missingNotifications = emptySet<String>()
|
||||
}
|
||||
@@ -215,8 +215,9 @@ class NotifCollectionLogger @Inject constructor(
|
||||
})
|
||||
}
|
||||
|
||||
fun logRecoveredRankings(newlyConsistentKeys: List<String>) {
|
||||
fun logRecoveredRankings(newlyConsistentKeys: List<String>, totalInconsistent: Int) {
|
||||
buffer.log(TAG, INFO, {
|
||||
int1 = totalInconsistent
|
||||
int1 = newlyConsistentKeys.size
|
||||
str1 = newlyConsistentKeys.joinToString { logKey(it) ?: "null" }
|
||||
}, {
|
||||
@@ -224,6 +225,32 @@ class NotifCollectionLogger @Inject constructor(
|
||||
})
|
||||
}
|
||||
|
||||
fun logMissingNotifications(
|
||||
newlyMissingKeys: List<String>,
|
||||
totalMissing: Int,
|
||||
) {
|
||||
buffer.log(TAG, WARNING, {
|
||||
int1 = totalMissing
|
||||
int2 = newlyMissingKeys.size
|
||||
str1 = newlyMissingKeys.joinToString { logKey(it) ?: "null" }
|
||||
}, {
|
||||
"Collection missing $int1 entries in ranking update. Just lost $int2: $str1"
|
||||
})
|
||||
}
|
||||
|
||||
fun logFoundNotifications(
|
||||
newlyFoundKeys: List<String>,
|
||||
totalMissing: Int,
|
||||
) {
|
||||
buffer.log(TAG, INFO, {
|
||||
int1 = totalMissing
|
||||
int2 = newlyFoundKeys.size
|
||||
str1 = newlyFoundKeys.joinToString { logKey(it) ?: "null" }
|
||||
}, {
|
||||
"Collection missing $int1 entries in ranking update. Just found $int2: $str1"
|
||||
})
|
||||
}
|
||||
|
||||
fun logRemoteExceptionOnNotificationClear(entry: NotificationEntry, e: RemoteException) {
|
||||
buffer.log(TAG, WTF, {
|
||||
str1 = entry.logKey
|
||||
@@ -362,29 +389,4 @@ class NotifCollectionLogger @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun maybeLogInconsistentRankings(
|
||||
logger: NotifCollectionLogger,
|
||||
oldKeysWithoutRankings: Set<String>,
|
||||
newEntriesWithoutRankings: Map<String, NotificationEntry>?,
|
||||
rankingMap: RankingMap
|
||||
) {
|
||||
if (oldKeysWithoutRankings.isEmpty() && newEntriesWithoutRankings == null) return
|
||||
val newlyConsistent: List<String> = oldKeysWithoutRankings
|
||||
.mapNotNull { key ->
|
||||
key.takeIf { key !in (newEntriesWithoutRankings ?: emptyMap()) }
|
||||
.takeIf { key in rankingMap.orderedKeys }
|
||||
}.sorted()
|
||||
if (newlyConsistent.isNotEmpty()) {
|
||||
logger.logRecoveredRankings(newlyConsistent)
|
||||
}
|
||||
val newlyInconsistent: List<NotificationEntry> = newEntriesWithoutRankings
|
||||
?.mapNotNull { (key, entry) ->
|
||||
entry.takeIf { key !in oldKeysWithoutRankings }
|
||||
}?.sortedBy { it.key } ?: emptyList()
|
||||
if (newlyInconsistent.isNotEmpty()) {
|
||||
val totalInconsistent: Int = newEntriesWithoutRankings?.size ?: 0
|
||||
logger.logMissingRankings(newlyInconsistent, totalInconsistent, rankingMap)
|
||||
}
|
||||
}
|
||||
|
||||
private const val TAG = "NotifCollection"
|
||||
|
||||
@@ -1518,7 +1518,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
verify(mCollectionListener).onRankingApplied();
|
||||
verifyNoMoreInteractions(mCollectionListener);
|
||||
verify(mLogger).logMissingRankings(eq(List.of(entry1)), eq(1), any());
|
||||
verify(mLogger, never()).logRecoveredRankings(any());
|
||||
verify(mLogger, never()).logRecoveredRankings(any(), anyInt());
|
||||
clearInvocations(mCollectionListener, mLogger);
|
||||
|
||||
// WHEN a ranking update includes key1 again
|
||||
@@ -1530,7 +1530,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
verify(mCollectionListener).onRankingApplied();
|
||||
verifyNoMoreInteractions(mCollectionListener);
|
||||
verify(mLogger, never()).logMissingRankings(any(), anyInt(), any());
|
||||
verify(mLogger).logRecoveredRankings(eq(List.of(key1)));
|
||||
verify(mLogger).logRecoveredRankings(eq(List.of(key1)), eq(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1556,7 +1556,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
verify(mCollectionListener).onRankingApplied();
|
||||
verifyNoMoreInteractions(mCollectionListener);
|
||||
verify(mLogger).logMissingRankings(eq(List.of(entry1)), eq(1), any());
|
||||
verify(mLogger, never()).logRecoveredRankings(any());
|
||||
verify(mLogger, never()).logRecoveredRankings(any(), anyInt());
|
||||
clearInvocations(mCollectionListener, mLogger);
|
||||
|
||||
// WHEN a ranking update includes key1 again
|
||||
@@ -1568,7 +1568,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
verify(mCollectionListener).onRankingApplied();
|
||||
verifyNoMoreInteractions(mCollectionListener);
|
||||
verify(mLogger, never()).logMissingRankings(any(), anyInt(), any());
|
||||
verify(mLogger).logRecoveredRankings(eq(List.of(key1)));
|
||||
verify(mLogger).logRecoveredRankings(eq(List.of(key1)), eq(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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.notifcollection
|
||||
|
||||
import android.service.notification.NotificationListenerService.RankingMap
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper
|
||||
class NotifCollectionInconsistencyTrackerTest : SysuiTestCase() {
|
||||
private val logger: NotifCollectionLogger = mock()
|
||||
private val entry1: NotificationEntry = NotificationEntryBuilder().setId(1).build()
|
||||
private val entry2: NotificationEntry = NotificationEntryBuilder().setId(2).build()
|
||||
private val collectionSet = mutableSetOf<String>()
|
||||
private val coalescedSet = mutableSetOf<String>()
|
||||
private lateinit var inconsistencyTracker: NotifCollectionInconsistencyTracker
|
||||
|
||||
private fun mapOfEntries(vararg entries: NotificationEntry): Map<String, NotificationEntry> =
|
||||
entries.associateBy { it.key }
|
||||
|
||||
private fun rankingMapOf(vararg entries: NotificationEntry): RankingMap =
|
||||
RankingMap(entries.map { it.ranking }.toTypedArray())
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
inconsistencyTracker = NotifCollectionInconsistencyTracker(logger)
|
||||
inconsistencyTracker.attach({ collectionSet }, { coalescedSet })
|
||||
collectionSet.clear()
|
||||
coalescedSet.clear()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun maybeLogInconsistentRankings_logsNewlyInconsistentRanking() {
|
||||
val rankingMap = rankingMapOf(entry1)
|
||||
inconsistencyTracker.maybeLogInconsistentRankings(
|
||||
oldKeysWithoutRankings = emptySet(),
|
||||
newEntriesWithoutRankings = mapOfEntries(entry2),
|
||||
rankingMap = rankingMap
|
||||
)
|
||||
verify(logger).logMissingRankings(
|
||||
newlyInconsistentEntries = eq(listOf(entry2)),
|
||||
totalInconsistent = eq(1),
|
||||
rankingMap = eq(rankingMap),
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun maybeLogInconsistentRankings_doesNotLogAlreadyInconsistentRanking() {
|
||||
inconsistencyTracker.maybeLogInconsistentRankings(
|
||||
oldKeysWithoutRankings = setOf(entry2.key),
|
||||
newEntriesWithoutRankings = mapOfEntries(entry2),
|
||||
rankingMap = rankingMapOf(entry1)
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun maybeLogInconsistentRankings_logsWhenRankingIsAdded() {
|
||||
inconsistencyTracker.maybeLogInconsistentRankings(
|
||||
oldKeysWithoutRankings = setOf(entry2.key),
|
||||
newEntriesWithoutRankings = mapOfEntries(),
|
||||
rankingMap = rankingMapOf(entry1, entry2)
|
||||
)
|
||||
verify(logger).logRecoveredRankings(
|
||||
newlyConsistentKeys = eq(listOf(entry2.key)),
|
||||
totalInconsistent = eq(0),
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun maybeLogInconsistentRankings_doesNotLogsWhenEntryIsRemoved() {
|
||||
inconsistencyTracker.maybeLogInconsistentRankings(
|
||||
oldKeysWithoutRankings = setOf(entry2.key),
|
||||
newEntriesWithoutRankings = mapOfEntries(),
|
||||
rankingMap = rankingMapOf(entry1)
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun maybeLogMissingNotifications_logsNewlyMissingNotifications() {
|
||||
inconsistencyTracker.maybeLogMissingNotifications(
|
||||
oldMissingKeys = setOf("a"),
|
||||
newMissingKeys = setOf("a", "b"),
|
||||
)
|
||||
verify(logger).logMissingNotifications(
|
||||
newlyMissingKeys = eq(listOf("b")),
|
||||
totalMissing = eq(2),
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun maybeLogMissingNotifications_logsNoLongerMissingNotifications() {
|
||||
inconsistencyTracker.maybeLogMissingNotifications(
|
||||
oldMissingKeys = setOf("a", "b"),
|
||||
newMissingKeys = setOf("a"),
|
||||
)
|
||||
verify(logger).logFoundNotifications(
|
||||
newlyFoundKeys = eq(listOf("b")),
|
||||
totalMissing = eq(1),
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun maybeLogMissingNotifications_logsBothAtOnce() {
|
||||
inconsistencyTracker.maybeLogMissingNotifications(
|
||||
oldMissingKeys = setOf("a"),
|
||||
newMissingKeys = setOf("b"),
|
||||
)
|
||||
verify(logger).logFoundNotifications(
|
||||
newlyFoundKeys = eq(listOf("a")),
|
||||
totalMissing = eq(1),
|
||||
)
|
||||
verify(logger).logMissingNotifications(
|
||||
newlyMissingKeys = eq(listOf("b")),
|
||||
totalMissing = eq(1),
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun maybeLogMissingNotifications_logsNothingWhenNoChange() {
|
||||
inconsistencyTracker.maybeLogMissingNotifications(
|
||||
oldMissingKeys = setOf("a"),
|
||||
newMissingKeys = setOf("a"),
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logNewMissingNotifications_doesNotLogForConsistentSets() {
|
||||
inconsistencyTracker.logNewMissingNotifications(rankingMapOf())
|
||||
verifyNoMoreInteractions(logger)
|
||||
|
||||
collectionSet.add(entry1.key)
|
||||
inconsistencyTracker.logNewMissingNotifications(rankingMapOf(entry1))
|
||||
verifyNoMoreInteractions(logger)
|
||||
|
||||
coalescedSet.add(entry2.key)
|
||||
inconsistencyTracker.logNewMissingNotifications(rankingMapOf(entry1, entry2))
|
||||
verifyNoMoreInteractions(logger)
|
||||
|
||||
coalescedSet.add(entry1.key)
|
||||
inconsistencyTracker.logNewMissingNotifications(rankingMapOf(entry1, entry2))
|
||||
verifyNoMoreInteractions(logger)
|
||||
|
||||
coalescedSet.remove(entry1.key)
|
||||
collectionSet.remove(entry1.key)
|
||||
inconsistencyTracker.logNewMissingNotifications(rankingMapOf(entry2))
|
||||
verifyNoMoreInteractions(logger)
|
||||
|
||||
coalescedSet.remove(entry2.key)
|
||||
inconsistencyTracker.logNewMissingNotifications(rankingMapOf())
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logNewMissingNotifications_logsAsExpected() {
|
||||
inconsistencyTracker.logNewMissingNotifications(rankingMapOf())
|
||||
verifyNoMoreInteractions(logger)
|
||||
|
||||
collectionSet.add(entry1.key)
|
||||
inconsistencyTracker.logNewMissingNotifications(rankingMapOf(entry1, entry2))
|
||||
verify(logger).logMissingNotifications(
|
||||
newlyMissingKeys = eq(listOf(entry2.key)),
|
||||
totalMissing = eq(1),
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
clearInvocations(logger)
|
||||
|
||||
inconsistencyTracker.logNewMissingNotifications(rankingMapOf(entry1, entry2))
|
||||
verifyNoMoreInteractions(logger)
|
||||
|
||||
coalescedSet.add(entry2.key)
|
||||
inconsistencyTracker.logNewMissingNotifications(rankingMapOf(entry1, entry2))
|
||||
verify(logger).logFoundNotifications(
|
||||
newlyFoundKeys = eq(listOf(entry2.key)),
|
||||
totalMissing = eq(0),
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
clearInvocations(logger)
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* 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.notifcollection
|
||||
|
||||
import android.service.notification.NotificationListenerService.RankingMap
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper
|
||||
class NotifCollectionLoggerTest : SysuiTestCase() {
|
||||
private val logger: NotifCollectionLogger = mock()
|
||||
private val entry1: NotificationEntry = NotificationEntryBuilder().setId(1).build()
|
||||
private val entry2: NotificationEntry = NotificationEntryBuilder().setId(2).build()
|
||||
|
||||
private fun mapOfEntries(vararg entries: NotificationEntry): Map<String, NotificationEntry> =
|
||||
entries.associateBy { it.key }
|
||||
|
||||
private fun rankingMapOf(vararg entries: NotificationEntry): RankingMap =
|
||||
RankingMap(entries.map { it.ranking }.toTypedArray())
|
||||
|
||||
@Test
|
||||
fun testMaybeLogInconsistentRankings_logsNewlyInconsistentRanking() {
|
||||
val rankingMap = rankingMapOf(entry1)
|
||||
maybeLogInconsistentRankings(
|
||||
logger = logger,
|
||||
oldKeysWithoutRankings = emptySet(),
|
||||
newEntriesWithoutRankings = mapOfEntries(entry2),
|
||||
rankingMap = rankingMap
|
||||
)
|
||||
verify(logger).logMissingRankings(
|
||||
newlyInconsistentEntries = eq(listOf(entry2)),
|
||||
totalInconsistent = eq(1),
|
||||
rankingMap = eq(rankingMap),
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMaybeLogInconsistentRankings_doesNotLogAlreadyInconsistentRanking() {
|
||||
maybeLogInconsistentRankings(
|
||||
logger = logger,
|
||||
oldKeysWithoutRankings = setOf(entry2.key),
|
||||
newEntriesWithoutRankings = mapOfEntries(entry2),
|
||||
rankingMap = rankingMapOf(entry1)
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMaybeLogInconsistentRankings_logsWhenRankingIsAdded() {
|
||||
maybeLogInconsistentRankings(
|
||||
logger = logger,
|
||||
oldKeysWithoutRankings = setOf(entry2.key),
|
||||
newEntriesWithoutRankings = mapOfEntries(),
|
||||
rankingMap = rankingMapOf(entry1, entry2)
|
||||
)
|
||||
verify(logger).logRecoveredRankings(
|
||||
newlyConsistentKeys = eq(listOf(entry2.key)),
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMaybeLogInconsistentRankings_doesNotLogsWhenEntryIsRemoved() {
|
||||
maybeLogInconsistentRankings(
|
||||
logger = logger,
|
||||
oldKeysWithoutRankings = setOf(entry2.key),
|
||||
newEntriesWithoutRankings = mapOfEntries(),
|
||||
rankingMap = rankingMapOf(entry1)
|
||||
)
|
||||
verifyNoMoreInteractions(logger)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user