Loading libs/WindowManager/Jetpack/src/androidx/window/common/ExtensionHelper.java +2 −13 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.annotation.SuppressLint; import android.app.WindowConfiguration; import android.content.Context; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.util.RotationUtils; import android.view.DisplayInfo; import android.view.Surface; Loading @@ -31,7 +30,6 @@ import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.UiContext; import androidx.annotation.VisibleForTesting; /** * Util class for both Sidecar and Extensions. Loading @@ -46,24 +44,15 @@ public final class ExtensionHelper { * Rotates the input rectangle specified in default display orientation to the current display * rotation. * * @param displayId the display id. * @param displayInfo the display information. * @param rotation the target rotation relative to the default display orientation. * @param inOutRect the input/output Rect as specified in the default display orientation. */ public static void rotateRectToDisplayRotation( int displayId, @Surface.Rotation int rotation, @NonNull Rect inOutRect) { final DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance(); final DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId); rotateRectToDisplayRotation(displayInfo, rotation, inOutRect); } // We suppress the Lint error CheckResult for Rect#intersect because in case the displayInfo and // folding features are out of sync, e.g. when a foldable devices is unfolding, it is acceptable // to provide the original folding feature Rect even if they don't intersect. @SuppressLint("RectIntersectReturnValueIgnored") @VisibleForTesting static void rotateRectToDisplayRotation(@NonNull DisplayInfo displayInfo, public static void rotateRectToDisplayRotation(@NonNull DisplayInfo displayInfo, @Surface.Rotation int rotation, @NonNull Rect inOutRect) { // The inOutRect is specified in the default display orientation, so here we need to get // the display width and height in the default orientation to perform the intersection and Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +37 −3 Original line number Diff line number Diff line Loading @@ -34,11 +34,14 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.os.Bundle; import android.os.IBinder; import android.os.StrictMode; import android.util.ArrayMap; import android.util.Log; import android.view.DisplayInfo; import android.view.Surface; import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; Loading Loading @@ -96,8 +99,29 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { private final SupportedWindowFeatures mSupportedWindowFeatures; private final DisplayStateProvider mDisplayStateProvider; public WindowLayoutComponentImpl(@NonNull Context context, @NonNull DeviceStateManagerFoldingFeatureProducer foldingFeatureProducer) { this(context, foldingFeatureProducer, new DisplayStateProvider() { @Override public int getDisplayRotation(@NonNull WindowConfiguration windowConfiguration) { return windowConfiguration.getDisplayRotation(); } @NonNull @Override public DisplayInfo getDisplayInfo(int displayId) { return DisplayManagerGlobal.getInstance().getDisplayInfo(displayId); } }); } @VisibleForTesting WindowLayoutComponentImpl(@NonNull Context context, @NonNull DeviceStateManagerFoldingFeatureProducer foldingFeatureProducer, @NonNull DisplayStateProvider displayStateProvider) { mDisplayStateProvider = displayStateProvider; ((Application) context.getApplicationContext()) .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged()); mFoldingFeatureProducer = foldingFeatureProducer; Loading Loading @@ -401,15 +425,16 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { // We will transform the feature bounds to the Activity window, so using the rotation // from the same source (WindowConfiguration) to make sure they are synchronized. final int rotation = windowConfiguration.getDisplayRotation(); final int rotation = mDisplayStateProvider.getDisplayRotation(windowConfiguration); final DisplayInfo displayInfo = mDisplayStateProvider.getDisplayInfo(displayId); for (CommonFoldingFeature baseFeature : storedFeatures) { Integer state = convertToExtensionState(baseFeature.getState()); if (state == null) { continue; } Rect featureRect = baseFeature.getRect(); rotateRectToDisplayRotation(displayId, rotation, featureRect); final Rect featureRect = baseFeature.getRect(); rotateRectToDisplayRotation(displayInfo, rotation, featureRect); transformToWindowSpaceRect(windowConfiguration, featureRect); if (isZero(featureRect)) { Loading Loading @@ -530,4 +555,13 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { public void onLowMemory() { } } @VisibleForTesting interface DisplayStateProvider { @Surface.Rotation int getDisplayRotation(@NonNull WindowConfiguration windowConfiguration); @NonNull DisplayInfo getDisplayInfo(int displayId); } } libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarHelper.java +9 −2 Original line number Diff line number Diff line Loading @@ -24,7 +24,9 @@ import android.annotation.NonNull; import android.app.Activity; import android.app.ActivityThread; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.os.IBinder; import android.view.DisplayInfo; import androidx.window.common.layout.CommonFoldingFeature; Loading Loading @@ -96,13 +98,18 @@ class SidecarHelper { return Collections.emptyList(); } final List<SidecarDisplayFeature> features = new ArrayList<>(); // We will transform the feature bounds to the Activity window, so using the rotation // from the same source (WindowConfiguration) to make sure they are synchronized. final int rotation = activity.getResources().getConfiguration().windowConfiguration .getDisplayRotation(); final DisplayInfo displayInfo = DisplayManagerGlobal.getInstance().getDisplayInfo(displayId); final List<SidecarDisplayFeature> features = new ArrayList<>(); for (CommonFoldingFeature baseFeature : featureList) { final SidecarDisplayFeature feature = new SidecarDisplayFeature(); final Rect featureRect = baseFeature.getRect(); rotateRectToDisplayRotation(displayId, rotation, featureRect); rotateRectToDisplayRotation(displayInfo, rotation, featureRect); transformToWindowSpaceRect(activity, featureRect); feature.setRect(featureRect); feature.setType(baseFeature.getType()); Loading libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/layout/WindowLayoutComponentImplTest.java +25 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import android.content.ContextWrapper; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; import androidx.annotation.NonNull; import androidx.test.core.app.ApplicationProvider; Loading Loading @@ -88,6 +90,29 @@ public class WindowLayoutComponentImplTest { final WindowConfiguration windowConfiguration = testUiContext.getResources().getConfiguration().windowConfiguration; final Rect featureRect = windowConfiguration.getBounds(); // Mock DisplayStateProvider to control rotation and DisplayInfo, preventing dependency on // the real device orientation or display configuration. This improves test reliability on // devices like foldables or tablets that might have varying configurations. final WindowLayoutComponentImpl.DisplayStateProvider displayStateProvider = new WindowLayoutComponentImpl.DisplayStateProvider() { @Override public int getDisplayRotation( @NonNull WindowConfiguration windowConfiguration) { return Surface.ROTATION_0; } @NonNull @Override public DisplayInfo getDisplayInfo(int displayId) { final DisplayInfo displayInfo = new DisplayInfo(); displayInfo.logicalWidth = featureRect.width(); displayInfo.logicalHeight = featureRect.height(); return displayInfo; } }; mWindowLayoutComponent = new WindowLayoutComponentImpl(mAppContext, mock(DeviceStateManagerFoldingFeatureProducer.class), displayStateProvider); final CommonFoldingFeature foldingFeature = new CommonFoldingFeature( CommonFoldingFeature.COMMON_TYPE_HINGE, CommonFoldingFeature.COMMON_STATE_FLAT, Loading Loading
libs/WindowManager/Jetpack/src/androidx/window/common/ExtensionHelper.java +2 −13 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.annotation.SuppressLint; import android.app.WindowConfiguration; import android.content.Context; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.util.RotationUtils; import android.view.DisplayInfo; import android.view.Surface; Loading @@ -31,7 +30,6 @@ import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.UiContext; import androidx.annotation.VisibleForTesting; /** * Util class for both Sidecar and Extensions. Loading @@ -46,24 +44,15 @@ public final class ExtensionHelper { * Rotates the input rectangle specified in default display orientation to the current display * rotation. * * @param displayId the display id. * @param displayInfo the display information. * @param rotation the target rotation relative to the default display orientation. * @param inOutRect the input/output Rect as specified in the default display orientation. */ public static void rotateRectToDisplayRotation( int displayId, @Surface.Rotation int rotation, @NonNull Rect inOutRect) { final DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance(); final DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId); rotateRectToDisplayRotation(displayInfo, rotation, inOutRect); } // We suppress the Lint error CheckResult for Rect#intersect because in case the displayInfo and // folding features are out of sync, e.g. when a foldable devices is unfolding, it is acceptable // to provide the original folding feature Rect even if they don't intersect. @SuppressLint("RectIntersectReturnValueIgnored") @VisibleForTesting static void rotateRectToDisplayRotation(@NonNull DisplayInfo displayInfo, public static void rotateRectToDisplayRotation(@NonNull DisplayInfo displayInfo, @Surface.Rotation int rotation, @NonNull Rect inOutRect) { // The inOutRect is specified in the default display orientation, so here we need to get // the display width and height in the default orientation to perform the intersection and Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +37 −3 Original line number Diff line number Diff line Loading @@ -34,11 +34,14 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.os.Bundle; import android.os.IBinder; import android.os.StrictMode; import android.util.ArrayMap; import android.util.Log; import android.view.DisplayInfo; import android.view.Surface; import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; Loading Loading @@ -96,8 +99,29 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { private final SupportedWindowFeatures mSupportedWindowFeatures; private final DisplayStateProvider mDisplayStateProvider; public WindowLayoutComponentImpl(@NonNull Context context, @NonNull DeviceStateManagerFoldingFeatureProducer foldingFeatureProducer) { this(context, foldingFeatureProducer, new DisplayStateProvider() { @Override public int getDisplayRotation(@NonNull WindowConfiguration windowConfiguration) { return windowConfiguration.getDisplayRotation(); } @NonNull @Override public DisplayInfo getDisplayInfo(int displayId) { return DisplayManagerGlobal.getInstance().getDisplayInfo(displayId); } }); } @VisibleForTesting WindowLayoutComponentImpl(@NonNull Context context, @NonNull DeviceStateManagerFoldingFeatureProducer foldingFeatureProducer, @NonNull DisplayStateProvider displayStateProvider) { mDisplayStateProvider = displayStateProvider; ((Application) context.getApplicationContext()) .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged()); mFoldingFeatureProducer = foldingFeatureProducer; Loading Loading @@ -401,15 +425,16 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { // We will transform the feature bounds to the Activity window, so using the rotation // from the same source (WindowConfiguration) to make sure they are synchronized. final int rotation = windowConfiguration.getDisplayRotation(); final int rotation = mDisplayStateProvider.getDisplayRotation(windowConfiguration); final DisplayInfo displayInfo = mDisplayStateProvider.getDisplayInfo(displayId); for (CommonFoldingFeature baseFeature : storedFeatures) { Integer state = convertToExtensionState(baseFeature.getState()); if (state == null) { continue; } Rect featureRect = baseFeature.getRect(); rotateRectToDisplayRotation(displayId, rotation, featureRect); final Rect featureRect = baseFeature.getRect(); rotateRectToDisplayRotation(displayInfo, rotation, featureRect); transformToWindowSpaceRect(windowConfiguration, featureRect); if (isZero(featureRect)) { Loading Loading @@ -530,4 +555,13 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { public void onLowMemory() { } } @VisibleForTesting interface DisplayStateProvider { @Surface.Rotation int getDisplayRotation(@NonNull WindowConfiguration windowConfiguration); @NonNull DisplayInfo getDisplayInfo(int displayId); } }
libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarHelper.java +9 −2 Original line number Diff line number Diff line Loading @@ -24,7 +24,9 @@ import android.annotation.NonNull; import android.app.Activity; import android.app.ActivityThread; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.os.IBinder; import android.view.DisplayInfo; import androidx.window.common.layout.CommonFoldingFeature; Loading Loading @@ -96,13 +98,18 @@ class SidecarHelper { return Collections.emptyList(); } final List<SidecarDisplayFeature> features = new ArrayList<>(); // We will transform the feature bounds to the Activity window, so using the rotation // from the same source (WindowConfiguration) to make sure they are synchronized. final int rotation = activity.getResources().getConfiguration().windowConfiguration .getDisplayRotation(); final DisplayInfo displayInfo = DisplayManagerGlobal.getInstance().getDisplayInfo(displayId); final List<SidecarDisplayFeature> features = new ArrayList<>(); for (CommonFoldingFeature baseFeature : featureList) { final SidecarDisplayFeature feature = new SidecarDisplayFeature(); final Rect featureRect = baseFeature.getRect(); rotateRectToDisplayRotation(displayId, rotation, featureRect); rotateRectToDisplayRotation(displayInfo, rotation, featureRect); transformToWindowSpaceRect(activity, featureRect); feature.setRect(featureRect); feature.setType(baseFeature.getType()); Loading
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/layout/WindowLayoutComponentImplTest.java +25 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import android.content.ContextWrapper; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; import androidx.annotation.NonNull; import androidx.test.core.app.ApplicationProvider; Loading Loading @@ -88,6 +90,29 @@ public class WindowLayoutComponentImplTest { final WindowConfiguration windowConfiguration = testUiContext.getResources().getConfiguration().windowConfiguration; final Rect featureRect = windowConfiguration.getBounds(); // Mock DisplayStateProvider to control rotation and DisplayInfo, preventing dependency on // the real device orientation or display configuration. This improves test reliability on // devices like foldables or tablets that might have varying configurations. final WindowLayoutComponentImpl.DisplayStateProvider displayStateProvider = new WindowLayoutComponentImpl.DisplayStateProvider() { @Override public int getDisplayRotation( @NonNull WindowConfiguration windowConfiguration) { return Surface.ROTATION_0; } @NonNull @Override public DisplayInfo getDisplayInfo(int displayId) { final DisplayInfo displayInfo = new DisplayInfo(); displayInfo.logicalWidth = featureRect.width(); displayInfo.logicalHeight = featureRect.height(); return displayInfo; } }; mWindowLayoutComponent = new WindowLayoutComponentImpl(mAppContext, mock(DeviceStateManagerFoldingFeatureProducer.class), displayStateProvider); final CommonFoldingFeature foldingFeature = new CommonFoldingFeature( CommonFoldingFeature.COMMON_TYPE_HINGE, CommonFoldingFeature.COMMON_STATE_FLAT, Loading