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

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

Merge "Log assistant notification cancels accordingly."

parents 29cf9f62 ef3f660d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -38864,6 +38864,7 @@ package android.service.notification {
    field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
    field public static final int REASON_APP_CANCEL = 8; // 0x8
    field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
    field public static final int REASON_ASSISTANT_CANCEL = 22; // 0x16
    field public static final int REASON_CANCEL = 2; // 0x2
    field public static final int REASON_CANCEL_ALL = 3; // 0x3
    field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
+6 −1
Original line number Diff line number Diff line
@@ -256,6 +256,8 @@ public abstract class NotificationListenerService extends Service {
    public static final int REASON_CHANNEL_REMOVED = 20;
    /** Notification was canceled due to the app's storage being cleared */
    public static final int REASON_CLEAR_DATA = 21;
    /** Notification was canceled due to an assistant adjustment update. */
    public static final int REASON_ASSISTANT_CANCEL = 22;

    /**
     * @hide
@@ -279,7 +281,10 @@ public abstract class NotificationListenerService extends Service {
            REASON_UNAUTOBUNDLED,
            REASON_CHANNEL_BANNED,
            REASON_SNOOZED,
            REASON_TIMEOUT
            REASON_TIMEOUT,
            REASON_CHANNEL_REMOVED,
            REASON_CLEAR_DATA,
            REASON_ASSISTANT_CANCEL,
    })
    public @interface NotificationCancelReason{};

+31 −4
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ import static android.service.notification.NotificationListenerService.NOTIFICAT
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
@@ -476,6 +477,14 @@ public class NotificationManagerService extends SystemService {
    @LoggingOnly
    private static final long RATE_LIMIT_TOASTS = 174840628L;
    /**
     * Whether listeners understand the more specific reason provided for notification
     * cancellations from an assistant, rather than using the more general REASON_LISTENER_CANCEL.
     */
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
    private static final long NOTIFICATION_LOG_ASSISTANT_CANCEL = 195579280L;
    private IActivityManager mAm;
    private ActivityTaskManagerInternal mAtm;
    private ActivityManager mActivityManager;
@@ -4388,6 +4397,13 @@ public class NotificationManagerService extends SystemService {
                synchronized (mNotificationLock) {
                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                    // Cancellation reason. If the token comes from assistant, label the
                    // cancellation as coming from the assistant; default to LISTENER_CANCEL.
                    int reason = REASON_LISTENER_CANCEL;
                    if (mAssistants.isServiceTokenValidLocked(token)) {
                        reason = REASON_ASSISTANT_CANCEL;
                    }
                    if (keys != null) {
                        final int N = keys.length;
                        for (int i = 0; i < N; i++) {
@@ -4400,7 +4416,7 @@ public class NotificationManagerService extends SystemService {
                            }
                            cancelNotificationFromListenerLocked(info, callingUid, callingPid,
                                    r.getSbn().getPackageName(), r.getSbn().getTag(),
                                    r.getSbn().getId(), userId);
                                    r.getSbn().getId(), userId, reason);
                        }
                    } else {
                        cancelAllLocked(callingUid, callingPid, info.userid,
@@ -4494,12 +4510,13 @@ public class NotificationManagerService extends SystemService {
         */
        @GuardedBy("mNotificationLock")
        private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
                int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
                int callingUid, int callingPid, String pkg, String tag, int id, int userId,
                int reason) {
            int mustNotHaveFlags = FLAG_ONGOING_EVENT;
            cancelNotification(callingUid, callingPid, pkg, tag, id, 0 /* mustHaveFlags */,
                    mustNotHaveFlags,
                    true,
                    userId, REASON_LISTENER_CANCEL, info);
                    userId, reason, info);
        }
        /**
@@ -4641,13 +4658,17 @@ public class NotificationManagerService extends SystemService {
            try {
                synchronized (mNotificationLock) {
                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                    int cancelReason = REASON_LISTENER_CANCEL;
                    if (mAssistants.isServiceTokenValidLocked(token)) {
                        cancelReason = REASON_ASSISTANT_CANCEL;
                    }
                    if (info.supportsProfiles()) {
                        Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
                                + "from " + info.component
                                + " use cancelNotification(key) instead.");
                    } else {
                        cancelNotificationFromListenerLocked(info, callingUid, callingPid,
                                pkg, tag, id, info.userid);
                                pkg, tag, id, info.userid, cancelReason);
                    }
                }
            } finally {
@@ -11049,6 +11070,12 @@ public class NotificationManagerService extends SystemService {
                        && (reason == REASON_CHANNEL_REMOVED || reason == REASON_CLEAR_DATA)) {
                    reason = REASON_CHANNEL_BANNED;
                }
                // apps before T don't know about REASON_ASSISTANT, so replace it with the
                // previously-used case, REASON_LISTENER_CANCEL
                if (!CompatChanges.isChangeEnabled(NOTIFICATION_LOG_ASSISTANT_CANCEL, info.uid)
                        && reason == REASON_ASSISTANT_CANCEL) {
                    reason = REASON_LISTENER_CANCEL;
                }
                listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
            } catch (RemoteException ex) {
                Slog.e(TAG, "unable to notify listener (removed): " + info, ex);
+7 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.notification;

import static android.service.notification.NotificationListenerService.REASON_ASSISTANT_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
@@ -180,7 +181,9 @@ public interface NotificationRecordLogger {
                + " shade.")
        NOTIFICATION_CANCEL_USER_SHADE(192),
        @UiEvent(doc = "Notification was canceled due to user dismissal from the lockscreen")
        NOTIFICATION_CANCEL_USER_LOCKSCREEN(193);
        NOTIFICATION_CANCEL_USER_LOCKSCREEN(193),
        @UiEvent(doc = "Notification was canceled due to an assistant adjustment update.")
        NOTIFICATION_CANCEL_ASSISTANT(906);

        private final int mId;
        NotificationCancelledEvent(int id) {
@@ -206,6 +209,9 @@ public interface NotificationRecordLogger {
                if ((REASON_CLICK <= reason) && (reason <= REASON_TIMEOUT)) {
                    return NotificationCancelledEvent.values()[reason];
                }
                if (reason == REASON_ASSISTANT_CANCEL) {
                    return NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT;
                }
                if (NotificationManagerService.DBG) {
                    throw new IllegalArgumentException("Unexpected cancel reason " + reason);
                }
+53 −0
Original line number Diff line number Diff line
@@ -4658,6 +4658,59 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(2, mNotificationRecordLogger.get(1).getInstanceId());
    }

    @Test
    public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception {
        NotificationManagerService.WorkerHandler handler = mock(
                NotificationManagerService.WorkerHandler.class);
        mService.setHandler(handler);
        when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
        when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);

        // Set up notifications: r1 is adjusted, r2 is not
        final NotificationRecord r1 = generateNotificationRecord(
                mTestNotificationChannel, 1, null, true);
        r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
        mService.addNotification(r1);
        final NotificationRecord r2 = generateNotificationRecord(
                mTestNotificationChannel, 2, null, true);
        r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
        mService.addNotification(r2);

        // Test an adjustment that sets importance to none (meaning it's cancelling)
        Bundle signals1 = new Bundle();
        signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE);
        Adjustment adjustment1 = new Adjustment(
                r1.getSbn().getPackageName(), r1.getKey(), signals1, "",
                r1.getUser().getIdentifier());

        mBinderService.applyAdjustmentFromAssistant(null, adjustment1);

        // Actually apply the adjustments & recalculate importance when run
        doAnswer(invocationOnMock -> {
            ((NotificationRecord) invocationOnMock.getArguments()[0])
                    .applyAdjustments();
            ((NotificationRecord) invocationOnMock.getArguments()[0])
                    .calculateImportance();
            return null;
        }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));

        // run the CancelNotificationRunnable when it happens
        ArgumentCaptor<NotificationManagerService.CancelNotificationRunnable> captor =
                ArgumentCaptor.forClass(
                        NotificationManagerService.CancelNotificationRunnable.class);

        verify(handler, times(1)).scheduleCancelNotification(
                captor.capture());

        // Run the runnable given to the cancel notification, and see if it logs properly
        NotificationManagerService.CancelNotificationRunnable runnable = captor.getValue();
        runnable.run();
        assertEquals(1, mNotificationRecordLogger.numCalls());
        assertEquals(
                NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT,
                mNotificationRecordLogger.event(0));
    }

    @Test
    public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception {
        final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);