Merge "Allow separate top and bottom rounded.xml layouts" into rvc-d1-dev

This commit is contained in:
TreeHugger Robot
2020-06-20 20:58:44 +00:00
committed by Android (Google) Code Review
7 changed files with 213 additions and 49 deletions

View File

@@ -0,0 +1,16 @@
<!--
Copyright (C) 2020 The Android Open Source Project
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.
-->
<!-- Overlay this resource to change rounded_corners_bottom -->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/rounded"/>

View File

@@ -0,0 +1,16 @@
<!--
Copyright (C) 2020 The Android Open Source Project
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.
-->
<!-- Overlay this resource to change rounded_corners_top -->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/rounded"/>

View File

@@ -16,6 +16,7 @@
-->
<com.android.systemui.RegionInterceptingFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rounded_corners_default"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
** Copyright 2020, 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.
-->
<com.android.systemui.RegionInterceptingFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rounded_corners_bottom"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/left"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="left|bottom"
android:tint="#ff000000"
android:src="@drawable/rounded_corner_bottom"/>
<ImageView
android:id="@+id/right"
android:layout_width="12dp"
android:layout_height="12dp"
android:tint="#ff000000"
android:layout_gravity="right|bottom"
android:src="@drawable/rounded_corner_bottom"/>
</com.android.systemui.RegionInterceptingFrameLayout>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
** Copyright 2020, 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.
-->
<com.android.systemui.RegionInterceptingFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rounded_corners_top"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/left"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="left|top"
android:tint="#ff000000"
android:src="@drawable/rounded_corner_top"/>
<ImageView
android:id="@+id/right"
android:layout_width="12dp"
android:layout_height="12dp"
android:tint="#ff000000"
android:layout_gravity="right|top"
android:src="@drawable/rounded_corner_top"/>
</com.android.systemui.RegionInterceptingFrameLayout>

View File

@@ -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);
}

View File

@@ -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);