Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8dbd9ad6 authored by Chong Zhang's avatar Chong Zhang
Browse files

Fix missing frame or wrong frame position when resize starts

When multi-thread renderer is used, delay the report to draw to the
first doFrame in ResizeFrameThread. Otherwise we could unfreeze the
window before the frame is drawn.

Also when content draw bounds is updated for the first frame, let
content draw before ResizeFrameThread so that the bounds get applied.

bug: 24715185

Change-Id: I5485dc0be3eae24c555bcc31ee8f71523b68ca8d
parent c8b71bec
Loading
Loading
Loading
Loading
+49 −6
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.HashSet;

/**
@@ -238,6 +239,7 @@ public final class ViewRootImpl implements ViewParent,
    boolean mNewSurfaceNeeded;
    boolean mHasHadWindowFocus;
    boolean mLastWasImTarget;
    CountDownLatch mWindowDrawCountDown;

    boolean mIsDrawing;
    int mLastSystemUiVisibility;
@@ -436,6 +438,12 @@ public final class ViewRootImpl implements ViewParent,
        }
    }

    public void reportDrawFinish() {
        if (mWindowDrawCountDown != null) {
            mWindowDrawCountDown.countDown();
        }
    }

    // FIXME for perf testing only
    private boolean mProfile = false;

@@ -2419,6 +2427,17 @@ public final class ViewRootImpl implements ViewParent,

        if (mReportNextDraw) {
            mReportNextDraw = false;

            // if we're using multi-thread renderer, wait for the window frame draws
            if (mWindowDrawCountDown != null) {
                try {
                    mWindowDrawCountDown.await();
                } catch (InterruptedException e) {
                    Log.e(TAG, "Window redraw count down interruped!");
                }
                mWindowDrawCountDown = null;
            }

            if (mAttachInfo.mHardwareRenderer != null) {
                mAttachInfo.mHardwareRenderer.fence();
            }
@@ -2568,13 +2587,13 @@ public final class ViewRootImpl implements ViewParent,

                // Stage the content drawn size now. It will be transferred to the renderer
                // shortly before the draw commands get send to the renderer.
                synchronized (mWindowCallbacks) {
                    for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
                        mWindowCallbacks.get(i).onContentDraw(mWindowAttributes.surfaceInsets.left,
                                mWindowAttributes.surfaceInsets.top, mWidth, mHeight);
                    }
                }
                final boolean updated = updateContentDrawBounds();

                mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);

                if (updated) {
                    requestDrawWindow();
                }
            } else {
                // If we get here with a disabled & requested hardware renderer, something went
                // wrong (an invalidate posted right before we destroyed the hardware surface
@@ -6796,6 +6815,30 @@ public final class ViewRootImpl implements ViewParent,
        }
    }

    private boolean updateContentDrawBounds() {
        boolean updated = false;
        synchronized (mWindowCallbacks) {
            for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
                updated |= mWindowCallbacks.get(i).onContentDrawn(
                        mWindowAttributes.surfaceInsets.left,
                        mWindowAttributes.surfaceInsets.top,
                        mWidth, mHeight);
            }
        }
        return updated | (mDragResizing && mReportNextDraw);
    }

    private void requestDrawWindow() {
        if (mReportNextDraw) {
            mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
        }
        synchronized (mWindowCallbacks) {
            for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
                mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
            }
        }
    }

    /**
     * Class for managing the accessibility interaction connection
     * based on the global accessibility state.
+9 −2
Original line number Diff line number Diff line
@@ -49,7 +49,14 @@ public interface WindowCallbacks {
    void onWindowDragResizeEnd();

    /**
     * The content will now be drawn to these bounds.
     * The content will now be drawn to these bounds. Returns true if
     * a draw should be requested after the next content draw.
     */
    void onContentDraw(int offsetX, int offsetY, int sizeX, int sizeY);
    boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY);

    /**
     * Called to request the window to draw one frame.
     * @param reportNextDraw Whether it should report when the requested draw finishes.
     */
    void onRequestDraw(boolean reportNextDraw);
}
+45 −8
Original line number Diff line number Diff line
@@ -355,9 +355,22 @@ public class NonClientDecorView extends LinearLayout
    }

    @Override
    public void onContentDraw(int xOffset, int yOffset, int xSize, int ySize) {
    public boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) {
        if (mFrameRendererThread == null) {
            return false;
        }
        return mFrameRendererThread.onContentDrawn(xOffset, yOffset, xSize, ySize);
    }

    @Override
    public void onRequestDraw(boolean reportNextDraw) {
        if (mFrameRendererThread != null) {
            mFrameRendererThread.onContentDraw(xOffset, yOffset, xSize, ySize);
            mFrameRendererThread.onRequsetDraw(reportNextDraw);
        } else if (reportNextDraw) {
            // If render thread is gone, just report immediately.
            if (isAttachedToWindow()) {
                getViewRootImpl().reportDrawFinish();
            }
        }
    }

@@ -423,6 +436,9 @@ public class NonClientDecorView extends LinearLayout
        private int mLastXOffset;
        private int mLastYOffset;

        // Whether to report when next frame is drawn or not.
        private boolean mReportNextDraw;

        ResizeFrameThread(ThreadedRenderer renderer, Rect initialBounds) {
            setName("ResizeFrame");
            mRenderer = renderer;
@@ -518,12 +534,13 @@ public class NonClientDecorView extends LinearLayout
        public void doFrame(long frameTimeNanos) {
            synchronized (this) {
                if (mRenderer == null) {
                    reportDrawIfNeeded();
                    // Tell the looper to stop. We are done.
                    Looper.myLooper().quit();
                    return;
                }
                mNewTargetRect.set(mTargetRect);
                if (!mNewTargetRect.equals(mOldTargetRect)) {
                if (!mNewTargetRect.equals(mOldTargetRect) || mReportNextDraw) {
                    mOldTargetRect.set(mNewTargetRect);
                    changeWindowSizeLocked(mNewTargetRect);
                }
@@ -538,8 +555,9 @@ public class NonClientDecorView extends LinearLayout
         * @param yOffset The y offset where the content is drawn to.
         * @param xSize The width size of the content. This should not be 0.
         * @param ySize The height of the content.
         * @return true if a frame should be requested after the content is drawn; false otherwise.
         */
        public void onContentDraw(int xOffset, int yOffset, int xSize, int ySize) {
        public boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) {
            synchronized (this) {
                final boolean firstCall = mLastContentWidth == 0;
                // The current content buffer is drawn here.
@@ -555,12 +573,17 @@ public class NonClientDecorView extends LinearLayout
                        mLastYOffset + mLastCaptionHeight + mLastContentHeight);
                // If this was the first call and changeWindowSizeLocked got already called prior
                // to us, we should re-issue a changeWindowSizeLocked now.
                if (firstCall && (mLastCaptionHeight != 0 || !mShowDecor)) {
                return firstCall && (mLastCaptionHeight != 0 || !mShowDecor);
            }
        }

        public void onRequsetDraw(boolean reportNextDraw) {
            synchronized (this) {
                mReportNextDraw = reportNextDraw;
                mOldTargetRect.set(0, 0, 0, 0);
                pingRenderLocked();
            }
        }
        }

        /**
         * Resizing the frame to fit the new window size.
@@ -617,6 +640,20 @@ public class NonClientDecorView extends LinearLayout
            // We need to render both rendered nodes explicitly.
            mRenderer.drawRenderNode(mFrameNode);
            mRenderer.drawRenderNode(mBackdropNode);

            reportDrawIfNeeded();
        }

        /**
         * Notify view root that a frame has been drawn by us, if it has requested so.
         */
        private void reportDrawIfNeeded() {
            if (mReportNextDraw) {
                if (isAttachedToWindow()) {
                    getViewRootImpl().reportDrawFinish();
                }
                mReportNextDraw = false;
            }
        }

        /**