Loading services/core/java/com/android/server/notification/NotificationManagerService.java +23 −3 Original line number Diff line number Diff line Loading @@ -828,6 +828,22 @@ public class NotificationManagerService extends SystemService { } } // Removes all notifications with the specified user & package. public void removePackageNotifications(String pkg, @UserIdInt int userId) { synchronized (mBufferLock) { Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator(); while (bufferIter.hasNext()) { final Pair<StatusBarNotification, Integer> pair = bufferIter.next(); if (pair.first != null && userId == pair.first.getNormalizedUserId() && pkg != null && pkg.equals(pair.first.getPackageName()) && pair.first.getNotification() != null) { bufferIter.remove(); } } } } void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) { synchronized (mBufferLock) { Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator(); Loading Loading @@ -1902,7 +1918,6 @@ public class NotificationManagerService extends SystemService { unhideNotificationsForPackages(pkgList, uidList); } } mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList); } } Loading Loading @@ -4216,7 +4231,8 @@ public class NotificationManagerService extends SystemService { boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel( pkg, callingUid, channelId, callingUid, isSystemOrSystemUi); if (previouslyExisted) { // Remove from both recent notification archive and notification history // Remove from both recent notification archive (recently dismissed notifications) // and notification history mArchive.removeChannelNotifications(pkg, callingUser, channelId); mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId); mListeners.notifyNotificationChannelChanged(pkg, Loading Loading @@ -9418,7 +9434,11 @@ public class NotificationManagerService extends SystemService { for (int i = 0; i < size; i++) { final String pkg = pkgList[i]; final int uid = uidList[i]; mHistoryManager.onPackageRemoved(UserHandle.getUserId(uid), pkg); final int userHandle = UserHandle.getUserId(uid); // Removes this package's notifications from both recent notification archive // (recently dismissed notifications) and notification history. mArchive.removePackageNotifications(pkg, userHandle); mHistoryManager.onPackageRemoved(userHandle, pkg); } } if (preferencesChanged) { Loading services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static org.mockito.Mockito.when; import android.app.Notification; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.flag.junit.SetFlagsRule; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; Loading @@ -39,6 +40,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.UiServiceTestCase; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; Loading @@ -55,6 +57,9 @@ import java.util.concurrent.atomic.AtomicBoolean; @SmallTest @RunWith(AndroidJUnit4.class) public class ArchiveTest extends UiServiceTestCase { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private static final int SIZE = 5; private NotificationManagerService.Archive mArchive; Loading Loading @@ -249,4 +254,29 @@ public class ArchiveTest extends UiServiceTestCase { assertThat(expected).contains(sbn.getKey()); } } @Test public void testRemoveNotificationsByPackage() { List<String> expected = new ArrayList<>(); StatusBarNotification sbn_remove = getNotification("pkg_remove", 0, UserHandle.of(USER_CURRENT)); mArchive.record(sbn_remove, REASON_CANCEL); StatusBarNotification sbn_keep = getNotification("pkg_keep", 1, UserHandle.of(USER_CURRENT)); mArchive.record(sbn_keep, REASON_CANCEL); expected.add(sbn_keep.getKey()); StatusBarNotification sbn_remove2 = getNotification("pkg_remove", 2, UserHandle.of(USER_CURRENT)); mArchive.record(sbn_remove2, REASON_CANCEL); mArchive.removePackageNotifications("pkg_remove", USER_CURRENT); List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true)); assertThat(actual).hasSize(expected.size()); for (StatusBarNotification sbn : actual) { assertThat(expected).contains(sbn.getKey()); } } } services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +68 −2 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Build.VERSION_CODES.O_MR1; import static android.os.Build.VERSION_CODES.P; import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE; import static android.os.PowerManager.PARTIAL_WAKE_LOCK; import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE; import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; Loading @@ -72,7 +73,6 @@ import static android.os.UserHandle.USER_SYSTEM; import static android.os.UserManager.USER_TYPE_FULL_SECONDARY; import static android.os.UserManager.USER_TYPE_PROFILE_CLONE; import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED; import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE; import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; import static android.service.notification.Adjustment.KEY_IMPORTANCE; import static android.service.notification.Adjustment.KEY_USER_SENTIMENT; Loading Loading @@ -307,7 +307,6 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; @SmallTest @RunWith(AndroidTestingRunner.class) @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service. Loading Loading @@ -813,6 +812,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mPackageIntentReceiver.onReceive(getContext(), intent); } private void simulatePackageRemovedBroadcast(String pkg, int uid) { // mimics receive broadcast that package is removed, but doesn't remove the package. final Bundle extras = new Bundle(); extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, new String[]{pkg}); extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid}); final Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); intent.setData(Uri.parse("package:" + pkg)); intent.putExtras(extras); mPackageIntentReceiver.onReceive(getContext(), intent); } private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) { // mimics receive broadcast that package is (un)distracting // but does not actually register that info with packagemanager Loading Loading @@ -878,6 +891,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mTestNotificationChannel.setAllowBubbles(channelEnabled); } private void setUpPrefsForHistory(int uid, boolean globalEnabled) { // Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, uid); // Sets NOTIFICATION_HISTORY_ENABLED setting for uid 0 Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0); // Forces an update by calling observe on mSettingsObserver, which picks up the settings // changes above. mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); assertEquals(globalEnabled, Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0 /* =def */, uid) != 0); } private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) { Notification.Builder nb = new Notification.Builder(mContext, "a") .setContentTitle("foo") Loading Loading @@ -9830,6 +9859,43 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[1]), pkgs[1]); } @Test public void testHandleOnPackageRemoved_ClearsHistory() throws RemoteException { // Enables Notification History setting setUpPrefsForHistory(mUid, true /* =enabled */); // Posts a notification to the mTestNotificationChannel. final NotificationRecord notif = generateNotificationRecord( mTestNotificationChannel, 1, null, false); mService.addNotification(notif); StatusBarNotification[] notifs = mBinderService.getActiveNotifications( notif.getSbn().getPackageName()); assertEquals(1, notifs.length); // Cancels all notifications. mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0, notif.getUserId(), REASON_CANCEL); waitForIdle(); notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); assertEquals(0, notifs.length); // Checks that notification history's recently canceled archive contains the notification. notifs = mBinderService.getHistoricalNotificationsWithAttribution(PKG, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */); waitForIdle(); assertEquals(1, notifs.length); // Remove sthe package that contained the channel simulatePackageRemovedBroadcast(PKG, mUid); waitForIdle(); // Checks that notification history no longer contains the notification. notifs = mBinderService.getHistoricalNotificationsWithAttribution( PKG, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */); waitForIdle(); assertEquals(0, notifs.length); } @Test public void testNotificationHistory_addNoisyNotification() throws Exception { NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +23 −3 Original line number Diff line number Diff line Loading @@ -828,6 +828,22 @@ public class NotificationManagerService extends SystemService { } } // Removes all notifications with the specified user & package. public void removePackageNotifications(String pkg, @UserIdInt int userId) { synchronized (mBufferLock) { Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator(); while (bufferIter.hasNext()) { final Pair<StatusBarNotification, Integer> pair = bufferIter.next(); if (pair.first != null && userId == pair.first.getNormalizedUserId() && pkg != null && pkg.equals(pair.first.getPackageName()) && pair.first.getNotification() != null) { bufferIter.remove(); } } } } void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) { synchronized (mBufferLock) { Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator(); Loading Loading @@ -1902,7 +1918,6 @@ public class NotificationManagerService extends SystemService { unhideNotificationsForPackages(pkgList, uidList); } } mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList); } } Loading Loading @@ -4216,7 +4231,8 @@ public class NotificationManagerService extends SystemService { boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel( pkg, callingUid, channelId, callingUid, isSystemOrSystemUi); if (previouslyExisted) { // Remove from both recent notification archive and notification history // Remove from both recent notification archive (recently dismissed notifications) // and notification history mArchive.removeChannelNotifications(pkg, callingUser, channelId); mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId); mListeners.notifyNotificationChannelChanged(pkg, Loading Loading @@ -9418,7 +9434,11 @@ public class NotificationManagerService extends SystemService { for (int i = 0; i < size; i++) { final String pkg = pkgList[i]; final int uid = uidList[i]; mHistoryManager.onPackageRemoved(UserHandle.getUserId(uid), pkg); final int userHandle = UserHandle.getUserId(uid); // Removes this package's notifications from both recent notification archive // (recently dismissed notifications) and notification history. mArchive.removePackageNotifications(pkg, userHandle); mHistoryManager.onPackageRemoved(userHandle, pkg); } } if (preferencesChanged) { Loading
services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static org.mockito.Mockito.when; import android.app.Notification; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.flag.junit.SetFlagsRule; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; Loading @@ -39,6 +40,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.UiServiceTestCase; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; Loading @@ -55,6 +57,9 @@ import java.util.concurrent.atomic.AtomicBoolean; @SmallTest @RunWith(AndroidJUnit4.class) public class ArchiveTest extends UiServiceTestCase { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private static final int SIZE = 5; private NotificationManagerService.Archive mArchive; Loading Loading @@ -249,4 +254,29 @@ public class ArchiveTest extends UiServiceTestCase { assertThat(expected).contains(sbn.getKey()); } } @Test public void testRemoveNotificationsByPackage() { List<String> expected = new ArrayList<>(); StatusBarNotification sbn_remove = getNotification("pkg_remove", 0, UserHandle.of(USER_CURRENT)); mArchive.record(sbn_remove, REASON_CANCEL); StatusBarNotification sbn_keep = getNotification("pkg_keep", 1, UserHandle.of(USER_CURRENT)); mArchive.record(sbn_keep, REASON_CANCEL); expected.add(sbn_keep.getKey()); StatusBarNotification sbn_remove2 = getNotification("pkg_remove", 2, UserHandle.of(USER_CURRENT)); mArchive.record(sbn_remove2, REASON_CANCEL); mArchive.removePackageNotifications("pkg_remove", USER_CURRENT); List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true)); assertThat(actual).hasSize(expected.size()); for (StatusBarNotification sbn : actual) { assertThat(expected).contains(sbn.getKey()); } } }
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +68 −2 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Build.VERSION_CODES.O_MR1; import static android.os.Build.VERSION_CODES.P; import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE; import static android.os.PowerManager.PARTIAL_WAKE_LOCK; import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE; import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; Loading @@ -72,7 +73,6 @@ import static android.os.UserHandle.USER_SYSTEM; import static android.os.UserManager.USER_TYPE_FULL_SECONDARY; import static android.os.UserManager.USER_TYPE_PROFILE_CLONE; import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED; import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE; import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; import static android.service.notification.Adjustment.KEY_IMPORTANCE; import static android.service.notification.Adjustment.KEY_USER_SENTIMENT; Loading Loading @@ -307,7 +307,6 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; @SmallTest @RunWith(AndroidTestingRunner.class) @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service. Loading Loading @@ -813,6 +812,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mPackageIntentReceiver.onReceive(getContext(), intent); } private void simulatePackageRemovedBroadcast(String pkg, int uid) { // mimics receive broadcast that package is removed, but doesn't remove the package. final Bundle extras = new Bundle(); extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, new String[]{pkg}); extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid}); final Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); intent.setData(Uri.parse("package:" + pkg)); intent.putExtras(extras); mPackageIntentReceiver.onReceive(getContext(), intent); } private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) { // mimics receive broadcast that package is (un)distracting // but does not actually register that info with packagemanager Loading Loading @@ -878,6 +891,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mTestNotificationChannel.setAllowBubbles(channelEnabled); } private void setUpPrefsForHistory(int uid, boolean globalEnabled) { // Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, uid); // Sets NOTIFICATION_HISTORY_ENABLED setting for uid 0 Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0); // Forces an update by calling observe on mSettingsObserver, which picks up the settings // changes above. mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); assertEquals(globalEnabled, Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0 /* =def */, uid) != 0); } private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) { Notification.Builder nb = new Notification.Builder(mContext, "a") .setContentTitle("foo") Loading Loading @@ -9830,6 +9859,43 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[1]), pkgs[1]); } @Test public void testHandleOnPackageRemoved_ClearsHistory() throws RemoteException { // Enables Notification History setting setUpPrefsForHistory(mUid, true /* =enabled */); // Posts a notification to the mTestNotificationChannel. final NotificationRecord notif = generateNotificationRecord( mTestNotificationChannel, 1, null, false); mService.addNotification(notif); StatusBarNotification[] notifs = mBinderService.getActiveNotifications( notif.getSbn().getPackageName()); assertEquals(1, notifs.length); // Cancels all notifications. mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0, notif.getUserId(), REASON_CANCEL); waitForIdle(); notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); assertEquals(0, notifs.length); // Checks that notification history's recently canceled archive contains the notification. notifs = mBinderService.getHistoricalNotificationsWithAttribution(PKG, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */); waitForIdle(); assertEquals(1, notifs.length); // Remove sthe package that contained the channel simulatePackageRemovedBroadcast(PKG, mUid); waitForIdle(); // Checks that notification history no longer contains the notification. notifs = mBinderService.getHistoricalNotificationsWithAttribution( PKG, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */); waitForIdle(); assertEquals(0, notifs.length); } @Test public void testNotificationHistory_addNoisyNotification() throws Exception { NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, Loading