Fix 2 graphical issues for drag resizing.

1. There used to be double offset from the origin.

This is because we used to (in NYC) make the surface position to display
origin and draw content with a offset in the surface. However we lately
let the surface position be inherited from task surface position, so
there will be an offset from surface position and an offset from drawing
content in that surface.

To fix the bug I removed the offset in drawing content. That offset is
provided by WindowState#getBackdropFrame() so it just solved the issue
by moving frame to the origin.

2. Window quickly jumps when user starts drag resizing a window.

The reason is out of synchronization between surface insets change and
graphical buffer update. When user is drag resizing, we suppress window
shadow to save some graphical resources, which will consequently change
surface insets. Change in surface insets will cause the surface being
repositioned to reflect the new surface insets because window frame
doesn't change. However the content is still drawn at old location with
old surface insets for the first a few frames, so the content jumps to a
wrong location for a split second. This also happens when users stop
drag resizing.

I kept the old surface insets when user is resizing so there won't be
surface reposition at the beginning and end of drag resizing, but still
suppress the shadow by adjusting the elevation of DecorView.

Also fixed a synchronization issue we found in BackdropFrameRenderer,
and cleaned up code in it.

Bug: 113254346
Test: Manual tests show drag resizing for both freeform and split screen
works.
Change-Id: I42349f88f14af35fac7c65e784462b5f2e1a71c7
This commit is contained in:
Garfield Tan
2018-10-16 17:09:49 -07:00
parent 1d63e024de
commit fbd8ea649f
4 changed files with 58 additions and 42 deletions

View File

@@ -2316,10 +2316,12 @@ public final class ViewRootImpl implements ViewParent,
mResizeMode = freeformResizing
? RESIZE_MODE_FREEFORM
: RESIZE_MODE_DOCKED_DIVIDER;
final boolean backdropSizeMatchesFrame =
mWinFrame.width() == mPendingBackDropFrame.width()
&& mWinFrame.height() == mPendingBackDropFrame.height();
// TODO: Need cutout?
startDragResizing(mPendingBackDropFrame,
mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
mPendingStableInsets, mResizeMode);
startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame,
mPendingVisibleInsets, mPendingStableInsets, mResizeMode);
} else {
// We shouldn't come here, but if we come we should end the resize.
endDragResizing();

View File

@@ -69,7 +69,6 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
private ColorDrawable mNavigationBarColor;
private boolean mOldFullscreen;
private boolean mFullscreen;
private final int mResizeMode;
private final Rect mOldSystemInsets = new Rect();
private final Rect mOldStableInsets = new Rect();
private final Rect mSystemInsets = new Rect();
@@ -79,7 +78,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
Drawable userCaptionBackgroundDrawable, int statusBarColor, int navigationBarColor,
boolean fullscreen, Rect systemInsets, Rect stableInsets, int resizeMode) {
boolean fullscreen, Rect systemInsets, Rect stableInsets) {
setName("ResizeFrame");
mRenderer = renderer;
@@ -100,7 +99,6 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
mStableInsets.set(stableInsets);
mOldSystemInsets.set(systemInsets);
mOldStableInsets.set(stableInsets);
mResizeMode = resizeMode;
// Kick off our draw thread.
start();
@@ -109,33 +107,35 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
void onResourcesLoaded(DecorView decorView, Drawable resizingBackgroundDrawable,
Drawable captionBackgroundDrawableDrawable, Drawable userCaptionBackgroundDrawable,
int statusBarColor, int navigationBarColor) {
mDecorView = decorView;
mResizingBackgroundDrawable = resizingBackgroundDrawable != null
&& resizingBackgroundDrawable.getConstantState() != null
? resizingBackgroundDrawable.getConstantState().newDrawable()
: null;
mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable != null
&& captionBackgroundDrawableDrawable.getConstantState() != null
? captionBackgroundDrawableDrawable.getConstantState().newDrawable()
: null;
mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable != null
&& userCaptionBackgroundDrawable.getConstantState() != null
? userCaptionBackgroundDrawable.getConstantState().newDrawable()
: null;
if (mCaptionBackgroundDrawable == null) {
mCaptionBackgroundDrawable = mResizingBackgroundDrawable;
}
if (statusBarColor != 0) {
mStatusBarColor = new ColorDrawable(statusBarColor);
addSystemBarNodeIfNeeded();
} else {
mStatusBarColor = null;
}
if (navigationBarColor != 0) {
mNavigationBarColor = new ColorDrawable(navigationBarColor);
addSystemBarNodeIfNeeded();
} else {
mNavigationBarColor = null;
synchronized (this) {
mDecorView = decorView;
mResizingBackgroundDrawable = resizingBackgroundDrawable != null
&& resizingBackgroundDrawable.getConstantState() != null
? resizingBackgroundDrawable.getConstantState().newDrawable()
: null;
mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable != null
&& captionBackgroundDrawableDrawable.getConstantState() != null
? captionBackgroundDrawableDrawable.getConstantState().newDrawable()
: null;
mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable != null
&& userCaptionBackgroundDrawable.getConstantState() != null
? userCaptionBackgroundDrawable.getConstantState().newDrawable()
: null;
if (mCaptionBackgroundDrawable == null) {
mCaptionBackgroundDrawable = mResizingBackgroundDrawable;
}
if (statusBarColor != 0) {
mStatusBarColor = new ColorDrawable(statusBarColor);
addSystemBarNodeIfNeeded();
} else {
mStatusBarColor = null;
}
if (navigationBarColor != 0) {
mNavigationBarColor = new ColorDrawable(navigationBarColor);
addSystemBarNodeIfNeeded();
} else {
mNavigationBarColor = null;
}
}
}
@@ -186,7 +186,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
* All resources of the renderer will be released. This function can be called from the
* the UI thread as well as the renderer thread.
*/
public void releaseRenderer() {
void releaseRenderer() {
synchronized (this) {
if (mRenderer != null) {
// Invalidate the current content bounds.
@@ -268,7 +268,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
* @param ySize The height of the content.
* @return true if a frame should be requested after the content is drawn; false otherwise.
*/
public boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) {
boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) {
synchronized (this) {
final boolean firstCall = mLastContentWidth == 0;
// The current content buffer is drawn here.
@@ -291,7 +291,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
}
}
public void onRequestDraw(boolean reportNextDraw) {
void onRequestDraw(boolean reportNextDraw) {
synchronized (this) {
mReportNextDraw = reportNextDraw;
mOldTargetRect.set(0, 0, 0, 0);
@@ -329,8 +329,8 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
return;
}
// Since the surface is spanning the entire screen, we have to add the start offset of
// the bounds to get to the surface location.
// Content may not be drawn at the surface origin, so we want to keep the offset when we're
// resizing it.
final int left = mLastXOffset + newBounds.left;
final int top = mLastYOffset + newBounds.top;
final int width = newBounds.width();
@@ -414,6 +414,8 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
}
void setUserCaptionBackgroundDrawable(Drawable userCaptionBackgroundDrawable) {
mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable;
synchronized (this) {
mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable;
}
}
}

View File

@@ -2093,7 +2093,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
getCurrentColor(mNavigationColorViewState), fullscreen, systemInsets,
stableInsets, resizeMode);
stableInsets);
// Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
// If we want to get the shadow shown while resizing, we would need to elevate a new
@@ -2229,7 +2229,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
// or it didn't change.
if ((wasAdjustedForStack || mElevationAdjustedForStack)
&& getElevation() != elevation) {
mWindow.setElevation(elevation);
if (!isResizing()) {
mWindow.setElevation(elevation);
} else {
// Just suppress the shadow when resizing, don't adjust surface insets because it'll
// cause a flicker when drag resize for freeform window starts. #onContentDrawn()
// will compensate the offset when passing to BackdropFrameRenderer.
setElevation(elevation);
}
}
}