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

Commit 0f6526e0 authored by Vinit Nayak's avatar Vinit Nayak
Browse files

Improve TaskMenuView layouts for split pairs

* Instead of basing calculations on the TaskView view,
use the TaskThumbnailView as the anchor.
This helps us prevent having to re-calculate positions
that were already done to layout the thumbnails
* TODO: Gracefully handle re-positioning task menu view
on rotation

Bug: 249693334
Test: Manual, opening task menu view in
land/seascape in portrait, w/ and w/o home rotation

Change-Id: I02da96d2735657d5340e23056de69392ff8452c4
parent 3c8ae3ef
Loading
Loading
Loading
Loading
+0 −17
Original line number Diff line number Diff line
package com.android.quickstep.views;

import static com.android.launcher3.AbstractFloatingView.getAnyView;
import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -14,7 +13,6 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -164,21 +162,6 @@ public class GroupedTaskView extends TaskView {
        }
    }

    @Override
    protected boolean showTaskMenuWithContainer(IconView iconView) {
        boolean showedTaskMenu = super.showTaskMenuWithContainer(iconView);
        if (iconView == mIconView2 && showedTaskMenu && !mActivity.getDeviceProfile().isTablet) {
            // Adjust the position of the secondary task's menu view (only on phones)
            TaskMenuView taskMenuView = getAnyView(mActivity, AbstractFloatingView.TYPE_TASK_MENU);
            DeviceProfile deviceProfile = mActivity.getDeviceProfile();
            getRecentsView().getPagedOrientationHandler()
                    .setSecondaryTaskMenuPosition(mSplitBoundsConfig, this,
                            deviceProfile, mTaskIdAttributeContainer[0].getThumbnailView(),
                            taskMenuView);
        }
        return showedTaskMenu;
    }

    @Nullable
    @Override
    public RunnableList launchTaskAnimated() {
+20 −45
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Outline;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
@@ -32,7 +31,6 @@ import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.widget.LinearLayout;
import android.widget.TextView;

@@ -56,13 +54,12 @@ import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
/**
 * Contains options for a recent task when long-pressing its icon.
 */
public class TaskMenuView extends AbstractFloatingView implements OnScrollChangedListener {
public class TaskMenuView extends AbstractFloatingView {

    private static final Rect sTempRect = new Rect();

    private static final int REVEAL_OPEN_DURATION = 150;
    private static final int REVEAL_CLOSE_DURATION = 100;
    private final float mTaskInsetMargin;

    private BaseDraggingActivity mActivity;
    private TextView mTaskName;
@@ -81,7 +78,6 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange

        mActivity = BaseDraggingActivity.fromContext(context);
        setClipToOutline(true);
        mTaskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
    }

    @Override
@@ -129,33 +125,6 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange
        };
    }

    private void setPosition(float x, float y, int overscrollShift) {
        PagedOrientationHandler pagedOrientationHandler = mTaskView.getPagedOrientationHandler();
        // Inset due to margin
        PointF additionalInset = pagedOrientationHandler
                .getAdditionalInsetForTaskMenu(mTaskInsetMargin);
        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
        int taskTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;

        float adjustedY = y + taskTopMargin - additionalInset.y;
        float adjustedX = x - additionalInset.x;
        // Changing pivot to make computations easier
        // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set,
        // which would render the X and Y position set here incorrect
        setPivotX(0);
        if (deviceProfile.isTablet) {
            // In tablet, set pivotY to original position without mThumbnailTopMargin adjustment.
            setPivotY(-taskTopMargin);
        } else {
            setPivotY(0);
        }
        setRotation(pagedOrientationHandler.getDegreesRotated());
        setX(pagedOrientationHandler.getTaskMenuX(adjustedX,
                mTaskContainer.getThumbnailView(), overscrollShift, deviceProfile));
        setY(pagedOrientationHandler.getTaskMenuY(
                adjustedY, mTaskContainer.getThumbnailView(), overscrollShift));
    }

    public void onRotationChanged() {
        if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
            mOpenCloseAnimator.end();
@@ -187,17 +156,9 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange
            return false;
        }
        post(this::animateOpen);
        ((RecentsView) mActivity.getOverviewPanel()).addOnScrollChangedListener(this);
        return true;
    }

    @Override
    public void onScrollChanged() {
        RecentsView rv = mActivity.getOverviewPanel();
        setPosition(mTaskView.getX() - rv.getScrollX(), mTaskView.getY() - rv.getScrollY(),
                rv.getOverScrollShift());
    }

    /** @return true if successfully able to populate task view menu, false otherwise */
    private boolean populateAndLayoutMenu() {
        if (mTaskContainer.getTask().icon == null) {
@@ -234,18 +195,18 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange
        RecentsView recentsView = mActivity.getOverviewPanel();
        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
        measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
        orientationHandler.setTaskMenuAroundTaskView(this, mTaskInsetMargin);

        // Get Position
        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
        mActivity.getDragLayer().getDescendantRectRelativeToSelf(mTaskView, sTempRect);
        mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskContainer.getThumbnailView(),
                sTempRect);
        Rect insets = mActivity.getDragLayer().getInsets();
        BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
        int padding = getResources()
                .getDimensionPixelSize(R.dimen.task_menu_vertical_padding);
        params.width = orientationHandler
                .getTaskMenuWidth(taskContainer.getThumbnailView(),
                        deviceProfile) - (2 * padding);
                        deviceProfile, taskContainer.getStagePosition()) - (2 * padding);
        // Gravity set to Left instead of Start as sTempRect.left measures Left distance not Start
        params.gravity = Gravity.LEFT;
        setLayoutParams(params);
@@ -260,7 +221,22 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange

        orientationHandler.setTaskOptionsMenuLayoutOrientation(
                deviceProfile, mOptionLayout, dividerSpacing, divider);
        setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top, 0);
        float thumbnailAlignedX = sTempRect.left - insets.left;
        float thumbnailAlignedY = sTempRect.top - insets.top;
        // Changing pivot to make computations easier
        // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set,
        // which would render the X and Y position set here incorrect
        setPivotX(0);
        setPivotY(0);
        setRotation(orientationHandler.getDegreesRotated());

        // Margin that insets the menuView inside the taskView
        float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
        setTranslationX(orientationHandler.getTaskMenuX(thumbnailAlignedX,
                mTaskContainer.getThumbnailView(), deviceProfile, taskInsetMargin));
        setTranslationY(orientationHandler.getTaskMenuY(
                thumbnailAlignedY, mTaskContainer.getThumbnailView(),
                mTaskContainer.getStagePosition(), this, taskInsetMargin));
    }

    private void animateOpen() {
@@ -306,7 +282,6 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange
    private void closeComplete() {
        mIsOpen = false;
        mActivity.getDragLayer().removeView(this);
        ((RecentsView) mActivity.getOverviewPanel()).removeOnScrollChangedListener(this);
    }

    private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
+21 −32
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;

import android.content.res.Resources;
@@ -265,20 +266,32 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
    }

    @Override
    public float getTaskMenuX(float x, View thumbnailView, int overScroll,
            DeviceProfile deviceProfile) {
        return thumbnailView.getMeasuredWidth() + x;
    public float getTaskMenuX(float x, View thumbnailView,
            DeviceProfile deviceProfile, float taskInsetMargin) {
        return thumbnailView.getMeasuredWidth() + x - taskInsetMargin;
    }

    @Override
    public float getTaskMenuY(float y, View thumbnailView, int overScroll) {
        return y + overScroll +
                (thumbnailView.getMeasuredHeight() - thumbnailView.getMeasuredWidth()) / 2f;
    public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
            View taskMenuView, float taskInsetMargin) {
        BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
        int taskMenuWidth = lp.width;
        if (stagePosition == STAGE_POSITION_UNDEFINED) {
            return y + taskInsetMargin
                    + (thumbnailView.getMeasuredHeight() - taskMenuWidth) / 2f;
        } else {
            return y + taskInsetMargin;
        }
    }

    @Override
    public int getTaskMenuWidth(View view, DeviceProfile deviceProfile) {
        return view.getMeasuredWidth();
    public int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
            @StagePosition int stagePosition) {
        if (stagePosition == SplitConfigurationOptions.STAGE_POSITION_UNDEFINED) {
            return thumbnailView.getMeasuredWidth();
        } else {
            return thumbnailView.getMeasuredHeight();
        }
    }

    @Override
@@ -299,17 +312,6 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
        lp.height = WRAP_CONTENT;
    }

    @Override
    public void setTaskMenuAroundTaskView(LinearLayout taskView, float margin) {
        BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskView.getLayoutParams();
        lp.topMargin += margin;
    }

    @Override
    public PointF getAdditionalInsetForTaskMenu(float margin) {
        return new PointF(margin, 0);
    }

    @Override
    public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
            int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
@@ -376,19 +378,6 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
        return isRtl ? 1 : -1;
    }

    @Override
    public void setSecondaryTaskMenuPosition(SplitBounds splitBounds, View taskView,
            DeviceProfile deviceProfile, View primarySnaphotView, View taskMenuView) {
        float topLeftTaskPlusDividerPercent = splitBounds.appsStackedVertically
                ? (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent)
                : (splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent);
        FrameLayout.LayoutParams snapshotParams =
                (FrameLayout.LayoutParams) primarySnaphotView.getLayoutParams();
        float additionalOffset = (taskView.getHeight() - snapshotParams.topMargin)
                * topLeftTaskPlusDividerPercent;
        taskMenuView.setY(taskMenuView.getY() + additionalOffset);
    }

    /* -------------------- */

    @Override
+6 −21
Original line number Diff line number Diff line
@@ -184,9 +184,12 @@ public interface PagedOrientationHandler {
     * taskMenu width is the same size as the thumbnail width (what got set below in
     * getTaskMenuWidth()), so we directly use that in the calculations.
     */
    float getTaskMenuX(float x, View thumbnailView, int overScroll, DeviceProfile deviceProfile);
    float getTaskMenuY(float y, View thumbnailView, int overScroll);
    int getTaskMenuWidth(View view, DeviceProfile deviceProfile);
    float getTaskMenuX(float x, View thumbnailView, DeviceProfile deviceProfile,
            float taskInsetMargin);
    float getTaskMenuY(float y, View thumbnailView, int stagePosition,
            View taskMenuView, float taskInsetMargin);
    int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
            @StagePosition int stagePosition);
    /**
     * Sets linear layout orientation for {@link com.android.launcher3.popup.SystemShortcut} items
     * inside task menu view.
@@ -200,16 +203,6 @@ public interface PagedOrientationHandler {
     */
    void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
            LinearLayout viewGroup, DeviceProfile deviceProfile);
    /**
     * Adjusts margins for the entire task menu view itself, which comprises of both app title and
     * shortcut options.
     */
    void setTaskMenuAroundTaskView(LinearLayout taskView, float margin);
    /**
     * Since the task menu layout is manually positioned on top of recents view, this method returns
     * additional adjustments to the positioning based on fake land/seascape
     */
    PointF getAdditionalInsetForTaskMenu(float margin);

    /**
     * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
@@ -230,14 +223,6 @@ public interface PagedOrientationHandler {
    /** @return Either 1 or -1, a factor to multiply by so the animation goes the correct way. */
    int getTaskDragDisplacementFactor(boolean isRtl);

    /**
     * Calls the corresponding {@link View#setX(float)} or {@link View#setY(float)}
     * on {@param taskMenuView} by taking the space needed by {@param primarySnapshotView} into
     * account.
     * This is expected to only be called for secondary (bottom/right) tasks.
     */
    void setSecondaryTaskMenuPosition(SplitBounds splitBounds, View taskView,
            DeviceProfile deviceProfile, View primarySnaphotView, View taskMenuView);
    /**
     * Maps the velocity from the coordinate plane of the foreground app to that
     * of Launcher's (which now will always be portrait)
+11 −42
Original line number Diff line number Diff line
@@ -55,7 +55,6 @@ import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.launcher3.views.BaseDragLayer;

import java.util.List;

@@ -264,26 +263,28 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
    }

    @Override
    public float getTaskMenuX(float x, View thumbnailView, int overScroll,
            DeviceProfile deviceProfile) {
    public float getTaskMenuX(float x, View thumbnailView,
            DeviceProfile deviceProfile, float taskInsetMargin) {
        if (deviceProfile.isLandscape) {
            return x + overScroll
            return x + taskInsetMargin
                    + (thumbnailView.getMeasuredWidth() - thumbnailView.getMeasuredHeight()) / 2f;
        } else {
            return x + overScroll;
            return x + taskInsetMargin;
        }
    }

    @Override
    public float getTaskMenuY(float y, View thumbnailView, int overScroll) {
        return y;
    public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
            View taskMenuView, float taskInsetMargin) {
        return y + taskInsetMargin;
    }

    @Override
    public int getTaskMenuWidth(View view, DeviceProfile deviceProfile) {
    public int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
            @StagePosition int stagePosition) {
        return deviceProfile.isLandscape && !deviceProfile.isTablet
                ? view.getMeasuredHeight()
                : view.getMeasuredWidth();
                ? thumbnailView.getMeasuredHeight()
                : thumbnailView.getMeasuredWidth();
    }

    @Override
@@ -303,38 +304,6 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
        lp.height = WRAP_CONTENT;
    }

    @Override
    public void setTaskMenuAroundTaskView(LinearLayout taskView, float margin) {
        BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskView.getLayoutParams();
        lp.topMargin += margin;
        lp.leftMargin += margin;
    }

    @Override
    public PointF getAdditionalInsetForTaskMenu(float margin) {
        return new PointF(0, 0);
    }

    @Override
    public void setSecondaryTaskMenuPosition(SplitBounds splitBounds, View taskView,
            DeviceProfile deviceProfile, View primarySnaphotView, View taskMenuView) {
        float topLeftTaskPlusDividerPercent = splitBounds.appsStackedVertically
                ? (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent)
                : (splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent);
        FrameLayout.LayoutParams snapshotParams =
                (FrameLayout.LayoutParams) primarySnaphotView.getLayoutParams();
        float additionalOffset;
        if (deviceProfile.isLandscape) {
            additionalOffset = (taskView.getWidth() - snapshotParams.leftMargin)
                    * topLeftTaskPlusDividerPercent;
            taskMenuView.setX(taskMenuView.getX() + additionalOffset);
        } else {
            additionalOffset = (taskView.getHeight() - snapshotParams.topMargin)
                    * topLeftTaskPlusDividerPercent;
            taskMenuView.setY(taskMenuView.getY() + additionalOffset);
        }
    }

    @Override
    public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
            int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
Loading