Rename SpaLib Codelab to SpaLib Gallery

Bug: 235727273
Test: Build
Change-Id: I98eb51cbaadf0dbfe61562e07061dd5c4d476f47
diff --git a/packages/SettingsLib/Spa/gallery/Android.bp b/packages/SettingsLib/Spa/gallery/Android.bp
new file mode 100644
index 0000000..bc083c9
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2022 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 {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_app {
+    name: "SpaLibGallery",
+
+    srcs: ["src/**/*.kt"],
+
+    static_libs: [
+        "SpaLib",
+        "androidx.compose.runtime_runtime",
+    ],
+    kotlincflags: ["-Xjvm-default=all"],
+    platform_apis: true,
+    min_sdk_version: "31",
+}
diff --git a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
new file mode 100644
index 0000000..cde47f2
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2022 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.settingslib.spa.gallery">
+
+    <application
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.SpaLib.DayNight">
+        <activity
+            android:name="com.android.settingslib.spa.gallery.MainActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/packages/SettingsLib/Spa/gallery/build.gradle b/packages/SettingsLib/Spa/gallery/build.gradle
new file mode 100644
index 0000000..98e6745
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/build.gradle
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2022 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.
+ */
+
+plugins {
+    id 'com.android.application'
+    id 'kotlin-android'
+}
+
+android {
+    namespace 'com.android.settingslib.spa.gallery'
+    compileSdk 33
+
+    defaultConfig {
+        applicationId "com.android.settingslib.spa.gallery"
+        minSdk spa_min_sdk
+        targetSdk 33
+        versionCode 1
+        versionName "1.0"
+    }
+
+    sourceSets {
+        main {
+            kotlin {
+                srcDir "src"
+            }
+            res.srcDirs = ["res"]
+            manifest.srcFile "AndroidManifest.xml"
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+    kotlinOptions {
+        jvmTarget = '1.8'
+        freeCompilerArgs = ["-Xjvm-default=all"]
+    }
+    buildFeatures {
+        compose true
+    }
+    composeOptions {
+        kotlinCompilerExtensionVersion jetpack_compose_version
+    }
+    packagingOptions {
+        resources {
+            excludes += '/META-INF/{AL2.0,LGPL2.1}'
+        }
+    }
+}
+
+dependencies {
+    implementation(project(":spa"))
+}
diff --git a/packages/SettingsLib/Spa/gallery/res/values/strings.xml b/packages/SettingsLib/Spa/gallery/res/values/strings.xml
new file mode 100644
index 0000000..510e6c2
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+  Copyright (C) 2022 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.
+  -->
+<resources>
+    <!-- Gallery App name. [DO NOT TRANSLATE] -->
+    <string name="app_name" translatable="false">SpaLib Gallery</string>
+</resources>
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/MainActivity.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/MainActivity.kt
new file mode 100644
index 0000000..7db53b4
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/MainActivity.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 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.gallery
+
+import com.android.settingslib.spa.framework.SpaActivity
+import com.android.settingslib.spa.gallery.page.galleryPageRepository
+
+class MainActivity : SpaActivity(galleryPageRepository)
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
new file mode 100644
index 0000000..937e594
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 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.gallery.page
+
+import android.os.Bundle
+import androidx.compose.foundation.layout.Column
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.navigation.NavType
+import androidx.navigation.navArgument
+import com.android.settingslib.spa.framework.api.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.compose.toState
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+
+private const val STRING_PARAM_NAME = "stringParam"
+private const val INT_PARAM_NAME = "intParam"
+
+object ArgumentPageProvider : SettingsPageProvider {
+    override val name = Destinations.Argument
+
+    override val arguments = listOf(
+        navArgument(STRING_PARAM_NAME) { type = NavType.StringType },
+        navArgument(INT_PARAM_NAME) { type = NavType.IntType },
+    )
+
+    @Composable
+    override fun Page(arguments: Bundle?) {
+        ArgumentPage(
+            stringParam = arguments!!.getString(STRING_PARAM_NAME, "default"),
+            intParam = arguments.getInt(INT_PARAM_NAME),
+        )
+    }
+
+    @Composable
+    fun EntryItem(stringParam: String, intParam: Int) {
+        Preference(object : PreferenceModel {
+            override val title = "Sample page with arguments"
+            override val summary =
+                "$STRING_PARAM_NAME=$stringParam, $INT_PARAM_NAME=$intParam".toState()
+            override val onClick = navigator("${Destinations.Argument}/$stringParam/$intParam")
+        })
+    }
+}
+
+@Composable
+fun ArgumentPage(stringParam: String, intParam: Int) {
+    Column {
+        Preference(object : PreferenceModel {
+            override val title = "String param value"
+            override val summary = stringParam.toState()
+        })
+
+        Preference(object : PreferenceModel {
+            override val title = "Int param value"
+            override val summary = intParam.toString().toState()
+        })
+
+        ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = intParam + 1)
+
+        ArgumentPageProvider.EntryItem(stringParam = "bar", intParam = intParam + 1)
+    }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun ArgumentPagePreview() {
+    SettingsTheme {
+        ArgumentPage(stringParam = "foo", intParam = 0)
+    }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
new file mode 100644
index 0000000..143c365
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 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.gallery.page
+
+import android.os.Bundle
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.api.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.compose.stateOf
+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.Footer
+
+object FooterPageProvider : SettingsPageProvider {
+    override val name = "Footer"
+
+    @Composable
+    override fun Page(arguments: Bundle?) {
+        FooterPage()
+    }
+
+    @Composable
+    fun EntryItem() {
+        Preference(object : PreferenceModel {
+            override val title = "Sample Footer"
+            override val onClick = navigator(name)
+        })
+    }
+}
+
+@Composable
+private fun FooterPage() {
+    Column(Modifier.verticalScroll(rememberScrollState())) {
+        Preference(remember {
+            object : PreferenceModel {
+                override val title = "Some Preference"
+                override val summary = stateOf("Some summary")
+            }
+        })
+        Footer(footerText = "Footer text always at the end of page.")
+    }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun FooterPagePreview() {
+    SettingsTheme {
+        FooterPage()
+    }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt
new file mode 100644
index 0000000..0d17cd2
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/HomePage.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 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.gallery.page
+
+import android.os.Bundle
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.api.SettingsPageProvider
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.gallery.R
+
+object HomePageProvider : SettingsPageProvider {
+    override val name = Destinations.Home
+
+    @Composable
+    override fun Page(arguments: Bundle?) {
+        HomePage()
+    }
+}
+
+@Composable
+private fun HomePage() {
+    Column {
+        Text(
+            text = stringResource(R.string.app_name),
+            modifier = Modifier.padding(SettingsDimension.itemPadding),
+            color = MaterialTheme.colorScheme.onSurface,
+            style = MaterialTheme.typography.headlineMedium,
+        )
+
+        PreferencePageProvider.EntryItem()
+        SwitchPreferencePageProvider.EntryItem()
+        ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = 0)
+
+        SliderPageProvider.EntryItem()
+        FooterPageProvider.EntryItem()
+    }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun HomeScreenPreview() {
+    SettingsTheme {
+        HomePage()
+    }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt
new file mode 100644
index 0000000..8f38d82
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PageRepository.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.gallery.page
+
+import com.android.settingslib.spa.framework.api.SettingsPageRepository
+
+object Destinations {
+    const val Home = "Home"
+    const val Preference = "Preference"
+    const val SwitchPreference = "SwitchPreference"
+    const val Argument = "Argument"
+    const val Slider = "Slider"
+}
+
+val galleryPageRepository = SettingsPageRepository(
+    allPages = listOf(
+        HomePageProvider,
+        PreferencePageProvider,
+        SwitchPreferencePageProvider,
+        ArgumentPageProvider,
+        SliderPageProvider,
+        FooterPageProvider,
+    ),
+    startDestination = Destinations.Home,
+)
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
new file mode 100644
index 0000000..3077a15
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 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.gallery.page
+
+import android.os.Bundle
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+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.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.api.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.compose.toState
+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 kotlinx.coroutines.delay
+
+object PreferencePageProvider : SettingsPageProvider {
+    override val name = Destinations.Preference
+
+    @Composable
+    override fun Page(arguments: Bundle?) {
+        PreferencePage()
+    }
+
+    @Composable
+    fun EntryItem() {
+        Preference(object : PreferenceModel {
+            override val title = "Sample Preference"
+            override val onClick = navigator(Destinations.Preference)
+        })
+    }
+}
+
+@Composable
+private fun PreferencePage() {
+    Column(Modifier.verticalScroll(rememberScrollState())) {
+        Preference(object : PreferenceModel {
+            override val title = "Preference"
+        })
+
+        Preference(object : PreferenceModel {
+            override val title = "Preference"
+            override val summary = "With summary".toState()
+        })
+
+        Preference(object : PreferenceModel {
+            override val title = "Preference"
+            override val summary = produceState(initialValue = " ") {
+                delay(1000L)
+                value = "Async summary"
+            }
+        })
+
+        var count by remember { mutableStateOf(0) }
+        Preference(object : PreferenceModel {
+            override val title = "Click me"
+            override val summary = derivedStateOf { count.toString() }
+            override val onClick: (() -> Unit) = { count++ }
+        })
+
+        var ticks by remember { mutableStateOf(0) }
+        LaunchedEffect(ticks) {
+            delay(1000L)
+            ticks++
+        }
+        Preference(object : PreferenceModel {
+            override val title = "Ticker"
+            override val summary = derivedStateOf { ticks.toString() }
+        })
+
+        Preference(object : PreferenceModel {
+            override val title = "Disabled"
+            override val summary = "Disabled".toState()
+            override val enabled = false.toState()
+        })
+    }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun PreferencePagePreview() {
+    SettingsTheme {
+        PreferencePage()
+    }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
new file mode 100644
index 0000000..9bcac1b
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 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.gallery.page
+
+import android.os.Bundle
+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.AccessAlarm
+import androidx.compose.material.icons.outlined.MusicNote
+import androidx.compose.material.icons.outlined.MusicOff
+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 com.android.settingslib.spa.framework.api.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.navigator
+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.SettingsSlider
+import com.android.settingslib.spa.widget.ui.SettingsSliderModel
+
+object SliderPageProvider : SettingsPageProvider {
+    override val name = Destinations.Slider
+
+    @Composable
+    override fun Page(arguments: Bundle?) {
+        SliderPage()
+    }
+
+    @Composable
+    fun EntryItem() {
+        Preference(object : PreferenceModel {
+            override val title = "Sample Slider"
+            override val onClick = navigator(Destinations.Slider)
+        })
+    }
+}
+
+@Composable
+private fun SliderPage() {
+    Column(Modifier.verticalScroll(rememberScrollState())) {
+        SettingsSlider(object : SettingsSliderModel {
+            override val title = "Slider"
+            override val initValue = 40
+        })
+
+        SettingsSlider(object : SettingsSliderModel {
+            override val title = "Slider with icon"
+            override val initValue = 30
+            override val onValueChangeFinished = {
+                println("onValueChangeFinished")
+            }
+            override val icon = Icons.Outlined.AccessAlarm
+        })
+
+        val initValue = 0
+        var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) }
+        var sliderPosition by remember { mutableStateOf(initValue) }
+        SettingsSlider(object : SettingsSliderModel {
+            override val title = "Slider with changeable icon"
+            override val initValue = initValue
+            override val onValueChange = { it: Int ->
+                sliderPosition = it
+                icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff
+            }
+            override val onValueChangeFinished = {
+                println("onValueChangeFinished: the value is $sliderPosition")
+            }
+            override val icon = icon
+        })
+
+        SettingsSlider(object : SettingsSliderModel {
+            override val title = "Slider with steps"
+            override val initValue = 2
+            override val valueRange = 1..5
+            override val showSteps = true
+        })
+    }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun SliderPagePreview() {
+    SettingsTheme {
+        SliderPage()
+    }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt
new file mode 100644
index 0000000..b6f7258
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 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.gallery.page
+
+import android.os.Bundle
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.produceState
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.api.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.compose.stateOf
+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.preference.SwitchPreference
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import kotlinx.coroutines.delay
+
+object SwitchPreferencePageProvider : SettingsPageProvider {
+    override val name = Destinations.SwitchPreference
+
+    @Composable
+    override fun Page(arguments: Bundle?) {
+        SwitchPreferencePage()
+    }
+
+    @Composable
+    fun EntryItem() {
+        Preference(object : PreferenceModel {
+            override val title = "Sample SwitchPreference"
+            override val onClick = navigator(Destinations.SwitchPreference)
+        })
+    }
+}
+
+@Composable
+private fun SwitchPreferencePage() {
+    Column(Modifier.verticalScroll(rememberScrollState())) {
+        SampleSwitchPreference()
+        SampleSwitchPreferenceWithSummary()
+        SampleSwitchPreferenceWithAsyncSummary()
+        SampleNotChangeableSwitchPreference()
+    }
+}
+
+@Composable
+private fun SampleSwitchPreference() {
+    val checked = rememberSaveable { mutableStateOf(false) }
+    SwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "SwitchPreference"
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    })
+}
+
+@Composable
+private fun SampleSwitchPreferenceWithSummary() {
+    val checked = rememberSaveable { mutableStateOf(true) }
+    SwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "SwitchPreference"
+            override val summary = stateOf("With summary")
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    })
+}
+
+@Composable
+private fun SampleSwitchPreferenceWithAsyncSummary() {
+    val checked = rememberSaveable { mutableStateOf(true) }
+    val summary = produceState(initialValue = " ") {
+        delay(1000L)
+        value = "Async summary"
+    }
+    SwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "SwitchPreference"
+            override val summary = summary
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    })
+}
+
+@Composable
+private fun SampleNotChangeableSwitchPreference() {
+    val checked = rememberSaveable { mutableStateOf(true) }
+    SwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "SwitchPreference"
+            override val summary = stateOf("Not changeable")
+            override val changeable = stateOf(false)
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    })
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun SwitchPreferencePagePreview() {
+    SettingsTheme {
+        SwitchPreferencePage()
+    }
+}