Fix stashed PiP so it only moves up/down if outside of insets
Add unit tests for adjust() method in PhonePipKeepClearAlgorithm. This covers test cases for applying gravity, moving PiP away from keep clear areas (which is equivalent to findUnoccludedPosition test cases), and for ignoring keep clear areas if PiP is stashed, testing only the up/down movement added by this change. Bug: 286478425 Test: atest PhonePipKeepClearAlgorithmTest Test: before http://recall/-/ekEuGtt9d9HWqkUtAzpHx8/dY9IMjhv5eBf0501pUCPKp Test: after http://recall/-/ekEuGtt9d9HWqkUtAzpHx8/eLrBdqzAKlGiNvFetdIsh9 Change-Id: I478d364a31652f6507d2a289295d336b62d0db81
This commit is contained in:
@@ -63,6 +63,15 @@ public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithmInterfac
|
||||
if (pipBoundsState.isImeShowing()) {
|
||||
insets.bottom -= pipBoundsState.getImeHeight();
|
||||
}
|
||||
// if PiP is stashed we only adjust the vertical position if it's outside of insets and
|
||||
// ignore all keep clear areas, since it's already on the side
|
||||
if (pipBoundsState.isStashed()) {
|
||||
if (startingBounds.bottom > insets.bottom || startingBounds.top < insets.top) {
|
||||
// bring PiP back to be aligned by bottom inset
|
||||
startingBounds.offset(0, insets.bottom - startingBounds.bottom);
|
||||
}
|
||||
return startingBounds;
|
||||
}
|
||||
Rect pipBounds = new Rect(startingBounds);
|
||||
|
||||
boolean shouldApplyGravity = false;
|
||||
|
||||
@@ -18,6 +18,9 @@ package com.android.wm.shell.pip.phone;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
@@ -26,10 +29,13 @@ import android.testing.TestableLooper;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@@ -42,6 +48,10 @@ import java.util.Set;
|
||||
public class PhonePipKeepClearAlgorithmTest extends ShellTestCase {
|
||||
|
||||
private PhonePipKeepClearAlgorithm mPipKeepClearAlgorithm;
|
||||
|
||||
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
|
||||
@Mock private PipBoundsState mMockPipBoundsState;
|
||||
|
||||
private static final Rect DISPLAY_BOUNDS = new Rect(0, 0, 1000, 1000);
|
||||
|
||||
@Before
|
||||
@@ -73,7 +83,6 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase {
|
||||
|
||||
@Test
|
||||
public void findUnoccludedPosition_withCollidingUnrestrictedKeepClearArea_moveBounds() {
|
||||
// TODO(b/183746978): update this test to accommodate for the updated algorithm
|
||||
final Rect inBounds = new Rect(0, 0, 100, 100);
|
||||
final Rect keepClearRect = new Rect(50, 50, 150, 150);
|
||||
|
||||
@@ -93,4 +102,202 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase {
|
||||
|
||||
assertEquals(inBounds, outBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_withCollidingRestrictedKeepClearArea_moveBounds() {
|
||||
final Rect pipBounds = new Rect(0, 0, 100, 100);
|
||||
final Rect keepClearRect = new Rect(50, 50, 150, 150);
|
||||
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
|
||||
when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
|
||||
doAnswer(invocation -> {
|
||||
Rect arg0 = invocation.getArgument(0);
|
||||
arg0.set(DISPLAY_BOUNDS);
|
||||
return null;
|
||||
}).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(
|
||||
mMockPipBoundsState, mMockPipBoundsAlgorithm);
|
||||
|
||||
assertFalse(outBounds.contains(keepClearRect));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_withNonCollidingRestrictedKeepClearArea_boundsUnchanged() {
|
||||
final Rect pipBounds = new Rect(0, 0, 100, 100);
|
||||
final Rect keepClearRect = new Rect(100, 100, 150, 150);
|
||||
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
|
||||
when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
|
||||
doAnswer(invocation -> {
|
||||
Rect arg0 = invocation.getArgument(0);
|
||||
arg0.set(DISPLAY_BOUNDS);
|
||||
return null;
|
||||
}).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(
|
||||
mMockPipBoundsState, mMockPipBoundsAlgorithm);
|
||||
|
||||
assertFalse(outBounds.contains(keepClearRect));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_withCollidingRestrictedKeepClearArea_whileStashed_boundsUnchanged() {
|
||||
final Rect pipBounds = new Rect(0, 0, 100, 100);
|
||||
final Rect keepClearRect = new Rect(50, 50, 150, 150);
|
||||
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
|
||||
when(mMockPipBoundsState.isStashed()).thenReturn(true);
|
||||
when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
|
||||
doAnswer(invocation -> {
|
||||
Rect arg0 = invocation.getArgument(0);
|
||||
arg0.set(DISPLAY_BOUNDS);
|
||||
return null;
|
||||
}).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(
|
||||
mMockPipBoundsState, mMockPipBoundsAlgorithm);
|
||||
|
||||
assertEquals(pipBounds, outBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_withNonCollidingRestrictedKeepClearArea_whileStashed_boundsUnchanged() {
|
||||
final Rect pipBounds = new Rect(0, 0, 100, 100);
|
||||
final Rect keepClearRect = new Rect(100, 100, 150, 150);
|
||||
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
|
||||
when(mMockPipBoundsState.isStashed()).thenReturn(true);
|
||||
when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
|
||||
doAnswer(invocation -> {
|
||||
Rect arg0 = invocation.getArgument(0);
|
||||
arg0.set(DISPLAY_BOUNDS);
|
||||
return null;
|
||||
}).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(
|
||||
mMockPipBoundsState, mMockPipBoundsAlgorithm);
|
||||
|
||||
assertEquals(pipBounds, outBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_aboveDisplayBounds_onLeftEdge_appliesBottomLeftGravity() {
|
||||
final Rect pipBounds = new Rect(
|
||||
0, DISPLAY_BOUNDS.top - 50, 100, DISPLAY_BOUNDS.top + 50);
|
||||
final Rect expected = new Rect(
|
||||
0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
|
||||
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
|
||||
doAnswer(invocation -> {
|
||||
Rect arg0 = invocation.getArgument(0);
|
||||
arg0.set(DISPLAY_BOUNDS);
|
||||
return null;
|
||||
}).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
|
||||
when(mMockPipBoundsAlgorithm.getSnapFraction(any(Rect.class))).thenReturn(0f);
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(
|
||||
mMockPipBoundsState, mMockPipBoundsAlgorithm);
|
||||
|
||||
assertEquals(expected, outBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_belowDisplayBounds_onLeftEdge_appliesBottomLeftGravity() {
|
||||
final Rect pipBounds = new Rect(
|
||||
0, DISPLAY_BOUNDS.bottom - 50, 100, DISPLAY_BOUNDS.bottom + 50);
|
||||
final Rect expected = new Rect(
|
||||
0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
|
||||
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
|
||||
doAnswer(invocation -> {
|
||||
Rect arg0 = invocation.getArgument(0);
|
||||
arg0.set(DISPLAY_BOUNDS);
|
||||
return null;
|
||||
}).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
|
||||
when(mMockPipBoundsAlgorithm.getSnapFraction(any(Rect.class))).thenReturn(3f);
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(
|
||||
mMockPipBoundsState, mMockPipBoundsAlgorithm);
|
||||
|
||||
assertEquals(expected, outBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_aboveDisplayBounds_onRightEdge_appliesBottomRightGravity() {
|
||||
final Rect pipBounds = new Rect(
|
||||
DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.top - 50,
|
||||
DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.top + 50);
|
||||
final Rect expected = new Rect(
|
||||
DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 100,
|
||||
DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom);
|
||||
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
|
||||
doAnswer(invocation -> {
|
||||
Rect arg0 = invocation.getArgument(0);
|
||||
arg0.set(DISPLAY_BOUNDS);
|
||||
return null;
|
||||
}).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
|
||||
when(mMockPipBoundsAlgorithm.getSnapFraction(any(Rect.class))).thenReturn(1f);
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(
|
||||
mMockPipBoundsState, mMockPipBoundsAlgorithm);
|
||||
|
||||
assertEquals(expected, outBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_belowDisplayBounds_onRightEdge_appliesBottomRightGravity() {
|
||||
final Rect pipBounds = new Rect(
|
||||
DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 50,
|
||||
DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom + 50);
|
||||
final Rect expected = new Rect(
|
||||
DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 100,
|
||||
DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom);
|
||||
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
|
||||
doAnswer(invocation -> {
|
||||
Rect arg0 = invocation.getArgument(0);
|
||||
arg0.set(DISPLAY_BOUNDS);
|
||||
return null;
|
||||
}).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
|
||||
when(mMockPipBoundsAlgorithm.getSnapFraction(any(Rect.class))).thenReturn(2f);
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(
|
||||
mMockPipBoundsState, mMockPipBoundsAlgorithm);
|
||||
|
||||
assertEquals(expected, outBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_whileStashed_aboveDisplayBounds_alignsToBottomInset() {
|
||||
final Rect pipBounds = new Rect(
|
||||
0, DISPLAY_BOUNDS.top - 50, 100, DISPLAY_BOUNDS.top + 50);
|
||||
final Rect expected = new Rect(
|
||||
0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
|
||||
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
|
||||
when(mMockPipBoundsState.isStashed()).thenReturn(true);
|
||||
doAnswer(invocation -> {
|
||||
Rect arg0 = invocation.getArgument(0);
|
||||
arg0.set(DISPLAY_BOUNDS);
|
||||
return null;
|
||||
}).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(
|
||||
mMockPipBoundsState, mMockPipBoundsAlgorithm);
|
||||
|
||||
assertEquals(expected, outBounds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_whileStashed_belowDisplayBounds_alignsToBottomInset() {
|
||||
final Rect pipBounds = new Rect(
|
||||
0, DISPLAY_BOUNDS.bottom - 50, 100, DISPLAY_BOUNDS.bottom + 50);
|
||||
final Rect expected = new Rect(
|
||||
0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
|
||||
when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
|
||||
when(mMockPipBoundsState.isStashed()).thenReturn(true);
|
||||
doAnswer(invocation -> {
|
||||
Rect arg0 = invocation.getArgument(0);
|
||||
arg0.set(DISPLAY_BOUNDS);
|
||||
return null;
|
||||
}).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
|
||||
|
||||
final Rect outBounds = mPipKeepClearAlgorithm.adjust(
|
||||
mMockPipBoundsState, mMockPipBoundsAlgorithm);
|
||||
|
||||
assertEquals(expected, outBounds);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user