From 8e2b850df7c2abfdf49d459b406f1f95d04dd5f7 Mon Sep 17 00:00:00 2001 From: Brian Isganitis Date: Wed, 20 Nov 2024 17:11:03 -0500 Subject: [PATCH] Implement initial LayoutTransition for Taskbar recents. The animations mostly match the spec, though the recents indicators scale/fade with icon currently. The change transitions need to incorporate translateX since that changes based on the number of icons in Taskbar. We need the translateX for pinning update to happen before TaskbarView lays out its children so that the animator computes the correct start and end values. Flag: com.android.launcher3.taskbar_recents_layout_transition Bug: 343521765 Test: go/testedequals Change-Id: I13aa49abf80ddc09fab890f78bde924a8f7f1d6e --- .../launcher3/taskbar/TaskbarView.java | 2 + .../taskbar/TaskbarViewCallbacks.java | 9 ++ .../taskbar/TaskbarViewController.java | 105 +++++++++++++++++- 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 130b9b7401..2945374624 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -839,6 +839,8 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar iconEnd += mAllAppsButtonTranslationOffset; } + mControllerCallbacks.onPreLayoutChildren(); + int count = getChildCount(); for (int i = count; i > 0; i--) { View child = getChildAt(i - 1); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java index f2bd4d0423..c7841c1340 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java @@ -16,6 +16,8 @@ package com.android.launcher3.taskbar; +import static com.android.launcher3.Flags.taskbarRecentsLayoutTransition; +import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP; import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW; @@ -110,6 +112,13 @@ public class TaskbarViewCallbacks { return new TaskbarHoverToolTipController(mActivity, mTaskbarView, icon); } + /** Callback invoked before Taskbar icons are laid out. */ + void onPreLayoutChildren() { + if (enableTaskbarPinning() && taskbarRecentsLayoutTransition()) { + mControllers.taskbarViewController.updateTaskbarIconTranslationXForPinning(); + } + } + /** * Notifies launcher to update icon alignment. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 4acf2fe378..fcdeee1b51 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -15,10 +15,17 @@ */ package com.android.launcher3.taskbar; +import static android.animation.LayoutTransition.APPEARING; +import static android.animation.LayoutTransition.CHANGE_APPEARING; +import static android.animation.LayoutTransition.CHANGE_DISAPPEARING; +import static android.animation.LayoutTransition.DISAPPEARING; + +import static com.android.app.animation.Interpolators.EMPHASIZED; import static com.android.app.animation.Interpolators.FINAL_FRAME; import static com.android.app.animation.Interpolators.LINEAR; import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation; import static com.android.launcher3.Flags.taskbarOverflow; +import static com.android.launcher3.Flags.taskbarRecentsLayoutTransition; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; @@ -40,13 +47,17 @@ import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_RE import android.animation.Animator; import android.animation.AnimatorSet; +import android.animation.LayoutTransition; +import android.animation.LayoutTransition.TransitionListener; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.graphics.Rect; +import android.util.FloatProperty; import android.util.Log; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.view.animation.Interpolator; import androidx.annotation.Nullable; @@ -74,6 +85,7 @@ import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.LauncherBindableItemsContainer; import com.android.launcher3.util.MultiPropertyFactory; +import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.launcher3.util.MultiTranslateDelegate; import com.android.launcher3.util.MultiValueAlpha; import com.android.quickstep.util.GroupTask; @@ -114,6 +126,11 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar /** Used if an unexpected edge case is hit in {@link #getPositionInHotseat}. */ private static final float ERROR_POSITION_IN_HOTSEAT_NOT_FOUND = -100; + private static final int TRANSITION_DELAY = 50; + private static final int TRANSITION_DEFAULT_DURATION = 500; + private static final int TRANSITION_FADE_IN_DURATION = 167; + private static final int TRANSITION_FADE_OUT_DURATION = 83; + private static boolean sEnableModelLoadingForTests = true; private final TaskbarActivityContext mActivity; @@ -158,7 +175,9 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar private final View.OnLayoutChangeListener mTaskbarViewLayoutChangeListener = (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { - updateTaskbarIconTranslationXForPinning(); + if (!taskbarRecentsLayoutTransition()) { + updateTaskbarIconTranslationXForPinning(); + } if (BubbleBarController.isBubbleBarEnabled()) { mControllers.navbarButtonsViewController.onLayoutsUpdated(); } @@ -432,7 +451,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar } } - private void updateTaskbarIconTranslationXForPinning() { + void updateTaskbarIconTranslationXForPinning() { View[] iconViews = mTaskbarView.getIconViews(); float scale = mTaskbarIconTranslationXForPinning.value; float transientTaskbarAllAppsOffset = mActivity.getResources().getDimension( @@ -1076,6 +1095,88 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar /** Called when there's a change in running apps to update the UI. */ public void commitRunningAppsToUI() { mModelCallbacks.commitRunningAppsToUI(); + if (taskbarRecentsLayoutTransition() && mTaskbarView.getLayoutTransition() == null) { + mTaskbarView.setLayoutTransition(createLayoutTransitionForRunningApps()); + } + } + + private LayoutTransition createLayoutTransitionForRunningApps() { + LayoutTransition layoutTransition = new LayoutTransition(); + layoutTransition.setDuration(TRANSITION_DEFAULT_DURATION); + layoutTransition.addTransitionListener(new TransitionListener() { + + @Override + public void startTransition( + LayoutTransition transition, ViewGroup container, View view, int type) { + if (type == APPEARING) { + view.setAlpha(0f); + view.setScaleX(0f); + view.setScaleY(0f); + } + } + + @Override + public void endTransition( + LayoutTransition transition, ViewGroup container, View view, int type) { + // Do nothing. + } + }); + + // Appearing. + AnimatorSet appearingSet = new AnimatorSet(); + Animator appearingAlphaAnimator = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f); + appearingAlphaAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0f, + (float) TRANSITION_FADE_IN_DURATION / TRANSITION_DEFAULT_DURATION)); + Animator appearingScaleAnimator = ObjectAnimator.ofFloat(null, SCALE_PROPERTY, 0f, 1f); + appearingScaleAnimator.setInterpolator(EMPHASIZED); + appearingSet.playTogether(appearingAlphaAnimator, appearingScaleAnimator); + layoutTransition.setAnimator(APPEARING, appearingSet); + layoutTransition.setStartDelay(APPEARING, TRANSITION_DELAY); + + // Disappearing. + AnimatorSet disappearingSet = new AnimatorSet(); + Animator disappearingAlphaAnimator = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f); + disappearingAlphaAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, + (float) TRANSITION_DELAY / TRANSITION_DEFAULT_DURATION, + (float) (TRANSITION_DELAY + TRANSITION_FADE_OUT_DURATION) + / TRANSITION_DEFAULT_DURATION)); + Animator disappearingScaleAnimator = ObjectAnimator.ofFloat(null, SCALE_PROPERTY, 1f, 0f); + disappearingScaleAnimator.setInterpolator(EMPHASIZED); + disappearingSet.playTogether(disappearingAlphaAnimator, disappearingScaleAnimator); + layoutTransition.setAnimator(DISAPPEARING, disappearingSet); + + // Change transitions. + FloatProperty translateXPinning = new FloatProperty<>("translateXPinning") { + @Override + public void setValue(View view, float value) { + getTranslationXForPinning(view).setValue(value); + } + + @Override + public Float get(View view) { + return getTranslationXForPinning(view).getValue(); + } + + private MultiProperty getTranslationXForPinning(View view) { + return ((Reorderable) view).getTranslateDelegate() + .getTranslationX(INDEX_TASKBAR_PINNING_ANIM); + } + }; + AnimatorSet changeSet = new AnimatorSet(); + changeSet.playTogether( + layoutTransition.getAnimator(CHANGE_APPEARING), + ObjectAnimator.ofFloat(null, translateXPinning, 0f, 1f)); + + // Change appearing. + layoutTransition.setAnimator(CHANGE_APPEARING, changeSet); + layoutTransition.setInterpolator(CHANGE_APPEARING, EMPHASIZED); + + // Change disappearing. + layoutTransition.setAnimator(CHANGE_DISAPPEARING, changeSet); + layoutTransition.setInterpolator(CHANGE_DISAPPEARING, EMPHASIZED); + layoutTransition.setStartDelay(CHANGE_DISAPPEARING, TRANSITION_DELAY); + + return layoutTransition; } /**