Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b583f18e authored by Alex Chau's avatar Alex Chau Committed by Automerger Merge Worker
Browse files

Merge "Animate inline QSB between home and apps" into tm-qpr-dev am: a5ae4c2e am: 7e77cda9

parents da9e22f4 7e77cda9
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP;
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 class QuickstepTransitionManager implements OnDeviceProfileChangeListener
    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 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
            workspace.forEachVisiblePage(
                    view -> viewsToAnimate.add(((CellLayout) view).getShortcutsAndWidgets()));

            // 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);
+3 −1
Original line number Diff line number Diff line
@@ -171,7 +171,9 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
                isResumed,
                fromInit,
                /* startAnimation= */ true,
                QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
                !isResumed
                        ? QuickstepTransitionManager.TASKBAR_TO_APP_DURATION
                        : QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION);
    }

    @Nullable
+45 −13
Original line number Diff line number Diff line
@@ -19,11 +19,13 @@ 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;

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 androidx.annotation.Nullable;
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 com.android.systemui.shared.recents.model.ThumbnailData;
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 @@ import java.util.function.Supplier;
 */
 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,9 +104,13 @@ import java.util.function.Supplier;
                    }
                    updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, true);
                    if (!mShouldDelayLauncherStateAnim) {
                        if (toState == LauncherState.NORMAL) {
                            applyState(QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION);
                        } else {
                            applyState();
                        }
                    }
                }

                @Override
                public void onStateTransitionComplete(LauncherState finalState) {
@@ -122,7 +131,12 @@ import java.util.function.Supplier;
        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 @@ import java.util.function.Supplier;
                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 @@ import java.util.function.Supplier;
                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 @@ import java.util.function.Supplier;
                    .setDuration(duration));
        }

        animatorSet.setInterpolator(EMPHASIZED);
        if (start) {
            animatorSet.start();
        }
@@ -374,6 +399,12 @@ import java.util.function.Supplier;
            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 @@ import java.util.function.Supplier;
        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 @@ import java.util.function.Supplier;
        }
    }

    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) {
+45 −5
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.res.Resources;
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.annotation.Nullable;
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 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
    // 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 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
                    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 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
        if (mAllAppsButton != null) {
            removeView(mAllAppsButton);
        }
        removeView(mQsb);

        for (int i = 0; i < hotseatItemInfos.length; i++) {
            ItemInfo hotseatItemInfo = hotseatItemInfos[i];
@@ -242,6 +250,11 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
            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 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
    @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,11 +310,26 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
        mIconLayoutBounds.bottom = mIconLayoutBounds.top + mIconTouchSize;
        for (int i = count; i > 0; i--) {
            View child = getChildAt(i - 1);
            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 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
        return mAllAppsButton;
    }

    /**
     * Returns the QSB in the taskbar.
     */
    public View getQsb() {
        return mQsb;
    }

    // FolderIconParent implemented methods.

    @Override
+48 −9
Original line number Diff line number Diff line
@@ -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.BubbleTextView;
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;
@@ -212,9 +216,10 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
     *                       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) {
@@ -226,11 +231,13 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
    /**
     * 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,
@@ -247,14 +254,13 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
        }

        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()) {
@@ -262,13 +268,46 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
                // 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;
Loading