Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28578810 authored by Alexander Roederer's avatar Alexander Roederer
Browse files

Adds bulk getChannelsBypassingDnd call to NMS

To generate the summary of apps bypassing Dnd, we need to check every
app and every notification channel. To save on binder calls, we add a
bulk method that returns the names of the apps that bypass.

Bug: 308819928
Test: atest NotificationManagerServiceTest
Flag: android.app.modes_ui
Change-Id: Ibf1c029768c83deb8787e3b560c6a105e97483a1
parent 7fdd622a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+29 −0
Original line number Diff line number Diff line
@@ -224,6 +224,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;
@@ -4534,6 +4535,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()) {
+122 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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