diff options
| author | 2024-10-17 16:14:56 +0000 | |
|---|---|---|
| committer | 2024-10-17 16:14:56 +0000 | |
| commit | 2ccd11b6d1c3d3f0b797cf8ec490980df93ffceb (patch) | |
| tree | 38f3834f94afea42cec50353d58cecc05077a3fb | |
| parent | a217457111342170ffad9a917779149d2b158696 (diff) | |
| parent | f89006814933548abf1d9c50f7386514255cf3f7 (diff) | |
Merge changes from topic "sysui-devicestate" into main
* changes:
Gerrit pre-upload formatting changes
Update SysUI usages of device state overlay config values
Adds SystemUI DeviceStateManager utilities
Update PosturesHelper to use DeviceStateManager API's
28 files changed, 984 insertions, 233 deletions
diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java index ea4ac2c928ce..635f6905e4f0 100644 --- a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java +++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java @@ -20,10 +20,13 @@ import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORE import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED; import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED; +import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.database.ContentObserver; +import android.hardware.devicestate.DeviceStateManager; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; @@ -67,7 +70,8 @@ public final class DeviceStateRotationLockSettingsManager { @VisibleForTesting DeviceStateRotationLockSettingsManager(Context context, SecureSettings secureSettings) { mSecureSettings = secureSettings; - mPosturesHelper = new PosturesHelper(context); + + mPosturesHelper = new PosturesHelper(context, getDeviceStateManager(context)); mPostureRotationLockDefaults = context.getResources() .getStringArray(R.array.config_perDeviceStateRotationLockDefaults); @@ -76,6 +80,14 @@ public final class DeviceStateRotationLockSettingsManager { listenForSettingsChange(); } + @Nullable + private DeviceStateManager getDeviceStateManager(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + return context.getSystemService(DeviceStateManager.class); + } + return null; + } + /** Returns a singleton instance of this class */ public static synchronized DeviceStateRotationLockSettingsManager getInstance(Context context) { if (sSingleton == null) { diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt index 6a13eb8c3907..14d59f2e416c 100644 --- a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt +++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt @@ -17,6 +17,12 @@ package com.android.settingslib.devicestate import android.content.Context +import android.hardware.devicestate.DeviceState +import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN +import android.hardware.devicestate.DeviceStateManager import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_FOLDED import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_HALF_FOLDED import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY @@ -24,37 +30,68 @@ import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNFOLDED import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNKNOWN import android.provider.Settings.Secure.DeviceStateRotationLockKey import com.android.internal.R +import android.hardware.devicestate.feature.flags.Flags as DeviceStateManagerFlags /** Helps to convert between device state and posture. */ -class PosturesHelper(context: Context) { +class PosturesHelper(context: Context, deviceStateManager: DeviceStateManager?) { - private val foldedDeviceStates = - context.resources.getIntArray(R.array.config_foldedDeviceStates) - private val halfFoldedDeviceStates = - context.resources.getIntArray(R.array.config_halfFoldedDeviceStates) - private val unfoldedDeviceStates = - context.resources.getIntArray(R.array.config_openDeviceStates) - private val rearDisplayDeviceStates = - context.resources.getIntArray(R.array.config_rearDisplayDeviceStates) + private val postures: Map<Int, List<Int>> + + init { + if (deviceStateManager != null && DeviceStateManagerFlags.deviceStatePropertyMigration()) { + postures = + deviceStateManager.supportedDeviceStates.groupBy { it.toPosture() } + .filterKeys { it != DEVICE_STATE_ROTATION_KEY_UNKNOWN } + .mapValues { it.value.map { it.identifier }} + } else { + val foldedDeviceStates = + context.resources.getIntArray(R.array.config_foldedDeviceStates).toList() + val halfFoldedDeviceStates = + context.resources.getIntArray(R.array.config_halfFoldedDeviceStates).toList() + val unfoldedDeviceStates = + context.resources.getIntArray(R.array.config_openDeviceStates).toList() + val rearDisplayDeviceStates = + context.resources.getIntArray(R.array.config_rearDisplayDeviceStates).toList() + + postures = + mapOf( + DEVICE_STATE_ROTATION_KEY_FOLDED to foldedDeviceStates, + DEVICE_STATE_ROTATION_KEY_HALF_FOLDED to halfFoldedDeviceStates, + DEVICE_STATE_ROTATION_KEY_UNFOLDED to unfoldedDeviceStates, + DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY to rearDisplayDeviceStates + ) + } + } @DeviceStateRotationLockKey fun deviceStateToPosture(deviceState: Int): Int { - return when (deviceState) { - in foldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_FOLDED - in halfFoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_HALF_FOLDED - in unfoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_UNFOLDED - in rearDisplayDeviceStates -> DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY - else -> DEVICE_STATE_ROTATION_KEY_UNKNOWN - } + return postures.filterValues { it.contains(deviceState) }.keys.firstOrNull() + ?: DEVICE_STATE_ROTATION_KEY_UNKNOWN } fun postureToDeviceState(@DeviceStateRotationLockKey posture: Int): Int? { - return when (posture) { - DEVICE_STATE_ROTATION_KEY_FOLDED -> foldedDeviceStates.firstOrNull() - DEVICE_STATE_ROTATION_KEY_HALF_FOLDED -> halfFoldedDeviceStates.firstOrNull() - DEVICE_STATE_ROTATION_KEY_UNFOLDED -> unfoldedDeviceStates.firstOrNull() - DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY -> rearDisplayDeviceStates.firstOrNull() - else -> null + return postures[posture]?.firstOrNull() + } + + /** + * Maps a [DeviceState] to the corresponding [DeviceStateRotationLockKey] value based on the + * properties of the state. + */ + @DeviceStateRotationLockKey + private fun DeviceState.toPosture(): Int { + return if (hasProperty(PROPERTY_FEATURE_REAR_DISPLAY)) { + DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY + } else if (hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)) { + DEVICE_STATE_ROTATION_KEY_FOLDED + } else if (hasProperties( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, + PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN + )) { + DEVICE_STATE_ROTATION_KEY_HALF_FOLDED + } else if (hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)) { + DEVICE_STATE_ROTATION_KEY_UNFOLDED + } else { + DEVICE_STATE_ROTATION_KEY_UNKNOWN } } } diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java index 52c2a87cc961..9f9aaf5ff83a 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java @@ -16,13 +16,22 @@ package com.android.settingslib.devicestate; +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 com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; +import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; import android.database.ContentObserver; +import android.hardware.devicestate.DeviceState; +import android.hardware.devicestate.DeviceStateManager; import android.os.UserHandle; import android.provider.Settings; @@ -42,7 +51,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; @SmallTest @RunWith(AndroidJUnit4.class) @@ -53,6 +65,8 @@ public class DeviceStateRotationLockSettingsManagerTest { @Mock private Context mMockContext; @Mock private Resources mMockResources; + @Mock private DeviceStateManager mDeviceStateManager; + private DeviceStateRotationLockSettingsManager mManager; private int mNumSettingsChanges = 0; private final ContentObserver mContentObserver = new ContentObserver(null) { @@ -70,6 +84,9 @@ public class DeviceStateRotationLockSettingsManagerTest { when(mMockContext.getApplicationContext()).thenReturn(mMockContext); when(mMockContext.getResources()).thenReturn(mMockResources); when(mMockContext.getContentResolver()).thenReturn(context.getContentResolver()); + when(mMockContext.getSystemService(DeviceStateManager.class)).thenReturn( + mDeviceStateManager); + when(mDeviceStateManager.getSupportedDeviceStates()).thenReturn(createDeviceStateList()); when(mMockResources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults)) .thenReturn(new String[]{"0:1", "1:0:2", "2:2"}); when(mMockResources.getIntArray(R.array.config_foldedDeviceStates)) @@ -180,4 +197,29 @@ public class DeviceStateRotationLockSettingsManagerTest { value, UserHandle.USER_CURRENT); } + + private List<DeviceState> createDeviceStateList() { + List<DeviceState> deviceStates = new ArrayList<>(); + deviceStates.add(createDeviceState(0 /* identifier */, "folded", + new HashSet<>(List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)), + new HashSet<>(List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)))); + deviceStates.add(createDeviceState(1 /* identifier */, "half_folded", + new HashSet<>(List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)), + new HashSet<>( + List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN)))); + deviceStates.add(createDeviceState(2, "unfolded", + new HashSet<>(List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)), + new HashSet<>(List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)))); + + return deviceStates; + } + + private DeviceState createDeviceState(int identifier, @NonNull String name, + @NonNull Set<@DeviceState.SystemDeviceStateProperties Integer> systemProperties, + @NonNull Set<@DeviceState.PhysicalDeviceStateProperties Integer> physicalProperties) { + DeviceState.Configuration deviceStateConfiguration = new DeviceState.Configuration.Builder( + identifier, name).setPhysicalProperties(systemProperties).setPhysicalProperties( + physicalProperties).build(); + return new DeviceState(deviceStateConfiguration); + } } diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/PosturesHelperTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/PosturesHelperTest.kt index d91c2fa66ca8..7a905cba491d 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/PosturesHelperTest.kt +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/PosturesHelperTest.kt @@ -18,6 +18,16 @@ package com.android.settingslib.devicestate import android.content.Context import android.content.res.Resources +import android.hardware.devicestate.DeviceState +import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN +import android.hardware.devicestate.DeviceStateManager +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.annotations.RequiresFlagsEnabled import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_FOLDED import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_HALF_FOLDED import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY @@ -32,14 +42,40 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import android.hardware.devicestate.feature.flags.Flags as DeviceStateManagerFlags +import org.mockito.Mockito.`when` as whenever private const val DEVICE_STATE_UNKNOWN = 0 -private const val DEVICE_STATE_CLOSED = 1 -private const val DEVICE_STATE_HALF_FOLDED = 2 -private const val DEVICE_STATE_OPEN = 3 -private const val DEVICE_STATE_REAR_DISPLAY = 4 +private val DEVICE_STATE_CLOSED = DeviceState( + DeviceState.Configuration.Builder(/* identifier= */ 1, "CLOSED") + .setSystemProperties(setOf(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)) + .setPhysicalProperties(setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)) + .build() +) +private val DEVICE_STATE_HALF_FOLDED = DeviceState( + DeviceState.Configuration.Builder(/* identifier= */ 2, "HALF_FOLDED") + .setSystemProperties(setOf(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)) + .setPhysicalProperties(setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN)) + .build() +) +private val DEVICE_STATE_OPEN = DeviceState( + DeviceState.Configuration.Builder(/* identifier= */ 3, "OPEN") + .setSystemProperties(setOf(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)) + .setPhysicalProperties(setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)) + .build() +) +private val DEVICE_STATE_REAR_DISPLAY = DeviceState( + DeviceState.Configuration.Builder(/* identifier= */ 4, "REAR_DISPLAY") + .setSystemProperties( + setOf( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + PROPERTY_FEATURE_REAR_DISPLAY + ) + ) + .setPhysicalProperties(setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)) + .build() +) @SmallTest @RunWith(AndroidJUnit4::class) @@ -51,6 +87,8 @@ class PosturesHelperTest { @Mock private lateinit var resources: Resources + @Mock private lateinit var deviceStateManager: DeviceStateManager + private lateinit var posturesHelper: PosturesHelper @Before @@ -59,30 +97,39 @@ class PosturesHelperTest { whenever(context.resources).thenReturn(resources) whenever(resources.getIntArray(R.array.config_foldedDeviceStates)) - .thenReturn(intArrayOf(DEVICE_STATE_CLOSED)) + .thenReturn(intArrayOf(DEVICE_STATE_CLOSED.identifier)) whenever(resources.getIntArray(R.array.config_halfFoldedDeviceStates)) - .thenReturn(intArrayOf(DEVICE_STATE_HALF_FOLDED)) + .thenReturn(intArrayOf(DEVICE_STATE_HALF_FOLDED.identifier)) whenever(resources.getIntArray(R.array.config_openDeviceStates)) - .thenReturn(intArrayOf(DEVICE_STATE_OPEN)) + .thenReturn(intArrayOf(DEVICE_STATE_OPEN.identifier)) whenever(resources.getIntArray(R.array.config_rearDisplayDeviceStates)) - .thenReturn(intArrayOf(DEVICE_STATE_REAR_DISPLAY)) + .thenReturn(intArrayOf(DEVICE_STATE_REAR_DISPLAY.identifier)) + whenever(deviceStateManager.supportedDeviceStates).thenReturn( + listOf( + DEVICE_STATE_CLOSED, + DEVICE_STATE_HALF_FOLDED, + DEVICE_STATE_OPEN, + DEVICE_STATE_REAR_DISPLAY + ) + ) - posturesHelper = PosturesHelper(context) + posturesHelper = PosturesHelper(context, deviceStateManager) } @Test - fun deviceStateToPosture_mapsCorrectly() { + @RequiresFlagsDisabled(DeviceStateManagerFlags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + fun deviceStateToPosture_mapsCorrectly_overlayConfigurationValues() { expect - .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_CLOSED)) + .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_CLOSED.identifier)) .isEqualTo(DEVICE_STATE_ROTATION_KEY_FOLDED) expect - .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_HALF_FOLDED)) + .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_HALF_FOLDED.identifier)) .isEqualTo(DEVICE_STATE_ROTATION_KEY_HALF_FOLDED) expect - .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_OPEN)) + .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_OPEN.identifier)) .isEqualTo(DEVICE_STATE_ROTATION_KEY_UNFOLDED) expect - .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_REAR_DISPLAY)) + .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_REAR_DISPLAY.identifier)) .isEqualTo(DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY) expect .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_UNKNOWN)) @@ -90,19 +137,58 @@ class PosturesHelperTest { } @Test - fun postureToDeviceState_mapsCorrectly() { + @RequiresFlagsEnabled(DeviceStateManagerFlags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + fun deviceStateToPosture_mapsCorrectly_deviceStateManager() { + expect + .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_CLOSED.identifier)) + .isEqualTo(DEVICE_STATE_ROTATION_KEY_FOLDED) + expect + .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_HALF_FOLDED.identifier)) + .isEqualTo(DEVICE_STATE_ROTATION_KEY_HALF_FOLDED) + expect + .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_OPEN.identifier)) + .isEqualTo(DEVICE_STATE_ROTATION_KEY_UNFOLDED) + expect + .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_REAR_DISPLAY.identifier)) + .isEqualTo(DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY) + expect + .that(posturesHelper.deviceStateToPosture(DEVICE_STATE_UNKNOWN)) + .isEqualTo(DEVICE_STATE_ROTATION_KEY_UNKNOWN) + } + + @Test + @RequiresFlagsDisabled(DeviceStateManagerFlags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + fun postureToDeviceState_mapsCorrectly_overlayConfigurationValues() { + expect + .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_FOLDED)) + .isEqualTo(DEVICE_STATE_CLOSED.identifier) + expect + .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_HALF_FOLDED)) + .isEqualTo(DEVICE_STATE_HALF_FOLDED.identifier) + expect + .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_UNFOLDED)) + .isEqualTo(DEVICE_STATE_OPEN.identifier) + expect + .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY)) + .isEqualTo(DEVICE_STATE_REAR_DISPLAY.identifier) + expect.that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_UNKNOWN)).isNull() + } + + @Test + @RequiresFlagsEnabled(DeviceStateManagerFlags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + fun postureToDeviceState_mapsCorrectly_deviceStateManager() { expect .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_FOLDED)) - .isEqualTo(DEVICE_STATE_CLOSED) + .isEqualTo(DEVICE_STATE_CLOSED.identifier) expect .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_HALF_FOLDED)) - .isEqualTo(DEVICE_STATE_HALF_FOLDED) + .isEqualTo(DEVICE_STATE_HALF_FOLDED.identifier) expect .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_UNFOLDED)) - .isEqualTo(DEVICE_STATE_OPEN) + .isEqualTo(DEVICE_STATE_OPEN.identifier) expect .that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_REAR_DISPLAY)) - .isEqualTo(DEVICE_STATE_REAR_DISPLAY) + .isEqualTo(DEVICE_STATE_REAR_DISPLAY.identifier) expect.that(posturesHelper.postureToDeviceState(DEVICE_STATE_ROTATION_KEY_UNKNOWN)).isNull() } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt index 3f5b9a35d3a5..bec8a30320e7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt @@ -16,6 +16,14 @@ package com.android.systemui.display.data.repository +import android.hardware.devicestate.DeviceState.PROPERTY_EMULATED_ONLY +import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT +import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN import android.hardware.devicestate.DeviceStateManager import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -40,6 +48,8 @@ import org.junit.Before import org.junit.runner.RunWith import org.mockito.Mockito.never import org.mockito.Mockito.verify +import org.mockito.kotlin.whenever +import android.hardware.devicestate.DeviceState as PlatformDeviceState @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @@ -59,15 +69,33 @@ class DeviceStateRepositoryTest : SysuiTestCase() { @Before fun setup() { mContext.orCreateTestableResources.apply { - addOverride(R.array.config_foldedDeviceStates, listOf(TEST_FOLDED).toIntArray()) - addOverride(R.array.config_halfFoldedDeviceStates, TEST_HALF_FOLDED.toIntArray()) - addOverride(R.array.config_openDeviceStates, TEST_UNFOLDED.toIntArray()) - addOverride(R.array.config_rearDisplayDeviceStates, TEST_REAR_DISPLAY.toIntArray()) + addOverride( + R.array.config_foldedDeviceStates, + listOf(TEST_FOLDED.identifier).toIntArray() + ) + addOverride( + R.array.config_halfFoldedDeviceStates, + TEST_HALF_FOLDED.identifier.toIntArray() + ) + addOverride(R.array.config_openDeviceStates, TEST_UNFOLDED.identifier.toIntArray()) + addOverride( + R.array.config_rearDisplayDeviceStates, + TEST_REAR_DISPLAY.identifier.toIntArray() + ) addOverride( R.array.config_concurrentDisplayDeviceStates, - TEST_CONCURRENT_DISPLAY.toIntArray() + TEST_CONCURRENT_DISPLAY.identifier.toIntArray() ) } + whenever(deviceStateManager.supportedDeviceStates).thenReturn( + listOf( + TEST_FOLDED, + TEST_HALF_FOLDED, + TEST_UNFOLDED, + TEST_REAR_DISPLAY, + TEST_CONCURRENT_DISPLAY + ) + ) deviceStateRepository = DeviceStateRepositoryImpl( mContext, @@ -85,9 +113,7 @@ class DeviceStateRepositoryTest : SysuiTestCase() { testScope.runTest { val state = displayState() - deviceStateManagerListener.value.onDeviceStateChanged( - getDeviceStateForIdentifier(TEST_FOLDED) - ) + deviceStateManagerListener.value.onDeviceStateChanged(TEST_FOLDED) assertThat(state()).isEqualTo(DeviceState.FOLDED) } @@ -97,9 +123,7 @@ class DeviceStateRepositoryTest : SysuiTestCase() { testScope.runTest { val state = displayState() - deviceStateManagerListener.value.onDeviceStateChanged( - getDeviceStateForIdentifier(TEST_HALF_FOLDED) - ) + deviceStateManagerListener.value.onDeviceStateChanged(TEST_HALF_FOLDED) assertThat(state()).isEqualTo(DeviceState.HALF_FOLDED) } @@ -109,9 +133,7 @@ class DeviceStateRepositoryTest : SysuiTestCase() { testScope.runTest { val state = displayState() - deviceStateManagerListener.value.onDeviceStateChanged( - getDeviceStateForIdentifier(TEST_UNFOLDED) - ) + deviceStateManagerListener.value.onDeviceStateChanged(TEST_UNFOLDED) assertThat(state()).isEqualTo(DeviceState.UNFOLDED) } @@ -121,9 +143,7 @@ class DeviceStateRepositoryTest : SysuiTestCase() { testScope.runTest { val state = displayState() - deviceStateManagerListener.value.onDeviceStateChanged( - getDeviceStateForIdentifier(TEST_REAR_DISPLAY) - ) + deviceStateManagerListener.value.onDeviceStateChanged(TEST_REAR_DISPLAY) assertThat(state()).isEqualTo(DeviceState.REAR_DISPLAY) } @@ -133,9 +153,7 @@ class DeviceStateRepositoryTest : SysuiTestCase() { testScope.runTest { val state = displayState() - deviceStateManagerListener.value.onDeviceStateChanged( - getDeviceStateForIdentifier(TEST_CONCURRENT_DISPLAY) - ) + deviceStateManagerListener.value.onDeviceStateChanged(TEST_CONCURRENT_DISPLAY) assertThat(state()).isEqualTo(DeviceState.CONCURRENT_DISPLAY) } @@ -164,9 +182,9 @@ class DeviceStateRepositoryTest : SysuiTestCase() { private fun Int.toIntArray() = listOf(this).toIntArray() - private fun getDeviceStateForIdentifier(id: Int): android.hardware.devicestate.DeviceState { - return android.hardware.devicestate.DeviceState( - android.hardware.devicestate.DeviceState.Configuration.Builder(id, /* name= */ "") + private fun getDeviceStateForIdentifier(id: Int): PlatformDeviceState { + return PlatformDeviceState( + PlatformDeviceState.Configuration.Builder(id, /* name= */ "") .build() ) } @@ -174,10 +192,68 @@ class DeviceStateRepositoryTest : SysuiTestCase() { private companion object { // Used to fake the ids in the test. Note that there is no guarantees different devices will // have the same ids (that's why the ones in this test start from 41) - const val TEST_FOLDED = 41 - const val TEST_HALF_FOLDED = 42 - const val TEST_UNFOLDED = 43 - const val TEST_REAR_DISPLAY = 44 - const val TEST_CONCURRENT_DISPLAY = 45 + val TEST_FOLDED = + PlatformDeviceState( + PlatformDeviceState.Configuration.Builder(41, "FOLDED") + .setSystemProperties( + setOf(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED) + ) + .build() + ) + val TEST_HALF_FOLDED = + PlatformDeviceState( + PlatformDeviceState.Configuration.Builder(42, "HALF_FOLDED") + .setSystemProperties( + setOf(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN) + ) + .build() + ) + val TEST_UNFOLDED = + PlatformDeviceState( + PlatformDeviceState.Configuration.Builder(43, "UNFOLDED") + .setSystemProperties( + setOf(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN) + ) + .build() + ) + val TEST_REAR_DISPLAY = + PlatformDeviceState( + PlatformDeviceState.Configuration.Builder(44, "REAR_DISPLAY") + .setSystemProperties( + setOf( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + PROPERTY_FEATURE_REAR_DISPLAY, + PROPERTY_EMULATED_ONLY + ) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN) + ) + .build() + ) + val TEST_CONCURRENT_DISPLAY = + PlatformDeviceState( + PlatformDeviceState.Configuration.Builder(45, "CONCURRENT_DISPLAY") + .setSystemProperties( + setOf( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, + PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT, + PROPERTY_EMULATED_ONLY + ) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN) + ) + .build() + ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt index e251ab50e3c7..baf3b5b4430f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt @@ -20,7 +20,10 @@ import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardViewController import com.android.systemui.Flags import com.android.systemui.SysuiTestCase +import com.android.systemui.defaultDeviceState +import com.android.systemui.deviceStateManager import com.android.systemui.flags.FeatureFlags +import com.android.systemui.kosmos.Kosmos import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.SysuiStatusBarStateController @@ -28,7 +31,6 @@ import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argThat -import com.android.systemui.util.mockito.whenever import java.util.function.Predicate import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse @@ -47,6 +49,7 @@ import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.MockitoAnnotations import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) @RunWithLooper @@ -65,6 +68,8 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController @Mock private lateinit var powerManager: PowerManager @Mock private lateinit var wallpaperManager: WallpaperManager + private val kosmos = Kosmos() + private val deviceStateManager = kosmos.deviceStateManager @Mock private lateinit var launcherUnlockAnimationController: ILauncherUnlockAnimationController.Stub @@ -173,7 +178,8 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { statusBarStateController, notificationShadeWindowController, powerManager, - wallpaperManager + wallpaperManager, + deviceStateManager ) { override fun shouldPerformSmartspaceTransition(): Boolean = shouldPerformSmartspaceTransition @@ -185,6 +191,8 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() { whenever(keyguardViewController.viewRootImpl).thenReturn(mock(ViewRootImpl::class.java)) whenever(powerManager.isInteractive).thenReturn(true) + whenever(deviceStateManager.supportedDeviceStates) + .thenReturn(listOf(kosmos.defaultDeviceState)) // All of these fields are final, so we can't mock them, but are needed so that the surface // appear amount setter doesn't short circuit. diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt index 04ca38fa4343..3e40c5ca797c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt @@ -22,6 +22,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.shared.model.Icon +import com.android.systemui.defaultDeviceState +import com.android.systemui.deviceStateManager +import com.android.systemui.foldedDeviceStateList import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject import com.android.systemui.qs.tiles.impl.rotation.domain.model.RotationLockTileModel @@ -30,11 +33,11 @@ import com.android.systemui.qs.tiles.viewmodel.QSTileState import com.android.systemui.res.R import com.android.systemui.statusbar.policy.DevicePostureController import com.android.systemui.statusbar.policy.devicePostureController -import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.whenever @SmallTest @RunWith(AndroidJUnit4::class) @@ -42,13 +45,17 @@ class RotationLockTileMapperTest : SysuiTestCase() { private val kosmos = Kosmos() private val rotationLockTileConfig = kosmos.qsRotationLockTileConfig private val devicePostureController = kosmos.devicePostureController + private val deviceStateManager = kosmos.deviceStateManager private lateinit var mapper: RotationLockTileMapper @Before fun setup() { + deviceStateManager whenever(devicePostureController.devicePosture) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED) + whenever(deviceStateManager.supportedDeviceStates) + .thenReturn(listOf(kosmos.defaultDeviceState)) mapper = RotationLockTileMapper( @@ -64,7 +71,8 @@ class RotationLockTileMapperTest : SysuiTestCase() { } .resources, context.theme, - devicePostureController + devicePostureController, + deviceStateManager ) } @@ -162,6 +170,7 @@ class RotationLockTileMapperTest : SysuiTestCase() { intArrayOf(1, 2, 3) ) } + whenever(deviceStateManager.supportedDeviceStates).thenReturn(kosmos.foldedDeviceStateList) } private fun createRotationLockTileState( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt index 5d850d82d806..f1015394d7b1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt @@ -18,15 +18,20 @@ package com.android.systemui.unfold import android.content.Context import android.content.res.Resources +import android.hardware.devicestate.DeviceStateManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.R import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImpl import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor +import com.android.systemui.defaultDeviceState +import com.android.systemui.deviceStateManager import com.android.systemui.display.data.repository.DeviceStateRepository import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState +import com.android.systemui.foldedDeviceStateList import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.kosmos.Kosmos import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.shared.model.ScreenPowerState import com.android.systemui.power.shared.model.WakeSleepReason @@ -39,10 +44,10 @@ import com.android.systemui.unfold.DisplaySwitchLatencyTracker.Companion.FOLDABL import com.android.systemui.unfold.DisplaySwitchLatencyTracker.DisplaySwitchLatencyEvent import com.android.systemui.unfold.data.repository.UnfoldTransitionRepositoryImpl import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor +import com.android.systemui.unfoldedDeviceState import com.android.systemui.util.animation.data.repository.AnimationStatusRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture -import com.android.systemui.util.mockito.mock import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import java.util.Optional @@ -63,6 +68,7 @@ import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import org.mockito.kotlin.mock @OptIn(ExperimentalCoroutinesApi::class) @RunWith(AndroidJUnit4::class) @@ -78,8 +84,14 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { private val animationStatusRepository = mock<AnimationStatusRepository>() private val keyguardInteractor = mock<KeyguardInteractor>() private val displaySwitchLatencyLogger = mock<DisplaySwitchLatencyLogger>() + private val kosmos = Kosmos() + private val deviceStateManager = kosmos.deviceStateManager + private val closedDeviceState = kosmos.foldedDeviceStateList.first() + private val openDeviceState = kosmos.unfoldedDeviceState + private val defaultDeviceState = kosmos.defaultDeviceState + private val nonEmptyClosedDeviceStatesArray: IntArray = + IntArray(2) { closedDeviceState.identifier } - private val nonEmptyClosedDeviceStatesArray: IntArray = IntArray(2) { 0 } private val testDispatcher: TestDispatcher = StandardTestDispatcher() private val testScope: TestScope = TestScope(testDispatcher) private val isAsleep = MutableStateFlow(false) @@ -108,6 +120,10 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { fun setup() { MockitoAnnotations.initMocks(this) whenever(mockContext.resources).thenReturn(resources) + whenever(mockContext.getSystemService(DeviceStateManager::class.java)) + .thenReturn(deviceStateManager) + whenever(deviceStateManager.supportedDeviceStates) + .thenReturn(listOf(closedDeviceState, openDeviceState)) whenever(resources.getIntArray(R.array.config_foldedDeviceStates)) .thenReturn(nonEmptyClosedDeviceStatesArray) whenever(foldStateRepository.state).thenReturn(deviceState) @@ -128,7 +144,8 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { testDispatcher.asExecutor(), testScope.backgroundScope, displaySwitchLatencyLogger, - systemClock + systemClock, + deviceStateManager ) } @@ -182,7 +199,8 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { testDispatcher.asExecutor(), testScope.backgroundScope, displaySwitchLatencyLogger, - systemClock + systemClock, + deviceStateManager ) areAnimationEnabled.emit(true) @@ -321,6 +339,8 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { deviceState.emit(DeviceState.UNFOLDED) whenever(resources.getIntArray(R.array.config_foldedDeviceStates)) .thenReturn(IntArray(0)) + whenever(deviceStateManager.supportedDeviceStates) + .thenReturn(listOf(defaultDeviceState)) displaySwitchLatencyTracker.start() deviceState.emit(DeviceState.HALF_FOLDED) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt index 1e5929daf9c0..a1122c3cbcd2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt @@ -23,9 +23,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.util.LatencyTracker import com.android.systemui.SysuiTestCase +import com.android.systemui.foldedDeviceStateList +import com.android.systemui.halfFoldedDeviceState import com.android.systemui.keyguard.ScreenLifecycle +import com.android.systemui.kosmos.Kosmos import com.android.systemui.unfold.util.FoldableDeviceStates import com.android.systemui.unfold.util.FoldableTestUtils +import com.android.systemui.unfoldedDeviceState import com.android.systemui.util.mockito.any import java.util.Optional import org.junit.Before @@ -38,6 +42,7 @@ import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.MockitoAnnotations +import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) @SmallTest @@ -62,6 +67,13 @@ class UnfoldLatencyTrackerTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) + whenever(deviceStateManager.supportedDeviceStates).thenReturn( + listOf( + Kosmos().foldedDeviceStateList[0], + Kosmos().unfoldedDeviceState + ) + ) + unfoldLatencyTracker = UnfoldLatencyTracker( latencyTracker, @@ -73,6 +85,7 @@ class UnfoldLatencyTrackerTest : SysuiTestCase() { screenLifecycle ) .apply { init() } + deviceStates = FoldableTestUtils.findDeviceStates(context) verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture()) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt index e4a1c2680658..9a9ec137a075 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt @@ -18,34 +18,53 @@ package com.android.systemui.unfold.util import android.content.Context import android.hardware.devicestate.DeviceState +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY +import android.hardware.devicestate.DeviceStateManager +import android.hardware.devicestate.feature.flags.Flags as DeviceStateManagerFlags import org.junit.Assume.assumeTrue object FoldableTestUtils { - /** Finds device state for folded and unfolded. */ fun findDeviceStates(context: Context): FoldableDeviceStates { - // TODO(b/325474477): Migrate clients to updated DeviceStateManager API's - val foldedDeviceStates: IntArray = context.resources.getIntArray( - com.android.internal.R.array.config_foldedDeviceStates) - assumeTrue("Test should be launched on a foldable device", - foldedDeviceStates.isNotEmpty()) - - val folded = getDeviceState( - identifier = foldedDeviceStates.maxOrNull()!! - ) - val unfolded = getDeviceState( - identifier = folded.identifier + 1 - ) - return FoldableDeviceStates(folded = folded, unfolded = unfolded) + if (DeviceStateManagerFlags.deviceStatePropertyMigration()) { + val deviceStateManager = context.getSystemService(DeviceStateManager::class.java) + val deviceStateList = deviceStateManager.supportedDeviceStates + + val folded = + deviceStateList.firstOrNull { state -> + state.hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY) + } + val unfolded = + deviceStateList.firstOrNull { state -> + state.hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY) + } + + assumeTrue( + "Test should only be ran on a foldable device", + (folded != null) && (unfolded != null) + ) + + return FoldableDeviceStates(folded = folded!!, unfolded = unfolded!!) + } else { + val foldedDeviceStates: IntArray = + context.resources.getIntArray( + com.android.internal.R.array.config_foldedDeviceStates + ) + assumeTrue( + "Test should be launched on a foldable device", + foldedDeviceStates.isNotEmpty() + ) + + val folded = getDeviceState(identifier = foldedDeviceStates.maxOrNull()!!) + val unfolded = getDeviceState(identifier = folded.identifier + 1) + return FoldableDeviceStates(folded = folded, unfolded = unfolded) + } } private fun getDeviceState(identifier: Int): DeviceState { - return DeviceState( - DeviceState.Configuration.Builder( - identifier, "" /* name */ - ).build() - ) + return DeviceState(DeviceState.Configuration.Builder(identifier, "" /* name */).build()) } } -data class FoldableDeviceStates(val folded: DeviceState, val unfolded: DeviceState)
\ No newline at end of file +data class FoldableDeviceStates(val folded: DeviceState, val unfolded: DeviceState) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/UtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/UtilsTest.kt new file mode 100644 index 000000000000..b4ba41a5c524 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/UtilsTest.kt @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.util + +import android.hardware.devicestate.DeviceState +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN +import android.hardware.devicestate.feature.flags.Flags +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.annotations.RequiresFlagsEnabled +import android.testing.TestableResources +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.deviceStateManager +import com.android.systemui.kosmos.Kosmos +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +class UtilsTest : SysuiTestCase() { + + private val kosmos = Kosmos() + private val deviceStateManager = kosmos.deviceStateManager + private lateinit var testableResources: TestableResources + + @Before + fun setUp() { + testableResources = context.orCreateTestableResources + } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + fun isFoldableReturnsFalse_overlayConfigurationValues() { + testableResources.addOverride( + com.android.internal.R.array.config_foldedDeviceStates, + intArrayOf() // empty array <=> device is not foldable + ) + whenever(deviceStateManager.supportedDeviceStates).thenReturn(listOf(DEFAULT_DEVICE_STATE)) + assertFalse(Utils.isDeviceFoldable(testableResources.resources, deviceStateManager)) + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + fun isFoldableReturnsFalse_deviceStateManager() { + testableResources.addOverride( + com.android.internal.R.array.config_foldedDeviceStates, + intArrayOf() // empty array <=> device is not foldable + ) + whenever(deviceStateManager.supportedDeviceStates).thenReturn(listOf(DEFAULT_DEVICE_STATE)) + assertFalse(Utils.isDeviceFoldable(testableResources.resources, deviceStateManager)) + } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + fun isFoldableReturnsTrue_overlayConfigurationValues() { + testableResources.addOverride( + com.android.internal.R.array.config_foldedDeviceStates, + intArrayOf(FOLDED_DEVICE_STATE.identifier) + ) + whenever(deviceStateManager.supportedDeviceStates) + .thenReturn(listOf(FOLDED_DEVICE_STATE, UNFOLDED_DEVICE_STATE)) + assertTrue(Utils.isDeviceFoldable(testableResources.resources, deviceStateManager)) + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION) + fun isFoldableReturnsTrue_deviceStateManager() { + testableResources.addOverride( + com.android.internal.R.array.config_foldedDeviceStates, + intArrayOf(FOLDED_DEVICE_STATE.identifier) + ) + whenever(deviceStateManager.supportedDeviceStates) + .thenReturn(listOf(FOLDED_DEVICE_STATE, UNFOLDED_DEVICE_STATE)) + assertTrue(Utils.isDeviceFoldable(testableResources.resources, deviceStateManager)) + } + + companion object { + private val DEFAULT_DEVICE_STATE = + DeviceState(DeviceState.Configuration.Builder(0 /* identifier */, "DEFAULT").build()) + private val FOLDED_DEVICE_STATE = + DeviceState( + DeviceState.Configuration.Builder(1 /* identifier */, "FOLDED") + .setSystemProperties( + setOf(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED) + ) + .build() + ) + private val UNFOLDED_DEVICE_STATE = + DeviceState( + DeviceState.Configuration.Builder(2 /* identifier */, "UNFOLDED") + .setSystemProperties( + setOf(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN) + ) + .build() + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java index 613280c3ba5d..7716ecedb772 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java @@ -17,6 +17,7 @@ package com.android.systemui.classifier; import android.content.res.Resources; +import android.hardware.devicestate.DeviceStateManager; import android.view.ViewConfiguration; import com.android.systemui.dagger.SysUISingleton; @@ -24,6 +25,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.res.R; import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.statusbar.phone.NotificationTapHelper; +import com.android.systemui.util.Utils; import dagger.Binds; import dagger.Module; @@ -104,12 +106,8 @@ public interface FalsingModule { /** */ @Provides @Named(IS_FOLDABLE_DEVICE) - static boolean providesIsFoldableDevice(@Main Resources resources) { - try { - return resources.getIntArray( - com.android.internal.R.array.config_foldedDeviceStates).length != 0; - } catch (Resources.NotFoundException e) { - return false; - } + static boolean providesIsFoldableDevice(@Main Resources resources, + DeviceStateManager deviceStateManager) { + return Utils.isDeviceFoldable(resources, deviceStateManager); } } diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt index fa7603ff777c..1da5351ac2a3 100644 --- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt @@ -17,7 +17,14 @@ package com.android.systemui.display.data.repository import android.content.Context +import android.hardware.devicestate.DeviceState as PlatformDeviceState +import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT +import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN import android.hardware.devicestate.DeviceStateManager +import android.hardware.devicestate.feature.flags.Flags as DeviceStateManagerFlags import com.android.internal.R import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Background @@ -34,15 +41,15 @@ interface DeviceStateRepository { val state: StateFlow<DeviceState> enum class DeviceState { - /** Device state in [R.array.config_foldedDeviceStates] */ + /** Device state that corresponds to the device being folded */ FOLDED, - /** Device state in [R.array.config_halfFoldedDeviceStates] */ + /** Device state that corresponds to the device being half-folded */ HALF_FOLDED, - /** Device state in [R.array.config_openDeviceStates] */ + /** Device state in that corresponds to the device being unfolded */ UNFOLDED, - /** Device state in [R.array.config_rearDisplayDeviceStates] */ + /** Device state that corresponds to the device being in rear display mode */ REAR_DISPLAY, - /** Device state in [R.array.config_concurrentDisplayDeviceStates] */ + /** Device state in that corresponds to the device being in concurrent display mode */ CONCURRENT_DISPLAY, /** Device state in none of the other arrays. */ UNKNOWN, @@ -52,8 +59,8 @@ interface DeviceStateRepository { class DeviceStateRepositoryImpl @Inject constructor( - context: Context, - deviceStateManager: DeviceStateManager, + val context: Context, + val deviceStateManager: DeviceStateManager, @Background bgScope: CoroutineScope, @Background executor: Executor ) : DeviceStateRepository { @@ -70,11 +77,17 @@ constructor( .stateIn(bgScope, started = SharingStarted.WhileSubscribed(), DeviceState.UNKNOWN) private fun deviceStateToPosture(deviceStateId: Int): DeviceState { - return deviceStateMap.firstOrNull { (ids, _) -> deviceStateId in ids }?.deviceState - ?: DeviceState.UNKNOWN + return if (DeviceStateManagerFlags.deviceStatePropertyMigration()) { + deviceStateManager.supportedDeviceStates + .firstOrNull { it.identifier == deviceStateId } + ?.toDeviceStateEnum() ?: DeviceState.UNKNOWN + } else { + deviceStateMap.firstOrNull { (ids, _) -> deviceStateId in ids }?.deviceState + ?: DeviceState.UNKNOWN + } } - private val deviceStateMap = + private val deviceStateMap: List<IdsPerDeviceState> = listOf( R.array.config_foldedDeviceStates to DeviceState.FOLDED, R.array.config_halfFoldedDeviceStates to DeviceState.HALF_FOLDED, @@ -85,4 +98,26 @@ constructor( .map { IdsPerDeviceState(context.resources.getIntArray(it.first).toSet(), it.second) } private data class IdsPerDeviceState(val ids: Set<Int>, val deviceState: DeviceState) + + /** + * Maps a [PlatformDeviceState] to the corresponding [DeviceState] value based on the properties + * of the state. + */ + private fun PlatformDeviceState.toDeviceStateEnum(): DeviceState { + return when { + hasProperty(PROPERTY_FEATURE_REAR_DISPLAY) -> DeviceState.REAR_DISPLAY + hasProperty(PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT) -> { + DeviceState.CONCURRENT_DISPLAY + } + hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY) -> DeviceState.FOLDED + hasProperties( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, + PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN + ) -> DeviceState.HALF_FOLDED + hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY) -> { + DeviceState.UNFOLDED + } + else -> DeviceState.UNKNOWN + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt index 2f41c0b2c1ea..f549e64ca853 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt @@ -23,6 +23,7 @@ import android.app.WallpaperManager import android.content.res.Resources import android.graphics.Matrix import android.graphics.Rect +import android.hardware.devicestate.DeviceStateManager import android.os.DeadObjectException import android.os.Handler import android.os.PowerManager @@ -56,6 +57,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.util.Utils.isDeviceFoldable import dagger.Lazy import javax.inject.Inject @@ -169,6 +171,7 @@ constructor( private val notificationShadeWindowController: NotificationShadeWindowController, private val powerManager: PowerManager, private val wallpaperManager: WallpaperManager, + private val deviceStateManager: DeviceStateManager ) : KeyguardStateController.Callback, ISysuiUnlockAnimationController.Stub() { interface KeyguardUnlockAnimationListener { @@ -489,7 +492,7 @@ constructor( "${!notificationShadeWindowController.isLaunchingActivity}" ) Log.wtf(TAG, " launcherUnlockController != null: ${launcherUnlockController != null}") - Log.wtf(TAG, " !isFoldable(context): ${!isFoldable(resources)}") + Log.wtf(TAG, " !isFoldable(context): ${!isDeviceFoldable(resources, deviceStateManager)}") } /** @@ -1310,11 +1313,4 @@ constructor( return if (fasterUnlockTransition()) UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS else LEGACY_UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS } - - companion object { - - fun isFoldable(resources: Resources): Boolean { - return resources.getIntArray(R.array.config_foldedDeviceStates).isNotEmpty() - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java index 5e8c2c9844ee..b019c136b6ca 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java @@ -24,6 +24,7 @@ import static com.android.wm.shell.Flags.enableTaskbarOnPhones; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; +import android.hardware.devicestate.DeviceStateManager; import android.hardware.display.DisplayManager; import android.os.Bundle; import android.os.RemoteException; @@ -58,6 +59,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.util.Utils; import com.android.systemui.util.settings.SecureSettings; import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.pip.Pip; @@ -128,7 +130,8 @@ public class NavigationBarControllerImpl implements Optional<Pip> pipOptional, Optional<BackAnimation> backAnimation, SecureSettings secureSettings, - DisplayTracker displayTracker) { + DisplayTracker displayTracker, + DeviceStateManager deviceStateManager) { mContext = context; mExecutor = mainExecutor; mNavigationBarComponentFactory = navigationBarComponentFactory; @@ -146,11 +149,19 @@ public class NavigationBarControllerImpl implements dumpManager, autoHideController, lightBarController, pipOptional, backAnimation.orElse(null), taskStackChangeListeners); mIsLargeScreen = isLargeScreen(mContext); - mIsPhone = - mContext.getResources().getIntArray(R.array.config_foldedDeviceStates).length == 0; + mIsPhone = determineIfPhone(mContext, deviceStateManager); dumpManager.registerDumpable(this); } + private boolean determineIfPhone(Context context, DeviceStateManager deviceStateManager) { + if (android.hardware.devicestate.feature.flags.Flags.deviceStatePropertyMigration()) { + return !Utils.isDeviceFoldable(context.getResources(), deviceStateManager); + } else { + return context.getResources().getIntArray(R.array.config_foldedDeviceStates).length + == 0; + } + } + @Override public void onConfigChanged(Configuration newConfig) { boolean isOldConfigLargeScreen = mIsLargeScreen; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt index 8e80fb0b4c3e..33dc6ed7a1e8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt @@ -17,6 +17,7 @@ package com.android.systemui.qs.tiles.impl.rotation.ui.mapper import android.content.res.Resources +import android.hardware.devicestate.DeviceStateManager import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper @@ -25,6 +26,7 @@ import com.android.systemui.qs.tiles.viewmodel.QSTileConfig import com.android.systemui.qs.tiles.viewmodel.QSTileState import com.android.systemui.res.R import com.android.systemui.statusbar.policy.DevicePostureController +import com.android.systemui.util.Utils.isDeviceFoldable import javax.inject.Inject /** Maps [RotationLockTileModel] to [QSTileState]. */ @@ -33,7 +35,8 @@ class RotationLockTileMapper constructor( @Main private val resources: Resources, private val theme: Resources.Theme, - private val devicePostureController: DevicePostureController + private val devicePostureController: DevicePostureController, + private val deviceStateManager: DeviceStateManager ) : QSTileDataToStateMapper<RotationLockTileModel> { override fun map(config: QSTileConfig, data: RotationLockTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { @@ -58,7 +61,7 @@ constructor( this.icon = { Icon.Loaded(resources.getDrawable(iconRes!!, theme), contentDescription = null) } - if (isDeviceFoldable()) { + if (isDeviceFoldable(resources, deviceStateManager)) { this.secondaryLabel = getSecondaryLabelWithPosture(this.activationState) } this.stateDescription = this.secondaryLabel @@ -67,11 +70,6 @@ constructor( setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK) } - private fun isDeviceFoldable(): Boolean { - val intArray = resources.getIntArray(com.android.internal.R.array.config_foldedDeviceStates) - return intArray.isNotEmpty() - } - private fun getSecondaryLabelWithPosture(activationState: QSTileState.ActivationState): String { val stateNames = resources.getStringArray(R.array.tile_states_rotation) val stateName = diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java index f02b871b196d..a32bf1ec70ae 100644 --- a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java @@ -16,6 +16,8 @@ package com.android.systemui.reardisplay; +import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; @@ -26,6 +28,7 @@ import android.content.res.Resources; import android.hardware.devicestate.DeviceState; import android.hardware.devicestate.DeviceStateManager; import android.hardware.devicestate.DeviceStateManagerGlobal; +import android.hardware.devicestate.feature.flags.Flags; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup.LayoutParams; @@ -42,6 +45,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieDrawable; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -66,11 +71,12 @@ public class RearDisplayDialogController implements ConfigurationController.ConfigurationListener, CommandQueue.Callbacks { - private int[] mFoldedStates; + private List<Integer> mFoldedStates; private boolean mStartedFolded; private boolean mServiceNotified = false; private int mAnimationRepeatCount = LottieDrawable.INFINITE; + private final DeviceStateManager mDeviceStateManager; private DeviceStateManagerGlobal mDeviceStateManagerGlobal; private DeviceStateManager.DeviceStateCallback mDeviceStateManagerCallback = new DeviceStateManagerCallback(); @@ -90,12 +96,14 @@ public class RearDisplayDialogController implements @Main Executor executor, @Main Resources resources, LayoutInflater layoutInflater, - SystemUIDialog.Factory systemUIDialogFactory) { + SystemUIDialog.Factory systemUIDialogFactory, + DeviceStateManager deviceStateManager) { mCommandQueue = commandQueue; mExecutor = executor; mResources = resources; mLayoutInflater = layoutInflater; mSystemUIDialogFactory = systemUIDialogFactory; + mDeviceStateManager = deviceStateManager; } @Override @@ -180,10 +188,23 @@ public class RearDisplayDialogController implements */ private void initializeValues(int startingBaseState) { mRearDisplayEducationDialog = mSystemUIDialogFactory.create(); - // TODO(b/329170810): Refactor and remove with updated DeviceStateManager values. - if (mFoldedStates == null) { - mFoldedStates = mResources.getIntArray( - com.android.internal.R.array.config_foldedDeviceStates); + if (Flags.deviceStatePropertyMigration()) { + if (mFoldedStates == null) { + mFoldedStates = new ArrayList<>(); + List<DeviceState> deviceStates = mDeviceStateManager.getSupportedDeviceStates(); + for (int i = 0; i < deviceStates.size(); i++) { + DeviceState state = deviceStates.get(i); + if (state.hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)) { + mFoldedStates.add(state.getIdentifier()); + } + } + } + } else { + // TODO(b/329170810): Refactor and remove with updated DeviceStateManager values. + if (mFoldedStates == null) { + mFoldedStates = copyIntArrayToList(mResources.getIntArray( + com.android.internal.R.array.config_foldedDeviceStates)); + } } mStartedFolded = isFoldedState(startingBaseState); mDeviceStateManagerGlobal = DeviceStateManagerGlobal.getInstance(); @@ -191,9 +212,17 @@ public class RearDisplayDialogController implements mExecutor); } + private List<Integer> copyIntArrayToList(int[] intArray) { + List<Integer> integerList = new ArrayList<>(intArray.length); + for (int i = 0; i < intArray.length; i++) { + integerList.add(intArray[i]); + } + return integerList; + } + private boolean isFoldedState(int state) { - for (int i = 0; i < mFoldedStates.length; i++) { - if (mFoldedStates[i] == state) return true; + for (int i = 0; i < mFoldedStates.size(); i++) { + if (mFoldedStates.get(i) == state) return true; } return false; } @@ -213,7 +242,7 @@ public class RearDisplayDialogController implements * TestAPI to allow us to set the folded states array, instead of reading from resources. */ @TestApi - void setFoldedStates(int[] foldedStates) { + void setFoldedStates(List<Integer> foldedStates) { mFoldedStates = foldedStates; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt index db237e89a683..5273702cf5e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt @@ -17,7 +17,10 @@ package com.android.systemui.statusbar.phone import android.content.Context import android.hardware.devicestate.DeviceState +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback +import android.hardware.devicestate.feature.flags.Flags as DeviceStateManagerFlags import com.android.internal.R /** @@ -47,12 +50,21 @@ internal class FoldStateListener( private var wasFolded: Boolean? = null override fun onDeviceStateChanged(state: DeviceState) { - val isFolded = foldedDeviceStates.contains(state.identifier) + val isFolded: Boolean + val willGoToSleep: Boolean + + if (DeviceStateManagerFlags.deviceStatePropertyMigration()) { + isFolded = state.hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY) + willGoToSleep = state.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP) + } else { + isFolded = foldedDeviceStates.contains(state.identifier) + willGoToSleep = goToSleepDeviceStates.contains(state.identifier) + } + if (wasFolded == isFolded) { return } wasFolded = isFolded - val willGoToSleep = goToSleepDeviceStates.contains(state.identifier) listener.onFoldStateChanged(isFolded, willGoToSleep) } } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyTracker.kt b/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyTracker.kt index b3e60e35d89e..d4686e28ce5f 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyTracker.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyTracker.kt @@ -17,6 +17,7 @@ package com.android.systemui.unfold import android.content.Context +import android.hardware.devicestate.DeviceStateManager import android.util.Log import com.android.app.tracing.TraceUtils.traceAsync import com.android.app.tracing.instantForTrack @@ -72,7 +73,8 @@ constructor( @UnfoldSingleThreadBg private val singleThreadBgExecutor: Executor, @Application private val applicationScope: CoroutineScope, private val displaySwitchLatencyLogger: DisplaySwitchLatencyLogger, - private val systemClock: SystemClock + private val systemClock: SystemClock, + private val deviceStateManager: DeviceStateManager ) : CoreStartable { private val backgroundDispatcher = singleThreadBgExecutor.asCoroutineDispatcher() @@ -81,7 +83,7 @@ constructor( @OptIn(ExperimentalCoroutinesApi::class) override fun start() { - if (!isDeviceFoldable(context)) { + if (!isDeviceFoldable(context.resources, deviceStateManager)) { return } applicationScope.launch(backgroundDispatcher) { diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt index 33fa9b8e0062..f806a5c52d5a 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt @@ -27,6 +27,7 @@ import com.android.systemui.keyguard.ScreenLifecycle import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider.Companion.areAnimationsEnabled import com.android.systemui.util.Compile +import com.android.systemui.util.Utils.isDeviceFoldable import java.util.Optional import java.util.concurrent.Executor import javax.inject.Inject @@ -51,18 +52,14 @@ constructor( @UiBackground private val uiBgExecutor: Executor, private val context: Context, private val contentResolver: ContentResolver, - private val screenLifecycle: ScreenLifecycle + private val screenLifecycle: ScreenLifecycle, ) : ScreenLifecycle.Observer, TransitionProgressListener { private var folded: Boolean? = null private var isTransitionEnabled: Boolean? = null private val foldStateListener = FoldStateListener(context) private var unfoldInProgress = false - private val isFoldable: Boolean - get() = - context.resources - .getIntArray(com.android.internal.R.array.config_foldedDeviceStates) - .isNotEmpty() + private val isFoldable: Boolean = isDeviceFoldable(context.resources, deviceStateManager) /** Registers for relevant events only if the device is foldable. */ fun init() { diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTraceLogger.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTraceLogger.kt index adf50a1e661b..a6224dcec13f 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTraceLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTraceLogger.kt @@ -16,6 +16,7 @@ package com.android.systemui.unfold import android.content.Context +import android.hardware.devicestate.DeviceStateManager import android.os.Trace import com.android.app.tracing.TraceStateLogger import com.android.systemui.CoreStartable @@ -24,6 +25,7 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.unfold.data.repository.FoldStateRepository import com.android.systemui.unfold.system.DeviceStateRepository +import com.android.systemui.util.Utils.isDeviceFoldable import javax.inject.Inject import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope @@ -42,13 +44,10 @@ constructor( private val foldStateRepository: FoldStateRepository, @Application applicationScope: CoroutineScope, @Background private val coroutineContext: CoroutineContext, - private val deviceStateRepository: DeviceStateRepository + private val deviceStateRepository: DeviceStateRepository, + private val deviceStateManager: DeviceStateManager ) : CoreStartable { - private val isFoldable: Boolean - get() = - context.resources - .getIntArray(com.android.internal.R.array.config_foldedDeviceStates) - .isNotEmpty() + private val isFoldable: Boolean = isDeviceFoldable(context.resources, deviceStateManager) private val bgScope = applicationScope.plus(coroutineContext) diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java index 3953188bb828..800d2894f192 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java @@ -14,11 +14,17 @@ package com.android.systemui.util; +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 android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.hardware.devicestate.DeviceState; +import android.hardware.devicestate.DeviceStateManager; +import android.hardware.devicestate.feature.flags.Flags; import android.provider.Settings; import android.view.DisplayCutout; @@ -84,9 +90,23 @@ public class Utils { /** * Returns {@code true} if the device is a foldable device */ - public static boolean isDeviceFoldable(Context context) { - return context.getResources() - .getIntArray(com.android.internal.R.array.config_foldedDeviceStates).length != 0; + public static boolean isDeviceFoldable(Resources resources, + DeviceStateManager deviceStateManager) { + if (Flags.deviceStatePropertyMigration()) { + List<DeviceState> deviceStates = deviceStateManager.getSupportedDeviceStates(); + for (int i = 0; i < deviceStates.size(); i++) { + DeviceState state = deviceStates.get(i); + if (state.hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY) + || state.hasProperty( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)) { + return true; + } + } + return false; + } else { + return resources.getIntArray( + com.android.internal.R.array.config_foldedDeviceStates).length != 0; + } } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java index 413aa55f4554..bc3c0d96fa22 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java @@ -40,6 +40,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import android.hardware.devicestate.DeviceStateManager; import android.util.SparseArray; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -94,6 +95,8 @@ public class NavigationBarControllerImplTest extends SysuiTestCase { private NavigationBarComponent.Factory mNavigationBarFactory; @Mock TaskbarDelegate mTaskbarDelegate; + @Mock + private DeviceStateManager mDeviceStateManager; @Before public void setUp() { @@ -116,7 +119,8 @@ public class NavigationBarControllerImplTest extends SysuiTestCase { Optional.of(mock(Pip.class)), Optional.of(mock(BackAnimation.class)), mock(SecureSettings.class), - mDisplayTracker)); + mDisplayTracker, + mDeviceStateManager)); initializeNavigationBars(); mMockitoSession = mockitoSession().mockStatic(Utilities.class).startMocking(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java index 3aaaf95810a4..83ede465c885 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java @@ -16,6 +16,11 @@ package com.android.systemui.reardisplay; +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_OPEN; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotSame; @@ -53,6 +58,9 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; +import java.util.Set; + @SmallTest @RunWith(AndroidJUnit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -69,13 +77,25 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase { private SysUiState mSysUiState; @Mock private Resources mResources; + @Mock + private DeviceStateManager mDeviceStateManager; LayoutInflater mLayoutInflater = LayoutInflater.from(mContext); private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); - private static final int CLOSED_BASE_STATE = 0; - private static final int OPEN_BASE_STATE = 1; + private static final DeviceState CLOSED_BASE_STATE = new DeviceState( + new DeviceState.Configuration.Builder(0, "CLOSED").setSystemProperties( + Set.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)) + .setPhysicalProperties(Set.of( + PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)) + .build()); + private static final DeviceState OPEN_BASE_STATE = new DeviceState( + new DeviceState.Configuration.Builder(1, "OPEN").setSystemProperties( + Set.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)) + .setPhysicalProperties(Set.of( + PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)) + .build()); @Before public void setup() { @@ -92,12 +112,13 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase { mFakeExecutor, mResources, mLayoutInflater, - mSystemUIDialogFactory); + mSystemUIDialogFactory, + mDeviceStateManager); controller.setDeviceStateManagerCallback(new TestDeviceStateManagerCallback()); - controller.setFoldedStates(new int[]{0}); + controller.setFoldedStates(List.of(0)); controller.setAnimationRepeatCount(0); - controller.showRearDisplayDialog(CLOSED_BASE_STATE); + controller.showRearDisplayDialog(CLOSED_BASE_STATE.getIdentifier()); verify(mSystemUIDialog).show(); View container = getDialogViewContainer(); @@ -115,12 +136,13 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase { mFakeExecutor, mResources, mLayoutInflater, - mSystemUIDialogFactory); + mSystemUIDialogFactory, + mDeviceStateManager); controller.setDeviceStateManagerCallback(new TestDeviceStateManagerCallback()); - controller.setFoldedStates(new int[]{0}); + controller.setFoldedStates(List.of(0)); controller.setAnimationRepeatCount(0); - controller.showRearDisplayDialog(CLOSED_BASE_STATE); + controller.showRearDisplayDialog(CLOSED_BASE_STATE.getIdentifier()); verify(mSystemUIDialog).show(); View container = getDialogViewContainer(); TextView deviceClosedTitleTextView = container.findViewById( @@ -144,12 +166,13 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase { mFakeExecutor, mResources, mLayoutInflater, - mSystemUIDialogFactory); + mSystemUIDialogFactory, + mDeviceStateManager); controller.setDeviceStateManagerCallback(new TestDeviceStateManagerCallback()); - controller.setFoldedStates(new int[]{0}); + controller.setFoldedStates(List.of(0)); controller.setAnimationRepeatCount(0); - controller.showRearDisplayDialog(OPEN_BASE_STATE); + controller.showRearDisplayDialog(OPEN_BASE_STATE.getIdentifier()); verify(mSystemUIDialog).show(); View container = getDialogViewContainer(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 72f410b7630d..9b3a43dc0310 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -18,6 +18,12 @@ package com.android.systemui.statusbar.phone; import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; +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_OPEN; +import static android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP; +import static android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE; import static android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED; import static android.provider.Settings.Global.HEADS_UP_ON; @@ -225,7 +231,9 @@ import org.mockito.MockitoAnnotations; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; +import java.util.List; import java.util.Optional; +import java.util.Set; import javax.inject.Provider; @@ -235,8 +243,22 @@ import javax.inject.Provider; @EnableFlags(FLAG_LIGHT_REVEAL_MIGRATION) public class CentralSurfacesImplTest extends SysuiTestCase { - private static final int FOLD_STATE_FOLDED = 0; - private static final int FOLD_STATE_UNFOLDED = 1; + private static final DeviceState FOLD_STATE_FOLDED = new DeviceState( + new DeviceState.Configuration.Builder(0 /* identifier */, "FOLDED" /* name */) + .setSystemProperties( + Set.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP)) + .setPhysicalProperties( + Set.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)) + .build()); + private static final DeviceState FOLD_STATE_UNFOLDED = new DeviceState( + new DeviceState.Configuration.Builder(1 /* identifier */, "UNFOLDED" /* name */) + .setSystemProperties( + Set.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, + PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE)) + .setPhysicalProperties( + Set.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)) + .build()); private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this); @@ -431,6 +453,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { when(mStackScroller.generateLayoutParams(any())).thenReturn(new LayoutParams(0, 0)); when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0)); when(mPowerManagerService.isInteractive()).thenReturn(true); + when(mDeviceStateManager.getSupportedDeviceStates()) + .thenReturn(List.of(FOLD_STATE_FOLDED, FOLD_STATE_UNFOLDED)); doAnswer(invocation -> { OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0]; @@ -999,8 +1023,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void deviceStateChange_unfolded_shadeOpen_setsLeaveOpenOnKeyguardHide() { - setFoldedStates(FOLD_STATE_FOLDED); - setGoToSleepStates(FOLD_STATE_FOLDED); + setFoldedStates(FOLD_STATE_FOLDED.getIdentifier()); + setGoToSleepStates(FOLD_STATE_FOLDED.getIdentifier()); mCentralSurfaces.setBarStateForTest(SHADE); when(mNotificationPanelViewController.isShadeFullyExpanded()).thenReturn(true); @@ -1011,8 +1035,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void deviceStateChange_unfolded_shadeOpen_onKeyguard_doesNotSetLeaveOpenOnKeyguardHide() { - setFoldedStates(FOLD_STATE_FOLDED); - setGoToSleepStates(FOLD_STATE_FOLDED); + setFoldedStates(FOLD_STATE_FOLDED.getIdentifier()); + setGoToSleepStates(FOLD_STATE_FOLDED.getIdentifier()); mCentralSurfaces.setBarStateForTest(KEYGUARD); when(mNotificationPanelViewController.isShadeFullyExpanded()).thenReturn(true); @@ -1024,8 +1048,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void deviceStateChange_unfolded_shadeClose_doesNotSetLeaveOpenOnKeyguardHide() { - setFoldedStates(FOLD_STATE_FOLDED); - setGoToSleepStates(FOLD_STATE_FOLDED); + setFoldedStates(FOLD_STATE_FOLDED.getIdentifier()); + setGoToSleepStates(FOLD_STATE_FOLDED.getIdentifier()); mCentralSurfaces.setBarStateForTest(SHADE); when(mNotificationPanelViewController.isShadeFullyExpanded()).thenReturn(false); @@ -1036,8 +1060,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void deviceStateChange_unfolded_shadeExpanding_onKeyguard_closesQS() { - setFoldedStates(FOLD_STATE_FOLDED); - setGoToSleepStates(FOLD_STATE_FOLDED); + setFoldedStates(FOLD_STATE_FOLDED.getIdentifier()); + setGoToSleepStates(FOLD_STATE_FOLDED.getIdentifier()); mCentralSurfaces.setBarStateForTest(KEYGUARD); when(mNotificationPanelViewController.isExpandingOrCollapsing()).thenReturn(true); @@ -1049,8 +1073,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void deviceStateChange_unfolded_shadeExpanded_onKeyguard_closesQS() { - setFoldedStates(FOLD_STATE_FOLDED); - setGoToSleepStates(FOLD_STATE_FOLDED); + setFoldedStates(FOLD_STATE_FOLDED.getIdentifier()); + setGoToSleepStates(FOLD_STATE_FOLDED.getIdentifier()); mCentralSurfaces.setBarStateForTest(KEYGUARD); when(mNotificationPanelViewController.isShadeFullyExpanded()).thenReturn(true); @@ -1367,9 +1391,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mCentralSurfaces.updateIsKeyguard(false /* forceStateChange */); } - private void setDeviceState(int state) { - DeviceState deviceState = new DeviceState( - new DeviceState.Configuration.Builder(state, "TEST").build()); + private void setDeviceState(DeviceState deviceState) { ArgumentCaptor<DeviceStateManager.DeviceStateCallback> callbackCaptor = ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class); verify(mDeviceStateManager).registerCallback(any(), callbackCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt index a3e2d1949a29..2e65478714af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt @@ -15,12 +15,15 @@ */ package com.android.systemui.statusbar.phone -import android.hardware.devicestate.DeviceState import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.R import com.android.systemui.SysuiTestCase +import com.android.systemui.foldedDeviceStateList +import com.android.systemui.halfFoldedDeviceState +import com.android.systemui.kosmos.Kosmos import com.android.systemui.statusbar.phone.FoldStateListener.OnFoldStateChangeListener +import com.android.systemui.unfoldedDeviceState import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -34,8 +37,7 @@ import org.mockito.MockitoAnnotations.initMocks @SmallTest class FoldStateListenerTest : SysuiTestCase() { - @Mock - private lateinit var listener: OnFoldStateChangeListener + @Mock private lateinit var listener: OnFoldStateChangeListener private lateinit var sut: FoldStateListener @Before @@ -111,25 +113,13 @@ class FoldStateListenerTest : SysuiTestCase() { } private fun setFoldedStates(vararg states: Int) { - mContext.orCreateTestableResources.addOverride( - R.array.config_foldedDeviceStates, - states - ) + mContext.orCreateTestableResources.addOverride(R.array.config_foldedDeviceStates, states) } companion object { - private val DEVICE_STATE_FOLDED = DeviceState( - DeviceState.Configuration.Builder(123 /* id */, "FOLDED" /* name */) - .build() - ) - private val DEVICE_STATE_HALF_FOLDED = DeviceState( - DeviceState.Configuration.Builder(456 /* id */, "HALF_FOLDED" /* name */) - .build() - ) - private val DEVICE_STATE_UNFOLDED = DeviceState( - DeviceState.Configuration.Builder(789 /* id */, "UNFOLDED" /* name */) - .build() - ) + private val DEVICE_STATE_FOLDED = Kosmos().foldedDeviceStateList.first() + private val DEVICE_STATE_HALF_FOLDED = Kosmos().halfFoldedDeviceState + private val DEVICE_STATE_UNFOLDED = Kosmos().unfoldedDeviceState private const val FOLDED = true private const val NOT_FOLDED = false diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java index f6e07d3d621e..3247a1ab6eb0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java @@ -16,6 +16,11 @@ package com.android.systemui.statusbar.policy; +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.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED; import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED; import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED; @@ -24,7 +29,9 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.annotation.NonNull; import android.hardware.devicestate.DeviceState; import android.hardware.devicestate.DeviceStateManager; import android.os.UserHandle; @@ -51,14 +58,37 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Collections; +import java.util.List; +import java.util.Set; + @RunWith(AndroidJUnit4.class) @SmallTest public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase { + private static final DeviceState DEFAULT_FOLDED_STATE = createDeviceState(0 /* identifier */, + "folded", Set.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY), + Set.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)); + private static final DeviceState DEFAULT_HALF_FOLDED_STATE = createDeviceState( + 2 /* identifier */, "half_folded", + Set.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY), + Set.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN)); + private static final DeviceState DEFAULT_UNFOLDED_STATE = createDeviceState(1 /* identifier */, + "unfolded", + Set.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY), + Set.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)); + private static final DeviceState UNKNOWN_DEVICE_STATE = createDeviceState(8 /* identifier */, + "unknown", Collections.emptySet(), Collections.emptySet()); + private static final List<DeviceState> DEVICE_STATE_LIST = List.of(DEFAULT_FOLDED_STATE, + DEFAULT_HALF_FOLDED_STATE, DEFAULT_UNFOLDED_STATE); + private static final String[] DEFAULT_SETTINGS = new String[]{"0:1", "2:0:1", "1:2"}; - private static final int[] DEFAULT_FOLDED_STATES = new int[]{0}; - private static final int[] DEFAULT_HALF_FOLDED_STATES = new int[]{2}; - private static final int[] DEFAULT_UNFOLDED_STATES = new int[]{1}; + private static final int[] DEFAULT_FOLDED_STATE_IDENTIFIERS = + new int[]{DEFAULT_FOLDED_STATE.getIdentifier()}; + private static final int[] DEFAULT_HALF_FOLDED_STATE_IDENTIFIERS = + new int[]{DEFAULT_HALF_FOLDED_STATE.getIdentifier()}; + private static final int[] DEFAULT_UNFOLDED_STATE_IDENTIFIERS = + new int[]{DEFAULT_UNFOLDED_STATE.getIdentifier()}; @Mock private DeviceStateManager mDeviceStateManager; @Mock private DeviceStateRotationLockSettingControllerLogger mLogger; @@ -77,10 +107,12 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase MockitoAnnotations.initMocks(/* testClass= */ this); TestableResources resources = mContext.getOrCreateTestableResources(); resources.addOverride(R.array.config_perDeviceStateRotationLockDefaults, DEFAULT_SETTINGS); - resources.addOverride(R.array.config_foldedDeviceStates, DEFAULT_FOLDED_STATES); - resources.addOverride(R.array.config_halfFoldedDeviceStates, DEFAULT_HALF_FOLDED_STATES); - resources.addOverride(R.array.config_openDeviceStates, DEFAULT_UNFOLDED_STATES); - + resources.addOverride(R.array.config_foldedDeviceStates, DEFAULT_FOLDED_STATE_IDENTIFIERS); + resources.addOverride(R.array.config_halfFoldedDeviceStates, + DEFAULT_HALF_FOLDED_STATE_IDENTIFIERS); + resources.addOverride(R.array.config_openDeviceStates, DEFAULT_UNFOLDED_STATE_IDENTIFIERS); + when(mDeviceStateManager.getSupportedDeviceStates()).thenReturn(DEVICE_STATE_LIST); + mContext.addMockSystemService(DeviceStateManager.class, mDeviceStateManager); ArgumentCaptor<DeviceStateManager.DeviceStateCallback> deviceStateCallbackArgumentCaptor = ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class); @@ -120,11 +152,11 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase 0, DEVICE_STATE_ROTATION_LOCK_UNLOCKED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED); mFakeRotationPolicy.setRotationLock(true); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(1)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_UNFOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse(); // Settings only exist for state 0 and 1 - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(2)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_HALF_FOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse(); } @@ -135,10 +167,10 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase 0, DEVICE_STATE_ROTATION_LOCK_UNLOCKED, 1, DEVICE_STATE_ROTATION_LOCK_LOCKED); mFakeRotationPolicy.setRotationLock(true); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(0)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_FOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse(); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(1)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_UNFOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue(); } @@ -148,7 +180,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase mFakeRotationPolicy.setRotationLock(true); // State 2 -> Ignored -> Fall back to state 1 which is unlocked - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(2)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_HALF_FOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse(); } @@ -162,7 +194,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase mFakeRotationPolicy.setRotationLock(false); // State 2 -> Ignored -> Fall back to state 1 which is locked - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(2)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_HALF_FOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue(); } @@ -174,7 +206,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase mSettingsManager.onPersistedSettingsChanged(); mFakeRotationPolicy.setRotationLock(true); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(0)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_FOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue(); mDeviceStateRotationLockSettingController.onRotationLockStateChanged( @@ -190,10 +222,10 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase @Test public void whenDeviceStateSwitchedToIgnoredState_useFallbackSetting() { - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(0)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_FOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue(); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(2)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_UNFOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse(); } @@ -203,10 +235,10 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase 8, DEVICE_STATE_ROTATION_LOCK_IGNORED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED); mFakeRotationPolicy.setRotationLock(true); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(1)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_UNFOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse(); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(8)); + mDeviceStateCallback.onDeviceStateChanged(UNKNOWN_DEVICE_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse(); mDeviceStateRotationLockSettingController.onRotationLockStateChanged( @@ -226,7 +258,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase 0, DEVICE_STATE_ROTATION_LOCK_UNLOCKED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED); mFakeRotationPolicy.setRotationLock(false); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(0)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_FOLDED_STATE); assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse(); @@ -242,7 +274,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase initializeSettingsWith( 0, DEVICE_STATE_ROTATION_LOCK_LOCKED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(0)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_FOLDED_STATE); mDeviceStateRotationLockSettingController.onRotationLockStateChanged( /* rotationLocked= */ false, @@ -263,7 +295,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase 0, DEVICE_STATE_ROTATION_LOCK_LOCKED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED, 2, DEVICE_STATE_ROTATION_LOCK_IGNORED); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(2)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_HALF_FOLDED_STATE); mDeviceStateRotationLockSettingController.onRotationLockStateChanged( /* rotationLocked= */ true, @@ -284,8 +316,8 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase 0, DEVICE_STATE_ROTATION_LOCK_LOCKED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED, 8, DEVICE_STATE_ROTATION_LOCK_IGNORED); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(1)); - mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(8)); + mDeviceStateCallback.onDeviceStateChanged(DEFAULT_UNFOLDED_STATE); + mDeviceStateCallback.onDeviceStateChanged(UNKNOWN_DEVICE_STATE); mDeviceStateRotationLockSettingController.onRotationLockStateChanged( /* rotationLocked= */ true, @@ -321,8 +353,13 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase mSettingsManager.onPersistedSettingsChanged(); } - private DeviceState createDeviceStateForIdentifier(int id) { - return new DeviceState(new DeviceState.Configuration.Builder(id, "" /* name */).build()); + private static DeviceState createDeviceState(int identifier, @NonNull String name, + @NonNull Set<@DeviceState.SystemDeviceStateProperties Integer> systemProperties, + @NonNull Set<@DeviceState.PhysicalDeviceStateProperties Integer> physicalProperties) { + DeviceState.Configuration deviceStateConfiguration = new DeviceState.Configuration.Builder( + identifier, name).setSystemProperties(systemProperties).setPhysicalProperties( + physicalProperties).build(); + return new DeviceState(deviceStateConfiguration); } private static class FakeRotationPolicy implements RotationPolicyWrapper { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt new file mode 100644 index 000000000000..9c55820b797c --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui + +import android.hardware.devicestate.DeviceState +import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN +import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN +import android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP +import android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE +import android.hardware.devicestate.DeviceStateManager +import com.android.systemui.kosmos.Kosmos +import org.mockito.kotlin.mock + +val Kosmos.deviceStateManager by Kosmos.Fixture { mock<DeviceStateManager>() } + +val Kosmos.defaultDeviceState by + Kosmos.Fixture { + DeviceState(DeviceState.Configuration.Builder(0 /* identifier */, "DEFAULT").build()) + } + +val Kosmos.foldedDeviceStateList by + Kosmos.Fixture { + listOf( + DeviceState( + DeviceState.Configuration.Builder(0, "FOLDED_0") + .setSystemProperties( + setOf( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP + ) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED) + ) + .build() + ), + DeviceState( + DeviceState.Configuration.Builder(1, "FOLDED_1") + .setSystemProperties( + setOf( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP + ) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED) + ) + .build() + ), + DeviceState( + DeviceState.Configuration.Builder(2, "FOLDED_2") + .setSystemProperties( + setOf( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP + ) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED) + ) + .build() + ) + ) + } + +val Kosmos.halfFoldedDeviceState by + Kosmos.Fixture { + DeviceState( + DeviceState.Configuration.Builder(3 /* identifier */, "HALF_FOLDED") + .setSystemProperties( + setOf( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, + PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE + ) + ) + .setPhysicalProperties( + setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN) + ) + .build() + ) + } + +val Kosmos.unfoldedDeviceState by + Kosmos.Fixture { + DeviceState( + DeviceState.Configuration.Builder(4 /* identifier */, "UNFOLDED") + .setSystemProperties( + setOf( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, + PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE + ) + ) + .setPhysicalProperties(setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)) + .build() + ) + } + +val Kosmos.rearDisplayDeviceState by + Kosmos.Fixture { + DeviceState( + DeviceState.Configuration.Builder(5 /* identifier */, "REAR_DISPLAY") + .setSystemProperties( + setOf( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + PROPERTY_FEATURE_REAR_DISPLAY + ) + ) + .build() + ) + } + +val Kosmos.unknownDeviceState by + Kosmos.Fixture { + DeviceState(DeviceState.Configuration.Builder(8 /* identifier */, "UNKNOWN").build()) + } |