Add icon to Preference widget

Also,
- Fix SwitchPreference's changeable not updatable
- Use MaterialTheme.colorScheme.onSurfaceVariant as tint color for Footer icon

Bug: 235727273
Test: Manual with Gallery App
Change-Id: Ifcd33a8a9975f70ac0aea8c4869d1aa0e3b34ec2
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt
index 3077a15..8a29d35 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt
@@ -20,13 +20,16 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.DisabledByDefault
+import androidx.compose.material.icons.outlined.TouchApp
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.produceState
-import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.tooling.preview.Preview
@@ -36,6 +39,7 @@
 import com.android.settingslib.spa.framework.theme.SettingsTheme
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.ui.SettingsIcon
 import kotlinx.coroutines.delay
 
 object PreferencePageProvider : SettingsPageProvider {
@@ -75,14 +79,17 @@
             }
         })
 
-        var count by remember { mutableStateOf(0) }
+        var count by rememberSaveable { mutableStateOf(0) }
         Preference(object : PreferenceModel {
             override val title = "Click me"
             override val summary = derivedStateOf { count.toString() }
             override val onClick: (() -> Unit) = { count++ }
+            override val icon = @Composable {
+                SettingsIcon(imageVector = Icons.Outlined.TouchApp)
+            }
         })
 
-        var ticks by remember { mutableStateOf(0) }
+        var ticks by rememberSaveable { mutableStateOf(0) }
         LaunchedEffect(ticks) {
             delay(1000L)
             ticks++
@@ -96,6 +103,9 @@
             override val title = "Disabled"
             override val summary = "Disabled".toState()
             override val enabled = false.toState()
+            override val icon = @Composable {
+              SettingsIcon(imageVector = Icons.Outlined.DisabledByDefault)
+            }
         })
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
index 1a80ed2..0e6f53a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
@@ -19,6 +19,7 @@
 import androidx.compose.foundation.clickable
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import com.android.settingslib.spa.framework.compose.stateOf
 
@@ -38,6 +39,14 @@
         get() = stateOf("")
 
     /**
+     * The icon of this [Preference].
+     *
+     * Default is `null` which means no icon.
+     */
+    val icon: (@Composable () -> Unit)?
+        get() = null
+
+    /**
      * Indicates whether this [Preference] is enabled.
      *
      * Disabled [Preference] will be displayed in disabled style.
@@ -61,13 +70,16 @@
  */
 @Composable
 fun Preference(model: PreferenceModel) {
-    val modifier = model.onClick?.let { onClick ->
-        Modifier.clickable(enabled = model.enabled.value) { onClick() }
-    } ?: Modifier
+    val modifier = remember(model.enabled.value, model.onClick) {
+      model.onClick?.let { onClick ->
+        Modifier.clickable(enabled = model.enabled.value, onClick = onClick)
+      } ?: Modifier
+    }
     BasePreference(
         title = model.title,
         summary = model.summary,
         modifier = modifier,
+        icon = model.icon,
         enabled = model.enabled,
     )
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt
index 0dab0df..b6d6936 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt
@@ -100,7 +100,7 @@
 ) {
     val checkedValue = checked.value
     val indication = LocalIndication.current
-    val modifier = remember(checkedValue) {
+    val modifier = remember(checkedValue, changeable.value) {
         if (checkedValue != null && onCheckedChange != null) {
             Modifier.toggleable(
                 value = checkedValue,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Footer.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Footer.kt
index 41fd03b..296cf3b 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Footer.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Footer.kt
@@ -20,8 +20,11 @@
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.Info
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.tooling.preview.Preview
@@ -32,7 +35,12 @@
 fun Footer(footerText: String) {
     if (footerText.isEmpty()) return
     Column(Modifier.padding(SettingsDimension.itemPadding)) {
-        SettingsIcon(imageVector = Icons.Outlined.Info, contentDescription = null)
+        Icon(
+            imageVector = Icons.Outlined.Info,
+            contentDescription = null,
+            modifier = Modifier.size(SettingsDimension.itemIconSize),
+            tint = MaterialTheme.colorScheme.onSurfaceVariant,
+        )
         Spacer(modifier = Modifier.height(SettingsDimension.itemPaddingVertical))
         SettingsBody(footerText)
     }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Icon.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Icon.kt
index cb08cdb..4f28e37 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Icon.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Icon.kt
@@ -25,13 +25,10 @@
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 
 @Composable
-fun SettingsIcon(
-    imageVector: ImageVector,
-    contentDescription: String?,
-) {
+fun SettingsIcon(imageVector: ImageVector) {
     Icon(
         imageVector = imageVector,
-        contentDescription = contentDescription,
+        contentDescription = null,
         modifier = Modifier.size(SettingsDimension.itemIconSize),
         tint = MaterialTheme.colorScheme.onSurface,
     )