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

Commit bb410951 authored by Winson's avatar Winson Committed by Winson Chung
Browse files

Updating layouts to use frame vs translation and clipping.

- This greatly simplifies the freeform layout as well, since we don’t 
  need to scale and clip the views to match the freeform task bounds.
- Also fixing the animation from the back of the stack

Change-Id: Iba998a788dbdc48d031da8a8c908ea1a9f8f795f
parent 6f775a8d
Loading
Loading
Loading
Loading
+0 −26
Original line number Diff line number Diff line
@@ -46,19 +46,6 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
                }
            };

    public static final Property<AnimateableViewBounds, Integer> CLIP_RIGHT =
            new IntProperty<AnimateableViewBounds>("clipRight") {
                @Override
                public void setValue(AnimateableViewBounds object, int clip) {
                    object.setClipRight(clip, false /* force */);
                }

                @Override
                public Integer get(AnimateableViewBounds object) {
                    return object.getClipRight();
                }
            };

    public AnimateableViewBounds(View source, int cornerRadius) {
        mSourceView = source;
        mCornerRadius = cornerRadius;
@@ -102,19 +89,6 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
        return mClipRect.bottom;
    }

    /** Sets the right clip. */
    public void setClipRight(int right, boolean force) {
        if (right != mClipRect.right || force) {
            mClipRect.right = right;
            updateClipBounds();
        }
    }

    /** Returns the right clip. */
    public int getClipRight() {
        return mClipRect.right;
    }

    private void updateClipBounds() {
        mClipBounds.set(mClipRect.left, mClipRect.top,
                mSourceView.getWidth() - mClipRect.right,
+24 −29
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.systemui.recents.views;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;

import java.util.Collections;
@@ -80,7 +79,6 @@ public class FreeformWorkspaceLayoutAlgorithm {
                float width = normalizedTaskWidths[i] * rowScale;
                if (rowWidth + width > normalizedWorkspaceWidth) {
                    // That is too long for this row, create new row
                    rowWidth = 0f;
                    if ((rowCount + 1) * rowScale > normalizedWorkspaceHeight) {
                        // The new row is too high, so we need to try fitting again.  Update the
                        // scale to be the smaller of the scale needed to fit the task in the
@@ -88,9 +86,11 @@ public class FreeformWorkspaceLayoutAlgorithm {
                        rowScale = Math.min(normalizedWorkspaceWidth / (rowWidth + width),
                                normalizedWorkspaceHeight / (rowCount + 1));
                        rowCount = 1;
                        rowWidth = 0;
                        i = 0;
                    } else {
                        // The new row fits, so continue
                        rowWidth = width;
                        rowCount++;
                        i++;
                    }
@@ -103,20 +103,20 @@ public class FreeformWorkspaceLayoutAlgorithm {
            }

            // Normalize each of the actual rects to that scale
            int height = (int) (rowScale * workspaceHeight);
            float rowTop = ((1f - (rowScale * rowCount)) * workspaceHeight) / 2f;
            float defaultRowLeft = ((1f - (maxRowWidth / normalizedWorkspaceWidth)) *
                    workspaceWidth) / 2f;
            float rowLeft = defaultRowLeft;
            float rowTop = ((1f - (rowScale * rowCount)) * workspaceHeight) / 2f;
            float rowHeight = rowScale * workspaceHeight;
            for (int i = 0; i < numFreeformTasks; i++) {
                Task task = freeformTasks.get(i);
                int width = (int) (height * normalizedTaskWidths[i]);
                float width = rowHeight * normalizedTaskWidths[i];
                if (rowLeft + width > workspaceWidth) {
                    // This goes on the next line
                    rowTop += height;
                    rowTop += rowHeight;
                    rowLeft = defaultRowLeft;
                }
                RectF rect = new RectF(rowLeft, rowTop, rowLeft + width, rowTop + height);
                RectF rect = new RectF(rowLeft, rowTop, rowLeft + width, rowTop + rowHeight);
                rowLeft += width;
                mTaskRectMap.put(task.key, rect);
            }
@@ -140,34 +140,29 @@ public class FreeformWorkspaceLayoutAlgorithm {
    public TaskViewTransform getTransform(Task task, TaskViewTransform transformOut,
            TaskStackLayoutAlgorithm stackLayout) {
        if (mTaskRectMap.containsKey(task.key)) {
            Rect taskRect = stackLayout.mTaskRect;
            RectF ffRect = mTaskRectMap.get(task.key);
            float scale = Math.max(ffRect.width() / taskRect.width(),
                    ffRect.height() / taskRect.height());
            int topOffset = (stackLayout.mFreeformRect.top - taskRect.top);
            int scaleXOffset = (int) (((1f - scale) * taskRect.width()) / 2);
            int scaleYOffset = (int) (((1f - scale) * taskRect.height()) / 2);
            final Rect taskRect = stackLayout.mTaskRect;
            final RectF ffRect = mTaskRectMap.get(task.key);

            transformOut.scale = scale * 0.95f;
            transformOut.translationX = (int) (ffRect.left - scaleXOffset);
            transformOut.translationY = (int) (topOffset + ffRect.top - scaleYOffset);
            transformOut.scale = 0.95f;
            transformOut.alpha = 1f;
            transformOut.translationZ = stackLayout.mMaxTranslationZ;
            transformOut.clipBottom = (int) (taskRect.height() - (ffRect.height() / scale));
            transformOut.clipRight = (int) (taskRect.width() - (ffRect.width() / scale));
            if (task.thumbnail != null) {
                if (task.bounds == null) {
                    // This is a stack task that has no freeform thumbnail, so keep the same bitmap
                    // scale as it had in the stack
                    transformOut.thumbnailScale = (float) taskRect.width() /
                            task.thumbnail.getWidth();
                } else {
                    // This is a freeform rect so fit the bitmap to the task bounds
                    transformOut.thumbnailScale = Math.min(
                        ((float) taskRect.width() - transformOut.clipRight) /
                                task.thumbnail.getWidth(),
                        ((float) taskRect.height() - transformOut.clipBottom) /
                                task.thumbnail.getHeight());
                            ffRect.width() / task.thumbnail.getWidth(),
                            ffRect.height() / task.thumbnail.getHeight());
                }
            } else {
                transformOut.thumbnailScale = 1f;
            }
            transformOut.rect.set(taskRect);
            transformOut.rect.offset(transformOut.translationX, transformOut.translationY);
            Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
            transformOut.rect.right -= transformOut.clipRight * scale;
            transformOut.rect.bottom -= transformOut.clipBottom * scale;
            transformOut.rect.set(ffRect);
            transformOut.rect.offset(stackLayout.mFreeformRect.left, stackLayout.mFreeformRect.top);
            transformOut.visible = true;
            transformOut.p = 1f;

+12 −5
Original line number Diff line number Diff line
@@ -506,6 +506,15 @@ public class TaskStackLayoutAlgorithm {
        return 0f;
    }

    /**
     * Returns the task progress that would put the task just off the back of the stack.
     */
    public float getStackBackTaskProgress(float stackScroll) {
        float min = mUnfocusedRange.relativeMin +
                mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin);
        return stackScroll + min;
    }

    /**
     * Returns the task progress that would put the task just off the front of the stack.
     */
@@ -647,6 +656,7 @@ public class TaskStackLayoutAlgorithm {
            return transformOut;
        }

        int x = (mStackRect.width() - mTaskRect.width()) / 2;
        int y;
        float z;
        float relP;
@@ -671,16 +681,13 @@ public class TaskStackLayoutAlgorithm {

        // Fill out the transform
        transformOut.scale = 1f;
        transformOut.translationX = (mStackRect.width() - mTaskRect.width()) / 2;
        transformOut.translationY = y;
        transformOut.alpha = 1f;
        transformOut.translationZ = z;
        transformOut.rect.set(mTaskRect);
        transformOut.rect.offset(transformOut.translationX, transformOut.translationY);
        transformOut.rect.offset(x, y);
        Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
        transformOut.visible = (transformOut.rect.top < mStackRect.bottom) &&
                (frontTransform == null || transformOut.rect.top != frontTransform.rect.top);
        transformOut.clipBottom = 0;
        transformOut.clipRight = 0;
        transformOut.thumbnailScale = 1f;
        transformOut.p = relP;
        return transformOut;
+29 −23
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -126,6 +127,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    Task mFocusedTask;
    // Optimizations
    int mStackViewsAnimationDuration;
    int mTaskCornerRadiusPx;
    boolean mStackViewsDirty = true;
    boolean mStackViewsClipDirty = true;
    boolean mAwaitingFirstLayout = true;
@@ -174,6 +176,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal

    public TaskStackView(Context context, TaskStack stack) {
        super(context);
        Resources res = context.getResources();

        // Set the stack first
        setStack(stack);
        mViewPool = new ViewPool<>(context, this);
@@ -184,6 +188,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                com.android.internal.R.interpolator.fast_out_slow_in);
        mTaskCornerRadiusPx = res.getDimensionPixelSize(
                R.dimen.recents_task_view_rounded_corners_radius);

        int taskBarDismissDozeDelaySeconds = getResources().getInteger(
                R.integer.recents_task_bar_dismiss_delay_seconds);
@@ -364,8 +370,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    private boolean updateStackTransforms(ArrayList<TaskViewTransform> taskTransforms,
                                       ArrayList<Task> tasks,
                                       float stackScroll,
                                       int[] visibleRangeOut,
                                       boolean boundTranslationsToRect) {
                                       int[] visibleRangeOut) {
        int taskTransformCount = taskTransforms.size();
        int taskCount = tasks.size();
        int frontMostVisibleIndex = -1;
@@ -411,11 +416,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                    break;
                }
            }

            if (boundTranslationsToRect) {
                transform.translationY = Math.min(transform.translationY,
                        mLayoutAlgorithm.mStackRect.bottom);
            }
            frontTransform = transform;
        }
        if (visibleRangeOut != null) {
@@ -433,7 +433,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
            float stackScroll = mStackScroller.getStackScroll();
            int[] visibleStackRange = mTmpVisibleRange;
            boolean isValidVisibleStackRange = updateStackTransforms(mCurrentTaskTransforms, tasks,
                    stackScroll, visibleStackRange, false);
                    stackScroll, visibleStackRange);
            boolean hasStackBackTransform = false;
            boolean hasStackFrontTransform = false;
            if (DEBUG) {
@@ -490,7 +490,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                }

                // Animate the task into place
                tv.updateViewPropertiesToTaskTransform(transform, transform.clipBottom,
                tv.updateViewPropertiesToTaskTransform(transform, 0,
                        mStackViewsAnimationDuration, mFastOutSlowInInterpolator,
                        mRequestUpdateClippingListener);

@@ -513,8 +513,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                        if (Float.compare(transform.p, 0f) <= 0) {
                            if (!hasStackBackTransform) {
                                hasStackBackTransform = true;
                                mLayoutAlgorithm.getStackTransform(0f, 0f, mTmpStackBackTransform,
                                        null);
                                mLayoutAlgorithm.getStackTransform(
                                        mLayoutAlgorithm.getStackBackTaskProgress(0f), 0f,
                                        mTmpStackBackTransform, null);
                            }
                            tv.updateViewPropertiesToTaskTransform(mTmpStackBackTransform, 0, 0,
                                    mFastOutSlowInInterpolator, mRequestUpdateClippingListener);
@@ -586,17 +587,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                // stacked and we can make assumptions about the visibility of the this
                // task relative to the ones in front of it.
                if (frontTv != null) {
                    mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
                    mTmpTaskRect.offset(0, tv.getTranslationY());
                    Utilities.scaleRectAboutCenter(mTmpTaskRect, tv.getScaleX());
                    float taskBottom = mTmpTaskRect.bottom;
                    mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
                    mTmpTaskRect.offset(0, frontTv.getTranslationY());
                    Utilities.scaleRectAboutCenter(mTmpTaskRect, frontTv.getScaleX());
                    float frontTaskTop = mTmpTaskRect.top;
                    float taskBottom = tv.getBottom();
                    float frontTaskTop = frontTv.getTop();
                    if (frontTaskTop < taskBottom) {
                        // Map the stack view space coordinate (the rects) to view space
                        clipBottom = (int) ((taskBottom - frontTaskTop) / tv.getScaleX()) - 1;
                        clipBottom = (int) (taskBottom - frontTaskTop) - mTaskCornerRadiusPx;
                    }
                }
            }
@@ -980,11 +975,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
            onFirstLayout();
        }

        requestSynchronizeStackViewsWithModel();
        if (changed) {
            if (mStackScroller.isScrollOutOfBounds()) {
                mStackScroller.boundScroll();
            }
            requestSynchronizeStackViewsWithModel();
            synchronizeStackViewsWithModel();
            requestUpdateStackViewsClip();
            clipTaskViews(true /* forceUpdate */);
@@ -1147,8 +1142,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        transformPointToViewLocal(point, tv);
        x = point[0];
        y = point[1];
        return (0 <= x) && (x < (tv.getMeasuredWidth() - tv.getViewBounds().getClipRight())) &&
                (0 <= y) && (y < (tv.getMeasuredHeight() - tv.getViewBounds().getClipBottom()));
        return (0 <= x) && (x < tv.getWidth()) && (0 <= y) && (y < tv.getHeight());
    }

    @Override
@@ -1498,6 +1492,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        event.taskView.animate()
                .withEndAction(event.postAnimationTrigger.decrementAsRunnable());

        // We translated the view but we need to animate it back from the current layout-space rect
        // to its final layout-space rect
        int x = (int) event.taskView.getTranslationX();
        int y = (int) event.taskView.getTranslationY();
        Rect taskViewRect = new Rect(event.taskView.getLeft(), event.taskView.getTop(),
                event.taskView.getRight(), event.taskView.getBottom());
        taskViewRect.offset(x, y);
        event.taskView.setTranslationX(0);
        event.taskView.setTranslationY(0);
        event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
                taskViewRect.right, taskViewRect.bottom);

        // Animate the tack view back into position
        requestSynchronizeStackViewsWithModel(250);
    }
+13 −6
Original line number Diff line number Diff line
@@ -232,8 +232,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
            mClipAnimation.playTogether(
                    ObjectAnimator.ofInt(mViewBounds, AnimateableViewBounds.CLIP_BOTTOM,
                            mViewBounds.getClipBottom(), clipBottom),
                    ObjectAnimator.ofInt(mViewBounds, AnimateableViewBounds.CLIP_RIGHT,
                            mViewBounds.getClipRight(), toTransform.clipRight),
                    ObjectAnimator.ofInt(this, TaskViewTransform.LEFT, getLeft(),
                            (int) toTransform.rect.left),
                    ObjectAnimator.ofInt(this, TaskViewTransform.TOP, getTop(),
                            (int) toTransform.rect.top),
                    ObjectAnimator.ofInt(this, TaskViewTransform.RIGHT, getRight(),
                            (int) toTransform.rect.right),
                    ObjectAnimator.ofInt(this, TaskViewTransform.BOTTOM, getBottom(),
                            (int) toTransform.rect.bottom),
                    ObjectAnimator.ofFloat(mThumbnailView, TaskViewThumbnail.BITMAP_SCALE,
                            mThumbnailView.getBitmapScale(), toTransform.thumbnailScale));
            mClipAnimation.setStartDelay(toTransform.startDelay);
@@ -242,8 +248,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
            mClipAnimation.start();
        } else {
            mViewBounds.setClipBottom(clipBottom, false /* forceUpdate */);
            mViewBounds.setClipRight(toTransform.clipRight, false /* forceUpdate */);
            mThumbnailView.setBitmapScale(toTransform.thumbnailScale);
            setLeftTopRightBottom((int) toTransform.rect.left, (int) toTransform.rect.top,
                    (int) toTransform.rect.right, (int) toTransform.rect.bottom);
        }
        if (!config.useHardwareLayers) {
            mThumbnailView.updateThumbnailVisibility(clipBottom - getPaddingBottom());
@@ -336,10 +343,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
            } else {
                // Animate the task up if it was occluding the launch target
                if (ctx.currentTaskOccludesLaunchTarget) {
                    setTranslationY(transform.translationY + taskViewAffiliateGroupEnterOffset);
                    setTranslationY(taskViewAffiliateGroupEnterOffset);
                    setAlpha(0f);
                    animate().alpha(1f)
                            .translationY(transform.translationY)
                            .translationY(0)
                            .setUpdateListener(null)
                            .setListener(new AnimatorListenerAdapter() {
                                private boolean hasEnded;
@@ -372,7 +379,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
                animate().translationZ(transform.translationZ);
            }
            animate()
                    .translationY(transform.translationY)
                    .translationY(0)
                    .setStartDelay(delay)
                    .setUpdateListener(ctx.updateListener)
                    .setListener(new AnimatorListenerAdapter() {
Loading