Merge "Dispatch DisplayCutout from DisplayAdapter"
This commit is contained in:
committed by
Android (Google) Code Review
commit
d396b28c20
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,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},
|
||||
@@ -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);
|
||||
|
||||
@@ -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). -->
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -228,6 +229,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}.
|
||||
*/
|
||||
@@ -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));
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -384,6 +389,38 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
assertEquals(-1, orderedDisplayIds.indexOfValue(dc.getDisplayId()));
|
||||
}
|
||||
|
||||
@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() {
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user