Animate inline QSB between home and apps
- Added a QSB to taskbar to be animated between inline QSB and taskbar
- Passed endValue of taskbar animator to TaskbarController to have aniamtion variation between home -> app and app -> home
- Tuned duartion of taskbar animation and also stagger animation when taskbar is present
- Disabled scaling down of taskbar and inline QSB for home -> app
- Disabled stagger animation of taskbar and inline QSB for app -> home
Bug: 220733187
Test: manual
Change-Id: I4aac0bbc343b992a0472298595770e2bf2a55990
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index e1a3b72..b20752d 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -31,7 +31,6 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.Utilities.mapBoundToRange;
-import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
@@ -184,6 +183,10 @@
public static final int SPLIT_DIVIDER_ANIM_DURATION = 100;
public static final int CONTENT_ALPHA_DURATION = 217;
+ public static final int TASKBAR_TO_APP_DURATION = 600;
+ // TODO(b/236145847): Tune TASKBAR_TO_HOME_DURATION to 383 after conflict with unlock animation
+ // is solved.
+ public static final int TASKBAR_TO_HOME_DURATION = 300;
protected static final int CONTENT_SCALE_DURATION = 350;
protected static final int CONTENT_SCRIM_DURATION = 350;
@@ -527,7 +530,15 @@
workspace.forEachVisiblePage(
view -> viewsToAnimate.add(((CellLayout) view).getShortcutsAndWidgets()));
- viewsToAnimate.add(mLauncher.getHotseat());
+ // Do not scale hotseat as a whole when taskbar is present, and scale QSB only if it's
+ // not inline.
+ if (mDeviceProfile.isTaskbarPresent) {
+ if (!mDeviceProfile.isQsbInline) {
+ viewsToAnimate.add(mLauncher.getHotseat().getQsb());
+ }
+ } else {
+ viewsToAnimate.add(mLauncher.getHotseat());
+ }
viewsToAnimate.forEach(view -> {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index ca30e72..6df31e5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -171,7 +171,9 @@
isResumed,
fromInit,
/* startAnimation= */ true,
- QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
+ !isResumed
+ ? QuickstepTransitionManager.TASKBAR_TO_APP_DURATION
+ : QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION);
}
@Nullable
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index dc0ef27..591b32f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -19,11 +19,13 @@
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;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -31,6 +33,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.Utilities;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.util.MultiValueAlpha;
@@ -44,7 +47,6 @@
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.StringJoiner;
-import java.util.function.Consumer;
import java.util.function.Supplier;
/**
@@ -53,6 +55,9 @@
*/
public class TaskbarLauncherStateController {
+ private static final String TAG = TaskbarLauncherStateController.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
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_RUNNING = 1 << 2;
@@ -99,7 +104,11 @@
}
updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, true);
if (!mShouldDelayLauncherStateAnim) {
- applyState();
+ if (toState == LauncherState.NORMAL) {
+ applyState(QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION);
+ } else {
+ applyState();
+ }
}
}
@@ -122,7 +131,12 @@
MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha();
mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
mIconAlphaForHome.setConsumer(
- (Consumer<Float>) alpha -> mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1));
+ alpha -> {
+ mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1);
+ if (mLauncher.getDeviceProfile().isQsbInline) {
+ mLauncher.getHotseat().setQsbAlpha(alpha > 0 ? 0 : 1);
+ }
+ });
mIconAlignmentForResumedState.finishAnimation();
onIconAlignmentRatioChangedForAppAndHomeTransition();
@@ -269,6 +283,11 @@
ObjectAnimator resumeAlignAnim = mIconAlignmentForResumedState
.animateToValue(toAlignmentForResumedState)
.setDuration(duration);
+ if (DEBUG) {
+ Log.d(TAG, "mIconAlignmentForResumedState - "
+ + mIconAlignmentForResumedState.value
+ + " -> " + toAlignmentForResumedState + ": " + duration);
+ }
resumeAlignAnim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -305,6 +324,11 @@
if (isRecentsAnimationRunning) {
gestureAlignAnim.setDuration(duration);
}
+ if (DEBUG) {
+ Log.d(TAG, "mIconAlignmentForGestureState - "
+ + mIconAlignmentForGestureState.value
+ + " -> " + toAlignmentForGestureState + ": " + duration);
+ }
gestureAlignAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -330,6 +354,7 @@
.setDuration(duration));
}
+ animatorSet.setInterpolator(EMPHASIZED);
if (start) {
animatorSet.start();
}
@@ -374,6 +399,12 @@
mIconAlignmentForLauncherState.finishAnimation();
animatorSet.play(mIconAlignmentForLauncherState.animateToValue(toAlignment)
.setDuration(duration));
+ if (DEBUG) {
+ Log.d(TAG, "mIconAlignmentForLauncherState - "
+ + mIconAlignmentForLauncherState.value
+ + " -> " + toAlignment + ": " + duration);
+ }
+ animatorSet.setInterpolator(EMPHASIZED);
}
}
@@ -396,17 +427,17 @@
onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioBetweenAppAndHome);
}
- private void onIconAlignmentRatioChanged(Supplier<Float> alignmentSupplier) {
+ private void onIconAlignmentRatioChanged(Supplier<AnimatedFloat> alignmentSupplier) {
if (mControllers == null) {
return;
}
- float alignment = alignmentSupplier.get();
+ AnimatedFloat animatedFloat = alignmentSupplier.get();
float currentValue = mIconAlphaForHome.getValue();
- boolean taskbarWillBeVisible = alignment < 1;
+ boolean taskbarWillBeVisible = animatedFloat.value < 1;
boolean firstFrameVisChanged = (taskbarWillBeVisible && Float.compare(currentValue, 1) != 0)
|| (!taskbarWillBeVisible && Float.compare(currentValue, 0) != 0);
- updateIconAlignment(alignment);
+ updateIconAlignment(animatedFloat.value, animatedFloat.getEndValue());
// Sync the first frame where we swap taskbar and hotseat.
if (firstFrameVisChanged && mCanSyncViews && !Utilities.IS_RUNNING_IN_TEST_HARNESS) {
@@ -416,21 +447,22 @@
}
}
- private void updateIconAlignment(float alignment) {
+ private void updateIconAlignment(float alignment, Float endAlignment) {
mControllers.taskbarViewController.setLauncherIconAlignment(
- alignment, mLauncher.getDeviceProfile());
+ alignment, endAlignment, mLauncher.getDeviceProfile());
// Switch taskbar and hotseat in last frame
setTaskbarViewVisible(alignment < 1);
mControllers.navbarButtonsViewController.updateTaskbarAlignment(alignment);
}
- private float getCurrentIconAlignmentRatioBetweenAppAndHome() {
- return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
+ private AnimatedFloat getCurrentIconAlignmentRatioBetweenAppAndHome() {
+ return mIconAlignmentForResumedState.value > mIconAlignmentForGestureState.value
+ ? mIconAlignmentForResumedState : mIconAlignmentForGestureState;
}
- private float getCurrentIconAlignmentRatioForLauncherState() {
- return mIconAlignmentForLauncherState.value;
+ private AnimatedFloat getCurrentIconAlignmentRatioForLauncherState() {
+ return mIconAlignmentForLauncherState;
}
private void setTaskbarViewVisible(boolean isVisible) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 6f88d64..6a43cc5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -20,6 +20,7 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -31,6 +32,7 @@
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -78,6 +80,8 @@
// Only non-null when device supports having an All Apps button.
private @Nullable AllAppsButton mAllAppsButton;
+ private View mQsb;
+
public TaskbarView(@NonNull Context context) {
this(context, null);
}
@@ -117,6 +121,9 @@
new ViewGroup.LayoutParams(mIconTouchSize, mIconTouchSize));
mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
}
+
+ // TODO: Disable touch events on QSB otherwise it can crash.
+ mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
}
private int getColorWithGivenLuminance(int color, float luminance) {
@@ -166,6 +173,7 @@
if (mAllAppsButton != null) {
removeView(mAllAppsButton);
}
+ removeView(mQsb);
for (int i = 0; i < hotseatItemInfos.length; i++) {
ItemInfo hotseatItemInfo = hotseatItemInfos[i];
@@ -242,6 +250,11 @@
int index = Utilities.isRtl(getResources()) ? 0 : getChildCount();
addView(mAllAppsButton, index);
}
+ if (mActivityContext.getDeviceProfile().isQsbInline) {
+ addView(mQsb, Utilities.isRtl(getResources()) ? getChildCount() : 0);
+ // Always set QSB to invisible after re-adding.
+ mQsb.setVisibility(View.INVISIBLE);
+ }
mThemeIconsBackground = calculateThemeIconsBackground();
setThemedIconsBackgroundColor(mThemeIconsBackground);
@@ -273,7 +286,12 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int count = getChildCount();
- int spaceNeeded = count * (mItemMarginLeftRight * 2 + mIconTouchSize);
+ int countExcludingQsb = count;
+ DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+ if (deviceProfile.isQsbInline) {
+ countExcludingQsb--;
+ }
+ int spaceNeeded = countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize);
int navSpaceNeeded = ApiWrapper.getHotseatEndOffset(getContext());
boolean layoutRtl = isLayoutRtl();
int iconEnd = right - (right - left - spaceNeeded) / 2;
@@ -292,10 +310,25 @@
mIconLayoutBounds.bottom = mIconLayoutBounds.top + mIconTouchSize;
for (int i = count; i > 0; i--) {
View child = getChildAt(i - 1);
- iconEnd -= mItemMarginLeftRight;
- int iconStart = iconEnd - mIconTouchSize;
- child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
- iconEnd = iconStart - mItemMarginLeftRight;
+ if (child == mQsb) {
+ int qsbStart;
+ int qsbEnd;
+ if (layoutRtl) {
+ qsbStart = iconEnd + mItemMarginLeftRight;
+ qsbEnd = qsbStart + deviceProfile.qsbWidth;
+ } else {
+ qsbEnd = iconEnd - mItemMarginLeftRight;
+ qsbStart = qsbEnd - deviceProfile.qsbWidth;
+ }
+ int qsbTop = (bottom - top - deviceProfile.hotseatQsbHeight) / 2;
+ int qsbBottom = qsbTop + deviceProfile.hotseatQsbHeight;
+ child.layout(qsbStart, qsbTop, qsbEnd, qsbBottom);
+ } else {
+ iconEnd -= mItemMarginLeftRight;
+ int iconStart = iconEnd - mIconTouchSize;
+ child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
+ iconEnd = iconStart - mItemMarginLeftRight;
+ }
}
mIconLayoutBounds.left = iconEnd;
}
@@ -367,6 +400,13 @@
return mAllAppsButton;
}
+ /**
+ * Returns the QSB in the taskbar.
+ */
+ public View getQsb() {
+ return mQsb;
+ }
+
// FolderIconParent implemented methods.
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index fdd9de5..0cbd0d1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -16,6 +16,7 @@
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.Utilities.squaredHypot;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
@@ -35,12 +36,15 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.icons.ThemedIconDrawable;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.HorizontalInsettableView;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.MultiValueAlpha;
@@ -211,9 +215,10 @@
* 0 => not aligned
* 1 => fully aligned
*/
- public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) {
+ public void setLauncherIconAlignment(float alignmentRatio, Float endAlignment,
+ DeviceProfile launcherDp) {
if (mIconAlignControllerLazy == null) {
- mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
+ mIconAlignControllerLazy = createIconAlignmentController(launcherDp, endAlignment);
}
mIconAlignControllerLazy.setPlayFraction(alignmentRatio);
if (alignmentRatio <= 0 || alignmentRatio >= 1) {
@@ -225,11 +230,13 @@
/**
* Creates an animation for aligning the taskbar icons with the provided Launcher device profile
*/
- private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) {
+ private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp,
+ Float endAlignment) {
mOnControllerPreCreateCallback.run();
PendingAnimation setter = new PendingAnimation(100);
+ DeviceProfile taskbarDp = mActivity.getDeviceProfile();
Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
- float scaleUp = ((float) launcherDp.iconSizePx) / mActivity.getDeviceProfile().iconSizePx;
+ float scaleUp = ((float) launcherDp.iconSizePx) / taskbarDp.iconSizePx;
int borderSpacing = launcherDp.hotseatBorderSpace;
int hotseatCellSize = DeviceProfile.calculateCellWidth(
launcherDp.availableWidthPx - hotseatPadding.left - hotseatPadding.right,
@@ -246,14 +253,13 @@
}
int collapsedHeight = mActivity.getDefaultTaskbarWindowHeight();
- int expandedHeight = Math.max(collapsedHeight,
- mActivity.getDeviceProfile().taskbarSize + offsetY);
+ int expandedHeight = Math.max(collapsedHeight, taskbarDp.taskbarSize + offsetY);
setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight(
anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
+ boolean isToHome = endAlignment != null && endAlignment == 1;
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
View child = mTaskbarView.getChildAt(i);
-
int positionInHotseat;
if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()
&& child == mTaskbarView.getAllAppsButtonView()) {
@@ -261,13 +267,46 @@
// as its convenient for animation purposes.
positionInHotseat = Utilities.isRtl(child.getResources())
? -1
- : mActivity.getDeviceProfile().numShownHotseatIcons;
+ : taskbarDp.numShownHotseatIcons;
if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) {
- setter.setViewAlpha(child, 0, LINEAR);
+ setter.setViewAlpha(child, 0,
+ isToHome
+ ? Interpolators.clampToProgress(LINEAR, 0f, 0.17f)
+ : Interpolators.clampToProgress(LINEAR, 0.72f, 0.84f));
}
} else if (child.getTag() instanceof ItemInfo) {
positionInHotseat = ((ItemInfo) child.getTag()).screenId;
+ } else if (child == mTaskbarView.getQsb()) {
+ boolean isRtl = Utilities.isRtl(child.getResources());
+ float hotseatIconCenter = isRtl
+ ? launcherDp.widthPx - hotseatPadding.right + borderSpacing
+ + launcherDp.qsbWidth / 2f
+ : hotseatPadding.left - borderSpacing - launcherDp.qsbWidth / 2f;
+ float childCenter = (child.getLeft() + child.getRight()) / 2f;
+ float halfQsbIconWidthDiff = (launcherDp.qsbWidth - taskbarDp.iconSizePx) / 2f;
+ setter.addFloat(child, ICON_TRANSLATE_X,
+ isRtl ? -halfQsbIconWidthDiff : halfQsbIconWidthDiff,
+ hotseatIconCenter - childCenter, LINEAR);
+
+ int qsbContentHeight = child.getHeight() - child.getPaddingTop()
+ - child.getPaddingBottom();
+ float scale = ((float) taskbarDp.iconSizePx) / qsbContentHeight;
+ setter.addFloat(child, SCALE_PROPERTY, scale, 1f, LINEAR);
+
+ setter.addFloat(child, VIEW_ALPHA, 0f, 1f,
+ isToHome
+ ? Interpolators.clampToProgress(LINEAR, 0f, 0.35f)
+ : Interpolators.clampToProgress(LINEAR, 0.84f, 1f));
+ setter.addOnFrameListener(animator -> AlphaUpdateListener.updateVisibility(child));
+
+ float qsbInsetFraction = halfQsbIconWidthDiff / launcherDp.qsbWidth;
+ if (child instanceof HorizontalInsettableView) {
+ setter.addFloat((HorizontalInsettableView) child,
+ HorizontalInsettableView.HORIZONTAL_INSETS, qsbInsetFraction, 0,
+ LINEAR);
+ }
+ continue;
} else {
Log.w(TAG, "Unsupported view found in createIconAlignmentController, v=" + child);
continue;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 713fa25..b3e2d91 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -234,7 +234,6 @@
STATE_LAUNCHER_BIND_TO_SERVICE;
public static final long MAX_SWIPE_DURATION = 350;
- public static final long HOME_DURATION = StaggeredWorkspaceAnim.DURATION_MS;
public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
private static final float SWIPE_DURATION_MULTIPLIER =
@@ -1141,7 +1140,9 @@
mInputConsumerProxy.enable();
}
if (endTarget == HOME) {
- duration = HOME_DURATION;
+ duration = mActivity.getDeviceProfile().isTaskbarPresent
+ ? StaggeredWorkspaceAnim.DURATION_TASKBAR_MS
+ : StaggeredWorkspaceAnim.DURATION_MS;
// Early detach the nav bar once the endTarget is determined as HOME
if (mRecentsAnimationController != null) {
mRecentsAnimationController.detachNavigationBarFromApp(true);
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java
index 6c7a885..a166553 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java
@@ -133,4 +133,11 @@
public boolean isAnimatingToValue(float endValue) {
return isAnimating() && mEndValue != null && mEndValue == endValue;
}
+
+ /**
+ * Returns the value we are animating to, or {@code null} if we are not currently animating.
+ */
+ public Float getEndValue() {
+ return mEndValue;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 32e08ff..de527a7 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -41,6 +41,7 @@
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Workspace;
@@ -60,10 +61,10 @@
public class StaggeredWorkspaceAnim {
private static final int APP_CLOSE_ROW_START_DELAY_MS = 10;
- // How long it takes to fade in each staggered row.
- private static final int ALPHA_DURATION_MS = 250;
// Should be used for animations running alongside this StaggeredWorkspaceAnim.
public static final int DURATION_MS = 250;
+ public static final int DURATION_TASKBAR_MS =
+ QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION;
private static final float MAX_VELOCITY_PX_PER_S = 22f;
@@ -91,16 +92,20 @@
mSpringTransY = transFactor * launcher.getResources()
.getDimensionPixelSize(R.dimen.swipe_up_max_workspace_trans_y);
+ DeviceProfile grid = launcher.getDeviceProfile();
+ long duration = grid.isTaskbarPresent ? DURATION_TASKBAR_MS : DURATION_MS;
if (staggerWorkspace) {
- DeviceProfile grid = launcher.getDeviceProfile();
Workspace<?> workspace = launcher.getWorkspace();
Hotseat hotseat = launcher.getHotseat();
- // Hotseat and QSB takes up two additional rows.
- int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
+ boolean staggerHotseat = !grid.isVerticalBarLayout() && !grid.isTaskbarPresent;
+ boolean staggerQsb =
+ !grid.isVerticalBarLayout() && !(grid.isTaskbarPresent && grid.isQsbInline);
+ int totalRows = grid.inv.numRows + (staggerHotseat ? 1 : 0) + (staggerQsb ? 1 : 0);
// Add animation for all the visible workspace pages
- workspace.forEachVisiblePage(page -> addAnimationForPage((CellLayout) page, totalRows));
+ workspace.forEachVisiblePage(
+ page -> addAnimationForPage((CellLayout) page, totalRows, duration));
boolean workspaceClipChildren = workspace.getClipChildren();
boolean workspaceClipToPadding = workspace.getClipToPadding();
@@ -119,23 +124,34 @@
View child = hotseatIcons.getChildAt(i);
CellLayout.LayoutParams lp =
((CellLayout.LayoutParams) child.getLayoutParams());
- addStaggeredAnimationForView(child, lp.cellY + 1, totalRows);
+ addStaggeredAnimationForView(child, lp.cellY + 1, totalRows, duration);
}
} else {
final int hotseatRow, qsbRow;
if (grid.isTaskbarPresent) {
- qsbRow = grid.inv.numRows + 1;
- hotseatRow = grid.inv.numRows + 2;
+ if (grid.isQsbInline) {
+ qsbRow = grid.inv.numRows + 1;
+ hotseatRow = grid.inv.numRows + 1;
+ } else {
+ qsbRow = grid.inv.numRows + 1;
+ hotseatRow = grid.inv.numRows + 2;
+ }
} else {
hotseatRow = grid.inv.numRows + 1;
qsbRow = grid.inv.numRows + 2;
}
- for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) {
- View child = hotseatIcons.getChildAt(i);
- addStaggeredAnimationForView(child, hotseatRow, totalRows);
- }
- addStaggeredAnimationForView(hotseat.getQsb(), qsbRow, totalRows);
+ // Do not stagger hotseat as a whole when taskbar is present, and stagger QSB only
+ // if it's not inline.
+ if (staggerHotseat) {
+ for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) {
+ View child = hotseatIcons.getChildAt(i);
+ addStaggeredAnimationForView(child, hotseatRow, totalRows, duration);
+ }
+ }
+ if (staggerQsb) {
+ addStaggeredAnimationForView(hotseat.getQsb(), qsbRow, totalRows, duration);
+ }
}
mAnimators.addListener(new AnimatorListenerAdapter() {
@@ -153,19 +169,19 @@
mAnimators.addListener(forEndCallback(launcher::resumeExpensiveViewUpdates));
if (animateOverviewScrim) {
- PendingAnimation pendingAnimation = new PendingAnimation(DURATION_MS);
+ PendingAnimation pendingAnimation = new PendingAnimation(duration);
launcher.getWorkspace().getStateTransitionAnimation()
.setScrim(pendingAnimation, NORMAL, new StateAnimationConfig());
mAnimators.play(pendingAnimation.buildAnim());
}
- addDepthAnimationForState(launcher, NORMAL, DURATION_MS);
+ addDepthAnimationForState(launcher, NORMAL, duration);
mAnimators.play(launcher.getRootView().getSysUiScrim().createSysuiMultiplierAnim(0f, 1f)
- .setDuration(DURATION_MS));
+ .setDuration(duration));
}
- private void addAnimationForPage(CellLayout page, int totalRows) {
+ private void addAnimationForPage(CellLayout page, int totalRows, long duration) {
ShortcutAndWidgetContainer itemsContainer = page.getShortcutsAndWidgets();
boolean pageClipChildren = page.getClipChildren();
@@ -178,7 +194,7 @@
for (int i = itemsContainer.getChildCount() - 1; i >= 0; i--) {
View child = itemsContainer.getChildAt(i);
CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
- addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows);
+ addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows, duration);
}
mAnimators.addListener(new AnimatorListenerAdapter() {
@@ -231,8 +247,9 @@
* @param v A view on the workspace.
* @param row The bottom-most row that contains the view.
* @param totalRows Total number of rows.
+ * @param duration duration of the animation
*/
- private void addStaggeredAnimationForView(View v, int row, int totalRows) {
+ private void addStaggeredAnimationForView(View v, int row, int totalRows, long duration) {
if (mIgnoredView != null && mIgnoredView == v) return;
// Invert the rows, because we stagger starting from the bottom of the screen.
int invertedRow = totalRows - row;
@@ -266,7 +283,7 @@
v.setAlpha(0);
ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f);
alpha.setInterpolator(LINEAR);
- alpha.setDuration(ALPHA_DURATION_MS);
+ alpha.setDuration(duration);
alpha.setStartDelay(startDelay);
alpha.addListener(new AnimatorListenerAdapter() {
@Override
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 76106fc..8c4c662 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -206,6 +206,13 @@
getShortcutsAndWidgets().setAlpha(alpha);
}
+ /**
+ * Sets the alpha value of just our QSB.
+ */
+ public void setQsbAlpha(float alpha) {
+ mQsb.setAlpha(alpha);
+ }
+
public float getIconsAlpha() {
return getShortcutsAndWidgets().getAlpha();
}
diff --git a/src/com/android/launcher3/util/HorizontalInsettableView.java b/src/com/android/launcher3/util/HorizontalInsettableView.java
index 7979bc0..486b73d 100644
--- a/src/com/android/launcher3/util/HorizontalInsettableView.java
+++ b/src/com/android/launcher3/util/HorizontalInsettableView.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.util;
+import android.util.FloatProperty;
+
/**
* Allows the implementing view to add insets to the left and right.
*/
@@ -32,4 +34,22 @@
*/
void setHorizontalInsets(float insetPercentage);
+ /**
+ * Returns the width percentage to inset the content from the left and from the right. See
+ * {@link #setHorizontalInsets};
+ */
+ float getHorizontalInsets();
+
+ FloatProperty<HorizontalInsettableView> HORIZONTAL_INSETS =
+ new FloatProperty<HorizontalInsettableView>("horizontalInsets") {
+ @Override
+ public Float get(HorizontalInsettableView view) {
+ return view.getHorizontalInsets();
+ }
+
+ @Override
+ public void setValue(HorizontalInsettableView view, float insetPercentage) {
+ view.setHorizontalInsets(insetPercentage);
+ }
+ };
}