diff options
| author | 2024-10-21 17:57:06 +0800 | |
|---|---|---|
| committer | 2024-10-23 14:41:30 +0800 | |
| commit | a21a24f1b89436855189675d15f0d50d25736aa9 (patch) | |
| tree | edbd13a01c1ea20c90b11268a38e9e8cc16e6f22 | |
| parent | 5f0bb6c013ab5df2c06e2307cd8714a46b6782bc (diff) | |
Implement getCurrentWindowLayoutInfo() API.
This commit implements the getCurrentWindowLayoutInfo() API in window
extension v9, targeting the 25Q2 release. It enables access to window
layout information during the onCreate lifecycle callback. Check
ag/29908303 for API definition and more details.
Bug: 337820752
Flag: com.android.window.flags.wlinfo_oncreate
Test: atest WMJetpackUnitTests:WindowLayoutComponentImplTest
Change-Id: I43403a633e9a396ab9ce2cc1aef4ff4c70547573
4 files changed, 99 insertions, 9 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/layout/CommonFoldingFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/layout/CommonFoldingFeature.java index 85c4fe1193ee..252974dd474e 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/common/layout/CommonFoldingFeature.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/layout/CommonFoldingFeature.java @@ -25,6 +25,7 @@ import android.hardware.devicestate.DeviceStateManager; import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -212,7 +213,8 @@ public final class CommonFoldingFeature { @NonNull private final Rect mRect; - CommonFoldingFeature(int type, @State int state, @NonNull Rect rect) { + @VisibleForTesting + public CommonFoldingFeature(int type, @State int state, @NonNull Rect rect) { assertReportableState(state); this.mType = type; this.mState = state; diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java index 2ab0310d6789..fcf3a3759f7a 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java @@ -57,6 +57,8 @@ class WindowExtensionsImpl implements WindowExtensions { */ private static final int NO_LEVEL_OVERRIDE = -1; + private static final int EXTENSIONS_VERSION_V9 = 9; + private static final int EXTENSIONS_VERSION_V8 = 8; private static final int EXTENSIONS_VERSION_V7 = 7; @@ -80,6 +82,9 @@ class WindowExtensionsImpl implements WindowExtensions { */ @VisibleForTesting static int getExtensionsVersionCurrentPlatform() { + if (Flags.wlinfoOncreate()) { + return EXTENSIONS_VERSION_V9; + } if (Flags.aeBackStackRestore()) { return EXTENSIONS_VERSION_V8; } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java index f1ea19a60f97..556da3798df5 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java @@ -74,6 +74,12 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { @GuardedBy("mLock") private final DeviceStateManagerFoldingFeatureProducer mFoldingFeatureProducer; + /** + * The last reported folding features from the device. This is initialized in the constructor + * because the data change callback added to {@link #mFoldingFeatureProducer} is immediately + * called. This is due to current device state from the device state manager already being + * available in the {@link DeviceStateManagerFoldingFeatureProducer}. + */ @GuardedBy("mLock") private final List<CommonFoldingFeature> mLastReportedFoldingFeatures = new ArrayList<>(); @@ -308,6 +314,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { * @param context a proxy for the {@link android.view.Window} that contains the * {@link DisplayFeature}. */ + @NonNull private WindowLayoutInfo getWindowLayoutInfo(@NonNull @UiContext Context context, List<CommonFoldingFeature> storedFeatures) { List<DisplayFeature> displayFeatureList = getDisplayFeatures(context, storedFeatures); @@ -329,6 +336,14 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { } } + @Override + @NonNull + public WindowLayoutInfo getCurrentWindowLayoutInfo(@NonNull @UiContext Context context) { + synchronized (mLock) { + return getWindowLayoutInfo(context, mLastReportedFoldingFeatures); + } + } + /** * Returns the {@link SupportedWindowFeatures} for the device. This list does not change over * time. diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/layout/WindowLayoutComponentImplTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/layout/WindowLayoutComponentImplTest.java index ff0a82fe05d6..ed4eddf7c209 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/layout/WindowLayoutComponentImplTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/layout/WindowLayoutComponentImplTest.java @@ -16,22 +16,30 @@ package androidx.window.extensions.layout; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; +import android.app.WindowConfiguration; import android.content.Context; import android.content.ContextWrapper; +import android.graphics.Rect; import android.platform.test.annotations.Presubmit; +import android.view.Display; +import androidx.annotation.NonNull; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; +import androidx.window.common.layout.CommonFoldingFeature; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.Collections; +import java.util.List; /** * Test class for {@link WindowLayoutComponentImpl}. @@ -44,31 +52,91 @@ import java.util.Collections; @RunWith(AndroidJUnit4.class) public class WindowLayoutComponentImplTest { + private final Context mAppContext = ApplicationProvider.getApplicationContext(); + + @NonNull private WindowLayoutComponentImpl mWindowLayoutComponent; @Before public void setUp() { - mWindowLayoutComponent = new WindowLayoutComponentImpl( - ApplicationProvider.getApplicationContext(), + mWindowLayoutComponent = new WindowLayoutComponentImpl(mAppContext, mock(DeviceStateManagerFoldingFeatureProducer.class)); } @Test - public void testAddWindowLayoutListenerOnFakeUiContext_noCrash() { - final Context fakeUiContext = createTestContext(); + public void testAddWindowLayoutListener_onFakeUiContext_noCrash() { + final Context fakeUiContext = new FakeUiContext(mAppContext); mWindowLayoutComponent.addWindowLayoutInfoListener(fakeUiContext, info -> {}); mWindowLayoutComponent.onDisplayFeaturesChanged(Collections.emptyList()); } - private static Context createTestContext() { - return new FakeUiContext(ApplicationProvider.getApplicationContext()); + @Test + public void testGetCurrentWindowLayoutInfo_noFoldingFeature_returnsEmptyList() { + final Context testUiContext = new TestUiContext(mAppContext); + + final WindowLayoutInfo layoutInfo = + mWindowLayoutComponent.getCurrentWindowLayoutInfo(testUiContext); + + assertThat(layoutInfo.getDisplayFeatures()).isEmpty(); + } + + @Test + public void testGetCurrentWindowLayoutInfo_hasFoldingFeature_returnsWindowLayoutInfo() { + final Context testUiContext = new TestUiContext(mAppContext); + final WindowConfiguration windowConfiguration = + testUiContext.getResources().getConfiguration().windowConfiguration; + final Rect featureRect = windowConfiguration.getBounds(); + final CommonFoldingFeature foldingFeature = new CommonFoldingFeature( + CommonFoldingFeature.COMMON_TYPE_HINGE, + CommonFoldingFeature.COMMON_STATE_FLAT, + featureRect + ); + mWindowLayoutComponent.onDisplayFeaturesChanged(List.of(foldingFeature)); + + final WindowLayoutInfo layoutInfo = + mWindowLayoutComponent.getCurrentWindowLayoutInfo(testUiContext); + + assertThat(layoutInfo.getDisplayFeatures()).containsExactly(new FoldingFeature( + featureRect, FoldingFeature.TYPE_HINGE, FoldingFeature.STATE_FLAT)); + } + + @Test + public void testGetCurrentWindowLayoutInfo_nonUiContext_returnsEmptyList() { + final WindowLayoutInfo layoutInfo = + mWindowLayoutComponent.getCurrentWindowLayoutInfo(mAppContext); + + assertThat(layoutInfo.getDisplayFeatures()).isEmpty(); + } + + /** + * A {@link Context} that simulates a UI context specifically for testing purposes. + * This class overrides {@link Context#getAssociatedDisplayId()} to return + * {@link Display#DEFAULT_DISPLAY}, ensuring the context is tied to the default display, + * and {@link Context#isUiContext()} to always return {@code true}, simulating a UI context. + */ + private static class TestUiContext extends ContextWrapper { + + TestUiContext(Context base) { + super(base); + } + + @Override + public int getAssociatedDisplayId() { + return Display.DEFAULT_DISPLAY; + } + + @Override + public boolean isUiContext() { + return true; + } } /** - * A {@link android.content.Context} overrides {@link android.content.Context#isUiContext} to - * {@code true}. + * A {@link Context} that cheats by overriding {@link Context#isUiContext} to always + * return {@code true}. This is useful for scenarios where a UI context is needed, + * but the underlying context isn't actually a UI one. */ private static class FakeUiContext extends ContextWrapper { |