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

Commit 5b8d2440 authored by jorgegil@google.com's avatar jorgegil@google.com
Browse files

Move reentry state into PipBoundsState

Bug: 169373982
Test: existing tests pass, reentry works
Change-Id: I45af27637f24ad0822e4bdf65cd3a93d4a2442dd
parent a4091c69
Loading
Loading
Loading
Loading
+24 −57
Original line number Diff line number Diff line
@@ -22,9 +22,9 @@ import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;

import android.annotation.NonNull;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
@@ -52,14 +52,11 @@ public class PipBoundsHandler {
    private static final String TAG = PipBoundsHandler.class.getSimpleName();
    private static final float INVALID_SNAP_FRACTION = -1f;

    private final @NonNull PipBoundsState mPipBoundsState;
    private final PipSnapAlgorithm mSnapAlgorithm;
    private final DisplayInfo mDisplayInfo = new DisplayInfo();
    private DisplayLayout mDisplayLayout;

    private ComponentName mLastPipComponentName;
    private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
    private Size mReentrySize;

    private float mDefaultAspectRatio;
    private float mMinAspectRatio;
    private float mMaxAspectRatio;
@@ -75,7 +72,8 @@ public class PipBoundsHandler {
    private boolean mIsShelfShowing;
    private int mShelfHeight;

    public PipBoundsHandler(Context context) {
    public PipBoundsHandler(Context context, @NonNull PipBoundsState pipBoundsState) {
        mPipBoundsState = pipBoundsState;
        mSnapAlgorithm = new PipSnapAlgorithm(context);
        mDisplayLayout = new DisplayLayout();
        reloadResources(context);
@@ -174,40 +172,6 @@ public class PipBoundsHandler {
        displayInfo.copyFrom(mDisplayInfo);
    }

    /**
     * Responds to IPinnedStackListener on saving reentry snap fraction and size
     * for a given {@link ComponentName}.
     */
    public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {
        mReentrySnapFraction = getSnapFraction(bounds);
        mReentrySize = new Size(bounds.width(), bounds.height());
        mLastPipComponentName = componentName;
    }

    /**
     * Responds to IPinnedStackListener on resetting reentry snap fraction and size
     * for a given {@link ComponentName}.
     */
    public void onResetReentryBounds(ComponentName componentName) {
        if (componentName.equals(mLastPipComponentName)) {
            onResetReentryBoundsUnchecked();
        }
    }

    private void onResetReentryBoundsUnchecked() {
        mReentrySnapFraction = INVALID_SNAP_FRACTION;
        mReentrySize = null;
        mLastPipComponentName = null;
    }

    /**
     * Returns ture if there's a valid snap fraction. This is used with {@link EXTRA_IS_FIRST_ENTRY}
     * to see if this is the first time user has entered PIP for the component.
     */
    public boolean hasSaveReentryBounds() {
        return mReentrySnapFraction != INVALID_SNAP_FRACTION;
    }

    /**
     * The {@link PipSnapAlgorithm} is couple on display bounds
     * @return {@link PipSnapAlgorithm}.
@@ -250,37 +214,43 @@ public class PipBoundsHandler {
    }

    /**
     * See {@link #getDestinationBounds(ComponentName, float, Rect, Size, boolean)}
     * See {@link #getDestinationBounds(float, Rect, Size, boolean)}
     */
    public Rect getDestinationBounds(ComponentName componentName, float aspectRatio, Rect bounds,
            Size minimalSize) {
        return getDestinationBounds(componentName, aspectRatio, bounds, minimalSize,
    public Rect getDestinationBounds(float aspectRatio, Rect bounds, Size minimalSize) {
        return getDestinationBounds(aspectRatio, bounds, minimalSize,
                false /* useCurrentMinEdgeSize */);
    }

    /**
     * @return {@link Rect} of the destination PiP window bounds.
     */
    public Rect getDestinationBounds(ComponentName componentName, float aspectRatio, Rect bounds,
    public Rect getDestinationBounds(float aspectRatio, Rect bounds,
            Size minimalSize, boolean useCurrentMinEdgeSize) {
        if (!componentName.equals(mLastPipComponentName)) {
            onResetReentryBoundsUnchecked();
            mLastPipComponentName = componentName;
        }
        boolean isReentryBounds = false;
        final Rect destinationBounds;
        if (bounds == null) {
            final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
            destinationBounds = new Rect(defaultBounds);
            if (mReentrySnapFraction == INVALID_SNAP_FRACTION && mReentrySize == null) {
            // Calculating initial entry bounds
            final PipBoundsState.PipReentryState state = mPipBoundsState.getReentryState();

            final Rect defaultBounds;
            if (state != null) {
                // Restore to reentry bounds.
                defaultBounds = getDefaultBounds(state.getSnapFraction(), state.getSize());
                isReentryBounds = true;
            } else {
                // Get actual default bounds.
                defaultBounds = getDefaultBounds(INVALID_SNAP_FRACTION, null /* size */);
                mOverrideMinimalSize = minimalSize;
            }

            destinationBounds = new Rect(defaultBounds);
        } else {
            // Just adjusting bounds (e.g. on aspect ratio changed).
            destinationBounds = new Rect(bounds);
        }
        if (isValidPictureInPictureAspectRatio(aspectRatio)) {
            boolean useCurrentSize = bounds == null && mReentrySize != null;
            transformBoundsToAspectRatio(destinationBounds, aspectRatio, useCurrentMinEdgeSize,
                    useCurrentSize);
                    isReentryBounds);
        }
        mAspectRatio = aspectRatio;
        return destinationBounds;
@@ -533,9 +503,6 @@ public class PipBoundsHandler {
    public void dump(PrintWriter pw, String prefix) {
        final String innerPrefix = prefix + "  ";
        pw.println(prefix + TAG);
        pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName);
        pw.println(innerPrefix + "mReentrySnapFraction=" + mReentrySnapFraction);
        pw.println(innerPrefix + "mReentrySize=" + mReentrySize);
        pw.println(innerPrefix + "mDisplayInfo=" + mDisplayInfo);
        pw.println(innerPrefix + "mDefaultAspectRatio=" + mDefaultAspectRatio);
        pw.println(innerPrefix + "mMinAspectRatio=" + mMinAspectRatio);
+80 −0
Original line number Diff line number Diff line
@@ -17,9 +17,15 @@
package com.android.wm.shell.pip;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.graphics.Rect;
import android.util.Size;

import com.android.internal.annotations.VisibleForTesting;

import java.io.PrintWriter;
import java.util.Objects;

/**
 * Singleton source of truth for the current state of PIP bounds.
@@ -28,6 +34,8 @@ public final class PipBoundsState {
    private static final String TAG = PipBoundsState.class.getSimpleName();

    private final @NonNull Rect mBounds = new Rect();
    private PipReentryState mPipReentryState;
    private ComponentName mLastPipComponentName;

    void setBounds(@NonNull Rect bounds) {
        mBounds.set(bounds);
@@ -38,6 +46,72 @@ public final class PipBoundsState {
        return new Rect(mBounds);
    }

    /**
     * Save the reentry state to restore to when re-entering PIP mode.
     *
     * TODO(b/169373982): consider refactoring this so that this class alone can use mBounds and
     * calculate the snap fraction to save for re-entry.
     */
    public void saveReentryState(@NonNull Rect bounds, float fraction) {
        mPipReentryState = new PipReentryState(new Size(bounds.width(), bounds.height()), fraction);
    }

    /**
     * Returns the saved reentry state.
     */
    @Nullable
    public PipReentryState getReentryState() {
        return mPipReentryState;
    }

    /**
     * Set the last {@link ComponentName} to enter PIP mode.
     */
    public void setLastPipComponentName(ComponentName lastPipComponentName) {
        final boolean changed = !Objects.equals(mLastPipComponentName, lastPipComponentName);
        mLastPipComponentName = lastPipComponentName;
        if (changed) {
            clearReentryState();
        }
    }

    public ComponentName getLastPipComponentName() {
        return mLastPipComponentName;
    }

    @VisibleForTesting
    void clearReentryState() {
        mPipReentryState = null;
    }

    static final class PipReentryState {
        private static final String TAG = PipReentryState.class.getSimpleName();

        private final @NonNull Size mSize;
        private final float mSnapFraction;

        PipReentryState(@NonNull Size size, float snapFraction) {
            mSize = size;
            mSnapFraction = snapFraction;
        }

        @NonNull
        Size getSize() {
            return mSize;
        }

        float getSnapFraction() {
            return mSnapFraction;
        }

        void dump(PrintWriter pw, String prefix) {
            final String innerPrefix = prefix + "  ";
            pw.println(prefix + TAG);
            pw.println(innerPrefix + "mSize=" + mSize);
            pw.println(innerPrefix + "mSnapFraction=" + mSnapFraction);
        }
    }

    /**
     * Dumps internal state.
     */
@@ -45,5 +119,11 @@ public final class PipBoundsState {
        final String innerPrefix = prefix + "  ";
        pw.println(prefix + TAG);
        pw.println(innerPrefix + "mBounds=" + mBounds);
        pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName);
        if (mPipReentryState == null) {
            pw.println(innerPrefix + "mPipReentryState=null");
        } else {
            mPipReentryState.dump(pw, innerPrefix);
        }
    }
}
+8 −5
Original line number Diff line number Diff line
@@ -329,7 +329,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
            PictureInPictureParams pictureInPictureParams) {
        mShouldIgnoreEnteringPipTransition = true;
        mState = State.ENTERING_PIP;
        return mPipBoundsHandler.getDestinationBounds(componentName,
        mPipBoundsState.setLastPipComponentName(componentName);
        return mPipBoundsHandler.getDestinationBounds(
                getAspectRatioOrDefault(pictureInPictureParams),
                null /* bounds */, getMinimalSize(activityInfo));
    }
@@ -465,6 +466,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        mLeash = leash;
        mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));
        mPictureInPictureParams = mTaskInfo.pictureInPictureParams;
        mPipBoundsState.setLastPipComponentName(mTaskInfo.topActivity);

        mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
        mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER);
@@ -491,7 +493,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        }

        final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
                mTaskInfo.topActivity, getAspectRatioOrDefault(mPictureInPictureParams),
                getAspectRatioOrDefault(mPictureInPictureParams),
                null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo));
        Objects.requireNonNull(destinationBounds, "Missing destination bounds");
        final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
@@ -686,13 +688,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
    @Override
    public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
        Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
        mPipBoundsState.setLastPipComponentName(info.topActivity);
        final PictureInPictureParams newParams = info.pictureInPictureParams;
        if (newParams == null || !applyPictureInPictureParams(newParams)) {
            Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + newParams);
            return;
        }
        final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
                info.topActivity, getAspectRatioOrDefault(newParams),
                getAspectRatioOrDefault(newParams),
                mPipBoundsState.getBounds(), getMinimalSize(info.topActivityInfo),
                true /* userCurrentMinEdgeSize */);
        Objects.requireNonNull(destinationBounds, "Missing destination bounds");
@@ -709,7 +712,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
    public void onFixedRotationFinished(int displayId) {
        if (mShouldDeferEnteringPip && mState.isInPip()) {
            final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
                    mTaskInfo.topActivity, getAspectRatioOrDefault(mPictureInPictureParams),
                    getAspectRatioOrDefault(mPictureInPictureParams),
                    null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo));
            // schedule a regular animation to ensure all the callbacks are still being sent
            enterPipWithAlphaAnimation(destinationBounds, 0 /* durationMs */);
@@ -783,7 +786,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        }

        final Rect newDestinationBounds = mPipBoundsHandler.getDestinationBounds(
                mTaskInfo.topActivity, getAspectRatioOrDefault(mPictureInPictureParams),
                getAspectRatioOrDefault(mPictureInPictureParams),
                null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo));
        if (newDestinationBounds.equals(currentDestinationBounds)) return;
        if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) {
+9 −2
Original line number Diff line number Diff line
@@ -173,7 +173,13 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac

        @Override
        public void onActivityHidden(ComponentName componentName) {
            mHandler.post(() -> mPipBoundsHandler.onResetReentryBounds(componentName));
            mHandler.post(() -> {
                if (componentName.equals(mPipBoundsState.getLastPipComponentName())) {
                    // The activity was removed, we don't want to restore to the reentry state
                    // saved for this component anymore.
                    mPipBoundsState.setLastPipComponentName(null);
                }
            });
        }

        @Override
@@ -384,7 +390,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
        if (isOutPipDirection(direction)) {
            // Exiting PIP, save the reentry bounds to restore to when re-entering.
            updateReentryBounds(pipBounds);
            mPipBoundsHandler.onSaveReentryBounds(activity, mReentryBounds);
            final float snapFraction = mPipBoundsHandler.getSnapFraction(mReentryBounds);
            mPipBoundsState.saveReentryState(mReentryBounds, snapFraction);
        }
        // Disable touches while the animation is running
        mTouchHandler.setTouchEnabled(false);
+51 −100

File changed.

Preview size limit exceeded, changes collapsed.

Loading