diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 59c9102749098..572581e0c1e03 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3190,7 +3190,8 @@ class WindowState extends WindowContainer implements WindowManagerP } boolean isDockedResizing() { - return mDragResizing && getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER; + return (mDragResizing && getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER) + || (isChildWindow() && getParentWindow().isDockedResizing()); } void dump(PrintWriter pw, String prefix, boolean dumpAll) { @@ -4144,6 +4145,105 @@ class WindowState extends WindowContainer implements WindowManagerP } } + /** + * Calculate the window crop according to system decor policy. In general this is + * the system decor rect (see #calculateSystemDecorRect), but we also have some + * special cases. This rectangle is in screen space. + */ + void calculatePolicyCrop(Rect policyCrop) { + final DisplayContent displayContent = getDisplayContent(); + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); + + if (!isDefaultDisplay()) { + // On a different display there is no system decor. Crop the window + // by the screen boundaries. + // TODO(multi-display) + policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height()); + policyCrop.intersect(-mCompatFrame.left, -mCompatFrame.top, + displayInfo.logicalWidth - mCompatFrame.left, + displayInfo.logicalHeight - mCompatFrame.top); + } else if (mLayer >= mService.mSystemDecorLayer) { + // Above the decor layer is easy, just use the entire window + policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height()); + } else if (mDecorFrame.isEmpty()) { + // Windows without policy decor aren't cropped. + policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height()); + } else { + // Crop to the system decor specified by policy. + calculateSystemDecorRect(policyCrop); + } + } + + /** + * The system decor rect is the region of the window which is not covered + * by system decorations. + */ + private void calculateSystemDecorRect(Rect systemDecorRect) { + final Rect decorRect = mDecorFrame; + final int width = mFrame.width(); + final int height = mFrame.height(); + + // Compute the offset of the window in relation to the decor rect. + final int left = mXOffset + mFrame.left; + final int top = mYOffset + mFrame.top; + + // Initialize the decor rect to the entire frame. + if (isDockedResizing()) { + // If we are resizing with the divider, the task bounds might be smaller than the + // stack bounds. The system decor is used to clip to the task bounds, which we don't + // want in this case in order to avoid holes. + // + // We take care to not shrink the width, for surfaces which are larger than + // the display region. Of course this area will not eventually be visible + // but if we truncate the width now, we will calculate incorrectly + // when adjusting to the stack bounds. + final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo(); + systemDecorRect.set(0, 0, + Math.max(width, displayInfo.logicalWidth), + Math.max(height, displayInfo.logicalHeight)); + } else { + systemDecorRect.set(0, 0, width, height); + } + + // If a freeform window is animating from a position where it would be cutoff, it would be + // cutoff during the animation. We don't want that, so for the duration of the animation + // we ignore the decor cropping and depend on layering to position windows correctly. + final boolean cropToDecor = !(inFreeformWorkspace() && isAnimatingLw()); + if (cropToDecor) { + // Intersect with the decor rect, offsetted by window position. + systemDecorRect.intersect(decorRect.left - left, decorRect.top - top, + decorRect.right - left, decorRect.bottom - top); + } + + // If size compatibility is being applied to the window, the + // surface is scaled relative to the screen. Also apply this + // scaling to the crop rect. We aren't using the standard rect + // scale function because we want to round things to make the crop + // always round to a larger rect to ensure we don't crop too + // much and hide part of the window that should be seen. + if (mEnforceSizeCompat && mInvGlobalScale != 1.0f) { + final float scale = mInvGlobalScale; + systemDecorRect.left = (int) (systemDecorRect.left * scale - 0.5f); + systemDecorRect.top = (int) (systemDecorRect.top * scale - 0.5f); + systemDecorRect.right = (int) ((systemDecorRect.right + 1) * scale - 0.5f); + systemDecorRect.bottom = (int) ((systemDecorRect.bottom + 1) * scale - 0.5f); + } + + } + + /** + * Expand the given rectangle by this windows surface insets. This + * takes you from the 'window size' to the 'surface size'. + * The surface insets are positive in each direction, so we inset by + * the inverse. + */ + void expandForSurfaceInsets(Rect r) { + r.inset(-mAttrs.surfaceInsets.left, + -mAttrs.surfaceInsets.top, + -mAttrs.surfaceInsets.right, + -mAttrs.surfaceInsets.bottom); + } + // TODO: Hack to work around the number of states AppWindowToken needs to access without having // access to its windows children. Need to investigate re-writing // {@link AppWindowToken#updateReportedVisibilityLocked} so this can be removed. diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index a428cce2332f8..04db499052ae5 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -22,6 +22,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; import static android.view.WindowManager.LayoutParams.FLAG_SCALED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static com.android.server.wm.AppWindowAnimator.sDummyAnimation; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; @@ -1068,99 +1069,75 @@ class WindowStateAnimator { } } - private void calculateSystemDecorRect() { - final WindowState w = mWin; - final Rect decorRect = w.mDecorFrame; - final int width = w.mFrame.width(); - final int height = w.mFrame.height(); - - // Compute the offset of the window in relation to the decor rect. - final int left = w.mXOffset + w.mFrame.left; - final int top = w.mYOffset + w.mFrame.top; - - // Initialize the decor rect to the entire frame. - if (w.isDockedResizing() || - (w.isChildWindow() && w.getParentWindow().isDockedResizing())) { - - // If we are resizing with the divider, the task bounds might be smaller than the - // stack bounds. The system decor is used to clip to the task bounds, which we don't - // want in this case in order to avoid holes. - // - // We take care to not shrink the width, for surfaces which are larger than - // the display region. Of course this area will not eventually be visible - // but if we truncate the width now, we will calculate incorrectly - // when adjusting to the stack bounds. - final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo(); - mSystemDecorRect.set(0, 0, - Math.max(width, displayInfo.logicalWidth), - Math.max(height, displayInfo.logicalHeight)); - } else { - mSystemDecorRect.set(0, 0, width, height); - } - - // If a freeform window is animating from a position where it would be cutoff, it would be - // cutoff during the animation. We don't want that, so for the duration of the animation - // we ignore the decor cropping and depend on layering to position windows correctly. - final boolean cropToDecor = !(w.inFreeformWorkspace() && w.isAnimatingLw()); - if (cropToDecor) { - // Intersect with the decor rect, offsetted by window position. - mSystemDecorRect.intersect(decorRect.left - left, decorRect.top - top, - decorRect.right - left, decorRect.bottom - top); - } - - // If size compatibility is being applied to the window, the - // surface is scaled relative to the screen. Also apply this - // scaling to the crop rect. We aren't using the standard rect - // scale function because we want to round things to make the crop - // always round to a larger rect to ensure we don't crop too - // much and hide part of the window that should be seen. - if (w.mEnforceSizeCompat && w.mInvGlobalScale != 1.0f) { - final float scale = w.mInvGlobalScale; - mSystemDecorRect.left = (int) (mSystemDecorRect.left * scale - 0.5f); - mSystemDecorRect.top = (int) (mSystemDecorRect.top * scale - 0.5f); - mSystemDecorRect.right = (int) ((mSystemDecorRect.right + 1) * scale - 0.5f); - mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom + 1) * scale - 0.5f); - } + /** + * In some scenarios we use a screen space clip rect (so called, final clip rect) + * to crop to stack bounds. Generally because it's easier to deal with while + * animating. + * + * @return True in scenarios where we use the final clip rect for stack clipping. + */ + private boolean useFinalClipRect() { + return (isAnimationSet() && resolveStackClip() == STACK_CLIP_AFTER_ANIM) + || mDestroyPreservedSurfaceUponRedraw || mWin.inPinnedWorkspace(); } - void calculateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect) { + /** + * Calculate the screen-space crop rect and fill finalClipRect. + * @return true if finalClipRect has been filled, otherwise, + * no screen space crop should be applied. + */ + private boolean calculateFinalCrop(Rect finalClipRect) { final WindowState w = mWin; final DisplayContent displayContent = w.getDisplayContent(); + finalClipRect.setEmpty(); + if (displayContent == null) { - clipRect.setEmpty(); - finalClipRect.setEmpty(); - return; + return false; } + + if (!shouldCropToStackBounds() || !useFinalClipRect()) { + return false; + } + + // Task is non-null per shouldCropToStackBounds + final TaskStack stack = w.getTask().mStack; + stack.getDimBounds(finalClipRect); + w.expandForSurfaceInsets(finalClipRect); + return true; + } + + /** + * Calculate the window-space crop rect and fill clipRect. + * @return true if clipRect has been filled otherwise, no window space + * crop should be applied. + */ + boolean calculateCrop(Rect clipRect) { + final WindowState w = mWin; + final DisplayContent displayContent = w.getDisplayContent(); + clipRect.setEmpty(); + + if (displayContent == null) { + return false; + } + + if (w.inPinnedWorkspace()) { + return false; + } + + // If we're animating, the wallpaper should only + // be updated at the end of the animation. + if (w.mAttrs.type == TYPE_WALLPAPER) { + return false; + } + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop win=" + w + " mLastCrop=" + mLastClipRect); - // Need to recompute a new system decor rect each time. - if (!w.isDefaultDisplay()) { - // On a different display there is no system decor. Crop the window - // by the screen boundaries. - mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height()); - mSystemDecorRect.intersect(-w.mCompatFrame.left, -w.mCompatFrame.top, - displayInfo.logicalWidth - w.mCompatFrame.left, - displayInfo.logicalHeight - w.mCompatFrame.top); - } else if (w.mLayer >= mService.mSystemDecorLayer) { - // Above the decor layer is easy, just use the entire window. - mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height()); - } else if (w.mDecorFrame.isEmpty()) { - // Windows without policy decor aren't cropped. - mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height()); - } else if (w.mAttrs.type == LayoutParams.TYPE_WALLPAPER && mAnimator.isAnimating()) { - // If we're animating, the wallpaper crop should only be updated at the end of the - // animation. - mTmpClipRect.set(mSystemDecorRect); - calculateSystemDecorRect(); - mSystemDecorRect.union(mTmpClipRect); - } else { - // Crop to the system decor specified by policy. - calculateSystemDecorRect(); - if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame=" - + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect); - } + w.calculatePolicyCrop(mSystemDecorRect); + + if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame=" + + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect); final boolean fullscreen = w.isFrameFullscreen(displayInfo); final boolean isFreeformResizing = @@ -1178,12 +1155,7 @@ class WindowStateAnimator { clipRect.offset(w.mShownPosition.x, w.mShownPosition.y); } - // Expand the clip rect for surface insets. - final WindowManager.LayoutParams attrs = w.mAttrs; - clipRect.left -= attrs.surfaceInsets.left; - clipRect.top -= attrs.surfaceInsets.top; - clipRect.right += attrs.surfaceInsets.right; - clipRect.bottom += attrs.surfaceInsets.bottom; + w.expandForSurfaceInsets(clipRect); if (mHasClipRect && fullscreen) { // We intersect the clip rect specified by the transformation with the expanded system @@ -1193,10 +1165,11 @@ class WindowStateAnimator { } // The clip rect was generated assuming (0,0) as the window origin, // so we need to translate to match the actual surface coordinates. - clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top); + clipRect.offset(w.mAttrs.surfaceInsets.left, w.mAttrs.surfaceInsets.top); - finalClipRect.setEmpty(); - adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing); + if (!useFinalClipRect()) { + adjustCropToStackBounds(clipRect, isFreeformResizing); + } if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Clip rect after stack adjustment=" + clipRect); @@ -1206,10 +1179,11 @@ class WindowStateAnimator { if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) { clipRect.setEmpty(); } + return true; } - void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) { - if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin + private void applyCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) { + if (DEBUG_WINDOW_CROP) Slog.d(TAG, "applyCrop: win=" + mWin + " clipRect=" + clipRect + " finalClipRect=" + finalClipRect); if (clipRect != null) { if (!clipRect.equals(mLastClipRect)) { @@ -1219,6 +1193,11 @@ class WindowStateAnimator { } else { mSurfaceController.clearCropInTransaction(recoveringMemory); } + + if (finalClipRect == null) { + finalClipRect = mService.mTmpRect; + finalClipRect.setEmpty(); + } if (!finalClipRect.equals(mLastFinalClipRect)) { mLastFinalClipRect.set(finalClipRect); mSurfaceController.setFinalCropInTransaction(finalClipRect); @@ -1236,9 +1215,9 @@ class WindowStateAnimator { return mStackClip; } } - private void adjustCropToStackBounds(WindowState w, Rect clipRect, Rect finalClipRect, - boolean isFreeformResizing) { + private boolean shouldCropToStackBounds() { + final WindowState w = mWin; final DisplayContent displayContent = w.getDisplayContent(); if (displayContent != null && !displayContent.isDefaultDisplay) { // There are some windows that live on other displays while their app and main window @@ -1246,22 +1225,32 @@ class WindowStateAnimator { // to the stack bounds which is only currently supported on the default display. // TODO(multi-display): Need to support cropping to stack bounds on other displays // when we have stacks on other displays. - return; + return false; } final Task task = w.getTask(); if (task == null || !task.cropWindowsToStackBounds()) { - return; + return false; } final int stackClip = resolveStackClip(); // It's animating and we don't want to clip it to stack bounds during animation - abort. if (isAnimationSet() && stackClip == STACK_CLIP_NONE) { + return false; + } + return true; + } + + private void adjustCropToStackBounds(Rect clipRect, + boolean isFreeformResizing) { + final WindowState w = mWin; + + if (!shouldCropToStackBounds()) { return; } - final TaskStack stack = task.mStack; + final TaskStack stack = w.getTask().mStack; stack.getDimBounds(mTmpStackBounds); final Rect surfaceInsets = w.getAttrs().surfaceInsets; // When we resize we use the big surface approach, which means we can't trust the @@ -1272,34 +1261,25 @@ class WindowStateAnimator { final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() : w.mFrame.top + mWin.mYOffset - surfaceInsets.top; - // If we are animating, we either apply the clip before applying all the animation - // transformation or after all the transformation. - final boolean useFinalClipRect = isAnimationSet() && stackClip == STACK_CLIP_AFTER_ANIM - || mDestroyPreservedSurfaceUponRedraw; - // We need to do some acrobatics with surface position, because their clip region is // relative to the inside of the surface, but the stack bounds aren't. - if (useFinalClipRect) { - finalClipRect.set(mTmpStackBounds); - } else { - if (StackId.hasWindowShadow(stack.mStackId) - && !StackId.isTaskResizeAllowed(stack.mStackId)) { + if (StackId.hasWindowShadow(stack.mStackId) + && !StackId.isTaskResizeAllowed(stack.mStackId)) { // The windows in this stack display drop shadows and the fill the entire stack // area. Adjust the stack bounds we will use to cropping take into account the // offsets we use to display the drop shadow so it doesn't get cropped. mTmpStackBounds.inset(-surfaceInsets.left, -surfaceInsets.top, -surfaceInsets.right, -surfaceInsets.bottom); - } - - clipRect.left = Math.max(0, - Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX); - clipRect.top = Math.max(0, - Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY); - clipRect.right = Math.max(0, - Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX); - clipRect.bottom = Math.max(0, - Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY); } + + clipRect.left = Math.max(0, + Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX); + clipRect.top = Math.max(0, + Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY); + clipRect.right = Math.max(0, + Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX); + clipRect.bottom = Math.max(0, + Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY); } void setSurfaceBoundariesLocked(final boolean recoveringMemory) { @@ -1339,7 +1319,13 @@ class WindowStateAnimator { // updates until a resize occurs. mService.markForSeamlessRotation(w, w.mSeamlesslyRotated && !mSurfaceResized); - calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect); + Rect clipRect = null, finalClipRect = null; + if (calculateCrop(mTmpClipRect)) { + clipRect = mTmpClipRect; + } + if (calculateFinalCrop(mTmpFinalClipRect)) { + finalClipRect = mTmpFinalClipRect; + } float surfaceWidth = mSurfaceController.getWidth(); float surfaceHeight = mSurfaceController.getHeight(); @@ -1404,16 +1390,8 @@ class WindowStateAnimator { mSurfaceController.forceScaleableInTransaction(false); } - Rect clipRect = mTmpClipRect; - if (w.inPinnedWorkspace()) { - clipRect = null; - task.mStack.getDimBounds(mTmpFinalClipRect); - mTmpFinalClipRect.inset(-w.mAttrs.surfaceInsets.left, -w.mAttrs.surfaceInsets.top, - -w.mAttrs.surfaceInsets.right, -w.mAttrs.surfaceInsets.bottom); - } - if (!w.mSeamlesslyRotated) { - updateSurfaceWindowCrop(clipRect, mTmpFinalClipRect, recoveringMemory); + applyCrop(clipRect, finalClipRect, recoveringMemory); mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale, mDtDx * w.mVScale * mExtraVScale, mDsDy * w.mHScale * mExtraHScale, @@ -1571,8 +1549,7 @@ class WindowStateAnimator { mService.openSurfaceTransaction(); mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left, mWin.mFrame.top + top, false); - calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect); - updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, false); + applyCrop(null, null, false); } catch (RuntimeException e) { Slog.w(TAG, "Error positioning surface of " + mWin + " pos=(" + left + "," + top + ")", e); 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 fd1c91a85d36e..b10c27342a29a 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java @@ -27,6 +27,7 @@ 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.DisplayInfo; import android.view.Gravity; import android.view.IWindow; import android.view.WindowManager; @@ -53,6 +54,7 @@ public class WindowFrameTests { class WindowStateWithTask extends WindowState { final Task mTask; + boolean mDockedResizingForTest = false; WindowStateWithTask(WindowManager.LayoutParams attrs, Task t) { super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0); mTask = t; @@ -62,6 +64,11 @@ public class WindowFrameTests { Task getTask() { return mTask; } + + @Override + boolean isDockedResizing() { + return mDockedResizingForTest; + } }; class TaskWithBounds extends Task { @@ -92,6 +99,10 @@ public class WindowFrameTests { public void setUp() throws Exception { final Context context = InstrumentationRegistry.getTargetContext(); sWm = TestWindowManagerPolicy.getWindowManagerService(context); + + // Just any non zero value. + sWm.mSystemDecorLayer = 10000; + mWindowToken = new WindowToken(sWm, new Binder(), 0, false, sWm.getDefaultDisplayContentLocked()); mStubStack = new TaskStack(sWm, 0); @@ -274,7 +285,63 @@ public class WindowFrameTests { assertRect(w.mContentInsets, 0, 0, 100, 100); } - private WindowState createWindow(Task task, int width, int height) { + @Test + public void testCalculatePolicyCrop() { + final WindowStateWithTask w = createWindow( + new TaskWithBounds(null), FILL_PARENT, FILL_PARENT); + w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; + + final Rect pf = new Rect(0, 0, 1000, 1000); + final Rect df = pf; + final Rect of = df; + final Rect cf = new Rect(pf); + // Produce some insets + cf.top += 50; + cf.bottom -= 100; + final Rect vf = cf; + final Rect sf = vf; + // We use a decor content frame with insets to produce cropping. + Rect dcf = cf; + + final Rect policyCrop = new Rect(); + + w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null); + w.calculatePolicyCrop(policyCrop); + // If we were above system decor we wouldnt' get any cropping though + w.mLayer = sWm.mSystemDecorLayer + 1; + w.calculatePolicyCrop(policyCrop); + assertRect(policyCrop, 0, 0, 1000, 1000); + w.mLayer = 1; + dcf.setEmpty(); + // Likewise with no decor frame we would get no crop + w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null); + w.calculatePolicyCrop(policyCrop); + assertRect(policyCrop, 0, 0, 1000, 1000); + + // Now we set up a window which doesn't fill the entire decor frame. + // Normally it would be cropped to it's frame but in the case of docked resizing + // we need to account for the fact the windows surface will be made + // fullscreen and thus also make the crop fullscreen. + w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; + w.mAttrs.width = 500; + w.mAttrs.height = 500; + w.mRequestedWidth = 500; + w.mRequestedHeight = 500; + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf); + + w.calculatePolicyCrop(policyCrop); + // Normally the crop is shrunk from the decor frame + // to the computed window frame. + assertRect(policyCrop, 0, 0, 500, 500); + + w.mDockedResizingForTest = true; + w.calculatePolicyCrop(policyCrop); + // But if we are docked resizing it won't be. + final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo(); + assertRect(policyCrop, 0, 0, 1000, 1000); + } + + private WindowStateWithTask createWindow(Task task, int width, int height) { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); attrs.width = width; attrs.height = height;