Provides apps the rounded corners info

- Created a new @hide class RoundedCorners
  - The class is used to create and manager all the rounded corners.
- Created a new public class RoundedCorner
  - Represent each rounded corner.
- Created a new public API in Display to get the original rounded
  corners.
- Created a new public API in WindowInsets to get the rounded corners
  relative to the window bounds.

Bug: 161808676
Test: atest RoundedCornerTest RoundedCornersTest
      DisplayPolicyLayoutTests DisplayPolicyTests
      WallpaperControllerTests
Change-Id: I58c671b0e9a077cdf26764c6302537c72db0f667
This commit is contained in:
shawnlin
2021-01-18 18:39:14 +08:00
parent d9b723b847
commit 5ab588a48b
22 changed files with 1199 additions and 42 deletions

View File

@@ -46120,6 +46120,7 @@ package android.view {
method @Deprecated public void getRectSize(android.graphics.Rect);
method public float getRefreshRate();
method public int getRotation();
method @Nullable public android.view.RoundedCorner getRoundedCorner(int);
method @Deprecated public void getSize(android.graphics.Point);
method public int getState();
method public android.view.Display.Mode[] getSupportedModes();
@@ -47373,6 +47374,20 @@ package android.view {
field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
}
public final class RoundedCorner implements android.os.Parcelable {
ctor public RoundedCorner(int, int, int, int);
method public int describeContents();
method @NonNull public android.graphics.Point getCenter();
method public int getPosition();
method public int getRadius();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.RoundedCorner> CREATOR;
field public static final int POSITION_BOTTOM_LEFT = 3; // 0x3
field public static final int POSITION_BOTTOM_RIGHT = 2; // 0x2
field public static final int POSITION_TOP_LEFT = 0; // 0x0
field public static final int POSITION_TOP_RIGHT = 1; // 0x1
}
public class ScaleGestureDetector {
ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener);
ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener, android.os.Handler);
@@ -49382,6 +49397,7 @@ package android.view {
method @NonNull public android.graphics.Insets getInsets(int);
method @NonNull public android.graphics.Insets getInsetsIgnoringVisibility(int);
method @Deprecated @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
method @Nullable public android.view.RoundedCorner getRoundedCorner(int);
method @Deprecated public int getStableInsetBottom();
method @Deprecated public int getStableInsetLeft();
method @Deprecated public int getStableInsetRight();
@@ -49415,6 +49431,7 @@ package android.view {
method @NonNull public android.view.WindowInsets.Builder setInsets(int, @NonNull android.graphics.Insets);
method @NonNull public android.view.WindowInsets.Builder setInsetsIgnoringVisibility(int, @NonNull android.graphics.Insets) throws java.lang.IllegalArgumentException;
method @Deprecated @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
method @NonNull public android.view.WindowInsets.Builder setRoundedCorner(int, @Nullable android.view.RoundedCorner);
method @Deprecated @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
method @Deprecated @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets);
method @Deprecated @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets);

View File

@@ -899,6 +899,32 @@ public final class Display {
}
}
/**
* Returns the {@link RoundedCorner} of the given position if there is one.
*
* @param position the position of the rounded corner on the display.
*
* @return the rounded corner of the given position. Returns {@code null} if there is none.
*/
@SuppressLint("VisiblySynchronized")
@Nullable
public RoundedCorner getRoundedCorner(@RoundedCorner.Position int position) {
synchronized (this) {
updateDisplayInfoLocked();
RoundedCorners roundedCorners;
if (mMayAdjustByFixedRotation) {
roundedCorners = getDisplayAdjustments().adjustRoundedCorner(
mDisplayInfo.roundedCorners,
mDisplayInfo.rotation,
mDisplayInfo.logicalWidth,
mDisplayInfo.logicalHeight);
} else {
roundedCorners = mDisplayInfo.roundedCorners;
}
return roundedCorners == null ? null : roundedCorners.getRoundedCorner(position);
}
}
/**
* Gets the pixel format of the display.
* @return One of the constants defined in {@link android.graphics.PixelFormat}.

View File

@@ -151,6 +151,23 @@ public class DisplayAdjustments {
: realCutout;
}
/**
* Returns the adjusted {@link RoundedCorners} if available. Otherwise the original
* {@link RoundedCorners} is returned.
*/
@Nullable
public RoundedCorners adjustRoundedCorner(@Nullable RoundedCorners realRoundedCorners,
@Surface.Rotation int realRotation, int displayWidth, int displayHeight) {
final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments;
if (realRoundedCorners == null || rotationAdjustments == null
|| rotationAdjustments.mRotation == realRotation) {
return realRoundedCorners;
}
return realRoundedCorners.rotate(
rotationAdjustments.mRotation, displayWidth, displayHeight);
}
/** Returns the adjusted rotation if available. Otherwise the original rotation is returned. */
@Surface.Rotation
public int getRotation(@Surface.Rotation int realRotation) {

View File

@@ -301,6 +301,12 @@ public final class DisplayInfo implements Parcelable {
*/
public float brightnessDefault;
/**
* The {@link RoundedCorners} if present, otherwise {@code null}.
*/
@Nullable
public RoundedCorners roundedCorners;
public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
@Override
public DisplayInfo createFromParcel(Parcel source) {
@@ -369,7 +375,8 @@ public final class DisplayInfo implements Parcelable {
&& refreshRateOverride == other.refreshRateOverride
&& brightnessMinimum == other.brightnessMinimum
&& brightnessMaximum == other.brightnessMaximum
&& brightnessDefault == other.brightnessDefault;
&& brightnessDefault == other.brightnessDefault
&& Objects.equals(roundedCorners, other.roundedCorners);
}
@Override
@@ -418,6 +425,7 @@ public final class DisplayInfo implements Parcelable {
brightnessMinimum = other.brightnessMinimum;
brightnessMaximum = other.brightnessMaximum;
brightnessDefault = other.brightnessDefault;
roundedCorners = other.roundedCorners;
}
public void readFromParcel(Parcel source) {
@@ -468,6 +476,7 @@ public final class DisplayInfo implements Parcelable {
brightnessMinimum = source.readFloat();
brightnessMaximum = source.readFloat();
brightnessDefault = source.readFloat();
roundedCorners = source.readTypedObject(RoundedCorners.CREATOR);
}
@Override
@@ -517,6 +526,7 @@ public final class DisplayInfo implements Parcelable {
dest.writeFloat(brightnessMinimum);
dest.writeFloat(brightnessMaximum);
dest.writeFloat(brightnessDefault);
dest.writeTypedObject(roundedCorners, flags);
}
@Override

View File

@@ -653,6 +653,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private void updateState(InsetsState newState) {
mState.setDisplayFrame(newState.getDisplayFrame());
mState.setDisplayCutout(newState.getDisplayCutout());
mState.setRoundedCorners(newState.getRoundedCorners());
@InsetsType int disabledUserAnimationTypes = 0;
@InsetsType int[] cancelledUserAnimationTypes = {0};
for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {

View File

@@ -173,6 +173,9 @@ public class InsetsState implements Parcelable {
private final DisplayCutout.ParcelableWrapper mDisplayCutout =
new DisplayCutout.ParcelableWrapper();
/** The rounded corners on the display */
private RoundedCorners mRoundedCorners = RoundedCorners.NO_ROUNDED_CORNERS;
public InsetsState() {
}
@@ -256,7 +259,8 @@ public class InsetsState implements Parcelable {
}
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
alwaysConsumeSystemBars, calculateRelativeCutout(frame), compatInsetsTypes,
alwaysConsumeSystemBars, calculateRelativeCutout(frame),
calculateRelativeRoundedCorners(frame), compatInsetsTypes,
(legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
}
@@ -281,6 +285,20 @@ public class InsetsState implements Parcelable {
return raw.inset(insetLeft, insetTop, insetRight, insetBottom);
}
private RoundedCorners calculateRelativeRoundedCorners(Rect frame) {
if (mDisplayFrame.equals(frame)) {
return mRoundedCorners;
}
if (frame == null) {
return RoundedCorners.NO_ROUNDED_CORNERS;
}
final int insetLeft = frame.left - mDisplayFrame.left;
final int insetTop = frame.top - mDisplayFrame.top;
final int insetRight = mDisplayFrame.right - frame.right;
final int insetBottom = mDisplayFrame.bottom - frame.bottom;
return mRoundedCorners.inset(insetLeft, insetTop, insetRight, insetBottom);
}
public Rect calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
@@ -462,6 +480,14 @@ public class InsetsState implements Parcelable {
return mDisplayCutout.get();
}
public void setRoundedCorners(RoundedCorners roundedCorners) {
mRoundedCorners = roundedCorners;
}
public RoundedCorners getRoundedCorners() {
return mRoundedCorners;
}
/**
* Modifies the state of this class to exclude a certain type to make it ready for dispatching
* to the client.
@@ -493,6 +519,7 @@ public class InsetsState implements Parcelable {
public void scale(float scale) {
mDisplayFrame.scale(scale);
mDisplayCutout.scale(scale);
mRoundedCorners = mRoundedCorners.scale(scale);
for (int i = 0; i < SIZE; i++) {
final InsetsSource source = mSources[i];
if (source != null) {
@@ -512,6 +539,7 @@ public class InsetsState implements Parcelable {
public void set(InsetsState other, boolean copySources) {
mDisplayFrame.set(other.mDisplayFrame);
mDisplayCutout.set(other.mDisplayCutout);
mRoundedCorners = other.getRoundedCorners();
if (copySources) {
for (int i = 0; i < SIZE; i++) {
InsetsSource source = other.mSources[i];
@@ -619,11 +647,15 @@ public class InsetsState implements Parcelable {
}
public void dump(String prefix, PrintWriter pw) {
final String newPrefix = prefix + " ";
pw.println(prefix + "InsetsState");
pw.println(newPrefix + "mDisplayFrame=" + mDisplayFrame);
pw.println(newPrefix + "mDisplayCutout=" + mDisplayCutout.get());
pw.println(newPrefix + "mRoundedCorners=" + mRoundedCorners);
for (int i = 0; i < SIZE; i++) {
InsetsSource source = mSources[i];
if (source == null) continue;
source.dump(prefix + " ", pw);
source.dump(newPrefix + " ", pw);
}
}
@@ -713,7 +745,8 @@ public class InsetsState implements Parcelable {
InsetsState state = (InsetsState) o;
if (!mDisplayFrame.equals(state.mDisplayFrame)
|| !mDisplayCutout.equals(state.mDisplayCutout)) {
|| !mDisplayCutout.equals(state.mDisplayCutout)
|| !mRoundedCorners.equals(state.mRoundedCorners)) {
return false;
}
for (int i = 0; i < SIZE; i++) {
@@ -737,7 +770,8 @@ public class InsetsState implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mDisplayFrame, mDisplayCutout, Arrays.hashCode(mSources));
return Objects.hash(mDisplayFrame, mDisplayCutout, Arrays.hashCode(mSources),
mRoundedCorners);
}
public InsetsState(Parcel in) {
@@ -754,6 +788,7 @@ public class InsetsState implements Parcelable {
mDisplayFrame.writeToParcel(dest, flags);
mDisplayCutout.writeToParcel(dest, flags);
dest.writeParcelableArray(mSources, 0);
dest.writeTypedObject(mRoundedCorners, flags);
}
public static final @android.annotation.NonNull Creator<InsetsState> CREATOR = new Creator<InsetsState>() {
@@ -771,6 +806,7 @@ public class InsetsState implements Parcelable {
mDisplayFrame.set(Rect.CREATOR.createFromParcel(in));
mDisplayCutout.set(DisplayCutout.ParcelableWrapper.CREATOR.createFromParcel(in));
mSources = in.readParcelableArray(null, InsetsSource.class);
mRoundedCorners = in.readTypedObject(RoundedCorners.CREATOR);
}
@Override
@@ -785,6 +821,7 @@ public class InsetsState implements Parcelable {
return "InsetsState: {"
+ "mDisplayFrame=" + mDisplayFrame
+ ", mDisplayCutout=" + mDisplayCutout
+ ", mRoundedCorners=" + mRoundedCorners
+ ", mSources= { " + joiner
+ " }";
}

View File

@@ -0,0 +1,239 @@
/*
* 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.view;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.graphics.Point;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Represents a rounded corner of the display.
*
* <code>
* ________
* / ^
* / | Radius
* | v
* | X <- Center point
* |<----->
* Radius
* </code>
*
* <p>Note: The rounded corner formed by the radius and the center is an approximation.</p>
*
* <p>{@link RoundedCorner} is immutable.</p>
*/
public final class RoundedCorner implements Parcelable {
/**
* The rounded corner is at the top-left of the screen.
*/
public static final int POSITION_TOP_LEFT = 0;
/**
* The rounded corner is at the top-right of the screen.
*/
public static final int POSITION_TOP_RIGHT = 1;
/**
* The rounded corner is at the bottom-right of the screen.
*/
public static final int POSITION_BOTTOM_RIGHT = 2;
/**
* The rounded corner is at the bottom-left of the screen.
*/
public static final int POSITION_BOTTOM_LEFT = 3;
/**
* @hide
*/
@IntDef(prefix = { "POSITION_" }, value = {
POSITION_TOP_LEFT,
POSITION_TOP_RIGHT,
POSITION_BOTTOM_RIGHT,
POSITION_BOTTOM_LEFT
})
@Retention(RetentionPolicy.SOURCE)
public @interface Position {}
private final @Position int mPosition;
private final int mRadius;
@NonNull
private final Point mCenter;
/**
* Creates an empty {@link RoundedCorner} on the given position.
* @hide
*/
@VisibleForTesting
public RoundedCorner(@Position int position) {
mPosition = position;
mRadius = 0;
mCenter = new Point(0, 0);
}
/**
* Creates a {@link RoundedCorner}.
*
* <p>Note that this is only useful for tests. For production code, developers should always
* use a {@link RoundedCorner} obtained from the system via
* {@link WindowInsets#getRoundedCorner} or {@link Display#getRoundedCorner}.</p>
*
* @param position the position of the rounded corner.
* @param radius the radius of the rounded corner.
* @param centerX the x of center point of the rounded corner.
* @param centerY the y of center point of the rounded corner.
*
*/
public RoundedCorner(@Position int position, int radius, int centerX,
int centerY) {
mPosition = position;
mRadius = radius;
mCenter = new Point(centerX, centerY);
}
/**
* Creates a {@link RoundedCorner} from a passed in {@link RoundedCorner}.
*
* @hide
*/
RoundedCorner(RoundedCorner rc) {
mPosition = rc.getPosition();
mRadius = rc.getRadius();
mCenter = new Point(rc.getCenter());
}
/**
* Get the position of this {@link RoundedCorner}.
*
* @see #POSITION_TOP_LEFT
* @see #POSITION_TOP_RIGHT
* @see #POSITION_BOTTOM_RIGHT
* @see #POSITION_BOTTOM_LEFT
*/
public @Position int getPosition() {
return mPosition;
}
/**
* Returns the radius of a quarter circle approximation of this {@link RoundedCorner}.
*
* @return the rounded corner radius of this {@link RoundedCorner}. Returns 0 if there is no
* rounded corner.
*/
public int getRadius() {
return mRadius;
}
/**
* Returns the circle center of a quarter circle approximation of this {@link RoundedCorner}.
*
* @return the center point of this {@link RoundedCorner} in the application's coordinate.
*/
@NonNull
public Point getCenter() {
return new Point(mCenter);
}
/**
* Checks whether this {@link RoundedCorner} exists and is inside the application's bounds.
*
* @return {@code false} if there is a rounded corner and is contained in the application's
* bounds. Otherwise return {@code true}.
*
* @hide
*/
public boolean isEmpty() {
return mRadius == 0 || mCenter.x == 0 || mCenter.y == 0;
}
private String getPositionString(@Position int position) {
switch (position) {
case POSITION_TOP_LEFT:
return "TopLeft";
case POSITION_TOP_RIGHT:
return "TopRight";
case POSITION_BOTTOM_RIGHT:
return "BottomRight";
case POSITION_BOTTOM_LEFT:
return "BottomLeft";
default:
return "Invalid";
}
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof RoundedCorner) {
RoundedCorner r = (RoundedCorner) o;
return mPosition == r.mPosition && mRadius == r.mRadius
&& mCenter.equals(r.mCenter);
}
return false;
}
@Override
public int hashCode() {
int result = 0;
result = 31 * result + mPosition;
result = 31 * result + mRadius;
result = 31 * result + mCenter.hashCode();
return result;
}
@Override
public String toString() {
return "RoundedCorner{"
+ "position=" + getPositionString(mPosition)
+ ", radius=" + mRadius
+ ", center=" + mCenter
+ '}';
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mPosition);
out.writeInt(mRadius);
out.writeInt(mCenter.x);
out.writeInt(mCenter.y);
}
public static final @NonNull Creator<RoundedCorner> CREATOR = new Creator<RoundedCorner>() {
@Override
public RoundedCorner createFromParcel(Parcel in) {
return new RoundedCorner(in.readInt(), in.readInt(), in.readInt(), in.readInt());
}
@Override
public RoundedCorner[] newArray(int size) {
return new RoundedCorner[size];
}
};
}

View File

@@ -0,0 +1,19 @@
/**
* 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.view;
parcelable RoundedCorners;

View File

@@ -0,0 +1,380 @@
/*
* 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.view;
import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
import static android.view.RoundedCorner.POSITION_TOP_LEFT;
import static android.view.RoundedCorner.POSITION_TOP_RIGHT;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources;
import android.graphics.Point;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
import android.view.RoundedCorner.Position;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.util.Arrays;
/**
* A class to create & manage all the {@link RoundedCorner} on the display.
*
* @hide
*/
public class RoundedCorners implements Parcelable {
public static final RoundedCorners NO_ROUNDED_CORNERS = new RoundedCorners(
new RoundedCorner(POSITION_TOP_LEFT), new RoundedCorner(POSITION_TOP_RIGHT),
new RoundedCorner(POSITION_BOTTOM_RIGHT), new RoundedCorner(POSITION_BOTTOM_LEFT));
/**
* The number of possible positions at which rounded corners can be located.
*/
public static final int ROUNDED_CORNER_POSITION_LENGTH = 4;
private static final Object CACHE_LOCK = new Object();
@GuardedBy("CACHE_LOCK")
private static int sCachedDisplayWidth;
@GuardedBy("CACHE_LOCK")
private static int sCachedDisplayHeight;
@GuardedBy("CACHE_LOCK")
private static Pair<Integer, Integer> sCachedRadii;
@GuardedBy("CACHE_LOCK")
private static RoundedCorners sCachedRoundedCorners;
@VisibleForTesting
public final RoundedCorner[] mRoundedCorners;
public RoundedCorners(RoundedCorner[] roundedCorners) {
mRoundedCorners = roundedCorners;
}
public RoundedCorners(RoundedCorner topLeft, RoundedCorner topRight, RoundedCorner bottomRight,
RoundedCorner bottomLeft) {
mRoundedCorners = new RoundedCorner[ROUNDED_CORNER_POSITION_LENGTH];
mRoundedCorners[POSITION_TOP_LEFT] = topLeft;
mRoundedCorners[POSITION_TOP_RIGHT] = topRight;
mRoundedCorners[POSITION_BOTTOM_RIGHT] = bottomRight;
mRoundedCorners[POSITION_BOTTOM_LEFT] = bottomLeft;
}
public RoundedCorners(RoundedCorners roundedCorners) {
mRoundedCorners = new RoundedCorner[ROUNDED_CORNER_POSITION_LENGTH];
for (int i = 0; i < ROUNDED_CORNER_POSITION_LENGTH; ++i) {
mRoundedCorners[i] = new RoundedCorner(roundedCorners.mRoundedCorners[i]);
}
}
/**
* Creates the rounded corners according to @android:dimen/rounded_corner_radius,
* @android:dimen/rounded_corner_radius_top and @android:dimen/rounded_corner_radius_bottom
*/
public static RoundedCorners fromResources(
Resources res, int displayWidth, int displayHeight) {
return fromRadii(loadRoundedCornerRadii(res), displayWidth, displayHeight);
}
/**
* Creates the rounded corners from radius
*/
@VisibleForTesting
public static RoundedCorners fromRadii(Pair<Integer, Integer> radii, int displayWidth,
int displayHeight) {
if (radii == null) {
return null;
}
synchronized (CACHE_LOCK) {
if (radii.equals(sCachedRadii) && sCachedDisplayWidth == displayWidth
&& sCachedDisplayHeight == displayHeight) {
return sCachedRoundedCorners;
}
}
final RoundedCorner[] roundedCorners = new RoundedCorner[ROUNDED_CORNER_POSITION_LENGTH];
final int topRadius = radii.first > 0 ? radii.first : 0;
final int bottomRadius = radii.second > 0 ? radii.second : 0;
for (int i = 0; i < ROUNDED_CORNER_POSITION_LENGTH; i++) {
roundedCorners[i] = createRoundedCorner(
i,
i <= POSITION_TOP_RIGHT ? topRadius : bottomRadius,
displayWidth,
displayHeight);
}
final RoundedCorners result = new RoundedCorners(roundedCorners);
synchronized (CACHE_LOCK) {
sCachedDisplayWidth = displayWidth;
sCachedDisplayHeight = displayHeight;
sCachedRadii = radii;
sCachedRoundedCorners = result;
}
return result;
}
/**
* Loads the rounded corner radii from resources.
*
* @param res
* @return a Pair of radius. The first is the top rounded corner radius and second is the
* bottom corner radius.
*/
@Nullable
private static Pair<Integer, Integer> loadRoundedCornerRadii(Resources res) {
final int radiusDefault = res.getDimensionPixelSize(R.dimen.rounded_corner_radius);
final int radiusTop = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_top);
final int radiusBottom = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_bottom);
if (radiusDefault == 0 && radiusTop == 0 && radiusBottom == 0) {
return null;
}
final Pair<Integer, Integer> radii = new Pair<>(
radiusTop > 0 ? radiusTop : radiusDefault,
radiusBottom > 0 ? radiusBottom : radiusDefault);
return radii;
}
/**
* Insets the reference frame of the rounded corners.
*
* @return a copy of this instance which has been inset
*/
public RoundedCorners inset(int insetLeft, int insetTop, int insetRight, int insetBottom) {
final RoundedCorner[] roundedCorners = new RoundedCorner[ROUNDED_CORNER_POSITION_LENGTH];
for (int i = 0; i < ROUNDED_CORNER_POSITION_LENGTH; i++) {
roundedCorners[i] = insetRoundedCorner(i, insetLeft, insetTop, insetRight, insetBottom);
}
return new RoundedCorners(roundedCorners);
}
private RoundedCorner insetRoundedCorner(@Position int position, int insetLeft,
int insetTop, int insetRight, int insetBottom) {
if (mRoundedCorners[position].isEmpty()) {
return new RoundedCorner(position);
}
final int radius = mRoundedCorners[position].getRadius();
final Point center = mRoundedCorners[position].getCenter();
boolean hasRoundedCorner;
switch (position) {
case POSITION_TOP_LEFT:
hasRoundedCorner = radius > insetTop || radius > insetLeft;
break;
case POSITION_TOP_RIGHT:
hasRoundedCorner = radius > insetTop || radius > insetRight;
break;
case POSITION_BOTTOM_RIGHT:
hasRoundedCorner = radius > insetBottom || radius > insetRight;
break;
case POSITION_BOTTOM_LEFT:
hasRoundedCorner = radius > insetBottom || radius > insetLeft;
break;
default:
throw new IllegalArgumentException(
"The position is not one of the RoundedCornerPosition =" + position);
}
return new RoundedCorner(
position, radius,
hasRoundedCorner ? center.x - insetLeft : 0,
hasRoundedCorner ? center.y - insetTop : 0);
}
/**
* Returns the {@link RoundedCorner} of the given position if there is one.
*
* @param position the position of the rounded corner on the display.
* @return the rounded corner of the given position. Returns {@code null} if
* {@link RoundedCorner#isEmpty()} is {@code true}.
*/
@Nullable
public RoundedCorner getRoundedCorner(@Position int position) {
return mRoundedCorners[position].isEmpty()
? null : new RoundedCorner(mRoundedCorners[position]);
}
/**
* Sets the rounded corner of given position.
*
* @param position the position of this rounded corner
* @param roundedCorner the rounded corner or null if there is none
*/
public void setRoundedCorner(@Position int position, @Nullable RoundedCorner roundedCorner) {
mRoundedCorners[position] = roundedCorner == null
? new RoundedCorner(position) : roundedCorner;
}
/**
* Returns an array of {@link RoundedCorner}s. Ordinal value of RoundedCornerPosition is used
* as an index of the array.
*
* @return an array of {@link RoundedCorner}s, one for each rounded corner area.
*/
public RoundedCorner[] getAllRoundedCorners() {
RoundedCorner[] roundedCorners = new RoundedCorner[ROUNDED_CORNER_POSITION_LENGTH];
for (int i = 0; i < ROUNDED_CORNER_POSITION_LENGTH; ++i) {
roundedCorners[i] = new RoundedCorner(roundedCorners[i]);
}
return roundedCorners;
}
/**
* Returns a scaled RoundedCorners.
*/
public RoundedCorners scale(float scale) {
if (scale == 1f) {
return this;
}
RoundedCorner[] roundedCorners = new RoundedCorner[ROUNDED_CORNER_POSITION_LENGTH];
for (int i = 0; i < ROUNDED_CORNER_POSITION_LENGTH; ++i) {
final RoundedCorner roundedCorner = mRoundedCorners[i];
roundedCorners[i] = new RoundedCorner(
i,
(int) (roundedCorner.getRadius() * scale),
(int) (roundedCorner.getCenter().x * scale),
(int) (roundedCorner.getCenter().y * scale));
}
return new RoundedCorners(roundedCorners);
}
/**
* Returns a rotated RoundedCorners.
*/
public RoundedCorners rotate(@Surface.Rotation int rotation, int initialDisplayWidth,
int initialDisplayHeight) {
if (rotation == ROTATION_0) {
return this;
}
final boolean isSizeFlipped = rotation == ROTATION_90 || rotation == ROTATION_270;
RoundedCorner[] newCorners = new RoundedCorner[ROUNDED_CORNER_POSITION_LENGTH];
int newPosistion;
for (int i = 0; i < mRoundedCorners.length; i++) {
newPosistion = getRotatedIndex(i, rotation);
newCorners[newPosistion] = createRoundedCorner(
newPosistion,
mRoundedCorners[i].getRadius(),
isSizeFlipped ? initialDisplayHeight : initialDisplayWidth,
isSizeFlipped ? initialDisplayWidth : initialDisplayHeight);
}
return new RoundedCorners(newCorners);
}
private static RoundedCorner createRoundedCorner(@Position int position,
int radius, int displayWidth, int displayHeight) {
switch (position) {
case POSITION_TOP_LEFT:
return new RoundedCorner(
POSITION_TOP_LEFT,
radius,
radius > 0 ? radius : 0,
radius > 0 ? radius : 0);
case POSITION_TOP_RIGHT:
return new RoundedCorner(
POSITION_TOP_RIGHT,
radius,
radius > 0 ? displayWidth - radius : 0,
radius > 0 ? radius : 0);
case POSITION_BOTTOM_RIGHT:
return new RoundedCorner(
POSITION_BOTTOM_RIGHT,
radius,
radius > 0 ? displayWidth - radius : 0,
radius > 0 ? displayHeight - radius : 0);
case POSITION_BOTTOM_LEFT:
return new RoundedCorner(
POSITION_BOTTOM_LEFT,
radius,
radius > 0 ? radius : 0,
radius > 0 ? displayHeight - radius : 0);
default:
throw new IllegalArgumentException(
"The position is not one of the RoundedCornerPosition =" + position);
}
}
private static int getRotatedIndex(int position, int rotation) {
return (position - rotation + ROUNDED_CORNER_POSITION_LENGTH) % 4;
}
@Override
public int hashCode() {
int result = 0;
for (RoundedCorner roundedCorner : mRoundedCorners) {
result = result * 31 + roundedCorner.hashCode();
}
return result;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof RoundedCorners) {
RoundedCorners r = (RoundedCorners) o;
return Arrays.deepEquals(mRoundedCorners, ((RoundedCorners) o).mRoundedCorners);
}
return false;
}
@Override
public String toString() {
return "RoundedCorners{" + Arrays.toString(mRoundedCorners) + "}";
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
if (equals(NO_ROUNDED_CORNERS)) {
dest.writeInt(0);
} else {
dest.writeInt(1);
dest.writeTypedArray(mRoundedCorners, flags);
}
}
public static final @NonNull Creator<RoundedCorners> CREATOR = new Creator<RoundedCorners>() {
@Override
public RoundedCorners createFromParcel(Parcel in) {
int variant = in.readInt();
if (variant == 0) {
return NO_ROUNDED_CORNERS;
}
RoundedCorner[] roundedCorners = new RoundedCorner[ROUNDED_CORNER_POSITION_LENGTH];
in.readTypedArray(roundedCorners, RoundedCorner.CREATOR);
return new RoundedCorners(roundedCorners);
}
@Override
public RoundedCorners[] newArray(int size) {
return new RoundedCorners[size];
}
};
}

View File

@@ -82,6 +82,7 @@ public final class WindowInsets {
@Nullable private Rect mTempRect;
private final boolean mIsRound;
@Nullable private final DisplayCutout mDisplayCutout;
@Nullable private final RoundedCorners mRoundedCorners;
/**
* In multi-window we force show the navigation bar. Because we don't want that the surface size
@@ -125,11 +126,12 @@ public final class WindowInsets {
* @hide
* @deprecated Use {@link WindowInsets(SparseArray, SparseArray, boolean, boolean, DisplayCutout)}
*/
public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect,
boolean isRound, boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
@Deprecated
public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect, boolean isRound,
boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
isRound, alwaysConsumeSystemBars, displayCutout, systemBars(),
isRound, alwaysConsumeSystemBars, displayCutout, null, systemBars(),
false /* compatIgnoreVisibility */);
}
@@ -150,7 +152,8 @@ public final class WindowInsets {
boolean[] typeVisibilityMap,
boolean isRound,
boolean alwaysConsumeSystemBars, DisplayCutout displayCutout,
@InsetsType int compatInsetsTypes, boolean compatIgnoreVisibility) {
RoundedCorners roundedCorners, @InsetsType int compatInsetsTypes,
boolean compatIgnoreVisibility) {
mSystemWindowInsetsConsumed = typeInsetsMap == null;
mTypeInsetsMap = mSystemWindowInsetsConsumed
? new Insets[SIZE]
@@ -170,6 +173,8 @@ public final class WindowInsets {
mDisplayCutoutConsumed = displayCutout == null;
mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
? null : displayCutout;
mRoundedCorners = roundedCorners;
}
/**
@@ -182,6 +187,7 @@ public final class WindowInsets {
src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
src.mTypeVisibilityMap, src.mIsRound,
src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
src.mRoundedCorners,
src.mCompatInsetsTypes,
src.mCompatIgnoreVisibility);
}
@@ -235,7 +241,7 @@ public final class WindowInsets {
@UnsupportedAppUsage
public WindowInsets(Rect systemWindowInsets) {
this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null,
systemBars(), false /* compatIgnoreVisibility */);
null, systemBars(), false /* compatIgnoreVisibility */);
}
/**
@@ -466,7 +472,7 @@ public final class WindowInsets {
public boolean hasInsets() {
return !getInsets(mTypeInsetsMap, all()).equals(Insets.NONE)
|| !getInsets(mTypeMaxInsetsMap, all()).equals(Insets.NONE)
|| mDisplayCutout != null;
|| mDisplayCutout != null || mRoundedCorners != null;
}
/**
@@ -486,6 +492,23 @@ public final class WindowInsets {
return mDisplayCutout;
}
/**
* Returns the {@link RoundedCorner} of the given position if there is one.
*
* @param position the position of the rounded corner on the display. The value should be one of
* the following:
* {@link RoundedCorner#POSITION_TOP_LEFT},
* {@link RoundedCorner#POSITION_TOP_RIGHT},
* {@link RoundedCorner#POSITION_BOTTOM_RIGHT},
* {@link RoundedCorner#POSITION_BOTTOM_LEFT}.
* @return the rounded corner of the given position. Returns {@code null} if there is none or
* the rounded corner area is not inside the application's bounds.
*/
@Nullable
public RoundedCorner getRoundedCorner(@RoundedCorner.Position int position) {
return mRoundedCorners == null ? null : mRoundedCorners.getRoundedCorner(position);
}
/**
* Returns a copy of this WindowInsets with the cutout fully consumed.
*
@@ -501,7 +524,7 @@ public final class WindowInsets {
mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
null /* displayCutout */,
null /* displayCutout */, mRoundedCorners,
mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -553,7 +576,7 @@ public final class WindowInsets {
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
displayCutoutCopyConstructorArgument(this),
mCompatInsetsTypes, mCompatIgnoreVisibility);
mRoundedCorners, mCompatInsetsTypes, mCompatIgnoreVisibility);
}
// TODO(b/119190588): replace @code with @link below
@@ -856,6 +879,8 @@ public final class WindowInsets {
result.append(mDisplayCutout != null ? "cutout=" + mDisplayCutout : "");
result.append("\n ");
result.append(mRoundedCorners != null ? "roundedCorners=" + mRoundedCorners : "");
result.append("\n ");
result.append(isRound() ? "round" : "");
result.append("}");
return result.toString();
@@ -947,6 +972,9 @@ public final class WindowInsets {
: mDisplayCutout == null
? DisplayCutout.NO_CUTOUT
: mDisplayCutout.inset(left, top, right, bottom),
mRoundedCorners == null
? RoundedCorners.NO_ROUNDED_CORNERS
: mRoundedCorners.inset(left, top, right, bottom),
mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -964,13 +992,14 @@ public final class WindowInsets {
&& Arrays.equals(mTypeInsetsMap, that.mTypeInsetsMap)
&& Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap)
&& Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
&& Objects.equals(mDisplayCutout, that.mDisplayCutout);
&& Objects.equals(mDisplayCutout, that.mDisplayCutout)
&& Objects.equals(mRoundedCorners, that.mRoundedCorners);
}
@Override
public int hashCode() {
return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout,
Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mRoundedCorners,
mAlwaysConsumeSystemBars, mSystemWindowInsetsConsumed, mStableInsetsConsumed,
mDisplayCutoutConsumed);
}
@@ -1032,6 +1061,7 @@ public final class WindowInsets {
private boolean mStableInsetsConsumed = true;
private DisplayCutout mDisplayCutout;
private RoundedCorners mRoundedCorners = RoundedCorners.NO_ROUNDED_CORNERS;
private boolean mIsRound;
private boolean mAlwaysConsumeSystemBars;
@@ -1057,6 +1087,7 @@ public final class WindowInsets {
mSystemInsetsConsumed = insets.mSystemWindowInsetsConsumed;
mStableInsetsConsumed = insets.mStableInsetsConsumed;
mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
mRoundedCorners = insets.mRoundedCorners;
mIsRound = insets.mIsRound;
mAlwaysConsumeSystemBars = insets.mAlwaysConsumeSystemBars;
}
@@ -1260,6 +1291,29 @@ public final class WindowInsets {
return this;
}
/** @hide */
@NonNull
public Builder setRoundedCorners(RoundedCorners roundedCorners) {
mRoundedCorners = roundedCorners != null
? roundedCorners : RoundedCorners.NO_ROUNDED_CORNERS;
return this;
}
/**
* Sets the rounded corner of given position.
*
* @see #getRoundedCorner(int)
* @param position the position of this rounded corner
* @param roundedCorner the rounded corner or null if there is none
* @return itself
*/
@NonNull
public Builder setRoundedCorner(@RoundedCorner.Position int position,
@Nullable RoundedCorner roundedCorner) {
mRoundedCorners.setRoundedCorner(position, roundedCorner);
return this;
}
/** @hide */
@NonNull
public Builder setRound(boolean round) {
@@ -1283,7 +1337,7 @@ public final class WindowInsets {
public WindowInsets build() {
return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout,
mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout, mRoundedCorners,
systemBars(), false /* compatIgnoreVisibility */);
}
}

View File

@@ -27,6 +27,10 @@ import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
import static android.view.RoundedCorner.POSITION_TOP_LEFT;
import static android.view.RoundedCorner.POSITION_TOP_RIGHT;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.navigationBars;
@@ -427,6 +431,27 @@ public class InsetsStateTest {
cutout.getBoundingRectBottom());
}
@Test
public void testCalculateRelativeRoundedCorners() {
mState.setDisplayFrame(new Rect(0, 0, 200, 400));
mState.setRoundedCorners(new RoundedCorners(
new RoundedCorner(POSITION_TOP_LEFT, 10, 10, 10),
new RoundedCorner(POSITION_TOP_RIGHT, 10, 190, 10),
new RoundedCorner(POSITION_BOTTOM_RIGHT, 20, 180, 380),
new RoundedCorner(POSITION_BOTTOM_LEFT, 20, 20, 380)));
WindowInsets windowInsets = mState.calculateInsets(new Rect(1, 2, 197, 396), null, false,
false, SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
WINDOWING_MODE_UNDEFINED, new SparseIntArray());
assertEquals(new RoundedCorner(POSITION_TOP_LEFT, 10, 9, 8),
windowInsets.getRoundedCorner(POSITION_TOP_LEFT));
assertEquals(new RoundedCorner(POSITION_TOP_RIGHT, 10, 189, 8),
windowInsets.getRoundedCorner(POSITION_TOP_RIGHT));
assertEquals(new RoundedCorner(POSITION_BOTTOM_RIGHT, 20, 179, 378),
windowInsets.getRoundedCorner(POSITION_BOTTOM_RIGHT));
assertEquals(new RoundedCorner(POSITION_BOTTOM_LEFT, 20, 19, 378),
windowInsets.getRoundedCorner(POSITION_BOTTOM_LEFT));
}
private void assertEqualsAndHashCode() {
assertEquals(mState, mState2);
assertEquals(mState.hashCode(), mState2.hashCode());

View File

@@ -0,0 +1,72 @@
/*
* 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.view;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import android.graphics.Point;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
public class RoundedCornerTest {
@Test
public void testGetPosition() {
RoundedCorner roundedCorner = new RoundedCorner(
RoundedCorner.POSITION_BOTTOM_LEFT, 2, 3, 4);
assertThat(roundedCorner.getPosition(), is(RoundedCorner.POSITION_BOTTOM_LEFT));
}
@Test
public void testGetRadius() {
RoundedCorner roundedCorner = new RoundedCorner(
RoundedCorner.POSITION_BOTTOM_LEFT, 2, 3, 4);
assertThat(roundedCorner.getRadius(), is(2));
}
@Test
public void testGetCenter() {
RoundedCorner roundedCorner = new RoundedCorner(
RoundedCorner.POSITION_BOTTOM_LEFT, 2, 3, 4);
assertThat(roundedCorner.getCenter(), equalTo(new Point(3, 4)));
}
@Test
public void testIsEmpty() {
RoundedCorner roundedCorner = new RoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
assertThat(roundedCorner.isEmpty(), is(true));
}
@Test
public void testEquals() {
RoundedCorner roundedCorner = new RoundedCorner(
RoundedCorner.POSITION_BOTTOM_LEFT, 2, 3, 4);
RoundedCorner roundedCorner2 = new RoundedCorner(
RoundedCorner.POSITION_BOTTOM_LEFT, 2, 3, 4);
assertThat(roundedCorner, equalTo(roundedCorner2));
}
}

View File

@@ -0,0 +1,202 @@
/*
* 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.view;
import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
import static android.view.RoundedCorner.POSITION_TOP_LEFT;
import static android.view.RoundedCorner.POSITION_TOP_RIGHT;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
public class RoundedCornersTest {
final RoundedCorners mRoundedCorners = new RoundedCorners(
new RoundedCorner(POSITION_TOP_LEFT, 10, 10, 10),
new RoundedCorner(POSITION_TOP_RIGHT, 10, 190, 10),
new RoundedCorner(POSITION_BOTTOM_RIGHT, 20, 180, 380),
new RoundedCorner(POSITION_BOTTOM_LEFT, 20, 20, 380));
@Test
public void testGetRoundedCorner() {
final Pair<Integer, Integer> radius = new Pair<>(10, 20);
RoundedCorners roundedCorners = RoundedCorners.fromRadii(radius, 200, 400);
assertThat(roundedCorners.getRoundedCorner(POSITION_TOP_LEFT),
equalTo(new RoundedCorner(POSITION_TOP_LEFT, 10, 10, 10)));
assertThat(roundedCorners.getRoundedCorner(POSITION_TOP_RIGHT),
equalTo(new RoundedCorner(POSITION_TOP_RIGHT, 10, 190, 10)));
assertThat(roundedCorners.getRoundedCorner(POSITION_BOTTOM_RIGHT),
equalTo(new RoundedCorner(POSITION_BOTTOM_RIGHT, 20, 180, 380)));
assertThat(roundedCorners.getRoundedCorner(POSITION_BOTTOM_LEFT),
equalTo(new RoundedCorner(POSITION_BOTTOM_LEFT, 20, 20, 380)));
}
@Test
public void testGetRoundedCorner_noRoundedCorners() {
RoundedCorners roundedCorners = RoundedCorners.NO_ROUNDED_CORNERS;
assertThat(roundedCorners.getRoundedCorner(POSITION_TOP_LEFT), nullValue());
assertThat(roundedCorners.getRoundedCorner(POSITION_TOP_RIGHT), nullValue());
assertThat(roundedCorners.getRoundedCorner(POSITION_BOTTOM_RIGHT), nullValue());
assertThat(roundedCorners.getRoundedCorner(POSITION_BOTTOM_LEFT), nullValue());
}
@Test
public void testHashCode() {
assertThat(mRoundedCorners.hashCode(),
equalTo(RoundedCorners.fromRadii(new Pair<>(10, 20), 200, 400).hashCode()));
assertThat(mRoundedCorners.hashCode(),
not(equalTo(RoundedCorners.fromRadii(new Pair<>(5, 10), 200, 400).hashCode())));
}
@Test
public void testEquals() {
assertThat(mRoundedCorners,
equalTo(RoundedCorners.fromRadii(new Pair<>(10, 20), 200, 400)));
assertThat(mRoundedCorners,
not(equalTo(RoundedCorners.fromRadii(new Pair<>(5, 10), 200, 400))));
}
@Test
public void testSetRoundedCorner() {
RoundedCorner roundedCorner = new RoundedCorner(POSITION_BOTTOM_LEFT, 5, 6, 7);
mRoundedCorners.setRoundedCorner(POSITION_BOTTOM_LEFT, roundedCorner);
assertThat(mRoundedCorners.getRoundedCorner(POSITION_BOTTOM_LEFT), equalTo(roundedCorner));
}
@Test
public void testSetRoundedCorner_null() {
mRoundedCorners.setRoundedCorner(POSITION_BOTTOM_LEFT, null);
assertThat(mRoundedCorners.mRoundedCorners[POSITION_BOTTOM_LEFT],
equalTo(new RoundedCorner(POSITION_BOTTOM_LEFT)));
assertThat(mRoundedCorners.getRoundedCorner(POSITION_BOTTOM_LEFT), nullValue());
}
@Test
public void testInsetRoundedCorners_partialOverlap() {
RoundedCorners roundedCorners = mRoundedCorners.inset(1, 2, 3, 4);
assertThat(roundedCorners.mRoundedCorners[POSITION_TOP_LEFT],
equalTo(new RoundedCorner(POSITION_TOP_LEFT, 10, 9, 8)));
assertThat(roundedCorners.mRoundedCorners[POSITION_TOP_RIGHT],
equalTo(new RoundedCorner(POSITION_TOP_RIGHT, 10, 189, 8)));
assertThat(roundedCorners.mRoundedCorners[POSITION_BOTTOM_RIGHT],
equalTo(new RoundedCorner(POSITION_BOTTOM_RIGHT, 20, 179, 378)));
assertThat(roundedCorners.mRoundedCorners[POSITION_BOTTOM_LEFT],
equalTo(new RoundedCorner(POSITION_BOTTOM_LEFT, 20, 19, 378)));
}
@Test
public void testInsetRoundedCorners_noOverlap() {
RoundedCorners roundedCorners = mRoundedCorners.inset(20, 20, 20, 20);
assertThat(roundedCorners.mRoundedCorners[POSITION_TOP_LEFT].isEmpty(), is(true));
assertThat(roundedCorners.mRoundedCorners[POSITION_TOP_RIGHT].isEmpty(), is(true));
assertThat(roundedCorners.mRoundedCorners[POSITION_BOTTOM_RIGHT].isEmpty(), is(true));
assertThat(roundedCorners.mRoundedCorners[POSITION_BOTTOM_LEFT].isEmpty(), is(true));
}
@Test
public void testRotateRoundedCorners_90() {
final Pair<Integer, Integer> radius = new Pair<>(10, 20);
RoundedCorners roundedCorners = RoundedCorners.fromRadii(radius, 200, 400)
.rotate(ROTATION_90, 200, 400);
assertThat(roundedCorners.getRoundedCorner(POSITION_TOP_LEFT),
equalTo(new RoundedCorner(POSITION_TOP_LEFT, 10, 10, 10)));
assertThat(roundedCorners.getRoundedCorner(POSITION_TOP_RIGHT),
equalTo(new RoundedCorner(POSITION_TOP_RIGHT, 20, 380, 20)));
assertThat(roundedCorners.getRoundedCorner(POSITION_BOTTOM_RIGHT),
equalTo(new RoundedCorner(POSITION_BOTTOM_RIGHT, 20, 380, 180)));
assertThat(roundedCorners.getRoundedCorner(POSITION_BOTTOM_LEFT),
equalTo(new RoundedCorner(POSITION_BOTTOM_LEFT, 10, 10, 190)));
}
@Test
public void testRotateRoundedCorners_270() {
final Pair<Integer, Integer> radius = new Pair<>(10, 20);
RoundedCorners roundedCorners = RoundedCorners.fromRadii(radius, 200, 400)
.rotate(ROTATION_270, 200, 400);
assertThat(roundedCorners.getRoundedCorner(POSITION_TOP_LEFT),
equalTo(new RoundedCorner(POSITION_TOP_LEFT, 20, 20, 20)));
assertThat(roundedCorners.getRoundedCorner(POSITION_TOP_RIGHT),
equalTo(new RoundedCorner(POSITION_TOP_RIGHT, 10, 390, 10)));
assertThat(roundedCorners.getRoundedCorner(POSITION_BOTTOM_RIGHT),
equalTo(new RoundedCorner(POSITION_BOTTOM_RIGHT, 10, 390, 190)));
assertThat(roundedCorners.getRoundedCorner(POSITION_BOTTOM_LEFT),
equalTo(new RoundedCorner(POSITION_BOTTOM_LEFT, 20, 20, 180)));
}
@Test
public void testFromRadius_cache() {
final Pair<Integer, Integer> radius = new Pair<>(10, 20);
RoundedCorners cached = RoundedCorners.fromRadii(radius, 200, 400);
assertThat(RoundedCorners.fromRadii(radius, 200, 400), sameInstance(cached));
}
@Test
public void testFromRadius_wontCacheIfRadiusChanged() {
final Pair<Integer, Integer> radius = new Pair<>(10, 20);
RoundedCorners cached = RoundedCorners.fromRadii(radius, 200, 400);
assertThat(RoundedCorners.fromRadii(new Pair<>(5, 10), 200, 400),
not(sameInstance(cached)));
}
@Test
public void testFromRadius_wontCacheIfDisplayWidthChanged() {
final Pair<Integer, Integer> radius = new Pair<>(10, 20);
RoundedCorners cached = RoundedCorners.fromRadii(radius, 200, 400);
assertThat(RoundedCorners.fromRadii(radius, 100, 400),
not(sameInstance(cached)));
}
@Test
public void testFromRadius_wontCacheIfDisplayHeightChanged() {
final Pair<Integer, Integer> radius = new Pair<>(10, 20);
RoundedCorners cached = RoundedCorners.fromRadii(radius, 200, 400);
assertThat(RoundedCorners.fromRadii(radius, 200, 300),
not(sameInstance(cached)));
}
}

View File

@@ -61,7 +61,7 @@ public class WindowInsetsTest {
WindowInsets.assignCompatInsets(maxInsets, new Rect(0, 10, 0, 0));
WindowInsets.assignCompatInsets(insets, new Rect(0, 0, 0, 0));
WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, false, null,
systemBars(), true /* compatIgnoreVisibility */);
null, systemBars(), true /* compatIgnoreVisibility */);
assertEquals(Insets.of(0, 10, 0, 0), windowInsets.getSystemWindowInsets());
}
}

View File

@@ -23,6 +23,7 @@ import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
import android.view.RoundedCorners;
import android.view.Surface;
import com.android.internal.BrightnessSynchronizer;
@@ -280,6 +281,11 @@ final class DisplayDeviceInfo {
*/
public DisplayCutout displayCutout;
/**
* The {@link RoundedCorners} if present or {@code null} otherwise.
*/
public RoundedCorners roundedCorners;
/**
* The touch attachment, per {@link DisplayViewport#touch}.
*/
@@ -401,7 +407,8 @@ final class DisplayDeviceInfo {
|| !BrightnessSynchronizer.floatEquals(brightnessMinimum, other.brightnessMinimum)
|| !BrightnessSynchronizer.floatEquals(brightnessMaximum, other.brightnessMaximum)
|| !BrightnessSynchronizer.floatEquals(brightnessDefault,
other.brightnessDefault)) {
other.brightnessDefault)
|| !Objects.equals(roundedCorners, other.roundedCorners)) {
diff |= DIFF_OTHER;
}
return diff;
@@ -444,6 +451,7 @@ final class DisplayDeviceInfo {
brightnessMinimum = other.brightnessMinimum;
brightnessMaximum = other.brightnessMaximum;
brightnessDefault = other.brightnessDefault;
roundedCorners = other.roundedCorners;
}
// For debugging purposes
@@ -487,6 +495,9 @@ final class DisplayDeviceInfo {
sb.append(", brightnessMinimum ").append(brightnessMinimum);
sb.append(", brightnessMaximum ").append(brightnessMaximum);
sb.append(", brightnessDefault ").append(brightnessDefault);
if (roundedCorners != null) {
sb.append(", roundedCorners ").append(roundedCorners);
}
sb.append(flagsToString(flags));
sb.append("}");
return sb.toString();

View File

@@ -35,6 +35,7 @@ import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
import android.view.RoundedCorners;
import android.view.SurfaceControl;
import com.android.internal.BrightnessSynchronizer;
@@ -604,6 +605,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
mInfo.width, mInfo.height);
mInfo.roundedCorners = RoundedCorners.fromResources(
res, mInfo.width, mInfo.height);
} else {
if (!res.getBoolean(
com.android.internal.R.bool.config_localDisplaysMirrorContent)) {

View File

@@ -195,6 +195,7 @@ final class LogicalDisplay {
info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
info.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
info.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
info.roundedCorners = mOverrideDisplayInfo.roundedCorners;
}
mInfo.set(info);
}
@@ -386,6 +387,7 @@ final class LogicalDisplay {
mBaseDisplayInfo.brightnessMinimum = deviceInfo.brightnessMinimum;
mBaseDisplayInfo.brightnessMaximum = deviceInfo.brightnessMaximum;
mBaseDisplayInfo.brightnessDefault = deviceInfo.brightnessDefault;
mBaseDisplayInfo.roundedCorners = deviceInfo.roundedCorners;
mPrimaryDisplayDeviceInfo = deviceInfo;
mInfo.set(null);
}

View File

@@ -204,6 +204,7 @@ import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.MagnificationSpec;
import android.view.RemoteAnimationDefinition;
import android.view.RoundedCorners;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
@@ -337,6 +338,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
= new RotationCache<>(this::calculateDisplayCutoutForRotationUncached);
boolean mIgnoreDisplayCutout;
RoundedCorners mInitialRoundedCorners;
private final RotationCache<RoundedCorners, RoundedCorners> mRoundedCornerCache =
new RotationCache<>(this::calculateRoundedCornersForRotationUncached);
/**
* Overridden display size. Initialized with {@link #mInitialDisplayWidth}
* and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
@@ -983,7 +988,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
mInsetsStateController = new InsetsStateController(this);
mDisplayFrames = new DisplayFrames(mDisplayId, mInsetsStateController.getRawInsetsState(),
mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
calculateRoundedCornersForRotation(mDisplayInfo.rotation));
initializeDisplayBaseInfo();
mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
@@ -1696,8 +1702,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mTmpConfiguration.unset();
final DisplayInfo info = computeScreenConfiguration(mTmpConfiguration, rotation);
final WmDisplayCutout cutout = calculateDisplayCutoutForRotation(rotation);
final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
final DisplayFrames displayFrames = new DisplayFrames(mDisplayId, new InsetsState(), info,
cutout);
cutout, roundedCorners);
token.applyFixedRotationTransform(info, displayFrames, mTmpConfiguration);
}
@@ -1958,6 +1965,23 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
rotated ? mInitialDisplayWidth : mInitialDisplayHeight);
}
RoundedCorners calculateRoundedCornersForRotation(int rotation) {
return mRoundedCornerCache.getOrCompute(mInitialRoundedCorners, rotation);
}
private RoundedCorners calculateRoundedCornersForRotationUncached(
RoundedCorners roundedCorners, int rotation) {
if (roundedCorners == null || roundedCorners == RoundedCorners.NO_ROUNDED_CORNERS) {
return RoundedCorners.NO_ROUNDED_CORNERS;
}
if (rotation == ROTATION_0) {
return roundedCorners;
}
return roundedCorners.rotate(rotation, mInitialDisplayWidth, mInitialDisplayHeight);
}
/**
* Compute display info and configuration according to the given rotation without changing
* current display.
@@ -2485,7 +2509,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void onDisplayInfoChanged() {
final DisplayInfo info = mDisplayInfo;
mDisplayFrames.onDisplayInfoUpdated(info, calculateDisplayCutoutForRotation(info.rotation));
mDisplayFrames.onDisplayInfoUpdated(info, calculateDisplayCutoutForRotation(info.rotation),
calculateRoundedCornersForRotation(info.rotation));
mInputMonitor.layoutInputConsumers(info.logicalWidth, info.logicalHeight);
mDisplayPolicy.onDisplayInfoChanged(info);
}
@@ -2518,6 +2543,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mInitialDisplayHeight = mDisplayInfo.logicalHeight;
mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
mInitialDisplayCutout = mDisplayInfo.displayCutout;
mInitialRoundedCorners = mDisplayInfo.roundedCorners;
}
/**
@@ -2535,11 +2561,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final DisplayCutout newCutout = mIgnoreDisplayCutout
? DisplayCutout.NO_CUTOUT : mDisplayInfo.displayCutout;
final String newUniqueId = mDisplayInfo.uniqueId;
final RoundedCorners newRoundedCorners = mDisplayInfo.roundedCorners;
final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
|| mInitialDisplayHeight != newHeight
|| mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi
|| !Objects.equals(mInitialDisplayCutout, newCutout);
|| !Objects.equals(mInitialDisplayCutout, newCutout)
|| !Objects.equals(mInitialRoundedCorners, newRoundedCorners);
final boolean physicalDisplayChanged = !newUniqueId.equals(mCurrentUniqueDisplayId);
if (displayMetricsChanged || physicalDisplayChanged) {
@@ -2558,6 +2586,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mInitialDisplayHeight = newHeight;
mInitialDisplayDensity = newDensity;
mInitialDisplayCutout = newCutout;
mInitialRoundedCorners = newRoundedCorners;
mCurrentUniqueDisplayId = newUniqueId;
reconfigureDisplayLocked();
}

View File

@@ -21,12 +21,12 @@ import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
import android.annotation.NonNull;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.InsetsState;
import android.view.RoundedCorners;
import com.android.server.wm.utils.WmDisplayCutout;
@@ -47,9 +47,6 @@ public class DisplayFrames {
*/
public final Rect mUnrestricted = new Rect();
/** The display cutout used for layout (after rotation) */
@NonNull public WmDisplayCutout mDisplayCutout = WmDisplayCutout.NO_CUTOUT;
/**
* During layout, the frame that is display-cutout safe, i.e. that does not intersect with it.
*/
@@ -61,26 +58,37 @@ public class DisplayFrames {
public int mRotation;
public DisplayFrames(int displayId, InsetsState insetsState, DisplayInfo info,
WmDisplayCutout displayCutout) {
WmDisplayCutout displayCutout, RoundedCorners roundedCorners) {
mDisplayId = displayId;
mInsetsState = insetsState;
onDisplayInfoUpdated(info, displayCutout);
onDisplayInfoUpdated(info, displayCutout, roundedCorners);
}
public void onDisplayInfoUpdated(DisplayInfo info, WmDisplayCutout displayCutout) {
/**
* Update {@link DisplayFrames} when {@link DisplayInfo} is updated.
*
* @param info the updated {@link DisplayInfo}.
* @param displayCutout the updated {@link DisplayCutout}.
* @param roundedCorners the updated {@link RoundedCorners}.
*/
public void onDisplayInfoUpdated(DisplayInfo info, WmDisplayCutout displayCutout,
RoundedCorners roundedCorners) {
mDisplayWidth = info.logicalWidth;
mDisplayHeight = info.logicalHeight;
mRotation = info.rotation;
mDisplayCutout = displayCutout != null ? displayCutout : WmDisplayCutout.NO_CUTOUT;
final WmDisplayCutout wmDisplayCutout =
displayCutout != null ? displayCutout : WmDisplayCutout.NO_CUTOUT;
final InsetsState state = mInsetsState;
final Rect unrestricted = mUnrestricted;
final Rect safe = mDisplayCutoutSafe;
final DisplayCutout cutout = mDisplayCutout.getDisplayCutout();
final DisplayCutout cutout = wmDisplayCutout.getDisplayCutout();
unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
safe.set(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
state.setDisplayFrame(unrestricted);
state.setDisplayCutout(cutout);
state.setRoundedCorners(roundedCorners != null ? roundedCorners
: RoundedCorners.NO_ROUNDED_CORNERS);
if (!cutout.isEmpty()) {
if (cutout.getSafeInsetLeft() > 0) {
safe.left = unrestricted.left + cutout.getSafeInsetLeft();
@@ -118,12 +126,5 @@ public class DisplayFrames {
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "DisplayFrames w=" + mDisplayWidth + " h=" + mDisplayHeight
+ " r=" + mRotation);
final String myPrefix = prefix + " ";
dumpFrame(mUnrestricted, "mUnrestricted", myPrefix, pw);
pw.println(myPrefix + "mDisplayCutout=" + mDisplayCutout);
}
private void dumpFrame(Rect frame, String name, String prefix, PrintWriter pw) {
pw.print(prefix + name + "="); frame.printShortString(pw); pw.println();
}
}

View File

@@ -66,6 +66,7 @@ import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsState;
import android.view.RoundedCorners;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
import android.view.WindowManager;
@@ -99,6 +100,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
private int mRotation = ROTATION_0;
private boolean mHasDisplayCutout;
private boolean mIsLongEdgeDisplayCutout;
private boolean mHasRoundedCorners;
private final Rect mDisplayBounds = new Rect();
@@ -153,6 +155,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
updateDisplayFrames();
}
public void addRoundedCorners() {
mHasRoundedCorners = true;
updateDisplayFrames();
}
private void updateDisplayFrames() {
mFrames = createDisplayFrames(
mDisplayContent.getInsetsStateController().getRawInsetsState());
@@ -166,9 +173,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
private DisplayFrames createDisplayFrames(InsetsState insetsState) {
final Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation,
mHasDisplayCutout, mIsLongEdgeDisplayCutout);
final RoundedCorners roundedCorners = mHasRoundedCorners
? mDisplayContent.calculateRoundedCornersForRotation(mRotation)
: RoundedCorners.NO_ROUNDED_CORNERS;
return new DisplayFrames(mDisplayContent.getDisplayId(),
insetsState,
info.first, info.second);
insetsState, info.first, info.second, roundedCorners);
}
@Test
@@ -753,6 +762,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
assertSimulateLayoutSameDisplayFrames();
addDisplayCutout();
assertSimulateLayoutSameDisplayFrames();
addRoundedCorners();
assertSimulateLayoutSameDisplayFrames();
}
private void assertSimulateLayoutSameDisplayFrames() {

View File

@@ -302,7 +302,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
mImeWindow.mAboveInsetsState = state;
mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(),
state, displayInfo, null /* displayCutout */);
state, displayInfo, null /* displayCutout */, null /* roundedCorners*/);
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);

View File

@@ -47,6 +47,7 @@ import android.platform.test.annotations.Presubmit;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsState;
import android.view.RoundedCorners;
import android.view.Surface;
import android.view.WindowManager;
@@ -146,7 +147,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
final DisplayInfo info = dc.computeScreenConfiguration(config, Surface.ROTATION_0);
final WmDisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
final DisplayFrames displayFrames = new DisplayFrames(dc.getDisplayId(), new InsetsState(),
info, cutout);
info, cutout, RoundedCorners.NO_ROUNDED_CORNERS);
wallpaperWindowToken.applyFixedRotationTransform(info, displayFrames, config);
// Check that the wallpaper has the same frame in landscape than in portrait