Loading libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java +42 −12 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static androidx.window.util.ExtensionHelper.isZero; import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Rect; import android.hardware.devicestate.DeviceStateManager; import android.util.Log; import androidx.annotation.NonNull; Loading @@ -33,7 +34,8 @@ import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; /** A representation of a folding feature for both Extension and Sidecar. /** * A representation of a folding feature for both Extension and Sidecar. * For Sidecar this is the same as combining {@link androidx.window.sidecar.SidecarDeviceState} and * {@link androidx.window.sidecar.SidecarDisplayFeature}. For Extensions this is the mirror of * {@link androidx.window.extensions.layout.FoldingFeature}. Loading Loading @@ -67,10 +69,11 @@ public final class CommonFoldingFeature { public static final int COMMON_STATE_UNKNOWN = -1; /** * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar * and Extensions do not match exactly. * A common state that contains no folding features. For example, an in-folding device in the * "closed" device state. */ public static final int COMMON_STATE_FLAT = 3; public static final int COMMON_STATE_NO_FOLDING_FEATURES = 1; /** * A common state to represent a HALF_OPENED hinge. This is needed because the definitions in * Sidecar and Extensions do not match exactly. Loading @@ -78,9 +81,27 @@ public final class CommonFoldingFeature { public static final int COMMON_STATE_HALF_OPENED = 2; /** * The possible states for a folding hinge. * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar * and Extensions do not match exactly. */ @IntDef({COMMON_STATE_UNKNOWN, COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED}) public static final int COMMON_STATE_FLAT = 3; /** * A common state where the hinge state should be derived using the base state from * {@link DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)} instead of the * emulated state. This is an internal state and must not be passed to clients. */ public static final int COMMON_STATE_USE_BASE_STATE = 1000; /** * The possible states for a folding hinge. Common in this context means normalized between * extensions and sidecar. */ @IntDef({COMMON_STATE_UNKNOWN, COMMON_STATE_NO_FOLDING_FEATURES, COMMON_STATE_HALF_OPENED, COMMON_STATE_FLAT, COMMON_STATE_USE_BASE_STATE}) @Retention(RetentionPolicy.SOURCE) public @interface State { } Loading Loading @@ -167,7 +188,7 @@ public final class CommonFoldingFeature { } String stateString = featureMatcher.group(6); stateString = stateString == null ? "" : stateString; final int state; @State final int state; switch (stateString) { case PATTERN_STATE_FLAT: state = COMMON_STATE_FLAT; Loading @@ -191,8 +212,8 @@ public final class CommonFoldingFeature { @NonNull private final Rect mRect; CommonFoldingFeature(int type, int state, @NonNull Rect rect) { assertValidState(state); CommonFoldingFeature(int type, @State int state, @NonNull Rect rect) { assertReportableState(state); this.mType = type; this.mState = state; if (rect.width() == 0 && rect.height() == 0) { Loading Loading @@ -230,14 +251,23 @@ public final class CommonFoldingFeature { && mRect.equals(that.mRect); } @Override public String toString() { return "CommonFoldingFeature=[Type: " + mType + ", state: " + mState + "]"; } @Override public int hashCode() { return Objects.hash(mType, mState, mRect); } private static void assertValidState(@Nullable Integer state) { if (state != null && state != COMMON_STATE_FLAT && state != COMMON_STATE_HALF_OPENED && state != COMMON_STATE_UNKNOWN) { /** * Checks if the provided folding feature state should be reported to clients. See * {@link androidx.window.extensions.layout.FoldingFeature} */ private static void assertReportableState(@State int state) { if (state != COMMON_STATE_FLAT && state != COMMON_STATE_HALF_OPENED && state != COMMON_STATE_UNKNOWN) { throw new IllegalArgumentException("Invalid state: " + state + "must be either COMMON_STATE_FLAT or COMMON_STATE_HALF_OPENED"); } Loading libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java +54 −9 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package androidx.window.common; import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN; import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE; import static androidx.window.common.CommonFoldingFeature.parseListFromString; import android.annotation.NonNull; Loading Loading @@ -52,13 +53,54 @@ public final class DeviceStateManagerFoldingFeatureProducer DeviceStateManagerFoldingFeatureProducer.class.getSimpleName(); private static final boolean DEBUG = false; /** * Emulated device state {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)} to * {@link CommonFoldingFeature.State} map. */ private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray(); /** * Emulated device state received via * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}. * "Emulated" states differ from "base" state in the sense that they may not correspond 1:1 with * physical device states. They represent the state of the device when various software * features and APIs are applied. The emulated states generally consist of all "base" states, * but may have additional states such as "concurrent" or "rear display". Concurrent mode for * example is activated via public API and can be active in both the "open" and "half folded" * device states. */ private int mCurrentDeviceState = INVALID_DEVICE_STATE; /** * Base device state received via * {@link DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)}. * "Base" in this context means the "physical" state of the device. */ private int mCurrentBaseDeviceState = INVALID_DEVICE_STATE; @NonNull private final BaseDataProducer<String> mRawFoldSupplier; private final DeviceStateCallback mDeviceStateCallback = new DeviceStateCallback() { @Override public void onStateChanged(int state) { mCurrentDeviceState = state; mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer .this::notifyFoldingFeatureChange); } @Override public void onBaseStateChanged(int state) { mCurrentBaseDeviceState = state; if (mDeviceStateToPostureMap.get(mCurrentDeviceState) == COMMON_STATE_USE_BASE_STATE) { mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer .this::notifyFoldingFeatureChange); } } }; public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context, @NonNull BaseDataProducer<String> rawFoldSupplier) { mRawFoldSupplier = rawFoldSupplier; Loading Loading @@ -92,12 +134,8 @@ public final class DeviceStateManagerFoldingFeatureProducer } if (mDeviceStateToPostureMap.size() > 0) { DeviceStateCallback deviceStateCallback = (state) -> { mCurrentDeviceState = state; mRawFoldSupplier.getData(this::notifyFoldingFeatureChange); }; Objects.requireNonNull(context.getSystemService(DeviceStateManager.class)) .registerCallback(context.getMainExecutor(), deviceStateCallback); .registerCallback(context.getMainExecutor(), mDeviceStateCallback); } } Loading Loading @@ -178,11 +216,18 @@ public final class DeviceStateManagerFoldingFeatureProducer } private List<CommonFoldingFeature> calculateFoldingFeature(String displayFeaturesString) { final int globalHingeState = globalHingeState(); return parseListFromString(displayFeaturesString, globalHingeState); return parseListFromString(displayFeaturesString, currentHingeState()); } @CommonFoldingFeature.State private int currentHingeState() { @CommonFoldingFeature.State int posture = mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN); if (posture == CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE) { posture = mDeviceStateToPostureMap.get(mCurrentBaseDeviceState, COMMON_STATE_UNKNOWN); } private int globalHingeState() { return mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN); return posture; } } Loading
libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java +42 −12 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static androidx.window.util.ExtensionHelper.isZero; import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Rect; import android.hardware.devicestate.DeviceStateManager; import android.util.Log; import androidx.annotation.NonNull; Loading @@ -33,7 +34,8 @@ import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; /** A representation of a folding feature for both Extension and Sidecar. /** * A representation of a folding feature for both Extension and Sidecar. * For Sidecar this is the same as combining {@link androidx.window.sidecar.SidecarDeviceState} and * {@link androidx.window.sidecar.SidecarDisplayFeature}. For Extensions this is the mirror of * {@link androidx.window.extensions.layout.FoldingFeature}. Loading Loading @@ -67,10 +69,11 @@ public final class CommonFoldingFeature { public static final int COMMON_STATE_UNKNOWN = -1; /** * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar * and Extensions do not match exactly. * A common state that contains no folding features. For example, an in-folding device in the * "closed" device state. */ public static final int COMMON_STATE_FLAT = 3; public static final int COMMON_STATE_NO_FOLDING_FEATURES = 1; /** * A common state to represent a HALF_OPENED hinge. This is needed because the definitions in * Sidecar and Extensions do not match exactly. Loading @@ -78,9 +81,27 @@ public final class CommonFoldingFeature { public static final int COMMON_STATE_HALF_OPENED = 2; /** * The possible states for a folding hinge. * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar * and Extensions do not match exactly. */ @IntDef({COMMON_STATE_UNKNOWN, COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED}) public static final int COMMON_STATE_FLAT = 3; /** * A common state where the hinge state should be derived using the base state from * {@link DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)} instead of the * emulated state. This is an internal state and must not be passed to clients. */ public static final int COMMON_STATE_USE_BASE_STATE = 1000; /** * The possible states for a folding hinge. Common in this context means normalized between * extensions and sidecar. */ @IntDef({COMMON_STATE_UNKNOWN, COMMON_STATE_NO_FOLDING_FEATURES, COMMON_STATE_HALF_OPENED, COMMON_STATE_FLAT, COMMON_STATE_USE_BASE_STATE}) @Retention(RetentionPolicy.SOURCE) public @interface State { } Loading Loading @@ -167,7 +188,7 @@ public final class CommonFoldingFeature { } String stateString = featureMatcher.group(6); stateString = stateString == null ? "" : stateString; final int state; @State final int state; switch (stateString) { case PATTERN_STATE_FLAT: state = COMMON_STATE_FLAT; Loading @@ -191,8 +212,8 @@ public final class CommonFoldingFeature { @NonNull private final Rect mRect; CommonFoldingFeature(int type, int state, @NonNull Rect rect) { assertValidState(state); CommonFoldingFeature(int type, @State int state, @NonNull Rect rect) { assertReportableState(state); this.mType = type; this.mState = state; if (rect.width() == 0 && rect.height() == 0) { Loading Loading @@ -230,14 +251,23 @@ public final class CommonFoldingFeature { && mRect.equals(that.mRect); } @Override public String toString() { return "CommonFoldingFeature=[Type: " + mType + ", state: " + mState + "]"; } @Override public int hashCode() { return Objects.hash(mType, mState, mRect); } private static void assertValidState(@Nullable Integer state) { if (state != null && state != COMMON_STATE_FLAT && state != COMMON_STATE_HALF_OPENED && state != COMMON_STATE_UNKNOWN) { /** * Checks if the provided folding feature state should be reported to clients. See * {@link androidx.window.extensions.layout.FoldingFeature} */ private static void assertReportableState(@State int state) { if (state != COMMON_STATE_FLAT && state != COMMON_STATE_HALF_OPENED && state != COMMON_STATE_UNKNOWN) { throw new IllegalArgumentException("Invalid state: " + state + "must be either COMMON_STATE_FLAT or COMMON_STATE_HALF_OPENED"); } Loading
libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java +54 −9 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package androidx.window.common; import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN; import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE; import static androidx.window.common.CommonFoldingFeature.parseListFromString; import android.annotation.NonNull; Loading Loading @@ -52,13 +53,54 @@ public final class DeviceStateManagerFoldingFeatureProducer DeviceStateManagerFoldingFeatureProducer.class.getSimpleName(); private static final boolean DEBUG = false; /** * Emulated device state {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)} to * {@link CommonFoldingFeature.State} map. */ private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray(); /** * Emulated device state received via * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}. * "Emulated" states differ from "base" state in the sense that they may not correspond 1:1 with * physical device states. They represent the state of the device when various software * features and APIs are applied. The emulated states generally consist of all "base" states, * but may have additional states such as "concurrent" or "rear display". Concurrent mode for * example is activated via public API and can be active in both the "open" and "half folded" * device states. */ private int mCurrentDeviceState = INVALID_DEVICE_STATE; /** * Base device state received via * {@link DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)}. * "Base" in this context means the "physical" state of the device. */ private int mCurrentBaseDeviceState = INVALID_DEVICE_STATE; @NonNull private final BaseDataProducer<String> mRawFoldSupplier; private final DeviceStateCallback mDeviceStateCallback = new DeviceStateCallback() { @Override public void onStateChanged(int state) { mCurrentDeviceState = state; mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer .this::notifyFoldingFeatureChange); } @Override public void onBaseStateChanged(int state) { mCurrentBaseDeviceState = state; if (mDeviceStateToPostureMap.get(mCurrentDeviceState) == COMMON_STATE_USE_BASE_STATE) { mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer .this::notifyFoldingFeatureChange); } } }; public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context, @NonNull BaseDataProducer<String> rawFoldSupplier) { mRawFoldSupplier = rawFoldSupplier; Loading Loading @@ -92,12 +134,8 @@ public final class DeviceStateManagerFoldingFeatureProducer } if (mDeviceStateToPostureMap.size() > 0) { DeviceStateCallback deviceStateCallback = (state) -> { mCurrentDeviceState = state; mRawFoldSupplier.getData(this::notifyFoldingFeatureChange); }; Objects.requireNonNull(context.getSystemService(DeviceStateManager.class)) .registerCallback(context.getMainExecutor(), deviceStateCallback); .registerCallback(context.getMainExecutor(), mDeviceStateCallback); } } Loading Loading @@ -178,11 +216,18 @@ public final class DeviceStateManagerFoldingFeatureProducer } private List<CommonFoldingFeature> calculateFoldingFeature(String displayFeaturesString) { final int globalHingeState = globalHingeState(); return parseListFromString(displayFeaturesString, globalHingeState); return parseListFromString(displayFeaturesString, currentHingeState()); } @CommonFoldingFeature.State private int currentHingeState() { @CommonFoldingFeature.State int posture = mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN); if (posture == CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE) { posture = mDeviceStateToPostureMap.get(mCurrentBaseDeviceState, COMMON_STATE_UNKNOWN); } private int globalHingeState() { return mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN); return posture; } }