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

Commit 40497595 authored by Nick Chameyev's avatar Nick Chameyev Committed by Automerger Merge Worker
Browse files

Merge "Extract PreviewPositionHelper to shared library" into tm-qpr-dev am: 3e7c6113

parents ad6d2fca 3e7c6113
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -46,9 +46,9 @@ import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.BaseActivityInterface;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
import com.android.quickstep.views.TaskView.FullscreenDrawParams;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;

@@ -317,9 +317,9 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
            // mIsRecentsRtl is the inverse of TaskView RTL.
            boolean isRtlEnabled = !mIsRecentsRtl;
            mPositionHelper.updateThumbnailMatrix(
                    mThumbnailPosition, mThumbnailData,
                    mTaskRect.width(), mTaskRect.height(),
                    mDp, mOrientationState.getRecentsActivityRotation(), isRtlEnabled);
                    mThumbnailPosition, mThumbnailData, mTaskRect.width(), mTaskRect.height(),
                    mDp.widthPx, mDp.taskbarSize, mDp.isTablet,
                    mOrientationState.getRecentsActivityRotation(), isRtlEnabled);
            mPositionHelper.getMatrix().invert(mInversePositionMatrix);
            if (DEBUG) {
                Log.d(TAG, " taskRect: " + mTaskRect);
+12 −205
Original line number Diff line number Diff line
@@ -16,10 +16,12 @@

package com.android.quickstep.views;

import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;

import static com.android.systemui.shared.recents.utilities.PreviewPositionHelper.MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT;
import static com.android.systemui.shared.recents.utilities.Utilities.isRelativePercentDifferenceGreaterThan;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
@@ -39,7 +41,6 @@ import android.os.Build;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Property;
import android.view.Surface;
import android.view.View;
import android.widget.ImageView;

@@ -58,6 +59,7 @@ import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.quickstep.views.TaskView.FullscreenDrawParams;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;

/**
 * A task in the Recents view.
@@ -65,7 +67,6 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
public class TaskThumbnailView extends View {
    private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
            new MainThreadInitializedObject<>(FullscreenDrawParams::new);
    private static final float MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT = 0.1f;

    public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
            new FloatProperty<TaskThumbnailView>("dimAlpha") {
@@ -417,7 +418,7 @@ public class TaskThumbnailView extends View {
        float thumbnailDataAspect =
                mThumbnailData.thumbnail.getWidth() / (float) mThumbnailData.thumbnail.getHeight();

        return Utilities.isRelativePercentDifferenceGreaterThan(thumbnailViewAspect,
        return isRelativePercentDifferenceGreaterThan(thumbnailViewAspect,
                thumbnailDataAspect, MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT);
    }

@@ -441,8 +442,8 @@ public class TaskThumbnailView extends View {
     */
    private void refreshOverlay() {
        if (mOverlayEnabled) {
            getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
                    mPreviewPositionHelper.mIsOrientationChanged);
            getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.getMatrix(),
                    mPreviewPositionHelper.isOrientationChanged());
        } else {
            getTaskOverlay().reset();
        }
@@ -463,18 +464,19 @@ public class TaskThumbnailView extends View {
    }

    private void updateThumbnailMatrix() {
        mPreviewPositionHelper.mIsOrientationChanged = false;
        mPreviewPositionHelper.setOrientationChanged(false);
        if (mBitmapShader != null && mThumbnailData != null) {
            mPreviewRect.set(0, 0, mThumbnailData.thumbnail.getWidth(),
                    mThumbnailData.thumbnail.getHeight());
            int currentRotation = getTaskView().getRecentsView().getPagedViewOrientedState()
                    .getRecentsActivityRotation();
            boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
            DeviceProfile dp = mActivity.getDeviceProfile();
            mPreviewPositionHelper.updateThumbnailMatrix(mPreviewRect, mThumbnailData,
                    getMeasuredWidth(), getMeasuredHeight(), mActivity.getDeviceProfile(),
                    currentRotation, isRtl);
                    getMeasuredWidth(), getMeasuredHeight(), dp.widthPx, dp.taskbarSize,
                    dp.isTablet, currentRotation, isRtl);

            mBitmapShader.setLocalMatrix(mPreviewPositionHelper.mMatrix);
            mBitmapShader.setLocalMatrix(mPreviewPositionHelper.getMatrix());
            mPaint.setShader(mBitmapShader);
        }
        getTaskView().updateCurrentFullscreenParams(mPreviewPositionHelper);
@@ -514,199 +516,4 @@ public class TaskThumbnailView extends View {
        }
        return mThumbnailData.isRealSnapshot && !mTask.isLocked;
    }

    /**
     * Utility class to position the thumbnail in the TaskView
     */
    public static class PreviewPositionHelper {

        private static final RectF EMPTY_RECT_F = new RectF();

        // Contains the portion of the thumbnail that is unclipped when fullscreen progress = 1.
        private final RectF mClippedInsets = new RectF();
        private final Matrix mMatrix = new Matrix();
        private boolean mIsOrientationChanged;

        public Matrix getMatrix() {
            return mMatrix;
        }

        /**
         * Updates the matrix based on the provided parameters
         */
        public void updateThumbnailMatrix(Rect thumbnailBounds, ThumbnailData thumbnailData,
                int canvasWidth, int canvasHeight, DeviceProfile dp, int currentRotation,
                boolean isRtl) {
            boolean isRotated = false;
            boolean isOrientationDifferent;

            int thumbnailRotation = thumbnailData.rotation;
            int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
            RectF thumbnailClipHint = new RectF();
            float canvasScreenRatio = canvasWidth / (float) dp.widthPx;
            float scaledTaskbarSize = dp.taskbarSize * canvasScreenRatio;
            thumbnailClipHint.bottom = dp.isTablet ? scaledTaskbarSize : 0;

            float scale = thumbnailData.scale;
            final float thumbnailScale;

            // Landscape vs portrait change.
            // Note: Disable rotation in grid layout.
            boolean windowingModeSupportsRotation =
                    thumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN && !dp.isTablet;
            isOrientationDifferent = isOrientationChange(deltaRotate)
                    && windowingModeSupportsRotation;
            if (canvasWidth == 0 || canvasHeight == 0 || scale == 0) {
                // If we haven't measured , skip the thumbnail drawing and only draw the background
                // color
                thumbnailScale = 0f;
            } else {
                // Rotate the screenshot if not in multi-window mode
                isRotated = deltaRotate > 0 && windowingModeSupportsRotation;

                float surfaceWidth = thumbnailBounds.width() / scale;
                float surfaceHeight = thumbnailBounds.height() / scale;
                float availableWidth = surfaceWidth
                        - (thumbnailClipHint.left + thumbnailClipHint.right);
                float availableHeight = surfaceHeight
                        - (thumbnailClipHint.top + thumbnailClipHint.bottom);

                float canvasAspect = canvasWidth / (float) canvasHeight;
                float availableAspect = isRotated
                        ? availableHeight / availableWidth
                        : availableWidth / availableHeight;
                boolean isAspectLargelyDifferent =
                        Utilities.isRelativePercentDifferenceGreaterThan(canvasAspect,
                                availableAspect, MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT);
                if (isRotated && isAspectLargelyDifferent) {
                    // Do not rotate thumbnail if it would not improve fit
                    isRotated = false;
                    isOrientationDifferent = false;
                }

                if (isAspectLargelyDifferent) {
                    // Crop letterbox insets if insets isn't already clipped
                    thumbnailClipHint.left = thumbnailData.letterboxInsets.left;
                    thumbnailClipHint.right = thumbnailData.letterboxInsets.right;
                    thumbnailClipHint.top = thumbnailData.letterboxInsets.top;
                    thumbnailClipHint.bottom = thumbnailData.letterboxInsets.bottom;
                    availableWidth = surfaceWidth
                            - (thumbnailClipHint.left + thumbnailClipHint.right);
                    availableHeight = surfaceHeight
                            - (thumbnailClipHint.top + thumbnailClipHint.bottom);
                }

                final float targetW, targetH;
                if (isOrientationDifferent) {
                    targetW = canvasHeight;
                    targetH = canvasWidth;
                } else {
                    targetW = canvasWidth;
                    targetH = canvasHeight;
                }
                float targetAspect = targetW / targetH;

                // Update the clipHint such that
                //   > the final clipped position has same aspect ratio as requested by canvas
                //   > first fit the width and crop the extra height
                //   > if that will leave empty space, fit the height and crop the width instead
                float croppedWidth = availableWidth;
                float croppedHeight = croppedWidth / targetAspect;
                if (croppedHeight > availableHeight) {
                    croppedHeight = availableHeight;
                    if (croppedHeight < targetH) {
                        croppedHeight = Math.min(targetH, surfaceHeight);
                    }
                    croppedWidth = croppedHeight * targetAspect;

                    // One last check in case the task aspect radio messed up something
                    if (croppedWidth > surfaceWidth) {
                        croppedWidth = surfaceWidth;
                        croppedHeight = croppedWidth / targetAspect;
                    }
                }

                // Update the clip hints. Align to 0,0, crop the remaining.
                if (isRtl) {
                    thumbnailClipHint.left += availableWidth - croppedWidth;
                    if (thumbnailClipHint.right < 0) {
                        thumbnailClipHint.left += thumbnailClipHint.right;
                        thumbnailClipHint.right = 0;
                    }
                } else {
                    thumbnailClipHint.right += availableWidth - croppedWidth;
                    if (thumbnailClipHint.left < 0) {
                        thumbnailClipHint.right += thumbnailClipHint.left;
                        thumbnailClipHint.left = 0;
                    }
                }
                thumbnailClipHint.bottom += availableHeight - croppedHeight;
                if (thumbnailClipHint.top < 0) {
                    thumbnailClipHint.bottom += thumbnailClipHint.top;
                    thumbnailClipHint.top = 0;
                } else if (thumbnailClipHint.bottom < 0) {
                    thumbnailClipHint.top += thumbnailClipHint.bottom;
                    thumbnailClipHint.bottom = 0;
                }

                thumbnailScale = targetW / (croppedWidth * scale);
            }

            if (!isRotated) {
                mMatrix.setTranslate(
                        -thumbnailClipHint.left * scale,
                        -thumbnailClipHint.top * scale);
            } else {
                setThumbnailRotation(deltaRotate, thumbnailBounds);
            }

            mClippedInsets.set(0, 0, 0, scaledTaskbarSize);

            mMatrix.postScale(thumbnailScale, thumbnailScale);
            mIsOrientationChanged = isOrientationDifferent;
        }

        private int getRotationDelta(int oldRotation, int newRotation) {
            int delta = newRotation - oldRotation;
            if (delta < 0) delta += 4;
            return delta;
        }

        /**
         * @param deltaRotation the number of 90 degree turns from the current orientation
         * @return {@code true} if the change in rotation results in a shift from landscape to
         * portrait or vice versa, {@code false} otherwise
         */
        private boolean isOrientationChange(int deltaRotation) {
            return deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270;
        }

        private void setThumbnailRotation(int deltaRotate, Rect thumbnailPosition) {
            float translateX = 0;
            float translateY = 0;

            mMatrix.setRotate(90 * deltaRotate);
            switch (deltaRotate) { /* Counter-clockwise */
                case Surface.ROTATION_90:
                    translateX = thumbnailPosition.height();
                    break;
                case Surface.ROTATION_270:
                    translateY = thumbnailPosition.width();
                    break;
                case Surface.ROTATION_180:
                    translateX = thumbnailPosition.width();
                    translateY = thumbnailPosition.height();
                    break;
            }
            mMatrix.postTranslate(translateX, translateY);
        }

        /**
         * Insets to used for clipping the thumbnail (in case it is drawing outside its own space)
         */
        public RectF getInsetsToDrawInFullscreen(DeviceProfile dp) {
            return dp.isTaskbarPresent && !dp.isTaskbarPresentInApps
                    ? mClippedInsets : EMPTY_RECT_F;
        }
    }
}
+12 −2
Original line number Diff line number Diff line
@@ -98,9 +98,9 @@ import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.TaskCornerRadius;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -121,6 +121,8 @@ public class TaskView extends FrameLayout implements Reusable {
    private static final String TAG = TaskView.class.getSimpleName();
    private static final boolean DEBUG = false;

    private static final RectF EMPTY_RECT_F = new RectF();

    public static final int FLAG_UPDATE_ICON = 1;
    public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;

@@ -1572,7 +1574,7 @@ public class TaskView extends FrameLayout implements Reusable {
         */
        public void setProgress(float fullscreenProgress, float parentScale, float taskViewScale,
                int previewWidth, DeviceProfile dp, PreviewPositionHelper pph) {
            RectF insets = pph.getInsetsToDrawInFullscreen(dp);
            RectF insets = getInsetsToDrawInFullscreen(pph, dp);

            float currentInsetsLeft = insets.left * fullscreenProgress;
            float currentInsetsTop = insets.top * fullscreenProgress;
@@ -1591,6 +1593,14 @@ public class TaskView extends FrameLayout implements Reusable {
                mScale = previewWidth / (previewWidth + currentInsetsLeft + currentInsetsRight);
            }
        }

        /**
         * Insets to used for clipping the thumbnail (in case it is drawing outside its own space)
         */
        private static RectF getInsetsToDrawInFullscreen(PreviewPositionHelper pph, DeviceProfile dp) {
            return dp.isTaskbarPresent && !dp.isTaskbarPresentInApps
                    ? pph.getClippedInsets() : EMPTY_RECT_F;
        }
    }

    public class TaskIdAttributeContainer {
+23 −9
Original line number Diff line number Diff line
@@ -20,26 +20,34 @@ import android.graphics.RectF
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.DeviceProfileBaseTest
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper
import com.android.quickstep.views.TaskView.FullscreenDrawParams
import com.android.systemui.shared.recents.model.ThumbnailData
import com.android.systemui.shared.recents.utilities.PreviewPositionHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock

/**
 * Test for TaskThumbnailView class.
 * Test for FullscreenDrawParams class.
 */
@SmallTest
@RunWith(AndroidJUnit4::class)
class TaskThumbnailViewTest : DeviceProfileBaseTest() {
class FullscreenDrawParamsTest : DeviceProfileBaseTest() {

    private var mThumbnailData: ThumbnailData = mock(ThumbnailData::class.java)

    private val mPreviewPositionHelper = PreviewPositionHelper()
    private lateinit var params: FullscreenDrawParams

    @Before
    fun setup() {
        params = FullscreenDrawParams(context)
    }

    @Test
    fun getInsetsToDrawInFullscreen_clipTaskbarSizeFromBottomForTablets() {
    fun setFullProgress_currentDrawnInsets_clipTaskbarSizeFromBottomForTablets() {
        initializeVarsForTablet()
        val dp = newDP()
        val previewRect = Rect(0, 0, 100, 100)
@@ -49,15 +57,18 @@ class TaskThumbnailViewTest : DeviceProfileBaseTest() {
        val isRtl = false

        mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
                canvasHeight, dp, currentRotation, isRtl)
                canvasHeight, dp.widthPx, dp.taskbarSize, dp.isTablet, currentRotation,
                isRtl)
        params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
                /* taskViewScale= */ 1.0f,  /* previewWidth= */ 0, dp, mPreviewPositionHelper)

        val expectedClippedInsets = RectF(0f, 0f, 0f, dp.taskbarSize / 2f)
        assertThat(mPreviewPositionHelper.getInsetsToDrawInFullscreen(dp))
        assertThat(params.mCurrentDrawnInsets)
                .isEqualTo(expectedClippedInsets)
    }

    @Test
    fun getInsetsToDrawInFullscreen_doNotClipTaskbarSizeFromBottomForPhones() {
    fun setFullProgress_currentDrawnInsets_doNotClipTaskbarSizeFromBottomForPhones() {
        initializeVarsForPhone()
        val dp = newDP()
        val previewRect = Rect(0, 0, 100, 100)
@@ -67,10 +78,13 @@ class TaskThumbnailViewTest : DeviceProfileBaseTest() {
        val isRtl = false

        mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
                canvasHeight, dp, currentRotation, isRtl)
                canvasHeight, dp.widthPx, dp.taskbarSize, dp.isTablet, currentRotation,
                isRtl)
        params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
                /* taskViewScale= */ 1.0f,  /* previewWidth= */ 0, dp, mPreviewPositionHelper)

        val expectedClippedInsets = RectF(0f, 0f, 0f, 0f)
        assertThat(mPreviewPositionHelper.getInsetsToDrawInFullscreen(dp))
        assertThat(params.mCurrentDrawnInsets)
                .isEqualTo(expectedClippedInsets)
    }
}
 No newline at end of file
+0 −10
Original line number Diff line number Diff line
@@ -818,16 +818,6 @@ public final class Utilities {
        };
    }

    /**
     * Compares the ratio of two quantities and returns whether that ratio is greater than the
     * provided bound. Order of quantities does not matter. Bound should be a decimal representation
     * of a percentage.
     */
    public static boolean isRelativePercentDifferenceGreaterThan(float first, float second,
            float bound) {
        return (Math.abs(first - second) / Math.abs((first + second) / 2.0f)) > bound;
    }

    /**
     * Rotates `inOutBounds` by `delta` 90-degree increments. Rotation is visually CCW. Parent
     * sizes represent the "space" that will rotate carrying inOutBounds along with it to determine