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

Commit 0ef7951d authored by Evan Rosky's avatar Evan Rosky Committed by Android (Google) Code Review
Browse files

Merge "Hook up fixed-rotation logic to shell transitions"

parents 1bf2e3cb 91a630b9
Loading
Loading
Loading
Loading
+54 −1
Original line number Diff line number Diff line
@@ -24,8 +24,10 @@ import static android.view.Surface.ROTATION_90;
import android.annotation.Dimension;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.Surface.Rotation;
import android.view.SurfaceControl;

/**
 * A class containing utility methods related to rotation.
@@ -121,12 +123,63 @@ public class RotationUtils {

    /** @return the rotation needed to rotate from oldRotation to newRotation. */
    @Rotation
    public static int deltaRotation(int oldRotation, int newRotation) {
    public static int deltaRotation(@Rotation int oldRotation, @Rotation int newRotation) {
        int delta = newRotation - oldRotation;
        if (delta < 0) delta += 4;
        return delta;
    }

    /**
     * Rotates a surface CCW around the origin (eg. a 90-degree rotation will result in the
     * bottom-left being at the origin). Use {@link #rotatePoint} to transform the top-left
     * corner appropriately.
     */
    public static void rotateSurface(SurfaceControl.Transaction t, SurfaceControl sc,
            @Rotation int rotation) {
        // Note: the matrix values look inverted, but they aren't because our coordinate-space
        // is actually left-handed.
        // Note: setMatrix expects values in column-major order.
        switch (rotation) {
            case ROTATION_0:
                t.setMatrix(sc, 1.f, 0.f, 0.f, 1.f);
                break;
            case ROTATION_90:
                t.setMatrix(sc, 0.f, -1.f, 1.f, 0.f);
                break;
            case ROTATION_180:
                t.setMatrix(sc, -1.f, 0.f, 0.f, -1.f);
                break;
            case ROTATION_270:
                t.setMatrix(sc, 0.f, 1.f, -1.f, 0.f);
                break;
        }
    }

    /**
     * Rotates a point CCW within a rectangle of size parentW x parentH with top/left at the
     * origin as if the point is stuck to the rectangle. The rectangle is transformed such that
     * it's top/left remains at the origin after the rotation.
     */
    public static void rotatePoint(Point inOutPoint, @Rotation int rotation,
            int parentW, int parentH) {
        int origX = inOutPoint.x;
        switch (rotation) {
            case ROTATION_0:
                return;
            case ROTATION_90:
                inOutPoint.x = inOutPoint.y;
                inOutPoint.y = parentW - origX;
                return;
            case ROTATION_180:
                inOutPoint.x = parentW - inOutPoint.x;
                inOutPoint.y = parentH - inOutPoint.y;
                return;
            case ROTATION_270:
                inOutPoint.x = parentH - inOutPoint.y;
                inOutPoint.y = origX;
        }
    }

    /**
     * Sets a matrix such that given a rotation, it transforms physical display
     * coordinates to that rotation's logical coordinates.
+21 −0
Original line number Diff line number Diff line
@@ -17,12 +17,14 @@
package android.util;

import static android.util.RotationUtils.rotateBounds;
import static android.util.RotationUtils.rotatePoint;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;

import static org.junit.Assert.assertEquals;

import android.graphics.Point;
import android.graphics.Rect;

import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -58,4 +60,23 @@ public class RotationUtilsTest {
        rotateBounds(testResult, testParent, ROTATION_270);
        assertEquals(new Rect(520, 40, 580, 120), testResult);
    }

    @Test
    public void testRotatePoint() {
        int parentW = 1000;
        int parentH = 600;
        Point testPt = new Point(60, 40);

        Point testResult = new Point(testPt);
        rotatePoint(testResult, ROTATION_90, parentW, parentH);
        assertEquals(new Point(40, 940), testResult);

        testResult.set(testPt.x, testPt.y);
        rotatePoint(testResult, ROTATION_180, parentW, parentH);
        assertEquals(new Point(940, 560), testResult);

        testResult.set(testPt.x, testPt.y);
        rotatePoint(testResult, ROTATION_270, parentW, parentH);
        assertEquals(new Point(560, 60), testResult);
    }
}
+5 −3
Original line number Diff line number Diff line
@@ -201,6 +201,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                "Display is changing, check if it should be seamless.");
        boolean checkedDisplayLayout = false;
        boolean hasTask = false;
        boolean displayExplicitSeamless = false;
        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);

@@ -209,7 +210,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {

            // This container isn't rotating, so we can ignore it.
            if (change.getEndRotation() == change.getStartRotation()) continue;

            if ((change.getFlags() & FLAG_IS_DISPLAY) != 0) {
                // In the presence of System Alert windows we can not seamlessly rotate.
                if ((change.getFlags() & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
@@ -217,6 +217,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                            "  display has system alert windows, so not seamless.");
                    return false;
                }
                displayExplicitSeamless =
                        change.getRotationAnimation() == ROTATION_ANIMATION_SEAMLESS;
            } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
                if (change.getRotationAnimation() != ROTATION_ANIMATION_SEAMLESS) {
                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
@@ -268,8 +270,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
            }
        }

        // ROTATION_ANIMATION_SEAMLESS can only be requested by task.
        if (hasTask) {
        // ROTATION_ANIMATION_SEAMLESS can only be requested by task or display.
        if (hasTask || displayExplicitSeamless) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  Rotation IS seamless.");
            return true;
        }
+20 −15
Original line number Diff line number Diff line
@@ -16,10 +16,14 @@

package com.android.wm.shell.util;

import android.graphics.Point;
import android.util.RotationUtils;
import android.view.SurfaceControl;

/**
 * Utility class that takes care of counter-rotating surfaces during a transition animation.
 * Utility class that takes care of rotating unchanging child-surfaces to match the parent rotation
 * during a transition animation. This gives the illusion that the child surfaces haven't rotated
 * relative to the screen.
 */
public class CounterRotator {
    private SurfaceControl mSurface = null;
@@ -33,29 +37,30 @@ public class CounterRotator {
     * Sets up this rotator.
     *
     * @param rotateDelta is the forward rotation change (the rotation the display is making).
     * @param displayW (and H) Is the size of the rotating display.
     * @param parentW (and H) Is the size of the rotating parent after the rotation.
     */
    public void setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta,
            float displayW, float displayH) {
            float parentW, float parentH) {
        if (rotateDelta == 0) return;
        // We want to counter-rotate, so subtract from 4
        rotateDelta = 4 - (rotateDelta + 4) % 4;
        mSurface = new SurfaceControl.Builder()
                .setName("Transition Unrotate")
                .setContainerLayer()
                .setParent(parent)
                .build();
        // column-major
        if (rotateDelta == 1) {
            t.setMatrix(mSurface, 0, 1, -1, 0);
            t.setPosition(mSurface, displayW, 0);
        } else if (rotateDelta == 2) {
            t.setMatrix(mSurface, -1, 0, 0, -1);
            t.setPosition(mSurface, displayW, displayH);
        } else if (rotateDelta == 3) {
            t.setMatrix(mSurface, 0, -1, 1, 0);
            t.setPosition(mSurface, 0, displayH);
        // Rotate forward to match the new rotation (rotateDelta is the forward rotation the parent
        // already took). Child surfaces will be in the old rotation relative to the new parent
        // rotation, so we need to forward-rotate the child surfaces to match.
        RotationUtils.rotateSurface(t, mSurface, rotateDelta);
        final Point tmpPt = new Point(0, 0);
        // parentW/H are the size in the END rotation, the rotation utilities expect the starting
        // size. So swap them if necessary
        if ((rotateDelta % 2) != 0) {
            final float w = parentW;
            parentW = parentH;
            parentH = w;
        }
        RotationUtils.rotatePoint(tmpPt, rotateDelta, (int) parentW, (int) parentH);
        t.setPosition(mSurface, tmpPt.x, tmpPt.y);
        t.show(mSurface);
    }

+7 −0
Original line number Diff line number Diff line
@@ -591,6 +591,13 @@ public class ShellTransitionTests {
                        .setRotate().build())
                .build();
        assertFalse(DefaultTransitionHandler.isRotationSeamless(noTask, displays));

        // Seamless if display is explicitly seamless.
        final TransitionInfo seamlessDisplay = new TransitionInfoBuilder(TRANSIT_CHANGE)
                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
                        .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
                .build();
        assertTrue(DefaultTransitionHandler.isRotationSeamless(seamlessDisplay, displays));
    }

    class TransitionInfoBuilder {
Loading