diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java index 2a21f421869b8..6cfbb43fa25a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java @@ -320,7 +320,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim * @param updatePostTime whether or not to refresh the post time */ public void updateEntry(boolean updatePostTime) { - mLogger.logUpdateEntry(updatePostTime); + mLogger.logUpdateEntry(mEntry.getKey(), updatePostTime); long currentTime = mClock.currentTimeMillis(); mEarliestRemovaltime = currentTime + mMinimumDisplayTime; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 63cb4ae39a581..5d6d0f701f127 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -424,7 +424,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } @Override - public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) { + public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear, + Runnable onFinishRunnable) { enableAppearDrawing(true); mIsHeadsUpAnimation = isHeadsUpAppear; if (mDrawingAppearAnimation) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index 624e7416d3ee7..4db96935ca401 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -358,7 +358,12 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { Runnable onFinishedRunnable, AnimatorListenerAdapter animationListener); - public abstract void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear); + public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) { + performAddAnimation(delay, duration, isHeadsUpAppear, null); + } + + public abstract void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear, + Runnable onEndRunnable); /** * Set the notification appearance to be below the speed bump. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt index f26598db27a58..ec406f0524ff9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.row import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogLevel.INFO -import com.android.systemui.log.LogLevel.WARNING import com.android.systemui.log.dagger.NotificationLog import javax.inject.Inject @@ -50,7 +49,7 @@ class NotifBindPipelineLogger @Inject constructor( } fun logRequestPipelineRowNotSet(notifKey: String) { - buffer.log(TAG, WARNING, { + buffer.log(TAG, INFO, { str1 = notifKey }, { "Row is not set so pipeline will not run. notif = $str1" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java index 9c755e970a0f8..273e39f0018c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java @@ -238,6 +238,13 @@ public abstract class StackScrollerDecorView extends ExpandableView { setContentVisible(true); } + @Override + public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear, + Runnable endRunnable) { + // TODO: use delay and duration + setContentVisible(true); + } + @Override public boolean needsClippingToShelf() { return false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.java index c9a0f6c428c54..bd5b7d7df5b63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.java @@ -39,7 +39,8 @@ public class MediaContainerView extends ExpandableView { } @Override - public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) { + public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear, + Runnable onEnd) { // No animation, it doesn't need it, this would be local } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 90f5179bc81d1..428334369e21e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -5658,6 +5658,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } } + protected void setLogger(StackStateLogger logger) { + mStateAnimator.setLogger(logger); + } + /** * A listener that is notified when the empty space below the notifications is clicked on */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 5833ec286983b..51ce7792ad086 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -184,6 +184,7 @@ public class NotificationStackScrollLayoutController { private final SectionHeaderController mSilentHeaderController; private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; private final InteractionJankMonitor mJankMonitor; + private final StackStateLogger mStackStateLogger; private NotificationStackScrollLayout mView; private boolean mFadeNotificationsOnDismiss; @@ -660,7 +661,9 @@ public class NotificationStackScrollLayoutController { NotificationRemoteInputManager remoteInputManager, VisualStabilityManager visualStabilityManager, ShadeController shadeController, - InteractionJankMonitor jankMonitor) { + InteractionJankMonitor jankMonitor, + StackStateLogger stackLogger) { + mStackStateLogger = stackLogger; mAllowLongPress = allowLongPress; mNotificationGutsManager = notificationGutsManager; mVisibilityProvider = visibilityProvider; @@ -712,6 +715,7 @@ public class NotificationStackScrollLayoutController { public void attach(NotificationStackScrollLayout view) { mView = view; + mView.setLogger(mStackStateLogger); mView.setController(this); mView.setTouchHandler(new TouchHandler()); mView.setStatusBar(mStatusBar); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java index 1d0d3742bcd82..0d2bddcc8b774 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java @@ -86,6 +86,7 @@ public class StackStateAnimator { private NotificationShelf mShelf; private float mStatusBarIconLocation; private int[] mTmpLocation = new int[2]; + private StackStateLogger mLogger; public StackStateAnimator(NotificationStackScrollLayout hostLayout) { mHostLayout = hostLayout; @@ -113,6 +114,10 @@ public class StackStateAnimator { }; } + protected void setLogger(StackStateLogger logger) { + mLogger = logger; + } + public boolean isRunning() { return !mAnimatorSet.isEmpty(); } @@ -337,6 +342,12 @@ public class StackStateAnimator { ArrayList animationEvents) { for (NotificationStackScrollLayout.AnimationEvent event : animationEvents) { final ExpandableView changingView = (ExpandableView) event.mChangingView; + boolean loggable = false; + String key = null; + if (changingView instanceof ExpandableNotificationRow && mLogger != null) { + loggable = true; + key = ((ExpandableNotificationRow) changingView).getEntry().getKey(); + } if (event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) { @@ -407,10 +418,22 @@ public class StackStateAnimator { if (event.headsUpFromBottom) { mTmpState.yTranslation = mHeadsUpAppearHeightBottom; } else { + Runnable onAnimationEnd = null; + if (loggable) { + String finalKey = key; + onAnimationEnd = () -> mLogger.appearAnimationEnded(finalKey); + } changingView.performAddAnimation(0, ANIMATION_DURATION_HEADS_UP_APPEAR, - true /* isHeadsUpAppear */); + true /* isHeadsUpAppear */, onAnimationEnd); } mHeadsUpAppearChildren.add(changingView); + // this only captures HEADS_UP_APPEAR animations, but HUNs can appear with normal + // ADD animations, which would not be logged here. + if (loggable) { + mLogger.logHUNViewAppearing( + ((ExpandableNotificationRow) changingView).getEntry().getKey()); + } + mTmpState.applyToView(changingView); } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR || @@ -453,10 +476,21 @@ public class StackStateAnimator { // We need to add the global animation listener, since once no animations are // running anymore, the panel will instantly hide itself. We need to wait until // the animation is fully finished for this though. + Runnable postAnimation = endRunnable; + if (loggable) { + mLogger.logHUNViewDisappearing(key); + + Runnable finalEndRunnable = endRunnable; + String finalKey1 = key; + postAnimation = () -> { + mLogger.disappearAnimationEnded(finalKey1); + if (finalEndRunnable != null) finalEndRunnable.run(); + }; + } long removeAnimationDelay = changingView.performRemoveAnimation( ANIMATION_DURATION_HEADS_UP_DISAPPEAR, 0, 0.0f, true /* isHeadsUpAppear */, targetLocation, - endRunnable, getGlobalAnimationFinishedListener()); + postAnimation, getGlobalAnimationFinishedListener()); mAnimationProperties.delay += removeAnimationDelay; } else if (endRunnable != null) { endRunnable.run(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt new file mode 100644 index 0000000000000..4315265e79ccb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt @@ -0,0 +1,44 @@ +package com.android.systemui.statusbar.notification.stack + +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.LogLevel +import com.android.systemui.log.dagger.NotificationHeadsUpLog +import javax.inject.Inject + +class StackStateLogger @Inject constructor( + @NotificationHeadsUpLog private val buffer: LogBuffer +) { + fun logHUNViewDisappearing(key: String) { + buffer.log(TAG, LogLevel.INFO, { + str1 = key + }, { + "Heads up view disappearing $str1 " + }) + } + + fun logHUNViewAppearing(key: String) { + buffer.log(TAG, LogLevel.INFO, { + str1 = key + }, { + "Heads up notification view appearing $str1 " + }) + } + + fun disappearAnimationEnded(key: String) { + buffer.log(TAG, LogLevel.INFO, { + str1 = key + }, { + "Heads up notification disappear animation ended $str1 " + }) + } + + fun appearAnimationEnded(key: String) { + buffer.log(TAG, LogLevel.INFO, { + str1 = key + }, { + "Heads up notification appear animation ended $str1 " + }) + } +} + +private const val TAG = "StackScroll" \ No newline at end of file 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 9587261e75bf2..81ec9ed263a4e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -184,6 +184,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { entry.setHeadsUp(false); setEntryPinned((HeadsUpEntry) alertEntry, false /* isPinned */); EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 0 /* visible */); + mLogger.logNotificationActuallyRemoved(entry.getKey()); for (OnHeadsUpChangedListener listener : mListeners) { listener.onHeadsUpStateChanged(entry, false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt index 2bdf62bbf75b0..6a74ba957b4b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt @@ -73,6 +73,14 @@ class HeadsUpManagerLogger @Inject constructor( }) } + fun logNotificationActuallyRemoved(key: String) { + buffer.log(TAG, INFO, { + str1 = key + }, { + "notification removed $str1 " + }) + } + fun logUpdateNotification(key: String, alert: Boolean, hasEntry: Boolean) { buffer.log(TAG, INFO, { str1 = key @@ -83,11 +91,12 @@ class HeadsUpManagerLogger @Inject constructor( }) } - fun logUpdateEntry(updatePostTime: Boolean) { + fun logUpdateEntry(key: String, updatePostTime: Boolean) { buffer.log(TAG, INFO, { + str1 = key bool1 = updatePostTime }, { - "update entry updatePostTime: $bool1" + "update entry $key updatePostTime: $bool1" }) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index 04c6f6c63927a..86a705f947e3e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -137,6 +137,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Mock private VisualStabilityManager mVisualStabilityManager; @Mock private ShadeController mShadeController; @Mock private InteractionJankMonitor mJankMonitor; + @Mock private StackStateLogger mStackLogger; @Captor private ArgumentCaptor mStateListenerArgumentCaptor; @@ -191,7 +192,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mRemoteInputManager, mVisualStabilityManager, mShadeController, - mJankMonitor + mJankMonitor, + mStackLogger ); when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true); 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 d15ba2615b8ff..d3258408b33a5 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 @@ -23,14 +23,20 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; import android.app.Notification; import android.app.PendingIntent; import android.app.Person; import android.content.Context; import android.content.Intent; +import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -40,12 +46,14 @@ 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.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -58,10 +66,15 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest { private HeadsUpManager mHeadsUpManager; private boolean mLivesPastNormalTime; private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake(); + @Mock private HeadsUpManager.HeadsUpEntry mAlertEntry; + @Mock private NotificationEntry mEntry; + @Mock private StatusBarNotification mSbn; + @Mock private Notification mNotification; + @Mock private HeadsUpManagerLogger mLogger; private final class TestableHeadsUpManager extends HeadsUpManager { - TestableHeadsUpManager(Context context) { - super(context, mock(HeadsUpManagerLogger.class)); + TestableHeadsUpManager(Context context, HeadsUpManagerLogger logger) { + super(context, logger); mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME; mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME; } @@ -73,10 +86,12 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest { @Before public void setUp() { + initMocks(this); mAccessibilityMgr = mDependency.injectMockDependency(AccessibilityManagerWrapper.class); mDependency.injectTestDependency(UiEventLogger.class, mUiEventLoggerFake); - - mHeadsUpManager = new TestableHeadsUpManager(mContext); + when(mEntry.getSbn()).thenReturn(mSbn); + when(mSbn.getNotification()).thenReturn(mNotification); + mHeadsUpManager = new TestableHeadsUpManager(mContext, mLogger); super.setUp(); mHeadsUpManager.mHandler.removeCallbacksAndMessages(null); mHeadsUpManager.mHandler = mTestHandler; @@ -87,6 +102,13 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest { mTestHandler.removeCallbacksAndMessages(null); } + @Test + public void testHunRemovedLogging() { + mAlertEntry.mEntry = mEntry; + mHeadsUpManager.onAlertEntryRemoved(mAlertEntry); + verify(mLogger, times(1)).logNotificationActuallyRemoved(eq(mEntry.getKey())); + } + @Test public void testShowNotification_autoDismissesWithAccessibilityTimeout() { doReturn(TEST_A11Y_AUTO_DISMISS_TIME).when(mAccessibilityMgr)