diff options
| -rw-r--r-- | services/core/java/com/android/server/wm/DeviceStateController.java | 100 | ||||
| -rw-r--r-- | services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java | 143 |
2 files changed, 198 insertions, 45 deletions
diff --git a/services/core/java/com/android/server/wm/DeviceStateController.java b/services/core/java/com/android/server/wm/DeviceStateController.java index 857e03d71f3f..475a50473780 100644 --- a/services/core/java/com/android/server/wm/DeviceStateController.java +++ b/services/core/java/com/android/server/wm/DeviceStateController.java @@ -16,9 +16,19 @@ package com.android.server.wm; +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_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_HALF_OPEN; + import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; +import android.hardware.devicestate.DeviceStateManager; +import android.hardware.devicestate.feature.flags.FeatureFlags; +import android.hardware.devicestate.feature.flags.FeatureFlagsImpl; import android.util.ArrayMap; import android.util.Pair; @@ -28,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; @@ -43,16 +54,16 @@ final class DeviceStateController { @NonNull private final WindowManagerGlobalLock mWmLock; @NonNull - private final int[] mOpenDeviceStates; + private final List<Integer> mOpenDeviceStates; @NonNull - private final int[] mHalfFoldedDeviceStates; + private final List<Integer> mHalfFoldedDeviceStates; @NonNull - private final int[] mFoldedDeviceStates; + private final List<Integer> mFoldedDeviceStates; @NonNull - private final int[] mRearDisplayDeviceStates; - private final int mConcurrentDisplayDeviceState; + private final List<Integer> mRearDisplayDeviceStates; + private final List<Integer> mConcurrentDisplayDeviceStates; @NonNull - private final int[] mReverseRotationAroundZAxisStates; + private final List<Integer> mReverseRotationAroundZAxisStates; @GuardedBy("mWmLock") @NonNull @VisibleForTesting @@ -76,18 +87,55 @@ final class DeviceStateController { DeviceStateController(@NonNull Context context, @NonNull WindowManagerGlobalLock wmLock) { mWmLock = wmLock; - mOpenDeviceStates = context.getResources() - .getIntArray(R.array.config_openDeviceStates); - mHalfFoldedDeviceStates = context.getResources() - .getIntArray(R.array.config_halfFoldedDeviceStates); - mFoldedDeviceStates = context.getResources() - .getIntArray(R.array.config_foldedDeviceStates); - mRearDisplayDeviceStates = context.getResources() - .getIntArray(R.array.config_rearDisplayDeviceStates); - mConcurrentDisplayDeviceState = context.getResources() - .getInteger(R.integer.config_deviceStateConcurrentRearDisplay); - mReverseRotationAroundZAxisStates = context.getResources() - .getIntArray(R.array.config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis); + final FeatureFlags deviceStateManagerFlags = new FeatureFlagsImpl(); + if (deviceStateManagerFlags.deviceStatePropertyMigration()) { + mOpenDeviceStates = new ArrayList<>(); + mHalfFoldedDeviceStates = new ArrayList<>(); + mFoldedDeviceStates = new ArrayList<>(); + mRearDisplayDeviceStates = new ArrayList<>(); + mConcurrentDisplayDeviceStates = new ArrayList<>(); + + final DeviceStateManager deviceStateManager = + context.getSystemService(DeviceStateManager.class); + final List<android.hardware.devicestate.DeviceState> deviceStates = + deviceStateManager.getSupportedDeviceStates(); + + for (int i = 0; i < deviceStates.size(); i++) { + final android.hardware.devicestate.DeviceState state = deviceStates.get(i); + if (state.hasProperty( + PROPERTY_FEATURE_REAR_DISPLAY)) { + mRearDisplayDeviceStates.add(state.getIdentifier()); + } else if (state.hasProperty( + PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT)) { + mConcurrentDisplayDeviceStates.add(state.getIdentifier()); + } else if (state.hasProperty( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)) { + mFoldedDeviceStates.add(state.getIdentifier()); + } else if (state.hasProperty( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)) { + if (state.hasProperty( + PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN)) { + mHalfFoldedDeviceStates.add(state.getIdentifier()); + } else { + mOpenDeviceStates.add(state.getIdentifier()); + } + } + } + } else { + mOpenDeviceStates = copyIntArrayToList(context.getResources() + .getIntArray(R.array.config_openDeviceStates)); + mHalfFoldedDeviceStates = copyIntArrayToList(context.getResources() + .getIntArray(R.array.config_halfFoldedDeviceStates)); + mFoldedDeviceStates = copyIntArrayToList(context.getResources() + .getIntArray(R.array.config_foldedDeviceStates)); + mRearDisplayDeviceStates = copyIntArrayToList(context.getResources() + .getIntArray(R.array.config_rearDisplayDeviceStates)); + mConcurrentDisplayDeviceStates = new ArrayList<>(List.of(context.getResources() + .getInteger(R.integer.config_deviceStateConcurrentRearDisplay))); + } + + mReverseRotationAroundZAxisStates = copyIntArrayToList(context.getResources().getIntArray( + R.array.config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis)); mMatchBuiltInDisplayOrientationToDefaultDisplay = context.getResources() .getBoolean(R.bool .config_matchSecondaryInternalDisplaysOrientationToReverseDefaultDisplay); @@ -145,7 +193,6 @@ final class DeviceStateController { */ public void onDeviceStateReceivedByDisplayManager(int state) { mCurrentState = state; - final DeviceState deviceState; if (ArrayUtils.contains(mHalfFoldedDeviceStates, state)) { deviceState = DeviceState.HALF_FOLDED; @@ -155,9 +202,10 @@ final class DeviceStateController { deviceState = DeviceState.REAR; } else if (ArrayUtils.contains(mOpenDeviceStates, state)) { deviceState = DeviceState.OPEN; - } else if (state == mConcurrentDisplayDeviceState) { + } else if (ArrayUtils.contains(mConcurrentDisplayDeviceStates, state)) { deviceState = DeviceState.CONCURRENT; } else { + deviceState = DeviceState.UNKNOWN; } @@ -190,4 +238,16 @@ final class DeviceStateController { } return entries; } + + @NonNull + private List<Integer> copyIntArrayToList(@Nullable int[] values) { + if (values == null) { + return Collections.emptyList(); + } + final List<Integer> valueList = new ArrayList<>(); + for (int i = 0; i < values.length; i++) { + valueList.add(values[i]); + } + return valueList; + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java index 51255948ed4a..36861fae35da 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java @@ -16,6 +16,15 @@ package com.android.server.wm; +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_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; +import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN; +import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN; +import static android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; @@ -24,8 +33,11 @@ import static org.junit.Assert.assertTrue; import android.content.Context; import android.content.res.Resources; +import android.hardware.devicestate.DeviceState; import android.hardware.devicestate.DeviceStateManager; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; import android.util.Pair; import androidx.test.filters.SmallTest; @@ -37,6 +49,8 @@ import com.google.common.util.concurrent.MoreExecutors; import org.junit.Before; import org.junit.Test; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -79,39 +93,67 @@ public class DeviceStateControllerTests { @Test public void testInitialization() { initialize(true /* supportFold */, true /* supportHalfFolded */); - mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]); + mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier()); assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState); } @Test public void testInitializationWithNoFoldSupport() { initialize(false /* supportFold */, false /* supportHalfFolded */); - mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]); + mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier()); // Note that the folded state is ignored. assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState); } @Test - public void testWithFoldSupported() { + @RequiresFlagsDisabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + public void testWithFoldSupported_withOverlayConfigValues() { initialize(true /* supportFold */, false /* supportHalfFolded */); - mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]); + mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier()); assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState); - mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]); + mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier()); assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState); - mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates[0]); + mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier()); assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState); // Ignored } @Test - public void testWithHalfFoldSupported() { + @RequiresFlagsEnabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + public void testWithFoldSupported_withDeviceStateManagerPropertyAPI() { + initialize(true /* supportFold */, false /* supportHalfFolded */); + mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier()); + assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState); + mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier()); + assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState); + mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier()); + assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState); // Ignored + } + + @Test + @RequiresFlagsDisabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + public void testWithHalfFoldSupported_withOverlayConfigValue() { + initialize(true /* supportFold */, true /* supportHalfFolded */); + mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier()); + assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState); + mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier()); + assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState); + mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier()); + assertEquals(DeviceStateController.DeviceState.HALF_FOLDED, mCurrentState); + mTarget.onDeviceStateReceivedByDisplayManager(mConcurrentDisplayState.getIdentifier()); + assertEquals(DeviceStateController.DeviceState.CONCURRENT, mCurrentState); + } + + @Test + @RequiresFlagsEnabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + public void testWithHalfFoldSupported_withDeviceStateManagerPropertyApi() { initialize(true /* supportFold */, true /* supportHalfFolded */); - mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]); + mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier()); assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState); - mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]); + mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier()); assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState); - mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates[0]); + mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier()); assertEquals(DeviceStateController.DeviceState.HALF_FOLDED, mCurrentState); - mTarget.onDeviceStateReceivedByDisplayManager(mConcurrentDisplayState); + mTarget.onDeviceStateReceivedByDisplayManager(mConcurrentDisplayState.getIdentifier()); assertEquals(DeviceStateController.DeviceState.CONCURRENT, mCurrentState); } @@ -121,16 +163,18 @@ public class DeviceStateControllerTests { assertEquals(1, mTarget.mDeviceStateCallbacks.size()); assertTrue(mTarget.mDeviceStateCallbacks.containsKey(mDelegate)); - mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]); + mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier()); assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState); - mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]); + mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier()); assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState); // The callback should not receive state change when it is unregistered. mTarget.unregisterDeviceStateCallback(mDelegate); assertTrue(mTarget.mDeviceStateCallbacks.isEmpty()); - mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]); - assertEquals(DeviceStateController.DeviceState.FOLDED /* unchanged */, mCurrentState); + + mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier()); + assertEquals(DeviceStateController.DeviceState.FOLDED /* unchanged */, + mCurrentState); } @Test @@ -151,16 +195,50 @@ public class DeviceStateControllerTests { assertEquals(mExecutor, entries.get(0).second); } - private final int[] mFoldedStates = {0}; - private final int[] mOpenDeviceStates = {1}; - private final int[] mHalfFoldedStates = {2}; - private final int[] mRearDisplayStates = {3}; - private final int mConcurrentDisplayState = 4; + private final List<DeviceState> mFoldedStates = new ArrayList<>( + List.of(new DeviceState(new DeviceState.Configuration.Builder(0, + "folded").setSystemProperties(new HashSet<>( + List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY))) + .setPhysicalProperties(new HashSet<>( + List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED))) + .build()))); + private final List<DeviceState> mOpenDeviceStates = new ArrayList<>( + List.of(new DeviceState(new DeviceState.Configuration.Builder(1, + "open").setSystemProperties(new HashSet<>( + List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY))) + .setPhysicalProperties(new HashSet<>( + List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN))) + .build()))); + private final List<DeviceState> mHalfFoldedStates = new ArrayList<>( + List.of(new DeviceState(new DeviceState.Configuration.Builder(2, + "half_folded").setSystemProperties(new HashSet<>( + List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY))) + .setPhysicalProperties(new HashSet<>( + List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN))) + .build()))); + private final List<DeviceState> mRearDisplayStates = new ArrayList<>( + List.of(new DeviceState(new DeviceState.Configuration.Builder(3, + "rear_display").setSystemProperties(new HashSet<>( + List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + PROPERTY_FEATURE_REAR_DISPLAY))) + .setPhysicalProperties(new HashSet<>( + List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN))) + .build()))); + private final DeviceState mConcurrentDisplayState = new DeviceState( + new DeviceState.Configuration.Builder(4, "concurrent_display") + .setSystemProperties(new HashSet<>(List.of( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, + PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT))) + .setPhysicalProperties(new HashSet<>(List.of( + PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN))) + .build()); private class DeviceStateControllerBuilder { private boolean mSupportFold = false; private boolean mSupportHalfFold = false; + private Consumer<DeviceStateController.DeviceState> mDelegate; + private final List<DeviceState> mDeviceStateList = new ArrayList<>(); DeviceStateControllerBuilder setSupportFold( boolean supportFold, boolean supportHalfFold) { @@ -179,13 +257,17 @@ public class DeviceStateControllerTests { if (enableFold || enableHalfFold) { when(mMockContext.getResources() .getIntArray(R.array.config_openDeviceStates)) - .thenReturn(mOpenDeviceStates); + .thenReturn(mapDeviceStateListToIdentifierArray(mOpenDeviceStates)); when(mMockContext.getResources() .getIntArray(R.array.config_rearDisplayDeviceStates)) - .thenReturn(mRearDisplayStates); + .thenReturn(mapDeviceStateListToIdentifierArray(mRearDisplayStates)); when(mMockContext.getResources() .getInteger(R.integer.config_deviceStateConcurrentRearDisplay)) - .thenReturn(mConcurrentDisplayState); + .thenReturn(mConcurrentDisplayState.getIdentifier()); + + mDeviceStateList.addAll(mOpenDeviceStates); + mDeviceStateList.addAll(mRearDisplayStates); + mDeviceStateList.add(mConcurrentDisplayState); } else { // Match the default value in framework resources when(mMockContext.getResources() @@ -196,12 +278,14 @@ public class DeviceStateControllerTests { if (enableFold) { when(mMockContext.getResources() .getIntArray(R.array.config_foldedDeviceStates)) - .thenReturn(mFoldedStates); + .thenReturn(mapDeviceStateListToIdentifierArray(mFoldedStates)); + mDeviceStateList.addAll(mFoldedStates); } if (enableHalfFold) { when(mMockContext.getResources() .getIntArray(R.array.config_halfFoldedDeviceStates)) - .thenReturn(mHalfFoldedStates); + .thenReturn(mapDeviceStateListToIdentifierArray(mHalfFoldedStates)); + mDeviceStateList.addAll(mHalfFoldedStates); } } @@ -210,11 +294,20 @@ public class DeviceStateControllerTests { mMockDeviceStateManager = mock(DeviceStateManager.class); when(mMockContext.getSystemService(DeviceStateManager.class)) .thenReturn(mMockDeviceStateManager); + when(mMockDeviceStateManager.getSupportedDeviceStates()).thenReturn(mDeviceStateList); Resources mockRes = mock(Resources.class); when(mMockContext.getResources()).thenReturn((mockRes)); mockFold(mSupportFold, mSupportHalfFold); mTarget = new DeviceStateController(mMockContext, new WindowManagerGlobalLock()); mTarget.registerDeviceStateCallback(mDelegate, mExecutor); } + + private int[] mapDeviceStateListToIdentifierArray(List<DeviceState> deviceStates) { + int[] identifiers = new int[deviceStates.size()]; + for (int i = 0; i < deviceStates.size(); i++) { + identifiers[i] = deviceStates.get(i).getIdentifier(); + } + return identifiers; + } } } |