Merge "PiP: Consider stash state when calculating snap fraction."

This commit is contained in:
Ben Lin
2020-11-06 19:00:58 +00:00
committed by Android (Google) Code Review
12 changed files with 134 additions and 42 deletions

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -196,6 +196,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
mMainExecutor.execute(() -> {
mPipBoundsHandler.onConfigurationChanged(mContext);
mTouchHandler.onConfigurationChanged();
mPipBoundsState.onConfigurationChanged();
});
}

View File

@@ -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());
}
/**

View File

@@ -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,

View File

@@ -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);

View File

@@ -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");
}

View File

@@ -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,

View File

@@ -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);

View File

@@ -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

View File

@@ -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