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

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

Update config ordering when entering/leaving pip

- Always set the activity windowing mode to the previous windowing mode
  prior to pip until SysUI has a chance to update
- When entering with bounds animation, do the bounds animation before
  resetting the activity windowing mode and setting final bounds
- When entering with alpha animation, immediately reset the activity
  windowing mode and final bounds
- When exiting, set the activity windowing mode to fullscreen along with
  the task bounds and do an inverse scale animation from the previous
  size up to fullscreen
- Skip the animation when exiting to fullscreen in another orientation
- Dumping pip task org state

Bug: 149946388
Test: Enter/exit pip
Test: atest PinnedStackTests

Change-Id: Ia5a50a5e2ce7621c2c678d0ded3d8c02b1932302
parent c0b7326a
Loading
Loading
Loading
Loading
+16 −3
Original line number Original line Diff line number Diff line
@@ -65,6 +65,10 @@ public class PipAnimationController {
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface TransitionDirection {}
    public @interface TransitionDirection {}


    public static boolean isInPipDirection(@TransitionDirection int direction) {
        return direction == TRANSITION_DIRECTION_TO_PIP;
    }

    public static boolean isOutPipDirection(@TransitionDirection int direction) {
    public static boolean isOutPipDirection(@TransitionDirection int direction) {
        return direction == TRANSITION_DIRECTION_TO_FULLSCREEN
        return direction == TRANSITION_DIRECTION_TO_FULLSCREEN
                || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
                || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
@@ -104,6 +108,12 @@ public class PipAnimationController {
        if (mCurrentAnimator == null) {
        if (mCurrentAnimator == null) {
            mCurrentAnimator = setupPipTransitionAnimator(
            mCurrentAnimator = setupPipTransitionAnimator(
                    PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
                    PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
        } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
                && mCurrentAnimator.isRunning()) {
            // If we are still animating the fade into pip, then just move the surface and ensure
            // we update with the new destination bounds, but don't interrupt the existing animation
            // with a new bounds
            mCurrentAnimator.setDestinationBounds(endBounds);
        } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_BOUNDS
        } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_BOUNDS
                && mCurrentAnimator.isRunning()) {
                && mCurrentAnimator.isRunning()) {
            mCurrentAnimator.setDestinationBounds(endBounds);
            mCurrentAnimator.setDestinationBounds(endBounds);
@@ -265,8 +275,7 @@ public class PipAnimationController {


        boolean inScaleTransition() {
        boolean inScaleTransition() {
            if (mAnimationType != ANIM_TYPE_BOUNDS) return false;
            if (mAnimationType != ANIM_TYPE_BOUNDS) return false;
            final int direction = getTransitionDirection();
            return !isInPipDirection(getTransitionDirection());
            return !isOutPipDirection(direction) && direction != TRANSITION_DIRECTION_TO_PIP;
        }
        }


        /**
        /**
@@ -354,7 +363,11 @@ public class PipAnimationController {
                            getCastedFractionValue(start.bottom, end.bottom, fraction));
                            getCastedFractionValue(start.bottom, end.bottom, fraction));
                    setCurrentValue(mTmpRect);
                    setCurrentValue(mTmpRect);
                    if (inScaleTransition()) {
                    if (inScaleTransition()) {
                        if (isOutPipDirection(getTransitionDirection())) {
                            getSurfaceTransactionHelper().scale(tx, leash, end, mTmpRect);
                        } else {
                            getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect);
                            getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect);
                        }
                    } else {
                    } else {
                        getSurfaceTransactionHelper().crop(tx, leash, mTmpRect);
                        getSurfaceTransactionHelper().crop(tx, leash, mTmpRect);
                    }
                    }
+4 −0
Original line number Original line Diff line number Diff line
@@ -209,6 +209,10 @@ public class PipBoundsHandler {
        return new Rect(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
        return new Rect(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
    }
    }


    public int getDisplayRotation() {
        return mDisplayInfo.rotation;
    }

    /**
    /**
     * Responds to IPinnedStackListener on {@link DisplayInfo} change.
     * Responds to IPinnedStackListener on {@link DisplayInfo} change.
     * It will normally follow up with a
     * It will normally follow up with a
+147 −38
Original line number Original line Diff line number Diff line
@@ -16,6 +16,9 @@


package com.android.systemui.pip;
package com.android.systemui.pip;


import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;


import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
@@ -25,25 +28,30 @@ import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTI
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
import static com.android.systemui.pip.PipAnimationController.isInPipDirection;
import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.PictureInPictureParams;
import android.app.PictureInPictureParams;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.util.Log;
import android.util.Size;
import android.util.Size;
import android.view.SurfaceControl;
import android.view.SurfaceControl;
import android.window.TaskOrganizer;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
import android.window.WindowOrganizer;


import com.android.internal.os.SomeArgs;
import com.android.internal.os.SomeArgs;
@@ -51,6 +59,7 @@ import com.android.systemui.R;
import com.android.systemui.pip.phone.PipUpdateThread;
import com.android.systemui.pip.phone.PipUpdateThread;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.Divider;


import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashMap;
import java.util.List;
import java.util.List;
@@ -90,7 +99,7 @@ public class PipTaskOrganizer extends TaskOrganizer {
    private final Rect mLastReportedBounds = new Rect();
    private final Rect mLastReportedBounds = new Rect();
    private final int mEnterExitAnimationDuration;
    private final int mEnterExitAnimationDuration;
    private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
    private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
    private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>();
    private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
    private final Divider mSplitDivider;
    private final Divider mSplitDivider;


    // These callbacks are called on the update thread
    // These callbacks are called on the update thread
@@ -110,7 +119,8 @@ public class PipTaskOrganizer extends TaskOrganizer {
        @Override
        @Override
        public void onPipAnimationEnd(SurfaceControl.Transaction tx,
        public void onPipAnimationEnd(SurfaceControl.Transaction tx,
                PipAnimationController.PipTransitionAnimator animator) {
                PipAnimationController.PipTransitionAnimator animator) {
            finishResize(tx, animator.getDestinationBounds(), animator.getTransitionDirection());
            finishResize(tx, animator.getDestinationBounds(), animator.getTransitionDirection(),
                    animator.getAnimationType());
            mMainHandler.post(() -> {
            mMainHandler.post(() -> {
                for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
                for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
                    final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
                    final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
@@ -170,7 +180,7 @@ public class PipTaskOrganizer extends TaskOrganizer {
            case MSG_FINISH_RESIZE: {
            case MSG_FINISH_RESIZE: {
                SurfaceControl.Transaction tx = (SurfaceControl.Transaction) args.arg2;
                SurfaceControl.Transaction tx = (SurfaceControl.Transaction) args.arg2;
                Rect toBounds = (Rect) args.arg3;
                Rect toBounds = (Rect) args.arg3;
                finishResize(tx, toBounds, args.argi1 /* direction */);
                finishResize(tx, toBounds, args.argi1 /* direction */, -1);
                if (updateBoundsCallback != null) {
                if (updateBoundsCallback != null) {
                    updateBoundsCallback.accept(toBounds);
                    updateBoundsCallback.accept(toBounds);
                }
                }
@@ -240,29 +250,77 @@ public class PipTaskOrganizer extends TaskOrganizer {
    }
    }


    /**
    /**
     * Dismiss PiP, this is done in two phases using {@link WindowContainerTransaction}
     * Expands PiP to the previous bounds, this is done in two phases using
     * - setActivityWindowingMode to undefined at beginning of the transaction. without changing
     * {@link WindowContainerTransaction}
     *   the windowing mode of the Task itself. This makes sure the activity render it's final
     * - setActivityWindowingMode to either fullscreen or split-secondary at beginning of the
     *   configuration while the Task is still in PiP.
     *   transaction. without changing the windowing mode of the Task itself. This makes sure the
     *   activity render it's final configuration while the Task is still in PiP.
     * - setWindowingMode to undefined at the end of transition
     * - setWindowingMode to undefined at the end of transition
     * @param animationDurationMs duration in millisecond for the exiting PiP transition
     * @param animationDurationMs duration in millisecond for the exiting PiP transition
     */
     */
    public void dismissPip(int animationDurationMs) {
    public void exitPip(int animationDurationMs) {
        if (!mInPip || mToken == null) {
        if (!mInPip || mToken == null) {
            Log.wtf(TAG, "Not allowed to dismissPip in current state"
            Log.wtf(TAG, "Not allowed to exitPip in current state"
                    + " mInPip=" + mInPip + " mToken=" + mToken);
                    + " mInPip=" + mInPip + " mToken=" + mToken);
            return;
            return;
        }
        }

        final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
        final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation()
                != mPipBoundsHandler.getDisplayRotation();
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        if (orientationDiffers) {
            // Don't bother doing an animation if the display rotation differs or if it's in
            // a non-supported windowing mode
            wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
            wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
            wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
            WindowOrganizer.applyTransaction(wct);
            WindowOrganizer.applyTransaction(wct);
        final Rect destinationBounds = mBoundsToRestore.remove(mToken.asBinder());
            mInPip = false;
        } else {
            final Rect destinationBounds = initialConfig.windowConfiguration.getBounds();
            final int direction = syncWithSplitScreenBounds(destinationBounds)
            final int direction = syncWithSplitScreenBounds(destinationBounds)
                ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN : TRANSITION_DIRECTION_TO_FULLSCREEN;
                    ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN
                    : TRANSITION_DIRECTION_TO_FULLSCREEN;
            final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
            mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds,
                    mLastReportedBounds);
            tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
            wct.setActivityWindowingMode(mToken, direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN
                    ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                    : WINDOWING_MODE_FULLSCREEN);
            wct.setBounds(mToken, destinationBounds);
            wct.setBoundsChangeTransaction(mToken, tx);
            applySyncTransaction(wct, new WindowContainerTransactionCallback() {
                @Override
                public void onTransactionReady(int id, SurfaceControl.Transaction t) {
                    t.apply();
                    scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
                    scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
                            direction, animationDurationMs, null /* updateBoundsCallback */);
                            direction, animationDurationMs, null /* updateBoundsCallback */);
                    mInPip = false;
                    mInPip = false;
                }
                }
            });
        }
    }

    /**
     * Removes PiP immediately.
     */
    public void removePip() {
        if (!mInPip || mToken == null) {
            Log.wtf(TAG, "Not allowed to removePip in current state"
                    + " mInPip=" + mInPip + " mToken=" + mToken);
            return;
        }
        getUpdateHandler().post(() -> {
            try {
                ActivityTaskManager.getService().removeStacksInWindowingModes(
                        new int[]{ WINDOWING_MODE_PINNED });
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to remove PiP", e);
            }
        });
        mInitialState.remove(mToken.asBinder());
    }


    @Override
    @Override
    public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
    public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
@@ -277,19 +335,37 @@ public class PipTaskOrganizer extends TaskOrganizer {
        mInPip = true;
        mInPip = true;
        mLeash = leash;
        mLeash = leash;


        // TODO: Skip enter animation when entering pip from another orientation
        final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
        final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
        mBoundsToRestore.put(mToken.asBinder(), currentBounds);
        mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));

        if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
        if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
            scheduleAnimateResizePip(currentBounds, destinationBounds,
            scheduleAnimateResizePip(currentBounds, destinationBounds,
                    TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration,
                    TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration,
                    null /* updateBoundsCallback */);
                    null /* updateBoundsCallback */);
        } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
        } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
            // If we are fading the PIP in, then we should move the pip to the final location as
            // soon as possible, but set the alpha immediately since the transaction can take a
            // while to process
            final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
            tx.setAlpha(mLeash, 0f);
            tx.apply();
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
            wct.setBounds(mToken, destinationBounds);
            wct.scheduleFinishEnterPip(mToken, destinationBounds);
            applySyncTransaction(wct, new WindowContainerTransactionCallback() {
                @Override
                public void onTransactionReady(int id, SurfaceControl.Transaction t) {
                    t.apply();
                    mUpdateHandler.post(() -> mPipAnimationController
                    mUpdateHandler.post(() -> mPipAnimationController
                            .getAnimator(mLeash, destinationBounds, 0f, 1f)
                            .getAnimator(mLeash, destinationBounds, 0f, 1f)
                            .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
                            .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
                            .setPipAnimationCallback(mPipAnimationCallback)
                            .setPipAnimationCallback(mPipAnimationCallback)
                            .setDuration(mEnterExitAnimationDuration)
                            .setDuration(mEnterExitAnimationDuration)
                            .start());
                            .start());
                }
            });
            mOneShotAnimationType = ANIM_TYPE_BOUNDS;
            mOneShotAnimationType = ANIM_TYPE_BOUNDS;
        } else {
        } else {
            throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType);
            throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType);
@@ -297,7 +373,7 @@ public class PipTaskOrganizer extends TaskOrganizer {
    }
    }


    /**
    /**
     * Note that dismissing PiP is now originated from SystemUI, see {@link #dismissPip(int)}.
     * Note that dismissing PiP is now originated from SystemUI, see {@link #exitPip(int)}.
     * Meanwhile this callback is invoked whenever the task is removed. For instance:
     * Meanwhile this callback is invoked whenever the task is removed. For instance:
     *   - as a result of removeStacksInWindowingModes from WM
     *   - as a result of removeStacksInWindowingModes from WM
     *   - activity itself is died
     *   - activity itself is died
@@ -411,6 +487,7 @@ public class PipTaskOrganizer extends TaskOrganizer {
            // can be initiated in other component, ignore if we are no longer in PIP
            // can be initiated in other component, ignore if we are no longer in PIP
            return;
            return;
        }
        }

        SomeArgs args = SomeArgs.obtain();
        SomeArgs args = SomeArgs.obtain();
        args.arg1 = updateBoundsCallback;
        args.arg1 = updateBoundsCallback;
        args.arg2 = currentBounds;
        args.arg2 = currentBounds;
@@ -509,7 +586,7 @@ public class PipTaskOrganizer extends TaskOrganizer {
            throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
            throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
                    + "directly");
                    + "directly");
        }
        }
        // Could happen when dismissPip
        // Could happen when exitPip
        if (mToken == null || mLeash == null) {
        if (mToken == null || mLeash == null) {
            Log.w(TAG, "Abort animation, invalid leash");
            Log.w(TAG, "Abort animation, invalid leash");
            return;
            return;
@@ -526,7 +603,7 @@ public class PipTaskOrganizer extends TaskOrganizer {
            throw new RuntimeException("Callers should call scheduleUserResizePip() instead of "
            throw new RuntimeException("Callers should call scheduleUserResizePip() instead of "
                    + "this directly");
                    + "this directly");
        }
        }
        // Could happen when dismissPip
        // Could happen when exitPip
        if (mToken == null || mLeash == null) {
        if (mToken == null || mLeash == null) {
            Log.w(TAG, "Abort animation, invalid leash");
            Log.w(TAG, "Abort animation, invalid leash");
            return;
            return;
@@ -537,32 +614,43 @@ public class PipTaskOrganizer extends TaskOrganizer {
    }
    }


    private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds,
    private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds,
            @PipAnimationController.TransitionDirection int direction) {
            @PipAnimationController.TransitionDirection int direction,
            @PipAnimationController.AnimationType int type) {
        if (Looper.myLooper() != mUpdateHandler.getLooper()) {
        if (Looper.myLooper() != mUpdateHandler.getLooper()) {
            throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
            throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
                    + "directly");
                    + "directly");
        }
        }
        mLastReportedBounds.set(destinationBounds);
        mLastReportedBounds.set(destinationBounds);
        if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
            return;
        }

        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final Rect taskBounds;
        final Rect taskBounds;
        if (isOutPipDirection(direction)) {
        if (isInPipDirection(direction)) {
            // If we are animating from fullscreen using a bounds animation, then reset the
            // activity windowing mode set by WM, and set the task bounds to the final bounds
            taskBounds = destinationBounds;
            wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
            wct.scheduleFinishEnterPip(mToken, destinationBounds);
        } else if (isOutPipDirection(direction)) {
            // If we are animating to fullscreen, then we need to reset the override bounds
            // If we are animating to fullscreen, then we need to reset the override bounds
            // on the task to ensure that the task "matches" the parent's bounds.
            // on the task to ensure that the task "matches" the parent's bounds.
            taskBounds = (direction == TRANSITION_DIRECTION_TO_FULLSCREEN)
            taskBounds = (direction == TRANSITION_DIRECTION_TO_FULLSCREEN)
                    ? null : destinationBounds;
                    ? null : destinationBounds;
            // As for the final windowing mode, simply reset it to undefined.
            // As for the final windowing mode, simply reset it to undefined and reset the activity
            // mode set prior to the animation running
            wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
            wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
            wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
            if (mSplitDivider != null && direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN) {
            if (mSplitDivider != null && direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN) {
                wct.reparent(mToken, mSplitDivider.getSecondaryRoot(), true /* onTop */);
                wct.reparent(mToken, mSplitDivider.getSecondaryRoot(), true /* onTop */);
            }
            }
        } else {
        } else {
            // Just a resize in PIP
            taskBounds = destinationBounds;
            taskBounds = destinationBounds;
        }
        }
        if (direction == TRANSITION_DIRECTION_TO_PIP) {

            wct.scheduleFinishEnterPip(mToken, taskBounds);
        } else {
        wct.setBounds(mToken, taskBounds);
        wct.setBounds(mToken, taskBounds);
        }
        wct.setBoundsChangeTransaction(mToken, tx);
        wct.setBoundsChangeTransaction(mToken, tx);
        WindowOrganizer.applyTransaction(wct);
        WindowOrganizer.applyTransaction(wct);
    }
    }
@@ -573,17 +661,17 @@ public class PipTaskOrganizer extends TaskOrganizer {
            throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of "
            throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of "
                    + "this directly");
                    + "this directly");
        }
        }
        // Could happen when dismissPip
        // Could happen when exitPip
        if (mToken == null || mLeash == null) {
        if (mToken == null || mLeash == null) {
            Log.w(TAG, "Abort animation, invalid leash");
            Log.w(TAG, "Abort animation, invalid leash");
            return;
            return;
        }
        }
        mUpdateHandler.post(() -> mPipAnimationController
        mPipAnimationController
                .getAnimator(mLeash, currentBounds, destinationBounds)
                .getAnimator(mLeash, currentBounds, destinationBounds)
                .setTransitionDirection(direction)
                .setTransitionDirection(direction)
                .setPipAnimationCallback(mPipAnimationCallback)
                .setPipAnimationCallback(mPipAnimationCallback)
                .setDuration(durationMs)
                .setDuration(durationMs)
                .start());
                .start();
    }
    }


    private Size getMinimalSize(ActivityInfo activityInfo) {
    private Size getMinimalSize(ActivityInfo activityInfo) {
@@ -623,6 +711,27 @@ public class PipTaskOrganizer extends TaskOrganizer {
        return true;
        return true;
    }
    }


    /**
     * Dumps internal states.
     */
    public void dump(PrintWriter pw, String prefix) {
        final String innerPrefix = prefix + "  ";
        pw.println(prefix + TAG);
        pw.println(innerPrefix + "mTaskInfo=" + mTaskInfo);
        pw.println(innerPrefix + "mToken=" + mToken
                + " binder=" + (mToken != null ? mToken.asBinder() : null));
        pw.println(innerPrefix + "mLeash=" + mLeash);
        pw.println(innerPrefix + "mInPip=" + mInPip);
        pw.println(innerPrefix + "mOneShotAnimationType=" + mOneShotAnimationType);
        pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
        pw.println(innerPrefix + "mLastReportedBounds=" + mLastReportedBounds);
        pw.println(innerPrefix + "mInitialState:");
        for (Map.Entry<IBinder, Configuration> e : mInitialState.entrySet()) {
            pw.println(innerPrefix + "  binder=" + e.getKey()
                    + " winConfig=" + e.getValue().windowConfiguration);
        }
    }

    /**
    /**
     * Callback interface for PiP transitions (both from and to PiP mode)
     * Callback interface for PiP transitions (both from and to PiP mode)
     */
     */
+1 −1
Original line number Original line Diff line number Diff line
@@ -101,7 +101,7 @@ public class PipAccessibilityInteractionConnection
                    result = true;
                    result = true;
                    break;
                    break;
                case AccessibilityNodeInfo.ACTION_EXPAND:
                case AccessibilityNodeInfo.ACTION_EXPAND:
                    mMotionHelper.expandPip();
                    mMotionHelper.expandPipToFullscreen();
                    result = true;
                    result = true;
                    break;
                    break;
                default:
                default:
+5 −6
Original line number Original line Diff line number Diff line
@@ -25,7 +25,6 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager;
import android.app.IActivityManager;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.content.pm.ParceledListSlice;
@@ -140,7 +139,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
                    != WINDOWING_MODE_PINNED) {
                    != WINDOWING_MODE_PINNED) {
                return;
                return;
            }
            }
            mTouchHandler.getMotionHelper().expandPip(clearedTask /* skipAnimation */);
            mTouchHandler.getMotionHelper().expandPipToFullscreen(clearedTask /* skipAnimation */);
        }
        }
    };
    };


@@ -214,7 +213,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
        }
        }
        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);


        final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
        mPipBoundsHandler = pipBoundsHandler;
        mPipBoundsHandler = pipBoundsHandler;
        mPipTaskOrganizer = pipTaskOrganizer;
        mPipTaskOrganizer = pipTaskOrganizer;
        mPipTaskOrganizer.registerPipTransitionCallback(this);
        mPipTaskOrganizer.registerPipTransitionCallback(this);
@@ -222,7 +220,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
        mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
        mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
        mMenuController = new PipMenuActivityController(context, mMediaController,
        mMenuController = new PipMenuActivityController(context, mMediaController,
                mInputConsumerController);
                mInputConsumerController);
        mTouchHandler = new PipTouchHandler(context, mActivityManager, activityTaskManager,
        mTouchHandler = new PipTouchHandler(context, mActivityManager,
                mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
                mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
                floatingContentCoordinator, deviceConfig, pipSnapAlgorithm);
                floatingContentCoordinator, deviceConfig, pipSnapAlgorithm);
        mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
        mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
@@ -237,7 +235,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio


        try {
        try {
            mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
            mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
            ActivityManager.StackInfo stackInfo = activityTaskManager.getStackInfo(
            ActivityManager.StackInfo stackInfo = ActivityTaskManager.getService().getStackInfo(
                    WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
                    WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
            if (stackInfo != null) {
            if (stackInfo != null) {
                // If SystemUI restart, and it already existed a pinned stack,
                // If SystemUI restart, and it already existed a pinned stack,
@@ -261,7 +259,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
     */
     */
    @Override
    @Override
    public void expandPip() {
    public void expandPip() {
        mTouchHandler.getMotionHelper().expandPip(false /* skipAnimation */);
        mTouchHandler.getMotionHelper().expandPipToFullscreen(false /* skipAnimation */);
    }
    }


    /**
    /**
@@ -378,5 +376,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
        mMenuController.dump(pw, innerPrefix);
        mMenuController.dump(pw, innerPrefix);
        mTouchHandler.dump(pw, innerPrefix);
        mTouchHandler.dump(pw, innerPrefix);
        mPipBoundsHandler.dump(pw, innerPrefix);
        mPipBoundsHandler.dump(pw, innerPrefix);
        mPipTaskOrganizer.dump(pw, innerPrefix);
    }
    }
}
}
Loading