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

Commit e32aa4fd authored by Chris Li's avatar Chris Li
Browse files

Fix NPE for animate frozen snapshot

Before, the snapshot can be null if the window is unfreezed but not
removed from the display changing list, or when it fails to take
screenshot (like because the display is not ready). Now, we make sure to
remove the window from the changing list in such cases.

Fix: 204400505
Test: atest WmTests:WindowContainerTests
Change-Id: I517232fc2ec689680a00b499495a4bad5a0d5f15
parent 8f7d2534
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -188,6 +188,10 @@ class SurfaceAnimator {
        mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
        mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
        if (snapshotAnim != null) {
        if (snapshotAnim != null) {
            mSnapshot = freezer.takeSnapshotForAnimation();
            mSnapshot = freezer.takeSnapshotForAnimation();
            if (mSnapshot == null) {
                Slog.e(TAG, "No snapshot target to start animation on for " + mAnimatable);
                return;
            }
            mSnapshot.startAnimation(t, snapshotAnim, type);
            mSnapshot.startAnimation(t, snapshotAnim, type);
        }
        }
    }
    }
+31 −8
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.hardware.HardwareBuffer;
import android.util.Slog;
import android.view.SurfaceControl;
import android.view.SurfaceControl;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
@@ -49,8 +50,10 @@ import com.android.internal.protolog.common.ProtoLog;
 */
 */
class SurfaceFreezer {
class SurfaceFreezer {


    private final Freezable mAnimatable;
    private static final String TAG = "SurfaceFreezer";
    private final WindowManagerService mWmService;

    private final @NonNull Freezable mAnimatable;
    private final @NonNull WindowManagerService mWmService;
    @VisibleForTesting
    @VisibleForTesting
    SurfaceControl mLeash;
    SurfaceControl mLeash;
    Snapshot mSnapshot = null;
    Snapshot mSnapshot = null;
@@ -59,7 +62,7 @@ class SurfaceFreezer {
    /**
    /**
     * @param animatable The object to animate.
     * @param animatable The object to animate.
     */
     */
    SurfaceFreezer(Freezable animatable, WindowManagerService service) {
    SurfaceFreezer(@NonNull Freezable animatable, @NonNull WindowManagerService service) {
        mAnimatable = animatable;
        mAnimatable = animatable;
        mWmService = service;
        mWmService = service;
    }
    }
@@ -86,11 +89,14 @@ class SurfaceFreezer {


        freezeTarget = freezeTarget != null ? freezeTarget : mAnimatable.getFreezeSnapshotTarget();
        freezeTarget = freezeTarget != null ? freezeTarget : mAnimatable.getFreezeSnapshotTarget();
        if (freezeTarget != null) {
        if (freezeTarget != null) {
            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBuffer(
            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBufferInner(
                    freezeTarget, startBounds);
                    freezeTarget, startBounds);
            final HardwareBuffer buffer = screenshotBuffer == null ? null
            final HardwareBuffer buffer = screenshotBuffer == null ? null
                    : screenshotBuffer.getHardwareBuffer();
                    : screenshotBuffer.getHardwareBuffer();
            if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
            if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
                // This can happen when display is not ready.
                Slog.w(TAG, "Failed to capture screenshot for " + mAnimatable);
                unfreeze(t);
                return;
                return;
            }
            }
            mSnapshot = new Snapshot(t, screenshotBuffer, mLeash);
            mSnapshot = new Snapshot(t, screenshotBuffer, mLeash);
@@ -124,6 +130,11 @@ class SurfaceFreezer {
     * snapshot.
     * snapshot.
     */
     */
    void unfreeze(SurfaceControl.Transaction t) {
    void unfreeze(SurfaceControl.Transaction t) {
        unfreezeInner(t);
        mAnimatable.onUnfrozen();
    }

    private void unfreezeInner(SurfaceControl.Transaction t) {
        if (mSnapshot != null) {
        if (mSnapshot != null) {
            mSnapshot.cancelAnimation(t, false /* restarting */);
            mSnapshot.cancelAnimation(t, false /* restarting */);
            mSnapshot = null;
            mSnapshot = null;
@@ -188,6 +199,18 @@ class SurfaceFreezer {
        return SurfaceControl.captureLayers(captureArgs);
        return SurfaceControl.captureLayers(captureArgs);
    }
    }


    @VisibleForTesting
    SurfaceControl.ScreenshotHardwareBuffer createSnapshotBufferInner(
            SurfaceControl target, Rect bounds) {
        return createSnapshotBuffer(target, bounds);
    }

    @VisibleForTesting
    GraphicBuffer createFromHardwareBufferInner(
            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer) {
        return GraphicBuffer.createFromHardwareBuffer(screenshotBuffer.getHardwareBuffer());
    }

    class Snapshot {
    class Snapshot {
        private SurfaceControl mSurfaceControl;
        private SurfaceControl mSurfaceControl;
        private AnimationAdapter mAnimation;
        private AnimationAdapter mAnimation;
@@ -198,10 +221,7 @@ class SurfaceFreezer {
         */
         */
        Snapshot(SurfaceControl.Transaction t,
        Snapshot(SurfaceControl.Transaction t,
                SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
                SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
            // We can't use a delegating constructor since we need to
            GraphicBuffer graphicBuffer = createFromHardwareBufferInner(screenshotBuffer);
            // reference this::onAnimationFinished
            GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(
                    screenshotBuffer.getHardwareBuffer());


            mSurfaceControl = mAnimatable.makeAnimationLeash()
            mSurfaceControl = mAnimatable.makeAnimationLeash()
                    .setName("snapshot anim: " + mAnimatable.toString())
                    .setName("snapshot anim: " + mAnimatable.toString())
@@ -275,5 +295,8 @@ class SurfaceFreezer {
         *         will be generated (but the rest of the freezing logic will still happen).
         *         will be generated (but the rest of the freezing logic will still happen).
         */
         */
        @Nullable SurfaceControl getFreezeSnapshotTarget();
        @Nullable SurfaceControl getFreezeSnapshotTarget();

        /** Called when the {@link #unfreeze(SurfaceControl.Transaction)} is called. */
        void onUnfrozen();
    }
    }
}
}
+7 −4
Original line number Original line Diff line number Diff line
@@ -614,7 +614,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        final DisplayContent dc = getDisplayContent();
        final DisplayContent dc = getDisplayContent();
        if (dc != null) {
        if (dc != null) {
            mSurfaceFreezer.unfreeze(getSyncTransaction());
            mSurfaceFreezer.unfreeze(getSyncTransaction());
            dc.mChangingContainers.remove(this);
        }
        }
        while (!mChildren.isEmpty()) {
        while (!mChildren.isEmpty()) {
            final E child = mChildren.peekLast();
            final E child = mChildren.peekLast();
@@ -1067,9 +1066,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        // part of a change transition.
        // part of a change transition.
        if (!visible) {
        if (!visible) {
            mSurfaceFreezer.unfreeze(getSyncTransaction());
            mSurfaceFreezer.unfreeze(getSyncTransaction());
            if (mDisplayContent != null) {
                mDisplayContent.mChangingContainers.remove(this);
            }
        }
        }
        WindowContainer parent = getParent();
        WindowContainer parent = getParent();
        if (parent != null) {
        if (parent != null) {
@@ -2647,6 +2643,13 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        return getSurfaceControl();
        return getSurfaceControl();
    }
    }


    @Override
    public void onUnfrozen() {
        if (mDisplayContent != null) {
            mDisplayContent.mChangingContainers.remove(this);
        }
    }

    @Override
    @Override
    public Builder makeAnimationLeash() {
    public Builder makeAnimationLeash() {
        return makeSurface().setContainerLayer();
        return makeSurface().setContainerLayer();
+1 −0
Original line number Original line Diff line number Diff line
@@ -419,6 +419,7 @@ public class AppTransitionTests extends WindowTestsBase {
        task.getBounds(taskBounds);
        task.getBounds(taskBounds);
        taskFragment.setBounds(0, 0, taskBounds.right / 2, taskBounds.bottom);
        taskFragment.setBounds(0, 0, taskBounds.right / 2, taskBounds.bottom);
        spyOn(taskFragment);
        spyOn(taskFragment);
        mockSurfaceFreezerSnapshot(taskFragment.mSurfaceFreezer);


        assertTrue(mDc.mChangingContainers.isEmpty());
        assertTrue(mDc.mChangingContainers.isEmpty());
        assertFalse(mDc.mAppTransition.isTransitionSet());
        assertFalse(mDc.mAppTransition.isTransitionSet());
+1 −0
Original line number Original line Diff line number Diff line
@@ -82,6 +82,7 @@ public class TaskFragmentTest extends WindowTestsBase {


    @Test
    @Test
    public void testStartChangeTransition_resetSurface() {
    public void testStartChangeTransition_resetSurface() {
        mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer);
        final Rect startBounds = new Rect(0, 0, 1000, 1000);
        final Rect startBounds = new Rect(0, 0, 1000, 1000);
        final Rect endBounds = new Rect(500, 500, 1000, 1000);
        final Rect endBounds = new Rect(500, 500, 1000, 1000);
        mTaskFragment.setBounds(startBounds);
        mTaskFragment.setBounds(startBounds);
Loading