Merge "Dispatch DisplayCutout from DisplayAdapter"

This commit is contained in:
TreeHugger Robot
2018-01-11 16:36:31 +00:00
committed by Android (Google) Code Review
14 changed files with 348 additions and 27 deletions

View File

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

View File

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

View File

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

View File

@@ -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" />

View File

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

View File

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

View File

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

View File

@@ -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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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