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

Commit e7ba686f authored by Winson Chung's avatar Winson Chung
Browse files

Ensure that windows are drawn before starting transition into PiP.

- Building upon ag/2125930, we ensure that all windows are drawn before
  starting the enter PiP animation.

Bug: 37420370
Test: bit FrameworksServicesTests:com.android.server.wm.BoundsAnimationControllerTests
Test: android.server.cts.ActivityManagerPinnedStackTests

Change-Id: I73fb71681f62bbc684efedbd3d40c3e1a670db46
parent 6cfc8afa
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -10589,8 +10589,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                                mStackSupervisor.getStack(PINNED_STACK_ID);
                        if (pinnedStack != null) {
                            pinnedStack.animateResizePinnedStack(null /* sourceHintBounds */,
                                    destBounds, animationDuration,
                                    false /* schedulePipModeChangedOnAnimationEnd */);
                                    destBounds, animationDuration, false /* fromFullscreen */);
                        }
                    } else {
                        throw new IllegalArgumentException("Stack: " + stackId
+11 −8
Original line number Diff line number Diff line
@@ -2986,18 +2986,21 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            mWindowManager.continueSurfaceLayout();
        }

        // The task might have already been running and its visibility needs to be synchronized
        // with the visibility of the stack / windows.
        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
        resumeFocusedStackTopActivityLocked();

        // Calculate the default bounds (don't use existing stack bounds as we may have just created
        // the stack
        // the stack, and schedule the start of the animation into PiP (the bounds animator that
        // is triggered by this is posted on another thread)
        final Rect destBounds = stack.getPictureInPictureBounds(aspectRatio,
                false /* useExistingStackBounds */);

        stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */,
                true /* schedulePipModeChangedOnAnimationEnd */);
                true /* fromFullscreen */);

        // Update the visibility of all activities after the they have been reparented to the new
        // stack.  This MUST run after the animation above is scheduled to ensure that the windows
        // drawn signal is scheduled after the bounds animation start call on the bounds animator
        // thread.
        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
        resumeFocusedStackTopActivityLocked();

        mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName,
                r.getTask().taskId);
    }
+2 −2
Original line number Diff line number Diff line
@@ -50,12 +50,12 @@ class PinnedActivityStack extends ActivityStack<PinnedStackWindowController>
    }

    void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
            boolean schedulePipModeChangedOnAnimationEnd) {
            boolean fromFullscreen) {
        if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
            mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
        } else {
            getWindowContainerController().animateResizePinnedStack(toBounds, sourceHintBounds,
                    animationDuration, schedulePipModeChangedOnAnimationEnd);
                    animationDuration, fromFullscreen);
        }
    }

+7 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.wm;

import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
@@ -51,6 +52,7 @@ import static com.android.server.wm.WindowManagerService.logWithStack;

import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -1343,9 +1345,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
                }
                mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();

                final TaskStack s = getStack();
                if (s != null) {
                    s.onAllWindowsDrawn();
                // Notify the pinned stack upon all windows drawn. If there was an animation in
                // progress then this signal will resume that animation.
                final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID);
                if (pinnedStack != null) {
                    pinnedStack.onAllWindowsDrawn();
                }
            }
        }
+41 −18
Original line number Diff line number Diff line
@@ -139,8 +139,14 @@ public class BoundsAnimationController {
        private final boolean mSkipAnimationStart;
        // True if this animation was canceled by the user, not as a part of a replacing animation
        private boolean mSkipAnimationEnd;

        // True if the animation target is animating from the fullscreen. Only one of
        // {@link mMoveToFullscreen} or {@link mMoveFromFullscreen} can be true at any time in the
        // animation.
        private boolean mMoveFromFullscreen;
        // True if the animation target should be moved to the fullscreen stack at the end of this
        // animation
        // animation. Only one of {@link mMoveToFullscreen} or {@link mMoveFromFullscreen} can be
        // true at any time in the animation.
        private boolean mMoveToFullscreen;

        // Whether to schedule PiP mode changes on animation start/end
@@ -151,15 +157,21 @@ public class BoundsAnimationController {
        private final int mFrozenTaskWidth;
        private final int mFrozenTaskHeight;

        // Timeout callback to ensure we continue the animation if waiting for resuming or app
        // windows drawn fails
        private final Runnable mResumeRunnable = () -> resume();

        BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to,
                @SchedulePipModeChangedState int schedulePipModeChangedState,
                boolean moveToFullscreen, boolean replacingExistingAnimation) {
                boolean moveFromFullscreen, boolean moveToFullscreen,
                boolean replacingExistingAnimation) {
            super();
            mTarget = target;
            mFrom.set(from);
            mTo.set(to);
            mSkipAnimationStart = replacingExistingAnimation;
            mSchedulePipModeChangedState = schedulePipModeChangedState;
            mMoveFromFullscreen = moveFromFullscreen;
            mMoveToFullscreen = moveToFullscreen;
            addUpdateListener(this);
            addListener(this);
@@ -177,13 +189,6 @@ public class BoundsAnimationController {
            }
        }

        final Runnable mResumeRunnable = new Runnable() {
                @Override
                public void run() {
                    resume();
                }
        };

        @Override
        public void onAnimationStart(Animator animation) {
            if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
@@ -199,6 +204,12 @@ public class BoundsAnimationController {
            if (!mSkipAnimationStart) {
                mTarget.onAnimationStart(mSchedulePipModeChangedState ==
                        SCHEDULE_PIP_MODE_CHANGED_ON_START);

                // When starting an animation from fullscreen, pause here and wait for the
                // windows-drawn signal before we start the rest of the transition down into PiP.
                if (mMoveFromFullscreen) {
                    pause();
                }
            }

            // Immediately update the task bounds if they have to become larger, but preserve
@@ -213,13 +224,20 @@ public class BoundsAnimationController {
                // correct logic to make this resize seamless.
                if (mMoveToFullscreen) {
                    pause();
                    mHandler.postDelayed(mResumeRunnable, WAIT_FOR_DRAW_TIMEOUT_MS);
                }
            }
        }

        @Override
        public void pause() {
            if (DEBUG) Slog.d(TAG, "pause: waiting for windows drawn");
            super.pause();
            mHandler.postDelayed(mResumeRunnable, WAIT_FOR_DRAW_TIMEOUT_MS);
        }

        @Override
        public void resume() {
            if (DEBUG) Slog.d(TAG, "resume:");
            mHandler.removeCallbacks(mResumeRunnable);
            super.resume();
        }
@@ -336,15 +354,15 @@ public class BoundsAnimationController {

    public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to,
            int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
            boolean moveToFullscreen) {
            boolean moveFromFullscreen, boolean moveToFullscreen) {
        animateBoundsImpl(target, from, to, animationDuration, schedulePipModeChangedState,
                moveToFullscreen);
                moveFromFullscreen, moveToFullscreen);
    }

    @VisibleForTesting
    BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to,
            int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
            boolean moveToFullscreen) {
            boolean moveFromFullscreen, boolean moveToFullscreen) {
        final BoundsAnimator existing = mRunningAnimations.get(target);
        final boolean replacing = existing != null;

@@ -387,7 +405,7 @@ public class BoundsAnimationController {
            existing.cancel();
        }
        final BoundsAnimator animator = new BoundsAnimator(target, from, to,
                schedulePipModeChangedState, moveToFullscreen, replacing);
                schedulePipModeChangedState, moveFromFullscreen, moveToFullscreen, replacing);
        mRunningAnimations.put(target, animator);
        animator.setFloatValues(0f, 1f);
        animator.setDuration((animationDuration != -1 ? animationDuration
@@ -397,14 +415,19 @@ public class BoundsAnimationController {
        return animator;
    }

    public Handler getHandler() {
        return mHandler;
    }

    public void onAllWindowsDrawn() {
        if (DEBUG) Slog.d(TAG, "onAllWindowsDrawn:");
        mHandler.post(this::resume);
    }

    private void resume() {
        for (int i = 0; i < mRunningAnimations.size(); i++) {
            final BoundsAnimator b = mRunningAnimations.valueAt(i);
            b.resume();
        }
    }

    public void onAllWindowsDrawn() {
        mHandler.post(this::resume);
    }
}
Loading