Loading core/java/android/app/INotificationManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -122,6 +122,7 @@ interface INotificationManager boolean onlyHasDefaultChannel(String pkg, int uid); boolean areChannelsBypassingDnd(); ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int uid); List<String> getPackagesBypassingDnd(int userId, boolean includeConversationChannels); boolean isPackagePaused(String pkg); void deleteNotificationHistoryItem(String pkg, int uid, long postedTime); boolean isPermissionFixed(String pkg, int userId); Loading services/core/java/com/android/server/notification/NotificationManagerService.java +29 −0 Original line number Diff line number Diff line Loading @@ -225,6 +225,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; Loading Loading @@ -4535,6 +4536,34 @@ public class NotificationManagerService extends SystemService { return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, uid); } @Override public List<String> getPackagesBypassingDnd(int userId, boolean includeConversationChannels) { checkCallerIsSystem(); final ArraySet<String> packageNames = new ArraySet<>(); for (int user : mUm.getProfileIds(userId, false)) { List<PackageInfo> pkgs = mPackageManagerClient.getInstalledPackagesAsUser(0, user); for (PackageInfo pi : pkgs) { String pkg = pi.packageName; // If any NotificationChannel for this package is bypassing, the // package is considered bypassing. for (NotificationChannel channel : getNotificationChannelsBypassingDnd(pkg, pi.applicationInfo.uid).getList()) { // Skips non-demoted conversation channels. if (!includeConversationChannels && !TextUtils.isEmpty(channel.getConversationId()) && !channel.isDemoted()) { continue; } packageNames.add(pkg); } } } return new ArrayList<String>(packageNames); } @Override public boolean areChannelsBypassingDnd() { if (android.app.Flags.modesApi()) { Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +122 −0 Original line number Diff line number Diff line Loading @@ -208,6 +208,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; Loading Loading @@ -12071,6 +12072,127 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(mPkg, mUid); } @Test public void testGetPackagesBypassingDnd_empty() throws RemoteException { mService.setPreferencesHelper(mPreferencesHelper); List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true); assertThat(result).isEmpty(); } @Test public void testGetPackagesBypassingDnd_excludeConversationChannels() throws RemoteException { mService.setPreferencesHelper(mPreferencesHelper); // Set packages PackageInfo pkg0 = new PackageInfo(); pkg0.packageName = "pkg0"; pkg0.applicationInfo = new ApplicationInfo(); pkg0.applicationInfo.uid = mUid; PackageInfo pkg1 = new PackageInfo(); pkg1.packageName = "pkg1"; pkg1.applicationInfo = new ApplicationInfo(); pkg1.applicationInfo.uid = mUid; PackageInfo pkg2 = new PackageInfo(); pkg2.packageName = "pkg2"; pkg2.applicationInfo = new ApplicationInfo(); pkg2.applicationInfo.uid = mUid; when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId)) .thenReturn(List.of(pkg0, pkg1, pkg2)); // Conversation channels NotificationChannel nc0 = new NotificationChannel("id0", "id0", NotificationManager.IMPORTANCE_HIGH); nc0.setConversationId("parentChannel", "conversationId"); // Demoted conversation channel NotificationChannel nc1 = new NotificationChannel("id1", "id1", NotificationManager.IMPORTANCE_HIGH); nc1.setConversationId("parentChannel", "conversationId"); nc1.setDemoted(true); // Non-conversation channels NotificationChannel nc2 = new NotificationChannel("id2", "id2", NotificationManager.IMPORTANCE_HIGH); NotificationChannel nc3 = new NotificationChannel("id3", "id3", NotificationManager.IMPORTANCE_HIGH); ParceledListSlice<NotificationChannel> pls0 = new ParceledListSlice(ImmutableList.of(nc0)); ParceledListSlice<NotificationChannel> pls1 = new ParceledListSlice(ImmutableList.of(nc1)); ParceledListSlice<NotificationChannel> pls2 = new ParceledListSlice(ImmutableList.of(nc2, nc3)); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid)) .thenReturn(pls0); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid)) .thenReturn(pls1); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid)) .thenReturn(pls2); List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, false); assertThat(result).containsExactly("pkg1", "pkg2"); } @Test public void testGetPackagesBypassingDnd_includeConversationChannels() throws RemoteException { mService.setPreferencesHelper(mPreferencesHelper); // Set packages PackageInfo pkg0 = new PackageInfo(); pkg0.packageName = "pkg0"; pkg0.applicationInfo = new ApplicationInfo(); pkg0.applicationInfo.uid = mUid; PackageInfo pkg1 = new PackageInfo(); pkg1.packageName = "pkg1"; pkg1.applicationInfo = new ApplicationInfo(); pkg1.applicationInfo.uid = mUid; PackageInfo pkg2 = new PackageInfo(); pkg2.packageName = "pkg2"; pkg2.applicationInfo = new ApplicationInfo(); pkg2.applicationInfo.uid = mUid; when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId)) .thenReturn(List.of(pkg0, pkg1, pkg2)); // Conversation channels NotificationChannel nc0 = new NotificationChannel("id0", "id0", NotificationManager.IMPORTANCE_HIGH); nc0.setConversationId("parentChannel", "conversationId"); // Demoted conversation channel NotificationChannel nc1 = new NotificationChannel("id1", "id1", NotificationManager.IMPORTANCE_HIGH); nc1.setConversationId("parentChannel", "conversationId"); nc1.setDemoted(true); // Non-conversation channels NotificationChannel nc2 = new NotificationChannel("id2", "id2", NotificationManager.IMPORTANCE_HIGH); NotificationChannel nc3 = new NotificationChannel("id3", "id3", NotificationManager.IMPORTANCE_HIGH); ParceledListSlice<NotificationChannel> pls0 = new ParceledListSlice(ImmutableList.of(nc0)); ParceledListSlice<NotificationChannel> pls1 = new ParceledListSlice(ImmutableList.of(nc1)); ParceledListSlice<NotificationChannel> pls2 = new ParceledListSlice(ImmutableList.of(nc2, nc3)); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid)) .thenReturn(pls0); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid)) .thenReturn(pls1); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid)) .thenReturn(pls2); List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true); assertThat(result).containsExactly("pkg0", "pkg1", "pkg2"); } @Test public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception { // set the testable NMS to not system uid/appid Loading
core/java/android/app/INotificationManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -122,6 +122,7 @@ interface INotificationManager boolean onlyHasDefaultChannel(String pkg, int uid); boolean areChannelsBypassingDnd(); ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int uid); List<String> getPackagesBypassingDnd(int userId, boolean includeConversationChannels); boolean isPackagePaused(String pkg); void deleteNotificationHistoryItem(String pkg, int uid, long postedTime); boolean isPermissionFixed(String pkg, int userId); Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +29 −0 Original line number Diff line number Diff line Loading @@ -225,6 +225,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; Loading Loading @@ -4535,6 +4536,34 @@ public class NotificationManagerService extends SystemService { return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, uid); } @Override public List<String> getPackagesBypassingDnd(int userId, boolean includeConversationChannels) { checkCallerIsSystem(); final ArraySet<String> packageNames = new ArraySet<>(); for (int user : mUm.getProfileIds(userId, false)) { List<PackageInfo> pkgs = mPackageManagerClient.getInstalledPackagesAsUser(0, user); for (PackageInfo pi : pkgs) { String pkg = pi.packageName; // If any NotificationChannel for this package is bypassing, the // package is considered bypassing. for (NotificationChannel channel : getNotificationChannelsBypassingDnd(pkg, pi.applicationInfo.uid).getList()) { // Skips non-demoted conversation channels. if (!includeConversationChannels && !TextUtils.isEmpty(channel.getConversationId()) && !channel.isDemoted()) { continue; } packageNames.add(pkg); } } } return new ArrayList<String>(packageNames); } @Override public boolean areChannelsBypassingDnd() { if (android.app.Flags.modesApi()) { Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +122 −0 Original line number Diff line number Diff line Loading @@ -208,6 +208,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; Loading Loading @@ -12071,6 +12072,127 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(mPkg, mUid); } @Test public void testGetPackagesBypassingDnd_empty() throws RemoteException { mService.setPreferencesHelper(mPreferencesHelper); List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true); assertThat(result).isEmpty(); } @Test public void testGetPackagesBypassingDnd_excludeConversationChannels() throws RemoteException { mService.setPreferencesHelper(mPreferencesHelper); // Set packages PackageInfo pkg0 = new PackageInfo(); pkg0.packageName = "pkg0"; pkg0.applicationInfo = new ApplicationInfo(); pkg0.applicationInfo.uid = mUid; PackageInfo pkg1 = new PackageInfo(); pkg1.packageName = "pkg1"; pkg1.applicationInfo = new ApplicationInfo(); pkg1.applicationInfo.uid = mUid; PackageInfo pkg2 = new PackageInfo(); pkg2.packageName = "pkg2"; pkg2.applicationInfo = new ApplicationInfo(); pkg2.applicationInfo.uid = mUid; when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId)) .thenReturn(List.of(pkg0, pkg1, pkg2)); // Conversation channels NotificationChannel nc0 = new NotificationChannel("id0", "id0", NotificationManager.IMPORTANCE_HIGH); nc0.setConversationId("parentChannel", "conversationId"); // Demoted conversation channel NotificationChannel nc1 = new NotificationChannel("id1", "id1", NotificationManager.IMPORTANCE_HIGH); nc1.setConversationId("parentChannel", "conversationId"); nc1.setDemoted(true); // Non-conversation channels NotificationChannel nc2 = new NotificationChannel("id2", "id2", NotificationManager.IMPORTANCE_HIGH); NotificationChannel nc3 = new NotificationChannel("id3", "id3", NotificationManager.IMPORTANCE_HIGH); ParceledListSlice<NotificationChannel> pls0 = new ParceledListSlice(ImmutableList.of(nc0)); ParceledListSlice<NotificationChannel> pls1 = new ParceledListSlice(ImmutableList.of(nc1)); ParceledListSlice<NotificationChannel> pls2 = new ParceledListSlice(ImmutableList.of(nc2, nc3)); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid)) .thenReturn(pls0); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid)) .thenReturn(pls1); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid)) .thenReturn(pls2); List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, false); assertThat(result).containsExactly("pkg1", "pkg2"); } @Test public void testGetPackagesBypassingDnd_includeConversationChannels() throws RemoteException { mService.setPreferencesHelper(mPreferencesHelper); // Set packages PackageInfo pkg0 = new PackageInfo(); pkg0.packageName = "pkg0"; pkg0.applicationInfo = new ApplicationInfo(); pkg0.applicationInfo.uid = mUid; PackageInfo pkg1 = new PackageInfo(); pkg1.packageName = "pkg1"; pkg1.applicationInfo = new ApplicationInfo(); pkg1.applicationInfo.uid = mUid; PackageInfo pkg2 = new PackageInfo(); pkg2.packageName = "pkg2"; pkg2.applicationInfo = new ApplicationInfo(); pkg2.applicationInfo.uid = mUid; when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId)) .thenReturn(List.of(pkg0, pkg1, pkg2)); // Conversation channels NotificationChannel nc0 = new NotificationChannel("id0", "id0", NotificationManager.IMPORTANCE_HIGH); nc0.setConversationId("parentChannel", "conversationId"); // Demoted conversation channel NotificationChannel nc1 = new NotificationChannel("id1", "id1", NotificationManager.IMPORTANCE_HIGH); nc1.setConversationId("parentChannel", "conversationId"); nc1.setDemoted(true); // Non-conversation channels NotificationChannel nc2 = new NotificationChannel("id2", "id2", NotificationManager.IMPORTANCE_HIGH); NotificationChannel nc3 = new NotificationChannel("id3", "id3", NotificationManager.IMPORTANCE_HIGH); ParceledListSlice<NotificationChannel> pls0 = new ParceledListSlice(ImmutableList.of(nc0)); ParceledListSlice<NotificationChannel> pls1 = new ParceledListSlice(ImmutableList.of(nc1)); ParceledListSlice<NotificationChannel> pls2 = new ParceledListSlice(ImmutableList.of(nc2, nc3)); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid)) .thenReturn(pls0); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid)) .thenReturn(pls1); when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid)) .thenReturn(pls2); List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true); assertThat(result).containsExactly("pkg0", "pkg1", "pkg2"); } @Test public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception { // set the testable NMS to not system uid/appid