Display Cutout: Dispatch Cutout from WindowManager
Adds the logic to dispatch a DisplayCutout from DisplayFrames
through WindowState to the View hierarchy. Does however not yet
change how windows are laid out in response to a DisplayCutout.
The display cutout is currently never present, the following CL
will add logic to emulate a display cutout on devices that do
not have a physical one.
Bug: 65689439
Test: runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
Change-Id: Ie4cd4b575755b66a7ffead31e28640983ef4894e
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index dd0ae33..e5ab3e1 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -42,6 +42,7 @@
import android.util.Log;
import android.util.MergedConfiguration;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.IWindowSession;
import android.view.InputChannel;
@@ -176,6 +177,9 @@
final Rect mFinalSystemInsets = new Rect();
final Rect mFinalStableInsets = new Rect();
final Rect mBackdropFrame = new Rect();
+ final DisplayCutout.ParcelableWrapper mDisplayCutout =
+ new DisplayCutout.ParcelableWrapper();
+ DisplayCutout mDispatchedDisplayCutout = DisplayCutout.NO_CUTOUT;
final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
final WindowManager.LayoutParams mLayout
@@ -302,7 +306,8 @@
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropRect, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
+ boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0, outsets);
mCaller.sendMessage(msg);
@@ -750,7 +755,7 @@
mInputChannel = new InputChannel();
if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
Display.DEFAULT_DISPLAY, mContentInsets, mStableInsets, mOutsets,
- mInputChannel) < 0) {
+ mDisplayCutout, mInputChannel) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
@@ -776,7 +781,7 @@
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,
mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
- mMergedConfiguration, mSurfaceHolder.mSurface);
+ mDisplayCutout, mMergedConfiguration, mSurfaceHolder.mSurface);
if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
+ ", frame=" + mWinFrame);
@@ -800,6 +805,8 @@
mStableInsets.top += padding.top;
mStableInsets.right += padding.right;
mStableInsets.bottom += padding.bottom;
+ mDisplayCutout.set(mDisplayCutout.get().inset(-padding.left, -padding.top,
+ -padding.right, -padding.bottom));
}
if (mCurWidth != w) {
@@ -819,6 +826,7 @@
insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets);
insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets);
insetsChanged |= !mDispatchedOutsets.equals(mOutsets);
+ insetsChanged |= !mDispatchedDisplayCutout.equals(mDisplayCutout.get());
mSurfaceHolder.setSurfaceFrameSize(w, h);
mSurfaceHolder.mSurfaceLock.unlock();
@@ -885,12 +893,13 @@
mDispatchedContentInsets.set(mContentInsets);
mDispatchedStableInsets.set(mStableInsets);
mDispatchedOutsets.set(mOutsets);
+ mDispatchedDisplayCutout = mDisplayCutout.get();
mFinalSystemInsets.set(mDispatchedOverscanInsets);
mFinalStableInsets.set(mDispatchedStableInsets);
WindowInsets insets = new WindowInsets(mFinalSystemInsets,
null, mFinalStableInsets,
getResources().getConfiguration().isScreenRound(), false,
- null /* displayCutout */);
+ mDispatchedDisplayCutout);
if (DEBUG) {
Log.v(TAG, "dispatching insets=" + insets);
}
diff --git a/core/java/android/view/DisplayCutout.aidl b/core/java/android/view/DisplayCutout.aidl
new file mode 100644
index 0000000..6d13b99
--- /dev/null
+++ b/core/java/android/view/DisplayCutout.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2017, 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 DisplayCutout.ParcelableWrapper;
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 611cc63..07a57fb 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -23,6 +23,7 @@
import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.DisplayCutout;
import com.android.internal.os.IResultReceiver;
import android.util.MergedConfiguration;
@@ -50,7 +51,8 @@
void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
in MergedConfiguration newMergedConfiguration, in Rect backDropFrame,
- boolean forceLayout, boolean alwaysConsumeNavBar, int displayId);
+ boolean forceLayout, boolean alwaysConsumeNavBar, int displayId,
+ in DisplayCutout.ParcelableWrapper displayCutout);
void moved(int newX, int newY);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 51d6514..ed167c8 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -22,6 +22,7 @@
import android.graphics.Region;
import android.os.Bundle;
import android.util.MergedConfiguration;
+import android.view.DisplayCutout;
import android.view.InputChannel;
import android.view.IWindow;
import android.view.IWindowId;
@@ -40,7 +41,8 @@
out InputChannel outInputChannel);
int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outContentInsets,
- out Rect outStableInsets, out Rect outOutsets, out InputChannel outInputChannel);
+ out Rect outStableInsets, out Rect outOutsets,
+ out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel);
int addWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets);
int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
@@ -96,6 +98,7 @@
int flags, out Rect outFrame, out Rect outOverscanInsets,
out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
out Rect outOutsets, out Rect outBackdropFrame,
+ out DisplayCutout.ParcelableWrapper displayCutout,
out MergedConfiguration outMergedConfiguration, out Surface outSurface);
/*
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0525ab1..f27989f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -25721,6 +25721,9 @@
*/
final Rect mStableInsets = new Rect();
+ final DisplayCutout.ParcelableWrapper mDisplayCutout =
+ new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
+
/**
* For windows that include areas that are not covered by real surface these are the outsets
* for real surface.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1c9d863..0bae36b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -384,12 +384,15 @@
final Rect mPendingContentInsets = new Rect();
final Rect mPendingOutsets = new Rect();
final Rect mPendingBackDropFrame = new Rect();
+ final DisplayCutout.ParcelableWrapper mPendingDisplayCutout =
+ new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
boolean mPendingAlwaysConsumeNavBar;
final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
= new ViewTreeObserver.InternalInsetsInfo();
final Rect mDispatchContentInsets = new Rect();
final Rect mDispatchStableInsets = new Rect();
+ DisplayCutout mDispatchDisplayCutout = DisplayCutout.NO_CUTOUT;
private WindowInsets mLastWindowInsets;
@@ -730,7 +733,7 @@
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
- mAttachInfo.mOutsets, mInputChannel);
+ mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
@@ -752,6 +755,7 @@
mPendingOverscanInsets.set(0, 0, 0, 0);
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingStableInsets.set(mAttachInfo.mStableInsets);
+ mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
mPendingVisibleInsets.set(0, 0, 0, 0);
mAttachInfo.mAlwaysConsumeNavBar =
(res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
@@ -1544,15 +1548,20 @@
if (mLastWindowInsets == null || forceConstruct) {
mDispatchContentInsets.set(mAttachInfo.mContentInsets);
mDispatchStableInsets.set(mAttachInfo.mStableInsets);
+ mDispatchDisplayCutout = mAttachInfo.mDisplayCutout.get();
+
Rect contentInsets = mDispatchContentInsets;
Rect stableInsets = mDispatchStableInsets;
+ DisplayCutout displayCutout = mDispatchDisplayCutout;
// For dispatch we preserve old logic, but for direct requests from Views we allow to
// immediately use pending insets.
if (!forceConstruct
&& (!mPendingContentInsets.equals(contentInsets) ||
- !mPendingStableInsets.equals(stableInsets))) {
+ !mPendingStableInsets.equals(stableInsets) ||
+ !mPendingDisplayCutout.get().equals(displayCutout))) {
contentInsets = mPendingContentInsets;
stableInsets = mPendingStableInsets;
+ displayCutout = mPendingDisplayCutout.get();
}
Rect outsets = mAttachInfo.mOutsets;
if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
@@ -1563,7 +1572,7 @@
mLastWindowInsets = new WindowInsets(contentInsets,
null /* windowDecorInsets */, stableInsets,
mContext.getResources().getConfiguration().isScreenRound(),
- mAttachInfo.mAlwaysConsumeNavBar, null /* displayCutout */);
+ mAttachInfo.mAlwaysConsumeNavBar, displayCutout);
}
return mLastWindowInsets;
}
@@ -1730,6 +1739,9 @@
if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
insetsChanged = true;
}
+ if (!mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout)) {
+ insetsChanged = true;
+ }
if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
@@ -1906,7 +1918,8 @@
+ " overscan=" + mPendingOverscanInsets.toShortString()
+ " content=" + mPendingContentInsets.toShortString()
+ " visible=" + mPendingVisibleInsets.toShortString()
- + " visible=" + mPendingStableInsets.toShortString()
+ + " stable=" + mPendingStableInsets.toShortString()
+ + " cutout=" + mPendingDisplayCutout.get().toString()
+ " outsets=" + mPendingOutsets.toShortString()
+ " surface=" + mSurface);
@@ -1931,6 +1944,8 @@
mAttachInfo.mVisibleInsets);
final boolean stableInsetsChanged = !mPendingStableInsets.equals(
mAttachInfo.mStableInsets);
+ final boolean cutoutChanged = !mPendingDisplayCutout.equals(
+ mAttachInfo.mDisplayCutout);
final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
final boolean surfaceSizeChanged = (relayoutResult
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
@@ -1955,6 +1970,14 @@
// Need to relayout with content insets.
contentInsetsChanged = true;
}
+ if (cutoutChanged) {
+ mAttachInfo.mDisplayCutout.set(mPendingDisplayCutout);
+ if (DEBUG_LAYOUT) {
+ Log.v(mTag, "DisplayCutout changing to: " + mAttachInfo.mDisplayCutout);
+ }
+ // Need to relayout with content insets.
+ contentInsetsChanged = true;
+ }
if (alwaysConsumeNavBarChanged) {
mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
contentInsetsChanged = true;
@@ -2056,6 +2079,7 @@
mResizeMode = freeformResizing
? RESIZE_MODE_FREEFORM
: RESIZE_MODE_DOCKED_DIVIDER;
+ // TODO: Need cutout?
startDragResizing(mPendingBackDropFrame,
mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
mPendingStableInsets, mResizeMode);
@@ -3776,6 +3800,7 @@
&& mPendingOverscanInsets.equals(args.arg5)
&& mPendingContentInsets.equals(args.arg2)
&& mPendingStableInsets.equals(args.arg6)
+ && mPendingDisplayCutout.get().equals(args.arg9)
&& mPendingVisibleInsets.equals(args.arg3)
&& mPendingOutsets.equals(args.arg7)
&& mPendingBackDropFrame.equals(args.arg8)
@@ -3808,6 +3833,7 @@
|| !mPendingOverscanInsets.equals(args.arg5)
|| !mPendingContentInsets.equals(args.arg2)
|| !mPendingStableInsets.equals(args.arg6)
+ || !mPendingDisplayCutout.get().equals(args.arg9)
|| !mPendingVisibleInsets.equals(args.arg3)
|| !mPendingOutsets.equals(args.arg7);
@@ -3815,6 +3841,7 @@
mPendingOverscanInsets.set((Rect) args.arg5);
mPendingContentInsets.set((Rect) args.arg2);
mPendingStableInsets.set((Rect) args.arg6);
+ mPendingDisplayCutout.set((DisplayCutout) args.arg9);
mPendingVisibleInsets.set((Rect) args.arg3);
mPendingOutsets.set((Rect) args.arg7);
mPendingBackDropFrame.set((Rect) args.arg8);
@@ -6258,7 +6285,7 @@
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
- mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame,
+ mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
mPendingMergedConfiguration, mSurface);
mPendingAlwaysConsumeNavBar =
@@ -6541,7 +6568,8 @@
private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
+ boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {
if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
+ " contentInsets=" + contentInsets.toShortString()
+ " visibleInsets=" + visibleInsets.toShortString()
@@ -6578,6 +6606,7 @@
args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
+ args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
args.argi1 = forceLayout ? 1 : 0;
args.argi2 = alwaysConsumeNavBar ? 1 : 0;
args.argi3 = displayId;
@@ -7610,12 +7639,13 @@
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
+ boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
- backDropFrame, forceLayout, alwaysConsumeNavBar, displayId);
+ backDropFrame, forceLayout, alwaysConsumeNavBar, displayId, displayCutout);
}
}
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index 8fb56d4..d9aa325 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -48,6 +48,7 @@
public Object arg6;
public Object arg7;
public Object arg8;
+ public Object arg9;
public int argi1;
public int argi2;
public int argi3;
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 361fd3da..7178a0d 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -22,6 +22,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.MergedConfiguration;
+import android.view.DisplayCutout;
import android.view.DragEvent;
import android.view.IWindow;
import android.view.IWindowSession;
@@ -41,7 +42,8 @@
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
+ boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {
if (reportDraw) {
try {
mSession.finishDrawing(this);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7415ec3..5b059a0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -211,6 +211,7 @@
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IApplicationToken;
@@ -4335,7 +4336,7 @@
// TODO: Should probably be moved into DisplayFrames.
public boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
DisplayFrames displayFrames, Rect outContentInsets, Rect outStableInsets,
- Rect outOutsets) {
+ Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
final int fl = PolicyControl.getWindowFlags(null, attrs);
final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility);
@@ -4361,12 +4362,15 @@
if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
+ Rect frame;
int availRight, availBottom;
if (canHideNavigationBar() &&
(systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
+ frame = displayFrames.mUnrestricted;
availRight = displayFrames.mUnrestricted.right;
availBottom = displayFrames.mUnrestricted.bottom;
} else {
+ frame = displayFrames.mRestricted;
availRight = displayFrames.mRestricted.right;
availBottom = displayFrames.mRestricted.bottom;
}
@@ -4397,10 +4401,12 @@
calculateRelevantTaskInsets(taskBounds, outStableInsets,
displayWidth, displayHeight);
}
+ outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(frame));
return mForceShowSystemBars;
}
outContentInsets.setEmpty();
outStableInsets.setEmpty();
+ outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
return mForceShowSystemBars;
}
@@ -4519,7 +4525,7 @@
w.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, df /* overlayFrame */,
df /* contentFrame */, df /* visibleFrame */, dcf /* decorFrame */,
- df /* stableFrame */, df /* outsetFrame */);
+ df /* stableFrame */, df /* outsetFrame */, displayFrames.mDisplayCutout);
final Rect frame = w.getFrameLw();
if (frame.left <= 0 && frame.top <= 0) {
@@ -4581,7 +4587,8 @@
// Let the status bar determine its size.
mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */,
vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */,
- dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */);
+ dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */,
+ displayFrames.mDisplayCutout);
// For layout, the status bar is always at the top with our fixed height.
displayFrames.mStable.top = displayFrames.mUnrestricted.top + mStatusBarHeight;
@@ -4712,7 +4719,7 @@
// And compute the final frame.
mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,
- mTmpNavigationFrame, mTmpNavigationFrame);
+ mTmpNavigationFrame, mTmpNavigationFrame, displayFrames.mDisplayCutout);
if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
return mNavigationBarController.checkHiddenLw();
}
@@ -5218,7 +5225,7 @@
+ " sf=" + sf.toShortString()
+ " osf=" + (osf == null ? "null" : osf.toShortString()));
- win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf);
+ win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout);
// Dock windows carve out the bottom of the screen, so normal windows
// can't appear underneath them.
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 5f067d4..4a7647b 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -77,6 +77,7 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.IApplicationToken;
import android.view.IWindowManager;
import android.view.InputEventReceiver;
@@ -210,10 +211,11 @@
* @param stableFrame The frame around which stable system decoration is positioned.
* @param outsetFrame The frame that includes areas that aren't part of the surface but we
* want to treat them as such.
+ * @param displayCutout the display displayCutout
*/
public void computeFrameLw(Rect parentFrame, Rect displayFrame,
Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame,
- Rect stableFrame, @Nullable Rect outsetFrame);
+ Rect stableFrame, @Nullable Rect outsetFrame, DisplayCutout displayCutout);
/**
* Retrieve the current frame of the window that has been assigned by
@@ -1144,12 +1146,13 @@
* @param outStableInsets The areas covered by stable system windows irrespective of their
* current visibility. Expressed as positive insets.
* @param outOutsets The areas that are not real display, but we would like to treat as such.
+ * @param outDisplayCutout The area that has been cut away from the display.
* @return Whether to always consume the navigation bar.
* See {@link #isNavBarForcedShownLw(WindowState)}.
*/
default boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
DisplayFrames displayFrames, Rect outContentInsets, Rect outStableInsets,
- Rect outOutsets) {
+ Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 0249713..209ce3f 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -21,8 +21,10 @@
import static android.view.Surface.ROTATION_90;
import static com.android.server.wm.proto.DisplayFramesProto.STABLE_BOUNDS;
+import android.annotation.NonNull;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import java.io.PrintWriter;
@@ -94,6 +96,14 @@
/** During layout, the current screen borders along which input method windows are placed. */
public final Rect mDock = new Rect();
+ /** Definition of the cutout */
+ @NonNull public DisplayCutout mDisplayCutout = DisplayCutout.NO_CUTOUT;
+
+ /**
+ * During layout, the frame that is display-cutout safe, i.e. that does not intersect with it.
+ */
+ public final Rect mDisplayCutoutSafe = new Rect();
+
private final Rect mDisplayInfoOverscan = new Rect();
private final Rect mRotatedDisplayInfoOverscan = new Rect();
public int mDisplayWidth;
@@ -152,7 +162,9 @@
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);
}
public int getInputMethodWindowVisibleHeight() {
@@ -182,6 +194,7 @@
dumpFrame(mUnrestricted, "mUnrestricted", myPrefix, pw);
dumpFrame(mDisplayInfoOverscan, "mDisplayInfoOverscan", myPrefix, pw);
dumpFrame(mRotatedDisplayInfoOverscan, "mRotatedDisplayInfoOverscan", myPrefix, pw);
+ pw.println(myPrefix + "mDisplayCutout=" + mDisplayCutout);
}
private void dumpFrame(Rect frame, String name, String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index ad7c300..63eea10 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -23,9 +23,8 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
+
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -45,13 +44,13 @@
import android.util.MergedConfiguration;
import android.util.Slog;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.IWindow;
import android.view.IWindowId;
import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.InputChannel;
import android.view.Surface;
-import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowManager;
@@ -192,15 +191,17 @@
int viewVisibility, Rect outContentInsets, Rect outStableInsets,
InputChannel outInputChannel) {
return addToDisplay(window, seq, attrs, viewVisibility, Display.DEFAULT_DISPLAY,
- outContentInsets, outStableInsets, null /* outOutsets */, outInputChannel);
+ outContentInsets, outStableInsets, null /* outOutsets */, null /* cutout */,
+ outInputChannel);
}
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
- Rect outOutsets, InputChannel outInputChannel) {
+ Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout,
+ InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
- outContentInsets, outStableInsets, outOutsets, outInputChannel);
+ outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}
@Override
@@ -214,7 +215,7 @@
public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
- outContentInsets, outStableInsets, null /* outOutsets */, null);
+ outContentInsets, outStableInsets, null /* outOutsets */, null /* cutout */, null);
}
@Override
@@ -232,6 +233,7 @@
int requestedWidth, int requestedHeight, int viewFlags,
int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
+ DisplayCutout.ParcelableWrapper cutout,
MergedConfiguration mergedConfiguration, Surface outSurface) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
@@ -239,7 +241,8 @@
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
- outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface);
+ outStableInsets, outsets, outBackdropFrame, cutout,
+ mergedConfiguration, outSurface);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 41915a3..3c1806d 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -57,6 +57,7 @@
import android.os.SystemClock;
import android.util.MergedConfiguration;
import android.util.Slog;
+import android.view.DisplayCutout;
import android.view.IWindowSession;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -134,6 +135,7 @@
window.setSession(session);
final Surface surface = new Surface();
final Rect tmpRect = new Rect();
+ final DisplayCutout.ParcelableWrapper tmpCutout = new DisplayCutout.ParcelableWrapper();
final Rect tmpFrame = new Rect();
final Rect taskBounds;
final Rect tmpContentInsets = new Rect();
@@ -196,7 +198,7 @@
try {
final int res = session.addToDisplay(window, window.mSeq, layoutParams,
View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect,
- tmpRect, null);
+ tmpRect, tmpCutout, null);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
return null;
@@ -212,7 +214,7 @@
try {
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
- tmpMergedConfiguration, surface);
+ tmpCutout, tmpMergedConfiguration, surface);
} catch (RemoteException e) {
// Local call.
}
@@ -437,7 +439,8 @@
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
+ boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {
if (mergedConfiguration != null && mOuter != null
&& mOuter.mOrientationOnCreation
!= mergedConfiguration.getMergedConfiguration().orientation) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 82f842c..1dc8a16 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -189,6 +189,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.AppTransitionAnimationSpec;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
@@ -1129,9 +1130,9 @@
}
public int addWindow(Session session, IWindow client, int seq,
- WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
+ LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
- InputChannel outInputChannel) {
+ DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
int[] appOp = new int[1];
int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
@@ -1466,7 +1467,7 @@
taskBounds = null;
}
if (mPolicy.getInsetHintLw(win.mAttrs, taskBounds, displayFrames, outContentInsets,
- outStableInsets, outOutsets)) {
+ outStableInsets, outOutsets, outDisplayCutout)) {
res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
}
@@ -1846,11 +1847,12 @@
}
public int relayoutWindow(Session session, IWindow client, int seq,
- WindowManager.LayoutParams attrs, int requestedWidth,
+ LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, int flags,
Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
- MergedConfiguration mergedConfiguration, Surface outSurface) {
+ DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
+ Surface outSurface) {
int result = 0;
boolean configChanged;
final boolean hasStatusBarPermission =
@@ -2135,6 +2137,7 @@
win.mLastRelayoutContentInsets.set(win.mContentInsets);
outVisibleInsets.set(win.mVisibleInsets);
outStableInsets.set(win.mStableInsets);
+ outCutout.set(win.mDisplayCutout);
outOutsets.set(win.mOutsets);
outBackdropFrame.set(win.getBackdropFrame(win.mFrame));
if (localLOGV) Slog.v(
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c2ac905..18755b1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -42,7 +42,6 @@
import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
@@ -144,6 +143,7 @@
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IApplicationToken;
@@ -320,6 +320,11 @@
private final Rect mLastOutsets = new Rect();
private boolean mOutsetsChanged = false;
+ /** Part of the display that has been cut away. See {@link DisplayCutout}. */
+ DisplayCutout mDisplayCutout = DisplayCutout.NO_CUTOUT;
+ private DisplayCutout mLastDisplayCutout = DisplayCutout.NO_CUTOUT;
+ private boolean mDisplayCutoutChanged;
+
/**
* Set to true if we are waiting for this window to receive its
* given internal insets before laying out other windows based on it.
@@ -772,7 +777,7 @@
@Override
public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overscanFrame,
Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
- Rect outsetFrame) {
+ Rect outsetFrame, DisplayCutout displayCutout) {
if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
// This window is being replaced and either already got information that it's being
// removed or we are still waiting for some information. Because of this we don't
@@ -1009,6 +1014,10 @@
mVisibleFrame.offset(-layoutXDiff, -layoutYDiff);
mStableFrame.offset(-layoutXDiff, -layoutYDiff);
+ // TODO(roosa): Figure out what frame exactly this needs to be calculated with.
+ mDisplayCutout = displayCutout.calculateRelativeTo(mFrame);
+
+
mCompatFrame.set(mFrame);
if (mEnforceSizeCompat) {
// If there is a size compatibility scale being applied to the
@@ -1149,8 +1158,9 @@
mOutsetsChanged |= !mLastOutsets.equals(mOutsets);
mFrameSizeChanged |= (mLastFrame.width() != mFrame.width()) ||
(mLastFrame.height() != mFrame.height());
+ mDisplayCutoutChanged |= !mLastDisplayCutout.equals(mDisplayCutout);
return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged
- || mOutsetsChanged || mFrameSizeChanged;
+ || mOutsetsChanged || mFrameSizeChanged || mDisplayCutoutChanged;
}
/**
@@ -1195,6 +1205,7 @@
|| winAnimator.mSurfaceResized
|| mOutsetsChanged
|| mFrameSizeChanged
+ || mDisplayCutoutChanged
|| configChanged
|| dragResizingChanged
|| !isResizedWhileNotDragResizingReported()
@@ -1214,7 +1225,8 @@
+ " dragResizingChanged=" + dragResizingChanged
+ " resizedWhileNotDragResizingReported="
+ isResizedWhileNotDragResizingReported()
- + " reportOrientationChanged=" + mReportOrientationChanged);
+ + " reportOrientationChanged=" + mReportOrientationChanged
+ + " displayCutoutChanged=" + mDisplayCutoutChanged);
}
// If it's a dead window left on screen, and the configuration changed, there is nothing
@@ -2849,6 +2861,7 @@
final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
final boolean reportOrientation = mReportOrientationChanged;
final int displayId = getDisplayId();
+ final DisplayCutout displayCutout = mDisplayCutout;
if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
&& mClient instanceof IWindow.Stub) {
// To prevent deadlock simulate one-way call if win.mClient is a local object.
@@ -2858,7 +2871,7 @@
try {
dispatchResized(frame, overscanInsets, contentInsets, visibleInsets,
stableInsets, outsets, reportDraw, mergedConfiguration,
- reportOrientation, displayId);
+ reportOrientation, displayId, displayCutout);
} catch (RemoteException e) {
// Not a remote call, RemoteException won't be raised.
}
@@ -2866,7 +2879,8 @@
});
} else {
dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
- outsets, reportDraw, mergedConfiguration, reportOrientation, displayId);
+ outsets, reportDraw, mergedConfiguration, reportOrientation, displayId,
+ displayCutout);
}
//TODO (multidisplay): Accessibility supported only for the default display.
@@ -2880,6 +2894,7 @@
mStableInsetsChanged = false;
mOutsetsChanged = false;
mFrameSizeChanged = false;
+ mDisplayCutoutChanged = false;
mResizedWhileNotDragResizingReported = true;
mWinAnimator.mSurfaceResized = false;
mReportOrientationChanged = false;
@@ -2922,14 +2937,16 @@
private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId)
+ MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId,
+ DisplayCutout displayCutout)
throws RemoteException {
final boolean forceRelayout = isDragResizeChanged() || mResizedWhileNotDragResizing
|| reportOrientation;
mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout,
- mPolicy.isNavBarForcedShownLw(this), displayId);
+ mPolicy.isNavBarForcedShownLw(this), displayId,
+ new DisplayCutout.ParcelableWrapper(displayCutout));
mDragResizingChangeReported = true;
}
@@ -3246,6 +3263,7 @@
pw.print(" stable="); mStableInsets.printShortString(pw);
pw.print(" surface="); mAttrs.surfaceInsets.printShortString(pw);
pw.print(" outsets="); mOutsets.printShortString(pw);
+ pw.print(" cutout=" + mDisplayCutout);
pw.println();
pw.print(prefix); pw.print("Lst insets: overscan=");
mLastOverscanInsets.printShortString(pw);
@@ -3254,6 +3272,7 @@
pw.print(" stable="); mLastStableInsets.printShortString(pw);
pw.print(" physical="); mLastOutsets.printShortString(pw);
pw.print(" outset="); mLastOutsets.printShortString(pw);
+ pw.print(" cutout=" + mLastDisplayCutout);
pw.println();
}
pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
@@ -4278,6 +4297,7 @@
mLastVisibleInsets.set(mVisibleInsets);
mLastStableInsets.set(mStableInsets);
mLastOutsets.set(mOutsets);
+ mLastDisplayCutout = mDisplayCutout;
}
// TODO: Hack to work around the number of states AppWindowToken needs to access without having
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index a70441d..d1e0132 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -20,6 +20,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.IApplicationToken;
import android.view.WindowManager;
@@ -34,6 +35,8 @@
public final Rect stableFrame = new Rect();
public Rect outsetFrame = new Rect();
+ public DisplayCutout displayCutout;
+
public WindowManager.LayoutParams attrs;
public int displayId;
public boolean isVoiceInteraction;
@@ -56,7 +59,7 @@
@Override
public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame,
Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
- @Nullable Rect outsetFrame) {
+ @Nullable Rect outsetFrame, DisplayCutout displayCutout) {
this.parentFrame.set(parentFrame);
this.displayFrame.set(displayFrame);
this.overscanFrame.set(overlayFrame);
@@ -65,6 +68,7 @@
this.decorFrame.set(decorFrame);
this.stableFrame.set(stableFrame);
this.outsetFrame = outsetFrame == null ? null : new Rect(outsetFrame);
+ this.displayCutout = displayCutout;
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
index 0a644b60..353aa7d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
@@ -23,6 +23,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.MergedConfiguration;
+import android.view.DisplayCutout;
import android.view.DragEvent;
import android.view.IWindow;
@@ -37,7 +38,8 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig,
- Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId)
+ Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout)
throws RemoteException {
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index fdcf57b..337fd50 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -22,12 +22,12 @@
import android.app.ActivityManager.TaskDescription;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
-import android.os.Debug;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IWindow;
@@ -38,6 +38,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import java.util.Arrays;
+
/**
* Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery.
*
@@ -158,7 +160,7 @@
// When mFrame extends past cf, the content insets are
// the difference between mFrame and ContentFrame. Visible
// and stable frames work the same way.
- w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+ w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame,0, 0, 1000, 1000);
assertRect(w.mContentInsets, 0, topContentInset, 0, bottomContentInset);
assertRect(w.mVisibleInsets, 0, topVisibleInset, 0, bottomVisibleInset);
@@ -173,7 +175,7 @@
w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT
w.mRequestedWidth = 100;
w.mRequestedHeight = 100;
- w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+ w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 100, 100, 200, 200);
assertRect(w.mContentInsets, 0, 0, 0, 0);
// In this case the frames are shrunk to the window frame.
@@ -194,7 +196,7 @@
// Here the window has FILL_PARENT, FILL_PARENT
// so we expect it to fill the entire available frame.
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 0, 0, 1000, 1000);
// It can select various widths and heights within the bounds.
@@ -202,14 +204,14 @@
// and we use mRequestedWidth/mRequestedHeight
w.mAttrs.width = 300;
w.mAttrs.height = 300;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
// Explicit width and height without requested width/height
// gets us nothing.
assertRect(w.mFrame, 0, 0, 0, 0);
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
// With requestedWidth/Height we can freely choose our size within the
// parent bounds.
assertRect(w.mFrame, 0, 0, 300, 300);
@@ -222,14 +224,14 @@
w.mRequestedWidth = -1;
w.mAttrs.width = 100;
w.mAttrs.height = 100;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 0, 0, 100, 100);
w.mAttrs.flags = 0;
// But sizes too large will be clipped to the containing frame
w.mRequestedWidth = 1200;
w.mRequestedHeight = 1200;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 0, 0, 1000, 1000);
// Before they are clipped though windows will be shifted
@@ -237,7 +239,7 @@
w.mAttrs.y = 300;
w.mRequestedWidth = 1000;
w.mRequestedHeight = 1000;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 0, 0, 1000, 1000);
// If there is room to move around in the parent frame the window will be shifted according
@@ -247,16 +249,16 @@
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 700, 0, 1000, 300);
w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 700, 700, 1000, 1000);
// Window specified x and y are interpreted as offsets in the opposite
// direction of gravity
w.mAttrs.x = 100;
w.mAttrs.y = 100;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, 600, 600, 900, 900);
}
@@ -277,7 +279,7 @@
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null, DisplayCutout.NO_CUTOUT);
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
@@ -289,7 +291,7 @@
final int cfRight = logicalWidth / 2;
final int cfBottom = logicalHeight / 2;
final Rect cf = new Rect(0, 0, cfRight, cfBottom);
- w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null);
+ w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
int contentInsetRight = taskRight - cfRight;
int contentInsetBottom = taskBottom - cfBottom;
@@ -306,7 +308,7 @@
final int insetRight = insetLeft + (taskRight - taskLeft);
final int insetBottom = insetTop + (taskBottom - taskTop);
task.mInsetBounds.set(insetLeft, insetTop, insetRight, insetBottom);
- w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null);
+ w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, DisplayCutout.NO_CUTOUT);
assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
contentInsetRight = insetRight - cfRight;
contentInsetBottom = insetBottom - cfBottom;
@@ -338,13 +340,13 @@
final Rect policyCrop = new Rect();
- w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+ w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
w.calculatePolicyCrop(policyCrop);
assertRect(policyCrop, 0, cf.top, logicalWidth, cf.bottom);
dcf.setEmpty();
// Likewise with no decor frame we would get no crop
- w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+ w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT);
w.calculatePolicyCrop(policyCrop);
assertRect(policyCrop, 0, 0, logicalWidth, logicalHeight);
@@ -357,7 +359,7 @@
w.mAttrs.height = logicalHeight / 2;
w.mRequestedWidth = logicalWidth / 2;
w.mRequestedHeight = logicalHeight / 2;
- w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT);
w.calculatePolicyCrop(policyCrop);
// Normally the crop is shrunk from the decor frame
@@ -394,7 +396,7 @@
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */,
pf /* contentFrame */, pf /* visibleFrame */, pf /* decorFrame */,
- pf /* stableFrame */, null /* outsetFrame */);
+ pf /* stableFrame */, null /* outsetFrame */, DisplayCutout.NO_CUTOUT);
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
@@ -413,12 +415,31 @@
w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */,
cf /* contentFrame */, cf /* visibleFrame */, pf /* decorFrame */,
- cf /* stableFrame */, null /* outsetFrame */);
+ cf /* stableFrame */, null /* outsetFrame */, DisplayCutout.NO_CUTOUT);
assertEquals(cf, w.mFrame);
assertEquals(cf, w.getContentFrameLw());
assertRect(w.mContentInsets, 0, 0, 0, 0);
}
+ @Test
+ public void testDisplayCutout() {
+ // Regular fullscreen task and window
+ Task task = new TaskWithBounds(null);
+ WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+ w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
+
+ final Rect pf = new Rect(0, 0, 1000, 1000);
+ // Create a display cutout of size 50x50, aligned top-center
+ final DisplayCutout cutout = createDisplayCutoutFromRect(500, 0, 550, 50);
+
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, cutout);
+
+ assertEquals(w.mDisplayCutout.getSafeInsetTop(), 50);
+ assertEquals(w.mDisplayCutout.getSafeInsetBottom(), 0);
+ assertEquals(w.mDisplayCutout.getSafeInsetLeft(), 0);
+ assertEquals(w.mDisplayCutout.getSafeInsetRight(), 0);
+ }
+
private WindowStateWithTask createWindow(Task task, int width, int height) {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
attrs.width = width;
@@ -426,4 +447,13 @@
return new WindowStateWithTask(attrs, task);
}
+
+ private DisplayCutout createDisplayCutoutFromRect(int left, int top, int right, int bottom) {
+ return DisplayCutout.fromBoundingPolygon(Arrays.asList(
+ new Point(left, top),
+ new Point (left, bottom),
+ new Point (right, bottom),
+ new Point (left, bottom)
+ ));
+ }
}
diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
index 6b9bb31..9174014 100644
--- a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
+++ b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
@@ -24,6 +24,7 @@
import android.util.Log;
import android.util.MergedConfiguration;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.IWindowSession;
import android.view.Surface;
import android.view.View;
@@ -103,7 +104,8 @@
WindowManagerGlobal.getWindowSession().relayout(window,
window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, mTmpRect,
mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect,
- new MergedConfiguration(), new Surface());
+ new DisplayCutout.ParcelableWrapper(), new MergedConfiguration(),
+ new Surface());
} catch (RemoteException e) {
e.printStackTrace();
}