From f1951ce1f7e65be9cfef5cec6ac3bff686758a7d Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 1 Dec 2021 15:55:04 -0800 Subject: [PATCH 1/3] Fix taskbar stash misalignment when going from app to overview Keep taskbar unaligned with hotseat if we're stashing anyway Test: Swipe up from app with taskbar present to overview, check frame by frame to ensure icons morph directly into the handle instead of above it Fixes: 208697792 Change-Id: If3238286b3383e75eb71fbd3b97d34bb3b44340b --- .../taskbar/TaskbarLauncherStateController.java | 12 ++++++++++-- .../launcher3/taskbar/TaskbarStashController.java | 7 +++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index b2c29b2d90..b9fda31c4e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -121,6 +121,7 @@ import java.util.function.Supplier; // If going home, align the icons to hotseat AnimatorSet animatorSet = new AnimatorSet(); + // Update stashed flags first to ensure goingToUnstashedLauncherState() returns correctly. TaskbarStashController stashController = mControllers.taskbarStashController; stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, toState.isTaskbarStashed()); @@ -195,7 +196,8 @@ import java.util.function.Supplier; if (hasAnyFlag(changedFlags, FLAG_RESUMED)) { boolean isResumed = isResumed(); ObjectAnimator anim = mIconAlignmentForResumedState - .animateToValue(isResumed ? 1 : 0) + .animateToValue(isResumed && goingToUnstashedLauncherState() + ? 1 : 0) .setDuration(duration); anim.addListener(new AnimatorListenerAdapter() { @@ -219,7 +221,8 @@ import java.util.function.Supplier; if (hasAnyFlag(changedFlags, FLAG_RECENTS_ANIMATION_RUNNING)) { boolean isRecentsAnimationRunning = isRecentsAnimationRunning(); Animator animator = mIconAlignmentForGestureState - .animateToValue(isRecentsAnimationRunning ? 1 : 0); + .animateToValue(isRecentsAnimationRunning && goingToUnstashedLauncherState() + ? 1 : 0); if (isRecentsAnimationRunning) { animator.setDuration(duration); } @@ -253,6 +256,11 @@ import java.util.function.Supplier; return animatorSet; } + /** Returns whether we're going to a state where taskbar icons should align with launcher. */ + private boolean goingToUnstashedLauncherState() { + return !mControllers.taskbarStashController.isInStashedLauncherState(); + } + private void playStateTransitionAnim(boolean isTransitionStateStashed, AnimatorSet animatorSet, long duration, boolean committed) { TaskbarStashController controller = mControllers.taskbarStashController; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 8965dc4816..a3ad83504c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -216,6 +216,13 @@ public class TaskbarStashController { return hasAnyFlag(FLAGS_STASHED_IN_APP); } + /** + * Returns whether the taskbar should be stashed in the current LauncherState. + */ + public boolean isInStashedLauncherState() { + return hasAnyFlag(FLAG_IN_STASHED_LAUNCHER_STATE) && supportsVisualStashing(); + } + private boolean hasAnyFlag(int flagMask) { return hasAnyFlag(mState, flagMask); } From 9566290e13529563cb57d3cffaab02011f051cef Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 2 Dec 2021 12:26:34 -0800 Subject: [PATCH 2/3] Cleanup some taskbar/hotseat handoff issues - Clearly distinguish Home <-> App icon alignment (ForResumedState and ForGestureState) from Home <-> Home states (ForLauncherState) by renaming onIconAlignmentRatioChanged() to onIconAlignmentRatioChangedForAppAndHomeTransition (for the former) - Make sure initial state is properly applied by treating all flags as changed - onIconAlignmentRatioChangedForStateTransition only runs when launcher is resumed (fixes 208648294) - Animate taskbar background alpha when going between home and app, separate from icon alignment (bug: 204657916) - Only copy hotseat's alpha to taskbar when hotseat is originally visible (also bug: 204657916) Test: Open an app on small screen, open large screen and ensure taskbar stays at the bottom instead of aligning with non-present hotseat (bug: 208648294) Test: Swipe up and down on home scren, ensure taskbar background never appears and there's no jump between taskbar and hotseat Change-Id: Iea59965118f2bdbd8ce49279f76fb01fbd61f60b --- .../TaskbarLauncherStateController.java | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index b9fda31c4e..76088ac638 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -52,10 +52,13 @@ import java.util.function.Supplier; public static final int FLAG_TRANSITION_STATE_START_STASHED = 1 << 2; public static final int FLAG_TRANSITION_STATE_COMMITTED_STASHED = 1 << 3; + /** Equivalent to an int with all 1s for binary operation purposes */ + private static final int FLAGS_ALL = ~0; + private final AnimatedFloat mIconAlignmentForResumedState = - new AnimatedFloat(this::onIconAlignmentRatioChanged); + new AnimatedFloat(this::onIconAlignmentRatioChangedForAppAndHomeTransition); private final AnimatedFloat mIconAlignmentForGestureState = - new AnimatedFloat(this::onIconAlignmentRatioChanged); + new AnimatedFloat(this::onIconAlignmentRatioChangedForAppAndHomeTransition); private final AnimatedFloat mIconAlignmentForLauncherState = new AnimatedFloat(this::onIconAlignmentRatioChangedForStateTransition); @@ -64,7 +67,7 @@ import java.util.function.Supplier; private MultiValueAlpha.AlphaProperty mIconAlphaForHome; private BaseQuickstepLauncher mLauncher; - private int mPrevState; + private Integer mPrevState; private int mState; private boolean mIsAnimatingToLauncherViaGesture; @@ -100,7 +103,7 @@ import java.util.function.Supplier; (Consumer) alpha -> mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1)); mIconAlignmentForResumedState.finishAnimation(); - onIconAlignmentRatioChanged(); + onIconAlignmentRatioChangedForAppAndHomeTransition(); mLauncher.getStateManager().addStateListener(mStateListener); } @@ -183,8 +186,9 @@ import java.util.function.Supplier; public Animator applyState(long duration, boolean start) { Animator animator = null; - if (mPrevState != mState) { - int changedFlags = mPrevState ^ mState; + if (mPrevState == null || mPrevState != mState) { + // If this is our initial state, treat all flags as changed. + int changedFlags = mPrevState == null ? FLAGS_ALL : mPrevState ^ mState; animator = onStateChangeApplied(changedFlags, duration, start); mPrevState = mState; } @@ -240,6 +244,12 @@ import java.util.function.Supplier; animatorSet.play(animator); } + if (hasAnyFlag(changedFlags, FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING)) { + boolean goingToLauncher = hasAnyFlag(FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING); + animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(goingToLauncher ? 0 : 1) + .setDuration(duration)); + } + if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_START_STASHED)) { playStateTransitionAnim(isTransitionStateStartStashed(), animatorSet, duration, false /* committed */); @@ -279,7 +289,9 @@ import java.util.function.Supplier; @Override public void onAnimationStart(Animator animation) { - mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha()); + if (mLauncher.getHotseat().getIconsAlpha() > 0) { + mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha()); + } } }); animatorSet.play(stashAnimator); @@ -306,11 +318,14 @@ import java.util.function.Supplier; } private void onIconAlignmentRatioChangedForStateTransition() { + if (!isResumed()) { + return; + } onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioForLauncherState); } - private void onIconAlignmentRatioChanged() { - onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatio); + private void onIconAlignmentRatioChangedForAppAndHomeTransition() { + onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioBetweenAppAndHome); } private void onIconAlignmentRatioChanged(Supplier alignmentSupplier) { @@ -321,13 +336,11 @@ import java.util.function.Supplier; mControllers.taskbarViewController.setLauncherIconAlignment( alignment, mLauncher.getDeviceProfile()); - mTaskbarBackgroundAlpha.updateValue(1 - alignment); - // Switch taskbar and hotseat in last frame setTaskbarViewVisible(alignment < 1); } - private float getCurrentIconAlignmentRatio() { + private float getCurrentIconAlignmentRatioBetweenAppAndHome() { return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value); } From 24675d36b7fc1dea197b8af179858d7c482b950d Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 24 Nov 2021 15:43:52 -0800 Subject: [PATCH 3/3] Improve quick switch from home to taskbar - Add LauncherState#isTaskbarAlignedWithHotseat() which defaults to !isTaskbarStashed(), but is always false for quick switch from home - Replaced FLAG_TRANSITION_STATE_START_STASHED and FLAG_TRANSITION_STATE_COMMITTED_STASHED with FLAG_STATE_TRANSITION_RUNNING and a reference to mLauncherState. STATE_START is equivalent to TRANSITION_RUNNING changing to true, and STATE_COMMITTED is equivalent to TRANSITION_RUNNING changing to false. Then can get details from the state such as whether taskbar is stashed and icon alignment from mLauncherState Test: quick switch from home, both with taskbar stashed in apps and not Fixes: 194728611 Bug: 204657916 Change-Id: I6cf84ec73a4036e14cc7268667c6f62100884c27 --- .../TaskbarLauncherStateController.java | 62 +++++++++---------- .../uioverrides/states/AllAppsState.java | 2 +- .../uioverrides/states/OverviewState.java | 2 +- .../uioverrides/states/QuickSwitchState.java | 15 +++++ .../NoButtonQuickSwitchTouchController.java | 10 ++- .../android/quickstep/views/RecentsView.java | 5 +- src/com/android/launcher3/LauncherState.java | 8 ++- 7 files changed, 68 insertions(+), 36 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 76088ac638..593bfd8038 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -49,8 +49,7 @@ import java.util.function.Supplier; public static final int FLAG_RESUMED = 1 << 0; public static final int FLAG_RECENTS_ANIMATION_RUNNING = 1 << 1; - public static final int FLAG_TRANSITION_STATE_START_STASHED = 1 << 2; - public static final int FLAG_TRANSITION_STATE_COMMITTED_STASHED = 1 << 3; + public static final int FLAG_TRANSITION_STATE_RUNNING = 1 << 2; /** Equivalent to an int with all 1s for binary operation purposes */ private static final int FLAGS_ALL = ~0; @@ -69,6 +68,7 @@ import java.util.function.Supplier; private Integer mPrevState; private int mState; + private LauncherState mLauncherState = LauncherState.NORMAL; private boolean mIsAnimatingToLauncherViaGesture; private boolean mIsAnimatingToLauncherViaResume; @@ -78,15 +78,20 @@ import java.util.function.Supplier; @Override public void onStateTransitionStart(LauncherState toState) { - updateStateForFlag(FLAG_TRANSITION_STATE_START_STASHED, - toState.isTaskbarStashed()); + if (toState != mLauncherState) { + // Treat FLAG_TRANSITION_STATE_RUNNING as a changed flag even if a previous + // state transition was already running, so we update the new target. + mPrevState &= ~FLAG_TRANSITION_STATE_RUNNING; + mLauncherState = toState; + } + updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, true); applyState(); } @Override public void onStateTransitionComplete(LauncherState finalState) { - updateStateForFlag(FLAG_TRANSITION_STATE_COMMITTED_STASHED, - finalState.isTaskbarStashed()); + mLauncherState = finalState; + updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, false); applyState(); } }; @@ -127,7 +132,7 @@ import java.util.function.Supplier; // Update stashed flags first to ensure goingToUnstashedLauncherState() returns correctly. TaskbarStashController stashController = mControllers.taskbarStashController; stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, - toState.isTaskbarStashed()); + toState.isTaskbarStashed(mLauncher)); stashController.updateStateForFlag(FLAG_IN_APP, false); updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true); @@ -189,8 +194,8 @@ import java.util.function.Supplier; if (mPrevState == null || mPrevState != mState) { // If this is our initial state, treat all flags as changed. int changedFlags = mPrevState == null ? FLAGS_ALL : mPrevState ^ mState; - animator = onStateChangeApplied(changedFlags, duration, start); mPrevState = mState; + animator = onStateChangeApplied(changedFlags, duration, start); } return animator; } @@ -250,14 +255,15 @@ import java.util.function.Supplier; .setDuration(duration)); } - if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_START_STASHED)) { - playStateTransitionAnim(isTransitionStateStartStashed(), animatorSet, duration, - false /* committed */); - } + if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_RUNNING)) { + boolean committed = !hasAnyFlag(FLAG_TRANSITION_STATE_RUNNING); + playStateTransitionAnim(animatorSet, duration, committed); - if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_COMMITTED_STASHED)) { - playStateTransitionAnim(isTransitionStateCommittedStashed(), animatorSet, duration, - true /* committed */); + if (committed && mLauncherState == LauncherState.QUICK_SWITCH) { + // We're about to be paused, set immediately to ensure seamless handoff. + updateStateForFlag(FLAG_RESUMED, false); + applyState(0 /* duration */); + } } if (start) { @@ -271,17 +277,19 @@ import java.util.function.Supplier; return !mControllers.taskbarStashController.isInStashedLauncherState(); } - private void playStateTransitionAnim(boolean isTransitionStateStashed, - AnimatorSet animatorSet, long duration, boolean committed) { + private void playStateTransitionAnim(AnimatorSet animatorSet, long duration, + boolean committed) { + boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher); + float toAlignment = mLauncherState.isTaskbarAlignedWithHotseat(mLauncher) ? 1 : 0; + TaskbarStashController controller = mControllers.taskbarStashController; - controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, - isTransitionStateStashed); + controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, isInStashedState); Animator stashAnimator = controller.applyStateWithoutStart(duration); if (stashAnimator != null) { stashAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - if (isTransitionStateStashed && committed) { + if (isInStashedState && committed) { // Reset hotseat alpha to default mLauncher.getHotseat().setIconsAlpha(1); } @@ -295,10 +303,10 @@ import java.util.function.Supplier; } }); animatorSet.play(stashAnimator); - animatorSet.play(mIconAlignmentForLauncherState.animateToValue( - getCurrentIconAlignmentRatioForLauncherState(), - isTransitionStateStashed ? 0 : 1)); } + + animatorSet.play(mIconAlignmentForLauncherState.animateToValue(toAlignment) + .setDuration(duration)); } private boolean isResumed() { @@ -309,14 +317,6 @@ import java.util.function.Supplier; return (mState & FLAG_RECENTS_ANIMATION_RUNNING) != 0; } - private boolean isTransitionStateStartStashed() { - return (mState & FLAG_TRANSITION_STATE_START_STASHED) != 0; - } - - private boolean isTransitionStateCommittedStashed() { - return (mState & FLAG_TRANSITION_STATE_COMMITTED_STASHED) != 0; - } - private void onIconAlignmentRatioChangedForStateTransition() { if (!isResumed()) { return; diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java index c554fd0a91..8f89d30564 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -69,7 +69,7 @@ public class AllAppsState extends LauncherState { } @Override - public boolean isTaskbarStashed() { + public boolean isTaskbarStashed(Launcher launcher) { return true; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java index a4eff87e06..08d0a80f03 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -92,7 +92,7 @@ public class OverviewState extends LauncherState { } @Override - public boolean isTaskbarStashed() { + public boolean isTaskbarStashed(Launcher launcher) { return true; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java index d36e76b89b..ffbb61b8ca 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java @@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides.states; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.util.Themes; @@ -42,6 +43,10 @@ public class QuickSwitchState extends BackgroundAppState { @Override public int getWorkspaceScrimColor(Launcher launcher) { + DeviceProfile dp = launcher.getDeviceProfile(); + if (dp.isTaskbarPresentInApps) { + return launcher.getColor(R.color.taskbar_background); + } return Themes.getAttrColor(launcher, R.attr.overviewScrimColor); } @@ -55,4 +60,14 @@ public class QuickSwitchState extends BackgroundAppState { public int getVisibleElements(Launcher launcher) { return TASKBAR; } + + @Override + public boolean isTaskbarStashed(Launcher launcher) { + return !launcher.getDeviceProfile().isTaskbarPresentInApps; + } + + @Override + public boolean isTaskbarAlignedWithHotseat(Launcher launcher) { + return false; + } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java index ff3c517949..f6148a7c8f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -236,8 +236,10 @@ public class NoButtonQuickSwitchTouchController implements TouchController, // - RecentsView fade (if it's empty) PendingAnimation xAnim = new PendingAnimation((long) (mXRange * 2)); xAnim.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1], LINEAR); + // Use QuickSwitchState instead of OverviewState to determine scrim color, + // since we need to take potential taskbar into account. xAnim.setViewBackgroundColor(mLauncher.getScrimView(), - toState.getWorkspaceScrimColor(mLauncher), LINEAR); + QUICK_SWITCH.getWorkspaceScrimColor(mLauncher), LINEAR); if (mRecentsView.getTaskViewCount() == 0) { xAnim.addFloat(mRecentsView, CONTENT_ALPHA, 0f, 1f, LINEAR); } @@ -310,6 +312,11 @@ public class NoButtonQuickSwitchTouchController implements TouchController, } }); overviewAnim.start(); + + // Create an empty state transition so StateListeners get onStateTransitionStart(). + mLauncher.getStateManager().createAnimationToNewWorkspace( + OVERVIEW, config.duration, StateAnimationConfig.SKIP_ALL_ANIMATIONS) + .dispatchOnStart(); return; } @@ -384,6 +391,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, config.animFlags = SKIP_ALL_ANIMATIONS; updateNonOverviewAnim(targetState, config); nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer(); + mNonOverviewAnim.dispatchOnStart(); new WorkspaceRevealAnim(mLauncher, false /* animateOverviewScrim */).start(); } else { diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 2ad586d2f2..ea3c7965a1 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -629,7 +629,7 @@ public abstract class RecentsView { return (getVisibleElements(launcher) & elements) == elements; } - public boolean isTaskbarStashed() { + /** Returns whether taskbar is stashed and thus should replace hotseat with a handle */ + public boolean isTaskbarStashed(Launcher launcher) { return false; } + /** Returns whether taskbar is aligned with the hotseat vs position inside apps */ + public boolean isTaskbarAlignedWithHotseat(Launcher launcher) { + return !isTaskbarStashed(launcher); + } + /** * Fraction shift in the vertical translation UI and related properties *