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

Commit 5df3b752 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Reduce unnecessary redraw when unlocking

The visible windows may be drawn earlier then the
timing to start requesting draw. And the starting
window should be used to cover the drawing time of
main window.

This may reduce hundreds of milliseconds of unlock
latency on slower devices.

Bug: 139522754
Bug: 140811348
Test: atest ActivityVisibilityTests
            WindowStateTests#testRequestDrawIfNeeded
Test: Use biometrics to unlock device with log
      WM_DEBUG_SCREEN_ON and WM_DEBUG_DRAW enabled.
      There shouldn't have multiple finishDrawingWindow
      from the same window.
Change-Id: I258fad2ef69b7d912ce6f799eb1f3adf29e38aec
parent 83a8a3bc
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;

import android.annotation.CallSuper;
@@ -70,7 +69,6 @@ import android.view.animation.Animation;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.SurfaceAnimator.Animatable;

@@ -2151,15 +2149,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
    }

    void waitForAllWindowsDrawn() {
        final WindowManagerPolicy policy = mWmService.mPolicy;
        forAllWindows(w -> {
            final boolean keyguard = policy.isKeyguardHostWindow(w.mAttrs);
            if (w.isVisibleLw() && (w.mActivityRecord != null || keyguard)) {
                w.mWinAnimator.mDrawState = DRAW_PENDING;
                // Force add to mResizingWindows.
                w.resetLastContentInsets();
                mWaitingForDrawn.add(w);
            }
            w.requestDrawIfNeeded(mWaitingForDrawn);
        }, true /* traverseTopToBottom */);
    }

+33 −0
Original line number Diff line number Diff line
@@ -1726,6 +1726,39 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                && isDrawnLw() && !isAnimating(TRANSITION | PARENTS);
    }

    /** @see WindowManagerInternal#waitForAllWindowsDrawn */
    void requestDrawIfNeeded(List<WindowState> outWaitingForDrawn) {
        if (!isVisible()) {
            return;
        }
        if (mActivityRecord != null) {
            if (mActivityRecord.allDrawn) {
                // The allDrawn of activity is reset when the visibility is changed to visible, so
                // the content should be ready if allDrawn is set.
                return;
            }
            if (mAttrs.type == TYPE_APPLICATION_STARTING) {
                if (isDrawnLw()) {
                    // Unnecessary to redraw a drawn starting window.
                    return;
                }
            } else if (mActivityRecord.startingWindow != null) {
                // If the activity has an active starting window, there is no need to wait for the
                // main window.
                return;
            }
        } else if (!mPolicy.isKeyguardHostWindow(mAttrs)) {
            return;
            // Always invalidate keyguard host window to make sure it shows the latest content
            // because its visibility may not be changed.
        }

        mWinAnimator.mDrawState = DRAW_PENDING;
        // Force add to {@link WindowManagerService#mResizingWindows}.
        resetLastContentInsets();
        outWaitingForDrawn.add(this);
    }

    @Override
    void onMovedByResize() {
        ProtoLog.d(WM_DEBUG_RESIZE, "onMovedByResize: Moving %s", this);
+29 −0
Original line number Diff line number Diff line
@@ -32,7 +32,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;

@@ -81,7 +83,9 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * Tests for the {@link WindowState} class.
@@ -520,6 +524,31 @@ public class WindowStateTests extends WindowTestsBase {
        assertTrue(window.isVisibleByPolicy());
    }

    @Test
    public void testRequestDrawIfNeeded() {
        final WindowState startingApp = createWindow(null /* parent */,
                TYPE_BASE_APPLICATION, "startingApp");
        final WindowState startingWindow = createWindow(null /* parent */,
                TYPE_APPLICATION_STARTING, startingApp.mToken, "starting");
        startingApp.mActivityRecord.startingWindow = startingWindow;
        final WindowState keyguardHostWindow = mStatusBarWindow;
        final WindowState allDrawnApp = mAppWindow;
        allDrawnApp.mActivityRecord.allDrawn = true;

        // The waiting list is used to ensure the content is ready when turning on screen.
        final List<WindowState> outWaitingForDrawn = mDisplayContent.mWaitingForDrawn;
        final List<WindowState> visibleWindows = Arrays.asList(mChildAppWindowAbove,
                keyguardHostWindow, allDrawnApp, startingApp, startingWindow);
        visibleWindows.forEach(w -> {
            w.mHasSurface = true;
            w.requestDrawIfNeeded(outWaitingForDrawn);
        });

        // Keyguard host window should be always contained. The drawn app or app with starting
        // window are unnecessary to draw.
        assertEquals(Arrays.asList(keyguardHostWindow, startingWindow), outWaitingForDrawn);
    }

    @Test
    public void testGetTransformationMatrix() {
        final int PARENT_WINDOW_OFFSET = 1;