Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryWithDismissStats.kt 0 → 100644 +46 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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 import com.android.internal.statusbar.NotificationVisibility import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats /** * A holder class for a [NotificationEntry] and an associated [DismissedByUserStats], used by * [NotifCollection] for handling dismissal. */ data class EntryWithDismissStats(val entry: NotificationEntry, val stats: DismissedByUserStats) { /** * Creates deep a copy of this object, but with the entry, key and rank updated to correspond to * the given entry. */ fun copyForEntry(newEntry: NotificationEntry) = EntryWithDismissStats( entry = newEntry, stats = DismissedByUserStats( stats.dismissalSurface, stats.dismissalSentiment, NotificationVisibility.obtain( newEntry.key, newEntry.ranking.rank, stats.notificationVisibility.count, /* visible= */ false, ), ), ) } packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +12 −25 Original line number Diff line number Diff line Loading @@ -63,14 +63,12 @@ import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; Loading Loading @@ -276,7 +274,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { * Dismisses multiple notifications on behalf of the user. */ public void dismissNotifications( List<Pair<NotificationEntry, DismissedByUserStats>> entriesToDismiss) { List<EntryWithDismissStats> entriesToDismiss) { Assert.isMainThread(); checkForReentrantCall(); Loading @@ -287,8 +285,8 @@ public class NotifCollection implements Dumpable, PipelineDumpable { final int entryCount = entriesToDismiss.size(); final List<NotificationEntry> entriesToLocallyDismiss = new ArrayList<>(); for (int i = 0; i < entriesToDismiss.size(); i++) { NotificationEntry entry = entriesToDismiss.get(i).first; DismissedByUserStats stats = entriesToDismiss.get(i).second; NotificationEntry entry = entriesToDismiss.get(i).getEntry(); DismissedByUserStats stats = entriesToDismiss.get(i).getStats(); requireNonNull(stats); NotificationEntry storedEntry = mNotificationSet.get(entry.getKey()); Loading Loading @@ -343,31 +341,20 @@ public class NotifCollection implements Dumpable, PipelineDumpable { dispatchEventsAndRebuildList("dismissNotifications"); } private List<Pair<NotificationEntry, DismissedByUserStats>> includeSummariesToDismiss( List<Pair<NotificationEntry, DismissedByUserStats>> entriesToDismiss) { private List<EntryWithDismissStats> includeSummariesToDismiss( List<EntryWithDismissStats> entriesToDismiss) { final HashSet<NotificationEntry> entriesSet = new HashSet<>(entriesToDismiss.size()); for (Pair<NotificationEntry, DismissedByUserStats> entryToStats : entriesToDismiss) { entriesSet.add(entryToStats.first); for (EntryWithDismissStats entryToStats : entriesToDismiss) { entriesSet.add(entryToStats.getEntry()); } final List<Pair<NotificationEntry, DismissedByUserStats>> entriesPlusSummaries = final List<EntryWithDismissStats> entriesPlusSummaries = new ArrayList<>(entriesToDismiss.size() + 1); for (Pair<NotificationEntry, DismissedByUserStats> entryToStats : entriesToDismiss) { for (EntryWithDismissStats entryToStats : entriesToDismiss) { entriesPlusSummaries.add(entryToStats); NotificationEntry summary = fetchSummaryToDismiss(entryToStats.first); NotificationEntry summary = fetchSummaryToDismiss(entryToStats.getEntry()); if (summary != null && !entriesSet.contains(summary)) { DismissedByUserStats currentStats = entryToStats.second; NotificationVisibility summaryVisibility = NotificationVisibility.obtain( summary.getKey(), summary.getRanking().getRank(), currentStats.notificationVisibility.count, /* visible= */ false); DismissedByUserStats summaryStats = new DismissedByUserStats( currentStats.dismissalSurface, currentStats.dismissalSentiment, summaryVisibility ); entriesPlusSummaries.add(new Pair<>(summary, summaryStats)); entriesPlusSummaries.add(entryToStats.copyForEntry(summary)); } } return entriesPlusSummaries; Loading @@ -379,7 +366,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { public void dismissNotification( NotificationEntry entry, @NonNull DismissedByUserStats stats) { dismissNotifications(List.of(new Pair<>(entry, stats))); dismissNotifications(List.of(new EntryWithDismissStats(entry, stats))); } /** Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +3 −3 Original line number Diff line number Diff line Loading @@ -43,7 +43,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.Pair; import android.util.Property; import android.view.Display; import android.view.MotionEvent; Loading Loading @@ -105,6 +104,7 @@ import com.android.systemui.statusbar.notification.HeadsUpTouchHelper.HeadsUpNot import com.android.systemui.statusbar.notification.LaunchAnimationParameters; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.collection.EntryWithDismissStats; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; Loading Loading @@ -1777,12 +1777,12 @@ public class NotificationStackScrollLayoutController implements Dumpable { mNotifCollection.dismissAllNotifications( mLockscreenUserManager.getCurrentUserId()); } else { final List<Pair<NotificationEntry, DismissedByUserStats>> final List<EntryWithDismissStats> entriesWithRowsDismissedFromShade = new ArrayList<>(); for (ExpandableNotificationRow row : viewsToRemove) { final NotificationEntry entry = row.getEntry(); entriesWithRowsDismissedFromShade.add( new Pair<>(entry, getDismissedByUserStats(entry))); new EntryWithDismissStats(entry, getDismissedByUserStats(entry))); } mNotifCollection.dismissNotifications(entriesWithRowsDismissedFromShade); } Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java +14 −11 Original line number Diff line number Diff line Loading @@ -72,7 +72,6 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Pair; import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; Loading Loading @@ -1292,8 +1291,8 @@ public class NotifCollectionTest extends SysuiTestCase { // WHEN both notifications are manually dismissed together mCollection.dismissNotifications( List.of(new Pair<>(entry1, defaultStats(entry1)), new Pair<>(entry2, defaultStats(entry2)))); List.of(entryWithDefaultStats(entry1), entryWithDefaultStats(entry2))); // THEN build list is only called one time verifyBuiltList(List.of(entry1, entry2)); Loading @@ -1311,8 +1310,8 @@ public class NotifCollectionTest extends SysuiTestCase { DismissedByUserStats stats1 = defaultStats(entry1); DismissedByUserStats stats2 = defaultStats(entry2); mCollection.dismissNotifications( List.of(new Pair<>(entry1, defaultStats(entry1)), new Pair<>(entry2, defaultStats(entry2)))); List.of(entryWithDefaultStats(entry1), entryWithDefaultStats(entry2))); // THEN we send the dismissals to system server FakeExecutor.exhaustExecutors(mBgExecutor); Loading Loading @@ -1343,8 +1342,8 @@ public class NotifCollectionTest extends SysuiTestCase { // WHEN both notifications are manually dismissed together mCollection.dismissNotifications( List.of(new Pair<>(entry1, defaultStats(entry1)), new Pair<>(entry2, defaultStats(entry2)))); List.of(entryWithDefaultStats(entry1), entryWithDefaultStats(entry2))); // THEN the entries are marked as dismissed assertEquals(DISMISSED, entry1.getDismissState()); Loading @@ -1368,8 +1367,8 @@ public class NotifCollectionTest extends SysuiTestCase { // WHEN both notifications are manually dismissed together mCollection.dismissNotifications( List.of(new Pair<>(entry1, defaultStats(entry1)), new Pair<>(entry2, defaultStats(entry2)))); List.of(entryWithDefaultStats(entry1), entryWithDefaultStats(entry2))); // THEN all interceptors get checked verify(mInterceptor1).shouldInterceptDismissal(entry1); Loading Loading @@ -1409,8 +1408,8 @@ public class NotifCollectionTest extends SysuiTestCase { // WHEN one child from each group are manually dismissed together mCollection.dismissNotifications( List.of(new Pair<>(entry1child, defaultStats(entry1child)), new Pair<>(entry2child1, defaultStats(entry2child1)))); List.of(entryWithDefaultStats(entry1child), entryWithDefaultStats(entry2child1))); // THEN the summary for the singleton child is dismissed, but not the other summary verify(mInterceptor1).shouldInterceptDismissal(entry1summary); Loading Loading @@ -1806,6 +1805,10 @@ public class NotifCollectionTest extends SysuiTestCase { NotificationVisibility.obtain(entry.getKey(), 7, 2, true)); } private static EntryWithDismissStats entryWithDefaultStats(NotificationEntry entry) { return new EntryWithDismissStats(entry, defaultStats(entry)); } private CollectionEvent postNotif(NotificationEntryBuilder builder) { clearInvocations(mCollectionListener); NotifEvent rawEvent = mNoMan.postNotif(builder); Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryWithDismissStats.kt 0 → 100644 +46 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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 import com.android.internal.statusbar.NotificationVisibility import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats /** * A holder class for a [NotificationEntry] and an associated [DismissedByUserStats], used by * [NotifCollection] for handling dismissal. */ data class EntryWithDismissStats(val entry: NotificationEntry, val stats: DismissedByUserStats) { /** * Creates deep a copy of this object, but with the entry, key and rank updated to correspond to * the given entry. */ fun copyForEntry(newEntry: NotificationEntry) = EntryWithDismissStats( entry = newEntry, stats = DismissedByUserStats( stats.dismissalSurface, stats.dismissalSentiment, NotificationVisibility.obtain( newEntry.key, newEntry.ranking.rank, stats.notificationVisibility.count, /* visible= */ false, ), ), ) }
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +12 −25 Original line number Diff line number Diff line Loading @@ -63,14 +63,12 @@ import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; Loading Loading @@ -276,7 +274,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { * Dismisses multiple notifications on behalf of the user. */ public void dismissNotifications( List<Pair<NotificationEntry, DismissedByUserStats>> entriesToDismiss) { List<EntryWithDismissStats> entriesToDismiss) { Assert.isMainThread(); checkForReentrantCall(); Loading @@ -287,8 +285,8 @@ public class NotifCollection implements Dumpable, PipelineDumpable { final int entryCount = entriesToDismiss.size(); final List<NotificationEntry> entriesToLocallyDismiss = new ArrayList<>(); for (int i = 0; i < entriesToDismiss.size(); i++) { NotificationEntry entry = entriesToDismiss.get(i).first; DismissedByUserStats stats = entriesToDismiss.get(i).second; NotificationEntry entry = entriesToDismiss.get(i).getEntry(); DismissedByUserStats stats = entriesToDismiss.get(i).getStats(); requireNonNull(stats); NotificationEntry storedEntry = mNotificationSet.get(entry.getKey()); Loading Loading @@ -343,31 +341,20 @@ public class NotifCollection implements Dumpable, PipelineDumpable { dispatchEventsAndRebuildList("dismissNotifications"); } private List<Pair<NotificationEntry, DismissedByUserStats>> includeSummariesToDismiss( List<Pair<NotificationEntry, DismissedByUserStats>> entriesToDismiss) { private List<EntryWithDismissStats> includeSummariesToDismiss( List<EntryWithDismissStats> entriesToDismiss) { final HashSet<NotificationEntry> entriesSet = new HashSet<>(entriesToDismiss.size()); for (Pair<NotificationEntry, DismissedByUserStats> entryToStats : entriesToDismiss) { entriesSet.add(entryToStats.first); for (EntryWithDismissStats entryToStats : entriesToDismiss) { entriesSet.add(entryToStats.getEntry()); } final List<Pair<NotificationEntry, DismissedByUserStats>> entriesPlusSummaries = final List<EntryWithDismissStats> entriesPlusSummaries = new ArrayList<>(entriesToDismiss.size() + 1); for (Pair<NotificationEntry, DismissedByUserStats> entryToStats : entriesToDismiss) { for (EntryWithDismissStats entryToStats : entriesToDismiss) { entriesPlusSummaries.add(entryToStats); NotificationEntry summary = fetchSummaryToDismiss(entryToStats.first); NotificationEntry summary = fetchSummaryToDismiss(entryToStats.getEntry()); if (summary != null && !entriesSet.contains(summary)) { DismissedByUserStats currentStats = entryToStats.second; NotificationVisibility summaryVisibility = NotificationVisibility.obtain( summary.getKey(), summary.getRanking().getRank(), currentStats.notificationVisibility.count, /* visible= */ false); DismissedByUserStats summaryStats = new DismissedByUserStats( currentStats.dismissalSurface, currentStats.dismissalSentiment, summaryVisibility ); entriesPlusSummaries.add(new Pair<>(summary, summaryStats)); entriesPlusSummaries.add(entryToStats.copyForEntry(summary)); } } return entriesPlusSummaries; Loading @@ -379,7 +366,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { public void dismissNotification( NotificationEntry entry, @NonNull DismissedByUserStats stats) { dismissNotifications(List.of(new Pair<>(entry, stats))); dismissNotifications(List.of(new EntryWithDismissStats(entry, stats))); } /** Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +3 −3 Original line number Diff line number Diff line Loading @@ -43,7 +43,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.Pair; import android.util.Property; import android.view.Display; import android.view.MotionEvent; Loading Loading @@ -105,6 +104,7 @@ import com.android.systemui.statusbar.notification.HeadsUpTouchHelper.HeadsUpNot import com.android.systemui.statusbar.notification.LaunchAnimationParameters; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.collection.EntryWithDismissStats; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; Loading Loading @@ -1777,12 +1777,12 @@ public class NotificationStackScrollLayoutController implements Dumpable { mNotifCollection.dismissAllNotifications( mLockscreenUserManager.getCurrentUserId()); } else { final List<Pair<NotificationEntry, DismissedByUserStats>> final List<EntryWithDismissStats> entriesWithRowsDismissedFromShade = new ArrayList<>(); for (ExpandableNotificationRow row : viewsToRemove) { final NotificationEntry entry = row.getEntry(); entriesWithRowsDismissedFromShade.add( new Pair<>(entry, getDismissedByUserStats(entry))); new EntryWithDismissStats(entry, getDismissedByUserStats(entry))); } mNotifCollection.dismissNotifications(entriesWithRowsDismissedFromShade); } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java +14 −11 Original line number Diff line number Diff line Loading @@ -72,7 +72,6 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Pair; import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; Loading Loading @@ -1292,8 +1291,8 @@ public class NotifCollectionTest extends SysuiTestCase { // WHEN both notifications are manually dismissed together mCollection.dismissNotifications( List.of(new Pair<>(entry1, defaultStats(entry1)), new Pair<>(entry2, defaultStats(entry2)))); List.of(entryWithDefaultStats(entry1), entryWithDefaultStats(entry2))); // THEN build list is only called one time verifyBuiltList(List.of(entry1, entry2)); Loading @@ -1311,8 +1310,8 @@ public class NotifCollectionTest extends SysuiTestCase { DismissedByUserStats stats1 = defaultStats(entry1); DismissedByUserStats stats2 = defaultStats(entry2); mCollection.dismissNotifications( List.of(new Pair<>(entry1, defaultStats(entry1)), new Pair<>(entry2, defaultStats(entry2)))); List.of(entryWithDefaultStats(entry1), entryWithDefaultStats(entry2))); // THEN we send the dismissals to system server FakeExecutor.exhaustExecutors(mBgExecutor); Loading Loading @@ -1343,8 +1342,8 @@ public class NotifCollectionTest extends SysuiTestCase { // WHEN both notifications are manually dismissed together mCollection.dismissNotifications( List.of(new Pair<>(entry1, defaultStats(entry1)), new Pair<>(entry2, defaultStats(entry2)))); List.of(entryWithDefaultStats(entry1), entryWithDefaultStats(entry2))); // THEN the entries are marked as dismissed assertEquals(DISMISSED, entry1.getDismissState()); Loading @@ -1368,8 +1367,8 @@ public class NotifCollectionTest extends SysuiTestCase { // WHEN both notifications are manually dismissed together mCollection.dismissNotifications( List.of(new Pair<>(entry1, defaultStats(entry1)), new Pair<>(entry2, defaultStats(entry2)))); List.of(entryWithDefaultStats(entry1), entryWithDefaultStats(entry2))); // THEN all interceptors get checked verify(mInterceptor1).shouldInterceptDismissal(entry1); Loading Loading @@ -1409,8 +1408,8 @@ public class NotifCollectionTest extends SysuiTestCase { // WHEN one child from each group are manually dismissed together mCollection.dismissNotifications( List.of(new Pair<>(entry1child, defaultStats(entry1child)), new Pair<>(entry2child1, defaultStats(entry2child1)))); List.of(entryWithDefaultStats(entry1child), entryWithDefaultStats(entry2child1))); // THEN the summary for the singleton child is dismissed, but not the other summary verify(mInterceptor1).shouldInterceptDismissal(entry1summary); Loading Loading @@ -1806,6 +1805,10 @@ public class NotifCollectionTest extends SysuiTestCase { NotificationVisibility.obtain(entry.getKey(), 7, 2, true)); } private static EntryWithDismissStats entryWithDefaultStats(NotificationEntry entry) { return new EntryWithDismissStats(entry, defaultStats(entry)); } private CollectionEvent postNotif(NotificationEntryBuilder builder) { clearInvocations(mCollectionListener); NotifEvent rawEvent = mNoMan.postNotif(builder); Loading