summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/DisplayCutout.java48
-rw-r--r--core/java/android/view/DisplayInfo.java11
-rw-r--r--core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/RoundedCorners.java1
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java11
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java14
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java26
-rw-r--r--services/core/java/com/android/server/wm/DisplayFrames.java43
-rw-r--r--services/core/java/com/android/server/wm/utils/CoordinateTransforms.java62
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java45
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java98
14 files changed, 348 insertions, 27 deletions
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 3dcfd00bc34c..1ef5f0950b16 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -153,7 +153,7 @@ public final class DisplayCutout {
@Override
public String toString() {
return "DisplayCutout{insets=" + mSafeInsets
- + " bounds=" + mBounds
+ + " boundingRect=" + getBoundingRect()
+ "}";
}
@@ -279,9 +279,7 @@ public final class DisplayCutout {
* @hide
*/
public static DisplayCutout fromBoundingPolygon(List<Point> points) {
- Region bounds = Region.obtain();
Path path = new Path();
-
path.reset();
for (int i = 0; i < points.size(); i++) {
Point point = points.get(i);
@@ -292,14 +290,24 @@ public final class DisplayCutout {
}
}
path.close();
+ return fromBounds(path);
+ }
+ /**
+ * Creates an instance from a bounding {@link Path}.
+ *
+ * @hide
+ */
+ public static DisplayCutout fromBounds(Path path) {
RectF clipRect = new RectF();
path.computeBounds(clipRect, false /* unused */);
Region clipRegion = Region.obtain();
clipRegion.set((int) clipRect.left, (int) clipRect.top,
(int) clipRect.right, (int) clipRect.bottom);
+ Region bounds = new Region();
bounds.setPath(path, clipRegion);
+ clipRegion.recycle();
return new DisplayCutout(ZERO_RECT, bounds);
}
@@ -329,12 +337,23 @@ public final class DisplayCutout {
@Override
public void writeToParcel(Parcel out, int flags) {
- if (mInner == NO_CUTOUT) {
+ writeCutoutToParcel(mInner, out, flags);
+ }
+
+ /**
+ * Writes a DisplayCutout to a {@link Parcel}.
+ *
+ * @see #readCutoutFromParcel(Parcel)
+ */
+ public static void writeCutoutToParcel(DisplayCutout cutout, Parcel out, int flags) {
+ if (cutout == null) {
+ out.writeInt(-1);
+ } else if (cutout == NO_CUTOUT) {
out.writeInt(0);
} else {
out.writeInt(1);
- out.writeTypedObject(mInner.mSafeInsets, flags);
- out.writeTypedObject(mInner.mBounds, flags);
+ out.writeTypedObject(cutout.mSafeInsets, flags);
+ out.writeTypedObject(cutout.mBounds, flags);
}
}
@@ -345,13 +364,13 @@ public final class DisplayCutout {
* Needed for AIDL out parameters.
*/
public void readFromParcel(Parcel in) {
- mInner = readCutout(in);
+ mInner = readCutoutFromParcel(in);
}
public static final Creator<ParcelableWrapper> CREATOR = new Creator<ParcelableWrapper>() {
@Override
public ParcelableWrapper createFromParcel(Parcel in) {
- return new ParcelableWrapper(readCutout(in));
+ return new ParcelableWrapper(readCutoutFromParcel(in));
}
@Override
@@ -360,8 +379,17 @@ public final class DisplayCutout {
}
};
- private static DisplayCutout readCutout(Parcel in) {
- if (in.readInt() == 0) {
+ /**
+ * Reads a DisplayCutout from a {@link Parcel}.
+ *
+ * @see #writeCutoutToParcel(DisplayCutout, Parcel, int)
+ */
+ public static DisplayCutout readCutoutFromParcel(Parcel in) {
+ int variant = in.readInt();
+ if (variant == -1) {
+ return null;
+ }
+ if (variant == 0) {
return NO_CUTOUT;
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index b813ddb63859..37e9815c93c5 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -149,6 +149,13 @@ public final class DisplayInfo implements Parcelable {
public int overscanBottom;
/**
+ * The {@link DisplayCutout} if present, otherwise {@code null}.
+ *
+ * @hide
+ */
+ public DisplayCutout displayCutout;
+
+ /**
* The rotation of the display relative to its natural orientation.
* May be one of {@link android.view.Surface#ROTATION_0},
* {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
@@ -301,6 +308,7 @@ public final class DisplayInfo implements Parcelable {
&& overscanTop == other.overscanTop
&& overscanRight == other.overscanRight
&& overscanBottom == other.overscanBottom
+ && Objects.equal(displayCutout, other.displayCutout)
&& rotation == other.rotation
&& modeId == other.modeId
&& defaultModeId == other.defaultModeId
@@ -342,6 +350,7 @@ public final class DisplayInfo implements Parcelable {
overscanTop = other.overscanTop;
overscanRight = other.overscanRight;
overscanBottom = other.overscanBottom;
+ displayCutout = other.displayCutout;
rotation = other.rotation;
modeId = other.modeId;
defaultModeId = other.defaultModeId;
@@ -379,6 +388,7 @@ public final class DisplayInfo implements Parcelable {
overscanTop = source.readInt();
overscanRight = source.readInt();
overscanBottom = source.readInt();
+ displayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(source);
rotation = source.readInt();
modeId = source.readInt();
defaultModeId = source.readInt();
@@ -425,6 +435,7 @@ public final class DisplayInfo implements Parcelable {
dest.writeInt(overscanTop);
dest.writeInt(overscanRight);
dest.writeInt(overscanBottom);
+ DisplayCutout.ParcelableWrapper.writeCutoutToParcel(displayCutout, dest, flags);
dest.writeInt(rotation);
dest.writeInt(modeId);
dest.writeInt(defaultModeId);
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d2685cfb5a8f..2440e9b43116 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2769,6 +2769,13 @@
some existing device-specific resource overlays. -->
<bool name="config_mainBuiltInDisplayIsRound">@bool/config_windowIsRound</bool>
+ <!-- The bounding path of the cutout region of the main built-in display.
+ Must either be empty if there is no cutout region, or a string that is parsable by
+ {@link android.util.PathParser}.
+ The path is assumed to be specified in display coordinates with pixel units and in
+ the display's native orientation. -->
+ <string translatable="false" name="config_mainBuiltInDisplayCutout"></string>
+
<!-- Ultrasound support for Mic/speaker path -->
<!-- Whether the default microphone audio source supports near-ultrasound frequencies
(range of 18 - 21 kHz). -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d2ad99b4b744..ac3d4020a3b0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3200,6 +3200,7 @@
<java-symbol type="string" name="battery_saver_warning_title" />
<java-symbol type="string" name="global_action_logout" />
+ <java-symbol type="string" name="config_mainBuiltInDisplayCutout" />
<java-symbol type="drawable" name="ic_logout" />
<java-symbol type="array" name="config_autoBrightnessDisplayValuesNits" />
diff --git a/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java b/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java
index 6aa465ce9f8c..a1022604c27f 100644
--- a/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java
+++ b/packages/SystemUI/src/com/android/systemui/EmulatedDisplayCutout.java
@@ -24,6 +24,7 @@ import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Point;
+import android.graphics.PorterDuff;
import android.graphics.Region;
import android.os.Handler;
import android.os.Looper;
@@ -114,10 +115,9 @@ public class EmulatedDisplayCutout extends SystemUI {
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ mBounds.reset();
if (insets.getDisplayCutout() != null) {
insets.getDisplayCutout().getBounds().getBoundaryPath(mBounds);
- } else {
- mBounds.reset();
}
invalidate();
return insets.consumeDisplayCutout();
@@ -126,7 +126,7 @@ public class EmulatedDisplayCutout extends SystemUI {
@Override
protected void onDraw(Canvas canvas) {
if (!mBounds.isEmpty()) {
- mPaint.setColor(Color.DKGRAY);
+ mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawPath(mBounds, mPaint);
diff --git a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
index b15b79fb984e..6f7a270799bc 100644
--- a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
+++ b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
@@ -163,6 +163,7 @@ public class RoundedCorners extends SystemUI implements Tunable {
| WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
lp.setTitle("RoundedOverlay");
lp.gravity = Gravity.TOP;
+ lp.flags2 |= WindowManager.LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA;
return lp;
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index fddb81ba2af7..6db3b44c17b2 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import android.hardware.display.DisplayViewport;
import android.util.DisplayMetrics;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.Surface;
import java.util.Arrays;
@@ -229,6 +230,11 @@ final class DisplayDeviceInfo {
public int flags;
/**
+ * The {@link DisplayCutout} if present or {@code null} otherwise.
+ */
+ public DisplayCutout displayCutout;
+
+ /**
* The touch attachment, per {@link DisplayViewport#touch}.
*/
public int touch;
@@ -321,6 +327,7 @@ final class DisplayDeviceInfo {
|| appVsyncOffsetNanos != other.appVsyncOffsetNanos
|| presentationDeadlineNanos != other.presentationDeadlineNanos
|| flags != other.flags
+ || !Objects.equal(displayCutout, other.displayCutout)
|| touch != other.touch
|| rotation != other.rotation
|| type != other.type
@@ -354,6 +361,7 @@ final class DisplayDeviceInfo {
appVsyncOffsetNanos = other.appVsyncOffsetNanos;
presentationDeadlineNanos = other.presentationDeadlineNanos;
flags = other.flags;
+ displayCutout = other.displayCutout;
touch = other.touch;
rotation = other.rotation;
type = other.type;
@@ -380,6 +388,9 @@ final class DisplayDeviceInfo {
sb.append(", ").append(xDpi).append(" x ").append(yDpi).append(" dpi");
sb.append(", appVsyncOff ").append(appVsyncOffsetNanos);
sb.append(", presDeadline ").append(presentationDeadlineNanos);
+ if (displayCutout != null) {
+ sb.append(", cutout ").append(displayCutout);
+ }
sb.append(", touch ").append(touchToString(touch));
sb.append(", rotation ").append(rotation);
sb.append(", type ").append(Display.typeToString(type));
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index eb9ff589d5f6..483b02c2bf65 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -30,9 +30,12 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemProperties;
import android.os.Trace;
+import android.text.TextUtils;
+import android.util.PathParser;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -400,12 +403,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
&& SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
}
+ mInfo.displayCutout = parseDefaultDisplayCutout(res);
mInfo.type = Display.TYPE_BUILT_IN;
mInfo.densityDpi = (int)(phys.density * 160 + 0.5f);
mInfo.xDpi = phys.xDpi;
mInfo.yDpi = phys.yDpi;
mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
} else {
+ mInfo.displayCutout = null;
mInfo.type = Display.TYPE_HDMI;
mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
mInfo.name = getContext().getResources().getString(
@@ -434,6 +439,15 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return mInfo;
}
+ private DisplayCutout parseDefaultDisplayCutout(Resources res) {
+ String cutoutString = res.getString(
+ com.android.internal.R.string.config_mainBuiltInDisplayCutout);
+ if (TextUtils.isEmpty(cutoutString)) {
+ return null;
+ }
+ return DisplayCutout.fromBounds(PathParser.createPathFromPathData(cutoutString));
+ }
+
@Override
public Runnable requestDisplayStateLocked(final int state, final int brightness) {
// Assume that the brightness is off if the display is being turned off.
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 78a540790db6..132f083c1adc 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -145,6 +145,7 @@ final class LogicalDisplay {
mInfo.overscanRight = mOverrideDisplayInfo.overscanRight;
mInfo.overscanBottom = mOverrideDisplayInfo.overscanBottom;
mInfo.rotation = mOverrideDisplayInfo.rotation;
+ mInfo.displayCutout = mOverrideDisplayInfo.displayCutout;
mInfo.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
mInfo.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
mInfo.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
@@ -280,6 +281,7 @@ final class LogicalDisplay {
mBaseDisplayInfo.largestNominalAppHeight = deviceInfo.height;
mBaseDisplayInfo.ownerUid = deviceInfo.ownerUid;
mBaseDisplayInfo.ownerPackageName = deviceInfo.ownerPackageName;
+ mBaseDisplayInfo.displayCutout = deviceInfo.displayCutout;
mPrimaryDisplayDeviceInfo = deviceInfo;
mInfo = null;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 252eff567cfd..df468acce74c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -62,6 +62,7 @@ import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_A
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
@@ -121,6 +122,7 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Matrix;
+import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
@@ -137,6 +139,7 @@ import android.util.MutableBoolean;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.InputDevice;
import android.view.MagnificationSpec;
@@ -158,6 +161,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -208,6 +212,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
int mInitialDisplayHeight = 0;
int mInitialDisplayDensity = 0;
+ DisplayCutout mInitialDisplayCutout;
+ DisplayCutout mDisplayCutoutOverride;
+
/**
* Overridden display size. Initialized with {@link #mInitialDisplayWidth}
* and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
@@ -1193,6 +1200,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mDisplayInfo.getLogicalMetrics(mRealDisplayMetrics,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
}
+ mDisplayInfo.displayCutout = calculateDisplayCutoutForCurrentRotation();
mDisplayInfo.getAppMetrics(mDisplayMetrics);
if (mDisplayScalingDisabled) {
mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
@@ -1214,6 +1222,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return mDisplayInfo;
}
+ DisplayCutout calculateDisplayCutoutForCurrentRotation() {
+ final DisplayCutout cutout = mInitialDisplayCutout;
+ if (cutout == null || cutout == DisplayCutout.NO_CUTOUT || mRotation == ROTATION_0) {
+ return cutout;
+ }
+ final Path bounds = cutout.getBounds().getBoundaryPath();
+ transformPhysicalToLogicalCoordinates(mRotation, mInitialDisplayWidth,
+ mInitialDisplayHeight, mTmpMatrix);
+ bounds.transform(mTmpMatrix);
+ return DisplayCutout.fromBounds(bounds);
+ }
+
/**
* Compute display configuration based on display properties and policy settings.
* Do not call if mDisplayReady == false.
@@ -1676,6 +1696,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mInitialDisplayWidth = mDisplayInfo.logicalWidth;
mInitialDisplayHeight = mDisplayInfo.logicalHeight;
mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
+ mInitialDisplayCutout = mDisplayInfo.displayCutout;
}
/**
@@ -1690,10 +1711,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth;
final int newHeight = rotated ? mDisplayInfo.logicalWidth : mDisplayInfo.logicalHeight;
final int newDensity = mDisplayInfo.logicalDensityDpi;
+ final DisplayCutout newCutout = mDisplayInfo.displayCutout;
final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
|| mInitialDisplayHeight != newHeight
- || mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi;
+ || mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi
+ || !Objects.equals(mInitialDisplayCutout, newCutout);
if (displayMetricsChanged) {
// Check if display size or density is forced.
@@ -1710,6 +1733,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mInitialDisplayWidth = newWidth;
mInitialDisplayHeight = newHeight;
mInitialDisplayDensity = newDensity;
+ mInitialDisplayCutout = newCutout;
mService.reconfigureDisplayLocked(this);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 015571255f0d..bd06192b09fd 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -22,6 +22,7 @@ import static android.view.Surface.ROTATION_90;
import static com.android.server.wm.proto.DisplayFramesProto.STABLE_BOUNDS;
import android.annotation.NonNull;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
@@ -100,9 +101,12 @@ public class DisplayFrames {
/** During layout, the current screen borders along which input method windows are placed. */
public final Rect mDock = new Rect();
- /** Definition of the cutout */
+ /** The display cutout used for layout (after rotation and emulation) */
@NonNull public DisplayCutout mDisplayCutout = DisplayCutout.NO_CUTOUT;
+ /** The cutout as supplied by display info */
+ @NonNull private DisplayCutout mDisplayInfoCutout = DisplayCutout.NO_CUTOUT;
+
/**
* During layout, the frame that is display-cutout safe, i.e. that does not intersect with it.
*/
@@ -126,6 +130,8 @@ public class DisplayFrames {
mRotation = info.rotation;
mDisplayInfoOverscan.set(
info.overscanLeft, info.overscanTop, info.overscanRight, info.overscanBottom);
+ mDisplayInfoCutout = info.displayCutout != null
+ ? info.displayCutout : DisplayCutout.NO_CUTOUT;
}
public void onBeginLayout(boolean emulateDisplayCutout, int statusBarHeight) {
@@ -166,12 +172,29 @@ public class DisplayFrames {
mStable.set(mUnrestricted);
mStableFullscreen.set(mUnrestricted);
mCurrent.set(mUnrestricted);
- mDisplayCutout = DisplayCutout.NO_CUTOUT;
- mDisplayCutoutSafe.set(Integer.MIN_VALUE, Integer.MIN_VALUE,
- Integer.MAX_VALUE, Integer.MAX_VALUE);
+ mDisplayCutout = mDisplayInfoCutout;
if (emulateDisplayCutout) {
setEmulatedDisplayCutout((int) (statusBarHeight * 0.8));
}
+ mDisplayCutout = mDisplayCutout.calculateRelativeTo(mOverscan);
+
+ mDisplayCutoutSafe.set(Integer.MIN_VALUE, Integer.MIN_VALUE,
+ Integer.MAX_VALUE, Integer.MAX_VALUE);
+ if (!mDisplayCutout.isEmpty()) {
+ final DisplayCutout c = mDisplayCutout;
+ if (c.getSafeInsetLeft() > 0) {
+ mDisplayCutoutSafe.left = mRestrictedOverscan.left + c.getSafeInsetLeft();
+ }
+ if (c.getSafeInsetTop() > 0) {
+ mDisplayCutoutSafe.top = mRestrictedOverscan.top + c.getSafeInsetTop();
+ }
+ if (c.getSafeInsetRight() > 0) {
+ mDisplayCutoutSafe.right = mRestrictedOverscan.right - c.getSafeInsetRight();
+ }
+ if (c.getSafeInsetBottom() > 0) {
+ mDisplayCutoutSafe.bottom = mRestrictedOverscan.bottom - c.getSafeInsetBottom();
+ }
+ }
}
public int getInputMethodWindowVisibleHeight() {
@@ -194,8 +217,7 @@ public class DisplayFrames {
new Point(height, (screenWidth - widthBottom) / 2),
new Point(height, (screenWidth + widthBottom) / 2),
new Point(0, (screenWidth + widthTop) / 2)
- )).calculateRelativeTo(mUnrestricted);
- mDisplayCutoutSafe.left = height;
+ ));
break;
case ROTATION_180:
mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
@@ -203,8 +225,7 @@ public class DisplayFrames {
new Point((screenWidth - widthBottom) / 2, screenHeight - height),
new Point((screenWidth + widthBottom) / 2, screenHeight - height),
new Point((screenWidth + widthTop) / 2, screenHeight)
- )).calculateRelativeTo(mUnrestricted);
- mDisplayCutoutSafe.bottom = screenHeight - height;
+ ));
break;
case ROTATION_270:
mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
@@ -212,8 +233,7 @@ public class DisplayFrames {
new Point(screenHeight - height, (screenWidth - widthBottom) / 2),
new Point(screenHeight - height, (screenWidth + widthBottom) / 2),
new Point(screenHeight, (screenWidth + widthTop) / 2)
- )).calculateRelativeTo(mUnrestricted);
- mDisplayCutoutSafe.right = screenHeight - height;
+ ));
break;
default:
mDisplayCutout = DisplayCutout.fromBoundingPolygon(Arrays.asList(
@@ -221,8 +241,7 @@ public class DisplayFrames {
new Point((screenWidth - widthBottom) / 2, height),
new Point((screenWidth + widthBottom) / 2, height),
new Point((screenWidth + widthTop) / 2, 0)
- )).calculateRelativeTo(mUnrestricted);
- mDisplayCutoutSafe.top = height;
+ ));
break;
}
}
diff --git a/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java
new file mode 100644
index 000000000000..09d7b5de1caf
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 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 com.android.server.wm.utils;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.annotation.Dimension;
+import android.graphics.Matrix;
+import android.view.Surface.Rotation;
+
+public class CoordinateTransforms {
+
+ private CoordinateTransforms() {
+ }
+
+ /**
+ * Sets a matrix such that given a rotation, it transforms physical display
+ * coordinates to that rotation's logical coordinates.
+ *
+ * @param rotation the rotation to which the matrix should transform
+ * @param out the matrix to be set
+ */
+ public static void transformPhysicalToLogicalCoordinates(@Rotation int rotation,
+ @Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) {
+ switch (rotation) {
+ case ROTATION_0:
+ out.reset();
+ break;
+ case ROTATION_90:
+ out.setRotate(270);
+ out.postTranslate(0, physicalWidth);
+ break;
+ case ROTATION_180:
+ out.setRotate(180);
+ out.postTranslate(physicalWidth, physicalHeight);
+ break;
+ case ROTATION_270:
+ out.setRotate(90);
+ out.postTranslate(physicalHeight, 0);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown rotation: " + rotation);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 693264cbe4ee..2284bbbbf3ac 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -37,13 +37,18 @@ import org.junit.runner.RunWith;
import android.annotation.SuppressLint;
import android.content.res.Configuration;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.DisplayMetrics;
import android.util.SparseIntArray;
+import android.view.DisplayCutout;
import android.view.MotionEvent;
+import android.view.Surface;
import java.util.Arrays;
import java.util.LinkedList;
@@ -53,7 +58,7 @@ import java.util.List;
* Tests for the {@link DisplayContent} class.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.DisplayContentTests
+ * atest com.android.server.wm.DisplayContentTests
*/
@SmallTest
@Presubmit
@@ -385,6 +390,38 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testDisplayCutout_rot0() throws Exception {
+ synchronized (sWm.getWindowManagerLock()) {
+ final DisplayContent dc = createNewDisplay();
+ dc.mInitialDisplayWidth = 200;
+ dc.mInitialDisplayHeight = 400;
+ final DisplayCutout cutout = createCutout(new Rect(80, 0, 120, 10));
+
+ dc.mInitialDisplayCutout = cutout;
+ dc.setRotation(Surface.ROTATION_0);
+ dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
+
+ assertEquals(cutout, dc.getDisplayInfo().displayCutout);
+ }
+ }
+
+ @Test
+ public void testDisplayCutout_rot90() throws Exception {
+ synchronized (sWm.getWindowManagerLock()) {
+ final DisplayContent dc = createNewDisplay();
+ dc.mInitialDisplayWidth = 200;
+ dc.mInitialDisplayHeight = 400;
+ final DisplayCutout cutout = createCutout(new Rect(80, 0, 120, 10));
+
+ dc.mInitialDisplayCutout = cutout;
+ dc.setRotation(Surface.ROTATION_90);
+ dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
+
+ assertEquals(createCutout(new Rect(0, 80, 10, 120)), dc.getDisplayInfo().displayCutout);
+ }
+ }
+
+ @Test
@SuppressLint("InlinedApi")
public void testOrientationDefinedByKeyguard() {
final DisplayContent dc = createNewDisplay();
@@ -449,4 +486,10 @@ public class DisplayContentTests extends WindowTestsBase {
y,
metaState);
}
+
+ private DisplayCutout createCutout(Rect r) {
+ Path p = new Path();
+ p.addRect(r.left, r.top, r.right, r.bottom, Path.Direction.CCW);
+ return DisplayCutout.fromBounds(p);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
new file mode 100644
index 000000000000..40a10e04c893
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 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 com.android.server.wm.utils;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.*;
+
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.PointF;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+
+public class CoordinateTransformsTest {
+
+ private static final int W = 200;
+ private static final int H = 400;
+
+ private final Matrix mMatrix = new Matrix();
+
+ @Rule
+ public final ErrorCollector mErrorCollector = new ErrorCollector();
+
+ @Before
+ public void setUp() throws Exception {
+ mMatrix.setTranslate(0xdeadbeef, 0xdeadbeef);
+ }
+
+ @Test
+ public void transformPhysicalToLogicalCoordinates_rot0() throws Exception {
+ transformPhysicalToLogicalCoordinates(ROTATION_0, W, H, mMatrix);
+ assertThat(mMatrix, is(Matrix.IDENTITY_MATRIX));
+ }
+
+ @Test
+ public void transformPhysicalToLogicalCoordinates_rot90() throws Exception {
+ transformPhysicalToLogicalCoordinates(ROTATION_90, W, H, mMatrix);
+
+ checkDevicePoint(0, 0).mapsToLogicalPoint(0, W);
+ checkDevicePoint(W, H).mapsToLogicalPoint(H, 0);
+ }
+
+ @Test
+ public void transformPhysicalToLogicalCoordinates_rot180() throws Exception {
+ transformPhysicalToLogicalCoordinates(ROTATION_180, W, H, mMatrix);
+
+ checkDevicePoint(0, 0).mapsToLogicalPoint(W, H);
+ checkDevicePoint(W, H).mapsToLogicalPoint(0, 0);
+ }
+
+ @Test
+ public void transformPhysicalToLogicalCoordinates_rot270() throws Exception {
+ transformPhysicalToLogicalCoordinates(ROTATION_270, W, H, mMatrix);
+
+ checkDevicePoint(0, 0).mapsToLogicalPoint(H, 0);
+ checkDevicePoint(W, H).mapsToLogicalPoint(0, W);
+ }
+
+ private DevicePointAssertable checkDevicePoint(int x, int y) {
+ final Point devicePoint = new Point(x, y);
+ final float[] fs = new float[] {x, y};
+ mMatrix.mapPoints(fs);
+ final PointF transformedPoint = new PointF(fs[0], fs[1]);
+
+ return (expectedX, expectedY) -> {
+ mErrorCollector.checkThat("t(" + devicePoint + ")",
+ transformedPoint, is(new PointF(expectedX, expectedY)));
+ };
+ }
+
+ public interface DevicePointAssertable {
+ void mapsToLogicalPoint(int x, int y);
+ }
+} \ No newline at end of file