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

Commit d9263306 authored by Geoffrey Pitsch's avatar Geoffrey Pitsch Committed by Android (Google) Code Review
Browse files

Merge "Delete the Default Channel when an app starts using channels."

parents 55ff64ea 1f17e024
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -3098,8 +3098,17 @@ public class NotificationManagerService extends SystemService {
        if (mIsTelevision && (new Notification.TvExtender(notification)).getChannel() != null) {
            channelId = (new Notification.TvExtender(notification)).getChannel();
        }
        final NotificationChannel channel =  mRankingHelper.getNotificationChannelWithFallback(pkg,
        final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
                notificationUid, channelId, false /* includeDeleted */);
        if (channel == null) {
            // STOPSHIP TODO: remove before release - should always throw without a valid channel.
            if (channelId == null) {
                Log.e(TAG, "Cannot post notification without channel ID when targeting O "
                        + " - notification=" + notification);
                return;
            }
            throw new IllegalArgumentException("No Channel found for notification=" + notification);
        }
        final StatusBarNotification n = new StatusBarNotification(
                pkg, opPkg, id, tag, notificationUid, callingPid, notification,
                user, null, System.currentTimeMillis());
+0 −1
Original line number Diff line number Diff line
@@ -39,7 +39,6 @@ public interface RankingConfig {
    void updateNotificationChannel(String pkg, int uid, NotificationChannel channel);
    void updateNotificationChannelFromAssistant(String pkg, int uid, NotificationChannel channel);
    NotificationChannel getNotificationChannel(String pkg, int uid, String channelId, boolean includeDeleted);
    NotificationChannel getNotificationChannelWithFallback(String pkg, int uid, String channelId, boolean includeDeleted);
    void deleteNotificationChannel(String pkg, int uid, String channelId);
    void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
    void permanentlyDeleteNotificationChannels(String pkg, int uid);
+80 −58
Original line number Diff line number Diff line
@@ -213,7 +213,11 @@ public class RankingHelper implements RankingConfig {
                            }
                        }

                        clampDefaultChannel(r);
                        try {
                            deleteDefaultChannelIfNeeded(r);
                        } catch (NameNotFoundException e) {
                            Slog.e(TAG, "deleteDefaultChannelIfNeeded - Exception: " + e);
                        }
                    }
                }
            }
@@ -247,42 +251,77 @@ public class RankingHelper implements RankingConfig {
            r.priority = priority;
            r.visibility = visibility;
            r.showBadge = showBadge;
            createDefaultChannelIfMissing(r);

            try {
                createDefaultChannelIfNeeded(r);
            } catch (NameNotFoundException e) {
                Slog.e(TAG, "createDefaultChannelIfNeeded - Exception: " + e);
            }

            if (r.uid == Record.UNKNOWN_UID) {
                mRestoredWithoutUids.put(pkg, r);
            } else {
                mRecords.put(key, r);
            }
            clampDefaultChannel(r);
        }
        return r;
    }

    // Clamp the importance level of the default channel for apps targeting the new SDK version,
    // unless the user has already changed the importance.
    private void clampDefaultChannel(Record r) {
        try {
            if (r.uid != Record.UNKNOWN_UID) {
                int userId = UserHandle.getUserId(r.uid);
                final ApplicationInfo applicationInfo =
                        mPm.getApplicationInfoAsUser(r.pkg, 0, userId);
                if (applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
                    final NotificationChannel defaultChannel =
                            r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID);
                    if ((defaultChannel.getUserLockedFields()
                            & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0) {
                        defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
                        updateConfig();
    private boolean shouldHaveDefaultChannel(Record r) throws NameNotFoundException {
        final int userId = UserHandle.getUserId(r.uid);
        final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg, 0, userId);
        if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
            // Pre-O apps should have it.
            return true;
        }

        // STOPSHIP TODO: remove before release - O+ apps should never have a default channel.
        // But for now, leave the default channel until an app has created its first channel.
        boolean hasCreatedAChannel = false;
        final int size = r.channels.size();
        for (int i = 0; i < size; i++) {
            final NotificationChannel notificationChannel = r.channels.valueAt(i);
            if (notificationChannel != null &&
                    notificationChannel.getId() != NotificationChannel.DEFAULT_CHANNEL_ID) {
                hasCreatedAChannel = true;
                break;
            }
        }
        } catch (NameNotFoundException e) {
            // oh well.
        if (!hasCreatedAChannel) {
            return true;
        }

        // Otherwise, should not have the default channel.
        return false;
    }

    private void createDefaultChannelIfMissing(Record r) {
    private void deleteDefaultChannelIfNeeded(Record r) throws NameNotFoundException {
        if (!r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
            // Not present
            return;
        }

        if (shouldHaveDefaultChannel(r)) {
            // Keep the default channel until upgraded.
            return;
        }

        // Remove Default Channel.
        r.channels.remove(NotificationChannel.DEFAULT_CHANNEL_ID);
    }

    private void createDefaultChannelIfNeeded(Record r) throws NameNotFoundException {
        if (r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
            // Already exists
            return;
        }

        if (!shouldHaveDefaultChannel(r)) {
            // Keep the default channel until upgraded.
            return;
        }

        // Create Default Channel
        NotificationChannel channel;
        channel = new NotificationChannel(
                NotificationChannel.DEFAULT_CHANNEL_ID,
@@ -301,7 +340,6 @@ public class RankingHelper implements RankingConfig {
        }
        r.channels.put(channel.getId(), channel);
    }
    }

    public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
        out.startTag(null, TAG_RANKING);
@@ -618,21 +656,6 @@ public class RankingHelper implements RankingConfig {
        updateConfig();
    }

    @Override
    public NotificationChannel getNotificationChannelWithFallback(String pkg, int uid,
            String channelId, boolean includeDeleted) {
        Record r = getOrCreateRecord(pkg, uid);
        if (channelId == null) {
            channelId = NotificationChannel.DEFAULT_CHANNEL_ID;
        }
        NotificationChannel channel = r.channels.get(channelId);
        if (channel != null && (includeDeleted || !channel.isDeleted())) {
            return channel;
        } else {
            return r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID);
        }
    }

    @Override
    public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId,
            boolean includeDeleted) {
@@ -1057,10 +1080,9 @@ public class RankingHelper implements RankingConfig {
                    Record fullRecord = getRecord(pkg,
                            mPm.getPackageUidAsUser(pkg, changeUserId));
                    if (fullRecord != null) {
                        clampDefaultChannel(fullRecord);
                    }
                } catch (NameNotFoundException e) {
                        deleteDefaultChannelIfNeeded(fullRecord);
                    }
                } catch (NameNotFoundException e) {}
            }
        }

+38 −34
Original line number Diff line number Diff line
@@ -59,21 +59,23 @@ import com.android.server.lights.LightsManager;

public class NotificationManagerServiceTest {
    private static final long WAIT_FOR_IDLE_TIMEOUT = 2;
    private final String pkg = "com.android.server.notification";
    private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
    private final int uid = Binder.getCallingUid();
    private NotificationManagerService mNotificationManagerService;
    private INotificationManager mBinderService;
    private IPackageManager mPackageManager = mock(IPackageManager.class);
    final PackageManager mPackageManagerClient = mock(PackageManager.class);
    private Context mContext;
    private final PackageManager mPackageManagerClient = mock(PackageManager.class);
    private Context mContext = InstrumentationRegistry.getTargetContext();
    private final String PKG = mContext.getPackageName();
    private HandlerThread mThread;
    final RankingHelper mRankingHelper = mock(RankingHelper.class);
    private final RankingHelper mRankingHelper = mock(RankingHelper.class);
    private NotificationChannel mTestNotificationChannel = new NotificationChannel(
            TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);

    @Before
    @Test
    @UiThreadTest
    public void setUp() throws Exception {
        mContext = InstrumentationRegistry.getTargetContext();
        mNotificationManagerService = new NotificationManagerService(mContext);

        // MockPackageManager - default returns ApplicationInfo with matching calling UID
@@ -93,13 +95,16 @@ public class NotificationManagerServiceTest {
                mock(NotificationManagerService.NotificationListeners.class);
        when(mockNotificationListeners.checkServiceTokenLocked(any())).thenReturn(
                mockNotificationListeners.new ManagedServiceInfo(null,
                        new ComponentName(pkg, "test_class"), uid, true, null, 0));
                        new ComponentName(PKG, "test_class"), uid, true, null, 0));

        mNotificationManagerService.init(mThread.getLooper(), mPackageManager,
                mPackageManagerClient, mockLightsManager, mockNotificationListeners);

        // Tests call directly into the Binder.
        mBinderService = mNotificationManagerService.getBinderService();

        mBinderService.createNotificationChannels(
                PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
    }

    public void waitForIdle() throws Exception {
@@ -127,7 +132,7 @@ public class NotificationManagerServiceTest {
    private NotificationRecord generateNotificationRecord(NotificationChannel channel,
            Notification.TvExtender extender) {
        if (channel == null) {
            channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
            channel = mTestNotificationChannel;
        }
        Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
                .setContentTitle("foo")
@@ -135,8 +140,7 @@ public class NotificationManagerServiceTest {
        if (extender != null) {
            nb.extend(extender);
        }
        StatusBarNotification sbn = new StatusBarNotification(mContext.getPackageName(),
                mContext.getPackageName(), 1, "tag", uid, 0,
        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", uid, 0,
                nb.build(), new UserHandle(uid), null, 0);
        return new NotificationRecord(mContext, sbn, channel);
    }
@@ -256,38 +260,38 @@ public class NotificationManagerServiceTest {
    @Test
    @UiThreadTest
    public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
        mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
                generateNotificationRecord(null).getNotification(), new int[1], 0);
        waitForIdle();
        StatusBarNotification[] notifs =
                mBinderService.getActiveNotifications(mContext.getPackageName());
                mBinderService.getActiveNotifications(PKG);
        assertEquals(1, notifs.length);
    }

    @Test
    @UiThreadTest
    public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
        mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
                generateNotificationRecord(null).getNotification(), new int[1], 0);
        mBinderService.cancelNotificationWithTag(mContext.getPackageName(), "tag", 0, 0);
        mBinderService.cancelNotificationWithTag(PKG, "tag", 0, 0);
        waitForIdle();
        StatusBarNotification[] notifs =
                mBinderService.getActiveNotifications(mContext.getPackageName());
                mBinderService.getActiveNotifications(PKG);
        assertEquals(0, notifs.length);
    }

    @Test
    @UiThreadTest
    public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
        mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
                generateNotificationRecord(null).getNotification(), new int[1], 0);
        waitForIdle();
        mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
                generateNotificationRecord(null).getNotification(), new int[1], 0);
        mBinderService.cancelNotificationWithTag(mContext.getPackageName(), "tag", 0, 0);
        mBinderService.cancelNotificationWithTag(PKG, "tag", 0, 0);
        waitForIdle();
        StatusBarNotification[] notifs =
                mBinderService.getActiveNotifications(mContext.getPackageName());
                mBinderService.getActiveNotifications(PKG);
        assertEquals(0, notifs.length);
    }

@@ -295,7 +299,7 @@ public class NotificationManagerServiceTest {
    @UiThreadTest
    public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
        mBinderService.cancelNotificationsFromListener(null, null);
        waitForIdle();
@@ -308,9 +312,9 @@ public class NotificationManagerServiceTest {
    @UiThreadTest
    public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
        mBinderService.cancelAllNotifications(sbn.getPackageName(), sbn.getUserId());
        mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
        waitForIdle();
        StatusBarNotification[] notifs =
                mBinderService.getActiveNotifications(sbn.getPackageName());
@@ -322,9 +326,9 @@ public class NotificationManagerServiceTest {
    public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
        mBinderService.cancelAllNotifications(sbn.getPackageName(), sbn.getUserId());
        mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
        waitForIdle();
        StatusBarNotification[] notifs =
                mBinderService.getActiveNotifications(sbn.getPackageName());
@@ -336,7 +340,7 @@ public class NotificationManagerServiceTest {
    public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
        mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
        waitForIdle();
@@ -349,7 +353,7 @@ public class NotificationManagerServiceTest {
    @UiThreadTest
    public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
        mBinderService.cancelAllNotifications(null, sbn.getUserId());
        waitForIdle();
@@ -362,7 +366,7 @@ public class NotificationManagerServiceTest {
    @UiThreadTest
    public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
                sbn.getId(), sbn.getNotification(), new int[1], UserHandle.USER_ALL);
        // Null pkg is how we signal a user switch.
        mBinderService.cancelAllNotifications(null, sbn.getUserId());
@@ -377,14 +381,14 @@ public class NotificationManagerServiceTest {
    public void testTvExtenderChannelOverride_onTv() throws Exception {
        mNotificationManagerService.setIsTelevision(true);
        mNotificationManagerService.setRankingHelper(mRankingHelper);
        when(mRankingHelper.getNotificationChannelWithFallback(
        when(mRankingHelper.getNotificationChannel(
                anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn(
                        new NotificationChannel("foo", "foo", NotificationManager.IMPORTANCE_HIGH));

        Notification.TvExtender tv = new Notification.TvExtender().setChannel("foo");
        mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
                generateNotificationRecord(null, tv).getNotification(), new int[1], 0);
        verify(mRankingHelper, times(1)).getNotificationChannelWithFallback(
        verify(mRankingHelper, times(1)).getNotificationChannel(
                anyString(), anyInt(), eq("foo"), anyBoolean());
    }

@@ -393,14 +397,14 @@ public class NotificationManagerServiceTest {
    public void testTvExtenderChannelOverride_notOnTv() throws Exception {
        mNotificationManagerService.setIsTelevision(false);
        mNotificationManagerService.setRankingHelper(mRankingHelper);
        when(mRankingHelper.getNotificationChannelWithFallback(
        when(mRankingHelper.getNotificationChannel(
                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
                new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH));
                mTestNotificationChannel);

        Notification.TvExtender tv = new Notification.TvExtender().setChannel("foo");
        mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
                generateNotificationRecord(null, tv).getNotification(), new int[1], 0);
        verify(mRankingHelper, times(1)).getNotificationChannelWithFallback(
                anyString(), anyInt(), eq("id"), anyBoolean());
        verify(mRankingHelper, times(1)).getNotificationChannel(
                anyString(), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean());
    }
}
+242 −216

File changed.

Preview size limit exceeded, changes collapsed.