diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d36371219ac0e..9679763b450c6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2834,6 +2834,8 @@ public class WindowManagerService extends IWindowManager.Stub } win.mRelayoutCalled = true; + win.mInRelayout = true; + final int oldVisibility = win.mViewVisibility; win.mViewVisibility = viewVisibility; if (DEBUG_SCREEN_ON) { @@ -2974,6 +2976,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_LAYOUT) { Slog.v(TAG_WM, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString()); } + win.mInRelayout = false; } if (configChanged) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index be27c82d61fce..ff95afc995b48 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -362,6 +362,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { */ boolean mRelayoutCalled; + boolean mInRelayout; + /** * If the application has called relayout() with changes that can * impact its window's size, we need to perform a layout pass on it @@ -1630,6 +1632,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { return task != null && task.inDockedWorkspace(); } + // TODO: Strange usage of word workspace here and above. + boolean inPinnedWorkspace() { + final Task task = getTask(); + return task != null && task.inPinnedWorkspace(); + } + boolean isDockedInEffect() { final Task task = getTask(); return task != null && task.isDockedInEffect(); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 42eddd5a0b10e..9dae0f2d3262e 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1428,8 +1428,24 @@ class WindowStateAnimator { float extraHScale = (float) 1.0; float extraVScale = (float) 1.0; - mSurfaceResized = mSurfaceController.setSizeInTransaction( - mTmpSize.width(), mTmpSize.height(), recoveringMemory); + // Once relayout has been called at least once, we need to make sure + // we only resize the client surface during calls to relayout. For + // clients which use indeterminate measure specs (MATCH_PARENT), + // we may try and change their window size without a call to relayout. + // However, this would be unsafe, as the client may be in the middle + // of producing a frame at the old size, having just completed layout + // to find the surface size changed underneath it. + // + // TODO: For N we only apply this fix to the pinned workspace. As we + // aren't observing known issues here outside of PiP resizing. (Typically + // the other windows that use -1 are PopupWindows which aren't likely + // to be rendering while we resize). + if (!w.inPinnedWorkspace() || (!w.mRelayoutCalled || w.mInRelayout)) { + mSurfaceResized = mSurfaceController.setSizeInTransaction( + mTmpSize.width(), mTmpSize.height(), recoveringMemory); + } else { + mSurfaceResized = false; + } mForceScaleUntilResize = mForceScaleUntilResize && !mSurfaceResized; @@ -1437,10 +1453,12 @@ class WindowStateAnimator { if ((task != null && task.mStack.getForceScaleToCrop()) || mForceScaleUntilResize) { int hInsets = w.getAttrs().surfaceInsets.left + w.getAttrs().surfaceInsets.right; int vInsets = w.getAttrs().surfaceInsets.top + w.getAttrs().surfaceInsets.bottom; + float surfaceWidth = mSurfaceController.getWidth(); + float surfaceHeight = mSurfaceController.getHeight(); // We want to calculate the scaling based on the content area, not based on // the entire surface, so that we scale in sync with windows that don't have insets. - extraHScale = (mTmpClipRect.width() - hInsets) / (float)(mTmpSize.width() - hInsets); - extraVScale = (mTmpClipRect.height() - vInsets) / (float)(mTmpSize.height() - vInsets); + extraHScale = (mTmpClipRect.width() - hInsets) / (float)(surfaceWidth - hInsets); + extraVScale = (mTmpClipRect.height() - vInsets) / (float)(surfaceHeight - vInsets); // In the case of ForceScaleToCrop we scale entire tasks together, // and so we need to scale our offsets relative to the task bounds @@ -1462,7 +1480,7 @@ class WindowStateAnimator { // Since we are scaled to fit in our previously desired crop, we can now // expose the whole window in buffer space, and not risk extending // past where the system would have cropped us - mTmpClipRect.set(0, 0, mTmpSize.width(), mTmpSize.height()); + mTmpClipRect.set(0, 0, (int)surfaceWidth, (int)surfaceHeight); mTmpFinalClipRect.setEmpty(); // Various surfaces in the scaled stack may resize at different times. diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index af47369b181ec..9646a49b8a88f 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -454,6 +454,15 @@ class WindowSurfaceController { return mSurfaceY; } + float getWidth() { + return mSurfaceW; + } + + float getHeight() { + return mSurfaceH; + } + + public void dump(PrintWriter pw, String prefix, boolean dumpAll) { if (dumpAll) { pw.print(prefix); pw.print("mSurface="); pw.println(mSurfaceControl);