Fix WM Jetpack device state updates and test failures
- Update window layouts when device state updates with Sidecar.
- Allow empty bounds for features in ExtensionTest, check if both
width and height are not zero simultaneously instead.
- Update valid bounds calculation in TestBoundsUtil - feature bounds
must be in window coordinate space and therefore start at 0 at either
top or left edge.
- Allow duplicate window layout updates from Sidecar.
Test: gradlew window:window:connectedAndroidTest
Bug: 174896792
Bug: 174894149
Bug: 172589087
Change-Id: I3380958de985cf75504e1fa74fbb4c6b104bb5c8
diff --git a/window/window/src/androidTest/java/androidx/window/ExtensionTest.java b/window/window/src/androidTest/java/androidx/window/ExtensionTest.java
index 829614a..6afbc51 100644
--- a/window/window/src/androidTest/java/androidx/window/ExtensionTest.java
+++ b/window/window/src/androidTest/java/androidx/window/ExtensionTest.java
@@ -110,7 +110,7 @@
}
@Test
- public void testWindowLayoutInfoCallback() {
+ public void testWindowLayoutCallback() {
assumeExtensionV10_V01();
ExtensionInterfaceCompat extension = initAndVerifyExtension(mContext);
ExtensionCallbackInterface callbackInterface = mock(ExtensionCallbackInterface.class);
@@ -121,7 +121,7 @@
assertTrue("Layout must happen after launch", activity.waitForLayout());
- verify(callbackInterface).onWindowLayoutChanged(any(), argThat(
+ verify(callbackInterface, atLeastOnce()).onWindowLayoutChanged(any(), argThat(
new WindowLayoutInfoValidator(activity)));
}
@@ -271,7 +271,8 @@
Rect featureRect = feature.getBounds();
WindowMetrics windowMetrics = new WindowManager(activity).getCurrentWindowMetrics();
- if (featureRect.isEmpty() || featureRect.left < 0 || featureRect.top < 0) {
+ if ((featureRect.height() == 0 && featureRect.width() == 0) || featureRect.left < 0
+ || featureRect.top < 0) {
return false;
}
if (featureRect.right < 1 || featureRect.right > windowMetrics.getBounds().width()) {
diff --git a/window/window/src/androidTest/java/androidx/window/SidecarCompatDeviceTest.java b/window/window/src/androidTest/java/androidx/window/SidecarCompatDeviceTest.java
index 627f589..75a20e8 100644
--- a/window/window/src/androidTest/java/androidx/window/SidecarCompatDeviceTest.java
+++ b/window/window/src/androidTest/java/androidx/window/SidecarCompatDeviceTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -87,7 +88,7 @@
SidecarWindowLayoutInfo sidecarWindowLayoutInfo =
mSidecarCompat.mSidecar.getWindowLayoutInfo(windowToken);
- verify(callbackInterface).onWindowLayoutChanged(any(),
+ verify(callbackInterface, atLeastOnce()).onWindowLayoutChanged(any(),
argThat(new SidecarMatcher(sidecarWindowLayoutInfo)));
}
diff --git a/window/window/src/androidTest/java/androidx/window/SidecarCompatTest.java b/window/window/src/androidTest/java/androidx/window/SidecarCompatTest.java
index 8de906b..5acba49 100644
--- a/window/window/src/androidTest/java/androidx/window/SidecarCompatTest.java
+++ b/window/window/src/androidTest/java/androidx/window/SidecarCompatTest.java
@@ -25,11 +25,14 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -127,7 +130,7 @@
fakeSidecarImp.triggerDeviceState(deviceState);
- verify(mockCallback).onDeviceStateChanged(any());
+ verify(mockCallback, atLeastOnce()).onDeviceStateChanged(any());
}
@Test
@@ -144,7 +147,8 @@
fakeSidecarImp.triggerGoodSignal();
- verify(mockCallback).onWindowLayoutChanged(eq(mActivity), any(WindowLayoutInfo.class));
+ verify(mockCallback, atLeastOnce()).onWindowLayoutChanged(eq(mActivity),
+ any(WindowLayoutInfo.class));
}
@Test
@@ -402,6 +406,47 @@
verify(listener).onDeviceStateChanged(expectedDeviceState);
}
+ @Test
+ public void testOnDeviceStateChangedUpdatesWindowLayout() {
+ FakeExtensionImp fakeSidecarImp = new FakeExtensionImp(
+ newDeviceState(SidecarDeviceState.POSTURE_CLOSED),
+ validWindowLayoutInfo());
+ SidecarCompat compat = new SidecarCompat(fakeSidecarImp, new SidecarAdapter());
+ ExtensionInterfaceCompat.ExtensionCallbackInterface mockCallback = mock(
+ ExtensionInterfaceCompat.ExtensionCallbackInterface.class);
+ compat.setExtensionCallback(mockCallback);
+ compat.onWindowLayoutChangeListenerAdded(mActivity);
+ ArgumentCaptor<WindowLayoutInfo> windowLayoutCaptor = ArgumentCaptor.forClass(
+ WindowLayoutInfo.class);
+
+ reset(mockCallback);
+ fakeSidecarImp.triggerDeviceState(newDeviceState(SidecarDeviceState.POSTURE_OPENED));
+ verify(mockCallback).onWindowLayoutChanged(eq(mActivity), windowLayoutCaptor.capture());
+ FoldingFeature capturedFoldingFeature = (FoldingFeature) windowLayoutCaptor.getValue()
+ .getDisplayFeatures().get(0);
+ assertEquals(FoldingFeature.STATE_FLAT, capturedFoldingFeature.getState());
+
+ reset(mockCallback);
+ fakeSidecarImp.triggerDeviceState(newDeviceState(SidecarDeviceState.POSTURE_HALF_OPENED));
+ verify(mockCallback).onWindowLayoutChanged(eq(mActivity), windowLayoutCaptor.capture());
+ capturedFoldingFeature = (FoldingFeature) windowLayoutCaptor.getValue().getDisplayFeatures()
+ .get(0);
+ assertEquals(FoldingFeature.STATE_HALF_OPENED, capturedFoldingFeature.getState());
+
+ reset(mockCallback);
+ fakeSidecarImp.triggerDeviceState(newDeviceState(SidecarDeviceState.POSTURE_FLIPPED));
+ verify(mockCallback).onWindowLayoutChanged(eq(mActivity), windowLayoutCaptor.capture());
+ capturedFoldingFeature = (FoldingFeature) windowLayoutCaptor.getValue().getDisplayFeatures()
+ .get(0);
+ assertEquals(FoldingFeature.STATE_FLIPPED, capturedFoldingFeature.getState());
+
+ // No display features must be reported in closed state
+ reset(mockCallback);
+ fakeSidecarImp.triggerDeviceState(newDeviceState(SidecarDeviceState.POSTURE_CLOSED));
+ verify(mockCallback).onWindowLayoutChanged(eq(mActivity), windowLayoutCaptor.capture());
+ assertTrue(windowLayoutCaptor.getValue().getDisplayFeatures().isEmpty());
+ }
+
private static SidecarDisplayFeature newDisplayFeature(Rect rect, int type) {
SidecarDisplayFeature feature = new SidecarDisplayFeature();
feature.setRect(rect);
@@ -416,6 +461,15 @@
return info;
}
+ private static SidecarWindowLayoutInfo validWindowLayoutInfo() {
+ List<SidecarDisplayFeature> goodFeatures = new ArrayList<>();
+
+ goodFeatures.add(newDisplayFeature(validFoldBound(WINDOW_BOUNDS),
+ SidecarDisplayFeature.TYPE_FOLD));
+
+ return newWindowLayoutInfo(goodFeatures);
+ }
+
private static SidecarDeviceState newDeviceState(int posture) {
SidecarDeviceState state = new SidecarDeviceState();
setSidecarDevicePosture(state, posture);
@@ -449,7 +503,7 @@
@Override
public void setSidecarCallback(@NonNull SidecarCallback callback) {
-
+ mCallback = callback;
}
@NonNull
@@ -460,12 +514,12 @@
@Override
public void onWindowLayoutChangeListenerAdded(@NonNull IBinder windowToken) {
-
+ mTokens.add(windowToken);
}
@Override
public void onWindowLayoutChangeListenerRemoved(@NonNull IBinder windowToken) {
-
+ mTokens.remove(windowToken);
}
@NonNull
@@ -497,7 +551,6 @@
public void triggerDeviceState(SidecarDeviceState state) {
mDeviceState = state;
mCallback.onDeviceStateChanged(state);
-
}
private SidecarWindowLayoutInfo malformedWindowLayoutInfo() {
@@ -515,14 +568,5 @@
return newWindowLayoutInfo(malformedFeatures);
}
-
- private SidecarWindowLayoutInfo validWindowLayoutInfo() {
- List<SidecarDisplayFeature> goodFeatures = new ArrayList<>();
-
- goodFeatures.add(newDisplayFeature(validFoldBound(WINDOW_BOUNDS),
- SidecarDisplayFeature.TYPE_FOLD));
-
- return newWindowLayoutInfo(goodFeatures);
- }
}
}
diff --git a/window/window/src/androidTest/java/androidx/window/TestBoundsUtil.java b/window/window/src/androidTest/java/androidx/window/TestBoundsUtil.java
index cf6533f..ff353db 100644
--- a/window/window/src/androidTest/java/androidx/window/TestBoundsUtil.java
+++ b/window/window/src/androidTest/java/androidx/window/TestBoundsUtil.java
@@ -28,7 +28,7 @@
public static Rect validFoldBound(Rect windowBounds) {
int verticalMid = windowBounds.top + windowBounds.height() / 2;
- return new Rect(windowBounds.left, verticalMid, windowBounds.right, verticalMid);
+ return new Rect(0, verticalMid, windowBounds.width(), verticalMid);
}
public static Rect invalidZeroBound() {
@@ -36,11 +36,11 @@
}
public static Rect invalidBoundShortWidth(Rect windowBounds) {
- return new Rect(windowBounds.left, windowBounds.top, windowBounds.right / 2, 2);
+ return new Rect(0, 0, windowBounds.width() / 2, 2);
}
public static Rect invalidBoundShortHeight(Rect windowBounds) {
- return new Rect(windowBounds.left, windowBounds.top, 2, windowBounds.bottom / 2);
+ return new Rect(0, 0, 2, windowBounds.height() / 2);
}
private static List<Rect> coreInvalidBounds(Rect windowBounds) {
diff --git a/window/window/src/main/java/androidx/window/SidecarCompat.java b/window/window/src/main/java/androidx/window/SidecarCompat.java
index ffb36a1..295151b 100644
--- a/window/window/src/main/java/androidx/window/SidecarCompat.java
+++ b/window/window/src/main/java/androidx/window/SidecarCompat.java
@@ -92,6 +92,17 @@
@SuppressLint("SyntheticAccessor")
public void onDeviceStateChanged(@NonNull SidecarDeviceState newDeviceState) {
extensionCallback.onDeviceStateChanged(mSidecarAdapter.translate(newDeviceState));
+
+ for (int i = 0; i < mWindowListenerRegisteredContexts.size(); i++) {
+ Activity activity = mWindowListenerRegisteredContexts.valueAt(i);
+ IBinder windowToken = getActivityWindowToken(activity);
+ if (windowToken == null) {
+ continue;
+ }
+ SidecarWindowLayoutInfo layoutInfo = mSidecar.getWindowLayoutInfo(windowToken);
+ extensionCallback.onWindowLayoutChanged(activity,
+ mSidecarAdapter.translate(activity, layoutInfo, newDeviceState));
+ }
}
@Override