diff options
3 files changed, 80 insertions, 40 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java index 64a1b0c804da..140d7765e5c1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java @@ -30,6 +30,7 @@ import android.graphics.Rect; import android.os.RemoteException; import android.util.ArraySet; import android.util.Size; +import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLog; @@ -42,9 +43,7 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Consumer; @@ -69,26 +68,36 @@ public class PipBoundsState { @Retention(RetentionPolicy.SOURCE) public @interface StashType {} + public static final int NAMED_KCA_LAUNCHER_SHELF = 0; + public static final int NAMED_KCA_TABLETOP_MODE = 1; + + @IntDef(prefix = { "NAMED_KCA_" }, value = { + NAMED_KCA_LAUNCHER_SHELF, + NAMED_KCA_TABLETOP_MODE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface NamedKca {} + private static final String TAG = PipBoundsState.class.getSimpleName(); - private final @NonNull Rect mBounds = new Rect(); - private final @NonNull Rect mMovementBounds = new Rect(); - private final @NonNull Rect mNormalBounds = new Rect(); - private final @NonNull Rect mExpandedBounds = new Rect(); - private final @NonNull Rect mNormalMovementBounds = new Rect(); - private final @NonNull Rect mExpandedMovementBounds = new Rect(); - private final @NonNull PipDisplayLayoutState mPipDisplayLayoutState; + @NonNull private final Rect mBounds = new Rect(); + @NonNull private final Rect mMovementBounds = new Rect(); + @NonNull private final Rect mNormalBounds = new Rect(); + @NonNull private final Rect mExpandedBounds = new Rect(); + @NonNull private final Rect mNormalMovementBounds = new Rect(); + @NonNull private final Rect mExpandedMovementBounds = new Rect(); + @NonNull private final PipDisplayLayoutState mPipDisplayLayoutState; private final Point mMaxSize = new Point(); private final Point mMinSize = new Point(); - private final @NonNull Context mContext; + @NonNull private final Context mContext; private float mAspectRatio; private int mStashedState = STASH_TYPE_NONE; private int mStashOffset; - private @Nullable PipReentryState mPipReentryState; + @Nullable private PipReentryState mPipReentryState; private final LauncherState mLauncherState = new LauncherState(); - private final @NonNull SizeSpecSource mSizeSpecSource; - private @Nullable ComponentName mLastPipComponentName; - private final @NonNull MotionBoundsState mMotionBoundsState = new MotionBoundsState(); + @NonNull private final SizeSpecSource mSizeSpecSource; + @Nullable private ComponentName mLastPipComponentName; + @NonNull private final MotionBoundsState mMotionBoundsState = new MotionBoundsState(); private boolean mIsImeShowing; private int mImeHeight; private boolean mIsShelfShowing; @@ -120,12 +129,18 @@ public class PipBoundsState { * as unrestricted keep clear area. Values in this map would be appended to * {@link #getUnrestrictedKeepClearAreas()} and this is meant for internal usage only. */ - private final Map<String, Rect> mNamedUnrestrictedKeepClearAreas = new HashMap<>(); + private final SparseArray<Rect> mNamedUnrestrictedKeepClearAreas = new SparseArray<>(); - private @Nullable Runnable mOnMinimalSizeChangeCallback; - private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback; - private List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>(); - private List<Consumer<Float>> mOnAspectRatioChangedCallbacks = new ArrayList<>(); + @Nullable private Runnable mOnMinimalSizeChangeCallback; + @Nullable private TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback; + private final List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>(); + private final List<Consumer<Float>> mOnAspectRatioChangedCallbacks = new ArrayList<>(); + + /** + * This is used to set the launcher shelf height ahead of non-auto-enter-pip animation, + * to avoid the race condition. See also {@link #NAMED_KCA_LAUNCHER_SHELF}. + */ + public final Rect mCachedLauncherShelfHeightKeepClearArea = new Rect(); // the size of the current bounds relative to the max size spec private float mBoundsScale; @@ -430,17 +445,32 @@ public class PipBoundsState { mUnrestrictedKeepClearAreas.addAll(unrestrictedAreas); } - /** Add a named unrestricted keep clear area. */ - public void addNamedUnrestrictedKeepClearArea(@NonNull String name, Rect unrestrictedArea) { - mNamedUnrestrictedKeepClearAreas.put(name, unrestrictedArea); + /** Set a named unrestricted keep clear area. */ + public void setNamedUnrestrictedKeepClearArea( + @NamedKca int tag, @Nullable Rect unrestrictedArea) { + if (unrestrictedArea == null) { + mNamedUnrestrictedKeepClearAreas.remove(tag); + } else { + mNamedUnrestrictedKeepClearAreas.put(tag, unrestrictedArea); + if (tag == NAMED_KCA_LAUNCHER_SHELF) { + mCachedLauncherShelfHeightKeepClearArea.set(unrestrictedArea); + } + } } - /** Remove a named unrestricted keep clear area. */ - public void removeNamedUnrestrictedKeepClearArea(@NonNull String name) { - mNamedUnrestrictedKeepClearAreas.remove(name); + /** + * Forcefully set the keep-clear-area for launcher shelf height if applicable. + * This is used for entering PiP in button navigation mode to make sure the destination bounds + * calculation includes the shelf height, to avoid race conditions that such callback is sent + * from Launcher after the entering animation is started. + */ + public void mayUseCachedLauncherShelfHeight() { + if (!mCachedLauncherShelfHeightKeepClearArea.isEmpty()) { + setNamedUnrestrictedKeepClearArea( + NAMED_KCA_LAUNCHER_SHELF, mCachedLauncherShelfHeightKeepClearArea); + } } - /** * @return restricted keep clear areas. */ @@ -454,9 +484,12 @@ public class PipBoundsState { */ @NonNull public Set<Rect> getUnrestrictedKeepClearAreas() { - if (mNamedUnrestrictedKeepClearAreas.isEmpty()) return mUnrestrictedKeepClearAreas; + if (mNamedUnrestrictedKeepClearAreas.size() == 0) return mUnrestrictedKeepClearAreas; final Set<Rect> unrestrictedAreas = new ArraySet<>(mUnrestrictedKeepClearAreas); - unrestrictedAreas.addAll(mNamedUnrestrictedKeepClearAreas.values()); + for (int i = 0; i < mNamedUnrestrictedKeepClearAreas.size(); i++) { + final int key = mNamedUnrestrictedKeepClearAreas.keyAt(i); + unrestrictedAreas.add(mNamedUnrestrictedKeepClearAreas.get(key)); + } return unrestrictedAreas; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 9bb9d868243b..a52141c5f9d6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -1020,6 +1020,9 @@ public class PipTransition extends PipTransitionController { mPipMenuController.attach(leash); } + // Make sure we have the launcher shelf into destination bounds calculation + // before the animator starts. + mPipBoundsState.mayUseCachedLauncherShelfHeight(); final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); final Rect currentBounds = pipChange.getStartAbsBounds(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 0cb7e17e41e9..7451d2251588 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -646,9 +646,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb }); mTabletopModeController.registerOnTabletopModeChangedListener((isInTabletopMode) -> { - final String tag = "tabletop-mode"; if (!isInTabletopMode) { - mPipBoundsState.removeNamedUnrestrictedKeepClearArea(tag); + mPipBoundsState.setNamedUnrestrictedKeepClearArea( + PipBoundsState.NAMED_KCA_TABLETOP_MODE, null); return; } @@ -657,14 +657,16 @@ public class PipController implements PipTransitionController.PipTransitionCallb if (mTabletopModeController.getPreferredHalfInTabletopMode() == TabletopModeController.PREFERRED_TABLETOP_HALF_TOP) { // Prefer top, avoid the bottom half of the display. - mPipBoundsState.addNamedUnrestrictedKeepClearArea(tag, new Rect( - displayBounds.left, displayBounds.centerY(), - displayBounds.right, displayBounds.bottom)); + mPipBoundsState.setNamedUnrestrictedKeepClearArea( + PipBoundsState.NAMED_KCA_TABLETOP_MODE, new Rect( + displayBounds.left, displayBounds.centerY(), + displayBounds.right, displayBounds.bottom)); } else { // Prefer bottom, avoid the top half of the display. - mPipBoundsState.addNamedUnrestrictedKeepClearArea(tag, new Rect( - displayBounds.left, displayBounds.top, - displayBounds.right, displayBounds.centerY())); + mPipBoundsState.setNamedUnrestrictedKeepClearArea( + PipBoundsState.NAMED_KCA_TABLETOP_MODE, new Rect( + displayBounds.left, displayBounds.top, + displayBounds.right, displayBounds.centerY())); } // Try to move the PiP window if we have entered PiP mode. @@ -916,10 +918,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb 0, mPipBoundsState.getDisplayBounds().bottom - height, mPipBoundsState.getDisplayBounds().right, mPipBoundsState.getDisplayBounds().bottom); - mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG, rect); + mPipBoundsState.setNamedUnrestrictedKeepClearArea( + PipBoundsState.NAMED_KCA_LAUNCHER_SHELF, rect); updatePipPositionForKeepClearAreas(); } else { - mPipBoundsState.removeNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG); + mPipBoundsState.setNamedUnrestrictedKeepClearArea( + PipBoundsState.NAMED_KCA_LAUNCHER_SHELF, null); // postpone moving in response to hide of Launcher in case there's another change mMainExecutor.removeCallbacks(mMovePipInResponseToKeepClearAreasChangeCallback); mMainExecutor.executeDelayed( @@ -968,8 +972,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb int launcherRotation, Rect hotseatKeepClearArea) { // preemptively add the keep clear area for Hotseat, so that it is taken into account // when calculating the entry destination bounds of PiP window - mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG, - hotseatKeepClearArea); + mPipBoundsState.setNamedUnrestrictedKeepClearArea( + PipBoundsState.NAMED_KCA_LAUNCHER_SHELF, hotseatKeepClearArea); onDisplayRotationChangedNotInPip(mContext, launcherRotation); // cache current min/max size Point minSize = mPipBoundsState.getMinSize(); |