Merge changes from topic "bounds-algo-tests"
* changes: Add unit tests for PipSnapAlgorithm Add unit tests for PipBoundsAlgorithm
This commit is contained in:
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Size;
|
||||
@@ -42,6 +43,9 @@ public class PipBoundsAlgorithm {
|
||||
private final @NonNull PipBoundsState mPipBoundsState;
|
||||
private final PipSnapAlgorithm mSnapAlgorithm;
|
||||
|
||||
private float mDefaultSizePercent;
|
||||
private float mMinAspectRatioForMinSize;
|
||||
private float mMaxAspectRatioForMinSize;
|
||||
private float mDefaultAspectRatio;
|
||||
private float mMinAspectRatio;
|
||||
private float mMaxAspectRatio;
|
||||
@@ -51,7 +55,7 @@ public class PipBoundsAlgorithm {
|
||||
|
||||
public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState) {
|
||||
mPipBoundsState = pipBoundsState;
|
||||
mSnapAlgorithm = new PipSnapAlgorithm(context);
|
||||
mSnapAlgorithm = new PipSnapAlgorithm();
|
||||
reloadResources(context);
|
||||
// Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
|
||||
// resources as it would clobber mAspectRatio when entering PiP from fullscreen which
|
||||
@@ -83,6 +87,11 @@ public class PipBoundsAlgorithm {
|
||||
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
|
||||
mMaxAspectRatio = res.getFloat(
|
||||
com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
|
||||
mDefaultSizePercent = res.getFloat(
|
||||
com.android.internal.R.dimen.config_pictureInPictureDefaultSizePercent);
|
||||
mMaxAspectRatioForMinSize = res.getFloat(
|
||||
com.android.internal.R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
|
||||
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,7 +183,7 @@ public class PipBoundsAlgorithm {
|
||||
final int minEdgeSize = useCurrentMinEdgeSize ? mPipBoundsState.getMinEdgeSize()
|
||||
: defaultMinEdgeSize;
|
||||
// Use the existing size but adjusted to the aspect ratio and min edge size.
|
||||
size = mSnapAlgorithm.getSizeForAspectRatio(
|
||||
size = getSizeForAspectRatio(
|
||||
new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize);
|
||||
} else {
|
||||
if (overrideMinSize != null) {
|
||||
@@ -184,7 +193,7 @@ public class PipBoundsAlgorithm {
|
||||
} else {
|
||||
// Calculate the default size using the display size and default min edge size.
|
||||
final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
|
||||
size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mDefaultMinSize,
|
||||
size = getSizeForAspectRatio(aspectRatio, mDefaultMinSize,
|
||||
displayInfo.logicalWidth, displayInfo.logicalHeight);
|
||||
}
|
||||
}
|
||||
@@ -229,7 +238,7 @@ public class PipBoundsAlgorithm {
|
||||
defaultSize = adjustSizeToAspectRatio(overrideMinSize, mDefaultAspectRatio);
|
||||
} else {
|
||||
// Calculate the default size using the display size and default min edge size.
|
||||
defaultSize = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
|
||||
defaultSize = getSizeForAspectRatio(mDefaultAspectRatio,
|
||||
mDefaultMinSize, displayInfo.logicalWidth, displayInfo.logicalHeight);
|
||||
}
|
||||
Gravity.apply(mDefaultStackGravity, defaultSize.getWidth(), defaultSize.getHeight(),
|
||||
@@ -270,12 +279,27 @@ public class PipBoundsAlgorithm {
|
||||
getInsetBounds(movementBounds);
|
||||
|
||||
// Apply the movement bounds adjustments based on the current state.
|
||||
mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
|
||||
getMovementBounds(stackBounds, movementBounds, movementBounds,
|
||||
(adjustForIme && mPipBoundsState.isImeShowing())
|
||||
? mPipBoundsState.getImeHeight() : 0);
|
||||
|
||||
return movementBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts movementBoundsOut so that it is the movement bounds for the given stackBounds.
|
||||
*/
|
||||
public void getMovementBounds(Rect stackBounds, Rect insetBounds, Rect movementBoundsOut,
|
||||
int bottomOffset) {
|
||||
// Adjust the right/bottom to ensure the stack bounds never goes offscreen
|
||||
movementBoundsOut.set(insetBounds);
|
||||
movementBoundsOut.right = Math.max(insetBounds.left, insetBounds.right
|
||||
- stackBounds.width());
|
||||
movementBoundsOut.bottom = Math.max(insetBounds.top, insetBounds.bottom
|
||||
- stackBounds.height());
|
||||
movementBoundsOut.bottom -= bottomOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the default snap fraction to apply instead of the default gravity when calculating
|
||||
* the default stack bounds when first entering PiP.
|
||||
@@ -303,6 +327,62 @@ public class PipBoundsAlgorithm {
|
||||
return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of the PiP at the given aspectRatio, ensuring that the minimum edge
|
||||
* is at least minEdgeSize.
|
||||
*/
|
||||
public Size getSizeForAspectRatio(float aspectRatio, float minEdgeSize, int displayWidth,
|
||||
int displayHeight) {
|
||||
final int smallestDisplaySize = Math.min(displayWidth, displayHeight);
|
||||
final int minSize = (int) Math.max(minEdgeSize, smallestDisplaySize * mDefaultSizePercent);
|
||||
|
||||
final int width;
|
||||
final int height;
|
||||
if (aspectRatio <= mMinAspectRatioForMinSize || aspectRatio > mMaxAspectRatioForMinSize) {
|
||||
// Beyond these points, we can just use the min size as the shorter edge
|
||||
if (aspectRatio <= 1) {
|
||||
// Portrait, width is the minimum size
|
||||
width = minSize;
|
||||
height = Math.round(width / aspectRatio);
|
||||
} else {
|
||||
// Landscape, height is the minimum size
|
||||
height = minSize;
|
||||
width = Math.round(height * aspectRatio);
|
||||
}
|
||||
} else {
|
||||
// Within these points, we ensure that the bounds fit within the radius of the limits
|
||||
// at the points
|
||||
final float widthAtMaxAspectRatioForMinSize = mMaxAspectRatioForMinSize * minSize;
|
||||
final float radius = PointF.length(widthAtMaxAspectRatioForMinSize, minSize);
|
||||
height = (int) Math.round(Math.sqrt((radius * radius)
|
||||
/ (aspectRatio * aspectRatio + 1)));
|
||||
width = Math.round(height * aspectRatio);
|
||||
}
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the adjusted size so that it conforms to the given aspectRatio, ensuring that the
|
||||
* minimum edge is at least minEdgeSize.
|
||||
*/
|
||||
public Size getSizeForAspectRatio(Size size, float aspectRatio, float minEdgeSize) {
|
||||
final int smallestSize = Math.min(size.getWidth(), size.getHeight());
|
||||
final int minSize = (int) Math.max(minEdgeSize, smallestSize);
|
||||
|
||||
final int width;
|
||||
final int height;
|
||||
if (aspectRatio <= 1) {
|
||||
// Portrait, width is the minimum size.
|
||||
width = minSize;
|
||||
height = Math.round(width / aspectRatio);
|
||||
} else {
|
||||
// Landscape, height is the minimum size
|
||||
height = minSize;
|
||||
width = Math.round(height * aspectRatio);
|
||||
}
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps internal states.
|
||||
*/
|
||||
|
||||
@@ -20,11 +20,9 @@ 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;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Size;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Calculates the snap targets and the snap position for the PIP given a position and a velocity.
|
||||
@@ -32,19 +30,6 @@ import android.util.Size;
|
||||
*/
|
||||
public class PipSnapAlgorithm {
|
||||
|
||||
private final float mDefaultSizePercent;
|
||||
private final float mMinAspectRatioForMinSize;
|
||||
private final float mMaxAspectRatioForMinSize;
|
||||
|
||||
public PipSnapAlgorithm(Context context) {
|
||||
Resources res = context.getResources();
|
||||
mDefaultSizePercent = res.getFloat(
|
||||
com.android.internal.R.dimen.config_pictureInPictureDefaultSizePercent);
|
||||
mMaxAspectRatioForMinSize = res.getFloat(
|
||||
com.android.internal.R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
|
||||
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fraction that describes where the PiP bounds is.
|
||||
* See {@link #getSnapFraction(Rect, Rect, int)}.
|
||||
@@ -135,82 +120,12 @@ public class PipSnapAlgorithm {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts {@param movementBoundsOut} so that it is the movement bounds for the given
|
||||
* {@param stackBounds}.
|
||||
*/
|
||||
public void getMovementBounds(Rect stackBounds, Rect insetBounds, Rect movementBoundsOut,
|
||||
int bottomOffset) {
|
||||
// Adjust the right/bottom to ensure the stack bounds never goes offscreen
|
||||
movementBoundsOut.set(insetBounds);
|
||||
movementBoundsOut.right = Math.max(insetBounds.left, insetBounds.right -
|
||||
stackBounds.width());
|
||||
movementBoundsOut.bottom = Math.max(insetBounds.top, insetBounds.bottom -
|
||||
stackBounds.height());
|
||||
movementBoundsOut.bottom -= bottomOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of the PiP at the given {@param aspectRatio}, ensuring that the minimum edge
|
||||
* is at least {@param minEdgeSize}.
|
||||
*/
|
||||
public Size getSizeForAspectRatio(float aspectRatio, float minEdgeSize, int displayWidth,
|
||||
int displayHeight) {
|
||||
final int smallestDisplaySize = Math.min(displayWidth, displayHeight);
|
||||
final int minSize = (int) Math.max(minEdgeSize, smallestDisplaySize * mDefaultSizePercent);
|
||||
|
||||
final int width;
|
||||
final int height;
|
||||
if (aspectRatio <= mMinAspectRatioForMinSize || aspectRatio > mMaxAspectRatioForMinSize) {
|
||||
// Beyond these points, we can just use the min size as the shorter edge
|
||||
if (aspectRatio <= 1) {
|
||||
// Portrait, width is the minimum size
|
||||
width = minSize;
|
||||
height = Math.round(width / aspectRatio);
|
||||
} else {
|
||||
// Landscape, height is the minimum size
|
||||
height = minSize;
|
||||
width = Math.round(height * aspectRatio);
|
||||
}
|
||||
} else {
|
||||
// Within these points, we ensure that the bounds fit within the radius of the limits
|
||||
// at the points
|
||||
final float widthAtMaxAspectRatioForMinSize = mMaxAspectRatioForMinSize * minSize;
|
||||
final float radius = PointF.length(widthAtMaxAspectRatioForMinSize, minSize);
|
||||
height = (int) Math.round(Math.sqrt((radius * radius) /
|
||||
(aspectRatio * aspectRatio + 1)));
|
||||
width = Math.round(height * aspectRatio);
|
||||
}
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the adjusted size so that it conforms to the given aspectRatio, ensuring that the
|
||||
* minimum edge is at least minEdgeSize.
|
||||
*/
|
||||
public Size getSizeForAspectRatio(Size size, float aspectRatio, float minEdgeSize) {
|
||||
final int smallestSize = Math.min(size.getWidth(), size.getHeight());
|
||||
final int minSize = (int) Math.max(minEdgeSize, smallestSize);
|
||||
|
||||
final int width;
|
||||
final int height;
|
||||
if (aspectRatio <= 1) {
|
||||
// Portrait, width is the minimum size.
|
||||
width = minSize;
|
||||
height = Math.round(width / aspectRatio);
|
||||
} else {
|
||||
// Landscape, height is the minimum size
|
||||
height = minSize;
|
||||
width = Math.round(height * aspectRatio);
|
||||
}
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
@VisibleForTesting
|
||||
void snapRectToClosestEdge(Rect stackBounds, Rect movementBounds, Rect boundsOut,
|
||||
@PipBoundsState.StashType int stashType) {
|
||||
int leftEdge = stackBounds.left;
|
||||
if (stashType == STASH_TYPE_LEFT) {
|
||||
|
||||
@@ -307,8 +307,7 @@ public class PipTouchHandler {
|
||||
|
||||
public void adjustBoundsForRotation(Rect outBounds, Rect curBounds, Rect insetBounds) {
|
||||
final Rect toMovementBounds = new Rect();
|
||||
mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(outBounds, insetBounds,
|
||||
toMovementBounds, 0);
|
||||
mPipBoundsAlgorithm.getMovementBounds(outBounds, insetBounds, toMovementBounds, 0);
|
||||
final int prevBottom = mPipBoundsState.getMovementBounds().bottom
|
||||
- mMovementBoundsExtraOffsets;
|
||||
if ((prevBottom - mBottomOffsetBufferPx) <= curBounds.top) {
|
||||
@@ -339,13 +338,13 @@ public class PipTouchHandler {
|
||||
|
||||
// Re-calculate the expanded bounds
|
||||
Rect normalMovementBounds = new Rect();
|
||||
mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(normalBounds, insetBounds,
|
||||
mPipBoundsAlgorithm.getMovementBounds(normalBounds, insetBounds,
|
||||
normalMovementBounds, bottomOffset);
|
||||
|
||||
if (mPipBoundsState.getMovementBounds().isEmpty()) {
|
||||
// mMovementBounds is not initialized yet and a clean movement bounds without
|
||||
// bottom offset shall be used later in this function.
|
||||
mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(curBounds, insetBounds,
|
||||
mPipBoundsAlgorithm.getMovementBounds(curBounds, insetBounds,
|
||||
mPipBoundsState.getMovementBounds(), 0 /* bottomOffset */);
|
||||
}
|
||||
|
||||
@@ -353,12 +352,12 @@ public class PipTouchHandler {
|
||||
float aspectRatio = (float) normalBounds.width() / normalBounds.height();
|
||||
Point displaySize = new Point();
|
||||
mContext.getDisplay().getRealSize(displaySize);
|
||||
Size expandedSize = mPipBoundsAlgorithm.getSnapAlgorithm().getSizeForAspectRatio(
|
||||
Size expandedSize = mPipBoundsAlgorithm.getSizeForAspectRatio(
|
||||
aspectRatio, mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
|
||||
mPipBoundsState.setExpandedBounds(
|
||||
new Rect(0, 0, expandedSize.getWidth(), expandedSize.getHeight()));
|
||||
Rect expandedMovementBounds = new Rect();
|
||||
mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(
|
||||
mPipBoundsAlgorithm.getMovementBounds(
|
||||
mPipBoundsState.getExpandedBounds(), insetBounds, expandedMovementBounds,
|
||||
bottomOffset);
|
||||
|
||||
@@ -381,7 +380,7 @@ public class PipTouchHandler {
|
||||
} else {
|
||||
final boolean isExpanded = mMenuState == MENU_STATE_FULL && willResizeMenu();
|
||||
final Rect toMovementBounds = new Rect();
|
||||
mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(curBounds, insetBounds,
|
||||
mPipBoundsAlgorithm.getMovementBounds(curBounds, insetBounds,
|
||||
toMovementBounds, mIsImeShowing ? mImeHeight : 0);
|
||||
final int prevBottom = mPipBoundsState.getMovementBounds().bottom
|
||||
- mMovementBoundsExtraOffsets;
|
||||
@@ -659,7 +658,7 @@ public class PipTouchHandler {
|
||||
|
||||
private void animateToUnexpandedState(Rect restoreBounds) {
|
||||
Rect restoredMovementBounds = new Rect();
|
||||
mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(restoreBounds,
|
||||
mPipBoundsAlgorithm.getMovementBounds(restoreBounds,
|
||||
mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
|
||||
mMotionHelper.animateToUnexpandedState(restoreBounds, mSavedSnapFraction,
|
||||
restoredMovementBounds, mPipBoundsState.getMovementBounds(), false /* immediate */);
|
||||
@@ -865,7 +864,7 @@ public class PipTouchHandler {
|
||||
* resized.
|
||||
*/
|
||||
private void updateMovementBounds() {
|
||||
mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(mPipBoundsState.getBounds(),
|
||||
mPipBoundsAlgorithm.getMovementBounds(mPipBoundsState.getBounds(),
|
||||
mInsetBounds, mPipBoundsState.getMovementBounds(), mIsImeShowing ? mImeHeight : 0);
|
||||
mMotionHelper.onMovementBoundsChanged();
|
||||
|
||||
@@ -877,7 +876,7 @@ public class PipTouchHandler {
|
||||
|
||||
private Rect getMovementBounds(Rect curBounds) {
|
||||
Rect movementBounds = new Rect();
|
||||
mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(curBounds, mInsetBounds,
|
||||
mPipBoundsAlgorithm.getMovementBounds(curBounds, mInsetBounds,
|
||||
movementBounds, mIsImeShowing ? mImeHeight : 0);
|
||||
return movementBounds;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
|
||||
private static final float DEFAULT_ASPECT_RATIO = 1f;
|
||||
private static final float MIN_ASPECT_RATIO = 0.5f;
|
||||
private static final float MAX_ASPECT_RATIO = 2f;
|
||||
private static final int DEFAULT_MIN_EDGE_SIZE = 100;
|
||||
|
||||
private PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
private DisplayInfo mDefaultDisplayInfo;
|
||||
@@ -73,7 +74,8 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
|
||||
com.android.internal.R.integer.config_defaultPictureInPictureGravity,
|
||||
Gravity.END | Gravity.BOTTOM);
|
||||
res.addOverride(
|
||||
com.android.internal.R.dimen.default_minimal_size_pip_resizable_task, 100);
|
||||
com.android.internal.R.dimen.default_minimal_size_pip_resizable_task,
|
||||
DEFAULT_MIN_EDGE_SIZE);
|
||||
res.addOverride(
|
||||
com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets,
|
||||
"16x16");
|
||||
@@ -111,6 +113,127 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
|
||||
ASPECT_RATIO_ERROR_MARGIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDefaultBounds_noOverrideMinSize_matchesDefaultSizeAndAspectRatio() {
|
||||
final Size defaultSize = mPipBoundsAlgorithm.getSizeForAspectRatio(DEFAULT_ASPECT_RATIO,
|
||||
DEFAULT_MIN_EDGE_SIZE, mDefaultDisplayInfo.logicalWidth,
|
||||
mDefaultDisplayInfo.logicalHeight);
|
||||
|
||||
mPipBoundsState.setOverrideMinSize(null);
|
||||
final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
assertEquals(defaultSize, new Size(defaultBounds.width(), defaultBounds.height()));
|
||||
assertEquals(DEFAULT_ASPECT_RATIO, getRectAspectRatio(defaultBounds),
|
||||
ASPECT_RATIO_ERROR_MARGIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDefaultBounds_widerOverrideMinSize_matchesMinSizeWidthAndDefaultAspectRatio() {
|
||||
overrideDefaultAspectRatio(1.0f);
|
||||
// The min size's aspect ratio is greater than the default aspect ratio.
|
||||
final Size overrideMinSize = new Size(150, 120);
|
||||
|
||||
mPipBoundsState.setOverrideMinSize(overrideMinSize);
|
||||
final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
// The default aspect ratio should trump the min size aspect ratio.
|
||||
assertEquals(DEFAULT_ASPECT_RATIO, getRectAspectRatio(defaultBounds),
|
||||
ASPECT_RATIO_ERROR_MARGIN);
|
||||
// The width of the min size is still used with the default aspect ratio.
|
||||
assertEquals(overrideMinSize.getWidth(), defaultBounds.width());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDefaultBounds_tallerOverrideMinSize_matchesMinSizeHeightAndDefaultAspectRatio() {
|
||||
overrideDefaultAspectRatio(1.0f);
|
||||
// The min size's aspect ratio is greater than the default aspect ratio.
|
||||
final Size overrideMinSize = new Size(120, 150);
|
||||
|
||||
mPipBoundsState.setOverrideMinSize(overrideMinSize);
|
||||
final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
// The default aspect ratio should trump the min size aspect ratio.
|
||||
assertEquals(DEFAULT_ASPECT_RATIO, getRectAspectRatio(defaultBounds),
|
||||
ASPECT_RATIO_ERROR_MARGIN);
|
||||
// The height of the min size is still used with the default aspect ratio.
|
||||
assertEquals(overrideMinSize.getHeight(), defaultBounds.height());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDefaultBounds_imeShowing_offsetByImeHeight() {
|
||||
final int imeHeight = 30;
|
||||
mPipBoundsState.setImeVisibility(false, 0);
|
||||
final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
mPipBoundsState.setImeVisibility(true, imeHeight);
|
||||
final Rect defaultBoundsWithIme = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
assertEquals(imeHeight, defaultBounds.top - defaultBoundsWithIme.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDefaultBounds_shelfShowing_offsetByShelfHeight() {
|
||||
final int shelfHeight = 30;
|
||||
mPipBoundsState.setShelfVisibility(false, 0);
|
||||
final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
mPipBoundsState.setShelfVisibility(true, shelfHeight);
|
||||
final Rect defaultBoundsWithShelf = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
assertEquals(shelfHeight, defaultBounds.top - defaultBoundsWithShelf.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDefaultBounds_imeAndShelfShowing_offsetByTallest() {
|
||||
final int imeHeight = 30;
|
||||
final int shelfHeight = 40;
|
||||
mPipBoundsState.setImeVisibility(false, 0);
|
||||
mPipBoundsState.setShelfVisibility(false, 0);
|
||||
final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
mPipBoundsState.setImeVisibility(true, imeHeight);
|
||||
mPipBoundsState.setShelfVisibility(true, shelfHeight);
|
||||
final Rect defaultBoundsWithIme = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
assertEquals(shelfHeight, defaultBounds.top - defaultBoundsWithIme.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDefaultBounds_boundsAtDefaultGravity() {
|
||||
final Rect insetBounds = new Rect();
|
||||
mPipBoundsAlgorithm.getInsetBounds(insetBounds);
|
||||
overrideDefaultStackGravity(Gravity.END | Gravity.BOTTOM);
|
||||
|
||||
final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
assertEquals(insetBounds.bottom, defaultBounds.bottom);
|
||||
assertEquals(insetBounds.right, defaultBounds.right);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNormalBounds_invalidAspectRatio_returnsDefaultBounds() {
|
||||
final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
|
||||
// Set an invalid current aspect ratio.
|
||||
mPipBoundsState.setAspectRatio(MIN_ASPECT_RATIO / 2);
|
||||
final Rect normalBounds = mPipBoundsAlgorithm.getNormalBounds();
|
||||
|
||||
assertEquals(defaultBounds, normalBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNormalBounds_validAspectRatio_returnsAdjustedDefaultBounds() {
|
||||
final Rect defaultBoundsAdjustedToAspectRatio = mPipBoundsAlgorithm.getDefaultBounds();
|
||||
mPipBoundsAlgorithm.transformBoundsToAspectRatio(defaultBoundsAdjustedToAspectRatio,
|
||||
MIN_ASPECT_RATIO, false /* useCurrentMinEdgeSize */, false /* useCurrentSize */);
|
||||
|
||||
// Set a valid current aspect ratio different that the default.
|
||||
mPipBoundsState.setAspectRatio(MIN_ASPECT_RATIO);
|
||||
final Rect normalBounds = mPipBoundsAlgorithm.getNormalBounds();
|
||||
|
||||
assertEquals(defaultBoundsAdjustedToAspectRatio, normalBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntryDestinationBounds_returnBoundsMatchesAspectRatio() {
|
||||
final float[] aspectRatios = new float[] {
|
||||
@@ -121,8 +244,7 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
|
||||
for (float aspectRatio : aspectRatios) {
|
||||
mPipBoundsState.setAspectRatio(aspectRatio);
|
||||
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
|
||||
final float actualAspectRatio =
|
||||
destinationBounds.width() / (destinationBounds.height() * 1f);
|
||||
final float actualAspectRatio = getRectAspectRatio(destinationBounds);
|
||||
assertEquals("Destination bounds matches the given aspect ratio",
|
||||
aspectRatio, actualAspectRatio, ASPECT_RATIO_ERROR_MARGIN);
|
||||
}
|
||||
@@ -274,6 +396,22 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
|
||||
assertBoundsInclusionWithMargin("useDefaultBounds", defaultBounds, actualBounds);
|
||||
}
|
||||
|
||||
private void overrideDefaultAspectRatio(float aspectRatio) {
|
||||
final TestableResources res = mContext.getOrCreateTestableResources();
|
||||
res.addOverride(
|
||||
com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio,
|
||||
aspectRatio);
|
||||
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
|
||||
}
|
||||
|
||||
private void overrideDefaultStackGravity(int stackGravity) {
|
||||
final TestableResources res = mContext.getOrCreateTestableResources();
|
||||
res.addOverride(
|
||||
com.android.internal.R.integer.config_defaultPictureInPictureGravity,
|
||||
stackGravity);
|
||||
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
|
||||
}
|
||||
|
||||
private void assertBoundsInclusionWithMargin(String from, Rect expected, Rect actual) {
|
||||
final Rect expectedWithMargin = new Rect(expected);
|
||||
expectedWithMargin.inset(-ROUNDING_ERROR_MARGIN, -ROUNDING_ERROR_MARGIN);
|
||||
@@ -282,4 +420,8 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
|
||||
+ " with error margin " + ROUNDING_ERROR_MARGIN,
|
||||
expectedWithMargin.contains(actual));
|
||||
}
|
||||
|
||||
private static float getRectAspectRatio(Rect rect) {
|
||||
return rect.width() / (rect.height() * 1f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.pip;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** Tests for {@link PipSnapAlgorithm}. **/
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@SmallTest
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
public class PipSnapAlgorithmTest extends ShellTestCase {
|
||||
private static final int DEFAULT_STASH_OFFSET = 32;
|
||||
private static final Rect DISPLAY_BOUNDS = new Rect(0, 0, 2000, 2000);
|
||||
private static final Rect STACK_BOUNDS_CENTERED = new Rect(900, 900, 1100, 1100);
|
||||
private static final Rect MOVEMENT_BOUNDS = new Rect(0, 0,
|
||||
DISPLAY_BOUNDS.width() - STACK_BOUNDS_CENTERED.width(),
|
||||
DISPLAY_BOUNDS.width() - STACK_BOUNDS_CENTERED.width());
|
||||
|
||||
private PipSnapAlgorithm mPipSnapAlgorithm;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mPipSnapAlgorithm = new PipSnapAlgorithm();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplySnapFraction_topEdge() {
|
||||
final float snapFraction = 0.25f;
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
|
||||
mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction);
|
||||
|
||||
assertEquals(MOVEMENT_BOUNDS.width() / 4, bounds.left);
|
||||
assertEquals(MOVEMENT_BOUNDS.top, bounds.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplySnapFraction_rightEdge() {
|
||||
final float snapFraction = 1.5f;
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
|
||||
mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction);
|
||||
|
||||
assertEquals(MOVEMENT_BOUNDS.right, bounds.left);
|
||||
assertEquals(MOVEMENT_BOUNDS.height() / 2, bounds.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplySnapFraction_bottomEdge() {
|
||||
final float snapFraction = 2.25f;
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
|
||||
mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction);
|
||||
|
||||
assertEquals((int) (MOVEMENT_BOUNDS.width() * 0.75f), bounds.left);
|
||||
assertEquals(MOVEMENT_BOUNDS.bottom, bounds.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplySnapFraction_leftEdge() {
|
||||
final float snapFraction = 3.75f;
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
|
||||
mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction);
|
||||
|
||||
assertEquals(MOVEMENT_BOUNDS.left, bounds.left);
|
||||
assertEquals((int) (MOVEMENT_BOUNDS.height() * 0.25f), bounds.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplySnapFraction_notStashed_isNotOffBounds() {
|
||||
final float snapFraction = 2f;
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
|
||||
mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction,
|
||||
PipBoundsState.STASH_TYPE_NONE, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS);
|
||||
|
||||
assertEquals(MOVEMENT_BOUNDS.right, bounds.left);
|
||||
assertEquals(MOVEMENT_BOUNDS.bottom, bounds.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplySnapFraction_stashedLeft() {
|
||||
final float snapFraction = 3f;
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
|
||||
mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction,
|
||||
PipBoundsState.STASH_TYPE_LEFT, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS);
|
||||
|
||||
final int offBoundsWidth = bounds.width() - DEFAULT_STASH_OFFSET;
|
||||
assertEquals(MOVEMENT_BOUNDS.left - offBoundsWidth, bounds.left);
|
||||
assertEquals(MOVEMENT_BOUNDS.bottom, bounds.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplySnapFraction_stashedRight() {
|
||||
final float snapFraction = 2f;
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
|
||||
mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction,
|
||||
PipBoundsState.STASH_TYPE_RIGHT, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS);
|
||||
|
||||
assertEquals(DISPLAY_BOUNDS.right - DEFAULT_STASH_OFFSET, bounds.left);
|
||||
assertEquals(MOVEMENT_BOUNDS.bottom, bounds.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnapRectToClosestEdge_rightEdge() {
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
// Move the centered rect slightly to the right side.
|
||||
bounds.offset(10, 0);
|
||||
|
||||
mPipSnapAlgorithm.snapRectToClosestEdge(bounds, MOVEMENT_BOUNDS, bounds,
|
||||
PipBoundsState.STASH_TYPE_NONE);
|
||||
|
||||
assertEquals(MOVEMENT_BOUNDS.right, bounds.left);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnapRectToClosestEdge_leftEdge() {
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
// Move the centered rect slightly to the left side.
|
||||
bounds.offset(-10, 0);
|
||||
|
||||
mPipSnapAlgorithm.snapRectToClosestEdge(bounds, MOVEMENT_BOUNDS, bounds,
|
||||
PipBoundsState.STASH_TYPE_NONE);
|
||||
|
||||
assertEquals(MOVEMENT_BOUNDS.left, bounds.left);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnapRectToClosestEdge_topEdge() {
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
// Move the centered rect slightly to the top half.
|
||||
bounds.offset(0, -10);
|
||||
|
||||
mPipSnapAlgorithm.snapRectToClosestEdge(bounds, MOVEMENT_BOUNDS, bounds,
|
||||
PipBoundsState.STASH_TYPE_NONE);
|
||||
|
||||
assertEquals(MOVEMENT_BOUNDS.top, bounds.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnapRectToClosestEdge_bottomEdge() {
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
// Move the centered rect slightly to the bottom half.
|
||||
bounds.offset(0, 10);
|
||||
|
||||
mPipSnapAlgorithm.snapRectToClosestEdge(bounds, MOVEMENT_BOUNDS, bounds,
|
||||
PipBoundsState.STASH_TYPE_NONE);
|
||||
|
||||
assertEquals(MOVEMENT_BOUNDS.bottom, bounds.top);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnapRectToClosestEdge_stashed_unStahesBounds() {
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
// Stash it on the left side.
|
||||
mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, 3.5f,
|
||||
PipBoundsState.STASH_TYPE_LEFT, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS);
|
||||
|
||||
mPipSnapAlgorithm.snapRectToClosestEdge(bounds, MOVEMENT_BOUNDS, bounds,
|
||||
PipBoundsState.STASH_TYPE_LEFT);
|
||||
|
||||
assertEquals(MOVEMENT_BOUNDS.left, bounds.left);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSnapFraction_leftEdge() {
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
// Move it slightly to the left side.
|
||||
bounds.offset(-10, 0);
|
||||
|
||||
final float snapFraction = mPipSnapAlgorithm.getSnapFraction(bounds, MOVEMENT_BOUNDS);
|
||||
|
||||
assertEquals(3.5f, snapFraction, 0.1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSnapFraction_rightEdge() {
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
// Move it slightly to the right side.
|
||||
bounds.offset(10, 0);
|
||||
|
||||
final float snapFraction = mPipSnapAlgorithm.getSnapFraction(bounds, MOVEMENT_BOUNDS);
|
||||
|
||||
assertEquals(1.5f, snapFraction, 0.1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSnapFraction_topEdge() {
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
// Move it slightly to the top half.
|
||||
bounds.offset(0, -10);
|
||||
|
||||
final float snapFraction = mPipSnapAlgorithm.getSnapFraction(bounds, MOVEMENT_BOUNDS);
|
||||
|
||||
assertEquals(0.5f, snapFraction, 0.1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSnapFraction_bottomEdge() {
|
||||
final Rect bounds = new Rect(STACK_BOUNDS_CENTERED);
|
||||
// Move it slightly to the bottom half.
|
||||
bounds.offset(0, 10);
|
||||
|
||||
final float snapFraction = mPipSnapAlgorithm.getSnapFraction(bounds, MOVEMENT_BOUNDS);
|
||||
|
||||
assertEquals(2.5f, snapFraction, 0.1f);
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
mPipBoundsState = new PipBoundsState(mContext);
|
||||
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState);
|
||||
mPipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
|
||||
mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
|
||||
mPipSnapAlgorithm = new PipSnapAlgorithm();
|
||||
mPipTouchHandler = new PipTouchHandler(mContext, mPipMenuActivityController,
|
||||
mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer,
|
||||
mFloatingContentCoordinator, mPipUiEventLogger);
|
||||
@@ -115,7 +115,8 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
@Test
|
||||
public void updateMovementBounds_minBounds() {
|
||||
Rect expectedMinMovementBounds = new Rect();
|
||||
mPipSnapAlgorithm.getMovementBounds(mMinBounds, mInsetBounds, expectedMinMovementBounds, 0);
|
||||
mPipBoundsAlgorithm.getMovementBounds(mMinBounds, mInsetBounds, expectedMinMovementBounds,
|
||||
0);
|
||||
|
||||
mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
|
||||
mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);
|
||||
@@ -129,12 +130,13 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
public void updateMovementBounds_maxBounds() {
|
||||
Point displaySize = new Point();
|
||||
mContext.getDisplay().getRealSize(displaySize);
|
||||
Size maxSize = mPipSnapAlgorithm.getSizeForAspectRatio(1,
|
||||
Size maxSize = mPipBoundsAlgorithm.getSizeForAspectRatio(1,
|
||||
mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.pip_expanded_shortest_edge_size), displaySize.x, displaySize.y);
|
||||
Rect maxBounds = new Rect(0, 0, maxSize.getWidth(), maxSize.getHeight());
|
||||
Rect expectedMaxMovementBounds = new Rect();
|
||||
mPipSnapAlgorithm.getMovementBounds(maxBounds, mInsetBounds, expectedMaxMovementBounds, 0);
|
||||
mPipBoundsAlgorithm.getMovementBounds(maxBounds, mInsetBounds, expectedMaxMovementBounds,
|
||||
0);
|
||||
|
||||
mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
|
||||
mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);
|
||||
|
||||
Reference in New Issue
Block a user