Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java +61 −28 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -430,16 +445,31 @@ 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. Loading @@ -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; } Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +3 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +16 −12 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -657,12 +657,14 @@ 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( 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( mPipBoundsState.setNamedUnrestrictedKeepClearArea( PipBoundsState.NAMED_KCA_TABLETOP_MODE, new Rect( displayBounds.left, displayBounds.top, displayBounds.right, displayBounds.centerY())); } Loading Loading @@ -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( Loading Loading @@ -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(); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java +61 −28 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -430,16 +445,31 @@ 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. Loading @@ -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; } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +3 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +16 −12 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -657,12 +657,14 @@ 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( 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( mPipBoundsState.setNamedUnrestrictedKeepClearArea( PipBoundsState.NAMED_KCA_TABLETOP_MODE, new Rect( displayBounds.left, displayBounds.top, displayBounds.right, displayBounds.centerY())); } Loading Loading @@ -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( Loading Loading @@ -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(); Loading