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

Commit 7fab6196 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Animates a fake TaskView in Home gesture tutorial." into ub-launcher3-rvc-dev

parents bc374cf7 f8a81176
Loading
Loading
Loading
Loading
+4 −314
Original line number Diff line number Diff line
@@ -15,58 +15,38 @@
 */
package com.android.quickstep;

import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;

import android.animation.Animator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.Interpolator;

import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;

import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;

import java.util.ArrayList;
import java.util.function.Consumer;
@@ -76,40 +56,13 @@ import java.util.function.Consumer;
 */
@TargetApi(Build.VERSION_CODES.Q)
public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extends RecentsView>
        implements RecentsAnimationListener {
        extends SwipeUpAnimationLogic implements RecentsAnimationListener {

    private static final String TAG = "BaseSwipeUpHandler";
    protected static final Rect TEMP_RECT = new Rect();

    public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
    private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;

    // The distance needed to drag to reach the task size in recents.
    protected int mTransitionDragLength;
    // How much further we can drag past recents, as a factor of mTransitionDragLength.
    protected float mDragLengthFactor = 1;
    // Start resisting when swiping past this factor of mTransitionDragLength.
    private float mDragLengthFactorStartPullback = 1f;
    // This is how far down we can scale down, where 0f is full screen and 1f is recents.
    private float mDragLengthFactorMaxPullback = 1f;

    protected final Context mContext;
    protected final RecentsAnimationDeviceState mDeviceState;
    protected final GestureState mGestureState;

    protected final BaseActivityInterface<?, T> mActivityInterface;
    protected final InputConsumerController mInputConsumer;

    protected final TaskViewSimulator mTaskViewSimulator;
    private AnimatorPlaybackController mWindowTransitionController;

    protected final TransformParams mTransformParams = new TransformParams();

    // Shift in the range of [0, 1].
    // 0 => preview snapShot is completely visible, and hotseat is completely translated down
    // 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
    // visible.
    protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);

    protected final ActivityInitListener mActivityInitListener;

    protected RecentsAnimationController mRecentsAnimationController;
@@ -120,7 +73,6 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend

    protected T mActivity;
    protected Q mRecentsView;
    protected DeviceProfile mDp;

    protected Runnable mGestureEndCallback;

@@ -132,13 +84,10 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend

    protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
            GestureState gestureState, InputConsumerController inputConsumer) {
        mContext = context;
        mDeviceState = deviceState;
        mGestureState = gestureState;
        super(context, deviceState, gestureState, new TransformParams());
        mActivityInterface = gestureState.getActivityInterface();
        mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
        mInputConsumer = inputConsumer;
        mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface());
    }

    /**
@@ -158,28 +107,6 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
        return mRecentsView != null ? mRecentsView.getEventDispatcher(navbarRotation) : null;
    }

    @UiThread
    public void updateDisplacement(float displacement) {
        // We are moving in the negative x/y direction
        displacement = -displacement;
        float shift;
        if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) {
            shift = mDragLengthFactor;
        } else {
            float translation = Math.max(displacement, 0);
            shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
            if (shift > mDragLengthFactorStartPullback) {
                float pullbackProgress = Utilities.getProgress(shift,
                        mDragLengthFactorStartPullback, mDragLengthFactor);
                pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
                shift = mDragLengthFactorStartPullback + pullbackProgress
                        * (mDragLengthFactorMaxPullback - mDragLengthFactorStartPullback);
            }
        }

        mCurrentShift.updateValue(shift);
    }

    public void setGestureEndCallback(Runnable gestureEndCallback) {
        mGestureEndCallback = gestureEndCallback;
    }
@@ -276,6 +203,7 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
            RecentsAnimationTargets targets) {
        mRecentsAnimationController = recentsAnimationController;
        mRecentsAnimationTargets = targets;
        mTransformParams.setTargetSet(mRecentsAnimationTargets);
        DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
        RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
                mGestureState.getRunningTaskId());
@@ -357,35 +285,6 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
        return mGestureState.getLastStartedTaskId() != -1;
    }

    protected void initTransitionEndpoints(DeviceProfile dp) {
        mDp = dp;

        mTaskViewSimulator.setDp(dp);
        mTaskViewSimulator.setLayoutRotation(
                mDeviceState.getCurrentActiveRotation(),
                mDeviceState.getDisplayRotation());
        mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength(
                dp, mContext, TEMP_RECT,
                mTaskViewSimulator.getOrientationState().getOrientationHandler());

        if (mDeviceState.isFullyGesturalNavMode()) {
            // We can drag all the way to the top of the screen.
            mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;

            float startScale = mTaskViewSimulator.getFullScreenScale();
            // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
            mDragLengthFactorStartPullback = (0.75f - startScale) / (1 - startScale);
            mDragLengthFactorMaxPullback = (0.5f - startScale) / (1 - startScale);
        } else {
            mDragLengthFactor = 1;
            mDragLengthFactorStartPullback = mDragLengthFactorMaxPullback = 1;
        }

        PendingAnimation pa = new PendingAnimation(mTransitionDragLength * 2);
        mTaskViewSimulator.addAppToOverviewAnim(pa, t -> t * mDragLengthFactor);
        mWindowTransitionController = pa.createPlaybackController();
    }

    /**
     * Return true if the window should be translated horizontally if the recents view scrolls
     */
@@ -457,7 +356,6 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
        if (mWindowTransitionController != null) {
            float progress = mCurrentShift.value / mDragLengthFactor;
            mWindowTransitionController.setPlayFraction(progress);
            mTransformParams.setTargetSet(mRecentsAnimationTargets);

            if (mRecentsViewScrollLinked) {
                mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
@@ -466,217 +364,9 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
        }
    }

    protected PagedOrientationHandler getOrientationHandler() {
        return mTaskViewSimulator.getOrientationState().getOrientationHandler();
    }

    /**
     * Creates an animation that transforms the current app window into the home app.
     * @param startProgress The progress of {@link #mCurrentShift} to start the window from.
     * @param homeAnimationFactory The home animation factory.
     */
    protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
            HomeAnimationFactory homeAnimationFactory) {
        final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
        final FloatingIconView fiv = homeAnimationFactory.mIconView;
        final boolean isFloatingIconView = fiv != null;

        mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor);
        mTaskViewSimulator.apply(mTransformParams
                .setProgress(startProgress)
                .setTargetSet(mRecentsAnimationTargets));
        RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect());

        // Matrix to map a rect in Launcher space to window space
        Matrix homeToWindowPositionMap = new Matrix();
        mTaskViewSimulator.applyWindowToHomeRotation(homeToWindowPositionMap);

        final RectF startRect = new RectF(cropRectF);
        mTaskViewSimulator.getCurrentMatrix().mapRect(startRect);
        // Move the startRect to Launcher space as floatingIconView runs in Launcher
        Matrix windowToHomePositionMap = new Matrix();
        homeToWindowPositionMap.invert(windowToHomePositionMap);
        windowToHomePositionMap.mapRect(startRect);

        RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
        if (isFloatingIconView) {
            anim.addAnimatorListener(fiv);
            fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
            fiv.setFastFinishRunnable(anim::end);
        }

        SpringAnimationRunner runner = new SpringAnimationRunner(
                homeAnimationFactory, cropRectF, homeToWindowPositionMap);
        anim.addOnUpdateListener(runner);
        anim.addAnimatorListener(runner);
        return anim;
    }

    public interface Factory {

        BaseSwipeUpHandler newHandler(
                GestureState gestureState, long touchTimeMs, boolean continuingLastGesture);
    }

    protected interface RunningWindowAnim {
        void end();

        void cancel();

        static RunningWindowAnim wrap(Animator animator) {
            return new RunningWindowAnim() {
                @Override
                public void end() {
                    animator.end();
                }

                @Override
                public void cancel() {
                    animator.cancel();
                }
            };
        }

        static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) {
            return new RunningWindowAnim() {
                @Override
                public void end() {
                    rectFSpringAnim.end();
                }

                @Override
                public void cancel() {
                    rectFSpringAnim.cancel();
                }
            };
        }
    }

    /**
     * @param progress The progress of the animation to the home screen.
     * @return The current alpha to set on the animating app window.
     */
    protected float getWindowAlpha(float progress) {
        // Alpha interpolates between [1, 0] between progress values [start, end]
        final float start = 0f;
        final float end = 0.85f;

        if (progress <= start) {
            return 1f;
        }
        if (progress >= end) {
            return 0f;
        }
        return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5);
    }

    protected abstract class HomeAnimationFactory {

        private FloatingIconView mIconView;

        public HomeAnimationFactory(@Nullable FloatingIconView iconView) {
            mIconView = iconView;
        }

        public @NonNull RectF getWindowTargetRect() {
            PagedOrientationHandler orientationHandler = getOrientationHandler();
            DeviceProfile dp = mDp;
            final int halfIconSize = dp.iconSizePx / 2;
            float primaryDimension = orientationHandler
                    .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
            float secondaryDimension = orientationHandler
                    .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
            final float targetX =  primaryDimension / 2f;
            final float targetY = secondaryDimension - dp.hotseatBarSizePx;
            // Fallback to animate to center of screen.
            return new RectF(targetX - halfIconSize, targetY - halfIconSize,
                    targetX + halfIconSize, targetY + halfIconSize);
        }

        public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome();

        public void playAtomicAnimation(float velocity) {
            // No-op
        }
    }

    private class SpringAnimationRunner extends AnimationSuccessListener
            implements RectFSpringAnim.OnUpdateListener, BuilderProxy {

        final Rect mCropRect = new Rect();
        final Matrix mMatrix = new Matrix();

        final RectF mWindowCurrentRect = new RectF();
        final Matrix mHomeToWindowPositionMap;

        final FloatingIconView mFIV;
        final AnimatorPlaybackController mHomeAnim;
        final RectF mCropRectF;

        final float mStartRadius;
        final float mEndRadius;
        final float mWindowAlphaThreshold;

        SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF,
                Matrix homeToWindowPositionMap) {
            mHomeAnim = factory.createActivityAnimationToHome();
            mCropRectF = cropRectF;
            mHomeToWindowPositionMap = homeToWindowPositionMap;

            cropRectF.roundOut(mCropRect);
            mFIV = factory.mIconView;

            // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
            // rounding at the end of the animation.
            mStartRadius = mTaskViewSimulator.getCurrentCornerRadius();
            mEndRadius = cropRectF.width() / 2f;

            // We want the window alpha to be 0 once this threshold is met, so that the
            // FolderIconView can be seen morphing into the icon shape.
            mWindowAlphaThreshold = mFIV != null ? 1f - SHAPE_PROGRESS_DURATION : 1f;
        }

        @Override
        public void onUpdate(RectF currentRect, float progress) {
            mHomeAnim.setPlayFraction(progress);
            mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);

            mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
            float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
            mTransformParams
                    .setTargetAlpha(getWindowAlpha(progress))
                    .setCornerRadius(cornerRadius);

            mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
            if (mFIV != null) {
                mFIV.update(currentRect, 1f, progress,
                        mWindowAlphaThreshold, mMatrix.mapRadius(cornerRadius), false);
            }
        }

        @Override
        public void onBuildTargetParams(
                Builder builder, RemoteAnimationTargetCompat app, TransformParams params) {
            builder.withMatrix(mMatrix)
                    .withWindowCrop(mCropRect)
                    .withCornerRadius(params.getCornerRadius());
        }

        @Override
        public void onCancel() {
            if (mFIV != null) {
                mFIV.fastFinish();
            }
        }

        @Override
        public void onAnimationStart(Animator animation) {
            mHomeAnim.dispatchOnStart();
        }

        @Override
        public void onAnimationSuccess(Animator animator) {
            mHomeAnim.getAnimationPlayer().end();
        }
    }
}
+350 −0

File added.

Preview size limit exceeded, changes collapsed.

+9 −3
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.quickstep.fallback;

import android.graphics.PointF;
import android.view.MotionEvent;

import androidx.annotation.Nullable;
@@ -30,7 +31,8 @@ import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
/**
 * In 0-button mode, intercepts swipe up from the nav bar on FallbackRecentsView to go home.
 */
public class FallbackNavBarTouchController implements TouchController {
public class FallbackNavBarTouchController implements TouchController,
        TriggerSwipeUpTouchTracker.OnSwipeUpListener {

    private final RecentsActivity mActivity;
    @Nullable
@@ -44,7 +46,7 @@ public class FallbackNavBarTouchController implements TouchController {
                    DefaultDisplay.INSTANCE.get(mActivity).getInfo());
            mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mActivity,
                    true /* disableHorizontalSwipe */, navBarPosition,
                    null /* onInterceptTouch */, this::onSwipeUp);
                    null /* onInterceptTouch */, this);
        } else {
            mTriggerSwipeUpTracker = null;
        }
@@ -72,7 +74,11 @@ public class FallbackNavBarTouchController implements TouchController {
        return false;
    }

    private void onSwipeUp(boolean wasFling) {
    @Override
    public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
        mActivity.<FallbackRecentsView>getOverviewPanel().startHome();
    }

    @Override
    public void onSwipeUpCancelled() {}
}
+9 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.quickstep.inputconsumers;

import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
import android.view.MotionEvent;

import com.android.launcher3.BaseActivity;
@@ -33,7 +34,8 @@ import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
import com.android.systemui.shared.system.InputMonitorCompat;

public class OverviewWithoutFocusInputConsumer implements InputConsumer {
public class OverviewWithoutFocusInputConsumer implements InputConsumer,
        TriggerSwipeUpTouchTracker.OnSwipeUpListener {

    private final Context mContext;
    private final InputMonitorCompat mInputMonitor;
@@ -45,7 +47,7 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer {
        mContext = context;
        mInputMonitor = inputMonitor;
        mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(context, disableHorizontalSwipe,
                deviceState.getNavBarPosition(), this::onInterceptTouch, this::onSwipeUp);
                deviceState.getNavBarPosition(), this::onInterceptTouch, this);
    }

    @Override
@@ -70,7 +72,8 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer {
        }
    }

    private void onSwipeUp(boolean wasFling) {
    @Override
    public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
        mContext.startActivity(new Intent(Intent.ACTION_MAIN)
                .addCategory(Intent.CATEGORY_HOME)
                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
@@ -83,4 +86,7 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer {
                wasFling ? Touch.FLING : Touch.SWIPE, Direction.UP, containerType, pageIndex);
        activity.getUserEventDispatcher().setPreviousHomeGesture(true);
    }

    @Override
    public void onSwipeUpCancelled() {}
}
+13 −8
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_
import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -74,7 +75,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
    private DeviceProfile mDp;

    private final Matrix mMatrix = new Matrix();
    private RemoteAnimationTargetCompat mRunningTarget;
    private final Point mRunningTargetWindowPosition = new Point();

    // Thumbnail view properties
    private final Rect mThumbnailPosition = new Rect();
@@ -139,13 +140,19 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
     * Sets the targets which the simulator will control
     */
    public void setPreview(RemoteAnimationTargetCompat runningTarget) {
        mRunningTarget = runningTarget;
        setPreviewBounds(runningTarget.screenSpaceBounds, runningTarget.contentInsets);
        mRunningTargetWindowPosition.set(runningTarget.position.x, runningTarget.position.y);
    }

        mThumbnailData.insets.set(mRunningTarget.contentInsets);
    /**
     * Sets the targets which the simulator will control
     */
    public void setPreviewBounds(Rect bounds, Rect insets) {
        mThumbnailData.insets.set(insets);
        // TODO: What is this?
        mThumbnailData.windowingMode = WINDOWING_MODE_FULLSCREEN;

        mThumbnailPosition.set(runningTarget.screenSpaceBounds);
        mThumbnailPosition.set(bounds);
        mLayoutValid = false;
    }

@@ -199,16 +206,14 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
        postDisplayRotation(deltaRotation(
                mOrientationState.getLauncherRotation(), mOrientationState.getDisplayRotation()),
                mDp.widthPx, mDp.heightPx, matrix);
        if (mRunningTarget != null) {
            matrix.postTranslate(-mRunningTarget.position.x, -mRunningTarget.position.y);
        }
        matrix.postTranslate(-mRunningTargetWindowPosition.x, -mRunningTargetWindowPosition.y);
    }

    /**
     * Applies the target to the previously set parameters
     */
    public void apply(TransformParams params) {
        if (mDp == null || mRunningTarget == null) {
        if (mDp == null || mThumbnailPosition.isEmpty()) {
            return;
        }
        if (!mLayoutValid) {
Loading