Merge "PiP: Consider stash state when calculating snap fraction."
This commit is contained in:
@@ -256,7 +256,8 @@ public class PipBoundsHandler {
|
||||
|
||||
// Calculate the snap fraction of the current stack along the old movement bounds
|
||||
final Rect postChangeStackBounds = new Rect(oldBounds);
|
||||
final float snapFraction = getSnapFraction(postChangeStackBounds);
|
||||
final float snapFraction = mSnapAlgorithm.getSnapFraction(postChangeStackBounds,
|
||||
getMovementBounds(postChangeStackBounds), mPipBoundsState.getStashedState());
|
||||
|
||||
// Update the display layout
|
||||
mPipBoundsState.getDisplayLayout().rotateTo(context.getResources(), toRotation);
|
||||
@@ -273,7 +274,8 @@ public class PipBoundsHandler {
|
||||
final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
|
||||
false /* adjustForIme */);
|
||||
mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
|
||||
snapFraction);
|
||||
snapFraction, mPipBoundsState.getStashedState(), mPipBoundsState.getStashOffset(),
|
||||
mPipBoundsState.getDisplayBounds());
|
||||
|
||||
getInsetBounds(outInsetBounds);
|
||||
outBounds.set(postChangeStackBounds);
|
||||
@@ -321,7 +323,7 @@ public class PipBoundsHandler {
|
||||
boolean useCurrentMinEdgeSize, boolean useCurrentSize) {
|
||||
// Save the snap fraction and adjust the size based on the new aspect ratio.
|
||||
final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
|
||||
getMovementBounds(stackBounds));
|
||||
getMovementBounds(stackBounds), mPipBoundsState.getStashedState());
|
||||
final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize;
|
||||
final Size size;
|
||||
if (useCurrentMinEdgeSize || useCurrentSize) {
|
||||
|
||||
@@ -16,34 +16,70 @@
|
||||
|
||||
package com.android.wm.shell.pip;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Size;
|
||||
import android.view.DisplayInfo;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Singleton source of truth for the current state of PIP bounds.
|
||||
*/
|
||||
public final class PipBoundsState {
|
||||
public static final int STASH_TYPE_NONE = 0;
|
||||
public static final int STASH_TYPE_LEFT = 1;
|
||||
public static final int STASH_TYPE_RIGHT = 2;
|
||||
|
||||
@IntDef(prefix = { "STASH_TYPE_" }, value = {
|
||||
STASH_TYPE_NONE,
|
||||
STASH_TYPE_LEFT,
|
||||
STASH_TYPE_RIGHT
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface StashType {}
|
||||
|
||||
private static final String TAG = PipBoundsState.class.getSimpleName();
|
||||
|
||||
private final @NonNull Rect mBounds = new Rect();
|
||||
private final Context mContext;
|
||||
private float mAspectRatio;
|
||||
private boolean mIsStashed;
|
||||
private int mStashedState = STASH_TYPE_NONE;
|
||||
private int mStashOffset;
|
||||
private PipReentryState mPipReentryState;
|
||||
private ComponentName mLastPipComponentName;
|
||||
private final DisplayInfo mDisplayInfo = new DisplayInfo();
|
||||
private final DisplayLayout mDisplayLayout = new DisplayLayout();
|
||||
private final @NonNull AnimatingBoundsState mAnimatingBoundsState = new AnimatingBoundsState();
|
||||
|
||||
public PipBoundsState(Context context) {
|
||||
mContext = context;
|
||||
reloadResources();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the resources.
|
||||
*/
|
||||
public void onConfigurationChanged() {
|
||||
reloadResources();
|
||||
}
|
||||
|
||||
private void reloadResources() {
|
||||
mStashOffset = mContext.getResources()
|
||||
.getDimensionPixelSize(R.dimen.pip_stash_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current PIP bounds.
|
||||
*/
|
||||
@@ -57,17 +93,32 @@ public final class PipBoundsState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Dictate where PiP currently should be stashed or not.
|
||||
* Dictate where PiP currently should be stashed, if at all.
|
||||
*/
|
||||
public void setStashed(boolean isStashed) {
|
||||
mIsStashed = isStashed;
|
||||
public void setStashed(@StashType int stashedState) {
|
||||
mStashedState = stashedState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return where the PiP is stashed, if at all.
|
||||
* @return {@code STASH_NONE}, {@code STASH_LEFT} or {@code STASH_RIGHT}.
|
||||
*/
|
||||
public @StashType int getStashedState() {
|
||||
return mStashedState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether PiP is stashed or not.
|
||||
*/
|
||||
public boolean isStashed() {
|
||||
return mIsStashed;
|
||||
return mStashedState != STASH_TYPE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset from the edge of the screen for PiP stash.
|
||||
*/
|
||||
public int getStashOffset() {
|
||||
return mStashOffset;
|
||||
}
|
||||
|
||||
public void setAspectRatio(float aspectRatio) {
|
||||
@@ -245,7 +296,8 @@ public final class PipBoundsState {
|
||||
pw.println(innerPrefix + "mAspectRatio=" + mAspectRatio);
|
||||
pw.println(innerPrefix + "mDisplayInfo=" + mDisplayInfo);
|
||||
pw.println(innerPrefix + "mDisplayLayout=" + mDisplayLayout);
|
||||
pw.println(innerPrefix + "mIsStashed=" + mIsStashed);
|
||||
pw.println(innerPrefix + "mStashedState=" + mStashedState);
|
||||
pw.println(innerPrefix + "mStashOffset=" + mStashOffset);
|
||||
if (mPipReentryState == null) {
|
||||
pw.println(innerPrefix + "mPipReentryState=null");
|
||||
} else {
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.wm.shell.pip;
|
||||
|
||||
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT;
|
||||
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE;
|
||||
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.PointF;
|
||||
@@ -41,10 +45,21 @@ public class PipSnapAlgorithm {
|
||||
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fraction that describes where the PiP bounds is.
|
||||
* See {@link #getSnapFraction(Rect, Rect, int)}.
|
||||
*/
|
||||
public float getSnapFraction(Rect stackBounds, Rect movementBounds) {
|
||||
return getSnapFraction(stackBounds, movementBounds, STASH_TYPE_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns a fraction that describes where along the {@param movementBounds} the
|
||||
* {@param stackBounds} are. If the {@param stackBounds} are not currently on the
|
||||
* {@param movementBounds} exactly, then they will be snapped to the movement bounds.
|
||||
* stashType dictates whether the PiP is stashed (off-screen) or not. If
|
||||
* that's the case, we will have to do some math to calculate the snap fraction
|
||||
* correctly.
|
||||
*
|
||||
* The fraction is defined in a clockwise fashion against the {@param movementBounds}:
|
||||
*
|
||||
@@ -54,9 +69,10 @@ public class PipSnapAlgorithm {
|
||||
* 3 +---+ 2
|
||||
* 3 2
|
||||
*/
|
||||
public float getSnapFraction(Rect stackBounds, Rect movementBounds) {
|
||||
public float getSnapFraction(Rect stackBounds, Rect movementBounds,
|
||||
@PipBoundsState.StashType int stashType) {
|
||||
final Rect tmpBounds = new Rect();
|
||||
snapRectToClosestEdge(stackBounds, movementBounds, tmpBounds);
|
||||
snapRectToClosestEdge(stackBounds, movementBounds, tmpBounds, stashType);
|
||||
final float widthFraction = (float) (tmpBounds.left - movementBounds.left) /
|
||||
movementBounds.width();
|
||||
final float heightFraction = (float) (tmpBounds.top - movementBounds.top) /
|
||||
@@ -103,6 +119,22 @@ public class PipSnapAlgorithm {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #applySnapFraction(Rect, Rect, float)}, but take stash state into
|
||||
* consideration.
|
||||
*/
|
||||
public void applySnapFraction(Rect stackBounds, Rect movementBounds, float snapFraction,
|
||||
@PipBoundsState.StashType int stashType, int stashOffset, Rect displayBounds) {
|
||||
applySnapFraction(stackBounds, movementBounds, snapFraction);
|
||||
|
||||
if (stashType != STASH_TYPE_NONE) {
|
||||
stackBounds.offsetTo(stashType == STASH_TYPE_LEFT
|
||||
? stashOffset - stackBounds.width()
|
||||
: displayBounds.right - stashOffset,
|
||||
stackBounds.top);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts {@param movementBoundsOut} so that it is the movement bounds for the given
|
||||
* {@param stackBounds}.
|
||||
@@ -178,17 +210,24 @@ public class PipSnapAlgorithm {
|
||||
* Snaps the {@param stackBounds} to the closest edge of the {@param movementBounds} and writes
|
||||
* the new bounds out to {@param boundsOut}.
|
||||
*/
|
||||
public void snapRectToClosestEdge(Rect stackBounds, Rect movementBounds, Rect boundsOut) {
|
||||
public void snapRectToClosestEdge(Rect stackBounds, Rect movementBounds, Rect boundsOut,
|
||||
@PipBoundsState.StashType int stashType) {
|
||||
int leftEdge = stackBounds.left;
|
||||
if (stashType == STASH_TYPE_LEFT) {
|
||||
leftEdge = movementBounds.left;
|
||||
} else if (stashType == STASH_TYPE_RIGHT) {
|
||||
leftEdge = movementBounds.right;
|
||||
}
|
||||
final int boundedLeft = Math.max(movementBounds.left, Math.min(movementBounds.right,
|
||||
stackBounds.left));
|
||||
leftEdge));
|
||||
final int boundedTop = Math.max(movementBounds.top, Math.min(movementBounds.bottom,
|
||||
stackBounds.top));
|
||||
boundsOut.set(stackBounds);
|
||||
|
||||
// Otherwise, just find the closest edge
|
||||
final int fromLeft = Math.abs(stackBounds.left - movementBounds.left);
|
||||
final int fromLeft = Math.abs(leftEdge - movementBounds.left);
|
||||
final int fromTop = Math.abs(stackBounds.top - movementBounds.top);
|
||||
final int fromRight = Math.abs(movementBounds.right - stackBounds.left);
|
||||
final int fromRight = Math.abs(movementBounds.right - leftEdge);
|
||||
final int fromBottom = Math.abs(movementBounds.bottom - stackBounds.top);
|
||||
final int shortest = Math.min(Math.min(fromLeft, fromRight), Math.min(fromTop, fromBottom));
|
||||
if (shortest == fromLeft) {
|
||||
|
||||
@@ -196,6 +196,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
mMainExecutor.execute(() -> {
|
||||
mPipBoundsHandler.onConfigurationChanged(mContext);
|
||||
mTouchHandler.onConfigurationChanged();
|
||||
mPipBoundsState.onConfigurationChanged();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.wm.shell.pip.phone;
|
||||
|
||||
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT;
|
||||
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
@@ -33,7 +36,6 @@ import androidx.dynamicanimation.animation.AnimationHandler;
|
||||
import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.animation.FloatProperties;
|
||||
import com.android.wm.shell.animation.PhysicsAnimator;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
@@ -79,8 +81,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
/** The region that all of PIP must stay within. */
|
||||
private final Rect mFloatingAllowedArea = new Rect();
|
||||
|
||||
private int mStashOffset = 0;
|
||||
|
||||
/** Coordinator instance for resolving conflicts with other floating content. */
|
||||
private FloatingContentCoordinator mFloatingContentCoordinator;
|
||||
|
||||
@@ -179,8 +179,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
|
||||
mSfAnimationHandlerThreadLocal.get());
|
||||
|
||||
reloadResources();
|
||||
|
||||
mResizePipUpdateListener = (target, values) -> {
|
||||
if (mPipBoundsState.getAnimatingBoundsState().isAnimating()) {
|
||||
mPipTaskOrganizer.scheduleUserResizePip(getBounds(),
|
||||
@@ -189,11 +187,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
};
|
||||
}
|
||||
|
||||
void reloadResources() {
|
||||
mStashOffset = mContext.getResources()
|
||||
.getDimensionPixelSize(R.dimen.pip_stash_offset);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Rect getFloatingBoundsOnScreen() {
|
||||
@@ -380,6 +373,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
*/
|
||||
void stashToEdge(
|
||||
float velocityX, float velocityY, @Nullable Runnable endAction) {
|
||||
mPipBoundsState.setStashed(velocityX < 0 ? STASH_TYPE_LEFT : STASH_TYPE_RIGHT);
|
||||
movetoTarget(velocityX, velocityY, endAction, true /* isStash */);
|
||||
}
|
||||
|
||||
@@ -399,9 +393,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig)
|
||||
.withEndActions(endAction);
|
||||
|
||||
final float leftEdge = isStash ? mStashOffset - mPipBoundsState.getBounds().width()
|
||||
final float leftEdge = isStash
|
||||
? mPipBoundsState.getStashOffset() - mPipBoundsState.getBounds().width()
|
||||
: mMovementBounds.left;
|
||||
final float rightEdge = isStash ? mPipBoundsState.getDisplayBounds().right - mStashOffset
|
||||
final float rightEdge = isStash
|
||||
? mPipBoundsState.getDisplayBounds().right - mPipBoundsState.getStashOffset()
|
||||
: mMovementBounds.right;
|
||||
|
||||
final float xEndValue = velocityX < 0 ? leftEdge : rightEdge;
|
||||
@@ -471,9 +467,12 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
if (savedSnapFraction < 0f) {
|
||||
// If there are no saved snap fractions, then just use the current bounds
|
||||
savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(getBounds()),
|
||||
currentMovementBounds);
|
||||
currentMovementBounds, mPipBoundsState.getStashedState());
|
||||
}
|
||||
mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction);
|
||||
|
||||
mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction,
|
||||
mPipBoundsState.getStashedState(), mPipBoundsState.getStashOffset(),
|
||||
mPipBoundsState.getDisplayBounds());
|
||||
|
||||
if (immediate) {
|
||||
movePip(normalBounds);
|
||||
@@ -512,8 +511,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
mFlingConfigY = new PhysicsAnimator.FlingConfig(
|
||||
DEFAULT_FRICTION, mMovementBounds.top, mMovementBounds.bottom);
|
||||
mStashConfigX = new PhysicsAnimator.FlingConfig(
|
||||
DEFAULT_FRICTION, mStashOffset - mPipBoundsState.getBounds().width(),
|
||||
mPipBoundsState.getDisplayBounds().right - mStashOffset);
|
||||
DEFAULT_FRICTION,
|
||||
mPipBoundsState.getStashOffset() - mPipBoundsState.getBounds().width(),
|
||||
mPipBoundsState.getDisplayBounds().right - mPipBoundsState.getStashOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -221,7 +221,6 @@ public class PipTouchHandler {
|
||||
R.dimen.pip_expanded_shortest_edge_size);
|
||||
mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
|
||||
mPipDismissTargetHandler.updateMagneticTargetSize();
|
||||
mMotionHelper.reloadResources();
|
||||
}
|
||||
|
||||
private boolean shouldShowResizeHandle() {
|
||||
@@ -730,7 +729,7 @@ public class PipTouchHandler {
|
||||
}
|
||||
|
||||
if (touchState.startedDragging()) {
|
||||
mPipBoundsState.setStashed(false);
|
||||
mPipBoundsState.setStashed(PipBoundsState.STASH_TYPE_NONE);
|
||||
mSavedSnapFraction = -1f;
|
||||
mPipDismissTargetHandler.showDismissTargetMaybe();
|
||||
}
|
||||
@@ -789,7 +788,6 @@ public class PipTouchHandler {
|
||||
if (mEnableStash
|
||||
&& (animatingBounds.right > mPipBoundsState.getDisplayBounds().right
|
||||
|| animatingBounds.left < mPipBoundsState.getDisplayBounds().left)) {
|
||||
mPipBoundsState.setStashed(true);
|
||||
mMotionHelper.stashToEdge(vel.x, vel.y, this::flingEndAction /* endAction */);
|
||||
} else {
|
||||
mMotionHelper.flingToSnapTarget(vel.x, vel.y,
|
||||
|
||||
@@ -61,7 +61,7 @@ public class PipBoundsHandlerTest extends ShellTestCase {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
initializeMockResources();
|
||||
mPipBoundsState = new PipBoundsState();
|
||||
mPipBoundsState = new PipBoundsState(mContext);
|
||||
mPipBoundsHandler = new PipBoundsHandler(mContext, mPipBoundsState);
|
||||
|
||||
mPipBoundsState.setDisplayInfo(mDefaultDisplayInfo);
|
||||
|
||||
@@ -51,7 +51,7 @@ public class PipBoundsStateTest extends ShellTestCase {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mPipBoundsState = new PipBoundsState();
|
||||
mPipBoundsState = new PipBoundsState(mContext);
|
||||
mTestComponentName1 = new ComponentName(mContext, "component1");
|
||||
mTestComponentName2 = new ComponentName(mContext, "component2");
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class PipTaskOrganizerTest extends ShellTestCase {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mComponent1 = new ComponentName(mContext, "component1");
|
||||
mComponent2 = new ComponentName(mContext, "component2");
|
||||
mPipBoundsState = new PipBoundsState();
|
||||
mPipBoundsState = new PipBoundsState(mContext);
|
||||
mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mPipBoundsState,
|
||||
mMockPipBoundsHandler, mMenuActivityController, mMockPipSurfaceTransactionHelper,
|
||||
mMockOptionalSplitScreen, mMockdDisplayController, mMockPipUiEventLogger,
|
||||
|
||||
@@ -88,7 +88,7 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mPipBoundsState = new PipBoundsState();
|
||||
mPipBoundsState = new PipBoundsState(mContext);
|
||||
mPipBoundsHandler = new PipBoundsHandler(mContext, mPipBoundsState);
|
||||
mPipSnapAlgorithm = mPipBoundsHandler.getSnapAlgorithm();
|
||||
mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
|
||||
|
||||
@@ -95,8 +95,8 @@ public abstract class TvPipModule {
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipBoundsState providePipBoundsState() {
|
||||
return new PipBoundsState();
|
||||
static PipBoundsState providePipBoundsState(Context context) {
|
||||
return new PipBoundsState(context);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
|
||||
@@ -93,8 +93,8 @@ public class WMShellModule {
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipBoundsState providePipBoundsState() {
|
||||
return new PipBoundsState();
|
||||
static PipBoundsState providePipBoundsState(Context context) {
|
||||
return new PipBoundsState(context);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
|
||||
Reference in New Issue
Block a user