From 4be21f873270b855a1e5f87cdbbd7ec0718ad2a8 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 9 Jun 2020 15:42:50 +0800 Subject: [PATCH] Use main executor to run remote animation from notification The pending intent of notification may launch the activity indirectly, e.g. service or receiver. Before the activity is started, the notification may be canceled, then the notification view is detached. And View#post will only put the runnable to a list that will be executed until attach again. So in this case since the notification view is removed, the remote animation is never executed that leads to remote animation timeout and the activity jumps cut without animation. This fix ensures that the handler to animate is valid. Also fix a flickering issue that if activity doesn't draw fast enough (ActivityLaunchAnimator#ANIMATION_DURATION) then the notification panel has started to collapse. The notification view may have clip bottom larger than its actual height, that causes negative crop (as no crop) height of the animating surface. So the first frame will show fully height and then start to animate from the height close to zero. This fix ensures that the crop height is at least zero. Fixes: 158207087 Test: atest ActivityLaunchAnimatorTest Test: Send a notification which will start a service. The service cancels the notification and starts a activity with >500ms delay. Check the launch animation should run smoothly. Change-Id: I78426db1ce295c633271fcaa685b47cc9f697761 --- .../notification/ActivityLaunchAnimator.java | 16 +++++++++++----- .../systemui/statusbar/phone/StatusBar.java | 2 +- .../notification/ActivityLaunchAnimatorTest.java | 7 +++++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java index 6aef6b407f376..6a3302473e63e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java @@ -41,6 +41,8 @@ import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController; +import java.util.concurrent.Executor; + /** * A class that allows activities to be launched in a seamless way where the notification * transforms nicely into the starting window. @@ -59,6 +61,7 @@ public class ActivityLaunchAnimator { private final float mWindowCornerRadius; private final NotificationShadeWindowViewController mNotificationShadeWindowViewController; private final NotificationShadeDepthController mDepthController; + private final Executor mMainExecutor; private Callback mCallback; private final Runnable mTimeoutRunnable = () -> { setAnimationPending(false); @@ -73,12 +76,14 @@ public class ActivityLaunchAnimator { Callback callback, NotificationPanelViewController notificationPanel, NotificationShadeDepthController depthController, - NotificationListContainer container) { + NotificationListContainer container, + Executor mainExecutor) { mNotificationPanel = notificationPanel; mNotificationContainer = container; mDepthController = depthController; mNotificationShadeWindowViewController = notificationShadeWindowViewController; mCallback = callback; + mMainExecutor = mainExecutor; mWindowCornerRadius = ScreenDecorationsUtils .getWindowCornerRadius(mNotificationShadeWindowViewController.getView() .getResources()); @@ -155,7 +160,7 @@ public class ActivityLaunchAnimator { RemoteAnimationTarget[] remoteAnimationWallpaperTargets, IRemoteAnimationFinishedCallback iRemoteAnimationFinishedCallback) throws RemoteException { - mSourceNotification.post(() -> { + mMainExecutor.execute(() -> { RemoteAnimationTarget primary = getPrimaryRemoteAnimationTarget( remoteAnimationTargets); if (primary == null) { @@ -191,8 +196,9 @@ public class ActivityLaunchAnimator { } } int targetWidth = primary.sourceContainerBounds.width(); - int notificationHeight = mSourceNotification.getActualHeight() - - mSourceNotification.getClipBottomAmount(); + // If the notification panel is collapsed, the clip may be larger than the height. + int notificationHeight = Math.max(mSourceNotification.getActualHeight() + - mSourceNotification.getClipBottomAmount(), 0); int notificationWidth = mSourceNotification.getWidth(); anim.setDuration(ANIMATION_DURATION); anim.setInterpolator(Interpolators.LINEAR); @@ -292,7 +298,7 @@ public class ActivityLaunchAnimator { @Override public void onAnimationCancelled() throws RemoteException { - mSourceNotification.post(() -> { + mMainExecutor.execute(() -> { setAnimationPending(false); mCallback.onLaunchAnimationCancelled(); }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 1bc42d1a169d8..e2714af33247b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1275,7 +1275,7 @@ public class StatusBar extends SystemUI implements DemoMode, mActivityLaunchAnimator = new ActivityLaunchAnimator( mNotificationShadeWindowViewController, this, mNotificationPanelViewController, mNotificationShadeDepthControllerLazy.get(), - (NotificationListContainer) mStackScroller); + (NotificationListContainer) mStackScroller, mContext.getMainExecutor()); // TODO: inject this. mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java index cdef49d6c94d2..2fa6cf02d8b46 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java @@ -36,6 +36,8 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Assert; import org.junit.Before; @@ -51,6 +53,7 @@ import org.mockito.junit.MockitoRule; @TestableLooper.RunWithLooper public class ActivityLaunchAnimatorTest extends SysuiTestCase { + private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); private ActivityLaunchAnimator mLaunchAnimator; @Mock private ActivityLaunchAnimator.Callback mCallback; @@ -80,8 +83,8 @@ public class ActivityLaunchAnimatorTest extends SysuiTestCase { mCallback, mNotificationPanelViewController, mNotificationShadeDepthController, - mNotificationContainer); - + mNotificationContainer, + mExecutor); } @Test