Fix black holes and flickering in docked resizing
When we start a resize with the docked stack divider,
set the surface background to be full-screen, and use
the traditional surface clipping/positioning in window
manager to adjust the size. This ensures that we don't
have any black holes because of asynchronicity (except
at the very beginning, but this can be worked around
later), and the position of the right/bottom activity
is always in sync with the position of the divider.
Also fix a bug in NonClientDecorView where the first
request to draw was dropped (because the thread hasn't
started up yet), and the main thread was waiting for it
indefinitily.
Bug: 24507122
Change-Id: I623bd48d5be64fac2fba45241b84f265944d200d
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d598291..d146e5e 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -270,7 +270,7 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig) {
+ Configuration newConfig, Rect backDropRect) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0, outsets);
mCaller.sendMessage(msg);
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index cc4bcb6..9e478c1 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -47,7 +47,7 @@
void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
- in Configuration newConfig);
+ in Configuration newConfig, in Rect backDropFrame);
void moved(int newX, int newY);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index dddea21..514f88b 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -668,7 +668,7 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig) {
+ Configuration newConfig, Rect backDropRect) {
SurfaceView surfaceView = mSurfaceView.get();
if (surfaceView != null) {
if (DEBUG) Log.v(
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index faeb353..5715f65 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5647,7 +5647,7 @@
public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig) {
+ Configuration newConfig, Rect backDropFrame) {
if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
+ " contentInsets=" + contentInsets.toShortString()
+ " visibleInsets=" + visibleInsets.toShortString()
@@ -5658,7 +5658,7 @@
if (mDragResizing) {
synchronized (mWindowCallbacks) {
for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- mWindowCallbacks.get(i).onWindowSizeIsChanging(frame);
+ mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame);
}
}
}
@@ -6677,11 +6677,11 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig) {
+ Configuration newConfig, Rect backDropFrame) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
- visibleInsets, stableInsets, outsets, reportDraw, newConfig);
+ visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame);
}
}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 07bfce7..8699843 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -35,7 +35,8 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
- Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) {
+ Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
+ Rect backDropFrame) {
if (reportDraw) {
try {
mSession.finishDrawing(this);
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index de542b1..de6e228 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -372,7 +372,7 @@
@Override
public void onRequestDraw(boolean reportNextDraw) {
if (mFrameRendererThread != null) {
- mFrameRendererThread.onRequsetDraw(reportNextDraw);
+ mFrameRendererThread.onRequestDraw(reportNextDraw);
} else if (reportNextDraw) {
// If render thread is gone, just report immediately.
if (isAttachedToWindow()) {
@@ -517,7 +517,12 @@
public void run() {
try {
Looper.prepare();
- mChoreographer = Choreographer.getInstance();
+ synchronized (this) {
+ mChoreographer = Choreographer.getInstance();
+
+ // Draw at least once.
+ mChoreographer.postFrameCallback(this);
+ }
Looper.loop();
} finally {
releaseRenderer();
@@ -580,7 +585,7 @@
}
}
- public void onRequsetDraw(boolean reportNextDraw) {
+ public void onRequestDraw(boolean reportNextDraw) {
synchronized (this) {
mReportNextDraw = reportNextDraw;
mOldTargetRect.set(0, 0, 0, 0);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0c7256c..a29ba78 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -10117,6 +10117,10 @@
}
}
+ boolean isDockedStackResizingLocked() {
+ return getDefaultDisplayContentLocked().getDockedDividerController().isResizing();
+ }
+
static int dipToPixel(int dip, DisplayMetrics displayMetrics) {
return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8693fb5..7bee7fd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1836,15 +1836,15 @@
@Override
public void run() {
try {
- mClient.resized(frame, overscanInsets, contentInsets,
- visibleInsets, stableInsets, outsets, reportDraw, newConfig);
+ dispatchResized(frame, overscanInsets, contentInsets, visibleInsets,
+ stableInsets, outsets, reportDraw, newConfig);
} catch (RemoteException e) {
// Not a remote call, RemoteException won't be raised.
}
}
});
} else {
- mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
+ dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
outsets, reportDraw, newConfig);
}
@@ -1873,6 +1873,15 @@
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
+ private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
+ Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+ Configuration newConfig) throws RemoteException {
+ DisplayInfo displayInfo = getDisplayInfo();
+ mTmpRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+ mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
+ outsets, reportDraw, newConfig, inFreeformWorkspace() ? frame : mTmpRect);
+ }
+
public void registerFocusObserver(IWindowFocusObserver observer) {
synchronized(mService.mWindowMap) {
if (mFocusCallbacks == null) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 4b1d677..a26ef60 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1061,8 +1061,10 @@
}
final boolean fullscreen = w.isFullscreen(displayInfo.appWidth, displayInfo.appHeight);
+ final boolean isFreeformResizing =
+ w.isDragResizing() && !mService.isDockedStackResizingLocked();
final Rect clipRect = mTmpClipRect;
- if (w.isDragResizing()) {
+ if (isFreeformResizing) {
// When we're doing a drag-resizing, the surface is set up to cover full screen.
// Set the clip rect to be the same size so that we don't get any scaling.
clipRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
@@ -1091,7 +1093,7 @@
// animation for docked window, otherwise the animating window will be suddenly cut off.
if (!(mAnimator.mAnimating && w.inDockedWorkspace())) {
- adjustCropToStackBounds(w, clipRect);
+ adjustCropToStackBounds(w, clipRect, isFreeformResizing);
}
w.transformFromScreenToSurfaceSpace(clipRect);
@@ -1102,7 +1104,7 @@
}
}
- private void adjustCropToStackBounds(WindowState w, Rect clipRect) {
+ private void adjustCropToStackBounds(WindowState w, Rect clipRect, boolean isFreeformResizing) {
final AppWindowToken appToken = w.mAppToken;
final Task task = w.getTask();
// We don't apply the the stack bounds to the window that is being replaced, because it was
@@ -1115,10 +1117,9 @@
// When we resize we use the big surface approach, which means we can't trust the
// window frame bounds anymore. Instead, the window will be placed at 0, 0, but to avoid
// hardcoding it, we use surface coordinates.
- final boolean isResizing = w.isDragResizing();
- final int frameX = isResizing ? (int) mSurfaceController.getX() :
+ final int frameX = isFreeformResizing ? (int) mSurfaceController.getX() :
w.mFrame.left + mWin.mXOffset - w.getAttrs().surfaceInsets.left;
- final int frameY = isResizing ? (int) mSurfaceController.getY() :
+ final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;
// 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.
@@ -1151,9 +1152,13 @@
// so that we don't need to reallocate during the process. This also prevents
// buffer drops due to size mismatch.
final DisplayInfo displayInfo = w.getDisplayInfo();
- if (displayInfo != null && w.isDragResizing()) {
+
+ // In freeform resize mode, put surface at 0/0.
+ if (w.isDragResizing() && !mService.isDockedStackResizingLocked()) {
left = 0;
top = 0;
+ }
+ if (displayInfo != null && w.isDragResizing()) {
width = displayInfo.logicalWidth;
height = displayInfo.logicalHeight;
} else {