diff options
11 files changed, 112 insertions, 18 deletions
diff --git a/core/java/android/service/notification/NotificationStats.java b/core/java/android/service/notification/NotificationStats.java index 76d5328d2fc5..9e23de1158de 100644 --- a/core/java/android/service/notification/NotificationStats.java +++ b/core/java/android/service/notification/NotificationStats.java @@ -52,7 +52,7 @@ public final class NotificationStats implements Parcelable { /** * Notification has not been dismissed yet. */ - public static final int DISMISSAL_NOT_DISMISSED = -1; + public static final int DISMISSAL_NOT_DISMISSED = -1000; /** * Notification has been dismissed from a {@link NotificationListenerService} or the app * itself. @@ -71,6 +71,37 @@ public final class NotificationStats implements Parcelable { */ public static final int DISMISSAL_SHADE = 3; + /** @hide */ + @IntDef(prefix = { "DISMISS_SENTIMENT_" }, value = { + DISMISS_SENTIMENT_UNKNOWN, DISMISS_SENTIMENT_NEGATIVE, DISMISS_SENTIMENT_NEUTRAL, + DISMISS_SENTIMENT_POSITIVE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DismissalSentiment {} + + /** + * No information is available about why this notification was dismissed, or the notification + * isn't dismissed yet. + */ + public static final int DISMISS_SENTIMENT_UNKNOWN = -1000; + /** + * The user indicated while dismissing that they did not like the notification. + */ + public static final int DISMISS_SENTIMENT_NEGATIVE = 0; + /** + * The user didn't indicate one way or another how they felt about the notification while + * dismissing it. + */ + public static final int DISMISS_SENTIMENT_NEUTRAL = 1; + /** + * The user indicated while dismissing that they did like the notification. + */ + public static final int DISMISS_SENTIMENT_POSITIVE = 2; + + + private @DismissalSentiment + int mDismissalSentiment = DISMISS_SENTIMENT_UNKNOWN; + public NotificationStats() { } @@ -82,6 +113,7 @@ public final class NotificationStats implements Parcelable { mViewedSettings = in.readByte() != 0; mInteracted = in.readByte() != 0; mDismissalSurface = in.readInt(); + mDismissalSentiment = in.readInt(); } @Override @@ -93,6 +125,7 @@ public final class NotificationStats implements Parcelable { dest.writeByte((byte) (mViewedSettings ? 1 : 0)); dest.writeByte((byte) (mInteracted ? 1 : 0)); dest.writeInt(mDismissalSurface); + dest.writeInt(mDismissalSentiment); } @Override @@ -212,6 +245,21 @@ public final class NotificationStats implements Parcelable { mDismissalSurface = dismissalSurface; } + /** + * Records whether the user indicated how they felt about a notification before or + * during dismissal. + */ + public void setDismissalSentiment(@DismissalSentiment int dismissalSentiment) { + mDismissalSentiment = dismissalSentiment; + } + + /** + * Returns how the user indicated they felt about a notification before or during dismissal. + */ + public @DismissalSentiment int getDismissalSentiment() { + return mDismissalSentiment; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index a79e15a0b7e7..b3af147063d0 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -60,7 +60,7 @@ interface IStatusBarService int uid, int initialPid, String message, int userId); void onClearAllNotifications(int userId); void onNotificationClear(String pkg, String tag, int id, int userId, String key, - int dismissalSurface, in NotificationVisibility nv); + int dismissalSurface, int dismissalSentiment, in NotificationVisibility nv); void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys, in NotificationVisibility[] noLongerVisibleKeys); void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded); diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index f0f31fbded6f..3333e1592bfa 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -316,7 +316,7 @@ public class Assistant extends NotificationAssistantService { saveFile(); } } catch (Throwable e) { - Slog.e(TAG, "Error occurred processing removal", e); + Slog.e(TAG, "Error occurred processing removal of " + sbn, e); } } @@ -327,17 +327,21 @@ public class Assistant extends NotificationAssistantService { @Override public void onNotificationsSeen(List<String> keys) { - if (keys == null) { - return; - } + try { + if (keys == null) { + return; + } - for (String key : keys) { - NotificationEntry entry = mLiveNotifications.get(key); + for (String key : keys) { + NotificationEntry entry = mLiveNotifications.get(key); - if (entry != null) { - entry.setSeen(); - mAgingHelper.onNotificationSeen(entry); + if (entry != null) { + entry.setSeen(); + mAgingHelper.onNotificationSeen(entry); + } } + } catch (Throwable e) { + Slog.e(TAG, "Error occurred processing seen", e); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 1393f8fed2ff..b655a6bab5b8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -414,7 +414,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } else if (mListContainer.hasPulsingNotifications()) { dismissalSurface = NotificationStats.DISMISSAL_AOD; } - mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(), dismissalSurface, nv); + int dismissalSentiment = NotificationStats.DISMISS_SENTIMENT_NEUTRAL; + mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(), dismissalSurface, + dismissalSentiment, nv); removeNotification(n.getKey(), null); } catch (RemoteException ex) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 094912b2cdc5..67db68deb928 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -1307,6 +1307,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } setDismissed(fromAccessibility); if (isClearable()) { + // TODO: track dismiss sentiment if (mOnDismissRunnable != null) { mOnDismissRunnable.run(); } diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index 8be8450b3413..decdac6cbfce 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -30,6 +30,7 @@ public interface NotificationDelegate { void onNotificationClear(int callingUid, int callingPid, String pkg, String tag, int id, int userId, String key, @NotificationStats.DismissalSurface int dismissalSurface, + @NotificationStats.DismissalSentiment int dismissalSentiment, NotificationVisibility nv); void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 62b35788c2b8..ce71dd2ec9ad 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -700,7 +700,8 @@ public class NotificationManagerService extends SystemService { } @Override - public void onNotificationClick(int callingUid, int callingPid, String key, NotificationVisibility nv) { + public void onNotificationClick(int callingUid, int callingPid, String key, + NotificationVisibility nv) { exitIdle(); synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); @@ -757,11 +758,13 @@ public class NotificationManagerService extends SystemService { public void onNotificationClear(int callingUid, int callingPid, String pkg, String tag, int id, int userId, String key, @NotificationStats.DismissalSurface int dismissalSurface, + @NotificationStats.DismissalSentiment int dismissalSentiment, NotificationVisibility nv) { synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); if (r != null) { r.recordDismissalSurface(dismissalSurface); + r.recordDismissalSentiment(dismissalSentiment); } } cancelNotification(callingUid, callingPid, pkg, tag, id, 0, @@ -797,8 +800,8 @@ public class NotificationManagerService extends SystemService { } @Override - public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, - int uid, int initialPid, String message, int userId) { + public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, + int id, int uid, int initialPid, String message, int userId) { cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, REASON_ERROR, null); } @@ -5966,6 +5969,7 @@ public class NotificationManagerService extends SystemService { } notificationList.remove(i); mNotificationsByKey.remove(r.getKey()); + r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL); canceledNotifications.add(r); cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName); } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index a6d861565080..fbb42ea160da 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -1065,6 +1065,10 @@ public final class NotificationRecord { mStats.setDismissalSurface(surface); } + public void recordDismissalSentiment(@NotificationStats.DismissalSentiment int sentiment) { + mStats.setDismissalSentiment(sentiment); + } + public void recordSnoozed() { mStats.setSnoozed(); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index f418ad4bf173..b8c9be777fef 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -1053,14 +1053,16 @@ public class StatusBarManagerService extends IStatusBarService.Stub { @Override public void onNotificationClear(String pkg, String tag, int id, int userId, String key, - @NotificationStats.DismissalSurface int dismissalSurface, NotificationVisibility nv) { + @NotificationStats.DismissalSurface int dismissalSurface, + @NotificationStats.DismissalSentiment int dismissalSentiment, + NotificationVisibility nv) { enforceStatusBarService(); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId, - key, dismissalSurface, nv); + key, dismissalSurface, dismissalSentiment, nv); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 4dcb8cf8b327..0ff124e4ce7a 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -2483,13 +2483,29 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.sbn.getTag(), - r.sbn.getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD, nv); + r.sbn.getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD, + NotificationStats.DISMISS_SENTIMENT_POSITIVE, nv); waitForIdle(); assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface()); } @Test + public void testStats_dismissalSentiment() throws Exception { + final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); + mService.addNotification(r); + + final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); + mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.sbn.getTag(), + r.sbn.getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD, + NotificationStats.DISMISS_SENTIMENT_NEGATIVE, nv); + waitForIdle(); + + assertEquals(NotificationStats.DISMISS_SENTIMENT_NEGATIVE, + r.getStats().getDismissalSentiment()); + } + + @Test public void testApplyAdjustmentMultiUser() throws Exception { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addNotification(r); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java index 0a630f462949..bae8564a0694 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java @@ -16,6 +16,8 @@ package com.android.server.notification; import static android.service.notification.NotificationStats.DISMISSAL_PEEK; +import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEGATIVE; +import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_POSITIVE; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -46,6 +48,7 @@ public class NotificationStatsTest extends UiServiceTestCase { assertFalse(stats.hasViewedSettings()); assertFalse(stats.hasSnoozed()); assertEquals(NotificationStats.DISMISSAL_NOT_DISMISSED, stats.getDismissalSurface()); + assertEquals(NotificationStats.DISMISS_SENTIMENT_UNKNOWN, stats.getDismissalSentiment()); } @Test @@ -97,10 +100,19 @@ public class NotificationStatsTest extends UiServiceTestCase { } @Test + public void testDismissalSentiment() { + NotificationStats stats = new NotificationStats(); + stats.setDismissalSentiment(DISMISS_SENTIMENT_NEGATIVE); + assertEquals(DISMISS_SENTIMENT_NEGATIVE, stats.getDismissalSentiment()); + assertFalse(stats.hasInteracted()); + } + + @Test public void testWriteToParcel() { NotificationStats stats = new NotificationStats(); stats.setViewedSettings(); stats.setDismissalSurface(NotificationStats.DISMISSAL_AOD); + stats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_POSITIVE); Parcel parcel = Parcel.obtain(); stats.writeToParcel(parcel, 0); parcel.setDataPosition(0); |