From 534aef4d05294c045f9095904e2ea4cbadd81c33 Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Wed, 16 Jun 2021 10:57:41 +0200 Subject: [PATCH] Fix bouncer to launcher/app animation This CL ensures that we don't show the keyguard early when unlocking the phone from the bouncer after swiping up on the lockscreen. Bug: 191031464 Test: Manual, swipe up on lockscreen with PIN Change-Id: Id7269189c857e1108a8e33074bb5abfd40437deb --- .../systemui/plugins/ActivityStarter.java | 7 + .../systemui/statusbar/phone/StatusBar.java | 132 +++++++++++------- .../phone/StatusBarKeyguardViewManager.java | 13 +- .../StatusBarNotificationActivityStarter.java | 111 +++++++++------ 4 files changed, 167 insertions(+), 96 deletions(-) diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java index 298b7c38066bc..7c81325d685f8 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java @@ -92,5 +92,12 @@ public interface ActivityStarter { * *after* returning to start hiding the keyguard. */ boolean onDismiss(); + + /** + * Whether running this action when we are locked will start an animation on the keyguard. + */ + default boolean willRunAnimationOnKeyguard() { + return false; + } } } 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 5ee5e489479df..e35875643e273 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -2841,9 +2841,11 @@ public class StatusBar extends SystemUI implements DemoMode, mActivityIntentHelper.wouldLaunchResolverActivity(intent, mLockscreenUserManager.getCurrentUserId()); + boolean animate = + animationController != null && !willLaunchResolverActivity && shouldAnimateLaunch( + true /* isActivityIntent */); ActivityLaunchAnimator.Controller animController = - !willLaunchResolverActivity && shouldAnimateLaunch(true /* isActivityIntent */) - ? wrapAnimationController(animationController, dismissShade) : null; + animate ? wrapAnimationController(animationController, dismissShade) : null; // If we animate, we will dismiss the shade only once the animation is done. This is taken // care of by the StatusBarLaunchAnimationController. @@ -2857,7 +2859,7 @@ public class StatusBar extends SystemUI implements DemoMode, int[] result = new int[]{ActivityManager.START_CANCELED}; mActivityLaunchAnimator.startIntentWithAnimation(animController, - true /* animate */, intent.getPackage(), (adapter) -> { + animate, intent.getPackage(), (adapter) -> { ActivityOptions options = new ActivityOptions( getActivityOptions(mDisplayId, adapter)); options.setDisallowEnterPictureInPictureWhileLaunching( @@ -2907,16 +2909,12 @@ public class StatusBar extends SystemUI implements DemoMode, } }; executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShadeDirectly, - willLaunchResolverActivity, true /* deferred */); + willLaunchResolverActivity, true /* deferred */, animate); } @Nullable private ActivityLaunchAnimator.Controller wrapAnimationController( - @Nullable ActivityLaunchAnimator.Controller animationController, boolean dismissShade) { - if (animationController == null) { - return null; - } - + ActivityLaunchAnimator.Controller animationController, boolean dismissShade) { View rootView = animationController.getLaunchContainer().getRootView(); if (rootView == mSuperStatusBarViewFactory.getStatusBarWindowView()) { // We are animating a view in the status bar. We have to make sure that the status bar @@ -2959,34 +2957,56 @@ public class StatusBar extends SystemUI implements DemoMode, final boolean dismissShade, final boolean afterKeyguardGone, final boolean deferred) { - dismissKeyguardThenExecute(() -> { - if (runnable != null) { - if (mStatusBarKeyguardViewManager.isShowing() - && mStatusBarKeyguardViewManager.isOccluded()) { - mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); - } else { - AsyncTask.execute(runnable); - } - } - if (dismissShade) { - if (mExpandedVisible && !mBouncerShowing) { - mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, - true /* force */, true /* delayed*/); - } else { + executeRunnableDismissingKeyguard(runnable, cancelAction, dismissShade, afterKeyguardGone, + deferred, false /* willAnimateOnKeyguard */); + } - // Do it after DismissAction has been processed to conserve the needed ordering. - mHandler.post(mShadeController::runPostCollapseRunnables); + public void executeRunnableDismissingKeyguard(final Runnable runnable, + final Runnable cancelAction, + final boolean dismissShade, + final boolean afterKeyguardGone, + final boolean deferred, + final boolean willAnimateOnKeyguard) { + OnDismissAction onDismissAction = new OnDismissAction() { + @Override + public boolean onDismiss() { + if (runnable != null) { + if (mStatusBarKeyguardViewManager.isShowing() + && mStatusBarKeyguardViewManager.isOccluded()) { + mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); + } else { + AsyncTask.execute(runnable); + } } - } else if (isInLaunchTransition() - && mNotificationPanelViewController.isLaunchTransitionFinished()) { + if (dismissShade) { + if (mExpandedVisible && !mBouncerShowing) { + mShadeController.animateCollapsePanels( + CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, + true /* force */, true /* delayed*/); + } else { - // We are not dismissing the shade, but the launch transition is already finished, - // so nobody will call readyForKeyguardDone anymore. Post it such that - // keyguardDonePending gets called first. - mHandler.post(mStatusBarKeyguardViewManager::readyForKeyguardDone); + // Do it after DismissAction has been processed to conserve the needed + // ordering. + mHandler.post(mShadeController::runPostCollapseRunnables); + } + } else if (StatusBar.this.isInLaunchTransition() + && mNotificationPanelViewController.isLaunchTransitionFinished()) { + + // We are not dismissing the shade, but the launch transition is already + // finished, + // so nobody will call readyForKeyguardDone anymore. Post it such that + // keyguardDonePending gets called first. + mHandler.post(mStatusBarKeyguardViewManager::readyForKeyguardDone); + } + return deferred; } - return deferred; - }, cancelAction, afterKeyguardGone); + + @Override + public boolean willRunAnimationOnKeyguard() { + return willAnimateOnKeyguard; + } + }; + dismissKeyguardThenExecute(onDismissAction, cancelAction, afterKeyguardGone); } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @@ -4609,28 +4629,37 @@ public class StatusBar extends SystemUI implements DemoMode, * * @param action The action to execute after dismissing the keyguard. * @param collapsePanel Whether we should collapse the panel after dismissing the keyguard. - * @param deferKeyguardDismiss Whether we should defer the keyguard actual dismissal, for - * instance to run animations on the keyguard before hiding it. + * @param willAnimateOnKeyguard Whether {@param action} will run an animation on the keyguard if + * we are locked. */ private void executeActionDismissingKeyguard(Runnable action, boolean afterKeyguardGone, - boolean collapsePanel, boolean deferKeyguardDismiss) { + boolean collapsePanel, boolean willAnimateOnKeyguard) { if (!mDeviceProvisionedController.isDeviceProvisioned()) return; - dismissKeyguardThenExecute(() -> { - new Thread(() -> { - try { - // The intent we are sending is for the application, which - // won't have permission to immediately start an activity after - // the user switches to home. We know it is safe to do at this - // point, so make sure new activity switches are now allowed. - ActivityManager.getService().resumeAppSwitches(); - } catch (RemoteException e) { - } - action.run(); - }).start(); + OnDismissAction onDismissAction = new OnDismissAction() { + @Override + public boolean onDismiss() { + new Thread(() -> { + try { + // The intent we are sending is for the application, which + // won't have permission to immediately start an activity after + // the user switches to home. We know it is safe to do at this + // point, so make sure new activity switches are now allowed. + ActivityManager.getService().resumeAppSwitches(); + } catch (RemoteException e) { + } + action.run(); + }).start(); - return collapsePanel ? mShadeController.collapsePanel() : deferKeyguardDismiss; - }, afterKeyguardGone); + return collapsePanel ? mShadeController.collapsePanel() : willAnimateOnKeyguard; + } + + @Override + public boolean willRunAnimationOnKeyguard() { + return willAnimateOnKeyguard; + } + }; + dismissKeyguardThenExecute(onDismissAction, afterKeyguardGone); } @Override @@ -4674,7 +4703,6 @@ public class StatusBar extends SystemUI implements DemoMode, // the animation on the keyguard). The animation will take care of (instantly) collapsing // the shade and hiding the keyguard once it is done. boolean collapse = !animate; - boolean deferKeyguardDismiss = animate; executeActionDismissingKeyguard(() -> { try { // We wrap animationCallback with a StatusBarLaunchAnimatorController so that the @@ -4703,7 +4731,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (intentSentUiThreadCallback != null) { postOnUiThread(intentSentUiThreadCallback); } - }, willLaunchResolverActivity, collapse, deferKeyguardDismiss); + }, willLaunchResolverActivity, collapse, animate); } private void postOnUiThread(Runnable runnable) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index c7efcb2923e73..2601b8b14e1d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -192,6 +192,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private OnDismissAction mAfterKeyguardGoneAction; private Runnable mKeyguardGoneCancelAction; + private boolean mDismissActionWillAnimateOnKeyguard; private final ArrayList mAfterKeyguardGoneRunnables = new ArrayList<>(); // Dismiss action to be launched when we stop dozing or the keyguard is gone. @@ -447,6 +448,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mAfterKeyguardGoneAction = r; mKeyguardGoneCancelAction = cancelAction; + mDismissActionWillAnimateOnKeyguard = r != null && r.willRunAnimationOnKeyguard(); // If there is an an alternate auth interceptor (like the UDFPS), show that one instead // of the bouncer. @@ -625,9 +627,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBouncer.startPreHideAnimation(finishRunnable); mStatusBar.onBouncerPreHideAnimation(); - // startPreHideAnimation() will change the visibility of the bouncer, so we have to - // make sure to update its state. - updateStates(); + // We update the state (which will show the keyguard) only if an animation will run on + // the keyguard. If there is no animation, we wait before updating the state so that we + // go directly from bouncer to launcher/app. + if (mDismissActionWillAnimateOnKeyguard) { + updateStates(); + } } else if (finishRunnable != null) { finishRunnable.run(); } @@ -798,6 +803,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mAfterKeyguardGoneAction = null; } mKeyguardGoneCancelAction = null; + mDismissActionWillAnimateOnKeyguard = false; for (int i = 0; i < mAfterKeyguardGoneRunnables.size(); i++) { mAfterKeyguardGoneRunnables.get(i).run(); } @@ -866,6 +872,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb return; // allow bouncer to trigger saved actions } mAfterKeyguardGoneAction = null; + mDismissActionWillAnimateOnKeyguard = false; if (mKeyguardGoneCancelAction != null) { mKeyguardGoneCancelAction.run(); mKeyguardGoneCancelAction = null; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index d93b76646d589..f6e0f51111fec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -260,10 +260,19 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit boolean showOverLockscreen = mKeyguardStateController.isShowing() && intent != null && mActivityIntentHelper.wouldShowOverLockscreen(intent.getIntent(), mLockscreenUserManager.getCurrentUserId()); - ActivityStarter.OnDismissAction postKeyguardAction = - () -> handleNotificationClickAfterKeyguardDismissed( + ActivityStarter.OnDismissAction postKeyguardAction = new ActivityStarter.OnDismissAction() { + @Override + public boolean onDismiss() { + return handleNotificationClickAfterKeyguardDismissed( entry, row, controller, intent, isActivityIntent, animate, showOverLockscreen); + } + + @Override + public boolean willRunAnimationOnKeyguard() { + return animate; + } + }; if (showOverLockscreen) { mIsCollapsingToShowActivityOverLockscreen = true; postKeyguardAction.onDismiss(); @@ -453,53 +462,73 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit public void startNotificationGutsIntent(final Intent intent, final int appUid, ExpandableNotificationRow row) { boolean animate = mStatusBar.shouldAnimateLaunch(true /* isActivityIntent */); - mActivityStarter.dismissKeyguardThenExecute(() -> { - AsyncTask.execute(() -> { - ActivityLaunchAnimator.Controller animationController = - new StatusBarLaunchAnimatorController( - mNotificationAnimationProvider.getAnimatorController(row), - mStatusBar, true /* isActivityIntent */); + ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { + @Override + public boolean onDismiss() { + AsyncTask.execute(() -> { + ActivityLaunchAnimator.Controller animationController = + new StatusBarLaunchAnimatorController( + mNotificationAnimationProvider.getAnimatorController(row), + mStatusBar, true /* isActivityIntent */); - mActivityLaunchAnimator.startIntentWithAnimation( - animationController, animate, intent.getPackage(), - (adapter) -> TaskStackBuilder.create(mContext) - .addNextIntentWithParentStack(intent) - .startActivities(getActivityOptions( - mStatusBar.getDisplayId(), - adapter), - new UserHandle(UserHandle.getUserId(appUid)))); - }); - return true; - }, null, false /* afterKeyguardGone */); + mActivityLaunchAnimator.startIntentWithAnimation( + animationController, animate, intent.getPackage(), + (adapter) -> TaskStackBuilder.create(mContext) + .addNextIntentWithParentStack(intent) + .startActivities(getActivityOptions( + mStatusBar.getDisplayId(), + adapter), + new UserHandle(UserHandle.getUserId(appUid)))); + }); + return true; + } + + @Override + public boolean willRunAnimationOnKeyguard() { + return animate; + } + }; + mActivityStarter.dismissKeyguardThenExecute(onDismissAction, null, + false /* afterKeyguardGone */); } @Override public void startHistoryIntent(View view, boolean showHistory) { boolean animate = mStatusBar.shouldAnimateLaunch(true /* isActivityIntent */); - mActivityStarter.dismissKeyguardThenExecute(() -> { - AsyncTask.execute(() -> { - Intent intent = showHistory ? new Intent( - Settings.ACTION_NOTIFICATION_HISTORY) : new Intent( - Settings.ACTION_NOTIFICATION_SETTINGS); - TaskStackBuilder tsb = TaskStackBuilder.create(mContext) - .addNextIntent(new Intent(Settings.ACTION_NOTIFICATION_SETTINGS)); - if (showHistory) { - tsb.addNextIntent(intent); - } + ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { + @Override + public boolean onDismiss() { + AsyncTask.execute(() -> { + Intent intent = showHistory ? new Intent( + Settings.ACTION_NOTIFICATION_HISTORY) : new Intent( + Settings.ACTION_NOTIFICATION_SETTINGS); + TaskStackBuilder tsb = TaskStackBuilder.create(mContext) + .addNextIntent(new Intent(Settings.ACTION_NOTIFICATION_SETTINGS)); + if (showHistory) { + tsb.addNextIntent(intent); + } - ActivityLaunchAnimator.Controller animationController = - new StatusBarLaunchAnimatorController( - ActivityLaunchAnimator.Controller.fromView(view), mStatusBar, - true /* isActivityIntent */); + ActivityLaunchAnimator.Controller animationController = + new StatusBarLaunchAnimatorController( + ActivityLaunchAnimator.Controller.fromView(view), mStatusBar, + true /* isActivityIntent */); - mActivityLaunchAnimator.startIntentWithAnimation(animationController, animate, - intent.getPackage(), - (adapter) -> tsb.startActivities( - getActivityOptions(mStatusBar.getDisplayId(), adapter), - UserHandle.CURRENT)); - }); - return true; - }, null, false /* afterKeyguardGone */); + mActivityLaunchAnimator.startIntentWithAnimation(animationController, animate, + intent.getPackage(), + (adapter) -> tsb.startActivities( + getActivityOptions(mStatusBar.getDisplayId(), adapter), + UserHandle.CURRENT)); + }); + return true; + } + + @Override + public boolean willRunAnimationOnKeyguard() { + return animate; + } + }; + mActivityStarter.dismissKeyguardThenExecute(onDismissAction, null, + false /* afterKeyguardGone */); } private void removeHunAfterClick(ExpandableNotificationRow row) {