Expand notif activity starter lifetime extension

Another animation is played while launching the intent for a
notification. This CL moves the onFinishLaunchNotifActivity invocation
until after that animation has ended (or after checking that it won't be
played).

Fixes: 220725343
Test: 1. Install Notify.apk (go/notify-apk)
      2. In the Notify app: Check off Delayed 5000 and Auto Cancel
      3. Click "Add" and spam click "Update" (5-10 times should suffice)
      4. Immediately tap the Notify heads up notification when it gets
         posted
      Observe: no crashing
Change-Id: I13312b4c42b4147fb061db617302cde4b45829ff
This commit is contained in:
Steve Elliott
2022-03-07 16:40:12 -05:00
parent bc08ff0490
commit 4bf10e42b9
4 changed files with 44 additions and 21 deletions

View File

@@ -22,15 +22,18 @@ class NotificationLaunchAnimatorControllerProvider @Inject constructor(
private val headsUpManager: HeadsUpManagerPhone,
private val jankMonitor: InteractionJankMonitor
) {
@JvmOverloads
fun getAnimatorController(
notification: ExpandableNotificationRow
notification: ExpandableNotificationRow,
onFinishAnimationCallback: Runnable = Runnable {}
): NotificationLaunchAnimatorController {
return NotificationLaunchAnimatorController(
notificationShadeWindowViewController,
notificationListContainer,
headsUpManager,
notification,
jankMonitor
jankMonitor,
onFinishAnimationCallback
)
}
}
@@ -45,7 +48,8 @@ class NotificationLaunchAnimatorController(
private val notificationListContainer: NotificationListContainer,
private val headsUpManager: HeadsUpManagerPhone,
private val notification: ExpandableNotificationRow,
private val jankMonitor: InteractionJankMonitor
private val jankMonitor: InteractionJankMonitor,
private val onFinishAnimationCallback: Runnable
) : ActivityLaunchAnimator.Controller {
companion object {
@@ -119,6 +123,7 @@ class NotificationLaunchAnimatorController(
if (!willAnimate) {
removeHun(animate = true)
onFinishAnimationCallback.run()
}
}
@@ -137,6 +142,7 @@ class NotificationLaunchAnimatorController(
notificationShadeWindowViewController.setExpandAnimationRunning(false)
notificationEntry.isExpandAnimationRunning = false
removeHun(animate = true)
onFinishAnimationCallback.run()
}
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -156,6 +162,7 @@ class NotificationLaunchAnimatorController(
notificationListContainer.setExpandingNotification(null)
applyParams(null)
removeHun(animate = false)
onFinishAnimationCallback.run()
}
private fun applyParams(params: ExpandAnimationParameters?) {

View File

@@ -370,6 +370,8 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
mLogger.logExpandingBubble(notificationKey);
removeHunAfterClick(row);
expandBubbleStackOnMainThread(entry);
mMainThreadHandler.post(
() -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
} else {
startNotificationIntent(intent, fillInIntent, entry, row, animate, isActivityIntent);
}
@@ -395,7 +397,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
mMainThreadHandler.post(() -> {
final Runnable removeNotification = () -> {
mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK, summaryToRemove);
mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
};
if (mPresenter.isCollapsing()) {
// To avoid lags we're only performing the remove
@@ -405,9 +406,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
removeNotification.run();
}
});
} else {
mMainThreadHandler.post(
() -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
}
mIsCollapsingToShowActivityOverLockscreen = false;
@@ -483,14 +481,19 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
boolean isActivityIntent) {
mLogger.logStartNotificationIntent(entry.getKey(), intent);
try {
Runnable onFinishAnimationCallback =
() -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
ActivityLaunchAnimator.Controller animationController =
new StatusBarLaunchAnimatorController(
mNotificationAnimationProvider.getAnimatorController(row),
mNotificationAnimationProvider
.getAnimatorController(row, onFinishAnimationCallback),
mCentralSurfaces,
isActivityIntent);
mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
animate, intent.getCreatorPackage(), (adapter) -> {
mActivityLaunchAnimator.startPendingIntentWithAnimation(
animationController,
animate,
intent.getCreatorPackage(),
(adapter) -> {
long eventTime = row.getAndResetLastActionUpTime();
Bundle options = eventTime > 0
? getActivityOptions(

View File

@@ -31,6 +31,7 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
@Mock lateinit var notificationListContainer: NotificationListContainer
@Mock lateinit var headsUpManager: HeadsUpManagerPhone
@Mock lateinit var jankMonitor: InteractionJankMonitor
@Mock lateinit var onFinishAnimationCallback: Runnable
private lateinit var notificationTestHelper: NotificationTestHelper
private lateinit var notification: ExpandableNotificationRow
@@ -52,7 +53,8 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
notificationListContainer,
headsUpManager,
notification,
jankMonitor
jankMonitor,
onFinishAnimationCallback
)
}
@@ -61,7 +63,7 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
}
@Test
fun testHunIsRemovedIfWeDontAnimateLaunch() {
fun testHunIsRemovedAndCallbackIsInvokedIfWeDontAnimateLaunch() {
flagNotificationAsHun()
controller.onIntentStarted(willAnimate = false)
@@ -69,10 +71,11 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
assertFalse(notification.entry.isExpandAnimationRunning)
verify(headsUpManager).removeNotification(
notificationKey, true /* releaseImmediately */, true /* animate */)
verify(onFinishAnimationCallback).run()
}
@Test
fun testHunIsRemovedWhenAnimationIsCancelled() {
fun testHunIsRemovedAndCallbackIsInvokedWhenAnimationIsCancelled() {
flagNotificationAsHun()
controller.onLaunchAnimationCancelled()
@@ -80,10 +83,11 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
assertFalse(notification.entry.isExpandAnimationRunning)
verify(headsUpManager).removeNotification(
notificationKey, true /* releaseImmediately */, true /* animate */)
verify(onFinishAnimationCallback).run()
}
@Test
fun testHunIsRemovedWhenAnimationEnds() {
fun testHunIsRemovedAndCallbackIsInvokedWhenAnimationEnds() {
flagNotificationAsHun()
controller.onLaunchAnimationEnd(isExpandingFullyAbove = true)
@@ -91,6 +95,7 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
assertFalse(notification.entry.isExpandAnimationRunning)
verify(headsUpManager).removeNotification(
notificationKey, true /* releaseImmediately */, false /* animate */)
verify(onFinishAnimationCallback).run()
}
@Test
@@ -99,4 +104,4 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
assertTrue(notification.entry.isExpandAnimationRunning)
}
}
}

View File

@@ -85,6 +85,7 @@ import com.android.systemui.wmshell.BubblesManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
@@ -188,10 +189,11 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
when(mOnUserInteractionCallback.getGroupSummaryToDismiss(mNotificationRow.getEntry()))
.thenReturn(null);
when(mVisibilityProvider.obtain(anyString(), anyBoolean())).thenAnswer(
invocation-> NotificationVisibility.obtain(invocation.getArgument(0), 0, 1, false));
when(mVisibilityProvider.obtain(any(NotificationEntry.class), anyBoolean())).thenAnswer(
invocation-> NotificationVisibility.obtain(
when(mVisibilityProvider.obtain(anyString(), anyBoolean()))
.thenAnswer(invocation -> NotificationVisibility.obtain(
invocation.getArgument(0), 0, 1, false));
when(mVisibilityProvider.obtain(any(NotificationEntry.class), anyBoolean()))
.thenAnswer(invocation -> NotificationVisibility.obtain(
invocation.<NotificationEntry>getArgument(0).getKey(), 0, 1, false));
HeadsUpManagerPhone headsUpManager = mock(HeadsUpManagerPhone.class);
@@ -431,12 +433,18 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
}
@Test
public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse() {
public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse()
throws Exception {
NotifActivityLaunchEvents.Listener listener =
mock(NotifActivityLaunchEvents.Listener.class);
mLaunchEventsEmitter.registerListener(listener);
mNotificationActivityStarter
.onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
ArgumentCaptor<ActivityLaunchAnimator.Controller> controllerCaptor =
ArgumentCaptor.forClass(ActivityLaunchAnimator.Controller.class);
verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(
controllerCaptor.capture(), anyBoolean(), any(), any());
controllerCaptor.getValue().onIntentStarted(false);
verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
}
}