diff --git a/.gemini/styleguide.md b/.gemini/styleguide.md
index dd76e4e19..5891186e5 100644
--- a/.gemini/styleguide.md
+++ b/.gemini/styleguide.md
@@ -16,6 +16,8 @@ When reviewing a pull request, focus on the following key areas:
* Does the new code align with the existing MVVM architecture?
* Are ViewModels, Repositories, and UI components used correctly?
* Does it introduce any anti-patterns or deviate from established conventions in the codebase?
+ * **Hilt Scoping Hygiene:** Verify Hilt dependency scopes are appropriate for their lifecycle (e.g., `SingletonComponent` vs `ActivityRetainedComponent`). Avoid over-scoping (such as using `Singleton` when the component state should be isolated per activity/test session to prevent state leaks between tests).
+ * **Git Merge & Diff Hygiene:** During merges from `main`, verify that recent `main` changes (such as scoping fixes or newly added configuration files like module `AndroidManifest.xml`s) are not accidentally reverted or lost in conflicts. Ensure the PR diff against `main` is minimal and contains zero unrelated "merge noise" or unintended file reversions.
2. **Code Quality and Best Practices**
* Check for adherence to official Kotlin style guides and Android best practices.
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 9f889b10e..0493140ed 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -151,6 +151,7 @@ dependencies {
// Access settings & model data
implementation(project(":data:settings"))
+ implementation(project(":data:settings-datastore"))
implementation(project(":core:model"))
// Camera Preview
diff --git a/data/settings-datastore/.gitignore b/data/settings-datastore/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/data/settings-datastore/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/data/settings-datastore/build.gradle.kts b/data/settings-datastore/build.gradle.kts
new file mode 100644
index 000000000..987bfa2d4
--- /dev/null
+++ b/data/settings-datastore/build.gradle.kts
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2026 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 {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.google.protobuf)
+ alias(libs.plugins.kotlin.kapt)
+}
+
+android {
+ namespace = "com.google.jetpackcamera.data.settingsdatastore"
+ compileSdk = libs.versions.compileSdk.get().toInt()
+
+ defaultConfig {
+ minSdk = libs.versions.minSdk.get().toInt()
+ testOptions.targetSdk = libs.versions.targetSdk.get().toInt()
+ lint.targetSdk = libs.versions.targetSdk.get().toInt()
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlin {
+ jvmToolchain(17)
+ }
+
+ @Suppress("UnstableApiUsage")
+ testOptions {
+ managedDevices {
+ localDevices {
+ create("pixel2Api28") {
+ device = "Pixel 2"
+ apiLevel = 28
+ }
+ create("pixel8Api34") {
+ device = "Pixel 8"
+ apiLevel = 34
+ systemImageSource = "aosp_atd"
+ }
+ }
+ }
+ }
+}
+
+dependencies {
+ implementation(libs.androidx.core.ktx)
+
+ // Hilt
+ implementation(libs.dagger.hilt.android)
+ kapt(libs.dagger.hilt.compiler)
+
+ // proto datastore
+ implementation(libs.protobuf.kotlin.lite)
+ implementation(libs.androidx.datastore)
+
+ // Access Model data
+ implementation(project(":core:common"))
+ implementation(project(":core:model"))
+ implementation(project(":data:settings"))
+
+ // Testing
+ testImplementation(libs.junit)
+ testImplementation(libs.truth)
+ androidTestImplementation(libs.androidx.espresso.core)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.truth)
+ androidTestImplementation(libs.kotlinx.coroutines.test)
+ androidTestImplementation(project(":data:settings-datastore:testing"))
+}
+
+protobuf {
+ protoc {
+ artifact = "com.google.protobuf:protoc:3.21.12"
+ }
+
+ generateProtoTasks {
+ all().forEach { task ->
+ task.builtins {
+ create("java") {
+ option("lite")
+ }
+ }
+
+ task.builtins {
+ create("kotlin") {
+ option("lite")
+ }
+ }
+ }
+ }
+}
+
+// Allow references to generated code
+kapt {
+ correctErrorTypes = true
+}
diff --git a/data/settings-datastore/consumer-rules.pro b/data/settings-datastore/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/data/settings-datastore/proguard-rules.pro b/data/settings-datastore/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/data/settings-datastore/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/data/settings/src/androidTest/java/com/google/jetpackcamera/settings/DataStoreModuleTest.kt b/data/settings-datastore/src/androidTest/java/com/google/jetpackcamera/data/settingsdatastore/DataStoreModuleTest.kt
similarity index 83%
rename from data/settings/src/androidTest/java/com/google/jetpackcamera/settings/DataStoreModuleTest.kt
rename to data/settings-datastore/src/androidTest/java/com/google/jetpackcamera/data/settingsdatastore/DataStoreModuleTest.kt
index 703783b23..f474577e3 100644
--- a/data/settings/src/androidTest/java/com/google/jetpackcamera/settings/DataStoreModuleTest.kt
+++ b/data/settings-datastore/src/androidTest/java/com/google/jetpackcamera/data/settingsdatastore/DataStoreModuleTest.kt
@@ -13,14 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.jetpackcamera.settings
+package com.google.jetpackcamera.data.settingsdatastore
import androidx.datastore.core.DataStore
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
-import com.google.jetpackcamera.settings.testing.FakeDataStoreModule
-import com.google.jetpackcamera.settings.testing.FakeJcaSettingsSerializer
+import com.google.jetpackcamera.settings.JcaSettings
+import com.google.jetpackcamera.settingsdatastore.testing.FakeDataStoreModule
+import com.google.jetpackcamera.settingsdatastore.testing.FakeJcaSettingsSerializer
import java.io.File
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
@@ -31,7 +33,7 @@ import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
+@OptIn(ExperimentalCoroutinesApi::class)
class DataStoreModuleTest {
@get:Rule
val tempFolder = TemporaryFolder()
diff --git a/data/settings/src/androidTest/java/com/google/jetpackcamera/settings/LocalSettingsRepositoryInstrumentedTest.kt b/data/settings-datastore/src/androidTest/java/com/google/jetpackcamera/data/settingsdatastore/LocalSettingsRepositoryInstrumentedTest.kt
similarity index 97%
rename from data/settings/src/androidTest/java/com/google/jetpackcamera/settings/LocalSettingsRepositoryInstrumentedTest.kt
rename to data/settings-datastore/src/androidTest/java/com/google/jetpackcamera/data/settingsdatastore/LocalSettingsRepositoryInstrumentedTest.kt
index fafb38dc3..f35fa1124 100644
--- a/data/settings/src/androidTest/java/com/google/jetpackcamera/settings/LocalSettingsRepositoryInstrumentedTest.kt
+++ b/data/settings-datastore/src/androidTest/java/com/google/jetpackcamera/data/settingsdatastore/LocalSettingsRepositoryInstrumentedTest.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.jetpackcamera.settings
+package com.google.jetpackcamera.data.settingsdatastore
import android.content.Context
import androidx.datastore.core.DataStore
@@ -22,13 +22,14 @@ import androidx.datastore.dataStoreFile
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
+import com.google.jetpackcamera.data.settingsdatastore.DataStoreModule.provideDataStore
import com.google.jetpackcamera.model.CaptureMode
import com.google.jetpackcamera.model.DarkMode
import com.google.jetpackcamera.model.DynamicRange
import com.google.jetpackcamera.model.FlashMode
import com.google.jetpackcamera.model.ImageOutputFormat
import com.google.jetpackcamera.model.LensFacing
-import com.google.jetpackcamera.settings.DataStoreModule.provideDataStore
+import com.google.jetpackcamera.settings.JcaSettings
import com.google.jetpackcamera.settings.model.CameraAppSettings
import com.google.jetpackcamera.settings.model.DEFAULT_CAMERA_APP_SETTINGS
import java.io.File
diff --git a/data/settings-datastore/src/main/AndroidManifest.xml b/data/settings-datastore/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8322d22ca
--- /dev/null
+++ b/data/settings-datastore/src/main/AndroidManifest.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/data/settings/src/main/java/com/google/jetpackcamera/settings/DataStoreModule.kt b/data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/DataStoreModule.kt
similarity index 91%
rename from data/settings/src/main/java/com/google/jetpackcamera/settings/DataStoreModule.kt
rename to data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/DataStoreModule.kt
index 7f8862455..806eecb3d 100644
--- a/data/settings/src/main/java/com/google/jetpackcamera/settings/DataStoreModule.kt
+++ b/data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/DataStoreModule.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -13,13 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.jetpackcamera.settings
+package com.google.jetpackcamera.data.settingsdatastore
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
import androidx.datastore.dataStoreFile
+import com.google.jetpackcamera.settings.JcaSettings
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -30,7 +31,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
-// with hilt will ensure datastore instance access is unique per file
@Module
@InstallIn(SingletonComponent::class)
object DataStoreModule {
diff --git a/data/settings/src/main/java/com/google/jetpackcamera/settings/JcaSettingsSerializer.kt b/data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/JcaSettingsSerializer.kt
similarity index 94%
rename from data/settings/src/main/java/com/google/jetpackcamera/settings/JcaSettingsSerializer.kt
rename to data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/JcaSettingsSerializer.kt
index f84a3248c..e47b1e9b2 100644
--- a/data/settings/src/main/java/com/google/jetpackcamera/settings/JcaSettingsSerializer.kt
+++ b/data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/JcaSettingsSerializer.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.jetpackcamera.settings
+package com.google.jetpackcamera.data.settingsdatastore
import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer
@@ -27,6 +27,7 @@ import com.google.jetpackcamera.model.proto.LensFacing
import com.google.jetpackcamera.model.proto.StabilizationMode
import com.google.jetpackcamera.model.proto.StreamConfig
import com.google.jetpackcamera.model.proto.VideoQuality
+import com.google.jetpackcamera.settings.JcaSettings
import com.google.protobuf.InvalidProtocolBufferException
import java.io.InputStream
import java.io.OutputStream
diff --git a/data/settings/src/main/java/com/google/jetpackcamera/settings/LocalSettingsRepository.kt b/data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/LocalSettingsRepository.kt
similarity index 96%
rename from data/settings/src/main/java/com/google/jetpackcamera/settings/LocalSettingsRepository.kt
rename to data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/LocalSettingsRepository.kt
index 7034f9eba..5e90a740b 100644
--- a/data/settings/src/main/java/com/google/jetpackcamera/settings/LocalSettingsRepository.kt
+++ b/data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/LocalSettingsRepository.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.jetpackcamera.settings
+package com.google.jetpackcamera.data.settingsdatastore
import androidx.datastore.core.DataStore
import com.google.jetpackcamera.core.common.DefaultCaptureModeOverride
@@ -39,13 +39,14 @@ import com.google.jetpackcamera.model.proto.DarkMode as DarkModeProto
import com.google.jetpackcamera.model.proto.FlashMode as FlashModeProto
import com.google.jetpackcamera.model.proto.StabilizationMode as StabilizationModeProto
import com.google.jetpackcamera.model.proto.StreamConfig as StreamConfigProto
+import com.google.jetpackcamera.settings.JcaSettings
+import com.google.jetpackcamera.settings.SettingsRepository
import com.google.jetpackcamera.settings.model.CameraAppSettings
import javax.inject.Inject
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
-
/**
- * Implementation of [SettingsRepository] with locally stored settings.
+ * Implementation of [com.google.jetpackcamera.settings.SettingsRepository] with locally stored settings.
*/
class LocalSettingsRepository @Inject constructor(
private val jcaSettings: DataStore,
diff --git a/data/settings/src/main/java/com/google/jetpackcamera/settings/SettingsModule.kt b/data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/SettingsModule.kt
similarity index 84%
rename from data/settings/src/main/java/com/google/jetpackcamera/settings/SettingsModule.kt
rename to data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/SettingsModule.kt
index 3c9fb71ec..5eef413dc 100644
--- a/data/settings/src/main/java/com/google/jetpackcamera/settings/SettingsModule.kt
+++ b/data/settings-datastore/src/main/java/com/google/jetpackcamera/data/settingsdatastore/SettingsModule.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.jetpackcamera.settings
+package com.google.jetpackcamera.data.settingsdatastore
+import com.google.jetpackcamera.settings.SettingsRepository
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
diff --git a/data/settings/src/main/proto/com/google/jetpackcamera/settings/jca_settings.proto b/data/settings-datastore/src/main/proto/com/google/jetpackcamera/settings/jca_settings.proto
similarity index 100%
rename from data/settings/src/main/proto/com/google/jetpackcamera/settings/jca_settings.proto
rename to data/settings-datastore/src/main/proto/com/google/jetpackcamera/settings/jca_settings.proto
diff --git a/data/settings-datastore/src/test/kotlin/ProtoConversionTest.kt b/data/settings-datastore/src/test/kotlin/ProtoConversionTest.kt
new file mode 100644
index 000000000..63736c236
--- /dev/null
+++ b/data/settings-datastore/src/test/kotlin/ProtoConversionTest.kt
@@ -0,0 +1,259 @@
+/*
+ * 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.google.jetpackcamera.settings
+
+import com.google.common.truth.Truth.assertThat
+import com.google.jetpackcamera.model.AspectRatio
+import com.google.jetpackcamera.model.DynamicRange
+import com.google.jetpackcamera.model.DynamicRange.Companion.toProto
+import com.google.jetpackcamera.model.ImageOutputFormat
+import com.google.jetpackcamera.model.ImageOutputFormat.Companion.toProto
+import com.google.jetpackcamera.model.LensFacing
+import com.google.jetpackcamera.model.LensFacing.Companion.toProto
+import com.google.jetpackcamera.model.LowLightBoostPriority
+import com.google.jetpackcamera.model.LowLightBoostPriority.Companion.toProto
+import com.google.jetpackcamera.model.StabilizationMode
+import com.google.jetpackcamera.model.VideoQuality
+import com.google.jetpackcamera.model.VideoQuality.Companion.toProto
+import com.google.jetpackcamera.model.proto.AspectRatio as AspectRatioProto
+import com.google.jetpackcamera.model.proto.DynamicRange as DynamicRangeProto
+import com.google.jetpackcamera.model.proto.ImageOutputFormat as ImageOutputFormatProto
+import com.google.jetpackcamera.model.proto.LensFacing as LensFacingProto
+import com.google.jetpackcamera.model.proto.LowLightBoostPriority as LowLightBoostPriorityProto
+import com.google.jetpackcamera.model.proto.StabilizationMode as StabilizationModeProto
+import com.google.jetpackcamera.model.proto.VideoQuality as VideoQualityProto
+import kotlin.enums.enumEntries
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ProtoConversionTest {
+
+ // --- DynamicRange ---
+ @Test
+ fun dynamicRange_convertsToCorrectProto() {
+ val correctConversions = { dynamicRange: DynamicRange ->
+ when (dynamicRange) {
+ DynamicRange.SDR -> DynamicRangeProto.DYNAMIC_RANGE_SDR
+ DynamicRange.HLG10 -> DynamicRangeProto.DYNAMIC_RANGE_HLG10
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it)).isEqualTo(it.toProto())
+ }
+ }
+
+ @Test
+ fun dynamicRangeProto_convertsToCorrectDynamicRange() {
+ val correctConversions = { dynamicRangeProto: DynamicRangeProto ->
+ when (dynamicRangeProto) {
+ DynamicRangeProto.DYNAMIC_RANGE_SDR,
+ DynamicRangeProto.UNRECOGNIZED,
+ DynamicRangeProto.DYNAMIC_RANGE_UNSPECIFIED -> DynamicRange.SDR
+
+ DynamicRangeProto.DYNAMIC_RANGE_HLG10 -> DynamicRange.HLG10
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it))
+ .isEqualTo(DynamicRange.fromProto(it))
+ }
+ }
+
+ // --- ImageOutputFormat ---
+ @Test
+ fun imageOutputFormat_convertsToCorrectProto() {
+ val correctConversions = { imageOutputFormat: ImageOutputFormat ->
+ when (imageOutputFormat) {
+ ImageOutputFormat.JPEG -> ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG
+ ImageOutputFormat.JPEG_ULTRA_HDR ->
+ ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it)).isEqualTo(it.toProto())
+ }
+ }
+
+ @Test
+ fun imageOutputFormatProto_convertsToCorrectImageOutputFormat() {
+ val correctConversions = { imageOutputFormatProto: ImageOutputFormatProto ->
+ when (imageOutputFormatProto) {
+ ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG,
+ ImageOutputFormatProto.UNRECOGNIZED -> ImageOutputFormat.JPEG
+
+ ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR ->
+ ImageOutputFormat.JPEG_ULTRA_HDR
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it))
+ .isEqualTo(ImageOutputFormat.fromProto(it))
+ }
+ }
+
+ // --- LensFacing ---
+ @Test
+ fun lensFacing_convertsToCorrectProto() {
+ val correctConversions = { lensFacing: LensFacing ->
+ when (lensFacing) {
+ LensFacing.BACK -> LensFacingProto.LENS_FACING_BACK
+ LensFacing.FRONT -> LensFacingProto.LENS_FACING_FRONT
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it)).isEqualTo(it.toProto())
+ }
+ }
+
+ @Test
+ fun lensFacingProto_convertsToCorrectLensFacing() {
+ val correctConversions = { lensFacingProto: LensFacingProto ->
+ when (lensFacingProto) {
+ LensFacingProto.LENS_FACING_BACK -> LensFacing.BACK
+ LensFacingProto.LENS_FACING_FRONT,
+ LensFacingProto.UNRECOGNIZED -> LensFacing.FRONT
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it))
+ .isEqualTo(LensFacing.fromProto(it))
+ }
+ }
+
+ // --- LowLightBoostPriority ---
+ @Test
+ fun lowLightBoostPriority_convertsToCorrectProto() {
+ val correctConversions = { priority: LowLightBoostPriority ->
+ when (priority) {
+ LowLightBoostPriority.PRIORITIZE_AE_MODE ->
+ LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_AE_MODE
+
+ LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES ->
+ LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it)).isEqualTo(it.toProto())
+ }
+ }
+
+ @Test
+ fun lowLightBoostPriorityProto_convertsToCorrectPriority() {
+ val correctConversions = { priorityProto: LowLightBoostPriorityProto ->
+ when (priorityProto) {
+ LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_AE_MODE,
+ LowLightBoostPriorityProto.UNRECOGNIZED -> LowLightBoostPriority.PRIORITIZE_AE_MODE
+
+ LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES ->
+ LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it))
+ .isEqualTo(LowLightBoostPriority.fromProto(it))
+ }
+ }
+
+ // --- VideoQuality ---
+ @Test
+ fun videoQuality_convertsToCorrectProto() {
+ val correctConversions = { videoQuality: VideoQuality ->
+ when (videoQuality) {
+ VideoQuality.UNSPECIFIED -> VideoQualityProto.VIDEO_QUALITY_UNSPECIFIED
+ VideoQuality.SD -> VideoQualityProto.VIDEO_QUALITY_SD
+ VideoQuality.HD -> VideoQualityProto.VIDEO_QUALITY_HD
+ VideoQuality.FHD -> VideoQualityProto.VIDEO_QUALITY_FHD
+ VideoQuality.UHD -> VideoQualityProto.VIDEO_QUALITY_UHD
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it)).isEqualTo(it.toProto())
+ }
+ }
+
+ @Test
+ fun videoQualityProto_convertsToCorrectVideoQuality() {
+ val correctConversions = { videoQualityProto: VideoQualityProto ->
+ when (videoQualityProto) {
+ VideoQualityProto.VIDEO_QUALITY_SD -> VideoQuality.SD
+ VideoQualityProto.VIDEO_QUALITY_HD -> VideoQuality.HD
+ VideoQualityProto.VIDEO_QUALITY_FHD -> VideoQuality.FHD
+ VideoQualityProto.VIDEO_QUALITY_UHD -> VideoQuality.UHD
+ VideoQualityProto.VIDEO_QUALITY_UNSPECIFIED,
+ VideoQualityProto.UNRECOGNIZED -> VideoQuality.UNSPECIFIED
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it))
+ .isEqualTo(VideoQuality.fromProto(it))
+ }
+ }
+
+ // --- AspectRatio (fromProto only) ---
+ @Test
+ fun aspectRatioProto_convertsToCorrectAspectRatio() {
+ val correctConversions = { aspectRatioProto: AspectRatioProto ->
+ when (aspectRatioProto) {
+ AspectRatioProto.ASPECT_RATIO_THREE_FOUR,
+ AspectRatioProto.ASPECT_RATIO_UNDEFINED,
+ AspectRatioProto.UNRECOGNIZED -> AspectRatio.THREE_FOUR
+
+ AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN -> AspectRatio.NINE_SIXTEEN
+ AspectRatioProto.ASPECT_RATIO_ONE_ONE -> AspectRatio.ONE_ONE
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it))
+ .isEqualTo(AspectRatio.fromProto(it))
+ }
+ }
+
+ // --- StabilizationMode (fromProto only) ---
+ @Test
+ fun stabilizationModeProto_convertsToCorrectStabilizationMode() {
+ val correctConversions = { stabilizationModeProto: StabilizationModeProto ->
+ when (stabilizationModeProto) {
+ StabilizationModeProto.STABILIZATION_MODE_OFF -> StabilizationMode.OFF
+ StabilizationModeProto.STABILIZATION_MODE_ON -> StabilizationMode.ON
+ StabilizationModeProto.STABILIZATION_MODE_HIGH_QUALITY ->
+ StabilizationMode.HIGH_QUALITY
+
+ StabilizationModeProto.STABILIZATION_MODE_OPTICAL -> StabilizationMode.OPTICAL
+ StabilizationModeProto.STABILIZATION_MODE_UNDEFINED,
+ StabilizationModeProto.UNRECOGNIZED,
+ StabilizationModeProto.STABILIZATION_MODE_AUTO -> StabilizationMode.AUTO
+ }
+ }
+
+ enumEntries().forEach {
+ assertThat(correctConversions(it))
+ .isEqualTo(StabilizationMode.fromProto(it))
+ }
+ }
+}
diff --git a/data/settings-datastore/testing/build.gradle.kts b/data/settings-datastore/testing/build.gradle.kts
new file mode 100644
index 000000000..21ee6b0c3
--- /dev/null
+++ b/data/settings-datastore/testing/build.gradle.kts
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2026 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 {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+}
+
+android {
+ namespace = "com.google.jetpackcamera.settings.testing"
+ compileSdk = libs.versions.compileSdk.get().toInt()
+
+ defaultConfig {
+ minSdk = libs.versions.minSdk.get().toInt()
+ testOptions.targetSdk = libs.versions.targetSdk.get().toInt()
+ lint.targetSdk = libs.versions.targetSdk.get().toInt()
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlin {
+ jvmToolchain(17)
+ }
+ }
+
+ dependencies {
+ implementation(project(":data:settings-datastore"))
+ implementation(project(":data:settings"))
+ implementation(project(":core:model"))
+
+ implementation(libs.kotlinx.coroutines.core)
+ implementation(libs.androidx.datastore)
+ implementation(libs.protobuf.kotlin.lite)
+ }
diff --git a/data/settings/testing/src/main/java/com/google/jetpackcamera/settings/testing/FakeDataStoreModule.kt b/data/settings-datastore/testing/src/main/java/com/google/jetpackcamera/settingsdatastore/testing/FakeDataStoreModule.kt
similarity index 95%
rename from data/settings/testing/src/main/java/com/google/jetpackcamera/settings/testing/FakeDataStoreModule.kt
rename to data/settings-datastore/testing/src/main/java/com/google/jetpackcamera/settingsdatastore/testing/FakeDataStoreModule.kt
index 7c07edfe6..c9bc09803 100644
--- a/data/settings/testing/src/main/java/com/google/jetpackcamera/settings/testing/FakeDataStoreModule.kt
+++ b/data/settings-datastore/testing/src/main/java/com/google/jetpackcamera/settingsdatastore/testing/FakeDataStoreModule.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.jetpackcamera.settings.testing
+package com.google.jetpackcamera.settingsdatastore.testing
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
diff --git a/data/settings/testing/src/main/java/com/google/jetpackcamera/settings/testing/FakeJcaSettingsSerializer.kt b/data/settings-datastore/testing/src/main/java/com/google/jetpackcamera/settingsdatastore/testing/FakeJcaSettingsSerializer.kt
similarity index 97%
rename from data/settings/testing/src/main/java/com/google/jetpackcamera/settings/testing/FakeJcaSettingsSerializer.kt
rename to data/settings-datastore/testing/src/main/java/com/google/jetpackcamera/settingsdatastore/testing/FakeJcaSettingsSerializer.kt
index 5b319f9d4..84a490c4c 100644
--- a/data/settings/testing/src/main/java/com/google/jetpackcamera/settings/testing/FakeJcaSettingsSerializer.kt
+++ b/data/settings-datastore/testing/src/main/java/com/google/jetpackcamera/settingsdatastore/testing/FakeJcaSettingsSerializer.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.jetpackcamera.settings.testing
+package com.google.jetpackcamera.settingsdatastore.testing
import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer
diff --git a/data/settings/build.gradle.kts b/data/settings/build.gradle.kts
index 443986762..08b43c4c2 100644
--- a/data/settings/build.gradle.kts
+++ b/data/settings/build.gradle.kts
@@ -19,7 +19,6 @@ plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.kapt)
alias(libs.plugins.dagger.hilt.android)
- alias(libs.plugins.google.protobuf)
}
android {
@@ -76,44 +75,19 @@ dependencies {
implementation(libs.dagger.hilt.android)
kapt(libs.dagger.hilt.compiler)
- // proto datastore
- implementation(libs.androidx.datastore)
- implementation(libs.protobuf.kotlin.lite)
-
- // Testing
- testImplementation(libs.junit)
- testImplementation(libs.truth)
- androidTestImplementation(libs.androidx.espresso.core)
- androidTestImplementation(libs.androidx.junit)
- androidTestImplementation(libs.truth)
- androidTestImplementation(libs.kotlinx.coroutines.test)
- androidTestImplementation(project(":data:settings:testing"))
-
// Access Model data
implementation(project(":core:model"))
implementation(project(":core:common"))
-}
-protobuf {
- protoc {
- artifact = "com.google.protobuf:protoc:3.21.12"
- }
-
- generateProtoTasks {
- all().forEach { task ->
- task.builtins {
- create("java") {
- option("lite")
- }
- }
+ // Testing
+ testImplementation(libs.junit)
+ testImplementation(libs.kotlinx.coroutines.test)
+ testImplementation(libs.truth) // For unit tests
+ testImplementation(project(":core:common")) // Explicitly add for unit tests
- task.builtins {
- create("kotlin") {
- option("lite")
- }
- }
- }
- }
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+ androidTestImplementation(libs.truth) // For instrumented tests
}
// Allow references to generated code
diff --git a/data/settings/src/main/java/com/google/jetpackcamera/settings/ConstraintsModule.kt b/data/settings/src/main/java/com/google/jetpackcamera/settings/ConstraintsModule.kt
index ed4e5b200..930a3c9da 100644
--- a/data/settings/src/main/java/com/google/jetpackcamera/settings/ConstraintsModule.kt
+++ b/data/settings/src/main/java/com/google/jetpackcamera/settings/ConstraintsModule.kt
@@ -18,8 +18,12 @@ package com.google.jetpackcamera.settings
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
+<<<<<<<< HEAD:data/settings/src/main/java/com/google/jetpackcamera/settings/ConstraintsModule.kt
import dagger.hilt.android.components.ActivityRetainedComponent
import dagger.hilt.android.scopes.ActivityRetainedScoped
+========
+import dagger.hilt.components.SingletonComponent
+>>>>>>>> main:data/settings/src/main/java/com/google/jetpackcamera/settings/SettingsModule.kt
/**
* Dagger [Module] for constraints data layer.
@@ -29,6 +33,7 @@ import dagger.hilt.android.scopes.ActivityRetainedScoped
interface ConstraintsModule {
@Binds
+<<<<<<<< HEAD:data/settings/src/main/java/com/google/jetpackcamera/settings/ConstraintsModule.kt
@ActivityRetainedScoped
fun bindsSettableConstraintsRepository(
settableConstraintsRepository: SettableConstraintsRepositoryImpl
@@ -44,4 +49,9 @@ interface ConstraintsModule {
fun bindsConstraintsRepository(
constraintsRepository: SettableConstraintsRepository
): ConstraintsRepository
+========
+ fun bindsSettingsRepository(
+ localSettingsRepository: LocalSettingsRepository
+ ): SettingsRepository
+>>>>>>>> main:data/settings/src/main/java/com/google/jetpackcamera/settings/SettingsModule.kt
}
diff --git a/data/settings/src/test/java/com/google/jetpackcamera/settings/ModelProtoConversionTest.kt b/data/settings/src/test/java/com/google/jetpackcamera/settings/ModelProtoConversionTest.kt
new file mode 100644
index 000000000..9131dfca4
--- /dev/null
+++ b/data/settings/src/test/java/com/google/jetpackcamera/settings/ModelProtoConversionTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2026 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.google.jetpackcamera.settings
+
+import com.google.common.truth.Truth.assertThat
+import com.google.jetpackcamera.model.DebugSettings
+import com.google.jetpackcamera.model.DebugSettings.Companion.encodeAsByteArray
+import com.google.jetpackcamera.model.DebugSettings.Companion.encodeAsString
+import com.google.jetpackcamera.model.DebugSettings.Companion.toProto
+import com.google.jetpackcamera.model.LensFacing
+import com.google.jetpackcamera.model.TestPattern
+import com.google.jetpackcamera.model.TestPattern.Companion.toProto
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ModelProtoConversionTest {
+
+ // --- TestPattern ---
+ @Test
+ fun testPattern_convertsToCorrectProto() {
+ val patterns = listOf(
+ TestPattern.Off,
+ TestPattern.ColorBars,
+ TestPattern.ColorBarsFadeToGray,
+ TestPattern.PN9,
+ TestPattern.Custom1,
+ TestPattern.SolidColor(1u, 2u, 3u, 4u)
+ )
+ patterns.forEach { pattern ->
+ val proto = pattern.toProto()
+ val domain = TestPattern.fromProto(proto)
+ assertThat(domain).isEqualTo(pattern)
+ }
+ }
+
+ // --- DebugSettings ---
+ @Test
+ fun debugSettings_convertsToCorrectProto() {
+ val settings = listOf(
+ DebugSettings(),
+ DebugSettings(isDebugModeEnabled = true),
+ DebugSettings(singleLensMode = LensFacing.BACK),
+ DebugSettings(singleLensMode = LensFacing.FRONT),
+ DebugSettings(testPattern = TestPattern.ColorBars),
+ DebugSettings(
+ isDebugModeEnabled = true,
+ singleLensMode = LensFacing.FRONT,
+ testPattern = TestPattern.SolidColor(255u, 0u, 0u, 255u)
+ )
+ )
+ settings.forEach { setting ->
+ val proto = setting.toProto()
+ val domain = DebugSettings.fromProto(proto)
+ assertThat(domain).isEqualTo(setting)
+ }
+ }
+
+ @Test
+ fun debugSettings_encodesAndDecodesCorrectly() {
+ val setting = DebugSettings(
+ isDebugModeEnabled = true,
+ singleLensMode = LensFacing.BACK,
+ testPattern = TestPattern.ColorBars
+ )
+
+ // Byte Array Serialization
+ val bytes = setting.encodeAsByteArray()
+ val decodedFromBytes = DebugSettings.parseFromByteArray(bytes)
+ assertThat(decodedFromBytes).isEqualTo(setting)
+
+ // Base64 String Serialization (used in Navigation Routes)
+ val string = setting.encodeAsString()
+ val decodedFromString = DebugSettings.parseFromString(string)
+ assertThat(decodedFromString).isEqualTo(setting)
+ }
+}
diff --git a/data/settings/src/test/java/com/google/jetpackcamera/settings/ProtoConversionTest.kt b/data/settings/src/test/java/com/google/jetpackcamera/settings/ProtoConversionTest.kt
deleted file mode 100644
index 5ce8f2643..000000000
--- a/data/settings/src/test/java/com/google/jetpackcamera/settings/ProtoConversionTest.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.google.jetpackcamera.settings
-
-import com.google.common.truth.Truth.assertThat
-import com.google.jetpackcamera.model.DynamicRange
-import com.google.jetpackcamera.model.DynamicRange.Companion.toProto
-import com.google.jetpackcamera.model.ImageOutputFormat
-import com.google.jetpackcamera.model.ImageOutputFormat.Companion.toProto
-import com.google.jetpackcamera.model.proto.DynamicRange as DynamicRangeProto
-import com.google.jetpackcamera.model.proto.ImageOutputFormat as ImageOutputFormatProto
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ProtoConversionTest {
- @Test
- fun dynamicRange_convertsToCorrectProto() {
- val correctConversions = { dynamicRange: DynamicRange ->
- when (dynamicRange) {
- DynamicRange.SDR -> DynamicRangeProto.DYNAMIC_RANGE_SDR
- DynamicRange.HLG10 -> DynamicRangeProto.DYNAMIC_RANGE_HLG10
- else -> TODO(
- "Test does not yet contain correct conversion for dynamic range " +
- "type: ${dynamicRange.name}"
- )
- }
- }
-
- enumValues().forEach {
- assertThat(correctConversions(it)).isEqualTo(it.toProto())
- }
- }
-
- @Test
- fun dynamicRangeProto_convertsToCorrectDynamicRange() {
- val correctConversions = { dynamicRangeProto: DynamicRangeProto ->
- when (dynamicRangeProto) {
- DynamicRangeProto.DYNAMIC_RANGE_SDR,
- DynamicRangeProto.UNRECOGNIZED,
- DynamicRangeProto.DYNAMIC_RANGE_UNSPECIFIED
- -> DynamicRange.SDR
-
- DynamicRangeProto.DYNAMIC_RANGE_HLG10 -> DynamicRange.HLG10
- else -> TODO(
- "Test does not yet contain correct conversion for dynamic range " +
- "proto type: ${dynamicRangeProto.name}"
- )
- }
- }
-
- enumValues().forEach {
- assertThat(correctConversions(it)).isEqualTo(DynamicRange.fromProto(it))
- }
- }
-
- @Test
- fun imageOutputFormat_convertsToCorrectProto() {
- val correctConversions = { imageOutputFormat: ImageOutputFormat ->
- when (imageOutputFormat) {
- ImageOutputFormat.JPEG -> ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG
- ImageOutputFormat.JPEG_ULTRA_HDR
- -> ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR
- else -> TODO(
- "Test does not yet contain correct conversion for image output format " +
- "type: ${imageOutputFormat.name}"
- )
- }
- }
-
- enumValues().forEach {
- assertThat(correctConversions(it)).isEqualTo(it.toProto())
- }
- }
-
- @Test
- fun imageOutputFormatProto_convertsToCorrectImageOutputFormat() {
- val correctConversions = { imageOutputFormatProto: ImageOutputFormatProto ->
- when (imageOutputFormatProto) {
- ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG,
- ImageOutputFormatProto.UNRECOGNIZED
- -> ImageOutputFormat.JPEG
- ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR
- -> ImageOutputFormat.JPEG_ULTRA_HDR
- else -> TODO(
- "Test does not yet contain correct conversion for image output format " +
- "proto type: ${imageOutputFormatProto.name}"
- )
- }
- }
-
- enumValues().forEach {
- assertThat(correctConversions(it)).isEqualTo(ImageOutputFormat.fromProto(it))
- }
- }
-}
diff --git a/feature/settings/build.gradle.kts b/feature/settings/build.gradle.kts
index 2e4835edc..7f6789636 100644
--- a/feature/settings/build.gradle.kts
+++ b/feature/settings/build.gradle.kts
@@ -116,6 +116,7 @@ dependencies {
implementation(libs.protobuf.kotlin.lite)
implementation(project(":data:settings"))
+ androidTestImplementation(project(":data:settings-datastore"))
implementation(project(":core:model"))
}
diff --git a/feature/settings/src/androidTest/java/com/google/jetpackcamera/settings/CameraAppSettingsViewModelTest.kt b/feature/settings/src/androidTest/java/com/google/jetpackcamera/settings/CameraAppSettingsViewModelTest.kt
index 6d09cf21a..c8dc3040e 100644
--- a/feature/settings/src/androidTest/java/com/google/jetpackcamera/settings/CameraAppSettingsViewModelTest.kt
+++ b/feature/settings/src/androidTest/java/com/google/jetpackcamera/settings/CameraAppSettingsViewModelTest.kt
@@ -23,6 +23,8 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
+import com.google.jetpackcamera.data.settingsdatastore.JcaSettingsSerializer
+import com.google.jetpackcamera.data.settingsdatastore.LocalSettingsRepository
import com.google.jetpackcamera.model.CaptureMode
import com.google.jetpackcamera.model.DarkMode
import com.google.jetpackcamera.model.LensFacing
diff --git a/settings.gradle.kts b/settings.gradle.kts
index f04820411..21666d917 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -64,3 +64,5 @@ include(":core:camera:postprocess")
include(":ui:controller")
include(":ui:controller:impl")
include(":ui:controller:testing")
+include(":data:settings-datastore")
+include(":data:settings-datastore:testing")