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

Commit 26d913d5 authored by Yuri Lin's avatar Yuri Lin Committed by Android (Google) Code Review
Browse files

Merge "Save original channel visibility on bundling notifications" into main

parents 722b9b25 a9dc130c
Loading
Loading
Loading
Loading
+3 −11
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.PipelineEntry
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
@@ -201,19 +200,13 @@ constructor(

    private fun shouldHideIfEntrySilent(entry: PipelineEntry): Boolean =
        when {
            // TODO(b/410825977): The bundle classifier clobbers the channel that the notification
            //  was posted to, and so we don't know whether any child of a bundle is SECRET. For now
            //  treat all bundles as SECRET.
            entry !is ListEntry -> true
            // Show if explicitly high priority (not hidden)
            highPriorityProvider.isExplicitlyHighPriority(entry) -> false
            // Ambient notifications are hidden always from lock screen
            entry.representativeEntry?.isAmbient == true -> true
            entry.asListEntry()?.representativeEntry?.isAmbient == true -> true
            // [Now notification is silent]
            // Hide regardless of parent priority if user wants silent notifs hidden
            // Always hide if user wants silent notifs hidden
            hideSilentNotificationsOnLockscreen -> true
            // Parent priority is high enough to be shown on the lockscreen, do not hide.
            entry.parent?.let(::shouldHideIfEntrySilent) == false -> false
            // Show when silent notifications are allowed on lockscreen
            else -> false
        }
@@ -244,8 +237,7 @@ constructor(
        // ranking.lockscreenVisibilityOverride contains possibly out of date DPC and Setting
        // info, and NotificationLockscreenUserManagerImpl is already listening for updates
        // to those
        return entry.ranking.channel != null &&
            entry.ranking.channel.lockscreenVisibility == VISIBILITY_SECRET
        return entry.ranking.channel?.lockscreenVisibility == VISIBILITY_SECRET
    }

    override fun dump(pw: PrintWriter, args: Array<out String>) =
+17 −1
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ import static android.service.notification.NotificationListenerService.REASON_US
import static android.service.notification.NotificationListenerService.Ranking.RANKING_DEMOTED;
import static android.service.notification.NotificationListenerService.Ranking.RANKING_PROMOTED;
import static android.service.notification.NotificationListenerService.Ranking.RANKING_UNCHANGED;
import static android.service.notification.NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
import static android.service.notification.NotificationListenerService.TRIM_FULL;
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -12226,6 +12227,21 @@ public class NotificationManagerService extends SystemService {
                    smartReplies = null;
                }
            }
            NotificationChannel effectiveChannel = record.getChannel().copy();
            if (notificationClassificationUi()) {
                // special handling for a notification's channel visibility when bundled: if the
                // notification's original channel had a more strict visibility than the current
                // channel, or if the current channel has an unspecified visibility, patch that
                // original visibility into the channel stored in Ranking.
                if (record.getOriginalChannelVisibility() != VISIBILITY_NO_OVERRIDE) {
                    int currentChannelVis = record.getChannel().getLockscreenVisibility();
                    if (currentChannelVis == VISIBILITY_NO_OVERRIDE
                            || record.getOriginalChannelVisibility() < currentChannelVis) {
                        effectiveChannel.setLockscreenVisibility(
                                record.getOriginalChannelVisibility());
                    }
                }
            }
            ranking.populate(
                    key,
                    rankings.size(),
@@ -12235,7 +12251,7 @@ public class NotificationManagerService extends SystemService {
                    record.getImportance(),
                    record.getImportanceExplanation(),
                    record.getSbn().getOverrideGroupKey(),
                    record.getChannel(),
                    effectiveChannel,
                    record.getPeopleOverride(),
                    record.getSnoozeCriteria(),
                    record.canShowBadge(),
+19 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.app.Flags;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Person;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -228,6 +229,12 @@ public final class NotificationRecord {
    // was present at the time of unclassification.
    private boolean mHadGroupSummaryWhenUnclassified = false;

    // If this notification was classified into a bundle, this value stores the visibility of the
    // original channel associated with this notification. If the original channel is set to be
    // secret, that information should override any more generous visibility settings on the newly
    // assigned bundle.
    private int mOriginalChannelVisibility = NotificationManager.VISIBILITY_NO_OVERRIDE;

    public NotificationRecord(Context context, StatusBarNotification sbn,
            NotificationChannel channel) {
        this.sbn = sbn;
@@ -809,6 +816,8 @@ public final class NotificationRecord {
                }
                if (android.service.notification.Flags.notificationClassification()) {
                    if (signals.containsKey(Adjustment.KEY_TYPE)) {
                        // Store original channel visibility before re-assigning channel
                        setOriginalChannelVisibility(mChannel.getLockscreenVisibility());
                        updateNotificationChannel(signals.getParcelable(Adjustment.KEY_TYPE,
                                NotificationChannel.class));
                        EventLogTags.writeNotificationAdjusted(getKey(),
@@ -816,6 +825,8 @@ public final class NotificationRecord {
                                mChannel.getId());
                    }
                    if (signals.containsKey(Adjustment.KEY_UNCLASSIFY)) {
                        // reset original channel visibility as we're returning to the original
                        setOriginalChannelVisibility(NotificationManager.VISIBILITY_NO_OVERRIDE);
                        updateNotificationChannel(signals.getParcelable(Adjustment.KEY_UNCLASSIFY,
                                NotificationChannel.class));
                        EventLogTags.writeNotificationAdjusted(getKey(),
@@ -1675,6 +1686,14 @@ public final class NotificationRecord {
        mHadGroupSummaryWhenUnclassified = exists;
    }

    public int getOriginalChannelVisibility() {
        return mOriginalChannelVisibility;
    }

    public void setOriginalChannelVisibility(int visibility) {
        mOriginalChannelVisibility = visibility;
    }

    /**
     * Whether this notification is a conversation notification.
     */
+4 −2
Original line number Diff line number Diff line
@@ -57,7 +57,9 @@ public class VisibilityExtractor implements NotificationSignalExtractor {
                    mConfig.canShowNotificationsOnLockscreen(userId);
            boolean dpmCanShowNotifications = adminAllowsKeyguardFeature(userId,
                    DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
            boolean channelCanShowNotifications = record.getChannel().getLockscreenVisibility()
            boolean channelCanShowNotifications =
                    record.getChannel().getLockscreenVisibility() != Notification.VISIBILITY_SECRET
                            && record.getOriginalChannelVisibility()
                            != Notification.VISIBILITY_SECRET;

            if (!userCanShowNotifications || !dpmCanShowNotifications
+75 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ 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_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
@@ -18315,6 +18316,80 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
    }
    @Test
    @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
            android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI,
            FLAG_NOTIFICATION_FORCE_GROUPING,
            FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION})
    public void testApplyAdjustment_keyType_storesOriginalChannelVisibility() throws Exception {
        NotificationManagerService.WorkerHandler handler = mock(
                NotificationManagerService.WorkerHandler.class);
        mService.setHandler(handler);
        when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
        when(mAssistants.isClassificationTypeAllowed(anyInt(), anyInt())).thenReturn(true);
        when(mAssistants.isAdjustmentAllowedForPackage(anyInt(), anyString(),
                anyString())).thenReturn(true);
        NotificationChannel secret = new NotificationChannel("secretChannelId", "secret channel",
                NotificationManager.IMPORTANCE_DEFAULT);
        mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(List.of(secret)));
        // Need to set the visibility as an update since this isn't a field typically set by apps
        secret.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
        mBinderService.updateNotificationChannelForPackage(mPkg, mUid, secret);
        final NotificationRecord r = generateNotificationRecord(secret);
        mService.addNotification(r);
        Bundle signals = new Bundle();
        signals.putInt(KEY_TYPE, TYPE_NEWS);
        Adjustment adjustment = new Adjustment(
                r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
        mBinderService.applyAdjustmentFromAssistant(null, adjustment);
        waitForIdle();
        r.applyAdjustments();
        // The notification should be bundled now
        assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
        // but the original channel visibility is stored
        assertThat(r.getOriginalChannelVisibility()).isEqualTo(Notification.VISIBILITY_SECRET);
        // check that the information made it to the ranking update too, via the stored channel:
        // it's still the "news" channel, but with the stricter visibility applied
        ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
        when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
        when(info.isSameUser(anyInt())).thenReturn(true);
        NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
        NotificationListenerService.Ranking ranking =
                nru.getRankingMap().getRawRankingObject(r.getKey());
        assertThat(ranking.getChannel().getId()).isEqualTo(NEWS_ID);
        assertThat(ranking.getChannel().getLockscreenVisibility()).isEqualTo(
                Notification.VISIBILITY_SECRET);
        // Now un-classify
        doAnswer(invocationOnMock -> {
            ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments();
            ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance();
            return null;
        }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
        mService.unclassifyNotification(r.getKey());
        mService.handleRankingSort();
        // confirm it's unclassified
        assertThat(r.getChannel().getId()).isEqualTo(secret.getId());
        // and that the original channel visibility is reset
        assertThat(r.getOriginalChannelVisibility()).isEqualTo(VISIBILITY_NO_OVERRIDE);
        // and the ranking objects will be updated accordingly (the ranking's channel should be the
        // notification's original channel)
        NotificationRankingUpdate nru2 = mService.makeRankingUpdateLocked(info);
        NotificationListenerService.Ranking ranking2 =
                nru2.getRankingMap().getRawRankingObject(r.getKey());
        assertThat(ranking2.getChannel()).isEqualTo(secret);
    }
    @Test
    @EnableFlags({FLAG_API_RICH_ONGOING,
            android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
Loading