Merge "Clear recent notifs in History on package removed" into main
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c2a1b6b..0492f43 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -828,6 +828,22 @@
}
}
+ // 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();
@@ -1902,7 +1918,6 @@
unhideNotificationsForPackages(pkgList, uidList);
}
}
-
mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList);
}
}
@@ -4216,7 +4231,8 @@
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,
@@ -9418,7 +9434,11 @@
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) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
index 4b6183d..8bc027d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
@@ -31,6 +31,7 @@
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;
@@ -39,6 +40,7 @@
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;
@@ -55,6 +57,9 @@
@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;
@@ -249,4 +254,29 @@
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());
+ }
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a47fbce..b45dcd4 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -65,6 +65,7 @@
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;
@@ -72,7 +73,6 @@
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;
@@ -307,7 +307,6 @@
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.
@@ -813,6 +812,20 @@
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
@@ -878,6 +891,22 @@
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")
@@ -9831,6 +9860,43 @@
}
@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,
null /* tvExtender */);