diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java index 6d778efbd7..ff7c138ff0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java @@ -17,7 +17,6 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE; -import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION; import android.animation.Animator; @@ -93,7 +92,8 @@ public class FallbackTaskbarUIController extends TaskbarUIController { } private void animateToRecentsState(RecentsState toState) { - Animator anim = createAnimToRecentsState(toState, TASKBAR_STASH_DURATION); + Animator anim = createAnimToRecentsState(toState, + mControllers.taskbarStashController.getStashDuration()); if (anim != null) { anim.start(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index ac584bf6cd..dcef6d3536 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -393,6 +393,11 @@ public class LauncherTaskbarUIController extends TaskbarUIController { mLauncher.launchSplitTasks(taskView, groupTask); } + @Override + protected void onIconLayoutBoundsChanged() { + mTaskbarLauncherStateController.resetIconAlignment(); + } + @Override public void dumpLogs(String prefix, PrintWriter pw) { super.dumpLogs(prefix, pw); diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java index 0f25ba1da6..f082fc68e4 100644 --- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java @@ -38,7 +38,6 @@ import com.android.launcher3.util.Executors; import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.MultiValueAlpha; import com.android.systemui.shared.navigationbar.RegionSamplingHelper; -import com.android.systemui.shared.system.QuickStepContract; import java.io.PrintWriter; @@ -152,6 +151,14 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT } } + /** + * Returns the stashed handle bounds. + * @param out The destination rect. + */ + public void getStashedHandleBounds(Rect out) { + out.set(mStashedHandleBounds); + } + private void initRegionSampler() { mRegionSamplingHelper = new RegionSamplingHelper(mStashedHandleView, new RegionSamplingHelper.SamplingCallback() { @@ -194,16 +201,19 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT */ public Animator createRevealAnimToIsStashed(boolean isStashed) { Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds()); + float startRadius = mStashedHandleRadius; if (DisplayController.isTransientTaskbar(mActivity)) { // Account for the full visual height of the transient taskbar. int heightDiff = (mTaskbarSize - visualBounds.height()) / 2; visualBounds.top -= heightDiff; visualBounds.bottom += heightDiff; + + startRadius = visualBounds.height() / 2f; } final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider( - mStashedHandleRadius, mStashedHandleRadius, visualBounds, mStashedHandleBounds); + startRadius, mStashedHandleRadius, visualBounds, mStashedHandleBounds); boolean isReversed = !isStashed; boolean changingDirection = mWasLastRevealAnimReversed != isReversed; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt index 82f27ae9e5..2d20582ad8 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt @@ -21,6 +21,7 @@ import android.graphics.Color import android.graphics.Paint import android.graphics.Path import com.android.launcher3.R +import com.android.launcher3.Utilities.mapRange import com.android.launcher3.Utilities.mapToRange import com.android.launcher3.anim.Interpolators import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound @@ -51,6 +52,9 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) { private val invertedLeftCornerPath: Path = Path() private val invertedRightCornerPath: Path = Path() + private val stashedHandleWidth = + context.resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width) + init { paint.color = context.getColor(R.color.taskbar_background) paint.flags = Paint.ANTI_ALIAS_FLAG @@ -111,12 +115,11 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) { canvas.drawPath(invertedRightCornerPath, paint) } else { // Approximates the stash/unstash animation to transform the background. - val scaleFactor = backgroundHeight / maxBackgroundHeight - val width = transientBackgroundBounds.width() - val widthScale = mapToRange(scaleFactor, 0f, 1f, 0.2f, 1f, Interpolators.LINEAR) - val newWidth = widthScale * width - val delta = width - newWidth - canvas.translate(0f, bottomMargin * ((1f - scaleFactor) / 2f)) + val progress = backgroundHeight / maxBackgroundHeight + val fullWidth = transientBackgroundBounds.width() + val newWidth = mapRange(progress, stashedHandleWidth.toFloat(), fullWidth.toFloat()) + val delta = fullWidth - newWidth + canvas.translate(0f, bottomMargin * ((1f - progress) / 2f)) // Draw shadow. val shadowAlpha = diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 80cdbe98cb..a25ec698a3 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -17,7 +17,6 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE; -import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION; import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME; import static com.android.systemui.animation.Interpolators.EMPHASIZED; @@ -41,6 +40,7 @@ import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.uioverrides.states.OverviewState; import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; +import com.android.launcher3.util.window.RefreshRateTracker; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.views.RecentsView; @@ -139,8 +139,7 @@ import java.util.StringJoiner; mIconAlphaForHome = mControllers.taskbarViewController .getTaskbarIconAlpha().get(ALPHA_INDEX_HOME); - mIconAlignment.finishAnimation(); - onIconAlignmentRatioChanged(); + resetIconAlignment(); mLauncher.getStateManager().addStateListener(mStateListener); @@ -234,7 +233,7 @@ import java.util.StringJoiner; } public void applyState() { - applyState(TASKBAR_STASH_DURATION); + applyState(mControllers.taskbarStashController.getStashDuration()); } public void applyState(long duration) { @@ -242,7 +241,7 @@ import java.util.StringJoiner; } public Animator applyState(boolean start) { - return applyState(TASKBAR_STASH_DURATION, start); + return applyState(mControllers.taskbarStashController.getStashDuration(), start); } public Animator applyState(long duration, boolean start) { @@ -329,8 +328,17 @@ import java.util.StringJoiner; + mTaskbarBackgroundAlpha.value + " -> " + backgroundAlpha + ": " + duration); } - animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(backgroundAlpha) - .setDuration(duration)); + + Animator taskbarBackgroundAlpha = mTaskbarBackgroundAlpha + .animateToValue(backgroundAlpha) + .setDuration(duration); + // Add a single frame delay to the taskbar bg to avoid too many moving parts during the + // app launch animation. + taskbarBackgroundAlpha.setStartDelay( + (hasAnyFlag(changedFlags, FLAG_RESUMED) && !goingToLauncher) + ? RefreshRateTracker.getSingleFrameMs(mLauncher) + : 0); + animatorSet.play(taskbarBackgroundAlpha); } float cornerRoundness = goingToLauncher ? 0 : 1; @@ -433,6 +441,14 @@ import java.util.StringJoiner; return (mState & FLAGS_LAUNCHER) != 0; } + /** + * Resets and updates the icon alignment. + */ + protected void resetIconAlignment() { + mIconAlignment.finishAnimation(); + onIconAlignmentRatioChanged(); + } + private void onIconAlignmentRatioChanged() { float currentValue = mIconAlphaForHome.getValue(); boolean taskbarWillBeVisible = mIconAlignment.value < 1; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 2f69b07456..50f5d9e953 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -17,8 +17,10 @@ package com.android.launcher3.taskbar; import static android.view.HapticFeedbackConstants.LONG_PRESS; +import static com.android.launcher3.anim.Interpolators.EMPHASIZED; import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; import static com.android.launcher3.anim.Interpolators.INSTANT; +import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.config.FeatureFlags.FORCE_PERSISTENT_TASKBAR; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW; @@ -41,6 +43,7 @@ import android.util.Log; import android.view.InsetsController; import android.view.View; import android.view.ViewConfiguration; +import android.view.animation.Interpolator; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -101,10 +104,19 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** * How long to stash/unstash when manually invoked via long press. + * + * Use {@link #getStashDuration()} to query duration */ - public static final long TASKBAR_STASH_DURATION = + private static final long TASKBAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE; + /** + * How long to stash/unstash transient taskbar. + * + * Use {@link #getStashDuration()} to query duration. + */ + private static final long TRANSIENT_TASKBAR_STASH_DURATION = 417; + /** * How long to stash/unstash when keyboard is appearing/disappearing. */ @@ -113,7 +125,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** * The scale TaskbarView animates to when being stashed. */ - private static final float STASHED_TASKBAR_SCALE = 0.3f; + protected static final float STASHED_TASKBAR_SCALE = 0.5f; /** * How long the hint animation plays, starting on motion down. @@ -121,6 +133,21 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba private static final long TASKBAR_HINT_STASH_DURATION = ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT; + /** + * How long to delay the icon/stash handle alpha. + */ + private static final long TASKBAR_STASH_ALPHA_START_DELAY = 33; + + /** + * How long the icon/stash handle alpha animation plays. + */ + private static final long TASKBAR_STASH_ALPHA_DURATION = 50; + + /** + * How long to delay the icon/stash handle alpha for the home to app taskbar animation. + */ + private static final long TASKBAR_STASH_ICON_ALPHA_HOME_TO_APP_START_DELAY = 66; + /** * The scale that TaskbarView animates to when hinting towards the stashed state. */ @@ -299,7 +326,16 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba boolean hideTaskbar = isVisible || !mActivity.isUserSetupComplete(); updateStateForFlag(FLAG_IN_SETUP, hideTaskbar); updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, hideTaskbar); - applyState(hideTaskbar ? 0 : TASKBAR_STASH_DURATION); + applyState(hideTaskbar ? 0 : getStashDuration()); + } + + /** + * Returns how long the stash/unstash animation should play. + */ + public long getStashDuration() { + return DisplayController.isTransientTaskbar(mActivity) + ? TRANSIENT_TASKBAR_STASH_DURATION + : TASKBAR_STASH_DURATION; } /** @@ -514,7 +550,10 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } mAnimator = new AnimatorSet(); addJankMonitorListener(mAnimator, /* appearing= */ !mIsStashed); - final float stashTranslation = isPhoneMode() ? 0 : (mUnstashedHeight - mStashedHeight); + boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity); + final float stashTranslation = isPhoneMode() || isTransientTaskbar + ? 0 + : (mUnstashedHeight - mStashedHeight); if (!supportsVisualStashing()) { // Just hide/show the icons and background instead of stashing into a handle. @@ -522,8 +561,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba .setDuration(duration)); mAnimator.playTogether(mTaskbarBackgroundOffset.animateToValue(isStashed ? 1 : 0) .setDuration(duration)); - mAnimator.playTogether(mIconTranslationYForStash.animateToValue(isStashed ? - stashTranslation : 0) + mAnimator.playTogether(mIconTranslationYForStash.animateToValue(isStashed + ? stashTranslation : 0) .setDuration(duration)); mAnimator.play(mTaskbarImeBgAlpha.animateToValue( hasAnyFlag(FLAG_STASHED_IN_APP_IME) ? 0 : 1).setDuration(duration)); @@ -531,6 +570,40 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba return; } + // If Hotseat is not the top element during animation to/from Launcher, fade in/out a + // already stashed Taskbar. + boolean skipStashAnimation = !mControllers.uiController.isHotseatIconOnTopWhenAligned() + && hasAnyFlag(changedFlags, FLAG_IN_APP); + if (isTransientTaskbar) { + createTransientAnimToIsStashed(mAnimator, isStashed, duration, animateBg, changedFlags, + skipStashAnimation); + } else { + createAnimToIsStashed(mAnimator, isStashed, duration, animateBg, skipStashAnimation, + stashTranslation); + } + + mAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mIsStashed = isStashed; + onIsStashedChanged(mIsStashed); + + cancelTimeoutIfExists(); + } + + @Override + public void onAnimationEnd(Animator animation) { + mAnimator = null; + + if (!mIsStashed) { + tryStartTaskbarTimeout(); + } + } + }); + } + + private void createAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration, + boolean animateBg, boolean skipStashAnimation, float stashTranslation) { AnimatorSet fullLengthAnimatorSet = new AnimatorSet(); // Not exactly half and may overlap. See [first|second]HalfDurationScale below. AnimatorSet firstHalfAnimatorSet = new AnimatorSet(); @@ -539,10 +612,6 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba final float firstHalfDurationScale; final float secondHalfDurationScale; - // If Hotseat is not the top element during animation to/from Launcher, fade in/out a - // already stashed Taskbar. - boolean skipStashAnimation = !mControllers.uiController.isHotseatIconOnTopWhenAligned() - && hasAnyFlag(changedFlags, FLAG_IN_APP); if (isStashed) { firstHalfDurationScale = 0.75f; secondHalfDurationScale = 0.5f; @@ -595,10 +664,6 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } } - if (DisplayController.isTransientTaskbar(mActivity)) { - fullLengthAnimatorSet.play(mControllers.taskbarViewController - .createRevealAnimToIsStashed(isStashed)); - } fullLengthAnimatorSet.play(mControllers.stashedHandleViewController .createRevealAnimToIsStashed(isStashed)); // Return the stashed handle to its default scale in case it was changed as part of the @@ -610,26 +675,73 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba secondHalfAnimatorSet.setDuration((long) (duration * secondHalfDurationScale)); secondHalfAnimatorSet.setStartDelay((long) (duration * (1 - secondHalfDurationScale))); - mAnimator.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet, + as.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet, secondHalfAnimatorSet); - mAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mIsStashed = isStashed; - onIsStashedChanged(mIsStashed); - cancelTimeoutIfExists(); + } + + private void createTransientAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration, + boolean animateBg, int changedFlags, boolean skipStashAnimation) { + Interpolator skipInterpolator = null; + + if (isStashed) { + if (animateBg) { + play(as, mTaskbarBackgroundOffset.animateToValue(1), 0, duration, EMPHASIZED); + } else { + as.addListener(AnimatorListeners.forEndCallback( + () -> mTaskbarBackgroundOffset.updateValue(1))); } - @Override - public void onAnimationEnd(Animator animation) { - mAnimator = null; + long alphaStartDelay = duration == 0 ? 0 : (changedFlags == FLAG_IN_APP) + ? TASKBAR_STASH_ICON_ALPHA_HOME_TO_APP_START_DELAY + : TASKBAR_STASH_ALPHA_START_DELAY; + long alphaDuration = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_DURATION; + play(as, mIconAlphaForStash.animateToValue(0), alphaStartDelay, alphaDuration, LINEAR); + play(as, mTaskbarStashedHandleAlpha.animateToValue(1), alphaStartDelay, + Math.max(0, duration - alphaStartDelay), LINEAR); - if (!mIsStashed) { - tryStartTaskbarTimeout(); - } + if (skipStashAnimation) { + skipInterpolator = INSTANT; } - }); + } else { + if (animateBg) { + play(as, mTaskbarBackgroundOffset.animateToValue(0), 0, duration, EMPHASIZED); + } else { + as.addListener(AnimatorListeners.forEndCallback( + () -> mTaskbarBackgroundOffset.updateValue(0))); + } + + long alphaStartDelay = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_START_DELAY; + long alphaDuration = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_DURATION; + play(as, mIconAlphaForStash.animateToValue(1), alphaStartDelay, alphaDuration, LINEAR); + play(as, mTaskbarStashedHandleAlpha.animateToValue(0), 0, alphaDuration, LINEAR); + + if (skipStashAnimation) { + skipInterpolator = FINAL_FRAME; + } + } + play(as, mControllers.taskbarViewController + .createRevealAnimToIsStashed(isStashed, isInApp()), 0, duration, EMPHASIZED); + + if (skipInterpolator != null) { + as.setInterpolator(skipInterpolator); + } + + play(as, mControllers.stashedHandleViewController + .createRevealAnimToIsStashed(isStashed), 0, duration, EMPHASIZED); + + // Return the stashed handle to its default scale in case it was changed as part of the + // feedforward hint. Note that the reveal animation above also visually scales it. + as.play(mTaskbarStashedHandleHintScale.animateToValue(1f) + .setDuration(isStashed ? duration / 2 : duration)); + } + + private static void play(AnimatorSet as, Animator a, long startDelay, long duration, + Interpolator interpolator) { + a.setDuration(duration); + a.setStartDelay(startDelay); + a.setInterpolator(interpolator); + as.play(a); } private void addJankMonitorListener(AnimatorSet animator, boolean expanding) { @@ -711,7 +823,6 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } } - /** * Returns an animator which applies the latest state if mIsStashed is changed, or {@code null} * otherwise. diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index 76b8b6dcd8..10d339bdeb 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -75,6 +75,11 @@ public class TaskbarUIController { protected void onStashedInAppChanged() { } + /** + * Called when taskbar icon layout bounds change. + */ + protected void onIconLayoutBoundsChanged() { } + /** Called when an icon is launched. */ @CallSuper public void onTaskbarIconLaunched(ItemInfo item) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index eddc278ddd..483f711a0f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -58,6 +58,8 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar private static final String TAG = TaskbarView.class.getSimpleName(); private static final float TASKBAR_BACKGROUND_LUMINANCE = 0.30f; + private static final Rect sTmpRect = new Rect(); + public int mThemeIconsBackground; private final int[] mTempOutLocation = new int[2]; @@ -339,6 +341,9 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar (right - navSpaceNeeded) - iconEnd; iconEnd += offset; } + + sTmpRect.set(mIconLayoutBounds); + // Layout the children mIconLayoutBounds.right = iconEnd; mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2; @@ -379,6 +384,10 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar mIconLayoutBounds.right = center + distanceFromCenter; mIconLayoutBounds.left = center - distanceFromCenter; } + + if (!sTmpRect.equals(mIconLayoutBounds)) { + mControllerCallbacks.notifyIconLayoutBoundsChanged(); + } } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 6252e60dca..a25ca8cc5f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -17,9 +17,9 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; -import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.anim.AnimatedFloat.VALUE; +import static com.android.launcher3.anim.AnimatorListeners.forEndCallback; import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP; @@ -28,6 +28,7 @@ import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGA import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL; import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.graphics.Rect; @@ -310,13 +311,48 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar * @param isStashed When true, the icon crops vertically to the size of the stashed handle. * When false, the reverse happens. */ - public AnimatorSet createRevealAnimToIsStashed(boolean isStashed) { + public AnimatorSet createRevealAnimToIsStashed(boolean isStashed, boolean isInApp) { AnimatorSet as = new AnimatorSet(); - for (int i = mTaskbarView.getChildCount() - 1; i >= 0; i--) { + + Rect stashedBounds = new Rect(); + mControllers.stashedHandleViewController.getStashedHandleBounds(stashedBounds); + + int numChildren = mTaskbarView.getChildCount(); + // We do not actually modify the width of the icons, but we will use this width to position + // the children to overlay the nav handle. + float virtualChildWidth = stashedBounds.width() / (float) numChildren; + + for (int i = numChildren - 1; i >= 0; i--) { View child = mTaskbarView.getChildAt(i); - if (child instanceof BubbleTextView) { - as.play(createRevealAnimForView(child, isStashed)); + + // Crop the icons to/from the nav handle shape. + as.play(createRevealAnimForView(child, isStashed)); + + // Translate the icons to/from their locations as the "nav handle." + // We look at 'left' and 'right' values to ensure that the children stay within the + // bounds of the stashed handle. + float iconLeft = child.getLeft(); + float newLeft = stashedBounds.left + (virtualChildWidth * i); + final float croppedTransX; + if (iconLeft > newLeft) { + float newRight = stashedBounds.right - (virtualChildWidth * (numChildren - 1 - i)); + croppedTransX = -(child.getLeft() + child.getWidth() - newRight); + } else { + croppedTransX = newLeft - iconLeft; } + + as.play(ObjectAnimator.ofFloat(child, ICON_REVEAL_TRANSLATE_X, isStashed + ? new float[] {croppedTransX} + : new float[] {croppedTransX, 0})); + + float croppedTransY = child.getHeight() - stashedBounds.height(); + as.play(ObjectAnimator.ofFloat(child, ICON_REVEAL_TRANSLATE_Y, isStashed + ? new float[] {croppedTransY} + : new float[] {croppedTransY, 0})); + as.addListener(forEndCallback(() -> { + ICON_REVEAL_TRANSLATE_X.set(child, 0f); + ICON_REVEAL_TRANSLATE_Y.set(child, 0f); + })); } return as; } @@ -409,7 +445,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar float scale = ((float) taskbarDp.iconSizePx) / launcherDp.hotseatQsbVisualHeight; setter.addFloat(child, SCALE_PROPERTY, scale, 1f, interpolator); - setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, interpolator); + setter.setFloat(child, ICON_TRANSLATE_Y, mTaskbarBottomMargin, interpolator); if (mIsHotseatIconOnTopWhenAligned) { setter.addFloat(child, VIEW_ALPHA, 0f, 1f, @@ -448,7 +484,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar float childCenter = (child.getLeft() + child.getRight()) / 2f; setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, interpolator); - setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, interpolator); + setter.setFloat(child, ICON_TRANSLATE_Y, mTaskbarBottomMargin, interpolator); setter.setFloat(child, SCALE_PROPERTY, scaleUp, interpolator); } @@ -626,6 +662,13 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar public void clearTouchInProgress() { mTouchInProgress = false; } + + /** + * Notifies launcher to update icon alignment. + */ + public void notifyIconLayoutBoundsChanged() { + mControllers.uiController.onIconLayoutBoundsChanged(); + } } public static final FloatProperty ICON_TRANSLATE_X = @@ -636,7 +679,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar if (view instanceof BubbleTextView) { ((BubbleTextView) view).setTranslationXForTaskbarAlignmentAnimation(v); } else if (view instanceof FolderIcon) { - ((FolderIcon) view).setTranslationForTaskbarAlignmentAnimation(v); + ((FolderIcon) view).setTranslationXForTaskbarAlignmentAnimation(v); } else { view.setTranslationX(v); } @@ -653,4 +696,81 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar return view.getTranslationX(); } }; + + public static final FloatProperty ICON_TRANSLATE_Y = + new FloatProperty("taskbarAlignmentTranslateY") { + + @Override + public void setValue(View view, float v) { + if (view instanceof BubbleTextView) { + ((BubbleTextView) view).setTranslationYForTaskbarAlignmentAnimation(v); + } else if (view instanceof FolderIcon) { + ((FolderIcon) view).setTranslationYForTaskbarAlignmentAnimation(v); + } else { + view.setTranslationY(v); + } + } + + @Override + public Float get(View view) { + if (view instanceof BubbleTextView) { + return ((BubbleTextView) view) + .getTranslationYForTaskbarAlignmentAnimation(); + } else if (view instanceof FolderIcon) { + return ((FolderIcon) view).getTranslationYForTaskbarAlignmentAnimation(); + } + return view.getTranslationY(); + } + }; + + public static final FloatProperty ICON_REVEAL_TRANSLATE_X = + new FloatProperty("taskbarRevealTranslateX") { + + @Override + public void setValue(View view, float v) { + if (view instanceof BubbleTextView) { + ((BubbleTextView) view).setTranslationXForTaskbarRevealAnimation(v); + } else if (view instanceof FolderIcon) { + ((FolderIcon) view).setTranslationXForTaskbarRevealAnimation(v); + } else { + view.setTranslationX(v); + } + } + + @Override + public Float get(View view) { + if (view instanceof BubbleTextView) { + return ((BubbleTextView) view).getTranslationXForTaskbarRevealAnimation(); + } else if (view instanceof FolderIcon) { + return ((FolderIcon) view).getTranslationXForTaskbarRevealAnimation(); + } + return view.getTranslationX(); + } + }; + + public static final FloatProperty ICON_REVEAL_TRANSLATE_Y = + new FloatProperty("taskbarRevealTranslateY") { + + @Override + public void setValue(View view, float v) { + if (view instanceof BubbleTextView) { + ((BubbleTextView) view).setTranslationYForTaskbarRevealAnimation(v); + } else if (view instanceof FolderIcon) { + ((FolderIcon) view).setTranslationYForTaskbarRevealAnimation(v); + } else { + view.setTranslationY(v); + } + } + + @Override + public Float get(View view) { + if (view instanceof BubbleTextView) { + return ((BubbleTextView) view).getTranslationYForTaskbarRevealAnimation(); + } else if (view instanceof FolderIcon) { + return ((FolderIcon) view).getTranslationYForTaskbarRevealAnimation(); + } + return view.getTranslationY(); + } + }; + } diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index edbce1068e..b109e8ab1c 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -104,6 +104,10 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, private final PointF mTranslationForReorderPreview = new PointF(0, 0); private float mTranslationXForTaskbarAlignmentAnimation = 0f; + private float mTranslationYForTaskbarAlignmentAnimation = 0f; + + private float mTranslationXForTaskbarRevealAnimation = 0f; + private float mTranslationYForTaskbarRevealAnimation = 0f; private final PointF mTranslationForMoveFromCenterAnimation = new PointF(0, 0); @@ -952,11 +956,17 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, } private void updateTranslation() { - super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x + super.setTranslationX(mTranslationForReorderBounce.x + + mTranslationForReorderPreview.x + mTranslationForMoveFromCenterAnimation.x - + mTranslationXForTaskbarAlignmentAnimation); - super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y - + mTranslationForMoveFromCenterAnimation.y); + + mTranslationXForTaskbarAlignmentAnimation + + mTranslationXForTaskbarRevealAnimation + ); + super.setTranslationY(mTranslationForReorderBounce.y + + mTranslationForReorderPreview.y + + mTranslationForMoveFromCenterAnimation.y + + mTranslationYForTaskbarAlignmentAnimation + + mTranslationYForTaskbarRevealAnimation); } public void setReorderBounceOffset(float x, float y) { @@ -1012,6 +1022,51 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, return mTranslationXForTaskbarAlignmentAnimation; } + /** + * Sets translationX for taskbar to launcher alignment animation + */ + public void setTranslationYForTaskbarAlignmentAnimation(float translationY) { + mTranslationYForTaskbarAlignmentAnimation = translationY; + updateTranslation(); + } + + /** + * Returns translationY value for taskbar to launcher alignment animation + */ + public float getTranslationYForTaskbarAlignmentAnimation() { + return mTranslationYForTaskbarAlignmentAnimation; + } + + /** + * Sets translationX value for taskbar reveal animation + */ + public void setTranslationXForTaskbarRevealAnimation(float translationX) { + mTranslationXForTaskbarRevealAnimation = translationX; + updateTranslation(); + } + + /** + * Returns translation values for taskbar reveal animation + */ + public float getTranslationXForTaskbarRevealAnimation() { + return mTranslationXForTaskbarRevealAnimation; + } + + /** + * Sets translationY value for taskbar reveal animation + */ + public void setTranslationYForTaskbarRevealAnimation(float translationY) { + mTranslationYForTaskbarRevealAnimation = translationY; + updateTranslation(); + } + + /** + * Returns translationY values for taskbar reveal animation + */ + public float getTranslationYForTaskbarRevealAnimation() { + return mTranslationYForTaskbarRevealAnimation; + } + public View getView() { return this; } diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index e69f7811e7..ee1a0608cf 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -135,6 +135,9 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel private final PointF mTranslationForMoveFromCenterAnimation = new PointF(0, 0); private float mTranslationXForTaskbarAlignmentAnimation = 0f; + private float mTranslationYForTaskbarAlignmentAnimation = 0f; + private float mTranslationXForTaskbarRevealAnimation = 0f; + private float mTranslationYForTaskbarRevealAnimation = 0f; private final PointF mTranslationForReorderBounce = new PointF(0, 0); private final PointF mTranslationForReorderPreview = new PointF(0, 0); @@ -416,7 +419,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel () -> { mPreviewItemManager.hidePreviewItem(finalIndex, false); mFolder.showItem(item); - }, + }, DragLayer.ANIMATION_END_DISAPPEAR, null); mFolder.hideItem(item); @@ -768,11 +771,15 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel } private void updateTranslation() { - super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x + super.setTranslationX(mTranslationForReorderBounce.x + + mTranslationForReorderPreview.x + mTranslationForMoveFromCenterAnimation.x - + mTranslationXForTaskbarAlignmentAnimation); + + mTranslationXForTaskbarAlignmentAnimation + + mTranslationXForTaskbarRevealAnimation); super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y - + mTranslationForMoveFromCenterAnimation.y); + + mTranslationForMoveFromCenterAnimation.y + + mTranslationYForTaskbarAlignmentAnimation + + mTranslationYForTaskbarRevealAnimation); } public void setReorderBounceOffset(float x, float y) { @@ -787,7 +794,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel /** * Sets translationX value for taskbar to launcher alignment animation */ - public void setTranslationForTaskbarAlignmentAnimation(float translationX) { + public void setTranslationXForTaskbarAlignmentAnimation(float translationX) { mTranslationXForTaskbarAlignmentAnimation = translationX; updateTranslation(); } @@ -799,6 +806,51 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel return mTranslationXForTaskbarAlignmentAnimation; } + /** + * Sets translationY value for taskbar to launcher alignment animation + */ + public void setTranslationYForTaskbarAlignmentAnimation(float translationY) { + mTranslationYForTaskbarAlignmentAnimation = translationY; + updateTranslation(); + } + + /** + * Returns translation values for taskbar to launcher alignment animation + */ + public float getTranslationYForTaskbarAlignmentAnimation() { + return mTranslationYForTaskbarAlignmentAnimation; + } + + /** + * Sets translationX value for taskbar reveal animation + */ + public void setTranslationXForTaskbarRevealAnimation(float translationX) { + mTranslationXForTaskbarRevealAnimation = translationX; + updateTranslation(); + } + + /** + * Returns translation values for taskbar reveal animation + */ + public float getTranslationXForTaskbarRevealAnimation() { + return mTranslationXForTaskbarRevealAnimation; + } + + /** + * Sets translationY value for taskbar reveal animation + */ + public void setTranslationYForTaskbarRevealAnimation(float translationY) { + mTranslationYForTaskbarRevealAnimation = translationY; + updateTranslation(); + } + + /** + * Returns translationY values for taskbar reveal animation + */ + public float getTranslationYForTaskbarRevealAnimation() { + return mTranslationYForTaskbarRevealAnimation; + } + /** * Sets translation values for move from center animation */