From ae42f512dfc219d9cec9f9f0e91ff700745df026 Mon Sep 17 00:00:00 2001 From: Diego Vela Date: Thu, 4 Nov 2021 21:08:27 -0700 Subject: Ignore folding feature when it is not on the active display. Ignore the folding feature states that are not reported through extensions. There is a crash when trying to process a folding feature while the corresponding display is not active. We had a fallback value for the posture of flat but the bounds that we calculated would be incorrect. We removed the default value and ignore the folding feature when the corresponding display is not active. Bug: 204477995 Test: manual - install the samples app from WindowManager Test: close a folding device and open the samples app Test: select the display feature sample. Test: app should not crash. Change-Id: I102ed61618915ae6782c40964882a54184538e81 --- .../layout/WindowLayoutComponentImpl.java | 71 ++++++++++++++++++---- 1 file changed, 60 insertions(+), 11 deletions(-) (limited to 'libs') 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 32d447ef1586..fe9ce971d4d9 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java @@ -18,9 +18,12 @@ package androidx.window.extensions.layout; import static android.view.Display.DEFAULT_DISPLAY; +import static androidx.window.common.DisplayFeature.COMMON_STATE_FLAT; +import static androidx.window.common.DisplayFeature.COMMON_STATE_HALF_OPENED; import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation; import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect; +import android.annotation.Nullable; import android.app.Activity; import android.content.Context; import android.graphics.Rect; @@ -119,22 +122,45 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { return !mWindowLayoutChangeListeners.isEmpty(); } - private int getFeatureState(DisplayFeature feature) { + /** + * Calculate the {@link DisplayFeature.State} from the feature or the device posture producer. + * If the given {@link DisplayFeature.State} is not valid then {@code null} will be returned. + * The {@link FoldingFeature} should be ignored in the case of an invalid + * {@link DisplayFeature.State}. + * + * @param feature a {@link DisplayFeature} to provide the feature state if present. + * @return {@link DisplayFeature.State} of the hinge if present or the state from the posture + * produce if present. + */ + @Nullable + private Integer getFeatureState(DisplayFeature feature) { Integer featureState = feature.getState(); Optional posture = mDevicePostureProducer.getData(); - int fallbackPosture = posture.orElse(DisplayFeature.COMMON_STATE_FLAT); - int displayFeatureState = featureState == null ? fallbackPosture : featureState; - return convertToExtensionState(displayFeatureState); + Integer state = featureState == null ? posture.orElse(null) : featureState; + return convertToExtensionState(state); } - private int convertToExtensionState(int state) { - switch (state) { - case DisplayFeature.COMMON_STATE_FLAT: - return FoldingFeature.STATE_FLAT; - case DisplayFeature.COMMON_STATE_HALF_OPENED: - return FoldingFeature.STATE_HALF_OPENED; + /** + * A convenience method to translate from the common feature state to the extensions feature + * state. More specifically, translates from {@link DisplayFeature.State} to + * {@link FoldingFeature.STATE_FLAT} or {@link FoldingFeature.STATE_HALF_OPENED}. If it is not + * possible to translate, then we will return a {@code null} value. + * + * @param state if it matches a value in {@link DisplayFeature.State}, {@code null} otherwise. + * @return a {@link FoldingFeature.STATE_FLAT} or {@link FoldingFeature.STATE_HALF_OPENED} if + * the given state matches a value in {@link DisplayFeature.State} and {@code null} otherwise. + */ + @Nullable + private Integer convertToExtensionState(@Nullable Integer state) { + if (state == null) { // The null check avoids a NullPointerException. + return null; + } else if (state == COMMON_STATE_FLAT) { + return FoldingFeature.STATE_FLAT; + } else if (state == COMMON_STATE_HALF_OPENED) { + return FoldingFeature.STATE_HALF_OPENED; + } else { + return null; } - return FoldingFeature.STATE_FLAT; } private void onDisplayFeaturesChanged() { @@ -151,6 +177,25 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { return new WindowLayoutInfo(displayFeatures); } + /** + * Translate from the {@link DisplayFeature} to + * {@link androidx.window.extensions.layout.DisplayFeature} for a given {@link Activity}. If a + * {@link DisplayFeature} is not valid then it will be omitted. + * + * For a {@link FoldingFeature} the bounds are localized into the {@link Activity} window + * coordinate space and the state is calculated either from {@link DisplayFeature#getState()} or + * {@link #mDisplayFeatureProducer}. The state from {@link #mDisplayFeatureProducer} may not be + * valid since {@link #mDisplayFeatureProducer} is a general state controller. If the state is + * not valid, the {@link FoldingFeature} is omitted from the {@link List} of + * {@link androidx.window.extensions.layout.DisplayFeature}. If the bounds are not valid, + * constructing a {@link FoldingFeature} will throw an {@link IllegalArgumentException} since + * this can cause negative UI effects down stream. + * + * @param activity a proxy for the {@link android.view.Window} that contains the + * {@link androidx.window.extensions.layout.DisplayFeature}. + * @return a {@link List} of valid {@link androidx.window.extensions.layout.DisplayFeature} that + * are within the {@link android.view.Window} of the {@link Activity} + */ private List getDisplayFeatures( @NonNull Activity activity) { List features = new ArrayList<>(); @@ -170,6 +215,10 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { if (storedFeatures.isPresent()) { for (DisplayFeature baseFeature : storedFeatures.get()) { + Integer state = getFeatureState(baseFeature); + if (state == null) { + continue; + } Rect featureRect = baseFeature.getRect(); rotateRectToDisplayRotation(displayId, featureRect); transformToWindowSpaceRect(activity, featureRect); -- cgit v1.2.3-59-g8ed1b