Loading core/java/android/service/notification/NotificationListenerService.java +26 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,32 @@ public abstract class NotificationListenerService extends Service { /** Notification was canceled due to timeout */ public static final int REASON_TIMEOUT = 19; /** * @hide */ @IntDef(prefix = "REASON_", value = { REASON_CLICK, REASON_CANCEL, REASON_CANCEL_ALL, REASON_ERROR, REASON_PACKAGE_CHANGED, REASON_USER_STOPPED, REASON_PACKAGE_BANNED, REASON_APP_CANCEL, REASON_APP_CANCEL_ALL, REASON_LISTENER_CANCEL, REASON_LISTENER_CANCEL_ALL, REASON_GROUP_SUMMARY_CANCELED, REASON_GROUP_OPTIMIZATION, REASON_PACKAGE_SUSPENDED, REASON_PROFILE_TURNED_OFF, REASON_UNAUTOBUNDLED, REASON_CHANNEL_BANNED, REASON_SNOOZED, REASON_TIMEOUT }) public @interface NotificationCancelReason{}; /** * The full trim of the StatusBarNotification including all its features. * Loading core/java/com/android/internal/logging/UiEventLogger.java +2 −2 Original line number Diff line number Diff line Loading @@ -56,8 +56,8 @@ public interface UiEventLogger { * @param event an enum implementing UiEventEnum interface. * @param uid the uid of the relevant app, if known (0 otherwise). * @param packageName the package name of the relevant app, if known (null otherwise). * @param instance An identifier obtained from an InstanceIdSequence. * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log(). */ void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName, @NonNull InstanceId instance); @Nullable InstanceId instance); } core/java/com/android/internal/logging/UiEventLoggerImpl.java +3 −1 Original line number Diff line number Diff line Loading @@ -41,9 +41,11 @@ public class UiEventLoggerImpl implements UiEventLogger { public void logWithInstanceId(UiEventEnum event, int uid, String packageName, InstanceId instance) { final int eventID = event.getId(); if (eventID > 0) { if ((eventID > 0) && (instance != null)) { FrameworkStatsLog.write(FrameworkStatsLog.UI_EVENT_REPORTED, eventID, uid, packageName, instance.getId()); } else { log(event, uid, packageName); } } } services/core/java/com/android/server/notification/NotificationManagerService.java +8 −2 Original line number Diff line number Diff line Loading @@ -7463,13 +7463,15 @@ public class NotificationManagerService extends SystemService { } @GuardedBy("mNotificationLock") private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason, private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, @NotificationListenerService.NotificationCancelReason int reason, boolean wasPosted, String listenerName) { cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName); } @GuardedBy("mNotificationLock") private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason, private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, @NotificationListenerService.NotificationCancelReason int reason, int rank, int count, boolean wasPosted, String listenerName) { final String canceledKey = r.getKey(); Loading Loading @@ -7587,6 +7589,10 @@ public class NotificationManagerService extends SystemService { EventLogTags.writeNotificationCanceled(canceledKey, reason, r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), rank, count, listenerName); if (wasPosted) { mNotificationRecordLogger.logNotificationCancelled(r, reason, r.getStats().getDismissalSurface()); } } @VisibleForTesting Loading services/core/java/com/android/server/notification/NotificationRecordLogger.java +134 −10 Original line number Diff line number Diff line Loading @@ -16,10 +16,16 @@ package com.android.server.notification; import static android.service.notification.NotificationListenerService.REASON_CANCEL; import static android.service.notification.NotificationListenerService.REASON_CLICK; import static android.service.notification.NotificationListenerService.REASON_TIMEOUT; import android.annotation.Nullable; import android.app.Notification; import android.app.Person; import android.os.Bundle; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationStats; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; Loading @@ -43,23 +49,145 @@ public interface NotificationRecordLogger { void logNotificationReported(@Nullable NotificationRecord r, @Nullable NotificationRecord old, int position, int buzzBeepBlink); /** * Logs a notification cancel / dismiss event using UiEventReported (event ids from the * NotificationCancelledEvents enum). * @param r The NotificationRecord. If null, no action is taken. * @param reason The reason the notification was canceled. * @param dismissalSurface The surface the notification was dismissed from. */ void logNotificationCancelled(@Nullable NotificationRecord r, @NotificationListenerService.NotificationCancelReason int reason, @NotificationStats.DismissalSurface int dismissalSurface); /** * The UiEvent enums that this class can log. */ enum NotificationReportedEvents implements UiEventLogger.UiEventEnum { INVALID(0), enum NotificationReportedEvent implements UiEventLogger.UiEventEnum { @UiEvent(doc = "New notification enqueued to post") NOTIFICATION_POSTED(162), @UiEvent(doc = "Notification substantially updated") @UiEvent(doc = "Notification substantially updated, or alerted again.") NOTIFICATION_UPDATED(163); private final int mId; NotificationReportedEvents(int id) { NotificationReportedEvent(int id) { mId = id; } @Override public int getId() { return mId; } public static NotificationReportedEvent fromRecordPair(NotificationRecordPair p) { return (p.old != null) ? NotificationReportedEvent.NOTIFICATION_UPDATED : NotificationReportedEvent.NOTIFICATION_POSTED; } } enum NotificationCancelledEvent implements UiEventLogger.UiEventEnum { INVALID(0), @UiEvent(doc = "Notification was canceled due to a notification click.") NOTIFICATION_CANCEL_CLICK(164), @UiEvent(doc = "Notification was canceled due to a user dismissal, surface not specified.") NOTIFICATION_CANCEL_USER_OTHER(165), @UiEvent(doc = "Notification was canceled due to a user dismiss-all (from the notification" + " shade).") NOTIFICATION_CANCEL_USER_CANCEL_ALL(166), @UiEvent(doc = "Notification was canceled due to an inflation error.") NOTIFICATION_CANCEL_ERROR(167), @UiEvent(doc = "Notification was canceled by the package manager modifying the package.") NOTIFICATION_CANCEL_PACKAGE_CHANGED(168), @UiEvent(doc = "Notification was canceled by the owning user context being stopped.") NOTIFICATION_CANCEL_USER_STOPPED(169), @UiEvent(doc = "Notification was canceled by the user banning the package.") NOTIFICATION_CANCEL_PACKAGE_BANNED(170), @UiEvent(doc = "Notification was canceled by the app canceling this specific notification.") NOTIFICATION_CANCEL_APP_CANCEL(171), @UiEvent(doc = "Notification was canceled by the app cancelling all its notifications.") NOTIFICATION_CANCEL_APP_CANCEL_ALL(172), @UiEvent(doc = "Notification was canceled by a listener reporting a user dismissal.") NOTIFICATION_CANCEL_LISTENER_CANCEL(173), @UiEvent(doc = "Notification was canceled by a listener reporting a user dismiss all.") NOTIFICATION_CANCEL_LISTENER_CANCEL_ALL(174), @UiEvent(doc = "Notification was canceled because it was a member of a canceled group.") NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED(175), @UiEvent(doc = "Notification was canceled because it was an invisible member of a group.") NOTIFICATION_CANCEL_GROUP_OPTIMIZATION(176), @UiEvent(doc = "Notification was canceled by the device administrator suspending the " + "package.") NOTIFICATION_CANCEL_PACKAGE_SUSPENDED(177), @UiEvent(doc = "Notification was canceled by the owning managed profile being turned off.") NOTIFICATION_CANCEL_PROFILE_TURNED_OFF(178), @UiEvent(doc = "Autobundled summary notification was canceled because its group was " + "unbundled") NOTIFICATION_CANCEL_UNAUTOBUNDLED(179), @UiEvent(doc = "Notification was canceled by the user banning the channel.") NOTIFICATION_CANCEL_CHANNEL_BANNED(180), @UiEvent(doc = "Notification was snoozed.") NOTIFICATION_CANCEL_SNOOZED(181), @UiEvent(doc = "Notification was canceled due to timeout") NOTIFICATION_CANCEL_TIMEOUT(182), // Values 183-189 reserved for future system dismissal reasons @UiEvent(doc = "Notification was canceled due to user dismissal of a peeking notification.") NOTIFICATION_CANCEL_USER_PEEK(190), @UiEvent(doc = "Notification was canceled due to user dismissal from the always-on display") NOTIFICATION_CANCEL_USER_AOD(191), @UiEvent(doc = "Notification was canceled due to user dismissal from the notification" + " shade.") NOTIFICATION_CANCEL_USER_SHADE(192), @UiEvent(doc = "Notification was canceled due to user dismissal from the lockscreen") NOTIFICATION_CANCEL_USER_LOCKSCREEN(193); private final int mId; NotificationCancelledEvent(int id) { mId = id; } @Override public int getId() { return mId; } public static NotificationCancelledEvent fromCancelReason( @NotificationListenerService.NotificationCancelReason int reason, @NotificationStats.DismissalSurface int surface) { // Shouldn't be possible to get a non-dismissed notification here. if (surface == NotificationStats.DISMISSAL_NOT_DISMISSED) { if (NotificationManagerService.DBG) { throw new IllegalArgumentException("Unexpected surface " + surface); } return INVALID; } // Most cancel reasons do not have a meaningful surface. Reason codes map directly // to NotificationCancelledEvent codes. if (surface == NotificationStats.DISMISSAL_OTHER) { if ((REASON_CLICK <= reason) && (reason <= REASON_TIMEOUT)) { return NotificationCancelledEvent.values()[reason]; } if (NotificationManagerService.DBG) { throw new IllegalArgumentException("Unexpected cancel reason " + reason); } return INVALID; } // User cancels have a meaningful surface, which we differentiate by. See b/149038335 // for caveats. if (reason != REASON_CANCEL) { if (NotificationManagerService.DBG) { throw new IllegalArgumentException("Unexpected cancel with surface " + reason); } return INVALID; } switch (surface) { case NotificationStats.DISMISSAL_PEEK: return NOTIFICATION_CANCEL_USER_PEEK; case NotificationStats.DISMISSAL_AOD: return NOTIFICATION_CANCEL_USER_AOD; case NotificationStats.DISMISSAL_SHADE: return NOTIFICATION_CANCEL_USER_SHADE; default: if (NotificationManagerService.DBG) { throw new IllegalArgumentException("Unexpected surface for user-dismiss " + reason); } return INVALID; } } } /** Loading Loading @@ -88,7 +216,8 @@ public interface NotificationRecordLogger { return true; } return !(Objects.equals(r.getSbn().getChannelIdLogTag(), old.getSbn().getChannelIdLogTag()) return !(Objects.equals(r.getSbn().getChannelIdLogTag(), old.getSbn().getChannelIdLogTag()) && Objects.equals(r.getSbn().getGroupLogTag(), old.getSbn().getGroupLogTag()) && (r.getSbn().getNotification().isGroupSummary() == old.getSbn().getNotification().isGroupSummary()) Loading @@ -97,11 +226,6 @@ public interface NotificationRecordLogger { && (r.getImportance() == old.getImportance())); } NotificationReportedEvents getUiEvent() { return (old != null) ? NotificationReportedEvents.NOTIFICATION_UPDATED : NotificationReportedEvents.NOTIFICATION_POSTED; } /** * @return hash code for the notification style class, or 0 if none exists. */ Loading Loading
core/java/android/service/notification/NotificationListenerService.java +26 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,32 @@ public abstract class NotificationListenerService extends Service { /** Notification was canceled due to timeout */ public static final int REASON_TIMEOUT = 19; /** * @hide */ @IntDef(prefix = "REASON_", value = { REASON_CLICK, REASON_CANCEL, REASON_CANCEL_ALL, REASON_ERROR, REASON_PACKAGE_CHANGED, REASON_USER_STOPPED, REASON_PACKAGE_BANNED, REASON_APP_CANCEL, REASON_APP_CANCEL_ALL, REASON_LISTENER_CANCEL, REASON_LISTENER_CANCEL_ALL, REASON_GROUP_SUMMARY_CANCELED, REASON_GROUP_OPTIMIZATION, REASON_PACKAGE_SUSPENDED, REASON_PROFILE_TURNED_OFF, REASON_UNAUTOBUNDLED, REASON_CHANNEL_BANNED, REASON_SNOOZED, REASON_TIMEOUT }) public @interface NotificationCancelReason{}; /** * The full trim of the StatusBarNotification including all its features. * Loading
core/java/com/android/internal/logging/UiEventLogger.java +2 −2 Original line number Diff line number Diff line Loading @@ -56,8 +56,8 @@ public interface UiEventLogger { * @param event an enum implementing UiEventEnum interface. * @param uid the uid of the relevant app, if known (0 otherwise). * @param packageName the package name of the relevant app, if known (null otherwise). * @param instance An identifier obtained from an InstanceIdSequence. * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log(). */ void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName, @NonNull InstanceId instance); @Nullable InstanceId instance); }
core/java/com/android/internal/logging/UiEventLoggerImpl.java +3 −1 Original line number Diff line number Diff line Loading @@ -41,9 +41,11 @@ public class UiEventLoggerImpl implements UiEventLogger { public void logWithInstanceId(UiEventEnum event, int uid, String packageName, InstanceId instance) { final int eventID = event.getId(); if (eventID > 0) { if ((eventID > 0) && (instance != null)) { FrameworkStatsLog.write(FrameworkStatsLog.UI_EVENT_REPORTED, eventID, uid, packageName, instance.getId()); } else { log(event, uid, packageName); } } }
services/core/java/com/android/server/notification/NotificationManagerService.java +8 −2 Original line number Diff line number Diff line Loading @@ -7463,13 +7463,15 @@ public class NotificationManagerService extends SystemService { } @GuardedBy("mNotificationLock") private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason, private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, @NotificationListenerService.NotificationCancelReason int reason, boolean wasPosted, String listenerName) { cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName); } @GuardedBy("mNotificationLock") private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason, private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, @NotificationListenerService.NotificationCancelReason int reason, int rank, int count, boolean wasPosted, String listenerName) { final String canceledKey = r.getKey(); Loading Loading @@ -7587,6 +7589,10 @@ public class NotificationManagerService extends SystemService { EventLogTags.writeNotificationCanceled(canceledKey, reason, r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), rank, count, listenerName); if (wasPosted) { mNotificationRecordLogger.logNotificationCancelled(r, reason, r.getStats().getDismissalSurface()); } } @VisibleForTesting Loading
services/core/java/com/android/server/notification/NotificationRecordLogger.java +134 −10 Original line number Diff line number Diff line Loading @@ -16,10 +16,16 @@ package com.android.server.notification; import static android.service.notification.NotificationListenerService.REASON_CANCEL; import static android.service.notification.NotificationListenerService.REASON_CLICK; import static android.service.notification.NotificationListenerService.REASON_TIMEOUT; import android.annotation.Nullable; import android.app.Notification; import android.app.Person; import android.os.Bundle; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationStats; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; Loading @@ -43,23 +49,145 @@ public interface NotificationRecordLogger { void logNotificationReported(@Nullable NotificationRecord r, @Nullable NotificationRecord old, int position, int buzzBeepBlink); /** * Logs a notification cancel / dismiss event using UiEventReported (event ids from the * NotificationCancelledEvents enum). * @param r The NotificationRecord. If null, no action is taken. * @param reason The reason the notification was canceled. * @param dismissalSurface The surface the notification was dismissed from. */ void logNotificationCancelled(@Nullable NotificationRecord r, @NotificationListenerService.NotificationCancelReason int reason, @NotificationStats.DismissalSurface int dismissalSurface); /** * The UiEvent enums that this class can log. */ enum NotificationReportedEvents implements UiEventLogger.UiEventEnum { INVALID(0), enum NotificationReportedEvent implements UiEventLogger.UiEventEnum { @UiEvent(doc = "New notification enqueued to post") NOTIFICATION_POSTED(162), @UiEvent(doc = "Notification substantially updated") @UiEvent(doc = "Notification substantially updated, or alerted again.") NOTIFICATION_UPDATED(163); private final int mId; NotificationReportedEvents(int id) { NotificationReportedEvent(int id) { mId = id; } @Override public int getId() { return mId; } public static NotificationReportedEvent fromRecordPair(NotificationRecordPair p) { return (p.old != null) ? NotificationReportedEvent.NOTIFICATION_UPDATED : NotificationReportedEvent.NOTIFICATION_POSTED; } } enum NotificationCancelledEvent implements UiEventLogger.UiEventEnum { INVALID(0), @UiEvent(doc = "Notification was canceled due to a notification click.") NOTIFICATION_CANCEL_CLICK(164), @UiEvent(doc = "Notification was canceled due to a user dismissal, surface not specified.") NOTIFICATION_CANCEL_USER_OTHER(165), @UiEvent(doc = "Notification was canceled due to a user dismiss-all (from the notification" + " shade).") NOTIFICATION_CANCEL_USER_CANCEL_ALL(166), @UiEvent(doc = "Notification was canceled due to an inflation error.") NOTIFICATION_CANCEL_ERROR(167), @UiEvent(doc = "Notification was canceled by the package manager modifying the package.") NOTIFICATION_CANCEL_PACKAGE_CHANGED(168), @UiEvent(doc = "Notification was canceled by the owning user context being stopped.") NOTIFICATION_CANCEL_USER_STOPPED(169), @UiEvent(doc = "Notification was canceled by the user banning the package.") NOTIFICATION_CANCEL_PACKAGE_BANNED(170), @UiEvent(doc = "Notification was canceled by the app canceling this specific notification.") NOTIFICATION_CANCEL_APP_CANCEL(171), @UiEvent(doc = "Notification was canceled by the app cancelling all its notifications.") NOTIFICATION_CANCEL_APP_CANCEL_ALL(172), @UiEvent(doc = "Notification was canceled by a listener reporting a user dismissal.") NOTIFICATION_CANCEL_LISTENER_CANCEL(173), @UiEvent(doc = "Notification was canceled by a listener reporting a user dismiss all.") NOTIFICATION_CANCEL_LISTENER_CANCEL_ALL(174), @UiEvent(doc = "Notification was canceled because it was a member of a canceled group.") NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED(175), @UiEvent(doc = "Notification was canceled because it was an invisible member of a group.") NOTIFICATION_CANCEL_GROUP_OPTIMIZATION(176), @UiEvent(doc = "Notification was canceled by the device administrator suspending the " + "package.") NOTIFICATION_CANCEL_PACKAGE_SUSPENDED(177), @UiEvent(doc = "Notification was canceled by the owning managed profile being turned off.") NOTIFICATION_CANCEL_PROFILE_TURNED_OFF(178), @UiEvent(doc = "Autobundled summary notification was canceled because its group was " + "unbundled") NOTIFICATION_CANCEL_UNAUTOBUNDLED(179), @UiEvent(doc = "Notification was canceled by the user banning the channel.") NOTIFICATION_CANCEL_CHANNEL_BANNED(180), @UiEvent(doc = "Notification was snoozed.") NOTIFICATION_CANCEL_SNOOZED(181), @UiEvent(doc = "Notification was canceled due to timeout") NOTIFICATION_CANCEL_TIMEOUT(182), // Values 183-189 reserved for future system dismissal reasons @UiEvent(doc = "Notification was canceled due to user dismissal of a peeking notification.") NOTIFICATION_CANCEL_USER_PEEK(190), @UiEvent(doc = "Notification was canceled due to user dismissal from the always-on display") NOTIFICATION_CANCEL_USER_AOD(191), @UiEvent(doc = "Notification was canceled due to user dismissal from the notification" + " shade.") NOTIFICATION_CANCEL_USER_SHADE(192), @UiEvent(doc = "Notification was canceled due to user dismissal from the lockscreen") NOTIFICATION_CANCEL_USER_LOCKSCREEN(193); private final int mId; NotificationCancelledEvent(int id) { mId = id; } @Override public int getId() { return mId; } public static NotificationCancelledEvent fromCancelReason( @NotificationListenerService.NotificationCancelReason int reason, @NotificationStats.DismissalSurface int surface) { // Shouldn't be possible to get a non-dismissed notification here. if (surface == NotificationStats.DISMISSAL_NOT_DISMISSED) { if (NotificationManagerService.DBG) { throw new IllegalArgumentException("Unexpected surface " + surface); } return INVALID; } // Most cancel reasons do not have a meaningful surface. Reason codes map directly // to NotificationCancelledEvent codes. if (surface == NotificationStats.DISMISSAL_OTHER) { if ((REASON_CLICK <= reason) && (reason <= REASON_TIMEOUT)) { return NotificationCancelledEvent.values()[reason]; } if (NotificationManagerService.DBG) { throw new IllegalArgumentException("Unexpected cancel reason " + reason); } return INVALID; } // User cancels have a meaningful surface, which we differentiate by. See b/149038335 // for caveats. if (reason != REASON_CANCEL) { if (NotificationManagerService.DBG) { throw new IllegalArgumentException("Unexpected cancel with surface " + reason); } return INVALID; } switch (surface) { case NotificationStats.DISMISSAL_PEEK: return NOTIFICATION_CANCEL_USER_PEEK; case NotificationStats.DISMISSAL_AOD: return NOTIFICATION_CANCEL_USER_AOD; case NotificationStats.DISMISSAL_SHADE: return NOTIFICATION_CANCEL_USER_SHADE; default: if (NotificationManagerService.DBG) { throw new IllegalArgumentException("Unexpected surface for user-dismiss " + reason); } return INVALID; } } } /** Loading Loading @@ -88,7 +216,8 @@ public interface NotificationRecordLogger { return true; } return !(Objects.equals(r.getSbn().getChannelIdLogTag(), old.getSbn().getChannelIdLogTag()) return !(Objects.equals(r.getSbn().getChannelIdLogTag(), old.getSbn().getChannelIdLogTag()) && Objects.equals(r.getSbn().getGroupLogTag(), old.getSbn().getGroupLogTag()) && (r.getSbn().getNotification().isGroupSummary() == old.getSbn().getNotification().isGroupSummary()) Loading @@ -97,11 +226,6 @@ public interface NotificationRecordLogger { && (r.getImportance() == old.getImportance())); } NotificationReportedEvents getUiEvent() { return (old != null) ? NotificationReportedEvents.NOTIFICATION_UPDATED : NotificationReportedEvents.NOTIFICATION_POSTED; } /** * @return hash code for the notification style class, or 0 if none exists. */ Loading