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

Commit 746235af authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

Merge "Remove SurfaceFreezer" into main

parents 9405a43f 9f26aed8
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -5605,7 +5605,6 @@ final class ActivityRecord extends WindowToken {
        }

        mAtmService.mBackNavigationController.onAppVisibilityChanged(this, visible);
        onChildVisibilityRequested(visible);

        final DisplayContent displayContent = getDisplayContent();
        displayContent.mOpeningApps.remove(this);
+0 −12
Original line number Diff line number Diff line
@@ -80,7 +80,6 @@ import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
import android.view.Display;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.WindowManager;
@@ -252,7 +251,6 @@ public class AppTransitionController {
        // Check if there is any override
        if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) {
            // Unfreeze the windows that were previously frozen for TaskFragment animation.
            unfreezeEmbeddedChangingWindows();
            overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
        }

@@ -545,16 +543,6 @@ public class AppTransitionController {
                : null;
    }

    private void unfreezeEmbeddedChangingWindows() {
        final ArraySet<WindowContainer> changingContainers = mDisplayContent.mChangingContainers;
        for (int i = changingContainers.size() - 1; i >= 0; i--) {
            final WindowContainer wc = changingContainers.valueAt(i);
            if (wc.isEmbedded()) {
                wc.mSurfaceFreezer.unfreeze(wc.getSyncTransaction());
            }
        }
    }

    private boolean transitionMayContainNonAppWindows(@TransitionOldType int transit) {
        // We don't want to have the client to animate any non-app windows.
        // Having {@code transit} of those types doesn't mean it will contain non-app windows, but
+3 −25
Original line number Diff line number Diff line
@@ -60,8 +60,6 @@ public class SurfaceAnimator {
    @VisibleForTesting
    SurfaceControl mLeash;
    @VisibleForTesting
    SurfaceFreezer.Snapshot mSnapshot;
    @VisibleForTesting
    final Animatable mAnimatable;
    @VisibleForTesting
    final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
@@ -165,7 +163,7 @@ public class SurfaceAnimator {
            @AnimationType int type,
            @Nullable OnAnimationFinishedCallback animationFinishedCallback,
            @Nullable Runnable animationCancelledCallback,
            @Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) {
            @Nullable AnimationAdapter snapshotAnim) {
        cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
        mAnimation = anim;
        mAnimationType = type;
@@ -177,7 +175,6 @@ public class SurfaceAnimator {
            cancelAnimation();
            return;
        }
        mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
        if (mLeash == null) {
            mLeash = createAnimationLeash(mAnimatable, surface, t, type,
                    mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
@@ -192,21 +189,13 @@ public class SurfaceAnimator {
            mAnimation.dump(pw, "");
            ProtoLog.d(WM_DEBUG_ANIM, "Animation start for %s, anim=%s", mAnimatable, sw);
        }
        if (snapshotAnim != null) {
            mSnapshot = freezer.takeSnapshotForAnimation();
            if (mSnapshot == null) {
                Slog.e(TAG, "No snapshot target to start animation on for " + mAnimatable);
                return;
            }
            mSnapshot.startAnimation(t, snapshotAnim, type);
        }
        setAnimatorPendingState(t);
    }

    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
            @AnimationType int type) {
        startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */,
                null /* animationCancelledCallback */, null /* snapshotAnim */, null /* freezer */);
                null /* animationCancelledCallback */, null /* snapshotAnim */);
    }

    /** Indicates that there are surface operations in the pending transaction. */
@@ -317,7 +306,6 @@ public class SurfaceAnimator {
        final OnAnimationFinishedCallback animationFinishedCallback =
                mSurfaceAnimationFinishedCallback;
        final Runnable animationCancelledCallback = mAnimationCancelledCallback;
        final SurfaceFreezer.Snapshot snapshot = mSnapshot;
        reset(t, false);
        if (animation != null) {
            if (forwardCancel) {
@@ -337,9 +325,6 @@ public class SurfaceAnimator {
        }

        if (forwardCancel) {
            if (snapshot != null) {
                snapshot.cancelAnimation(t, false /* restarting */);
            }
            if (leash != null) {
                t.remove(leash);
                mService.scheduleAnimationLocked();
@@ -352,12 +337,6 @@ public class SurfaceAnimator {
        mAnimation = null;
        mSurfaceAnimationFinishedCallback = null;
        mAnimationType = ANIMATION_TYPE_NONE;
        final SurfaceFreezer.Snapshot snapshot = mSnapshot;
        mSnapshot = null;
        if (snapshot != null) {
            // Reset the mSnapshot reference before calling the callback to prevent circular reset.
            snapshot.cancelAnimation(t, !destroyLeash);
        }
        if (mLeash == null) {
            return;
        }
@@ -597,8 +576,7 @@ public class SurfaceAnimator {
        void commitPendingTransaction();

        /**
         * Called when the animation leash is created. Note that this is also called by
         * {@link SurfaceFreezer}, so this doesn't mean we're about to start animating.
         * Called when the animation leash is created.
         *
         * @param t The transaction to use to apply any necessary changes.
         * @param leash The leash that was created.
+0 −303
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import static com.android.internal.protolog.WmProtoLogGroups.WM_SHOW_TRANSACTIONS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.util.Slog;
import android.view.SurfaceControl;
import android.window.ScreenCapture;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;

/**
 * This class handles "freezing" of an Animatable. The Animatable in question should implement
 * Freezable.
 *
 * The point of this is to enable WindowContainers to each be capable of freezing themselves.
 * Freezing means taking a snapshot and placing it above everything in the sub-hierarchy.
 * The "placing above" requires that a parent surface be inserted above the target surface so that
 * the target surface and the snapshot are siblings.
 *
 * The overall flow for a transition using this would be:
 * 1. Set transition and record animatable in mChangingApps
 * 2. Call {@link #freeze} to set-up the leashes and cover with a snapshot.
 * 3. When transition participants are ready, start SurfaceAnimator with this as a parameter
 * 4. SurfaceAnimator will then {@link #takeLeashForAnimation} instead of creating another leash.
 * 5. The animation system should eventually clean this up via {@link #unfreeze}.
 */
class SurfaceFreezer {

    private static final String TAG = "SurfaceFreezer";

    private final @NonNull Freezable mAnimatable;
    private final @NonNull WindowManagerService mWmService;
    @VisibleForTesting
    SurfaceControl mLeash;
    Snapshot mSnapshot = null;
    final Rect mFreezeBounds = new Rect();

    /**
     * @param animatable The object to animate.
     */
    SurfaceFreezer(@NonNull Freezable animatable, @NonNull WindowManagerService service) {
        mAnimatable = animatable;
        mWmService = service;
    }

    /**
     * Freeze the target surface. This is done by creating a leash (inserting a parent surface
     * above the target surface) and then taking a snapshot and placing it over the target surface.
     *
     * @param startBounds The original bounds (on screen) of the surface we are snapshotting.
     * @param relativePosition The related position of the snapshot surface to its parent.
     * @param freezeTarget The surface to take snapshot from. If {@code null}, we will take a
     *                     snapshot from the {@link #mAnimatable} surface.
     */
    void freeze(SurfaceControl.Transaction t, Rect startBounds, Point relativePosition,
            @Nullable SurfaceControl freezeTarget) {
        reset(t);
        mFreezeBounds.set(startBounds);

        mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(),
                t, ANIMATION_TYPE_SCREEN_ROTATION, startBounds.width(), startBounds.height(),
                relativePosition.x, relativePosition.y, false /* hidden */,
                mWmService.mTransactionFactory);
        mAnimatable.onAnimationLeashCreated(t, mLeash);

        freezeTarget = freezeTarget != null ? freezeTarget : mAnimatable.getFreezeSnapshotTarget();
        if (freezeTarget != null) {
            ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBufferInner(
                    freezeTarget, startBounds);
            final HardwareBuffer buffer = screenshotBuffer == null ? null
                    : screenshotBuffer.getHardwareBuffer();
            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;
            }
            mSnapshot = new Snapshot(t, screenshotBuffer, mLeash);
        }
    }

    /**
     * Used by {@link SurfaceAnimator}. This "transfers" the leash to be used for animation.
     * By transferring the leash, this will no longer try to clean-up the leash when finished.
     */
    SurfaceControl takeLeashForAnimation() {
        SurfaceControl out = mLeash;
        mLeash = null;
        return out;
    }

    /**
     * Used by {@link SurfaceAnimator}. This "transfers" the snapshot leash to be used for
     * animation. By transferring the leash, this will no longer try to clean-up the leash when
     * finished.
     */
    @Nullable
    Snapshot takeSnapshotForAnimation() {
        final Snapshot out = mSnapshot;
        mSnapshot = null;
        return out;
    }

    /**
     * Clean-up the snapshot and remove leash. If the leash was taken, this just cleans-up the
     * snapshot.
     */
    void unfreeze(SurfaceControl.Transaction t) {
        unfreezeInner(t);
        mAnimatable.onUnfrozen();
    }

    private void unfreezeInner(SurfaceControl.Transaction t) {
        if (mSnapshot != null) {
            mSnapshot.cancelAnimation(t, false /* restarting */);
            mSnapshot = null;
        }
        if (mLeash == null) {
            return;
        }
        SurfaceControl leash = mLeash;
        mLeash = null;
        final boolean scheduleAnim = SurfaceAnimator.removeLeash(t, mAnimatable, leash,
                true /* destroy */);
        if (scheduleAnim) {
            mWmService.scheduleAnimationLocked();
        }
    }

    /** Resets the snapshot before taking another one if the animation hasn't been started yet. */
    private void reset(SurfaceControl.Transaction t) {
        // Those would have been taken by the SurfaceAnimator if the animation has been started, so
        // we can remove the leash directly.
        // No need to reset the mAnimatable leash, as this is called before a new animation leash is
        // created, so another #onAnimationLeashCreated will be called.
        if (mSnapshot != null) {
            mSnapshot.destroy(t);
            mSnapshot = null;
        }
        if (mLeash != null) {
            t.remove(mLeash);
            mLeash = null;
        }
    }

    void setLayer(SurfaceControl.Transaction t, int layer) {
        if (mLeash != null) {
            t.setLayer(mLeash, layer);
        }
    }

    void setRelativeLayer(SurfaceControl.Transaction t, SurfaceControl relativeTo, int layer) {
        if (mLeash != null) {
            t.setRelativeLayer(mLeash, relativeTo, layer);
        }
    }

    boolean hasLeash() {
        return mLeash != null;
    }

    private static ScreenCapture.ScreenshotHardwareBuffer createSnapshotBuffer(
            @NonNull SurfaceControl target, @Nullable Rect bounds) {
        Rect cropBounds = null;
        if (bounds != null) {
            cropBounds = new Rect(bounds);
            cropBounds.offsetTo(0, 0);
        }
        ScreenCapture.LayerCaptureArgs captureArgs =
                new ScreenCapture.LayerCaptureArgs.Builder(target)
                        .setSourceCrop(cropBounds)
                        .setCaptureSecureLayers(true)
                        .setAllowProtected(true)
                        .build();
        return ScreenCapture.captureLayers(captureArgs);
    }

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

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

    class Snapshot {
        private SurfaceControl mSurfaceControl;
        private AnimationAdapter mAnimation;

        /**
         * @param t Transaction to create the thumbnail in.
         * @param screenshotBuffer A thumbnail or placeholder for thumbnail to initialize with.
         */
        Snapshot(SurfaceControl.Transaction t,
                ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
            GraphicBuffer graphicBuffer = createFromHardwareBufferInner(screenshotBuffer);

            mSurfaceControl = mAnimatable.makeAnimationLeash()
                    .setName("snapshot anim: " + mAnimatable.toString())
                    .setFormat(PixelFormat.TRANSLUCENT)
                    .setParent(parent)
                    .setSecure(screenshotBuffer.containsSecureLayers())
                    .setCallsite("SurfaceFreezer.Snapshot")
                    .setBLASTLayer()
                    .build();

            ProtoLog.i(WM_SHOW_TRANSACTIONS, "  THUMBNAIL %s: CREATE", mSurfaceControl);

            t.setBuffer(mSurfaceControl, graphicBuffer);
            t.setColorSpace(mSurfaceControl, screenshotBuffer.getColorSpace());
            t.show(mSurfaceControl);

            // We parent the thumbnail to the container, and just place it on top of anything else
            // in the container.
            t.setLayer(mSurfaceControl, Integer.MAX_VALUE);
        }

        void destroy(SurfaceControl.Transaction t) {
            if (mSurfaceControl == null) {
                return;
            }
            t.remove(mSurfaceControl);
            mSurfaceControl = null;
        }

        /**
         * Starts an animation.
         *
         * @param anim The object that bridges the controller, {@link SurfaceAnimator}, with the
         *             component responsible for running the animation. It runs the animation with
         *             {@link AnimationAdapter#startAnimation} once the hierarchy with
         *             the Leash has been set up.
         */
        void startAnimation(SurfaceControl.Transaction t, AnimationAdapter anim, int type) {
            cancelAnimation(t, true /* restarting */);
            mAnimation = anim;
            if (mSurfaceControl == null) {
                cancelAnimation(t, false /* restarting */);
                return;
            }
            mAnimation.startAnimation(mSurfaceControl, t, type, (typ, ani) -> { });
        }

        /**
         * Cancels the animation, and resets the leash.
         *
         * @param t The transaction to use for all cancelling surface operations.
         * @param restarting Whether we are restarting the animation.
         */
        void cancelAnimation(SurfaceControl.Transaction t, boolean restarting) {
            final SurfaceControl leash = mSurfaceControl;
            final AnimationAdapter animation = mAnimation;
            mAnimation = null;
            if (animation != null) {
                animation.onAnimationCancelled(leash);
            }
            if (!restarting) {
                destroy(t);
            }
        }
    }

    /** freezable */
    public interface Freezable extends SurfaceAnimator.Animatable {
        /**
         * @return The surface to take a snapshot of. If this returns {@code null}, no snapshot
         *         will be generated (but the rest of the freezing logic will still happen).
         */
        @Nullable SurfaceControl getFreezeSnapshotTarget();

        /** Called when the {@link #unfreeze(SurfaceControl.Transaction)} is called. */
        void onUnfrozen();
    }
}
+1 −29
Original line number Diff line number Diff line
@@ -52,11 +52,9 @@ import static android.view.SurfaceControl.METADATA_TASK_ID;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -75,7 +73,6 @@ import static com.android.server.wm.ActivityRecord.TRANSFER_SPLASH_SCREEN_COPYIN
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
@@ -161,13 +158,11 @@ import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.InsetsState;
import android.view.RemoteAnimationAdapter;
import android.view.SurfaceControl;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -2344,32 +2339,9 @@ class Task extends TaskFragment {
        mLastSurfaceSize.set(width, height);
    }

    @VisibleForTesting
    Point getLastSurfaceSize() {
        return mLastSurfaceSize;
    }

    @VisibleForTesting
    boolean isInChangeTransition() {
        return mSurfaceFreezer.hasLeash() || AppTransition.isChangeTransitOld(mTransit);
    }

    @Override
    public SurfaceControl getFreezeSnapshotTarget() {
        if (!mDisplayContent.mAppTransition.containsTransitRequest(TRANSIT_CHANGE)) {
            return null;
        }
        // Skip creating snapshot if this transition is controlled by a remote animator which
        // doesn't need it.
        final ArraySet<Integer> activityTypes = new ArraySet<>();
        activityTypes.add(getActivityType());
        final RemoteAnimationAdapter adapter =
                mDisplayContent.mAppTransitionController.getRemoteAnimationOverride(
                        this, TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE, activityTypes);
        if (adapter != null && !adapter.getChangeNeedsSnapshot()) {
            return null;
        }
        return getSurfaceControl();
        return AppTransition.isChangeTransitOld(mTransit);
    }

    @Override
Loading