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:
Mateusz Cicheński
2023-06-10 00:35:28 +00:00
parent c831c399fa
commit ef4a74170f
2 changed files with 217 additions and 1 deletions

View File

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

View File

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