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

Commit 7c8cb67c authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Reject old notifications

Reject notifications with a 'when' that's 2 weeks or older.

An unset when and a when of '0' are special cased and will still be
posted as those appear to users as current notifications

Test: NotificationManagerServiceTest
Flag: com.android.server.notification.reject_old_notifications
Bug: 339833083
Change-Id: I62254e7e86194eda1e6f1a8b5e35181bcb4ecf31
parent a1756dd7
Loading
Loading
Loading
Loading
+45 −15
Original line number Diff line number Diff line
@@ -593,6 +593,8 @@ public class NotificationManagerService extends SystemService {
    static final long NOTIFICATION_TTL = Duration.ofDays(3).toMillis();
    static final long NOTIFICATION_MAX_AGE_AT_POST = Duration.ofDays(14).toMillis();
    private IActivityManager mAm;
    private ActivityTaskManagerInternal mAtm;
    private ActivityManager mActivityManager;
@@ -2637,28 +2639,49 @@ public class NotificationManagerService extends SystemService {
     * Cleanup broadcast receivers change listeners.
     */
    public void onDestroy() {
        if (mIntentReceiver != null) {
            getContext().unregisterReceiver(mIntentReceiver);
        }
        if (mPackageIntentReceiver != null) {
            getContext().unregisterReceiver(mPackageIntentReceiver);
        }
        if (Flags.allNotifsNeedTtl()) {
            if (mTtlHelper != null) {
                mTtlHelper.destroy();
            }
        } else {
            if (mNotificationTimeoutReceiver != null) {
                getContext().unregisterReceiver(mNotificationTimeoutReceiver);
            }
        }
        if (mRestoreReceiver != null) {
            getContext().unregisterReceiver(mRestoreReceiver);
        }
        if (mLocaleChangeReceiver != null) {
            getContext().unregisterReceiver(mLocaleChangeReceiver);
        }
        if (mSettingsObserver != null) {
            mSettingsObserver.destroy();
        }
        if (mRoleObserver != null) {
            mRoleObserver.destroy();
        }
        if (mShortcutHelper != null) {
            mShortcutHelper.destroy();
        }
        if (mStatsManager != null) {
            mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_PREFERENCES);
            mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES);
            mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES);
            mStatsManager.clearPullAtomCallback(DND_MODE_RULE);
        }
        if (mAppOps != null) {
            mAppOps.stopWatchingMode(mAppOpsListener);
        }
        if (mAlarmManager != null) {
            mAlarmManager.cancelAll();
        }
    }
    protected String[] getStringArrayResource(int key) {
        return getContext().getResources().getStringArray(key);
@@ -8016,6 +8039,13 @@ public class NotificationManagerService extends SystemService {
            return false;
        }
        if (Flags.rejectOldNotifications() && n.hasAppProvidedWhen() && n.getWhen() > 0
                && (System.currentTimeMillis() - n.getWhen()) > NOTIFICATION_MAX_AGE_AT_POST) {
            Slog.d(TAG, "Ignored enqueue for old " + n.getWhen() + " notification " + r.getKey());
            mUsageStats.registerTooOldBlocked(r);
            return false;
        }
        return true;
    }
+14 −0
Original line number Diff line number Diff line
@@ -257,6 +257,14 @@ public class NotificationUsageStats {
        }
    }

    public synchronized void registerTooOldBlocked(NotificationRecord notification) {
        AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
        for (AggregatedStats stats : aggregatedStatsArray) {
            stats.numTooOld++;
        }
        releaseAggregatedStatsLocked(aggregatedStatsArray);
    }

    @GuardedBy("this")
    private AggregatedStats[] getAggregatedStatsLocked(NotificationRecord record) {
        return getAggregatedStatsLocked(record.getSbn().getPackageName());
@@ -405,6 +413,7 @@ public class NotificationUsageStats {
        public int numUndecoratedRemoteViews;
        public long mLastAccessTime;
        public int numImagesRemoved;
        public int numTooOld;

        public AggregatedStats(Context context, String key) {
            this.key = key;
@@ -535,6 +544,7 @@ public class NotificationUsageStats {
            maybeCount("note_over_alert_rate", (numAlertViolations - previous.numAlertViolations));
            maybeCount("note_over_quota", (numQuotaViolations - previous.numQuotaViolations));
            maybeCount("note_images_removed", (numImagesRemoved - previous.numImagesRemoved));
            maybeCount("not_too_old", (numTooOld - previous.numTooOld));
            noisyImportance.maybeCount(previous.noisyImportance);
            quietImportance.maybeCount(previous.quietImportance);
            finalImportance.maybeCount(previous.finalImportance);
@@ -570,6 +580,7 @@ public class NotificationUsageStats {
            previous.numAlertViolations = numAlertViolations;
            previous.numQuotaViolations = numQuotaViolations;
            previous.numImagesRemoved = numImagesRemoved;
            previous.numTooOld = numTooOld;
            noisyImportance.update(previous.noisyImportance);
            quietImportance.update(previous.quietImportance);
            finalImportance.update(previous.finalImportance);
@@ -679,6 +690,8 @@ public class NotificationUsageStats {
            output.append("numQuotaViolations=").append(numQuotaViolations).append("\n");
            output.append(indentPlusTwo);
            output.append("numImagesRemoved=").append(numImagesRemoved).append("\n");
            output.append(indentPlusTwo);
            output.append("numTooOld=").append(numTooOld).append("\n");
            output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n");
            output.append(indentPlusTwo).append(quietImportance.toString()).append("\n");
            output.append(indentPlusTwo).append(finalImportance.toString()).append("\n");
@@ -725,6 +738,7 @@ public class NotificationUsageStats {
            maybePut(dump, "notificationEnqueueRate", getEnqueueRate());
            maybePut(dump, "numAlertViolations", numAlertViolations);
            maybePut(dump, "numImagesRemoved", numImagesRemoved);
            maybePut(dump, "numTooOld", numTooOld);
            noisyImportance.maybePut(dump, previous.noisyImportance);
            quietImportance.maybePut(dump, previous.quietImportance);
            finalImportance.maybePut(dump, previous.finalImportance);
+7 −0
Original line number Diff line number Diff line
@@ -135,3 +135,10 @@ flag {
  description: "This flag controls which signal is used to handle a user switch system event"
  bug: "337077643"
}

flag {
  name: "reject_old_notifications"
  namespace: "systemui"
  description: "This flag does not allow notifications older than 2 weeks old to be posted"
  bug: "339833083"
}
 No newline at end of file
+162 −106
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL;
import static com.android.server.notification.Flags.FLAG_REJECT_OLD_NOTIFICATIONS;
import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION;
import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
import static com.android.server.notification.NotificationManagerService.NOTIFICATION_TTL;
@@ -339,6 +340,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -909,7 +911,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        }
        mService.clearNotifications();
        TestableLooper.get(this).processAllMessages();
        if (mTestableLooper != null) {
            mTestableLooper.processAllMessages();
        }
        try {
            mService.onDestroy();
@@ -920,14 +924,16 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        InstrumentationRegistry.getInstrumentation()
                .getUiAutomation().dropShellPermissionIdentity();
        if (mWorkerHandler != null) {
            // Remove scheduled messages that would be processed when the test is already done, and
            // could cause issues, for example, messages that remove/cancel shown toasts (this causes
            // problematic interactions with mocks when they're no longer working as expected).
            mWorkerHandler.removeCallbacksAndMessages(null);
        }
        if (TestableLooper.get(this) != null) {
        if (mTestableLooper != null) {
            // Must remove static reference to this test object to prevent leak (b/261039202)
            TestableLooper.remove(this);
            mTestableLooper.remove(this);
        }
    }
@@ -1009,8 +1015,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    }
    public void waitForIdle() {
        if (mTestableLooper != null) {
            mTestableLooper.processAllMessages();
        }
    }
    private void setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled,
            int pkgPref, boolean channelEnabled) {
@@ -1302,6 +1310,106 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        return nrSummary;
    }
    private NotificationRecord createAndPostCallStyleNotification(String packageName,
            UserHandle userHandle, String testName) throws Exception {
        Person person = new Person.Builder().setName("caller").build();
        Notification.Builder nb = new Notification.Builder(mContext,
                mTestNotificationChannel.getId())
                .setFlag(FLAG_USER_INITIATED_JOB, true)
                .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
                .setSmallIcon(android.R.drawable.sym_def_app_icon);
        StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, 1,
                testName, mUid, 0, nb.build(), userHandle, null, 0);
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        mService.addEnqueuedNotification(r);
        mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
                r.getUid(), mPostNotificationTrackerFactory.newTracker(null)).run();
        waitForIdle();
        return mService.findNotificationLocked(
                packageName, r.getSbn().getTag(), r.getSbn().getId(), r.getSbn().getUserId());
    }
    private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
            throws RemoteException {
        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, testName, mUid, 0,
                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
        waitForIdle();
        return mService.findNotificationLocked(
                mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
    }
    private static <T extends Parcelable> T parcelAndUnparcel(T source,
            Parcelable.Creator<T> creator) {
        Parcel parcel = Parcel.obtain();
        source.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        return creator.createFromParcel(parcel);
    }
    private PendingIntent createPendingIntent(String action) {
        return PendingIntent.getActivity(mContext, 0,
                new Intent(action).setPackage(mContext.getPackageName()),
                PendingIntent.FLAG_MUTABLE);
    }
    private void allowTestPackageToToast() throws Exception {
        assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty();
        mService.isSystemUid = false;
        mService.isSystemAppId = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false);
        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId))
                .thenReturn(false);
    }
    private boolean enqueueToast(String testPackage, ITransientNotification callback)
            throws RemoteException {
        return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(),
                callback);
    }
    private boolean enqueueToast(INotificationManager service, String testPackage,
            IBinder token, ITransientNotification callback) throws RemoteException {
        return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */
                true, DEFAULT_DISPLAY);
    }
    private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException {
        return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY);
    }
    private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext,
            int displayId) throws RemoteException {
        return ((INotificationManager) mService.mService).enqueueTextToast(testPackage,
                new Binder(), text, TOAST_DURATION, isUiContext, displayId,
                /* textCallback= */ null);
    }
    private void mockIsVisibleBackgroundUsersSupported(boolean supported) {
        when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported);
    }
    private void mockIsUserVisible(int displayId, boolean visible) {
        when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible);
    }
    private void mockDisplayAssignedToUser(int displayId) {
        when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId);
    }
    private void verifyToastShownForTestPackage(String text, int displayId) {
        verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(),
                eq(TOAST_DURATION), any(), eq(displayId));
    }
    @Test
    @DisableFlags(FLAG_ALL_NOTIFS_NEED_TTL)
    public void testLimitTimeOutBroadcast() {
@@ -14065,11 +14173,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    public void enqueueUpdate_whenBelowMaxEnqueueRate_accepts() throws Exception {
        // Post the first version.
        Notification original = generateNotificationRecord(null).getNotification();
        original.when = 111;
        original.when = System.currentTimeMillis();
        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId);
        waitForIdle();
        assertThat(mService.mNotificationList).hasSize(1);
        assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(111);
        assertThat(mService.mNotificationList.get(0).getNotification().when)
                .isEqualTo(original.when);
        reset(mUsageStats);
        when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
@@ -14077,7 +14186,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        // Post the update.
        Notification update = generateNotificationRecord(null).getNotification();
        update.when = 222;
        update.when = System.currentTimeMillis() + 111;
        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId);
        waitForIdle();
@@ -14086,18 +14195,19 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        verify(mUsageStats, never()).registerPostedByApp(any());
        verify(mUsageStats).registerUpdatedByApp(any(), any());
        assertThat(mService.mNotificationList).hasSize(1);
        assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(222);
        assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(update.when);
    }
    @Test
    public void enqueueUpdate_whenAboveMaxEnqueueRate_rejects() throws Exception {
        // Post the first version.
        Notification original = generateNotificationRecord(null).getNotification();
        original.when = 111;
        original.when = System.currentTimeMillis();
        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId);
        waitForIdle();
        assertThat(mService.mNotificationList).hasSize(1);
        assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(111);
        assertThat(mService.mNotificationList.get(0).getNotification().when)
                .isEqualTo(original.when);
        reset(mUsageStats);
        when(mUsageStats.getAppEnqueueRate(eq(mPkg)))
@@ -14105,7 +14215,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        // Post the update.
        Notification update = generateNotificationRecord(null).getNotification();
        update.when = 222;
        update.when = System.currentTimeMillis() + 111;
        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId);
        waitForIdle();
@@ -14114,7 +14224,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        verify(mUsageStats, never()).registerPostedByApp(any());
        verify(mUsageStats, never()).registerUpdatedByApp(any(), any());
        assertThat(mService.mNotificationList).hasSize(1);
        assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(111); // old
        assertThat(mService.mNotificationList.get(0).getNotification().when)
                .isEqualTo(original.when); // old
    }
    @Test
@@ -15479,103 +15590,48 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertThat(n.getTimeoutAfter()).isEqualTo(20);
    }
    private NotificationRecord createAndPostCallStyleNotification(String packageName,
            UserHandle userHandle, String testName) throws Exception {
        Person person = new Person.Builder().setName("caller").build();
        Notification.Builder nb = new Notification.Builder(mContext,
                mTestNotificationChannel.getId())
                .setFlag(FLAG_USER_INITIATED_JOB, true)
                .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent))
                .setSmallIcon(android.R.drawable.sym_def_app_icon);
        StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, 1,
                testName, mUid, 0, nb.build(), userHandle, null, 0);
    @Test
    @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
    public void testRejectOldNotification_oldWhen() throws Exception {
        Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setWhen(System.currentTimeMillis() - Duration.ofDays(15).toMillis())
                .build();
        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
                n, UserHandle.getUserHandleForUid(mUid), null, 0);
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        mService.addEnqueuedNotification(r);
        mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
                r.getUid(), mPostNotificationTrackerFactory.newTracker(null)).run();
        waitForIdle();
        return mService.findNotificationLocked(
                packageName, r.getSbn().getTag(), r.getSbn().getId(), r.getSbn().getUserId());
    }
    private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
            throws RemoteException {
        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, testName, mUid, 0,
                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(),
                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
        waitForIdle();
        return mService.findNotificationLocked(
                mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
    }
    private static <T extends Parcelable> T parcelAndUnparcel(T source,
            Parcelable.Creator<T> creator) {
        Parcel parcel = Parcel.obtain();
        source.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        return creator.createFromParcel(parcel);
    }
    private PendingIntent createPendingIntent(String action) {
        return PendingIntent.getActivity(mContext, 0,
                new Intent(action).setPackage(mContext.getPackageName()),
                PendingIntent.FLAG_MUTABLE);
    }
    private void allowTestPackageToToast() throws Exception {
        assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty();
        mService.isSystemUid = false;
        mService.isSystemAppId = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false);
        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId))
                .thenReturn(false);
    }
    private boolean enqueueToast(String testPackage, ITransientNotification callback)
            throws RemoteException {
        return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(),
                callback);
    }
    private boolean enqueueToast(INotificationManager service, String testPackage,
            IBinder token, ITransientNotification callback) throws RemoteException {
        return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */
                true, DEFAULT_DISPLAY);
    }
    private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException {
        return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY);
    }
    private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext,
            int displayId) throws RemoteException {
        return ((INotificationManager) mService.mService).enqueueTextToast(testPackage,
                new Binder(), text, TOAST_DURATION, isUiContext, displayId,
                /* textCallback= */ null);
        assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
                .isFalse();
    }
    private void mockIsVisibleBackgroundUsersSupported(boolean supported) {
        when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported);
    }
    @Test
    @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
    public void testRejectOldNotification_mediumOldWhen() throws Exception {
        Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setWhen(System.currentTimeMillis() - Duration.ofDays(13).toMillis())
                .build();
        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
                n, UserHandle.getUserHandleForUid(mUid), null, 0);
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
    private void mockIsUserVisible(int displayId, boolean visible) {
        when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible);
        assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
                .isTrue();
    }
    private void mockDisplayAssignedToUser(int displayId) {
        when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId);
    }
    @Test
    @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS)
    public void testRejectOldNotification_zeroWhen() throws Exception {
        Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setWhen(0)
                .build();
        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0,
                n, UserHandle.getUserHandleForUid(mUid), null, 0);
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
    private void verifyToastShownForTestPackage(String text, int displayId) {
        verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(),
                eq(TOAST_DURATION), any(), eq(displayId));
        assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false))
                .isTrue();
    }
}