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

Commit 92ff7c75 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Reset draw state after notifying invisible to activity window

This moves the concept of I69f893a19d6426710bb0b8b0e18f3d2664cb6412
to a more suitable place. Instead of resetting draw state when the
app becomes visible, it is more general when setting app window to
be invisible.

There are 2 cases that could benefit from this:
1. The computation ActivityRecord#updateReportedVisibilityLocked
depends on w.isDrawn(). So ActivityRecord#isReportedDrawn() won't
get stale draw state.

2. ActivityRecord#addStartingWindow checks w.isDrawn() to skip
adding starting window. So it can avoid missing starting window
when launching app again in a short time, e.g. return to home
and click the same app immediately.

Bug: 373023636
Test: atest ActivityRecordTests#testSetVisibility_visibleToInvisible
Flag: com.android.window.flags.reset_draw_state_on_client_invisible

Change-Id: I91ffbd5ce4d014feb667383fda404df23759be89
parent 8ac5a154
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -8,6 +8,16 @@ flag {
  bug: "232195501"
}

flag {
  name: "reset_draw_state_on_client_invisible"
  namespace: "windowing_frontend"
  description: "Reset draw state if the client is notified to be invisible"
  bug: "373023636"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
    name: "wait_for_transition_on_display_switch"
    namespace: "windowing_frontend"
+2 −1
Original line number Diff line number Diff line
@@ -5508,7 +5508,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                clearAllDrawn();
                // Reset the draw state in order to prevent the starting window to be immediately
                // dismissed when the app still has the surface.
                if (!isVisible() && !isClientVisible()) {
                if (!Flags.resetDrawStateOnClientInvisible()
                        && !isVisible() && !isClientVisible()) {
                    forAllWindows(w -> {
                        if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
                            w.mWinAnimator.resetDrawState();
+10 −0
Original line number Diff line number Diff line
@@ -3304,6 +3304,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                android.os.Process.killProcess(mSession.mPid);
            }
        }

        // Because the client is notified to be invisible, it should no longer be considered as
        // drawn state. This prevent the app from showing incomplete content if the app is
        // requested to be visible in a short time (e.g. before activity stopped).
        if (Flags.resetDrawStateOnClientInvisible() && !clientVisible && mActivityRecord != null
                && mWinAnimator.mDrawState == HAS_DRAWN) {
            mWinAnimator.resetDrawState();
            // Make sure the app can report drawn if it becomes visible again.
            forceReportingResized();
        }
    }

    void onStartFreezingScreen() {
+15 −6
Original line number Diff line number Diff line
@@ -3214,23 +3214,32 @@ public class ActivityRecordTests extends WindowTestsBase {
        assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
    }

    @SetupWindows(addWindows = W_ACTIVITY)
    @Test
    public void testSetVisibility_visibleToInvisible() {
        final ActivityRecord activity = new ActivityBuilder(mAtm)
                .setCreateTask(true).build();
        final TestTransitionPlayer player = registerTestTransitionPlayer();
        final ActivityRecord activity = mAppWindow.mActivityRecord;
        makeWindowVisibleAndDrawn(mAppWindow);
        // By default, activity is visible.
        assertTrue(activity.isVisible());
        assertTrue(activity.isVisibleRequested());
        assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
        assertTrue(mAppWindow.isDrawn());
        assertFalse(mAppWindow.setReportResizeHints());

        // Request the activity to be invisible. Since the visibility changes, app transition
        // animation should be applied on this activity.
        mDisplayContent.prepareAppTransition(0);
        activity.mTransitionController.requestCloseTransitionIfNeeded(activity);
        activity.setVisibility(false);
        assertTrue(activity.isVisible());
        assertFalse(activity.isVisibleRequested());
        assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity));
        assertTrue(activity.mDisplayContent.mClosingApps.contains(activity));

        player.start();
        mSetFlagsRule.enableFlags(Flags.FLAG_RESET_DRAW_STATE_ON_CLIENT_INVISIBLE);
        // ActivityRecord#commitVisibility(false) -> WindowState#sendAppVisibilityToClients().
        player.finish();
        assertFalse(activity.isVisible());
        assertFalse("Reset draw state after committing invisible", mAppWindow.isDrawn());
        assertTrue("Set pending redraw hint", mAppWindow.setReportResizeHints());
    }

    @Test