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

Commit 74b561a1 authored by Andrii Kulian's avatar Andrii Kulian
Browse files

Track app visibility updates on the client

When client receives two consecutive app visibility updates
sometimes it might handle them in single traversal pass and
in ViewRootImpl#performTraversals it will not detect a
visibility change.
Server side in this case will be stuck waiting for relayout
call from the client and will not draw the app window. This
can also cause focus not being switched properly and WM
remain with no focused window.

Bug: 64517357
Test: android.server.cts.ActivityManagerPinnedStackTests
Test: #testEnterPipFromTaskWithMultipleActivities
Test: Run the test and check if there are no focused window logs
Change-Id: I714da72a881e2dee5cf8dafd62113fbb9f2f3f4d
parent f523c630
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -259,6 +259,9 @@ public final class ViewRootImpl implements ViewParent,
    // visibility to control drawing. The decor view visibility will get adjusted when the app get
    // stopped and that's when the app will stop drawing further frames.
    private boolean mForceDecorViewVisibility = false;
    // Used for tracking app visibility updates separately in case we get double change. This will
    // make sure that we always call relayout for the corresponding window.
    private boolean mAppVisibilityChanged;
    int mOrigWindowType = -1;

    /** Whether the window had focus during the most recent traversal. */
@@ -1058,6 +1061,7 @@ public final class ViewRootImpl implements ViewParent,
    void handleAppVisibility(boolean visible) {
        if (mAppVisible != visible) {
            mAppVisible = visible;
            mAppVisibilityChanged = true;
            scheduleTraversals();
            if (!mAppVisible) {
                WindowManagerGlobal.trimForeground();
@@ -1600,7 +1604,11 @@ public final class ViewRootImpl implements ViewParent,

        final int viewVisibility = getHostVisibility();
        final boolean viewVisibilityChanged = !mFirst
                && (mViewVisibility != viewVisibility || mNewSurfaceNeeded);
                && (mViewVisibility != viewVisibility || mNewSurfaceNeeded
                // Also check for possible double visibility update, which will make current
                // viewVisibility value equal to mViewVisibility and we may miss it.
                || mAppVisibilityChanged);
        mAppVisibilityChanged = false;
        final boolean viewUserVisibilityChanged = !mFirst &&
                ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));