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

Commit 8aa6016b authored by Winson Chung's avatar Winson Chung
Browse files

Add fallback animation for auto-enter without source rect hint

- Launcher will create a new surface which is faded in over the app,
  and as it finishes the recents animation, we transfer the overlay
  from the leash to the task (as with the transform), and when the
  pip task organizer receives it, it can fade out and remove the
  surface
- Fixes flash of status bar colors when going from light status bar
  to home (dark status bar) by deferring whether a task affects the
  sysui flag until it enters pip (only for autoenter)

https://recall.googleplex.com/projects/e3f080d7-2818-43f0-a087-405000b8fdf5/sessions/971a84c8-a622-4b34-a9de-4e595595da42

Bug: 184703546
Test: Swipe up from app with auto-enter but no source hint rect

Change-Id: I0a00cdb98d0a599ef065206e0cd2cfc0e6cc72b1
parent 9b14a508
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.view;

import android.app.ActivityManager;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.SurfaceControl;
import android.graphics.GraphicBuffer;
import android.window.PictureInPictureSurfaceTransaction;
import android.window.TaskSnapshot;
@@ -43,9 +44,10 @@ interface IRecentsAnimationController {
     * updated accordingly. This should be called before `finish`
     * @param taskId for which the leash should be updated
     * @param finishTransaction leash operations for the final transform.
     * @param overlay the surface control for an overlay being shown above the pip (can be null)
     */
     void setFinishTaskTransaction(int taskId,
             in PictureInPictureSurfaceTransaction finishTransaction);
             in PictureInPictureSurfaceTransaction finishTransaction, in SurfaceControl overlay);

    /**
     * Notifies to the system that the animation into Recents should end, and all leashes associated
+3 −0
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@
    <!-- Animation duration for resizing of PIP. -->
    <integer name="config_pipResizeAnimationDuration">425</integer>

    <!-- Animation duration for crossfading of PIP (specifically to fade out the layer on top). -->
    <integer name="config_pipCrossfadeAnimationDuration">150</integer>

    <!-- Allow dragging the PIP to a location to close it -->
    <bool name="config_pipEnableDismissDragToEdge">true</bool>

+29 −17
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {

    private final SyncTransactionQueue mSyncQueue;

    private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>();
    private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>();

    public FullscreenTaskListener(SyncTransactionQueue syncQueue) {
        mSyncQueue = syncQueue;
@@ -50,14 +50,14 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {

    @Override
    public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
        if (mLeashByTaskId.get(taskInfo.taskId) != null) {
        if (mDataByTaskId.get(taskInfo.taskId) != null) {
            throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId);
        }
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
                taskInfo.taskId);
        mLeashByTaskId.put(taskInfo.taskId, leash);
        if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
        final Point positionInParent = taskInfo.positionInParent;
        mDataByTaskId.put(taskInfo.taskId, new TaskData(leash, positionInParent));
        if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
        mSyncQueue.runInSync(t -> {
            // Reset several properties back to fullscreen (PiP, for example, leaves all these
            // properties in a bad state).
@@ -72,45 +72,57 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
    @Override
    public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
        if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
        final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
        final TaskData data = mDataByTaskId.get(taskInfo.taskId);
        final Point positionInParent = taskInfo.positionInParent;
        if (!positionInParent.equals(data.positionInParent)) {
            data.positionInParent.set(positionInParent.x, positionInParent.y);
            mSyncQueue.runInSync(t -> {
            // Reset several properties back. For instance, when an Activity enters PiP with
            // multiple activities in the same task, a new task will be created from that Activity
            // and we want reset the leash of the original task.
            t.setPosition(leash, positionInParent.x, positionInParent.y);
            t.setWindowCrop(leash, null);
                t.setPosition(data.surface, positionInParent.x, positionInParent.y);
            });
        }
    }

    @Override
    public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
        if (mLeashByTaskId.get(taskInfo.taskId) == null) {
        if (mDataByTaskId.get(taskInfo.taskId) == null) {
            Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
            return;
        }
        mLeashByTaskId.remove(taskInfo.taskId);
        mDataByTaskId.remove(taskInfo.taskId);
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d",
                taskInfo.taskId);
    }

    @Override
    public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
        if (!mLeashByTaskId.contains(taskId)) {
        if (!mDataByTaskId.contains(taskId)) {
            throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
        }
        b.setParent(mLeashByTaskId.get(taskId));
        b.setParent(mDataByTaskId.get(taskId).surface);
    }

    @Override
    public void dump(@NonNull PrintWriter pw, String prefix) {
        final String innerPrefix = prefix + "  ";
        pw.println(prefix + this);
        pw.println(innerPrefix + mLeashByTaskId.size() + " Tasks");
        pw.println(innerPrefix + mDataByTaskId.size() + " Tasks");
    }

    @Override
    public String toString() {
        return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN);
    }

    /**
     * Per-task data for each managed task.
     */
    private static class TaskData {
        public final SurfaceControl surface;
        public final Point positionInParent;

        public TaskData(SurfaceControl surface, Point positionInParent) {
            this.surface = surface;
            this.positionInParent = positionInParent;
        }
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.wm.shell.pip;

import android.app.PictureInPictureParams;
import android.view.SurfaceControl;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
@@ -48,8 +49,10 @@ interface IPip {
     *
     * @param componentName ComponentName represents the Activity
     * @param destinationBounds the destination bounds the PiP window lands into
     * @param overlay an optional overlay to fade out after entering PiP
     */
    oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 2;
    oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds,
            in SurfaceControl overlay) = 2;

    /**
     * Sets listener to get pinned stack animation callbacks.
+49 −20
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
    private final PipUiEventLogger mPipUiEventLoggerLogger;
    private final int mEnterAnimationDuration;
    private final int mExitAnimationDuration;
    private final int mCrossFadeAnimationDuration;
    private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
    private final Optional<LegacySplitScreenController> mSplitScreenOptional;
    protected final ShellTaskOrganizer mTaskOrganizer;
@@ -244,6 +245,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
     */
    private boolean mInSwipePipToHomeTransition;

    /**
     * An optional overlay used to mask content changing between an app in/out of PiP, only set if
     * {@link #mInSwipePipToHomeTransition} is true.
     */
    private SurfaceControl mSwipePipToHomeOverlay;

    public PipTaskOrganizer(Context context,
            @NonNull SyncTransactionQueue syncTransactionQueue,
            @NonNull PipBoundsState pipBoundsState,
@@ -267,6 +274,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
                .getInteger(R.integer.config_pipEnterAnimationDuration);
        mExitAnimationDuration = context.getResources()
                .getInteger(R.integer.config_pipExitAnimationDuration);
        mCrossFadeAnimationDuration = context.getResources()
                .getInteger(R.integer.config_pipCrossfadeAnimationDuration);
        mSurfaceTransactionHelper = surfaceTransactionHelper;
        mPipAnimationController = pipAnimationController;
        mPipUiEventLoggerLogger = pipUiEventLogger;
@@ -337,10 +346,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
     * Callback when launcher finishes swipe-pip-to-home operation.
     * Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards.
     */
    public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
    public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
            SurfaceControl overlay) {
        // do nothing if there is no startSwipePipToHome being called before
        if (mInSwipePipToHomeTransition) {
            mPipBoundsState.setBounds(destinationBounds);
            mSwipePipToHomeOverlay = overlay;
        }
    }

@@ -583,6 +594,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,

    private void onEndOfSwipePipToHomeTransition() {
        final Rect destinationBounds = mPipBoundsState.getBounds();
        final SurfaceControl swipeToHomeOverlay = mSwipePipToHomeOverlay;
        final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
        mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds);
        mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds);
@@ -591,8 +603,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
            // Ensure menu's settled in its final bounds first.
            finishResizeForMenu(destinationBounds);
            sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);

            // Remove the swipe to home overlay
            if (swipeToHomeOverlay != null) {
                fadeOutAndRemoveOverlay(swipeToHomeOverlay);
            }
        }, tx);
        mInSwipePipToHomeTransition = false;
        mSwipePipToHomeOverlay = null;
    }

    private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable,
@@ -1122,25 +1140,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
                mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest);

                // Start animation to fade out the snapshot.
                final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f);
                animator.setDuration(mEnterAnimationDuration);
                animator.addUpdateListener(animation -> {
                    final float alpha = (float) animation.getAnimatedValue();
                    final SurfaceControl.Transaction transaction =
                            mSurfaceControlTransactionFactory.getTransaction();
                    transaction.setAlpha(snapshotSurface, alpha);
                    transaction.apply();
                });
                animator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        final SurfaceControl.Transaction tx =
                                mSurfaceControlTransactionFactory.getTransaction();
                        tx.remove(snapshotSurface);
                        tx.apply();
                    }
                });
                animator.start();
                fadeOutAndRemoveOverlay(snapshotSurface);
            });
        } else {
            applyFinishBoundsResize(wct, direction);
@@ -1282,6 +1282,35 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        return true;
    }

    /**
     * Fades out and removes an overlay surface.
     */
    private void fadeOutAndRemoveOverlay(SurfaceControl surface) {
        if (surface == null) {
            return;
        }

        final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f);
        animator.setDuration(mCrossFadeAnimationDuration);
        animator.addUpdateListener(animation -> {
            final float alpha = (float) animation.getAnimatedValue();
            final SurfaceControl.Transaction transaction =
                    mSurfaceControlTransactionFactory.getTransaction();
            transaction.setAlpha(surface, alpha);
            transaction.apply();
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                final SurfaceControl.Transaction tx =
                        mSurfaceControlTransactionFactory.getTransaction();
                tx.remove(surface);
                tx.apply();
            }
        });
        animator.start();
    }

    /**
     * Dumps internal states.
     */
Loading