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

Commit 2dbdddb4 authored by Vinit Nayak's avatar Vinit Nayak
Browse files

Add funtional animation for SplitSelect from Grid.

Long ways to go to final UI - TODO(b/186800707)
Add comments to grid layout code,
no functional changes at all.

Bug: 181705607
Test: Enter split screen from overview task menu
in grid and carousel. Able to select all items
and enter split.

Change-Id: Ib62f1b286acf0781ec47862fa31b670e6ff1892a
parent 13e4618b
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -15,12 +15,6 @@
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <com.android.quickstep.views.SplitPlaceholderView
        android:id="@+id/split_placeholder"
        android:layout_width="match_parent"
        android:layout_height="@dimen/split_placeholder_size"
        android:background="@android:color/darker_gray"
        android:visibility="gone" />

    <com.android.quickstep.views.LauncherRecentsView
        android:id="@+id/overview_panel"
@@ -31,6 +25,13 @@
        android:clipToPadding="false"
        android:visibility="invisible" />

    <com.android.quickstep.views.SplitPlaceholderView
        android:id="@+id/split_placeholder"
        android:layout_width="match_parent"
        android:layout_height="@dimen/split_placeholder_size"
        android:background="@android:color/darker_gray"
        android:visibility="gone" />

    <include
        android:id="@+id/overview_actions_view"
        layout="@layout/overview_actions_container" />
+5 −5
Original line number Diff line number Diff line
@@ -22,12 +22,12 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FA
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;

import android.util.FloatProperty;
@@ -97,10 +97,10 @@ public abstract class BaseRecentsViewStateController<T extends RecentsView>
        PagedOrientationHandler orientationHandler =
                ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
        FloatProperty taskViewsFloat = orientationHandler.getSplitSelectTaskOffset(
                TASK_PRIMARY_TRANSLATION, TASK_SECONDARY_TRANSLATION, mLauncher.getDeviceProfile());
                TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
                mLauncher.getDeviceProfile());
        setter.setFloat(mRecentsView, taskViewsFloat,
                toState.getOverviewSecondaryTranslation(mLauncher),
                config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
                toState.getOverviewSecondaryTranslation(mLauncher), LINEAR);

        setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
                config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
+10 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITIO
import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -64,6 +65,7 @@ public class SplitSelectStateController {
    private final SystemUiProxy mSystemUiProxy;
    private TaskView mInitialTaskView;
    private SplitPositionOption mInitialPosition;
    private Rect mInitialBounds;
    private final Handler mHandler;

    public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
@@ -74,9 +76,11 @@ public class SplitSelectStateController {
    /**
     * To be called after first task selected
     */
    public void setInitialTaskSelect(TaskView taskView, SplitPositionOption positionOption) {
    public void setInitialTaskSelect(TaskView taskView, SplitPositionOption positionOption,
            Rect initialBounds) {
        mInitialTaskView = taskView;
        mInitialPosition = positionOption;
        mInitialBounds = initialBounds;
    }

    /**
@@ -220,9 +224,14 @@ public class SplitSelectStateController {
    public void resetState() {
        mInitialTaskView = null;
        mInitialPosition = null;
        mInitialBounds = null;
    }

    public boolean isSplitSelectActive() {
        return mInitialTaskView != null;
    }

    public Rect getInitialBounds() {
        return mInitialBounds;
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -245,8 +245,8 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher, Laun
        if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
            // We want to keep the tasks translations in this temporary state
            // after resetting the rest above
            setTaskViewsResistanceTranslation(mTaskViewsSecondaryTranslation);
            setTaskViewsPrimaryTranslation(mTaskViewsPrimaryTranslation);
            setTaskViewsPrimarySplitTranslation(mTaskViewsPrimarySplitTranslation);
            setTaskViewsSecondarySplitTranslation(mTaskViewsSecondarySplitTranslation);
        }
    }

+135 −58
Original line number Diff line number Diff line
@@ -254,16 +254,29 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
     * more specific, we'd want to create a similar FloatProperty just for a TaskView's
     * offsetX/Y property
     */
    public static final FloatProperty<RecentsView> TASK_PRIMARY_TRANSLATION =
            new FloatProperty<RecentsView>("taskPrimaryTranslation") {
    public static final FloatProperty<RecentsView> TASK_PRIMARY_SPLIT_TRANSLATION =
            new FloatProperty<RecentsView>("taskPrimarySplitTranslation") {
                @Override
                public void setValue(RecentsView recentsView, float v) {
                    recentsView.setTaskViewsPrimaryTranslation(v);
                    recentsView.setTaskViewsPrimarySplitTranslation(v);
                }

                @Override
                public Float get(RecentsView recentsView) {
                    return recentsView.mTaskViewsPrimaryTranslation;
                    return recentsView.mTaskViewsPrimarySplitTranslation;
                }
            };

    public static final FloatProperty<RecentsView> TASK_SECONDARY_SPLIT_TRANSLATION =
            new FloatProperty<RecentsView>("taskSecondarySplitTranslation") {
                @Override
                public void setValue(RecentsView recentsView, float v) {
                    recentsView.setTaskViewsSecondarySplitTranslation(v);
                }

                @Override
                public Float get(RecentsView recentsView) {
                    return recentsView.mTaskViewsSecondarySplitTranslation;
                }
            };

@@ -279,7 +292,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
                    view.mLiveTileTaskViewSimulator.recentsViewScale.value = scale;
                    view.updatePageOffsets();
                    view.setTaskViewsResistanceTranslation(view.mTaskViewsSecondaryTranslation);
                    view.setTaskViewsPrimaryTranslation(view.mTaskViewsPrimaryTranslation);
                }

                @Override
@@ -363,7 +375,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T

    private float mAdjacentPageOffset = 0;
    protected float mTaskViewsSecondaryTranslation = 0;
    protected float mTaskViewsPrimaryTranslation = 0;
    protected float mTaskViewsPrimarySplitTranslation = 0;
    protected float mTaskViewsSecondarySplitTranslation = 0;
    // Progress from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
    private float mGridProgress = 0;
    private final IntSet mTopRowIdSet = new IntSet();
@@ -1839,15 +1852,28 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
        final int boxLength = Math.max(mLastComputedGridTaskSize.width(),
                mLastComputedGridTaskSize.height());
        int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
        float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
        float taskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;

        /*
         * taskGridVerticalDiff is used to position the top of a task in the top row of the grid
         * heightOffset is the vertical space one grid task takes + space between top and
         *   bottom row
         * Summed together they provide the top position for bottom row of grid tasks
         */
        final float taskGridVerticalDiff =
                mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
        final float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;

        int topRowWidth = 0;
        int bottomRowWidth = 0;
        float topAccumulatedTranslationX = 0;
        float bottomAccumulatedTranslationX = 0;

        // Contains whether the child index is in top or bottom of grid (for non-focused task)
        // Different from mTopRowIdSet, which contains the taskId of what task is in top row
        IntSet topSet = new IntSet();
        IntSet bottomSet = new IntSet();

        // Horizontal grid translation for each task
        float[] gridTranslations = new float[taskCount];

        int focusedTaskIndex = Integer.MAX_VALUE;
@@ -1901,7 +1927,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
                boolean isTopRow = isTaskDismissal ? mTopRowIdSet.contains(taskId)
                        : topRowWidth <= bottomRowWidth;
                if (isTopRow) {
                    gridTranslations[i] += topAccumulatedTranslationX;
                    topRowWidth += taskWidthAndSpacing;
                    topSet.add(i);
                    mTopRowIdSet.add(taskId);
@@ -1917,11 +1942,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
                        widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
                    }

                    float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
                    gridTranslations[i] += gridTranslationX;
                    topAccumulatedTranslationX += gridTranslationX;
                    float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
                    gridTranslations[i] += topAccumulatedTranslationX + currentTaskTranslationX;
                    topAccumulatedTranslationX += currentTaskTranslationX;
                } else {
                    gridTranslations[i] += bottomAccumulatedTranslationX;
                    bottomRowWidth += taskWidthAndSpacing;
                    bottomSet.add(i);

@@ -1937,9 +1961,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
                        widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
                    }

                    float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
                    gridTranslations[i] += gridTranslationX;
                    bottomAccumulatedTranslationX += gridTranslationX;
                    float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
                    gridTranslations[i] += bottomAccumulatedTranslationX + currentTaskTranslationX;
                    bottomAccumulatedTranslationX += currentTaskTranslationX;
                }
                if (taskView == snappedTaskView) {
                    snappedTaskRowWidth = isTopRow ? topRowWidth : bottomRowWidth;
@@ -2130,18 +2154,43 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
        // Use setFloat instead of setViewAlpha as we want to keep the view visible even when it's
        // alpha is set to 0 so that it can be recycled in the view pool properly
        anim.setFloat(taskView, VIEW_ALPHA, 0, ACCEL_2);
        FloatProperty<TaskView> secondaryViewTranslate =
                taskView.getSecondaryDissmissTranslationProperty();
        int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
        int verticalFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
        SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();

        ResourceProvider rp = DynamicResource.provider(mActivity);
        SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_START)
                .setDampingRatio(rp.getFloat(R.dimen.dismiss_task_trans_y_damping_ratio))
                .setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_y_stiffness));
        FloatProperty<TaskView> dismissingTaskViewTranslate =
                taskView.getSecondaryDissmissTranslationProperty();;
        // TODO(b/186800707) translate entire grid size distance
        int translateDistance = mOrientationHandler.getSecondaryDimension(taskView);
        int positiveNegativeFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
        if (splitController.isSplitSelectActive()) {
            // Have the task translate towards whatever side was just pinned
            int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitController
                    .getActiveSplitPositionOption(), mActivity.getDeviceProfile());
            switch (dir) {
                case PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE:
                    dismissingTaskViewTranslate = taskView
                            .getSecondaryDissmissTranslationProperty();
                    positiveNegativeFactor = -1;
                    break;

        anim.add(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate,
                verticalFactor * secondaryTaskDimension).setDuration(duration), LINEAR, sp);
                case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE:
                    dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty();
                    positiveNegativeFactor = 1;
                    break;

                case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_NEGATIVE:
                    dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty();
                    positiveNegativeFactor = -1;
                    break;
                default:
                    throw new IllegalStateException("Invalid split task translation: " + dir);
            }
        }
        anim.add(ObjectAnimator.ofFloat(taskView, dismissingTaskViewTranslate,
                positiveNegativeFactor * translateDistance).setDuration(duration), LINEAR, sp);

        if (LIVE_TILE.get() && taskView.isRunningTask()) {
            anim.addOnFrameCallback(() -> {
@@ -2206,18 +2255,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
                    }
                }

                // Additional offset for fake landscape, if the pinning happens to the right or
                // left, we need to scroll all the tasks away from the direction of the splaceholder
                // view
                if (isSplitSelectionActive()) {
                    int splitPosition = getSplitPlaceholder().getSplitController()
                            .getActiveSplitPositionOption().mStagePosition;
                    int direction = mOrientationHandler
                            .getSplitTranslationDirectionFactor(splitPosition);
                    int splitOffset = mOrientationHandler.getSplitAnimationTranslation(
                            mSplitPlaceholderView.getHeight(), mActivity.getDeviceProfile());
                    offset += direction * splitOffset;
                }
                int scrollDiff = newScroll[i] - oldScroll[i] + offset;
                if (scrollDiff != 0) {
                    FloatProperty translationProperty = child instanceof TaskView
@@ -2768,13 +2805,20 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
        mLiveTileTaskViewSimulator.recentsViewSecondaryTranslation.value = translation;
    }

    protected void setTaskViewsPrimaryTranslation(float translation) {
        mTaskViewsPrimaryTranslation = translation;
    protected void setTaskViewsPrimarySplitTranslation(float translation) {
        mTaskViewsPrimarySplitTranslation = translation;
        for (int i = 0; i < getTaskViewCount(); i++) {
            TaskView task = getTaskViewAt(i);
            task.getPrimaryDismissTranslationProperty().set(task, translation / getScaleY());
            task.getPrimarySplitTranslationProperty().set(task, translation);
        }
    }

    protected void setTaskViewsSecondarySplitTranslation(float translation) {
        mTaskViewsSecondarySplitTranslation = translation;
        for (int i = 0; i < getTaskViewCount(); i++) {
            TaskView task = getTaskViewAt(i);
            task.getSecondarySplitTranslationProperty().set(task, translation);
        }
        mLiveTileTaskViewSimulator.recentsViewPrimaryTranslation.value = translation;
    }

    /**
@@ -2797,8 +2841,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
    public void initiateSplitSelect(TaskView taskView, SplitPositionOption splitPositionOption) {
        mSplitHiddenTaskView = taskView;
        SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
        splitController.setInitialTaskSelect(taskView,
                splitPositionOption);
        Rect initialBounds = new Rect(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
                taskView.getBottom());
        splitController.setInitialTaskSelect(taskView, splitPositionOption, initialBounds);
        mSplitHiddenTaskViewIndex = indexOfChild(taskView);
        mSplitPlaceholderView.setLayoutParams(
                splitController.getLayoutParamsForActivePosition(getResources(),
@@ -2818,7 +2863,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
    }

    public PendingAnimation cancelSplitSelect(boolean animate) {
        mSplitPlaceholderView.getSplitController().resetState();
        SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
        SplitPositionOption splitOption = splitController.getActiveSplitPositionOption();
        Rect initialBounds = splitController.getInitialBounds();
        splitController.resetState();
        int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
        PendingAnimation pendingAnim = new PendingAnimation(duration);
        if (!animate) {
@@ -2833,8 +2881,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
        getPageScrolls(oldScroll, false,
                view -> view.getVisibility() != GONE && view != mSplitHiddenTaskView);

        // x is correct, y is before tasks move up
        int[] locationOnScreen = mSplitHiddenTaskView.getLocationOnScreen();
        int[] newScroll = new int[getChildCount()];
        getPageScrolls(newScroll, false, SIMPLE_SCROLL_LOGIC);

@@ -2842,20 +2888,42 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
        for (int i = mSplitHiddenTaskViewIndex; i >= 0; i--) {
            View child = getChildAt(i);
            if (child == mSplitHiddenTaskView) {
                TaskView taskView = (TaskView) child;

                int left = newScroll[i] + getPaddingStart();
                int topMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
                int top = -mSplitHiddenTaskView.getHeight() - locationOnScreen[1];
                mSplitHiddenTaskView.layout(left, top,
                        left + mSplitHiddenTaskView.getWidth(),
                        top + mSplitHiddenTaskView.getHeight());
                pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, TRANSLATION_Y,
                        -top + mSplitPlaceholderView.getHeight() - topMargin));
                int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitOption,
                        mActivity.getDeviceProfile());
                FloatProperty<TaskView> dismissingTaskViewTranslate;
                Rect hiddenBounds = new Rect(taskView.getLeft(), taskView.getTop(),
                        taskView.getRight(), taskView.getBottom());
                int distanceDelta = 0;
                if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE) {
                    dismissingTaskViewTranslate = taskView
                            .getSecondaryDissmissTranslationProperty();
                    distanceDelta = initialBounds.top - hiddenBounds.top;
                    taskView.layout(initialBounds.left, hiddenBounds.top, initialBounds.right,
                            hiddenBounds.bottom);
                } else {
                    dismissingTaskViewTranslate = taskView
                            .getPrimaryDismissTranslationProperty();
                    distanceDelta = initialBounds.left - hiddenBounds.left;
                    taskView.layout(hiddenBounds.left, initialBounds.top, hiddenBounds.right,
                            initialBounds.bottom);
                    if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE) {
                        distanceDelta *= -1;
                    }
                }
                pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView,
                        dismissingTaskViewTranslate,
                        distanceDelta));
                pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, ALPHA, 1));
            } else {
                // If insertion is on last index (furthest from clear all), we directly add the view
                // else we translate all views to the right of insertion index further right,
                // ignore views to left
                if (showAsGrid()) {
                    // TODO(b/186800707) handle more elegantly for grid
                    continue;
                }
                int scrollDiff = newScroll[i] - oldScroll[i];
                if (scrollDiff != 0) {
                    FloatProperty translationProperty = child instanceof TaskView
@@ -2881,6 +2949,12 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
        pendingAnim.addListener(new AnimationSuccessListener() {
            @Override
            public void onAnimationSuccess(Animator animator) {
                // TODO(b/186800707) Figure out how to undo for grid view
                //  Need to handle cases where dismissed task is
                //  * Top Row
                //  * Bottom Row
                //  * Focused Task
                updateGridProperties();
                resetFromSplitSelectionState();
            }
        });
@@ -2890,6 +2964,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T

    private void resetFromSplitSelectionState() {
        mSplitHiddenTaskView.setTranslationY(0);
        if (!showAsGrid()) {
            // TODO(b/186800707)
            int pageToSnapTo = mCurrentPage;
            if (mSplitHiddenTaskViewIndex <= pageToSnapTo) {
                pageToSnapTo += 1;
@@ -2897,6 +2973,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
                pageToSnapTo = mSplitHiddenTaskViewIndex;
            }
            snapToPageImmediately(pageToSnapTo);
        }
        onLayout(false /*  changed */, getLeft(), getTop(), getRight(), getBottom());
        resetTaskVisuals();
        mSplitHiddenTaskView = null;
Loading