diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index 82ad00ad7c6da..2e75395cb5c13 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -30,6 +30,8 @@ import android.util.Log; import android.view.accessibility.AccessibilityManager; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.statusbar.AlertingNotificationManager; @@ -60,9 +62,28 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { private final ArrayMap mSnoozedPackages; private final AccessibilityManagerWrapper mAccessibilityMgr; + private final UiEventLogger mUiEventLogger; + + /** + * Enum entry for notification peek logged from this class. + */ + enum NotificationPeekEvent implements UiEventLogger.UiEventEnum { + @UiEvent(doc = "Heads-up notification peeked on screen.") + NOTIFICATION_PEEK(801); + + private final int mId; + NotificationPeekEvent(int id) { + mId = id; + } + @Override public int getId() { + return mId; + } + } + public HeadsUpManager(@NonNull final Context context) { mContext = context; mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class); + mUiEventLogger = Dependency.get(UiEventLogger.class); Resources resources = context.getResources(); mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time); mAutoDismissNotificationDecay = resources.getInteger(R.integer.heads_up_notification_decay); @@ -130,6 +151,11 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { if (entry.isRowPinned() != isPinned) { entry.setRowPinned(isPinned); updatePinnedMode(); + if (isPinned && entry.getSbn() != null) { + mUiEventLogger.logWithInstanceId( + NotificationPeekEvent.NOTIFICATION_PEEK, entry.getSbn().getUid(), + entry.getSbn().getPackageName(), entry.getSbn().getInstanceId()); + } for (OnHeadsUpChangedListener listener : mListeners) { if (isPinned) { listener.onHeadsUpPinned(entry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java index 0e4b053833b97..d72f43272e8cf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.policy; import static com.google.common.truth.Truth.assertThat; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -25,12 +26,16 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import android.app.Notification; +import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.AlertingNotificationManagerTest; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; @@ -49,6 +54,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest { private AccessibilityManagerWrapper mAccessibilityMgr; private HeadsUpManager mHeadsUpManager; private boolean mLivesPastNormalTime; + private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake(); private final class TestableHeadsUpManager extends HeadsUpManager { TestableHeadsUpManager(Context context) { @@ -65,6 +71,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest { @Before public void setUp() { mAccessibilityMgr = mDependency.injectMockDependency(AccessibilityManagerWrapper.class); + mDependency.injectTestDependency(UiEventLogger.class, mUiEventLoggerFake); mHeadsUpManager = new TestableHeadsUpManager(mContext); super.setUp(); @@ -108,5 +115,28 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest { assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0); assertThat(activeRemoteInput.compareTo(ongoingCall)).isGreaterThan(0); } -} + @Test + public void testPinEntry_logsPeek() { + // Needs full screen intent in order to be pinned + final PendingIntent fullScreenIntent = PendingIntent.getActivity(mContext, 0, + new Intent(), PendingIntent.FLAG_MUTABLE); + + HeadsUpManager.HeadsUpEntry entryToPin = mHeadsUpManager.new HeadsUpEntry(); + entryToPin.setEntry(new NotificationEntryBuilder() + .setSbn(createNewSbn(0, + new Notification.Builder(mContext, "") + .setFullScreenIntent(fullScreenIntent, true))) + .build()); + // Note: the standard way to show a notification would be calling showNotification rather + // than onAlertEntryAdded. However, in practice showNotification in effect adds + // the notification and then updates it; in order to not log twice, the entry needs + // to have a functional ExpandableNotificationRow that can keep track of whether it's + // pinned or not (via isRowPinned()). That feels like a lot to pull in to test this one bit. + mHeadsUpManager.onAlertEntryAdded(entryToPin); + + assertEquals(1, mUiEventLoggerFake.numLogs()); + assertEquals(HeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(), + mUiEventLoggerFake.eventId(0)); + } +}