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

Commit 78c357c6 authored by Winson Chung's avatar Winson Chung Committed by Automerger Merge Worker
Browse files

Merge "Fix flash when canceling the recents animation with a screenshot" into sc-dev am: 1da53a25

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15090191

Change-Id: I695bf5b7341bfc108e766bdfaeb4ab0e9e1852fb
parents 9105de28 1da53a25
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -279,11 +279,6 @@ public abstract class ActivityTaskManagerInternal {
     */
    public abstract boolean isRecentsComponentHomeActivity(int userId);

    /**
     * Cancels any currently running recents animation.
     */
    public abstract void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition);

    /**
     * Returns true if the app can close system dialogs. Otherwise it either throws a {@link
     * SecurityException} or returns false with a logcat message depending on whether the app
+0 −5
Original line number Diff line number Diff line
@@ -5255,11 +5255,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
            return getRecentTasks().isRecentsComponentHomeActivity(userId);
        }

        @Override
        public void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition) {
            ActivityTaskManagerService.this.cancelRecentsAnimation(restoreHomeRootTaskPosition);
        }

        @Override
        public boolean checkCanCloseSystemDialogs(int pid, int uid, @Nullable String packageName) {
            return ActivityTaskManagerService.this.checkCanCloseSystemDialogs(pid, uid,
+93 −60
Original line number Diff line number Diff line
@@ -36,8 +36,10 @@ import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.app.WindowConfiguration;
import android.graphics.GraphicBuffer;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.Binder;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
@@ -54,6 +56,7 @@ import android.view.InputWindowHandle;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.WindowInsets.Type;
import android.window.PictureInPictureSurfaceTransaction;
import android.window.TaskSnapshot;
@@ -150,6 +153,8 @@ public class RecentsAnimationController implements DeathRecipient {
    private boolean mCancelOnNextTransitionStart;
    // Whether to take a screenshot when handling a deferred cancel
    private boolean mCancelDeferredWithScreenshot;
    // The reorder mode to apply after the cleanupScreenshot() callback
    private int mPendingCancelWithScreenshotReorderMode = REORDER_MOVE_TO_ORIGINAL_POSITION;

    @VisibleForTesting
    boolean mIsAddingTaskToTargets;
@@ -158,12 +163,6 @@ public class RecentsAnimationController implements DeathRecipient {
    private boolean mNavigationBarAttachedToApp;
    private ActivityRecord mNavBarAttachedApp;

    /**
     * Animates the screenshot of task that used to be controlled by RecentsAnimation.
     * @see {@link #setCancelOnNextTransitionStart}
     */
    SurfaceAnimator mRecentScreenshotAnimator;

    /**
     * An app transition listener to cancel the recents animation only after the app transition
     * starts or is canceled.
@@ -355,12 +354,9 @@ public class RecentsAnimationController implements DeathRecipient {
        public void cleanupScreenshot() {
            final long token = Binder.clearCallingIdentity();
            try {
                synchronized (mService.mGlobalLock) {
                    if (mRecentScreenshotAnimator != null) {
                        mRecentScreenshotAnimator.cancelAnimation();
                        mRecentScreenshotAnimator = null;
                    }
                }
                // Note, the callback will handle its own synchronization, do not lock on WM lock
                // prior to calling the callback
                continueDeferredCancelAnimation();
            } finally {
                Binder.restoreCallingIdentity(token);
            }
@@ -519,13 +515,13 @@ public class RecentsAnimationController implements DeathRecipient {
    }

    @VisibleForTesting
    AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
    TaskAnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
        return addAnimation(task, isRecentTaskInvisible, false /* hidden */,
                null /* finishedCallback */);
    }

    @VisibleForTesting
    AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible, boolean hidden,
    TaskAnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible, boolean hidden,
            OnAnimationFinishedCallback finishedCallback) {
        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName());
        final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
@@ -541,9 +537,7 @@ public class RecentsAnimationController implements DeathRecipient {
    void removeAnimation(TaskAnimationAdapter taskAdapter) {
        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
                "removeAnimation(%d)", taskAdapter.mTask.mTaskId);
        taskAdapter.mTask.setCanAffectSystemUiFlags(true);
        taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter.mLastAnimationType,
                taskAdapter);
        taskAdapter.onRemove();
        mPendingAnimations.remove(taskAdapter);
    }

@@ -821,8 +815,22 @@ public class RecentsAnimationController implements DeathRecipient {
    }

    /**
     * If there is a recents animation running, we need to cancel the animation and snapshot the
     * tasks before the change (to ensure they are captured at the right configuration)
     * Cancels the running animation when starting home, providing a snapshot for the runner to
     * properly handle the cancellation. This call uses the provided hint to determine how to
     * finish the animation.
     */
    public void cancelAnimationForHomeStart() {
        if (mCanceled) {
            return;
        }
        cancelAnimation(mWillFinishToHome ? REORDER_MOVE_TO_TOP : REORDER_KEEP_IN_PLACE,
                true /* screenshot */, "cancelAnimationForHomeStart");
    }

    /**
     * Cancels the running animation when there is a display change, providing a snapshot for the
     * runner to properly handle the cancellation. This call uses the provided hint to determine
     * how to finish the animation.
     */
    public void cancelAnimationForDisplayChange() {
        if (mCanceled) {
@@ -843,16 +851,22 @@ public class RecentsAnimationController implements DeathRecipient {
            mCanceled = true;

            if (screenshot && !mPendingAnimations.isEmpty()) {
                final TaskAnimationAdapter adapter = mPendingAnimations.get(0);
                final Task task = adapter.mTask;
                // Screen shot previous task when next task starts transition and notify the runner.
                // We will actually finish the animation once the runner calls cleanUpScreenshot().
                final Task task = mPendingAnimations.get(0).mTask;
                final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode);
                final TaskSnapshot taskSnapshot = screenshotRecentTask(task);
                mPendingCancelWithScreenshotReorderMode = reorderMode;
                try {
                    mRunner.onAnimationCanceled(taskSnapshot);
                } catch (RemoteException e) {
                    Slog.e(TAG, "Failed to cancel recents animation", e);
                }
                if (taskSnapshot == null) {
                if (taskSnapshot != null) {
                    // Defer until the runner calls back to cleanupScreenshot()
                    adapter.setSnapshotOverlay(taskSnapshot);
                } else {
                    // Do a normal cancel since we couldn't screenshot
                    mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
                }
            } else {
@@ -869,6 +883,12 @@ public class RecentsAnimationController implements DeathRecipient {
        }
    }

    @VisibleForTesting
    void continueDeferredCancelAnimation() {
        mCallbacks.onAnimationFinished(mPendingCancelWithScreenshotReorderMode,
                false /* sendUserLeaveHint */);
    }

    @VisibleForTesting
    void setWillFinishToHome(boolean willFinishToHome) {
        mWillFinishToHome = willFinishToHome;
@@ -915,29 +935,13 @@ public class RecentsAnimationController implements DeathRecipient {
        return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
    }

    TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode) {
    TaskSnapshot screenshotRecentTask(Task task) {
        final TaskSnapshotController snapshotController = mService.mTaskSnapshotController;
        final ArraySet<Task> tasks = Sets.newArraySet(task);
        snapshotController.snapshotTasks(tasks);
        snapshotController.addSkipClosingAppSnapshotTasks(tasks);
        final TaskSnapshot taskSnapshot = snapshotController.getSnapshot(task.mTaskId,
                task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */);
        if (taskSnapshot == null) {
            return null;
        }

        final TaskScreenshotAnimatable animatable = new TaskScreenshotAnimatable(
                mService.mSurfaceControlFactory, task,
                new SurfaceControl.ScreenshotHardwareBuffer(taskSnapshot.getHardwareBuffer(),
                        taskSnapshot.getColorSpace(), false /* containsSecureLayers */));
        mRecentScreenshotAnimator = new SurfaceAnimator(
                animatable,
                (type, anim) -> {
                    ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "mRecentScreenshotAnimator finish");
                    mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
                }, mService);
        mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
        return taskSnapshot;
        return snapshotController.getSnapshot(task.mTaskId, task.mUserId,
                false /* restoreFromDisk */, false /* isLowResolution */);
    }

    void cleanupAnimation(@ReorderMode int reorderMode) {
@@ -976,12 +980,6 @@ public class RecentsAnimationController implements DeathRecipient {
        mRunner = null;
        mCanceled = true;

        // Make sure previous animator has cleaned-up.
        if (mRecentScreenshotAnimator != null) {
            mRecentScreenshotAnimator.cancelAnimation();
            mRecentScreenshotAnimator = null;
        }

        // Restore IME icon only when moving the original app task to front from recents, in case
        // IME icon may missing if the moving task has already been the current focused task.
        if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION && !mIsAddingTaskToTargets) {
@@ -1028,16 +1026,7 @@ public class RecentsAnimationController implements DeathRecipient {

    @Override
    public void binderDied() {
        if (!mCanceled) {
        cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
        } else {
            synchronized (mService.getWindowManagerLock()) {
                if (mRecentScreenshotAnimator != null) {
                    mRecentScreenshotAnimator.cancelAnimation();
                    mRecentScreenshotAnimator = null;
                }
            }
        }

        synchronized (mService.getWindowManagerLock()) {
            // Clear associated input consumers on runner death
@@ -1171,6 +1160,8 @@ public class RecentsAnimationController implements DeathRecipient {
        private PictureInPictureSurfaceTransaction mFinishTransaction;
        // An overlay used to mask the content as an app goes into PIP
        private SurfaceControl mFinishOverlay;
        // An overlay used for canceling the animation with a screenshot
        private SurfaceControl mSnapshotOverlay;

        TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
            mTask = task;
@@ -1205,10 +1196,47 @@ public class RecentsAnimationController implements DeathRecipient {
            return mTarget;
        }

        void setSnapshotOverlay(TaskSnapshot snapshot) {
            // Create a surface control for the snapshot and reparent it to the leash
            final HardwareBuffer buffer = snapshot.getHardwareBuffer();
            if (buffer == null) {
                return;
            }

            final SurfaceSession session = new SurfaceSession();
            mSnapshotOverlay = mService.mSurfaceControlFactory.apply(session)
                    .setName("RecentTaskScreenshotSurface")
                    .setCallsite("TaskAnimationAdapter.setSnapshotOverlay")
                    .setFormat(buffer.getFormat())
                    .setParent(mCapturedLeash)
                    .setBLASTLayer()
                    .build();

            final float scale = 1.0f * mTask.getBounds().width() / buffer.getWidth();
            mTask.getPendingTransaction()
                    .setBuffer(mSnapshotOverlay, GraphicBuffer.createFromHardwareBuffer(buffer))
                    .setColorSpace(mSnapshotOverlay, snapshot.getColorSpace())
                    .setLayer(mSnapshotOverlay, Integer.MAX_VALUE)
                    .setMatrix(mSnapshotOverlay, scale, 0, 0, scale)
                    .show(mSnapshotOverlay)
                    .apply();
        }

        void onRemove() {
            if (mSnapshotOverlay != null) {
                // Clean up the snapshot overlay if necessary
                mTask.getPendingTransaction()
                        .remove(mSnapshotOverlay)
                        .apply();
                mSnapshotOverlay = null;
            }
            mTask.setCanAffectSystemUiFlags(true);
            mCapturedFinishCallback.onAnimationFinished(mLastAnimationType, this);
        }

        void onCleanup() {
            if (mFinishTransaction != null) {
            final Transaction pendingTransaction = mTask.getPendingTransaction();

            if (mFinishTransaction != null) {
                // Reparent the overlay
                if (mFinishOverlay != null) {
                    pendingTransaction.reparent(mFinishOverlay, mTask.mSurfaceControl);
@@ -1236,10 +1264,15 @@ public class RecentsAnimationController implements DeathRecipient {
            } else if (!mTask.isAttached()) {
                // Apply the task's pending transaction in case it is detached and its transaction
                // is not reachable.
                mTask.getPendingTransaction().apply();
                pendingTransaction.apply();
            }
        }

        @VisibleForTesting
        public SurfaceControl getSnapshotOverlay() {
            return mSnapshotOverlay;
        }

        @Override
        public boolean getShowWallpaper() {
            return false;
+3 −1
Original line number Diff line number Diff line
@@ -1529,7 +1529,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        // Updates the extra information of the intent.
        if (fromHomeKey) {
            homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
            mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "startHomeActivity");
            if (mWindowManager.getRecentsAnimationController() != null) {
                mWindowManager.getRecentsAnimationController().cancelAnimationForHomeStart();
            }
        }
        homeIntent.putExtra(WindowManagerPolicy.EXTRA_START_REASON, reason);

+0 −120
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;

import android.graphics.GraphicBuffer;
import android.hardware.HardwareBuffer;
import android.view.SurfaceControl;
import android.view.SurfaceSession;

import com.android.internal.protolog.common.ProtoLog;

import java.util.function.Function;

/**
 * Class used by {@link RecentsAnimationController} to create a surface control with taking
 * screenshot of task when canceling recents animation.
 *
 * @see {@link RecentsAnimationController#setCancelOnNextTransitionStart}
 */
class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable {
    private static final String TAG = "TaskScreenshotAnim";
    private Task mTask;
    private SurfaceControl mSurfaceControl;
    private int mWidth;
    private int mHeight;

    TaskScreenshotAnimatable(Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory,
            Task task, SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer) {
        HardwareBuffer buffer = screenshotBuffer == null
                ? null : screenshotBuffer.getHardwareBuffer();
        mTask = task;
        mWidth = (buffer != null) ? buffer.getWidth() : 1;
        mHeight = (buffer != null) ? buffer.getHeight() : 1;
        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
                "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d",
                        task, mWidth, mHeight);
        mSurfaceControl = surfaceControlFactory.apply(new SurfaceSession())
                .setName("RecentTaskScreenshotSurface")
                .setBLASTLayer()
                .setCallsite("TaskScreenshotAnimatable")
                .build();
        if (buffer != null) {
            GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(buffer);
            getPendingTransaction().setBuffer(mSurfaceControl, graphicBuffer);
            getPendingTransaction().setColorSpace(mSurfaceControl,
                    screenshotBuffer.getColorSpace());
            final float scale = 1.0f * mTask.getBounds().width() / mWidth;
            getPendingTransaction().setMatrix(mSurfaceControl, scale, 0, 0, scale);
        }
        getPendingTransaction().show(mSurfaceControl);
    }

    @Override
    public SurfaceControl.Transaction getPendingTransaction() {
        return mTask.getPendingTransaction();
    }

    @Override
    public void commitPendingTransaction() {
        mTask.commitPendingTransaction();
    }

    @Override
    public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) {
        t.setLayer(leash, 1);
    }

    @Override
    public void onAnimationLeashLost(SurfaceControl.Transaction t) {
        if (mSurfaceControl != null) {
            t.remove(mSurfaceControl);
            mSurfaceControl = null;
        }
    }

    @Override
    public SurfaceControl.Builder makeAnimationLeash() {
        return mTask.makeAnimationLeash();
    }

    @Override
    public SurfaceControl getAnimationLeashParent() {
        return mTask.getAnimationLeashParent();
    }

    @Override
    public SurfaceControl getSurfaceControl() {
        return mSurfaceControl;
    }

    @Override
    public SurfaceControl getParentSurfaceControl() {
        return mTask.mSurfaceControl;
    }

    @Override
    public int getSurfaceWidth() {
        return mWidth;
    }

    @Override
    public int getSurfaceHeight() {
        return mHeight;
    }
}
Loading