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

Commit 1d420572 authored by Julia Reynolds's avatar Julia Reynolds Committed by Android (Google) Code Review
Browse files

Merge "Implement policy for promoted notifications" into main

parents 20f915ec 70e1718c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6495,6 +6495,7 @@ package android.app {
    field public static final int FLAG_NO_CLEAR = 32; // 0x20
    field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
    field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
    field @FlaggedApi("android.app.api_rich_ongoing") public static final int FLAG_PROMOTED_ONGOING = 262144; // 0x40000
    field @Deprecated public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
    field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0
    field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2
+2 −0
Original line number Diff line number Diff line
@@ -258,4 +258,6 @@ interface INotificationManager
    @EnforcePermission(allOf={"INTERACT_ACROSS_USERS", "ACCESS_NOTIFICATIONS"})
    void unregisterCallNotificationEventListener(String packageName, in UserHandle userHandle, in ICallNotificationEventCallback listener);

    void setCanBePromoted(String pkg, int uid, boolean promote);
    boolean canBePromoted(String pkg, int uid);
}
+58 −0
Original line number Diff line number Diff line
@@ -772,6 +772,17 @@ public class Notification implements Parcelable
    @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_SILENT_FLAG)
    public static final int FLAG_SILENT = 1 << 17;  //0x00020000
    /**
     * Bit to be bitwise-ored into the {@link #flags} field that should be
     * set by the system if this notification is a promoted ongoing notification, either via a
     * user setting or allowlist.
     *
     * Applications cannot set this flag directly, but the posting app and
     * {@link android.service.notification.NotificationListenerService} can read it.
     */
    @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
    public static final int FLAG_PROMOTED_ONGOING = 0x00040000;
    private static final List<Class<? extends Style>> PLATFORM_STYLE_CLASSES = Arrays.asList(
            BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
            DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class,
@@ -3109,6 +3120,53 @@ public class Notification implements Parcelable
        }
    }
    /**
     * @hide
     */
    @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING)
    public boolean containsCustomViews() {
        return contentView != null
                || bigContentView != null
                || headsUpContentView != null
                || (publicVersion != null
                && (publicVersion.contentView != null
                || publicVersion.bigContentView != null
                || publicVersion.headsUpContentView != null));
    }
    /**
     * @hide
     */
    @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING)
    public boolean hasTitle() {
        return extras != null
                && (!TextUtils.isEmpty(extras.getCharSequence(EXTRA_TITLE))
                || !TextUtils.isEmpty(extras.getCharSequence(EXTRA_TITLE_BIG)));
    }
    /**
     * @hide
     */
    @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING)
    public boolean hasPromotableStyle() {
        //TODO(b/367739672): Add progress style
        return extras == null || !extras.containsKey(Notification.EXTRA_TEMPLATE)
                || isStyle(Notification.BigPictureStyle.class)
                || isStyle(Notification.BigTextStyle.class)
                || isStyle(Notification.CallStyle.class);
    }
    /**
     * @hide
     */
    @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING)
    public boolean hasPromotableCharacteristics() {
        return isColorized()
                && hasTitle()
                && !containsCustomViews()
                && hasPromotableStyle();
    }
    /**
     * Whether this notification was posted by a headless system app.
     *
+278 −3
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static android.app.Notification.EXTRA_PICTURE;
import static android.app.Notification.EXTRA_PICTURE_ICON;
import static android.app.Notification.EXTRA_SUMMARY_TEXT;
import static android.app.Notification.EXTRA_TITLE;
import static android.app.Notification.FLAG_CAN_COLORIZE;
import static android.app.Notification.GROUP_ALERT_CHILDREN;
import static android.app.Notification.GROUP_ALERT_SUMMARY;
import static android.app.Notification.GROUP_KEY_SILENT;
@@ -96,6 +97,7 @@ import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import android.text.style.TextAppearanceSpan;
import android.util.Pair;
import android.util.Slog;
import android.widget.RemoteViews;

import androidx.test.InstrumentationRegistry;
@@ -126,6 +128,8 @@ public class NotificationTest {

    private Context mContext;

    private RemoteViews mRemoteViews;

    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();
    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -133,23 +137,25 @@ public class NotificationTest {
    @Before
    public void setUp() {
        mContext = InstrumentationRegistry.getContext();
        mRemoteViews = new RemoteViews(
                mContext.getPackageName(), R.layout.notification_template_header);
    }

    @Test
    public void testColorizedByPermission() {
        Notification n = new Notification.Builder(mContext, "test")
                .setFlag(Notification.FLAG_CAN_COLORIZE, true)
                .setFlag(FLAG_CAN_COLORIZE, true)
                .setColorized(true).setColor(Color.WHITE)
                .build();
        assertTrue(n.isColorized());

        n = new Notification.Builder(mContext, "test")
                .setFlag(Notification.FLAG_CAN_COLORIZE, true)
                .setFlag(FLAG_CAN_COLORIZE, true)
                .build();
        assertFalse(n.isColorized());

        n = new Notification.Builder(mContext, "test")
                .setFlag(Notification.FLAG_CAN_COLORIZE, false)
                .setFlag(FLAG_CAN_COLORIZE, false)
                .setColorized(true).setColor(Color.WHITE)
                .build();
        assertFalse(n.isColorized());
@@ -214,6 +220,275 @@ public class NotificationTest {
        assertFalse(n.hasCompletedProgress());
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasTitle_noStyle() {
        Notification n = new Notification.Builder(mContext, "test")
                .setContentTitle("TITLE")
                .build();
        assertThat(n.hasTitle()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasTitle_bigText() {
        Notification n = new Notification.Builder(mContext, "test")
                .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
                .build();
        assertThat(n.hasTitle()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasTitle_noTitle() {
        Notification n = new Notification.Builder(mContext, "test")
                .setContentText("text not title")
                .build();
        assertThat(n.hasTitle()).isFalse();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testContainsCustomViews_none() {
        Notification np = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .build();
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .setPublicVersion(np)
                .build();
        assertThat(n.containsCustomViews()).isFalse();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testContainsCustomViews_content() {
        Notification np = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .build();
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .setCustomContentView(mRemoteViews)
                .setPublicVersion(np)
                .build();
        assertThat(n.containsCustomViews()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testContainsCustomViews_big() {
        Notification np = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .build();
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .setCustomBigContentView(mRemoteViews)
                .setPublicVersion(np)
                .build();
        assertThat(n.containsCustomViews()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testContainsCustomViews_headsUp() {
        Notification np = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .build();
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .setCustomHeadsUpContentView(mRemoteViews)
                .setPublicVersion(np)
                .build();
        assertThat(n.containsCustomViews()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testContainsCustomViews_content_public() {
        Notification np = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("public")
                .setCustomContentView(mRemoteViews)
                .build();
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .setPublicVersion(np)
                .build();
        assertThat(n.containsCustomViews()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testContainsCustomViews_big_public() {
        Notification np = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .setCustomBigContentView(mRemoteViews)
                .build();
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .setPublicVersion(np)
                .build();
        assertThat(n.containsCustomViews()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testContainsCustomViews_headsUp_public() {
        Notification np = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .setCustomHeadsUpContentView(mRemoteViews)
                .build();
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .setPublicVersion(np)
                .build();
        assertThat(n.containsCustomViews()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableStyle_noStyle() {
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setContentText("test")
                .build();
        assertThat(n.hasPromotableStyle()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableStyle_bigPicture() {
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setStyle(new Notification.BigPictureStyle())
                .build();
        assertThat(n.hasPromotableStyle()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableStyle_bigText() {
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setStyle(new Notification.BigTextStyle())
                .build();
        assertThat(n.hasPromotableStyle()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableStyle_no_messagingStyle() {
        Notification.MessagingStyle style = new Notification.MessagingStyle("self name")
                .setGroupConversation(true)
                .setConversationTitle("test conversation title");
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setStyle(style)
                .build();
        assertThat(n.hasPromotableStyle()).isFalse();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableStyle_no_mediaStyle() {
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setStyle(new Notification.MediaStyle())
                .build();
        assertThat(n.hasPromotableStyle()).isFalse();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableStyle_no_inboxStyle() {
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setStyle(new Notification.InboxStyle())
                .build();
        assertThat(n.hasPromotableStyle()).isFalse();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableStyle_callText() {
        PendingIntent answerIntent = createPendingIntent("answer");
        PendingIntent declineIntent = createPendingIntent("decline");
        Notification.CallStyle style = Notification.CallStyle.forIncomingCall(
                new Person.Builder().setName("A Caller").build(),
                declineIntent,
                answerIntent
        );
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setStyle(style)
                .build();
        assertThat(n.hasPromotableStyle()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableCharacteristics() {
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
                .setColor(Color.WHITE)
                .setColorized(true)
                .setFlag(FLAG_CAN_COLORIZE, true)
                .build();
        assertThat(n.hasPromotableCharacteristics()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableCharacteristics_wrongStyle() {
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setStyle(new Notification.InboxStyle())
                .setContentTitle("TITLE")
                .setColor(Color.WHITE)
                .setColorized(true)
                .setFlag(FLAG_CAN_COLORIZE, true)
                .build();
        assertThat(n.hasPromotableCharacteristics()).isFalse();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableCharacteristics_notColorized() {
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
                .setColor(Color.WHITE)
                .build();
        assertThat(n.hasPromotableCharacteristics()).isFalse();
    }

    @Test
    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
    public void testHasPromotableCharacteristics_noTitle() {
        Notification n = new Notification.Builder(mContext, "test")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setStyle(new Notification.BigTextStyle())
                .setColor(Color.WHITE)
                .setColorized(true)
                .setFlag(FLAG_CAN_COLORIZE, true)
                .build();
        assertThat(n.hasPromotableCharacteristics()).isFalse();
    }

    @Test
    @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
    public void testGetShortCriticalText_noneSet() {
+104 −9
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import static android.app.Notification.EXTRA_LARGE_ICON_BIG;
import static android.app.Notification.EXTRA_SUB_TEXT;
import static android.app.Notification.EXTRA_TEXT;
import static android.app.Notification.EXTRA_TEXT_LINES;
import static android.app.Notification.EXTRA_TITLE;
import static android.app.Notification.EXTRA_TITLE_BIG;
import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY;
import static android.app.Notification.FLAG_AUTO_CANCEL;
@@ -45,6 +46,7 @@ import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_NO_DISMISS;
import static android.app.Notification.FLAG_ONGOING_EVENT;
import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
import static android.app.Notification.FLAG_PROMOTED_ONGOING;
import static android.app.Notification.FLAG_USER_INITIATED_JOB;
import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT;
import static android.app.NotificationChannel.NEWS_ID;
@@ -3516,7 +3518,7 @@ public class NotificationManagerService extends SystemService {
    private String getHistoryTitle(Notification n) {
        CharSequence title = null;
        if (n.extras != null) {
            title = n.extras.getCharSequence(Notification.EXTRA_TITLE);
            title = n.extras.getCharSequence(EXTRA_TITLE);
            if (title == null) {
                title = n.extras.getCharSequence(EXTRA_TITLE_BIG);
            }
@@ -4113,6 +4115,75 @@ public class NotificationManagerService extends SystemService {
            handleSavePolicyFile();
        }
        @Override
        @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING)
        public boolean canBePromoted(String pkg, int uid) {
            checkCallerIsSystemOrSystemUiOrShell();
            if (!android.app.Flags.uiRichOngoing()) {
                return false;
            }
            return mPreferencesHelper.canBePromoted(pkg, uid);
        }
        @Override
        @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING)
        public void setCanBePromoted(String pkg, int uid, boolean promote) {
            checkCallerIsSystemOrSystemUiOrShell();
            if (!android.app.Flags.uiRichOngoing()) {
                return;
            }
            boolean changed = mPreferencesHelper.setCanBePromoted(pkg, uid, promote);
            if (changed) {
                // check for pending/posted notifs from this app and update the flag
                synchronized (mNotificationLock) {
                    // for enqueued we just need to update the flag
                    List<NotificationRecord> enqueued = findAppNotificationByListLocked(
                            mEnqueuedNotifications, pkg, UserHandle.getUserId(uid));
                    for (NotificationRecord r : enqueued) {
                        if (promote
                                && r.getNotification().hasPromotableCharacteristics()
                                && r.getImportance() > IMPORTANCE_MIN) {
                            r.getNotification().flags |= FLAG_PROMOTED_ONGOING;
                        } else if (!promote) {
                            r.getNotification().flags &= ~FLAG_PROMOTED_ONGOING;
                        }
                    }
                    // if the notification is posted we need to update the flag and tell listeners
                    List<NotificationRecord> posted = findAppNotificationByListLocked(
                            mNotificationList, pkg, UserHandle.getUserId(uid));
                    for (NotificationRecord r : posted) {
                        if (promote
                                && !hasFlag(r.getNotification().flags, FLAG_PROMOTED_ONGOING)
                                && r.getNotification().hasPromotableCharacteristics()
                                && r.getImportance() > IMPORTANCE_MIN) {
                            r.getNotification().flags |= FLAG_PROMOTED_ONGOING;
                            // we could set a wake lock here but this value should only change
                            // in response to user action, so the device should be awake long enough
                            // to post
                            PostNotificationTracker tracker =
                                    mPostNotificationTrackerFactory.newTracker(null);
                            // Set false for isAppForeground because that field is only used
                            // for bubbles and messagingstyle can not be promoted
                            mHandler.post(new EnqueueNotificationRunnable(
                                    r.getUser().getIdentifier(),
                                    r, /* isAppForeground */ false, /* isAppProvided= */ false,
                                    tracker));
                        } else if (!promote
                                && hasFlag(r.getNotification().flags, FLAG_PROMOTED_ONGOING)){
                            r.getNotification().flags &= ~FLAG_PROMOTED_ONGOING;
                            PostNotificationTracker tracker =
                                    mPostNotificationTrackerFactory.newTracker(null);
                            mHandler.post(new EnqueueNotificationRunnable(
                                    r.getUser().getIdentifier(),
                                    r, /* isAppForeground */ false, /* isAppProvided= */ false,
                                    tracker));
                        }
                    }
                }
                handleSavePolicyFile();
            }
        }
        @Override
        public boolean hasSentValidMsg(String pkg, int uid) {
            checkCallerIsSystem();
@@ -7698,6 +7769,16 @@ public class NotificationManagerService extends SystemService {
            return false;
        }
        if (android.app.Flags.uiRichOngoing()) {
            // This would normally be done in fixNotification(), but we need the channel info so
            // it's done a little late
            if (mPreferencesHelper.canBePromoted(pkg, notificationUid)
                    && notification.hasPromotableCharacteristics()
                    && channel.getImportance() > IMPORTANCE_MIN) {
                notification.flags |= FLAG_PROMOTED_ONGOING;
            }
        }
        final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
        r.setIsAppImportanceLocked(mPermissionHelper.isPermissionUserSet(pkg, userId));
        r.setPostSilently(postSilently);
@@ -7938,6 +8019,9 @@ public class NotificationManagerService extends SystemService {
            }
        }
        // Apps cannot set this flag
         notification.flags &= ~FLAG_PROMOTED_ONGOING;
        // Ensure CallStyle has all the correct actions
        if (notification.isStyle(Notification.CallStyle.class)) {
            Notification.Builder builder =
@@ -8061,12 +8145,7 @@ public class NotificationManagerService extends SystemService {
    private void checkRemoteViews(String pkg, String tag, int id, Notification notification) {
        if (android.app.Flags.removeRemoteViews()) {
            if (notification.contentView != null || notification.bigContentView != null
                    ||  notification.headsUpContentView != null
                    || (notification.publicVersion != null
                    && (notification.publicVersion.contentView != null
                    || notification.publicVersion.bigContentView != null
                    || notification.publicVersion.headsUpContentView != null))) {
            if (notification.containsCustomViews()) {
                Slog.i(TAG, "Removed customViews for " + pkg);
                mUsageStats.registerImageRemoved(pkg);
            }
@@ -9236,8 +9315,8 @@ public class NotificationManagerService extends SystemService {
            }
        }
        final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
        final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
        final String oldTitle = String.valueOf(oldN.extras.get(EXTRA_TITLE));
        final String newTitle = String.valueOf(newN.extras.get(EXTRA_TITLE));
        if (!Objects.equals(oldTitle, newTitle)) {
            if (DEBUG_INTERRUPTIVENESS) {
                Slog.v(TAG, "INTERRUPTIVENESS: "
@@ -10653,6 +10732,22 @@ public class NotificationManagerService extends SystemService {
    }
    @GuardedBy("mNotificationLock")
    @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING)
    private @NonNull List<NotificationRecord> findAppNotificationByListLocked(
            ArrayList<NotificationRecord> list, String pkg, int userId) {
        List<NotificationRecord> records = new ArrayList<>();
        final int len = list.size();
        for (int i = 0; i < len; i++) {
            NotificationRecord r = list.get(i);
            if (notificationMatchesUserId(r, userId, false)
                    && r.getSbn().getPackageName().equals(pkg)) {
                records.add(r);
            }
        }
        return records;
    }
    @GuardedBy("mNotificationLock")
    private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
            ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
Loading