Merge "Do not expand when SettingsDropdownBox disabled" into main
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
index e185367..761bb79 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
@@ -27,7 +27,7 @@
 import com.android.settingslib.spa.gallery.dialog.DialogMainPageProvider
 import com.android.settingslib.spa.gallery.dialog.NavDialogProvider
 import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
-import com.android.settingslib.spa.gallery.editor.SettingsExposedDropdownMenuBoxPageProvider
+import com.android.settingslib.spa.gallery.editor.SettingsDropdownBoxPageProvider
 import com.android.settingslib.spa.gallery.editor.SettingsDropdownCheckBoxProvider
 import com.android.settingslib.spa.gallery.home.HomePageProvider
 import com.android.settingslib.spa.gallery.itemList.ItemListPageProvider
@@ -99,7 +99,7 @@
                 OperateListPageProvider,
                 EditorMainPageProvider,
                 SettingsOutlinedTextFieldPageProvider,
-                SettingsExposedDropdownMenuBoxPageProvider,
+                SettingsDropdownBoxPageProvider,
                 SettingsDropdownCheckBoxProvider,
                 SettingsTextFieldPasswordPageProvider,
                 SearchScaffoldPageProvider,
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/EditorMainPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/EditorMainPageProvider.kt
index 9f2158a..c511542 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/EditorMainPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/EditorMainPageProvider.kt
@@ -35,7 +35,7 @@
         return listOf(
             SettingsOutlinedTextFieldPageProvider.buildInjectEntry().setLink(fromPage = owner)
                 .build(),
-            SettingsExposedDropdownMenuBoxPageProvider.buildInjectEntry().setLink(fromPage = owner)
+            SettingsDropdownBoxPageProvider.buildInjectEntry().setLink(fromPage = owner)
                 .build(),
             SettingsDropdownCheckBoxProvider.buildInjectEntry().setLink(fromPage = owner)
                 .build(),
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuBoxPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsDropdownBoxPageProvider.kt
similarity index 63%
rename from packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuBoxPageProvider.kt
rename to packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsDropdownBoxPageProvider.kt
index 5ffbe8ba..2ebb5f5 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsExposedDropdownMenuBoxPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/editor/SettingsDropdownBoxPageProvider.kt
@@ -28,16 +28,15 @@
 import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.theme.SettingsTheme
-import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuBox
+import com.android.settingslib.spa.widget.editor.SettingsDropdownBox
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
 
-private const val TITLE = "Sample SettingsExposedDropdownMenuBox"
+private const val TITLE = "Sample SettingsDropdownBox"
 
-object SettingsExposedDropdownMenuBoxPageProvider : SettingsPageProvider {
-    override val name = "SettingsExposedDropdownMenuBox"
-    private const val exposedDropdownMenuBoxLabel = "ExposedDropdownMenuBoxLabel"
+object SettingsDropdownBoxPageProvider : SettingsPageProvider {
+    override val name = "SettingsDropdownBox"
 
     override fun getTitle(arguments: Bundle?): String {
         return TITLE
@@ -45,18 +44,44 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        var selectedItem by remember { mutableIntStateOf(-1) }
-        val options = listOf("item1", "item2", "item3")
         RegularScaffold(title = TITLE) {
-            SettingsExposedDropdownMenuBox(
-                label = exposedDropdownMenuBoxLabel,
-                options = options,
-                selectedOptionIndex = selectedItem,
-                enabled = true,
-                onselectedOptionTextChange = { selectedItem = it })
+            Regular()
+            NotEnabled()
+            Empty()
         }
     }
 
+    @Composable
+    private fun Regular() {
+        var selectedItem by remember { mutableIntStateOf(-1) }
+        SettingsDropdownBox(
+            label = "SettingsDropdownBox",
+            options = listOf("item1", "item2", "item3"),
+            selectedOptionIndex = selectedItem,
+        ) { selectedItem = it }
+    }
+
+    @Composable
+    private fun NotEnabled() {
+        var selectedItem by remember { mutableIntStateOf(0) }
+        SettingsDropdownBox(
+            label = "Not enabled",
+            options = listOf("item1", "item2", "item3"),
+            enabled = false,
+            selectedOptionIndex = selectedItem,
+        ) { selectedItem = it }
+    }
+
+    @Composable
+    private fun Empty() {
+        var selectedItem by remember { mutableIntStateOf(-1) }
+        SettingsDropdownBox(
+            label = "Empty",
+            options = emptyList(),
+            selectedOptionIndex = selectedItem,
+        ) { selectedItem = it }
+    }
+
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = createSettingsPage())
             .setUiLayoutFn {
@@ -70,8 +95,8 @@
 
 @Preview(showBackground = true)
 @Composable
-private fun SettingsExposedDropdownMenuBoxPagePreview() {
+private fun SettingsDropdownBoxPagePreview() {
     SettingsTheme {
-        SettingsExposedDropdownMenuBoxPageProvider.Page(null)
+        SettingsDropdownBoxPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt
new file mode 100644
index 0000000..679c562
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.settingslib.spa.widget.editor
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ExposedDropdownMenuBox
+import androidx.compose.material3.ExposedDropdownMenuDefaults
+import androidx.compose.material3.OutlinedTextField
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+
+internal interface DropdownTextBoxScope {
+    fun dismiss()
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+internal fun DropdownTextBox(
+    label: String,
+    text: String,
+    enabled: Boolean = true,
+    errorMessage: String? = null,
+    content: @Composable DropdownTextBoxScope.() -> Unit,
+) {
+    var expanded by remember { mutableStateOf(false) }
+    val scope = remember {
+        object : DropdownTextBoxScope {
+            override fun dismiss() {
+                expanded = false
+            }
+        }
+    }
+    ExposedDropdownMenuBox(
+        expanded = expanded,
+        onExpandedChange = { expanded = enabled && it },
+        modifier = Modifier
+            .padding(SettingsDimension.menuFieldPadding)
+            .width(Width),
+    ) {
+        OutlinedTextField(
+            // The `menuAnchor` modifier must be passed to the text field for correctness.
+            modifier = Modifier
+                .menuAnchor()
+                .fillMaxWidth(),
+            value = text,
+            onValueChange = { },
+            label = { Text(text = label) },
+            trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
+            singleLine = true,
+            readOnly = true,
+            enabled = enabled,
+            isError = errorMessage != null,
+            supportingText = errorMessage?.let { { Text(text = it) } },
+        )
+        ExposedDropdownMenu(
+            expanded = expanded,
+            modifier = Modifier.width(Width),
+            onDismissRequest = { expanded = false },
+        ) { scope.content() }
+    }
+}
+
+private val Width = 310.dp
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsDropdownBox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsDropdownBox.kt
new file mode 100644
index 0000000..ff141c2
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsDropdownBox.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.settingslib.spa.widget.editor
+
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ExposedDropdownMenuDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+
+@Composable
+@OptIn(ExperimentalMaterial3Api::class)
+fun SettingsDropdownBox(
+    label: String,
+    options: List<String>,
+    selectedOptionIndex: Int,
+    enabled: Boolean = true,
+    onSelectedOptionChange: (Int) -> Unit,
+) {
+    DropdownTextBox(
+        label = label,
+        text = options.getOrElse(selectedOptionIndex) { "" },
+        enabled = enabled && options.isNotEmpty(),
+    ) {
+        options.forEachIndexed { index, option ->
+            DropdownMenuItem(
+                text = { Text(option) },
+                onClick = {
+                    dismiss()
+                    onSelectedOptionChange(index)
+                },
+                contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
+            )
+        }
+    }
+}
+
+@Preview
+@Composable
+private fun SettingsDropdownBoxPreview() {
+    val item1 = "item1"
+    val item2 = "item2"
+    val item3 = "item3"
+    val options = listOf(item1, item2, item3)
+    SettingsTheme {
+        SettingsDropdownBox(
+            label = "ExposedDropdownMenuBoxLabel",
+            options = options,
+            selectedOptionIndex = 0,
+            enabled = true,
+        ) {}
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsDropdownCheckBox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsDropdownCheckBox.kt
index 57963e6..0e7e499 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsDropdownCheckBox.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsDropdownCheckBox.kt
@@ -19,28 +19,15 @@
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
 import androidx.compose.material3.Checkbox
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.ExposedDropdownMenuBox
-import androidx.compose.material3.ExposedDropdownMenuDefaults
-import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableIntStateOf
 import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.layout.onSizeChanged
-import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.framework.theme.SettingsOpacity.alphaForEnabled
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -68,7 +55,6 @@
     }
 }
 
-@OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun SettingsDropdownCheckBox(
     label: String,
@@ -78,43 +64,18 @@
     errorMessage: String? = null,
     onSelectedStateChange: () -> Unit = {},
 ) {
-    var dropDownWidth by remember { mutableIntStateOf(0) }
-    var expanded by remember { mutableStateOf(false) }
-    val changeable = enabled && options.changeable
-    ExposedDropdownMenuBox(
-        expanded = expanded,
-        onExpandedChange = { expanded = changeable && it },
-        modifier = Modifier
-            .width(350.dp)
-            .padding(SettingsDimension.textFieldPadding)
-            .onSizeChanged { dropDownWidth = it.width },
+    DropdownTextBox(
+        label = label,
+        text = getDisplayText(options) ?: emptyText,
+        enabled = enabled && options.changeable,
+        errorMessage = errorMessage,
     ) {
-        OutlinedTextField(
-            // The `menuAnchor` modifier must be passed to the text field for correctness.
-            modifier = Modifier
-                .menuAnchor()
-                .fillMaxWidth(),
-            value = getDisplayText(options) ?: emptyText,
-            onValueChange = {},
-            label = { Text(text = label) },
-            trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded) },
-            readOnly = true,
-            enabled = changeable,
-            isError = errorMessage != null,
-            supportingText = errorMessage?.let { { Text(text = it) } },
-        )
-        ExposedDropdownMenu(
-            expanded = expanded,
-            modifier = Modifier.width(with(LocalDensity.current) { dropDownWidth.toDp() }),
-            onDismissRequest = { expanded = false },
-        ) {
-            for (option in options) {
-                CheckboxItem(option) {
-                    option.onClick()
-                    if (option.changeable) {
-                        checkboxItemOnClick(options, option)
-                        onSelectedStateChange()
-                    }
+        for (option in options) {
+            CheckboxItem(option) {
+                option.onClick()
+                if (option.changeable) {
+                    checkboxItemOnClick(options, option)
+                    onSelectedStateChange()
                 }
             }
         }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBox.kt
deleted file mode 100644
index f6692a3..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBox.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2023 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.settingslib.spa.widget.editor
-
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.material3.DropdownMenuItem
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.ExposedDropdownMenuBox
-import androidx.compose.material3.ExposedDropdownMenuDefaults
-import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import com.android.settingslib.spa.framework.theme.SettingsDimension
-import com.android.settingslib.spa.framework.theme.SettingsTheme
-
-@Composable
-@OptIn(ExperimentalMaterial3Api::class)
-fun SettingsExposedDropdownMenuBox(
-    label: String,
-    options: List<String>,
-    selectedOptionIndex: Int,
-    enabled: Boolean,
-    onselectedOptionTextChange: (Int) -> Unit,
-) {
-    var expanded by remember { mutableStateOf(false) }
-    ExposedDropdownMenuBox(
-        expanded = expanded,
-        onExpandedChange = { expanded = it },
-        modifier = Modifier
-            .width(350.dp)
-            .padding(SettingsDimension.menuFieldPadding),
-    ) {
-        OutlinedTextField(
-            // The `menuAnchor` modifier must be passed to the text field for correctness.
-            modifier = Modifier
-                .menuAnchor()
-                .fillMaxWidth(),
-            value = options.getOrElse(selectedOptionIndex) { "" },
-            onValueChange = { },
-            label = { Text(text = label) },
-            trailingIcon = {
-                ExposedDropdownMenuDefaults.TrailingIcon(
-                    expanded = expanded
-                )
-            },
-            singleLine = true,
-            readOnly = true,
-            enabled = enabled
-        )
-        if (options.isNotEmpty()) {
-            ExposedDropdownMenu(
-                expanded = expanded,
-                modifier = Modifier
-                    .fillMaxWidth(),
-                onDismissRequest = { expanded = false },
-            ) {
-                options.forEach { option ->
-                    DropdownMenuItem(
-                        text = { Text(option) },
-                        onClick = {
-                            onselectedOptionTextChange(options.indexOf(option))
-                            expanded = false
-                        },
-                        contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
-                    )
-                }
-            }
-        }
-    }
-}
-
-@Preview
-@Composable
-private fun SettingsExposedDropdownMenuBoxsPreview() {
-    val item1 = "item1"
-    val item2 = "item2"
-    val item3 = "item3"
-    val options = listOf(item1, item2, item3)
-    SettingsTheme {
-        SettingsExposedDropdownMenuBox(
-            label = "ExposedDropdownMenuBoxLabel",
-            options = options,
-            selectedOptionIndex = 0,
-            enabled = true,
-            onselectedOptionTextChange = {})
-    }
-}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsDropdownBoxTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsDropdownBoxTest.kt
new file mode 100644
index 0000000..c347424
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsDropdownBoxTest.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.settingslib.spa.widget.editor
+
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SettingsDropdownBoxTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun dropdownMenuBox_displayed() {
+        composeTestRule.setContent {
+            var selectedItem by remember { mutableStateOf(0) }
+            SettingsDropdownBox(
+                label = LABEL,
+                options = options,
+                selectedOptionIndex = selectedItem,
+            ) { selectedItem = it }
+        }
+
+        composeTestRule.onNodeWithText(LABEL).assertIsDisplayed()
+    }
+
+    @Test
+    fun dropdownMenuBox_enabled_expanded() {
+        composeTestRule.setContent {
+            var selectedItem by remember { mutableIntStateOf(0) }
+            SettingsDropdownBox(
+                label = LABEL,
+                options = options,
+                selectedOptionIndex = selectedItem
+            ) { selectedItem = it }
+        }
+        composeTestRule.onNodeWithText(ITEM2).assertDoesNotExist()
+
+        composeTestRule.onNodeWithText(LABEL).performClick()
+
+        composeTestRule.onNodeWithText(ITEM2).assertIsDisplayed()
+    }
+
+    @Test
+    fun dropdownMenuBox_notEnabled_notExpanded() {
+        composeTestRule.setContent {
+            var selectedItem by remember { mutableIntStateOf(0) }
+            SettingsDropdownBox(
+                label = LABEL,
+                options = options,
+                enabled = false,
+                selectedOptionIndex = selectedItem
+            ) { selectedItem = it }
+        }
+        composeTestRule.onNodeWithText(ITEM2).assertDoesNotExist()
+
+        composeTestRule.onNodeWithText(LABEL).performClick()
+
+        composeTestRule.onNodeWithText(ITEM2).assertDoesNotExist()
+    }
+
+    @Test
+    fun dropdownMenuBox_valueChanged() {
+        composeTestRule.setContent {
+            var selectedItem by remember { mutableIntStateOf(0) }
+            SettingsDropdownBox(
+                label = LABEL,
+                options = options,
+                selectedOptionIndex = selectedItem
+            ) { selectedItem = it }
+        }
+        composeTestRule.onNodeWithText(ITEM2).assertDoesNotExist()
+
+        composeTestRule.onNodeWithText(LABEL).performClick()
+        composeTestRule.onNodeWithText(ITEM2).performClick()
+
+        composeTestRule.onNodeWithText(ITEM2).assertIsDisplayed()
+    }
+    private companion object {
+        const val LABEL = "Label"
+        const val ITEM2 = "item2"
+        val options = listOf("item1", ITEM2, "item3")
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBoxTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBoxTest.kt
deleted file mode 100644
index bc67e4c..0000000
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/editor/SettingsExposedDropdownMenuBoxTest.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2023 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.settingslib.spa.widget.editor
-
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.test.assertIsDisplayed
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onNodeWithText
-import androidx.compose.ui.test.performClick
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class SettingsExposedDropdownMenuBoxTest {
-    @get:Rule
-    val composeTestRule = createComposeRule()
-    private val options = listOf("item1", "item2", "item3")
-    private val item2 = "item2"
-    private val exposedDropdownMenuBoxLabel = "ExposedDropdownMenuBoxLabel"
-
-    @Test
-    fun exposedDropdownMenuBoxs_displayed() {
-        composeTestRule.setContent {
-            var selectedItem by remember { mutableStateOf(0) }
-            SettingsExposedDropdownMenuBox(
-                label = exposedDropdownMenuBoxLabel,
-                options = options,
-                selectedOptionIndex = selectedItem,
-                enabled = true,
-                onselectedOptionTextChange = { selectedItem = it })
-        }
-        composeTestRule.onNodeWithText(exposedDropdownMenuBoxLabel, substring = true)
-            .assertIsDisplayed()
-    }
-
-    @Test
-    fun exposedDropdownMenuBoxs_expanded() {
-        composeTestRule.setContent {
-            var selectedItem by remember { mutableIntStateOf(0) }
-            SettingsExposedDropdownMenuBox(
-                label = exposedDropdownMenuBoxLabel,
-                options = options,
-                selectedOptionIndex = selectedItem,
-                enabled = true,
-                onselectedOptionTextChange = { selectedItem = it })
-        }
-        composeTestRule.onNodeWithText(item2, substring = true)
-            .assertDoesNotExist()
-        composeTestRule.onNodeWithText(exposedDropdownMenuBoxLabel, substring = true)
-            .performClick()
-        composeTestRule.onNodeWithText(item2, substring = true)
-            .assertIsDisplayed()
-    }
-
-    @Test
-    fun exposedDropdownMenuBoxs_valueChanged() {
-        composeTestRule.setContent {
-            var selectedItem by remember { mutableIntStateOf(0) }
-            SettingsExposedDropdownMenuBox(
-                label = exposedDropdownMenuBoxLabel,
-                options = options,
-                selectedOptionIndex = selectedItem,
-                enabled = true,
-                onselectedOptionTextChange = { selectedItem = it })
-        }
-        composeTestRule.onNodeWithText(item2, substring = true)
-            .assertDoesNotExist()
-        composeTestRule.onNodeWithText(exposedDropdownMenuBoxLabel, substring = true)
-            .performClick()
-        composeTestRule.onNodeWithText(item2, substring = true)
-            .performClick()
-        composeTestRule.onNodeWithText(item2, substring = true)
-            .assertIsDisplayed()
-    }
-}
\ No newline at end of file