Loading core/java/android/util/RotationUtils.java +55 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.view.Surface.ROTATION_90; import android.annotation.Dimension; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; import android.view.Surface.Rotation; /** Loading Loading @@ -72,6 +73,60 @@ public class RotationUtils { return rotated; } /** * Rotates bounds as if parentBounds and bounds are a group. The group is rotated from * oldRotation to newRotation. This assumes that parentBounds is at 0,0 and remains at 0,0 after * rotation. The bounds will be at the same physical position in parentBounds. * * Only 'inOutBounds' is mutated. */ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, @Rotation int oldRotation, @Rotation int newRotation) { rotateBounds(inOutBounds, parentBounds, deltaRotation(oldRotation, newRotation)); } /** * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta` * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and * remains at 0,0 after rotation. The bounds will be at the same physical position in * parentBounds. * * Only 'inOutBounds' is mutated. */ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, @Rotation int rotation) { final int origLeft = inOutBounds.left; final int origTop = inOutBounds.top; switch (rotation) { case ROTATION_0: return; case ROTATION_90: inOutBounds.left = inOutBounds.top; inOutBounds.top = parentBounds.right - inOutBounds.right; inOutBounds.right = inOutBounds.bottom; inOutBounds.bottom = parentBounds.right - origLeft; return; case ROTATION_180: inOutBounds.left = parentBounds.right - inOutBounds.right; inOutBounds.right = parentBounds.right - origLeft; inOutBounds.top = parentBounds.bottom - inOutBounds.bottom; inOutBounds.bottom = parentBounds.bottom - origTop; return; case ROTATION_270: inOutBounds.left = parentBounds.bottom - inOutBounds.bottom; inOutBounds.bottom = inOutBounds.right; inOutBounds.right = parentBounds.bottom - inOutBounds.top; inOutBounds.top = origLeft; } } /** @return the rotation needed to rotate from oldRotation to newRotation. */ @Rotation public static int deltaRotation(int oldRotation, int newRotation) { int delta = newRotation - oldRotation; if (delta < 0) delta += 4; return delta; } /** * Sets a matrix such that given a rotation, it transforms physical display * coordinates to that rotation's logical coordinates. Loading core/tests/coretests/src/android/util/RotationUtilsTest.java 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.util; import static android.util.RotationUtils.rotateBounds; 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.Rect; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; /** * Tests for {@link RotationUtils}. * * Build/Install/Run: * atest FrameworksCoreTests:RotationUtilsTest */ @SmallTest @RunWith(AndroidJUnit4.class) public class RotationUtilsTest { @Test public void testRotateBounds() { Rect testParent = new Rect(0, 0, 1000, 600); Rect testInner = new Rect(40, 20, 120, 80); Rect testResult = new Rect(testInner); rotateBounds(testResult, testParent, ROTATION_90); assertEquals(new Rect(20, 880, 80, 960), testResult); testResult.set(testInner); rotateBounds(testResult, testParent, ROTATION_180); assertEquals(new Rect(880, 520, 960, 580), testResult); testResult.set(testInner); rotateBounds(testResult, testParent, ROTATION_270); assertEquals(new Rect(520, 40, 580, 120), testResult); } } libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java +3 −35 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.content.res.Configuration.UI_MODE_TYPE_CAR; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.os.Process.SYSTEM_UID; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; import static android.util.RotationUtils.rotateBounds; import static android.util.RotationUtils.rotateInsets; import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; Loading @@ -37,7 +39,6 @@ import android.graphics.Rect; import android.os.SystemProperties; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.RotationUtils; import android.util.Size; import android.view.Display; import android.view.DisplayCutout; Loading Loading @@ -240,38 +241,6 @@ public class DisplayLayout { return navigationBarPosition(res, mWidth, mHeight, mRotation); } /** * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta` * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and * remains at 0,0 after rotation. * * Only 'bounds' is mutated. */ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, int delta) { int rdelta = ((delta % 4) + 4) % 4; int origLeft = inOutBounds.left; switch (rdelta) { case 0: return; case 1: inOutBounds.left = inOutBounds.top; inOutBounds.top = parentBounds.right - inOutBounds.right; inOutBounds.right = inOutBounds.bottom; inOutBounds.bottom = parentBounds.right - origLeft; return; case 2: inOutBounds.left = parentBounds.right - inOutBounds.right; inOutBounds.right = parentBounds.right - origLeft; return; case 3: inOutBounds.left = parentBounds.bottom - inOutBounds.bottom; inOutBounds.bottom = inOutBounds.right; inOutBounds.right = parentBounds.bottom - inOutBounds.top; inOutBounds.top = origLeft; return; } } /** * Calculates the stable insets if we already have the non-decor insets. */ Loading Loading @@ -359,8 +328,7 @@ public class DisplayLayout { if (rotation == ROTATION_0) { return computeSafeInsets(cutout, displayWidth, displayHeight); } final Insets waterfallInsets = RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation); final Insets waterfallInsets = rotateInsets(cutout.getWaterfallInsets(), rotation); final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); Rect[] cutoutRects = cutout.getBoundingRectsAll(); final Rect[] newBounds = new Rect[cutoutRects.length]; Loading libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java +2 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.legacysplitscreen; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.util.RotationUtils.rotateBounds; import static android.view.WindowManager.DOCKED_BOTTOM; import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.DOCKED_LEFT; Loading Loading @@ -244,7 +245,7 @@ public class LegacySplitDisplayLayout { DividerSnapAlgorithm snap = initSnapAlgorithmForRotation(context, tmpDL, dividerSize); tmpRect.set(bounds); DisplayLayout.rotateBounds(tmpRect, displayRect, rotation - dl.rotation()); rotateBounds(tmpRect, displayRect, dl.rotation(), rotation); rotatedDisplayRect.set(0, 0, tmpDL.width(), tmpDL.height()); final int dockSide = getPrimarySplitSide(tmpRect, rotatedDisplayRect, tmpDL.getOrientation()); Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +2 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.pip; import static android.util.RotationUtils.rotateBounds; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; Loading @@ -33,7 +34,6 @@ import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.wm.shell.animation.Interpolators; import com.android.wm.shell.common.DisplayLayout; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -448,7 +448,7 @@ public class PipAnimationController { // Rotate the end bounds according to the rotation delta because the display will // be rotated to the same orientation. rotatedEndRect = new Rect(endValue); DisplayLayout.rotateBounds(rotatedEndRect, endValue, rotationDelta); rotateBounds(rotatedEndRect, endValue, rotationDelta); } else { rotatedEndRect = null; } Loading Loading
core/java/android/util/RotationUtils.java +55 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.view.Surface.ROTATION_90; import android.annotation.Dimension; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; import android.view.Surface.Rotation; /** Loading Loading @@ -72,6 +73,60 @@ public class RotationUtils { return rotated; } /** * Rotates bounds as if parentBounds and bounds are a group. The group is rotated from * oldRotation to newRotation. This assumes that parentBounds is at 0,0 and remains at 0,0 after * rotation. The bounds will be at the same physical position in parentBounds. * * Only 'inOutBounds' is mutated. */ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, @Rotation int oldRotation, @Rotation int newRotation) { rotateBounds(inOutBounds, parentBounds, deltaRotation(oldRotation, newRotation)); } /** * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta` * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and * remains at 0,0 after rotation. The bounds will be at the same physical position in * parentBounds. * * Only 'inOutBounds' is mutated. */ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, @Rotation int rotation) { final int origLeft = inOutBounds.left; final int origTop = inOutBounds.top; switch (rotation) { case ROTATION_0: return; case ROTATION_90: inOutBounds.left = inOutBounds.top; inOutBounds.top = parentBounds.right - inOutBounds.right; inOutBounds.right = inOutBounds.bottom; inOutBounds.bottom = parentBounds.right - origLeft; return; case ROTATION_180: inOutBounds.left = parentBounds.right - inOutBounds.right; inOutBounds.right = parentBounds.right - origLeft; inOutBounds.top = parentBounds.bottom - inOutBounds.bottom; inOutBounds.bottom = parentBounds.bottom - origTop; return; case ROTATION_270: inOutBounds.left = parentBounds.bottom - inOutBounds.bottom; inOutBounds.bottom = inOutBounds.right; inOutBounds.right = parentBounds.bottom - inOutBounds.top; inOutBounds.top = origLeft; } } /** @return the rotation needed to rotate from oldRotation to newRotation. */ @Rotation public static int deltaRotation(int oldRotation, int newRotation) { int delta = newRotation - oldRotation; if (delta < 0) delta += 4; return delta; } /** * Sets a matrix such that given a rotation, it transforms physical display * coordinates to that rotation's logical coordinates. Loading
core/tests/coretests/src/android/util/RotationUtilsTest.java 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.util; import static android.util.RotationUtils.rotateBounds; 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.Rect; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; /** * Tests for {@link RotationUtils}. * * Build/Install/Run: * atest FrameworksCoreTests:RotationUtilsTest */ @SmallTest @RunWith(AndroidJUnit4.class) public class RotationUtilsTest { @Test public void testRotateBounds() { Rect testParent = new Rect(0, 0, 1000, 600); Rect testInner = new Rect(40, 20, 120, 80); Rect testResult = new Rect(testInner); rotateBounds(testResult, testParent, ROTATION_90); assertEquals(new Rect(20, 880, 80, 960), testResult); testResult.set(testInner); rotateBounds(testResult, testParent, ROTATION_180); assertEquals(new Rect(880, 520, 960, 580), testResult); testResult.set(testInner); rotateBounds(testResult, testParent, ROTATION_270); assertEquals(new Rect(520, 40, 580, 120), testResult); } }
libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java +3 −35 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.content.res.Configuration.UI_MODE_TYPE_CAR; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.os.Process.SYSTEM_UID; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; import static android.util.RotationUtils.rotateBounds; import static android.util.RotationUtils.rotateInsets; import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; Loading @@ -37,7 +39,6 @@ import android.graphics.Rect; import android.os.SystemProperties; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.RotationUtils; import android.util.Size; import android.view.Display; import android.view.DisplayCutout; Loading Loading @@ -240,38 +241,6 @@ public class DisplayLayout { return navigationBarPosition(res, mWidth, mHeight, mRotation); } /** * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta` * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and * remains at 0,0 after rotation. * * Only 'bounds' is mutated. */ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, int delta) { int rdelta = ((delta % 4) + 4) % 4; int origLeft = inOutBounds.left; switch (rdelta) { case 0: return; case 1: inOutBounds.left = inOutBounds.top; inOutBounds.top = parentBounds.right - inOutBounds.right; inOutBounds.right = inOutBounds.bottom; inOutBounds.bottom = parentBounds.right - origLeft; return; case 2: inOutBounds.left = parentBounds.right - inOutBounds.right; inOutBounds.right = parentBounds.right - origLeft; return; case 3: inOutBounds.left = parentBounds.bottom - inOutBounds.bottom; inOutBounds.bottom = inOutBounds.right; inOutBounds.right = parentBounds.bottom - inOutBounds.top; inOutBounds.top = origLeft; return; } } /** * Calculates the stable insets if we already have the non-decor insets. */ Loading Loading @@ -359,8 +328,7 @@ public class DisplayLayout { if (rotation == ROTATION_0) { return computeSafeInsets(cutout, displayWidth, displayHeight); } final Insets waterfallInsets = RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation); final Insets waterfallInsets = rotateInsets(cutout.getWaterfallInsets(), rotation); final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); Rect[] cutoutRects = cutout.getBoundingRectsAll(); final Rect[] newBounds = new Rect[cutoutRects.length]; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java +2 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.legacysplitscreen; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.util.RotationUtils.rotateBounds; import static android.view.WindowManager.DOCKED_BOTTOM; import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.DOCKED_LEFT; Loading Loading @@ -244,7 +245,7 @@ public class LegacySplitDisplayLayout { DividerSnapAlgorithm snap = initSnapAlgorithmForRotation(context, tmpDL, dividerSize); tmpRect.set(bounds); DisplayLayout.rotateBounds(tmpRect, displayRect, rotation - dl.rotation()); rotateBounds(tmpRect, displayRect, dl.rotation(), rotation); rotatedDisplayRect.set(0, 0, tmpDL.width(), tmpDL.height()); final int dockSide = getPrimarySplitSide(tmpRect, rotatedDisplayRect, tmpDL.getOrientation()); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +2 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.pip; import static android.util.RotationUtils.rotateBounds; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; Loading @@ -33,7 +34,6 @@ import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.wm.shell.animation.Interpolators; import com.android.wm.shell.common.DisplayLayout; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -448,7 +448,7 @@ public class PipAnimationController { // Rotate the end bounds according to the rotation delta because the display will // be rotated to the same orientation. rotatedEndRect = new Rect(endValue); DisplayLayout.rotateBounds(rotatedEndRect, endValue, rotationDelta); rotateBounds(rotatedEndRect, endValue, rotationDelta); } else { rotatedEndRect = null; } Loading