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

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

Merge "WM: Fix seamless rotation"

parents c5af8b08 0e7b70a3
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -1107,10 +1107,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        }

        if (rotateSeamlessly) {
            forAllWindows(w -> {
                    w.mWinAnimator.seamlesslyRotateWindow(getPendingTransaction(),
                            oldRotation, rotation);
            }, true /* traverseTopToBottom */);
            seamlesslyRotate(getPendingTransaction(), oldRotation, rotation);
        }

        mService.mDisplayManagerInternal.performTraversal(getPendingTransaction());
+14 −0
Original line number Diff line number Diff line
@@ -735,6 +735,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        return candidate;
    }

    /**
     * Seamlessly rotates the container, by recomputing the location in the new
     * rotation, and rotating buffers until they are updated for the new rotation.
     *
     * @param t the transaction to perform the seamless rotation in
     * @param oldRotation the rotation we are rotating from
     * @param newRotation the rotation we are rotating to
     */
    void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) {
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            mChildren.get(i).seamlesslyRotate(t, oldRotation, newRotation);
        }
    }

    /**
     * Returns true if this container is opaque and fills all the space made available by its parent
     * container.
+27 −1
Original line number Diff line number Diff line
@@ -152,6 +152,8 @@ import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
import static com.android.server.wm.WindowStateProto.VISIBLE_FRAME;
import static com.android.server.wm.WindowStateProto.VISIBLE_INSETS;
import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
import static com.android.server.wm.utils.CoordinateTransforms.transformRect;
import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation;

import android.annotation.CallSuper;
import android.app.AppOpsManager;
@@ -1813,7 +1815,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
                && !isDragResizing() && !adjustedForMinimizedDockOrIme
                && getWindowConfiguration().hasMovementAnimations()
                && !mWinAnimator.mLastHidden) {
                && !mWinAnimator.mLastHidden
                && !mSeamlesslyRotated) {
            startMoveAnimation(left, top);
        }

@@ -4860,6 +4863,29 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        mFrameNumber = frameNumber;
    }

    @Override
    void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) {
        if (!isVisibleNow() || mIsWallpaper) {
            return;
        }
        final Matrix transform = mTmpMatrix;

        mService.markForSeamlessRotation(this, true);

        // We rotated the screen, but have not performed a new layout pass yet. In the mean time,
        // we recompute the coordinates of mFrame in the new orientation, so the surface can be
        // properly placed.
        transformToRotation(oldRotation, newRotation, getDisplayInfo(), transform);
        transformRect(transform, mFrame, null /* tmpRectF */);

        updateSurfacePosition(t);
        mWinAnimator.seamlesslyRotate(t, oldRotation, newRotation);

        // Dispatch to children only after mFrame has been updated, as it's needed in the
        // child's updateSurfacePosition.
        super.seamlesslyRotate(t, oldRotation, newRotation);
    }

    private final class MoveAnimationSpec implements AnimationSpec {

        private final long mDuration;
+5 −31
Original line number Diff line number Diff line
@@ -46,13 +46,13 @@ import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE;
import static com.android.server.wm.WindowStateAnimatorProto.LAST_CLIP_RECT;
import static com.android.server.wm.WindowStateAnimatorProto.SURFACE;
import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Debug;
import android.os.Trace;
@@ -1497,40 +1497,14 @@ class WindowStateAnimator {
        }
    }

    void seamlesslyRotateWindow(SurfaceControl.Transaction t,
            int oldRotation, int newRotation) {
    void seamlesslyRotate(SurfaceControl.Transaction t, int oldRotation, int newRotation) {
        final WindowState w = mWin;
        if (!w.isVisibleNow() || w.mIsWallpaper) {
            return;
        }

        final Rect cropRect = mService.mTmpRect;
        final Rect displayRect = mService.mTmpRect2;
        final RectF frameRect = mService.mTmpRectF;
        // We rotated the screen, but have not received a new buffer with the correct size yet. In
        // the mean time, we rotate the buffer we have to the new orientation.
        final Matrix transform = mService.mTmpTransform;

        final float x = w.mFrame.left;
        final float y = w.mFrame.top;
        final float width = w.mFrame.width();
        final float height = w.mFrame.height();

        mService.getDefaultDisplayContentLocked().getBounds(displayRect);
        final float displayWidth = displayRect.width();
        final float displayHeight = displayRect.height();

        // Compute a transform matrix to undo the coordinate space transformation,
        // and present the window at the same physical position it previously occupied.
        final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation);
        DisplayContent.createRotationMatrix(deltaRotation, x, y, displayWidth, displayHeight,
        transformToRotation(oldRotation, newRotation, w.mFrame.width(), w.mFrame.height(),
                transform);

        // We just need to apply a rotation matrix to the window. For example
        // if we have a portrait window and rotate to landscape, the window is still portrait
        // and now extends off the bottom of the screen (and only halfway across). Essentially we
        // apply a transform to display the current buffer at it's old position
        // (in the new coordinate space). We then freeze layer updates until the resize
        // occurs, at which point we undo, them.
        mService.markForSeamlessRotation(w, true);
        transform.getValues(mService.mTmpFloats);

        float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];
+93 −0
Original line number Diff line number Diff line
@@ -22,7 +22,11 @@ import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;

import android.annotation.Dimension;
import android.annotation.Nullable;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.DisplayInfo;
import android.view.Surface.Rotation;

public class CoordinateTransforms {
@@ -59,4 +63,93 @@ public class CoordinateTransforms {
                throw new IllegalArgumentException("Unknown rotation: " + rotation);
        }
    }

    /**
     * Sets a matrix such that given a rotation, it transforms that rotation's logical coordinates
     * to physical coordinates.
     *
     * @param rotation the rotation to which the matrix should transform
     * @param out      the matrix to be set
     */
    public static void transformLogicalToPhysicalCoordinates(@Rotation int rotation,
            @Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) {
        switch (rotation) {
            case ROTATION_0:
                out.reset();
                break;
            case ROTATION_90:
                out.setRotate(90);
                out.preTranslate(0, -physicalWidth);
                break;
            case ROTATION_180:
                out.setRotate(180);
                out.preTranslate(-physicalWidth, -physicalHeight);
                break;
            case ROTATION_270:
                out.setRotate(270);
                out.preTranslate(-physicalHeight, 0);
                break;
            default:
                throw new IllegalArgumentException("Unknown rotation: " + rotation);
        }
    }

    /**
     * Sets a matrix such that given a two rotations, that it transforms coordinates given in the
     * old rotation to coordinates that refer to the same physical location in the new rotation.
     *
     * @param oldRotation the rotation to transform from
     * @param newRotation the rotation to transform to
     * @param info the display info
     * @param out a matrix that will be set to the transform
     */
    public static void transformToRotation(@Rotation int oldRotation,
            @Rotation int newRotation, DisplayInfo info, Matrix out) {
        final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270;
        final int h = flipped ? info.logicalWidth : info.logicalHeight;
        final int w = flipped ? info.logicalHeight : info.logicalWidth;

        final Matrix tmp = new Matrix();
        transformLogicalToPhysicalCoordinates(oldRotation, w, h, out);
        transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp);
        out.postConcat(tmp);
    }

    /**
     * Sets a matrix such that given a two rotations, that it transforms coordinates given in the
     * old rotation to coordinates that refer to the same physical location in the new rotation.
     *
     * @param oldRotation the rotation to transform from
     * @param newRotation the rotation to transform to
     * @param newWidth the width of the area to transform, in the new rotation
     * @param newHeight the height of the area to transform, in the new rotation
     * @param out a matrix that will be set to the transform
     */
    public static void transformToRotation(@Rotation int oldRotation,
            @Rotation int newRotation, int newWidth, int newHeight, Matrix out) {
        final boolean flipped = newRotation == ROTATION_90 || newRotation == ROTATION_270;
        final int h = flipped ? newWidth : newHeight;
        final int w = flipped ? newHeight : newWidth;

        final Matrix tmp = new Matrix();
        transformLogicalToPhysicalCoordinates(oldRotation, w, h, out);
        transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp);
        out.postConcat(tmp);
    }

    /**
     * Transforms a rect using a transformation matrix
     *
     * @param transform the transformation to apply to the rect
     * @param inOutRect the rect to transform
     * @param tmp a temporary value, if null the function will allocate its own.
     */
    public static void transformRect(Matrix transform, Rect inOutRect, @Nullable RectF tmp) {
        if (tmp == null) {
            tmp = new RectF();
        }
        tmp.set(inOutRect);
        transform.mapRect(tmp);
        inOutRect.set((int) tmp.left, (int) tmp.top, (int) tmp.right, (int) tmp.bottom);
    }
}
Loading