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

Commit ac171dec authored by Matías Hernández's avatar Matías Hernández
Browse files

Send DND related broadcasts to the correct destinations

Previously, broadcasts such as ACTION_INTERRUPTION_FILTER_CHANGED were sent to every ConditionProvider package for all started users, even if the package had DND Access only for some subset of them. Now, they are sent only to the profiles of the current user, and only to the packages that have such access.

Fixes: 270338618
Test: New unit tests + manual verification
Change-Id: I4909a76a1f160eb5fb0be734a170982ffd2c0a69
parent 6cab17b4
Loading
Loading
Loading
Loading
+1 −19
Original line number Original line Diff line number Diff line
@@ -892,6 +892,7 @@ abstract public class ManagedServices {
        return allowedComponents;
        return allowedComponents;
    }
    }


    @NonNull
    protected List<String> getAllowedPackages(int userId) {
    protected List<String> getAllowedPackages(int userId) {
        final List<String> allowedPackages = new ArrayList<>();
        final List<String> allowedPackages = new ArrayList<>();
        synchronized (mApproved) {
        synchronized (mApproved) {
@@ -1181,25 +1182,6 @@ abstract public class ManagedServices {
        return installed;
        return installed;
    }
    }


    protected Set<String> getAllowedPackages() {
        final Set<String> allowedPackages = new ArraySet<>();
        synchronized (mApproved) {
            for (int k = 0; k < mApproved.size(); k++) {
                ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
                for (int i = 0; i < allowedByType.size(); i++) {
                    final ArraySet<String> allowed = allowedByType.valueAt(i);
                    for (int j = 0; j < allowed.size(); j++) {
                        String pkgName = getPackageName(allowed.valueAt(j));
                        if (!TextUtils.isEmpty(pkgName)) {
                            allowedPackages.add(pkgName);
                        }
                    }
                }
            }
        }
        return allowedPackages;
    }

    private void trimApprovedListsAccordingToInstalledServices(int userId) {
    private void trimApprovedListsAccordingToInstalledServices(int userId) {
        synchronized (mApproved) {
        synchronized (mApproved) {
            final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
            final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+11 −9
Original line number Original line Diff line number Diff line
@@ -2709,16 +2709,18 @@ public class NotificationManagerService extends SystemService {
    }
    }
    private void sendRegisteredOnlyBroadcast(String action) {
    private void sendRegisteredOnlyBroadcast(String action) {
        Intent intent = new Intent(action);
        int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true);
        getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
        Intent intent = new Intent(action).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                UserHandle.ALL, null);
        for (int userId : userIds) {
            getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null);
        }
        // explicitly send the broadcast to all DND packages, even if they aren't currently running
        // explicitly send the broadcast to all DND packages, even if they aren't currently running
        intent.setFlags(0);
        for (int userId : userIds) {
        final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages();
            for (String pkg : mConditionProviders.getAllowedPackages(userId)) {
        for (String pkg : dndApprovedPackages) {
                Intent pkgIntent = new Intent(action).setPackage(pkg).setFlags(
            intent.setPackage(pkg);
                        Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId));
            getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
            }
        }
        }
    }
    }
+7 −47
Original line number Original line Diff line number Diff line
@@ -24,6 +24,8 @@ import static android.service.notification.NotificationListenerService.META_DATA
import static com.android.server.notification.ManagedServices.APPROVAL_BY_COMPONENT;
import static com.android.server.notification.ManagedServices.APPROVAL_BY_COMPONENT;
import static com.android.server.notification.ManagedServices.APPROVAL_BY_PACKAGE;
import static com.android.server.notification.ManagedServices.APPROVAL_BY_PACKAGE;


import static com.google.common.truth.Truth.assertThat;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNotNull;
@@ -1201,28 +1203,11 @@ public class ManagedServicesTest extends UiServiceTestCase {
                    mIpm, approvalLevel);
                    mIpm, approvalLevel);
            loadXml(service);
            loadXml(service);


            List<String> allowedPackagesForUser0 = new ArrayList<>();
            assertThat(service.getAllowedPackages(0)).containsExactly("this.is.a.package.name",
            allowedPackagesForUser0.add("this.is.a.package.name");
                    "another.package", "secondary");
            allowedPackagesForUser0.add("another.package");
            assertThat(service.getAllowedPackages(10)).containsExactly("this.is.another.package",
            allowedPackagesForUser0.add("secondary");
                    "package", "this.is.another.package", "component");

            assertThat(service.getAllowedPackages(999)).isEmpty();
            List<String> actual = service.getAllowedPackages(0);
            assertEquals(3, actual.size());
            for (String pkg : allowedPackagesForUser0) {
                assertTrue(actual.contains(pkg));
            }

            List<String> allowedPackagesForUser10 = new ArrayList<>();
            allowedPackagesForUser10.add("this.is.another.package");
            allowedPackagesForUser10.add("package");
            allowedPackagesForUser10.add("this.is.another.package");
            allowedPackagesForUser10.add("component");

            actual = service.getAllowedPackages(10);
            assertEquals(4, actual.size());
            for (String pkg : allowedPackagesForUser10) {
                assertTrue(actual.contains(pkg));
            }
        }
        }
    }
    }


@@ -1262,31 +1247,6 @@ public class ManagedServicesTest extends UiServiceTestCase {
        assertEquals(0, service.getAllowedComponents(10).size());
        assertEquals(0, service.getAllowedComponents(10).size());
    }
    }


    @Test
    public void testGetAllowedPackages() throws Exception {
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                mIpm, APPROVAL_BY_COMPONENT);
        loadXml(service);
        service.mApprovalLevel = APPROVAL_BY_PACKAGE;
        loadXml(service);

        List<String> allowedPackages = new ArrayList<>();
        allowedPackages.add("this.is.a.package.name");
        allowedPackages.add("another.package");
        allowedPackages.add("secondary");
        allowedPackages.add("this.is.another.package");
        allowedPackages.add("package");
        allowedPackages.add("component");
        allowedPackages.add("bananas!");
        allowedPackages.add("non.user.set.package");

        Set<String> actual = service.getAllowedPackages();
        assertEquals(allowedPackages.size(), actual.size());
        for (String pkg : allowedPackages) {
            assertTrue(actual.contains(pkg));
        }
    }

    @Test
    @Test
    public void testOnUserRemoved() throws Exception {
    public void testOnUserRemoved() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
+75 −1
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_ONGOING_EVENT;
import static android.app.Notification.FLAG_ONGOING_EVENT;
import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
@@ -50,7 +51,6 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;

import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
@@ -237,6 +237,7 @@ import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal;


import com.google.android.collect.Lists;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList;


import org.junit.After;
import org.junit.After;
@@ -245,10 +246,13 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.ArgumentMatchers;
import org.mockito.InOrder;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.Answer;


import java.io.BufferedInputStream;
import java.io.BufferedInputStream;
@@ -440,6 +444,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
        mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
        mContext.addMockSystemService(NotificationManager.class, mMockNm);
        mContext.addMockSystemService(NotificationManager.class, mMockNm);


        doNothing().when(mContext).sendBroadcastAsUser(any(), any());
        doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
        doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());


        setDpmAppOppsExemptFromDismissal(false);
        setDpmAppOppsExemptFromDismissal(false);
@@ -7827,6 +7832,75 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                eq("another.package"), eq(rule), anyString());
                eq("another.package"), eq(rule), anyString());
    }
    }


    @Test
    public void onZenModeChanged_sendsBroadcasts() throws Exception {
        when(mAmi.getCurrentUserId()).thenReturn(100);
        when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102});
        when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() {
            @Override
            public List<String> answer(InvocationOnMock invocation) {
                int userId = invocation.getArgument(0);
                switch (userId) {
                    case 100:
                        return Lists.newArrayList("a", "b", "c");
                    case 101:
                        return Lists.newArrayList();
                    case 102:
                        return Lists.newArrayList("b");
                    default:
                        throw new IllegalArgumentException(
                                "Why would you ask for packages of userId " + userId + "?");
                }
            }
        });

        mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null,
                "testing!");
        waitForIdle();

        InOrder inOrder = inOrder(mContext);
        // Verify broadcasts for registered receivers
        inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
                new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
                        Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(100)), eq(null));
        inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
                new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
                        Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(101)), eq(null));
        inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(
                new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags(
                        Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(102)), eq(null));

        // Verify broadcast for packages that manage DND.
        inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
                ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("a").setFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
        inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
                ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
        inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
                ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("c").setFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100)));
        inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent(
                ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102)));
    }

    private static Intent eqIntent(Intent wanted) {
        return ArgumentMatchers.argThat(
                new ArgumentMatcher<Intent>() {
                    @Override
                    public boolean matches(Intent argument) {
                        return wanted.filterEquals(argument)
                                && wanted.getFlags() == argument.getFlags();
                    }

                    @Override
                    public String toString() {
                        return wanted.toString();
                    }
                });
    }

    @Test
    @Test
    public void testAreNotificationsEnabledForPackage() throws Exception {
    public void testAreNotificationsEnabledForPackage() throws Exception {
        mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
        mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),