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

Commit 9cb05c2d authored by Alexander Roederer's avatar Alexander Roederer
Browse files

Use NotifManagerService to handle lifetime ext

Modifies NotificationManagerService to handle lifetime extending
notifications on direct reply or smart reply. When a notification has a
direct reply or smart reply event, the notification will have a new flag
indicating such. Then, notification manager service checks this flag
before canceling the notification in the appropriate cases.

Bug: 230652175
Test: atest NotificationManagerServiceTest
Change-Id: I2085a0eeaac9eaa87b25d8a157b6ad40eac0865a
parent b40a6c09
Loading
Loading
Loading
Loading
+66 −20
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.app.Notification.FLAG_BUBBLE;
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
import static android.app.Notification.FLAG_INSISTENT;
import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_NO_DISMISS;
import static android.app.Notification.FLAG_ONGOING_EVENT;
@@ -58,6 +59,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.Flags.lifetimeExtensionRefactor;
import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
import static android.content.Context.BIND_AUTO_CREATE;
import static android.content.Context.BIND_FOREGROUND_SERVICE;
@@ -1224,7 +1226,7 @@ public class NotificationManagerService extends SystemService {
        public void onClearAll(int callingUid, int callingPid, int userId) {
            synchronized (mNotificationLock) {
                cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
                        /*includeCurrentProfiles*/ true);
                        /*includeCurrentProfiles*/ true, FLAG_ONGOING_EVENT | FLAG_NO_CLEAR);
            }
        }
@@ -1498,6 +1500,7 @@ public class NotificationManagerService extends SystemService {
            synchronized (mNotificationLock) {
                NotificationRecord r = mNotificationsByKey.get(key);
                if (r != null) {
                    r.recordSmartReplied();
                    LogMaker logMaker = r.getLogMaker()
                            .setCategory(MetricsEvent.SMART_REPLY_ACTION)
                            .setSubtype(replyIndex)
@@ -1804,7 +1807,17 @@ public class NotificationManagerService extends SystemService {
                    record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
                }
                if (record != null) {
                    cancelNotification(record.getSbn().getUid(), record.getSbn().getInitialPid(),
                    if (lifetimeExtensionRefactor()) {
                        cancelNotification(record.getSbn().getUid(),
                                record.getSbn().getInitialPid(),
                                record.getSbn().getPackageName(), record.getSbn().getTag(),
                                record.getSbn().getId(), 0,
                                FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB
                                        | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY,
                                true, record.getUserId(), REASON_TIMEOUT, null);
                    } else {
                        cancelNotification(record.getSbn().getUid(),
                                record.getSbn().getInitialPid(),
                                record.getSbn().getPackageName(), record.getSbn().getTag(),
                                record.getSbn().getId(), 0,
                                FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB,
@@ -1812,6 +1825,7 @@ public class NotificationManagerService extends SystemService {
                    }
                }
            }
        }
    };
    private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
@@ -3728,8 +3742,16 @@ public class NotificationManagerService extends SystemService {
        @Override
        public void cancelNotificationWithTag(String pkg, String opPkg, String tag, int id,
                int userId) {
            // Don't allow client applications to cancel foreground service notifs, user-initiated
            // job notifs, autobundled summaries, or notifs that have been replied to.
            int mustNotHaveFlags = isCallingUidSystem() ? 0 :
                    (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY);
            if (lifetimeExtensionRefactor()) {
                mustNotHaveFlags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
            }
            cancelNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(),
                    tag, id, userId);
                    tag, id, userId, mustNotHaveFlags);
        }
        @Override
@@ -3740,10 +3762,17 @@ public class NotificationManagerService extends SystemService {
                    Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
            // Don't allow the app to cancel active FGS or UIJ notifications
            if (lifetimeExtensionRefactor()) {
                cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
                        pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB
                                | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY,
                        userId, REASON_APP_CANCEL_ALL);
            } else {
                cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
                        pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB,
                        userId, REASON_APP_CANCEL_ALL);
            }
        }
        @Override
        public void silenceNotificationSound() {
@@ -4808,8 +4837,16 @@ public class NotificationManagerService extends SystemService {
                                    r.getSbn().getId(), userId, reason);
                        }
                    } else {
                        if (lifetimeExtensionRefactor()) {
                            cancelAllLocked(callingUid, callingPid, info.userid,
                                REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
                                    REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(),
                                    FLAG_ONGOING_EVENT | FLAG_NO_CLEAR
                                            | FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
                        } else {
                            cancelAllLocked(callingUid, callingPid, info.userid,
                                    REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(),
                                    FLAG_ONGOING_EVENT | FLAG_NO_CLEAR);
                        }
                    }
                }
            } finally {
@@ -4923,6 +4960,9 @@ public class NotificationManagerService extends SystemService {
                int callingUid, int callingPid, String pkg, String tag, int id, int userId,
                int reason) {
            int mustNotHaveFlags = FLAG_ONGOING_EVENT;
            if (lifetimeExtensionRefactor()) {
                mustNotHaveFlags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
            }
            cancelNotification(callingUid, callingPid, pkg, tag, id, 0 /* mustHaveFlags */,
                    mustNotHaveFlags,
                    true,
@@ -6712,7 +6752,12 @@ public class NotificationManagerService extends SystemService {
        @Override
        public void cancelNotification(String pkg, String opPkg, int callingUid, int callingPid,
                String tag, int id, int userId) {
            cancelNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, userId);
            // Don't allow client applications to cancel foreground service notifs,
            // user-initiated job notifs or autobundled summaries.
            final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
                    (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY);
            cancelNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, userId,
                    mustNotHaveFlags);
        }
        @Override
@@ -6907,7 +6952,7 @@ public class NotificationManagerService extends SystemService {
    }
    void cancelNotificationInternal(String pkg, String opPkg, int callingUid, int callingPid,
            String tag, int id, int userId) {
            String tag, int id, int userId, int mustNotHaveFlags) {
        userId = ActivityManager.handleIncomingUser(callingPid,
                callingUid, userId, true, false, "cancelNotificationWithTag", pkg);
@@ -6935,10 +6980,6 @@ public class NotificationManagerService extends SystemService {
            }
        }
        // Don't allow client applications to cancel foreground service notifs, user-initiated job
        // notifs or autobundled summaries.
        final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
                (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY);
        cancelNotification(uid, callingPid, pkg, tag, id, 0,
                mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
    }
@@ -7294,6 +7335,11 @@ public class NotificationManagerService extends SystemService {
        notification.flags &= ~FLAG_FSI_REQUESTED_BUT_DENIED;
        // Apps should not create notifications that are lifetime extended.
        if (lifetimeExtensionRefactor()) {
            notification.flags &= ~FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
        }
        if (notification.fullScreenIntent != null) {
            final AttributionSource attributionSource =
                    new AttributionSource.Builder(notificationUid).setPackageName(pkg).build();
@@ -10088,7 +10134,7 @@ public class NotificationManagerService extends SystemService {
    @GuardedBy("mNotificationLock")
    void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
            ManagedServiceInfo listener, boolean includeCurrentProfiles) {
            ManagedServiceInfo listener, boolean includeCurrentProfiles, int mustNotHaveFlags) {
        final long cancellationElapsedTimeMs = SystemClock.elapsedRealtime();
        mHandler.post(new Runnable() {
            @Override
@@ -10100,7 +10146,7 @@ public class NotificationManagerService extends SystemService {
                            null, userId, 0, 0, reason, listenerName);
                    FlagChecker flagChecker = (int flags) -> {
                        int flagsToCheck = FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
                        int flagsToCheck = mustNotHaveFlags;
                        if (REASON_LISTENER_CANCEL_ALL == reason
                                || REASON_CANCEL_ALL == reason) {
                            flagsToCheck |= FLAG_BUBBLE;
+193 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static android.app.Notification.FLAG_AUTO_CANCEL;
import static android.app.Notification.FLAG_BUBBLE;
import static android.app.Notification.FLAG_CAN_COLORIZE;
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_ONGOING_EVENT;
import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
@@ -320,6 +321,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    private static final int SECONDARY_DISPLAY_ID = 42;
    private static final int TEST_PROFILE_USERHANDLE = 12;
    private static final String ACTION_NOTIFICATION_TIMEOUT =
            NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
    private static final String EXTRA_KEY = "key";
    private static final String SCHEME_TIMEOUT = "timeout";
    private final int mUid = Binder.getCallingUid();
    private final @UserIdInt int mUserId = UserHandle.getUserId(mUid);
@@ -442,6 +448,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    MultiRateLimiter mToastRateLimiter;
    BroadcastReceiver mPackageIntentReceiver;
    BroadcastReceiver mUserSwitchIntentReceiver;
    BroadcastReceiver mNotificationTimeoutReceiver;
    NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
    TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
@@ -676,6 +683,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(),
                any(), intentFilterCaptor.capture(), any(), any());
        verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(),
                intentFilterCaptor.capture(), anyInt());
        verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(),
                intentFilterCaptor.capture());
        List<BroadcastReceiver> broadcastReceivers = broadcastReceiverCaptor.getAllValues();
@@ -695,9 +704,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                    mUserSwitchIntentReceiver = broadcastReceivers.get(i);
                }
            }
            if (filter.hasAction(ACTION_NOTIFICATION_TIMEOUT)
                    && filter.hasDataScheme(SCHEME_TIMEOUT)) {
                mNotificationTimeoutReceiver = broadcastReceivers.get(i);
            }
        }
        assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
        assertNotNull("User-switch receiver should exist", mUserSwitchIntentReceiver);
        assertNotNull("Notification timeout receiver should exist", mNotificationTimeoutReceiver);
        // Pretend the shortcut exists
        List<ShortcutInfo> shortcutInfos = new ArrayList<>();
@@ -2429,6 +2443,59 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.getNotificationRecordCount());
    }
    @Test
    public void testCancelWithTagDoesNotCancelLifetimeExtended() throws Exception {
        mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
        final NotificationRecord notif = generateNotificationRecord(null);
        notif.getSbn().getNotification().flags =
                Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
        mService.addNotification(notif);
        final StatusBarNotification sbn = notif.getSbn();
        assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
        assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
        mBinderService.cancelNotificationWithTag(PKG, PKG, sbn.getTag(), sbn.getId(),
                sbn.getUserId());
        waitForIdle();
        assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1);
        assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
        mSetFlagsRule.disableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
        mBinderService.cancelNotificationWithTag(PKG, PKG, sbn.getTag(), sbn.getId(),
                sbn.getUserId());
        waitForIdle();
        assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(0);
        assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
    }
    @Test
    public void testCancelAllDoesNotCancelLifetimeExtended() throws Exception {
        mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
        // Adds a lifetime extended notification.
        final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1,
                null, false);
        notif.getSbn().getNotification().flags =
                Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
        mService.addNotification(notif);
        // Adds a second, non-lifetime extended notification.
        final NotificationRecord notifCancelable = generateNotificationRecord(
                mTestNotificationChannel, 2, null, false);
        mService.addNotification(notifCancelable);
        // Verify that both notifications have been posted and are active.
        assertThat(mBinderService.getActiveNotifications(PKG).length).isEqualTo(2);
        mBinderService.cancelAllNotifications(PKG, notif.getSbn().getUserId());
        waitForIdle();
        // The non-lifetime extended notification, with id = 2, has been cancelled.
        StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
        assertThat(notifs.length).isEqualTo(1);
        assertThat(notifs[0].getId()).isEqualTo(1);
    }
    @Test
    public void testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()
            throws Exception {
@@ -2831,6 +2898,24 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, notifs.length);
    }
    @Test
    public void testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt()
            throws Exception {
        mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
        final NotificationRecord notif = generateNotificationRecord(
                mTestNotificationChannel, 1, null, false);
        notif.getNotification().flags = FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
        mService.addNotification(notif);
        mService.getBinderService().cancelNotificationsFromListener(null, null);
        waitForIdle();
        StatusBarNotification[] notifs =
                mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
        assertThat(notifs.length).isEqualTo(1);
    }
    @Test
    public void testCancelNotificationsFromListener_byKey_GroupWithOngoingParent()
            throws Exception {
@@ -3035,6 +3120,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, notifs.length);
    }
    @Test
    public void testCancelNotificationsFromListener_byKey_NoClearLifetimeExt()
            throws Exception {
        mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
        final NotificationRecord notif = generateNotificationRecord(
                mTestNotificationChannel, 3, null, false);
        notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
        mService.addNotification(notif);
        String[] keys = {notif.getSbn().getKey()};
        mService.getBinderService().cancelNotificationsFromListener(null, keys);
        waitForIdle();
        StatusBarNotification[] notifs =
                mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
        assertEquals(1, notifs.length);
    }
    @Test
    public void testGroupInstanceIds() throws Exception {
        final NotificationRecord group1 = generateNotificationRecord(
@@ -5298,6 +5399,79 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                anyInt());
    }
    private void simulateNotificationTimeoutBroadcast(String notificationKey) {
        final Bundle extras = new Bundle();
        extras.putString(EXTRA_KEY, notificationKey);
        final Intent intent = new Intent(ACTION_NOTIFICATION_TIMEOUT);
        intent.putExtras(extras);
        mNotificationTimeoutReceiver.onReceive(getContext(), intent);
    }
    @Test
    public void testTimeout_CancelsNotification() throws Exception {
        final NotificationRecord notif = generateNotificationRecord(
                mTestNotificationChannel, 1, null, false);
        mService.addNotification(notif);
        simulateNotificationTimeoutBroadcast(notif.getKey());
        waitForIdle();
        // Check that the notification was cancelled.
        StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
        assertThat(notifsAfter.length).isEqualTo(0);
        assertThat(mService.getNotificationRecord(notif.getKey())).isNull();
    }
    @Test
    public void testTimeout_NoCancelForegroundServiceNotification() throws Exception {
        // Creates a notification with FLAG_FOREGROUND_SERVICE
        final NotificationRecord notif = generateNotificationRecord(null);
        notif.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
        mService.addNotification(notif);
        simulateNotificationTimeoutBroadcast(notif.getKey());
        waitForIdle();
        // Check that the notification was not cancelled.
        StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
        assertThat(notifsAfter.length).isEqualTo(1);
        assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
    }
    @Test
    public void testTimeout_NoCancelUserInitJobNotification() throws Exception {
        // Create a notification with FLAG_USER_INITIATED_JOB
        final NotificationRecord notif = generateNotificationRecord(null);
        notif.getSbn().getNotification().flags = Notification.FLAG_USER_INITIATED_JOB;
        mService.addNotification(notif);
        simulateNotificationTimeoutBroadcast(notif.getKey());
        waitForIdle();
        // Check that the notification was not cancelled.
        StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
        assertThat(notifsAfter.length).isEqualTo(1);
        assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
    }
    @Test
    public void testTimeout_NoCancelLifetimeExtensionNotification() throws Exception {
        mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
        // Create a notification with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY
        final NotificationRecord notif = generateNotificationRecord(null);
        notif.getSbn().getNotification().flags =
                Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
        mService.addNotification(notif);
        simulateNotificationTimeoutBroadcast(notif.getKey());
        waitForIdle();
        // Check that the notification was not cancelled.
        StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
        assertThat(notifsAfter.length).isEqualTo(1);
        assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif);
    }
    @Test
    public void testBumpFGImportance_channelChangePreOApp() throws Exception {
        String preOPkg = PKG_N_MR1;
@@ -7913,6 +8087,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    @Test
    public void testOnNotificationSmartReplySent() {
        mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
        final int replyIndex = 2;
        final String reply = "Hello";
        final boolean modifiedBeforeSending = true;
@@ -7930,6 +8105,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(1, mNotificationRecordLogger.numCalls());
        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED,
                mNotificationRecordLogger.event(0));
        // Check that r.recordSmartReplied was called.
        assertThat(r.getSbn().getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY)
                .isGreaterThan(0);
        assertThat(r.getStats().hasSmartReplied()).isTrue();
    }
    @Test
@@ -13116,6 +13295,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                eq("package"), anyString(), anyInt(), anyBoolean());
    }
    @Test
    public void testFixNotification_clearsLifetimeExtendedFlag() throws Exception {
        mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
        Notification n = new Notification.Builder(mContext, "test")
                .setFlag(FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true)
                .build();
        assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
        mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
        assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0);
    }
    private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
            throws RemoteException {
        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, testName, mUid, 0,