Loading services/core/java/com/android/server/wm/DeviceStateController.java +80 −20 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading @@ -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); Loading Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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; } } services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java +118 −25 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } Loading @@ -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 Loading @@ -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) { Loading @@ -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() Loading @@ -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); } } Loading @@ -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; } } } Loading
services/core/java/com/android/server/wm/DeviceStateController.java +80 −20 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading @@ -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); Loading Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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; } }
services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java +118 −25 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } Loading @@ -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 Loading @@ -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) { Loading @@ -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() Loading @@ -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); } } Loading @@ -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; } } }