diff --git a/packages/SystemUI/res/drawable/rounded_corner_bottom.xml b/packages/SystemUI/res/drawable/rounded_corner_bottom.xml new file mode 100644 index 0000000000000..ef1a82f9798c7 --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_corner_bottom.xml @@ -0,0 +1,16 @@ + + + diff --git a/packages/SystemUI/res/drawable/rounded_corner_top.xml b/packages/SystemUI/res/drawable/rounded_corner_top.xml new file mode 100644 index 0000000000000..79348928a7a8f --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_corner_top.xml @@ -0,0 +1,16 @@ + + + diff --git a/packages/SystemUI/res/layout/rounded_corners.xml b/packages/SystemUI/res/layout/rounded_corners.xml index 1849068d91b83..db892d78c5563 100644 --- a/packages/SystemUI/res/layout/rounded_corners.xml +++ b/packages/SystemUI/res/layout/rounded_corners.xml @@ -16,6 +16,7 @@ --> + + + + + diff --git a/packages/SystemUI/res/layout/rounded_corners_top.xml b/packages/SystemUI/res/layout/rounded_corners_top.xml new file mode 100644 index 0000000000000..813c97d06f579 --- /dev/null +++ b/packages/SystemUI/res/layout/rounded_corners_top.xml @@ -0,0 +1,36 @@ + + + + + + diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 7861211e802da..6c06553a84a6c 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -48,10 +48,11 @@ import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; -import android.graphics.drawable.VectorDrawable; +import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.HandlerExecutor; @@ -117,12 +118,15 @@ public class ScreenDecorations extends SystemUI implements Tunable { private DisplayManager.DisplayListener mDisplayListener; private CameraAvailabilityListener mCameraListener; + //TODO: These are piecemeal being updated to Points for now to support non-square rounded + // corners. for now it is only supposed when reading the intrinsic size from the drawables with + // mIsRoundedCornerMultipleRadius is set @VisibleForTesting - protected int mRoundedDefault; + protected Point mRoundedDefault = new Point(0, 0); @VisibleForTesting - protected int mRoundedDefaultTop; + protected Point mRoundedDefaultTop = new Point(0, 0); @VisibleForTesting - protected int mRoundedDefaultBottom; + protected Point mRoundedDefaultBottom = new Point(0, 0); @VisibleForTesting protected View[] mOverlays; @Nullable @@ -375,8 +379,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { if (mOverlays[pos] != null) { return; } - mOverlays[pos] = LayoutInflater.from(mContext) - .inflate(R.layout.rounded_corners, null); + mOverlays[pos] = overlayForPosition(pos); mCutoutViews[pos] = new DisplayCutoutView(mContext, pos, this); ((ViewGroup) mOverlays[pos]).addView(mCutoutViews[pos]); @@ -405,6 +408,23 @@ public class ScreenDecorations extends SystemUI implements Tunable { new ValidatingPreDrawListener(mOverlays[pos])); } + /** + * Allow overrides for top/bottom positions + */ + private View overlayForPosition(@BoundsPosition int pos) { + switch (pos) { + case BOUNDS_POSITION_TOP: + return LayoutInflater.from(mContext) + .inflate(R.layout.rounded_corners_top, null); + case BOUNDS_POSITION_BOTTOM: + return LayoutInflater.from(mContext) + .inflate(R.layout.rounded_corners_bottom, null); + default: + return LayoutInflater.from(mContext) + .inflate(R.layout.rounded_corners, null); + } + } + private void updateView(@BoundsPosition int pos) { if (mOverlays == null || mOverlays[pos] == null) { return; @@ -590,27 +610,36 @@ public class ScreenDecorations extends SystemUI implements Tunable { } private void updateRoundedCornerRadii() { + // We should eventually move to just using the intrinsic size of the drawables since + // they should be sized to the exact pixels they want to cover. Therefore I'm purposely not + // upgrading all of the configs to contain (width, height) pairs. Instead assume that a + // device configured using the single integer config value is okay with drawing the corners + // as a square final int newRoundedDefault = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.rounded_corner_radius); final int newRoundedDefaultTop = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.rounded_corner_radius_top); final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.rounded_corner_radius_bottom); - final boolean roundedCornersChanged = mRoundedDefault != newRoundedDefault - || mRoundedDefaultBottom != newRoundedDefaultBottom - || mRoundedDefaultTop != newRoundedDefaultTop; - if (roundedCornersChanged) { + final boolean changed = mRoundedDefault.x != newRoundedDefault + || mRoundedDefaultTop.x != newRoundedDefault + || mRoundedDefaultBottom.x != newRoundedDefault; + + if (changed) { // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the - // max(width, height) size of drawable/rounded.xml instead of rounded_corner_radius + // (width, height) size of drawable/rounded.xml instead of rounded_corner_radius if (mIsRoundedCornerMultipleRadius) { - final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded); - mRoundedDefault = Math.max(d.getIntrinsicWidth(), d.getIntrinsicHeight()); - mRoundedDefaultTop = mRoundedDefaultBottom = mRoundedDefault; + Drawable d = mContext.getDrawable(R.drawable.rounded); + mRoundedDefault.set(d.getIntrinsicWidth(), d.getIntrinsicHeight()); + d = mContext.getDrawable(R.drawable.rounded_corner_top); + mRoundedDefaultTop.set(d.getIntrinsicWidth(), d.getIntrinsicHeight()); + d = mContext.getDrawable(R.drawable.rounded_corner_bottom); + mRoundedDefaultBottom.set(d.getIntrinsicWidth(), d.getIntrinsicHeight()); } else { - mRoundedDefault = newRoundedDefault; - mRoundedDefaultTop = newRoundedDefaultTop; - mRoundedDefaultBottom = newRoundedDefaultBottom; + mRoundedDefault.set(newRoundedDefault, newRoundedDefault); + mRoundedDefaultTop.set(newRoundedDefaultTop, newRoundedDefaultTop); + mRoundedDefaultBottom.set(newRoundedDefaultBottom, newRoundedDefaultBottom); } onTuningChanged(SIZE, null); } @@ -625,7 +654,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { if (shouldShowRoundedCorner(pos)) { final int gravity = getRoundedCornerGravity(pos, id == R.id.left); ((FrameLayout.LayoutParams) rounded.getLayoutParams()).gravity = gravity; - rounded.setRotation(getRoundedCornerRotation(gravity)); + setRoundedCornerOrientation(rounded, gravity); rounded.setVisibility(View.VISIBLE); } } @@ -646,23 +675,38 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } - private int getRoundedCornerRotation(int gravity) { + /** + * Configures the rounded corner drawable's view matrix based on the gravity. + * + * The gravity describes which corner to configure for, and the drawable we are rotating is + * assumed to be oriented for the top-left corner of the device regardless of the target corner. + * Therefore we need to rotate 180 degrees to get a bottom-left corner, and mirror in the x- or + * y-axis for the top-right and bottom-left corners. + */ + private void setRoundedCornerOrientation(View corner, int gravity) { + corner.setRotation(0); + corner.setScaleX(1); + corner.setScaleY(1); switch (gravity) { case Gravity.TOP | Gravity.LEFT: - return 0; + return; case Gravity.TOP | Gravity.RIGHT: - return 90; + corner.setScaleX(-1); // flip X axis + return; case Gravity.BOTTOM | Gravity.LEFT: - return 270; + corner.setScaleY(-1); // flip Y axis + return; case Gravity.BOTTOM | Gravity.RIGHT: - return 180; + corner.setRotation(180); + return; default: throw new IllegalArgumentException("Unsupported gravity: " + gravity); } } - private boolean hasRoundedCorners() { - return mRoundedDefault > 0 || mRoundedDefaultBottom > 0 || mRoundedDefaultTop > 0 + return mRoundedDefault.x > 0 + || mRoundedDefaultBottom.x > 0 + || mRoundedDefaultTop.x > 0 || mIsRoundedCornerMultipleRadius; } @@ -712,12 +756,13 @@ public class ScreenDecorations extends SystemUI implements Tunable { mHandler.post(() -> { if (mOverlays == null) return; if (SIZE.equals(key)) { - int size = mRoundedDefault; - int sizeTop = mRoundedDefaultTop; - int sizeBottom = mRoundedDefaultBottom; + Point size = mRoundedDefault; + Point sizeTop = mRoundedDefaultTop; + Point sizeBottom = mRoundedDefaultBottom; if (newValue != null) { try { - size = (int) (Integer.parseInt(newValue) * mDensity); + int s = (int) (Integer.parseInt(newValue) * mDensity); + size = new Point(s, s); } catch (Exception e) { } } @@ -726,14 +771,17 @@ public class ScreenDecorations extends SystemUI implements Tunable { }); } - private void updateRoundedCornerSize(int sizeDefault, int sizeTop, int sizeBottom) { + private void updateRoundedCornerSize( + Point sizeDefault, + Point sizeTop, + Point sizeBottom) { if (mOverlays == null) { return; } - if (sizeTop == 0) { + if (sizeTop.x == 0) { sizeTop = sizeDefault; } - if (sizeBottom == 0) { + if (sizeBottom.x == 0) { sizeBottom = sizeDefault; } @@ -760,10 +808,10 @@ public class ScreenDecorations extends SystemUI implements Tunable { } @VisibleForTesting - protected void setSize(View view, int pixelSize) { + protected void setSize(View view, Point pixelSize) { LayoutParams params = view.getLayoutParams(); - params.width = pixelSize; - params.height = pixelSize; + params.width = pixelSize.x; + params.height = pixelSize.y; view.setLayoutParams(params); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index b9ddff3a59ea8..d107f646bb6b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -44,6 +44,7 @@ import static org.mockito.Mockito.when; import android.content.res.Configuration; import android.graphics.Insets; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.VectorDrawable; import android.hardware.display.DisplayManager; @@ -193,6 +194,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { @Test public void testRoundingRadius_NoCutout() { final int testRadius = 1; + final Point testRadiusPoint = new Point(1, 1); mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false); mContext.getOrCreateTestableResources().addOverride( @@ -209,9 +211,9 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Size of corner view should same as rounded_corner_radius{_top|_bottom} - assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(testRadius); - assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(testRadius); - assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(testRadius); + assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(testRadiusPoint); + assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(testRadiusPoint); + assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(testRadiusPoint); } @Test @@ -237,14 +239,18 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].findViewById(R.id.left); View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].findViewById(R.id.right); - verify(mScreenDecorations, atLeastOnce()).setSize(leftRoundedCorner, testTopRadius); - verify(mScreenDecorations, atLeastOnce()).setSize(rightRoundedCorner, testTopRadius); + verify(mScreenDecorations, atLeastOnce()) + .setSize(leftRoundedCorner, new Point(testTopRadius, testTopRadius)); + verify(mScreenDecorations, atLeastOnce()) + .setSize(rightRoundedCorner, new Point(testTopRadius, testTopRadius)); leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].findViewById(R.id.left); rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].findViewById(R.id.right); - verify(mScreenDecorations, atLeastOnce()).setSize(leftRoundedCorner, testBottomRadius); - verify(mScreenDecorations, atLeastOnce()).setSize(rightRoundedCorner, testBottomRadius); + verify(mScreenDecorations, atLeastOnce()) + .setSize(leftRoundedCorner, new Point(testBottomRadius, testBottomRadius)); + verify(mScreenDecorations, atLeastOnce()) + .setSize(rightRoundedCorner, new Point(testBottomRadius, testBottomRadius)); } @Test @@ -276,20 +282,24 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].findViewById(R.id.left); View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].findViewById(R.id.right); - verify(mScreenDecorations, atLeastOnce()).setSize(leftRoundedCorner, testTopRadius); - verify(mScreenDecorations, atLeastOnce()).setSize(rightRoundedCorner, testBottomRadius); + verify(mScreenDecorations, atLeastOnce()) + .setSize(leftRoundedCorner, new Point(testTopRadius, testTopRadius)); + verify(mScreenDecorations, atLeastOnce()) + .setSize(rightRoundedCorner, new Point(testBottomRadius, testBottomRadius)); leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].findViewById(R.id.left); rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].findViewById(R.id.right); - verify(mScreenDecorations, atLeastOnce()).setSize(leftRoundedCorner, testTopRadius); - verify(mScreenDecorations, atLeastOnce()).setSize(rightRoundedCorner, testBottomRadius); + verify(mScreenDecorations, atLeastOnce()) + .setSize(leftRoundedCorner, new Point(testTopRadius, testTopRadius)); + verify(mScreenDecorations, atLeastOnce()) + .setSize(rightRoundedCorner, new Point(testBottomRadius, testBottomRadius)); } @Test public void testRoundingMultipleRadius_NoCutout() { final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded); - final int multipleRadiusSize = Math.max(d.getIntrinsicWidth(), d.getIntrinsicHeight()); + final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight()); mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false); @@ -600,14 +610,15 @@ public class ScreenDecorationsTest extends SysuiTestCase { .addOverride(R.bool.config_roundedCornerMultipleRadius, false); mScreenDecorations.start(); - assertEquals(mScreenDecorations.mRoundedDefault, 20); + assertEquals(mScreenDecorations.mRoundedDefault, new Point(20, 20)); mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.dimen.rounded_corner_radius, 5); mScreenDecorations.onConfigurationChanged(null); - assertEquals(mScreenDecorations.mRoundedDefault, 5); + assertEquals(mScreenDecorations.mRoundedDefault, new Point(5, 5)); } + @Test public void testBoundingRectsToRegion() throws Exception { Rect rect = new Rect(1, 2, 3, 4);