diff options
author | 2024-09-20 18:50:35 +0000 | |
---|---|---|
committer | 2024-11-08 21:01:19 +0000 | |
commit | 30ac01b752230191a003d7b010c9c9e056cb04a7 (patch) | |
tree | 46e67bdcf05c1a3ead5ac8dc43643075a95babbd | |
parent | 73cdce538e2bad650737bf1727e8edfe21500bad (diff) |
Add DEVICE_STATE_REAR_DISPLAY_OUTER_DEFAULT
Adds this new state which is the same as DEVICE_STATE_REAR_DISPLAY,
except with the additional property
PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT.
Note that this change/topic can be enabled even without the
System-UI-side change that actually displays a new dialog on the
inner display while in this mode. To the user, it will still be
exactly like the existing Rear Display Mode.
For the changes in this CL to take effect (regardless of the
SystemUI side), the corresponding changes must be done in the
device-specific overlays. Namely:
A) Add a new display layout that maps to the new device state (state 5)
defined in BookStyleDeviceStatePolicy
B) Update the config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis
overlays to include state 5
C) Update the config_rearDisplayDeviceStates overlay to include state 5
D) Update the config_device_state_postures overlay to include state 5
E) Enable the flag
Bug: 371095273
Flag: android.hardware.devicestate.feature.flags.device_state_rdm_v2
Test: demo app
Test: atest WindowAreaComponentImplTests
Test: atest ExtensionRearDisplayTest
BYPASS_LARGE_CHANGE_WARNING
Change-Id: I4a4559649df6c37dc183514a38010dcab698b14d
5 files changed, 151 insertions, 15 deletions
diff --git a/core/java/android/hardware/devicestate/DeviceState.java b/core/java/android/hardware/devicestate/DeviceState.java index e583627c0960..8b4d0da147bc 100644 --- a/core/java/android/hardware/devicestate/DeviceState.java +++ b/core/java/android/hardware/devicestate/DeviceState.java @@ -172,6 +172,23 @@ public final class DeviceState { */ public static final int PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT = 17; + /** + * Property that indicates that this state corresponds to the device state for rear display + * mode, where both the inner and outer displays are on. In this state, the outer display + * is the default display where the app is shown, and the inner display is used by the system to + * show a UI affordance for exiting the mode. + * + * Note that this value should generally not be used, and may be removed in the future (e.g. + * if or when it becomes the only type of rear display mode when + * {@link android.hardware.devicestate.feature.flags.Flags#deviceStateRdmV2} is removed). + * + * As such, clients should strongly consider relying on {@link #PROPERTY_FEATURE_REAR_DISPLAY} + * instead. + * + * @hide + */ + public static final int PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT = 1001; + /** @hide */ @IntDef(prefix = {"PROPERTY_"}, flag = false, value = { PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED, @@ -190,7 +207,8 @@ public final class DeviceState { PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE, PROPERTY_EXTENDED_DEVICE_STATE_EXTERNAL_DISPLAY, PROPERTY_FEATURE_REAR_DISPLAY, - PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT + PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT, + PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT }) @Retention(RetentionPolicy.SOURCE) @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) diff --git a/core/java/android/hardware/devicestate/feature/flags.aconfig b/core/java/android/hardware/devicestate/feature/flags.aconfig index 98ba9192044d..6230f4dbf6f4 100644 --- a/core/java/android/hardware/devicestate/feature/flags.aconfig +++ b/core/java/android/hardware/devicestate/feature/flags.aconfig @@ -29,4 +29,13 @@ flag { metadata { purpose: PURPOSE_BUGFIX } +} + +flag { + name: "device_state_rdm_v2" + is_exported: true + namespace: "windowing_sdk" + description: "Enables Rear Display Mode V2, where the inner display shows the user a UI affordance for exiting the state" + bug: "372486634" + is_fixed_read_only: true }
\ No newline at end of file diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java index 4d7be39ca5a4..76eb207a31c9 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java @@ -19,6 +19,7 @@ package androidx.window.extensions.area; import static android.hardware.devicestate.DeviceState.PROPERTY_EMULATED_ONLY; import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT; import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY; +import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT; import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY; import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; @@ -104,6 +105,30 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, @GuardedBy("mLock") private int mLastReportedRearDisplayPresentationStatus; + @VisibleForTesting + static int getRdmV1Identifier(List<DeviceState> currentSupportedDeviceStates) { + for (int i = 0; i < currentSupportedDeviceStates.size(); i++) { + DeviceState state = currentSupportedDeviceStates.get(i); + if (state.hasProperty(PROPERTY_FEATURE_REAR_DISPLAY) + && !state.hasProperty(PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT)) { + return state.getIdentifier(); + } + } + return INVALID_DEVICE_STATE_IDENTIFIER; + } + + @VisibleForTesting + static int getRdmV2Identifier(List<DeviceState> currentSupportedDeviceStates) { + for (int i = 0; i < currentSupportedDeviceStates.size(); i++) { + DeviceState state = currentSupportedDeviceStates.get(i); + if (state.hasProperties(PROPERTY_FEATURE_REAR_DISPLAY, + PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT)) { + return state.getIdentifier(); + } + } + return INVALID_DEVICE_STATE_IDENTIFIER; + } + public WindowAreaComponentImpl(@NonNull Context context) { mDeviceStateManager = context.getSystemService(DeviceStateManager.class); mDisplayManager = context.getSystemService(DisplayManager.class); @@ -112,12 +137,10 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, mCurrentSupportedDeviceStates = mDeviceStateManager.getSupportedDeviceStates(); if (Flags.deviceStatePropertyMigration()) { - for (int i = 0; i < mCurrentSupportedDeviceStates.size(); i++) { - DeviceState state = mCurrentSupportedDeviceStates.get(i); - if (state.hasProperty(PROPERTY_FEATURE_REAR_DISPLAY)) { - mRearDisplayState = state.getIdentifier(); - break; - } + if (Flags.deviceStateRdmV2()) { + mRearDisplayState = getRdmV2Identifier(mCurrentSupportedDeviceStates); + } else { + mRearDisplayState = getRdmV1Identifier(mCurrentSupportedDeviceStates); } } else { mFoldedDeviceStates = context.getResources().getIntArray( diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java index ccb4ebe9199e..d677fef5c22c 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java @@ -16,8 +16,13 @@ package androidx.window.extensions.area; +import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY; +import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT; +import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; + import static org.junit.Assert.assertEquals; +import android.hardware.devicestate.DeviceState; import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; import android.view.Surface; @@ -29,11 +34,34 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) public class WindowAreaComponentImplTests { + private static final DeviceState REAR_DISPLAY_STATE_V1 = new DeviceState( + new DeviceState.Configuration.Builder(1, "STATE_0") + .setSystemProperties( + Set.of(PROPERTY_FEATURE_REAR_DISPLAY)) + .build()); + private static final DeviceState REAR_DISPLAY_STATE_V2 = new DeviceState( + new DeviceState.Configuration.Builder(2, "STATE_0") + .setSystemProperties( + Set.of(PROPERTY_FEATURE_REAR_DISPLAY, + PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT)) + .build()); + // The PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT state must be present together with the + // PROPERTY_FEATURE_REAR_DISPLAY state in order to be a valid state. + private static final DeviceState INVALID_REAR_DISPLAY_STATE = new DeviceState( + new DeviceState.Configuration.Builder(2, "STATE_0") + .setSystemProperties( + Set.of(PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT)) + .build()); + private final DisplayMetrics mTestDisplayMetrics = new DisplayMetrics(); @Before @@ -93,4 +121,37 @@ public class WindowAreaComponentImplTests { Surface.ROTATION_270, Surface.ROTATION_0, mTestDisplayMetrics); assertEquals(expectedMetrics, mTestDisplayMetrics); } + + @Test + public void testRdmV1Identifier() { + final List<DeviceState> supportedStates = new ArrayList<>(); + supportedStates.add(REAR_DISPLAY_STATE_V2); + assertEquals(INVALID_DEVICE_STATE_IDENTIFIER, + WindowAreaComponentImpl.getRdmV1Identifier(supportedStates)); + + supportedStates.add(REAR_DISPLAY_STATE_V1); + assertEquals(REAR_DISPLAY_STATE_V1.getIdentifier(), + WindowAreaComponentImpl.getRdmV1Identifier(supportedStates)); + } + + @Test + public void testRdmV2Identifier_whenStateIsImproperlyConfigured() { + final List<DeviceState> supportedStates = new ArrayList<>(); + supportedStates.add(INVALID_REAR_DISPLAY_STATE); + assertEquals(INVALID_DEVICE_STATE_IDENTIFIER, + WindowAreaComponentImpl.getRdmV2Identifier(supportedStates)); + } + + @Test + public void testRdmV2Identifier_whenStateIsProperlyConfigured() { + final List<DeviceState> supportedStates = new ArrayList<>(); + + supportedStates.add(REAR_DISPLAY_STATE_V1); + assertEquals(INVALID_DEVICE_STATE_IDENTIFIER, + WindowAreaComponentImpl.getRdmV2Identifier(supportedStates)); + + supportedStates.add(REAR_DISPLAY_STATE_V2); + assertEquals(REAR_DISPLAY_STATE_V2.getIdentifier(), + WindowAreaComponentImpl.getRdmV2Identifier(supportedStates)); + } } diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleDeviceStatePolicy.java b/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleDeviceStatePolicy.java index cc5573bb01d8..f34ec72d7e27 100644 --- a/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleDeviceStatePolicy.java +++ b/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleDeviceStatePolicy.java @@ -19,6 +19,7 @@ package com.android.server.policy; import static android.hardware.devicestate.DeviceState.PROPERTY_EMULATED_ONLY; import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT; import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY; +import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT; import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY; import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY; import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED; @@ -71,6 +72,7 @@ public class BookStyleDeviceStatePolicy extends DeviceStatePolicy implements private static final int DEVICE_STATE_OPENED = 2; private static final int DEVICE_STATE_REAR_DISPLAY = 3; private static final int DEVICE_STATE_CONCURRENT_INNER_DEFAULT = 4; + private static final int DEVICE_STATE_REAR_DISPLAY_OUTER_DEFAULT = 5; private static final int TENT_MODE_SWITCH_ANGLE_DEGREES = 90; private static final int TABLE_TOP_MODE_SWITCH_ANGLE_DEGREES = 125; private static final int MIN_CLOSED_ANGLE_DEGREES = 0; @@ -130,14 +132,17 @@ public class BookStyleDeviceStatePolicy extends DeviceStatePolicy implements return hingeAngle >= MAX_CLOSED_ANGLE_DEGREES && hingeAngle <= TABLE_TOP_MODE_SWITCH_ANGLE_DEGREES; }), - createConfig(getOpenedDeviceState(), /* activeStatePredicate= */ - ALLOWED), - createConfig(getRearDisplayDeviceState(), /* activeStatePredicate= */ - NOT_ALLOWED), - createConfig(getDualDisplayDeviceState(), /* activeStatePredicate= */ - NOT_ALLOWED, /* availabilityPredicate= */ - provider -> !mIsDualDisplayBlockingEnabled - || provider.hasNoConnectedExternalDisplay())}; + createConfig(getOpenedDeviceState(), + /* activeStatePredicate= */ ALLOWED), + createConfig(getRearDisplayDeviceState(), + /* activeStatePredicate= */ NOT_ALLOWED), + createConfig(getDualDisplayDeviceState(), + /* activeStatePredicate= */ NOT_ALLOWED, + /* availabilityPredicate= */ provider -> !mIsDualDisplayBlockingEnabled + || provider.hasNoConnectedExternalDisplay()), + createConfig(getRearDisplayOuterDefaultState(), + /* activeStatePredicate= */ NOT_ALLOWED) + }; } private DeviceStatePredicateWrapper createClosedConfiguration( @@ -266,4 +271,24 @@ public class BookStyleDeviceStatePolicy extends DeviceStatePolicy implements .setSystemProperties(systemProperties) .build()); } + + /** + * Returns the {link DeviceState.Configuration} that represents the new rear display state + * where the inner display is also enabled, showing a system affordance to exit the state. + */ + @NonNull + private DeviceState getRearDisplayOuterDefaultState() { + Set<@DeviceState.SystemDeviceStateProperties Integer> systemProperties = new HashSet<>( + List.of(PROPERTY_EMULATED_ONLY, + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST, + PROPERTY_FEATURE_REAR_DISPLAY, + PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT)); + + return new DeviceState(new DeviceState.Configuration.Builder( + DEVICE_STATE_REAR_DISPLAY_OUTER_DEFAULT, + "REAR_DISPLAY_OUTER_DEFAULT") + .setSystemProperties(systemProperties) + .build()); + } } |