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

Commit eb22e8ed authored by Chong Zhang's avatar Chong Zhang
Browse files

Fixes for broken saved surface

- Reset and restore the visibility flags and hasSurface states when
  surface is saved or restored. When the surface is in saved stated,
  we have to make the rest of the system believe that the window has
  no surface.

- Set app windows to 'mExiting' when we start a transistion because
  window manager changes the visibility of the app. We can't rely on
  receiving a relayoutWindow from the app to invisible. We need to
  mark it exiting so that when the transition is done, the surfaces
  get removed (or saved if possible) promptly.

- We need to save the surface if the app token is the last one in
  a task, regardless of whether it's visible, this means the whole
  task is going into background. But if the app has another visible
  token on top of it, we don't need to save it. For example one
  activity launches another activity, in this case we don't want to
  save the surface of the activity on the bottom.

bug: 26573100

Change-Id: Id845f87b30cda1cebcc12ad2ac8dbf19a068a86e
parent b7a73360
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -302,6 +302,13 @@ class AppWindowToken extends WindowToken {
        }
    }

    void markSurfacesExiting() {
        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
            WindowState win = allAppWindows.get(i);
            win.mExiting = true;
        }
    }

    /**
     * Checks whether we should save surfaces for this app.
     *
@@ -329,15 +336,14 @@ class AppWindowToken extends WindowToken {
        if (!hasSavedSurface()) {
            return;
        }

        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG_WM,
                "Restoring saved surfaces: " + this + ", allDrawn=" + allDrawn);

        mAnimatingWithSavedSurface = true;
        for (int i = windows.size() - 1; i >= 0; i--) {
            WindowState ws = windows.get(i);
            ws.restoreSavedSurface();
        }
        // Mark the app allDrawn since it must be allDrawn at the time
        // it was first saved.
        allDrawn = true;
    }

    void destroySavedSurfaces() {
+1 −2
Original line number Diff line number Diff line
@@ -281,8 +281,7 @@ public class WindowAnimator {
            final int flags = win.mAttrs.flags;
            boolean canBeForceHidden = mPolicy.canBeForceHidden(win, win.mAttrs);
            boolean shouldBeForceHidden = shouldForceHide(win);
            if (winAnimator.mSurfaceController != null
                    && winAnimator.mSurfaceController.hasSurface()) {
            if (winAnimator.hasSurface()) {
                final boolean wasAnimating = winAnimator.mWasAnimating;
                final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
                winAnimator.mWasAnimating = nowAnimating;
+7 −19
Original line number Diff line number Diff line
@@ -2679,20 +2679,11 @@ public class WindowManagerService extends IWindowManager.Stub
            } else {
                winAnimator.mEnterAnimationPending = false;
                winAnimator.mEnteringAnimation = false;
                if (winAnimator.mSurfaceController != null &&
                        winAnimator.mSurfaceController.hasSurface()) {
                if (winAnimator.hasSurface() && !win.mExiting) {
                    if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Relayout invis " + win
                            + ": mExiting=" + win.mExiting);
                    // If we are using a saved surface to do enter animation, just let the
                    // animation run and don't destroy the surface. This could happen when
                    // the app sets visibility to invisible for the first time after resume,
                    // or when the user exits immediately after a resume. In both cases, we
                    // don't want to destroy the saved surface.
                    // If we are not currently running the exit animation, we
                    // need to see about starting one.
                    final boolean notExitingOrAnimating =
                            !win.mExiting && !win.isAnimatingWithSavedSurface();
                    result |= notExitingOrAnimating ? RELAYOUT_RES_SURFACE_CHANGED : 0;
                    // We don't want to animate visibility of windows which are pending
                    // replacement. In the case of activity relaunch child windows
                    // could request visibility changes as they are detached from the main
@@ -2700,11 +2691,11 @@ public class WindowManagerService extends IWindowManager.Stub
                    // these visibility changes though, we would cause a visual glitch
                    // hiding the window before it's replacement was available.
                    // So we just do nothing on our side.
                    if (notExitingOrAnimating && win.mWillReplaceWindow == false) {
                        focusMayChange = tryStartingAnimation(win, winAnimator, isDefaultDisplay,
                                focusMayChange);

                    if (!win.mWillReplaceWindow) {
                        focusMayChange = tryStartExitingAnimation(
                                win, winAnimator, isDefaultDisplay, focusMayChange);
                    }
                    result |= RELAYOUT_RES_SURFACE_CHANGED;
                }

                outSurface.release();
@@ -2787,7 +2778,7 @@ public class WindowManagerService extends IWindowManager.Stub
        return result;
    }

    private boolean tryStartingAnimation(WindowState win, WindowStateAnimator winAnimator,
    private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator,
            boolean isDefaultDisplay, boolean focusMayChange) {
        // Try starting an animation; if there isn't one, we
        // can destroy the surface right away.
@@ -4240,6 +4231,7 @@ public class WindowManagerService extends IWindowManager.Stub
                        }
                    }
                } else {
                    wtoken.markSurfacesExiting();
                    mClosingApps.add(wtoken);
                    wtoken.mEnteringAnimation = false;
                }
@@ -10278,10 +10270,6 @@ public class WindowManagerService extends IWindowManager.Stub
        return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
    }

    void scheduleSurfaceDestroy(WindowState win) {
        mDestroySurface.add(win);
    }

    @Override
    public void registerDockedStackListener(IDockedStackListener listener) {
        if (!checkCallingPermission(android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS,
+42 −18
Original line number Diff line number Diff line
@@ -1768,43 +1768,67 @@ final class WindowState implements WindowManagerPolicy.WindowState {
        return mAppToken != null && mAppToken.mAnimatingWithSavedSurface;
    }

    // Returns true if the surface is saved.
    boolean destroyOrSaveSurface() {
        Task task = getTask();
    private boolean shouldSaveSurface() {
        if (ActivityManager.isLowRamDeviceStatic()) {
            // Don't save surfaces on Svelte devices.
            mSurfaceSaved = false;
        } else if (task == null || task.inHomeStack()
                || task.getTopVisibleAppToken() != mAppToken) {
            return false;
        }

        if (isChildWindow()) {
            return false;
        }

        Task task = getTask();
        if (task == null || task.inHomeStack()) {
            // Don't save surfaces for home stack apps. These usually resume and draw
            // first frame very fast. Saving surfaces are mostly a waste of memory.
            return false;
        }

        final AppWindowToken taskTop = task.getTopVisibleAppToken();
        if (taskTop != null && taskTop != mAppToken) {
            // Don't save if the window is not the topmost window.
            mSurfaceSaved = false;
        } else if (isChildWindow()) {
            mSurfaceSaved = false;
        } else {
            mSurfaceSaved = mAppToken.shouldSaveSurface();
            return false;
        }
        if (mSurfaceSaved == false) {

        return mAppToken.shouldSaveSurface();
    }

    void destroyOrSaveSurface() {
        mSurfaceSaved = shouldSaveSurface();
        if (mSurfaceSaved) {
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                Slog.v(TAG, "Saving surface: " + this);
            }

            mWinAnimator.hide("saved surface");
            mWinAnimator.mDrawState = WindowStateAnimator.NO_SURFACE;
            setHasSurface(false);
        } else {
            mWinAnimator.destroySurfaceLocked();
        }
        return mSurfaceSaved;
    }

    public void destroySavedSurface() {
        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "Destroying saved surface: " + this);
        if (mSurfaceSaved) {
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                Slog.v(TAG, "Destroying saved surface: " + this);
            }
            mWinAnimator.destroySurfaceLocked();
        }
    }

    public boolean hasSavedSurface() {
        return mSurfaceSaved;
    }

    public void restoreSavedSurface() {
        mSurfaceSaved = false;
        setHasSurface(true);
        mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
            Slog.v(TAG, "Restoring saved surface: " + this);
        }
    }

    public boolean hasSavedSurface() {
        return mSurfaceSaved;
    }

    @Override
+8 −3
Original line number Diff line number Diff line
@@ -468,7 +468,7 @@ class WindowStateAnimator {
        if (WindowManagerService.localLOGV) Slog.v(
                TAG, "Exit animation finished in " + this
                + ": remove=" + mWin.mRemoveOnExit);
        if (mSurfaceController != null && mSurfaceController.hasSurface()) {
        if (hasSurface()) {
            mService.mDestroySurface.add(mWin);
            mWin.mDestroying = true;
            hide("finishExit");
@@ -734,6 +734,11 @@ class WindowStateAnimator {
        mTmpSize.bottom += scale * (attrs.surfaceInsets.top + attrs.surfaceInsets.bottom);
    }

    boolean hasSurface() {
        return !mWin.mSurfaceSaved
                && mSurfaceController != null && mSurfaceController.hasSurface();
    }

    void destroySurfaceLocked() {
        final AppWindowToken wtoken = mWin.mAppToken;
        if (wtoken != null) {
@@ -1229,7 +1234,7 @@ class WindowStateAnimator {

    void prepareSurfaceLocked(final boolean recoveringMemory) {
        final WindowState w = mWin;
        if (mSurfaceController == null || !mSurfaceController.hasSurface()) {
        if (!hasSurface()) {
            if (w.mOrientationChanging) {
                if (DEBUG_ORIENTATION) {
                    Slog.v(TAG, "Orientation change skips hidden " + w);
@@ -1311,7 +1316,7 @@ class WindowStateAnimator {
                    w.mOrientationChanging = false;
                }
            }
            if (mSurfaceController != null && mSurfaceController.hasSurface()) {
            if (hasSurface()) {
                w.mToken.hasVisible = true;
            }
        } else {
Loading