From 190c006f9769d71d30847fcf6b1d6cae54b291e5 Mon Sep 17 00:00:00 2001 From: Trevor McGuire Date: Mon, 29 Jun 2026 19:55:05 +0000 Subject: [PATCH 01/14] Restore datastore-proto module and decouple via SettingsDataSource This PR restores the `datastore-proto` module that was removed in PR #525. It brings back the `.proto` files, mappers, and serializers, but in a separate module under `:core:settings:datastore-proto`. Key architectural changes: - The `datastore-proto` module encapsulates `DataStoreFactory.create()` so `androidx.datastore` is no longer exposed to `:app`. - The `datastore-proto` module is completely Hilt-free. - Updates `:app`'s `AppSettingsModule` to manually provide the `ProtoDataStoreSettingsDataSource`. --- app/build.gradle.kts | 3 +- .../google/jetpackcamera/AppSettingsModule.kt | 20 +- .../settings/datastore-proto/build.gradle.kts | 78 ++++++ .../google/jetpackcamera/settings/Mappers.kt | 236 +++++++++++++++++ .../ProtoDataStoreSettingsDataSource.kt | 183 +++++++++++++ .../settings/ProtoJcaSettingsSerializer.kt | 59 +++++ .../model/proto/aspect_ratio.proto | 27 ++ .../model/proto/concurrent_camera_mode.proto | 24 ++ .../jetpackcamera/model/proto/dark_mode.proto | 26 ++ .../model/proto/debug_settings.proto | 29 +++ .../model/proto/dynamic_range.proto | 26 ++ .../model/proto/flash_mode.proto | 27 ++ .../model/proto/image_output_format.proto | 25 ++ .../model/proto/lens_facing.proto | 25 ++ .../proto/low_light_boost_priority.proto | 25 ++ .../model/proto/stabilization_mode.proto | 29 +++ .../model/proto/stream_config.proto | 26 ++ .../model/proto/test_pattern.proto | 55 ++++ .../model/proto/video_quality.proto | 28 ++ .../settings/proto_jca_settings.proto | 51 ++++ .../jetpackcamera/settings/MappersTest.kt | 244 ++++++++++++++++++ .../ProtoDataStoreSettingsDataSourceTest.kt | 231 +++++++++++++++++ gradle/libs.versions.toml | 11 +- settings.gradle.kts | 1 + 24 files changed, 1463 insertions(+), 26 deletions(-) create mode 100644 core/settings/datastore-proto/build.gradle.kts create mode 100644 core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/Mappers.kt create mode 100644 core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt create mode 100644 core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/debug_settings.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dynamic_range.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/test_pattern.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/video_quality.proto create mode 100644 core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/settings/proto_jca_settings.proto create mode 100644 core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/MappersTest.kt create mode 100644 core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2e67075a4..5bfab0893 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -153,10 +153,9 @@ dependencies { // Access settings & model data implementation(project(":data:settings")) - implementation(project(":core:settings:datastore-prefs")) + implementation(project(":core:settings:datastore-proto")) implementation(project(":core:settings")) implementation(project(":core:model")) - implementation(libs.androidx.datastore.preferences) // Camera Preview implementation(project(":feature:preview")) diff --git a/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt b/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt index 49a9f434c..4a4115bb1 100644 --- a/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt +++ b/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt @@ -16,13 +16,6 @@ package com.google.jetpackcamera import android.content.Context -import androidx.datastore.core.DataStore -import androidx.datastore.preferences.core.PreferenceDataStoreFactory -import androidx.datastore.preferences.core.Preferences -import androidx.datastore.preferences.preferencesDataStoreFile -import com.google.jetpackcamera.core.common.DefaultCaptureModeOverride -import com.google.jetpackcamera.core.settings.datastoreprefs.PrefsDataStoreSettingsDataSource -import com.google.jetpackcamera.model.CaptureMode import com.google.jetpackcamera.settings.SettingsDataSource import dagger.Module import dagger.Provides @@ -35,20 +28,11 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) object AppSettingsModule { - @Provides - @Singleton - fun providePreferencesDataStore(@ApplicationContext context: Context): DataStore { - return PreferenceDataStoreFactory.create( - produceFile = { context.preferencesDataStoreFile("app_settings.preferences_pb") } - ) - } - @Provides @Singleton fun provideSettingsDataSource( - dataStore: DataStore, - @DefaultCaptureModeOverride defaultCaptureMode: CaptureMode + @ApplicationContext context: Context, ): SettingsDataSource { - return PrefsDataStoreSettingsDataSource(dataStore, defaultCaptureMode) + return com.google.jetpackcamera.settings.ProtoDataStoreSettingsDataSource.create(context) } } diff --git a/core/settings/datastore-proto/build.gradle.kts b/core/settings/datastore-proto/build.gradle.kts new file mode 100644 index 000000000..34a4af571 --- /dev/null +++ b/core/settings/datastore-proto/build.gradle.kts @@ -0,0 +1,78 @@ +/* + * 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.protobuf) +} + +android { + namespace = "com.google.jetpackcamera.settings.datastore.proto" + 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" + } + + flavorDimensions += "flavor" + productFlavors { + create("stable") { + dimension = "flavor" + isDefault = true + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlin { + jvmToolchain(17) + } +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.21.12" + } + generateProtoTasks { + all().forEach { task -> + task.builtins { + create("java") { + option("lite") + } + create("kotlin") { + option("lite") + } + } + } + } +} + +dependencies { + implementation(project(":core:settings")) + implementation(project(":core:model")) + implementation(libs.protobuf.kotlin.lite) + implementation(libs.androidx.datastore) + + // Testing + testImplementation(libs.junit) + testImplementation(libs.truth) + testImplementation(libs.kotlinx.coroutines.test) +} diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/Mappers.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/Mappers.kt new file mode 100644 index 000000000..47754f1fb --- /dev/null +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/Mappers.kt @@ -0,0 +1,236 @@ +/* + * 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.jetpackcamera.model.AspectRatio +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.model.LowLightBoostPriority +import com.google.jetpackcamera.model.StabilizationMode +import com.google.jetpackcamera.model.StreamConfig +import com.google.jetpackcamera.model.VideoQuality +import com.google.jetpackcamera.model.proto.AspectRatio as AspectRatioProto +import com.google.jetpackcamera.model.proto.DarkMode as DarkModeProto +import com.google.jetpackcamera.model.proto.DynamicRange as DynamicRangeProto +import com.google.jetpackcamera.model.proto.FlashMode as FlashModeProto +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.StreamConfig as StreamConfigProto +import com.google.jetpackcamera.model.proto.VideoQuality as VideoQualityProto +import com.google.jetpackcamera.settings.model.CameraAppSettings +import com.google.jetpackcamera.settings.proto.JcaSettings + +internal fun AspectRatioProto.toDomain(): AspectRatio { + return when (this) { + AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN -> AspectRatio.NINE_SIXTEEN + AspectRatioProto.ASPECT_RATIO_ONE_ONE -> AspectRatio.ONE_ONE + AspectRatioProto.ASPECT_RATIO_THREE_FOUR, + AspectRatioProto.ASPECT_RATIO_UNDEFINED, + AspectRatioProto.UNRECOGNIZED -> AspectRatio.THREE_FOUR + } +} + +internal fun AspectRatio.toProto(): AspectRatioProto { + return when (this) { + AspectRatio.NINE_SIXTEEN -> AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN + AspectRatio.ONE_ONE -> AspectRatioProto.ASPECT_RATIO_ONE_ONE + AspectRatio.THREE_FOUR -> AspectRatioProto.ASPECT_RATIO_THREE_FOUR + } +} + +internal fun DarkModeProto.toDomain(): DarkMode { + return when (this) { + DarkModeProto.DARK_MODE_DARK -> DarkMode.DARK + DarkModeProto.DARK_MODE_LIGHT -> DarkMode.LIGHT + DarkModeProto.DARK_MODE_SYSTEM, + DarkModeProto.UNRECOGNIZED -> DarkMode.SYSTEM + } +} + +internal fun DarkMode.toProto(): DarkModeProto { + return when (this) { + DarkMode.DARK -> DarkModeProto.DARK_MODE_DARK + DarkMode.LIGHT -> DarkModeProto.DARK_MODE_LIGHT + DarkMode.SYSTEM -> DarkModeProto.DARK_MODE_SYSTEM + } +} + +internal fun DynamicRangeProto.toDomain(): DynamicRange { + return when (this) { + DynamicRangeProto.DYNAMIC_RANGE_HLG10 -> DynamicRange.HLG10 + DynamicRangeProto.DYNAMIC_RANGE_SDR, + DynamicRangeProto.DYNAMIC_RANGE_UNSPECIFIED, + DynamicRangeProto.UNRECOGNIZED -> DynamicRange.SDR + } +} + +internal fun DynamicRange.toProto(): DynamicRangeProto { + return when (this) { + DynamicRange.HLG10 -> DynamicRangeProto.DYNAMIC_RANGE_HLG10 + DynamicRange.SDR -> DynamicRangeProto.DYNAMIC_RANGE_SDR + } +} + +internal fun FlashModeProto.toDomain(): FlashMode { + return when (this) { + FlashModeProto.FLASH_MODE_ON -> FlashMode.ON + FlashModeProto.FLASH_MODE_AUTO -> FlashMode.AUTO + FlashModeProto.FLASH_MODE_LOW_LIGHT_BOOST -> FlashMode.LOW_LIGHT_BOOST + FlashModeProto.FLASH_MODE_OFF, + FlashModeProto.UNRECOGNIZED -> FlashMode.OFF + } +} + +internal fun FlashMode.toProto(): FlashModeProto { + return when (this) { + FlashMode.ON -> FlashModeProto.FLASH_MODE_ON + FlashMode.AUTO -> FlashModeProto.FLASH_MODE_AUTO + FlashMode.LOW_LIGHT_BOOST -> FlashModeProto.FLASH_MODE_LOW_LIGHT_BOOST + FlashMode.OFF -> FlashModeProto.FLASH_MODE_OFF + } +} + +internal fun ImageOutputFormatProto.toDomain(): ImageOutputFormat { + return when (this) { + ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR -> + ImageOutputFormat.JPEG_ULTRA_HDR + ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG, + ImageOutputFormatProto.UNRECOGNIZED -> ImageOutputFormat.JPEG + } +} + +internal fun ImageOutputFormat.toProto(): ImageOutputFormatProto { + return when (this) { + ImageOutputFormat.JPEG_ULTRA_HDR -> + ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR + ImageOutputFormat.JPEG -> ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG + } +} + +internal fun LensFacingProto.toDomain(): LensFacing { + return when (this) { + LensFacingProto.LENS_FACING_FRONT -> LensFacing.FRONT + LensFacingProto.LENS_FACING_BACK, + LensFacingProto.UNRECOGNIZED -> LensFacing.BACK + } +} + +internal fun LensFacing.toProto(): LensFacingProto { + return when (this) { + LensFacing.FRONT -> LensFacingProto.LENS_FACING_FRONT + LensFacing.BACK -> LensFacingProto.LENS_FACING_BACK + } +} + +internal fun LowLightBoostPriorityProto.toDomain(): LowLightBoostPriority { + return when (this) { + LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES -> + LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES + LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_AE_MODE, + LowLightBoostPriorityProto.UNRECOGNIZED -> LowLightBoostPriority.PRIORITIZE_AE_MODE + } +} + +internal fun LowLightBoostPriority.toProto(): LowLightBoostPriorityProto { + return when (this) { + LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES -> + LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES + LowLightBoostPriority.PRIORITIZE_AE_MODE -> + LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_AE_MODE + } +} + +internal fun StabilizationModeProto.toDomain(): StabilizationMode { + return when (this) { + StabilizationModeProto.STABILIZATION_MODE_ON -> StabilizationMode.ON + StabilizationModeProto.STABILIZATION_MODE_OFF -> StabilizationMode.OFF + StabilizationModeProto.STABILIZATION_MODE_HIGH_QUALITY -> StabilizationMode.HIGH_QUALITY + StabilizationModeProto.STABILIZATION_MODE_OPTICAL -> StabilizationMode.OPTICAL + StabilizationModeProto.STABILIZATION_MODE_AUTO, + StabilizationModeProto.STABILIZATION_MODE_UNDEFINED, + StabilizationModeProto.UNRECOGNIZED -> StabilizationMode.AUTO + } +} + +internal fun StabilizationMode.toProto(): StabilizationModeProto { + return when (this) { + StabilizationMode.ON -> StabilizationModeProto.STABILIZATION_MODE_ON + StabilizationMode.OFF -> StabilizationModeProto.STABILIZATION_MODE_OFF + StabilizationMode.HIGH_QUALITY -> StabilizationModeProto.STABILIZATION_MODE_HIGH_QUALITY + StabilizationMode.OPTICAL -> StabilizationModeProto.STABILIZATION_MODE_OPTICAL + StabilizationMode.AUTO -> StabilizationModeProto.STABILIZATION_MODE_AUTO + } +} + +internal fun StreamConfigProto.toDomain(): StreamConfig { + return when (this) { + StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM -> StreamConfig.SINGLE_STREAM + StreamConfigProto.STREAM_CONFIG_MULTI_STREAM, + StreamConfigProto.STREAM_CONFIG_UNDEFINED, + StreamConfigProto.UNRECOGNIZED -> StreamConfig.MULTI_STREAM + } +} + +internal fun StreamConfig.toProto(): StreamConfigProto { + return when (this) { + StreamConfig.SINGLE_STREAM -> StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM + StreamConfig.MULTI_STREAM -> StreamConfigProto.STREAM_CONFIG_MULTI_STREAM + } +} + +internal fun VideoQualityProto.toDomain(): VideoQuality { + return when (this) { + 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 + } +} + +internal fun VideoQuality.toProto(): VideoQualityProto { + return when (this) { + VideoQuality.SD -> VideoQualityProto.VIDEO_QUALITY_SD + VideoQuality.HD -> VideoQualityProto.VIDEO_QUALITY_HD + VideoQuality.FHD -> VideoQualityProto.VIDEO_QUALITY_FHD + VideoQuality.UHD -> VideoQualityProto.VIDEO_QUALITY_UHD + VideoQuality.UNSPECIFIED -> VideoQualityProto.VIDEO_QUALITY_UNSPECIFIED + } +} + +internal fun JcaSettings.toDomain(): CameraAppSettings { + return CameraAppSettings( + cameraLensFacing = this.defaultLensFacing.toDomain(), + flashMode = this.flashModeStatus.toDomain(), + targetFrameRate = this.targetFrameRate, + aspectRatio = this.aspectRatioStatus.toDomain(), + streamConfig = this.streamConfigStatus.toDomain(), + stabilizationMode = this.stabilizationMode.toDomain(), + dynamicRange = this.dynamicRangeStatus.toDomain(), + imageFormat = this.imageFormatStatus.toDomain(), + maxVideoDurationMillis = this.maxVideoDurationMillis, + videoQuality = this.videoQuality.toDomain(), + audioEnabled = this.audioEnabledStatus, + lowLightBoostPriority = this.lowLightBoostPriority.toDomain(), + darkMode = this.darkModeStatus.toDomain() + ) +} diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt new file mode 100644 index 000000000..eb6de3c33 --- /dev/null +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt @@ -0,0 +1,183 @@ +/* + * 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 android.content.Context +import android.util.Log +import androidx.datastore.core.DataStore +import androidx.datastore.core.DataStoreFactory +import com.google.jetpackcamera.model.AspectRatio +import com.google.jetpackcamera.model.ConcurrentCameraMode +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.model.LowLightBoostPriority +import com.google.jetpackcamera.model.StabilizationMode +import com.google.jetpackcamera.model.StreamConfig +import com.google.jetpackcamera.model.VideoQuality +import com.google.jetpackcamera.settings.model.CameraAppSettings +import com.google.jetpackcamera.settings.proto.JcaSettings +import java.io.File +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map + +class ProtoDataStoreSettingsDataSource( + private val jcaSettings: DataStore +) : SettingsDataSource { + + private val jcaSettingsFlow: Flow = jcaSettings.data.catch { exception -> + if (exception is java.io.IOException) { + emit(JcaSettings.getDefaultInstance()) + } else { + throw exception + } + } + + override val defaultCameraAppSettings: Flow = jcaSettingsFlow.map { + it.toDomain() + } + + override suspend fun getCurrentDefaultCameraAppSettings(): CameraAppSettings = + jcaSettingsFlow.first().toDomain() + + override suspend fun updateDefaultLensFacing(lensFacing: LensFacing) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setDefaultLensFacing(lensFacing.toProto()) + .build() + } + } + + override suspend fun updateDarkModeStatus(darkMode: DarkMode) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setDarkModeStatus(darkMode.toProto()) + .build() + } + } + + override suspend fun updateFlashModeStatus(flashMode: FlashMode) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setFlashModeStatus(flashMode.toProto()) + .build() + } + } + + override suspend fun updateAspectRatio(aspectRatio: AspectRatio) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setAspectRatioStatus(aspectRatio.toProto()) + .build() + } + } + + override suspend fun updateStreamConfig(streamConfig: StreamConfig) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setStreamConfigStatus(streamConfig.toProto()) + .build() + } + } + + override suspend fun updateLowLightBoostPriority(lowLightBoostPriority: LowLightBoostPriority) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setLowLightBoostPriority(lowLightBoostPriority.toProto()) + .build() + } + } + + override suspend fun updateStabilizationMode(stabilizationMode: StabilizationMode) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setStabilizationMode(stabilizationMode.toProto()) + .build() + } + } + + override suspend fun updateDynamicRange(dynamicRange: DynamicRange) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setDynamicRangeStatus(dynamicRange.toProto()) + .build() + } + } + + override suspend fun updateTargetFrameRate(targetFrameRate: Int) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setTargetFrameRate(targetFrameRate) + .build() + } + } + + override suspend fun updateImageFormat(imageFormat: ImageOutputFormat) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setImageFormatStatus(imageFormat.toProto()) + .build() + } + } + + override suspend fun updateMaxVideoDuration(durationMillis: Long) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setMaxVideoDurationMillis(durationMillis) + .build() + } + } + + override suspend fun updateVideoQuality(videoQuality: VideoQuality) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setVideoQuality(videoQuality.toProto()) + .build() + } + } + + override suspend fun updateAudioEnabled(isAudioEnabled: Boolean) { + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setAudioEnabledStatus(isAudioEnabled) + .build() + } + } + + override suspend fun updateConcurrentCameraMode(concurrentCameraMode: ConcurrentCameraMode) { + // Not implemented because this field was introduced after the proto was removed. + // The DataStore should not be modified to include new fields, as it is only + // meant to keep backward compatibility with the old user data binary schemas. + Log.w(TAG, "Proto datastore does not support concurrent camera mode") + } + + companion object { + private const val TAG = "ProtoSettingsDS" + private const val FILE_LOCATION = "JcaSettings.pb" + + fun create(context: Context): SettingsDataSource { + val dataStore = DataStoreFactory.create( + serializer = ProtoJcaSettingsSerializer, + produceFile = { File(context.filesDir, "datastore/$FILE_LOCATION") } + ) + return ProtoDataStoreSettingsDataSource(dataStore) + } + } +} diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt new file mode 100644 index 000000000..dc941a9c7 --- /dev/null +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt @@ -0,0 +1,59 @@ +/* + * 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.google.jetpackcamera.settings + +import androidx.datastore.core.CorruptionException +import androidx.datastore.core.Serializer +import com.google.jetpackcamera.model.UNLIMITED_VIDEO_DURATION +import com.google.jetpackcamera.model.proto.AspectRatio +import com.google.jetpackcamera.model.proto.DarkMode +import com.google.jetpackcamera.model.proto.DynamicRange +import com.google.jetpackcamera.model.proto.FlashMode +import com.google.jetpackcamera.model.proto.ImageOutputFormat +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.proto.JcaSettings +import com.google.protobuf.InvalidProtocolBufferException +import java.io.InputStream +import java.io.OutputStream +object ProtoJcaSettingsSerializer : Serializer { + + override val defaultValue: JcaSettings = JcaSettings.newBuilder() + .setDarkModeStatus(DarkMode.DARK_MODE_DARK) + .setDefaultLensFacing(LensFacing.LENS_FACING_BACK) + .setFlashModeStatus(FlashMode.FLASH_MODE_OFF) + .setAspectRatioStatus(AspectRatio.ASPECT_RATIO_NINE_SIXTEEN) + .setStreamConfigStatus(StreamConfig.STREAM_CONFIG_MULTI_STREAM) + .setStabilizationMode(StabilizationMode.STABILIZATION_MODE_AUTO) + .setDynamicRangeStatus(DynamicRange.DYNAMIC_RANGE_UNSPECIFIED) + .setImageFormatStatus(ImageOutputFormat.IMAGE_OUTPUT_FORMAT_JPEG) + .setMaxVideoDurationMillis(UNLIMITED_VIDEO_DURATION) + .setVideoQuality(VideoQuality.VIDEO_QUALITY_UNSPECIFIED) + .setAudioEnabledStatus(true) + .build() + + override suspend fun readFrom(input: InputStream): JcaSettings { + try { + return JcaSettings.parseFrom(input) + } catch (exception: InvalidProtocolBufferException) { + throw CorruptionException("Cannot read proto.", exception) + } + } + + override suspend fun writeTo(t: JcaSettings, output: OutputStream) = t.writeTo(output) +} diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto new file mode 100644 index 000000000..da8011c35 --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto @@ -0,0 +1,27 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum AspectRatio { + ASPECT_RATIO_UNDEFINED = 0; + ASPECT_RATIO_THREE_FOUR = 1; + ASPECT_RATIO_NINE_SIXTEEN= 2; + ASPECT_RATIO_ONE_ONE = 3; +} \ No newline at end of file diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto new file mode 100644 index 000000000..4f50d2524 --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto @@ -0,0 +1,24 @@ +/* + * 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. + */ +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum ConcurrentCameraMode { + CONCURRENT_CAMERA_MODE_OFF = 0; + CONCURRENT_CAMERA_MODE_DUAL = 1; +} diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto new file mode 100644 index 000000000..8b38ef403 --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto @@ -0,0 +1,26 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum DarkMode { + DARK_MODE_SYSTEM = 0; + DARK_MODE_LIGHT= 1; + DARK_MODE_DARK = 2; +} \ No newline at end of file diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/debug_settings.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/debug_settings.proto new file mode 100644 index 000000000..2c3633afc --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/debug_settings.proto @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 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. + */ + +syntax = "proto3"; + +import "com/google/jetpackcamera/model/proto/lens_facing.proto"; +import "com/google/jetpackcamera/model/proto/test_pattern.proto"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +message DebugSettings { + bool is_debug_mode_enabled = 1; + optional LensFacing single_lens_mode = 2; + TestPattern test_pattern = 3; +} diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dynamic_range.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dynamic_range.proto new file mode 100644 index 000000000..6ebe80b97 --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dynamic_range.proto @@ -0,0 +1,26 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum DynamicRange { + DYNAMIC_RANGE_UNSPECIFIED = 0; + DYNAMIC_RANGE_SDR = 1; + DYNAMIC_RANGE_HLG10 = 2; +} \ No newline at end of file diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto new file mode 100644 index 000000000..fc87418e7 --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto @@ -0,0 +1,27 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum FlashMode{ + FLASH_MODE_AUTO = 0; + FLASH_MODE_ON = 1; + FLASH_MODE_OFF = 2; + FLASH_MODE_LOW_LIGHT_BOOST = 3; +} \ No newline at end of file diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto new file mode 100644 index 000000000..b64556b08 --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto @@ -0,0 +1,25 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum ImageOutputFormat { + IMAGE_OUTPUT_FORMAT_JPEG = 0; + IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR = 1; +} \ No newline at end of file diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto new file mode 100644 index 000000000..2e898a4eb --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto @@ -0,0 +1,25 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum LensFacing { + LENS_FACING_BACK = 0; + LENS_FACING_FRONT = 1; +} \ No newline at end of file diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto new file mode 100644 index 000000000..bd8fd7dbf --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2025 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum LowLightBoostPriority { + LOW_LIGHT_BOOST_PRIORITY_AE_MODE = 0; + LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES = 1; +} diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto new file mode 100644 index 000000000..bdba01437 --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto @@ -0,0 +1,29 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum StabilizationMode { + STABILIZATION_MODE_UNDEFINED = 0; + STABILIZATION_MODE_AUTO = 1; + STABILIZATION_MODE_OFF = 2; + STABILIZATION_MODE_ON = 3; + STABILIZATION_MODE_HIGH_QUALITY = 4; + STABILIZATION_MODE_OPTICAL = 5; +} \ No newline at end of file diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto new file mode 100644 index 000000000..28af05d60 --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto @@ -0,0 +1,26 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum StreamConfig { + STREAM_CONFIG_UNDEFINED = 0; + STREAM_CONFIG_MULTI_STREAM = 1; + STREAM_CONFIG_SINGLE_STREAM = 2; +} \ No newline at end of file diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/test_pattern.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/test_pattern.proto new file mode 100644 index 000000000..b74d3d96d --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/test_pattern.proto @@ -0,0 +1,55 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +// Represents the TestPattern sealed interface. +message TestPattern { + oneof pattern { + TestPatternOff off = 1; + TestPatternColorBars color_bars = 2; + TestPatternColorBarsFadeToGray color_bars_fade_to_gray = 3; + TestPatternPN9 pn9 = 4; + TestPatternCustom1 custom1 = 5; + TestPatternSolidColor solid_color = 6; + } +} + +// Corresponds to TestPattern.Off +message TestPatternOff {} + +// Corresponds to TestPattern.ColorBars +message TestPatternColorBars {} + +// Corresponds to TestPattern.ColorBarsFadeToGray +message TestPatternColorBarsFadeToGray {} + +// Corresponds to TestPattern.PN9 +message TestPatternPN9 {} + +// Corresponds to TestPattern.Custom1 +message TestPatternCustom1 {} + +// Corresponds to TestPattern.SolidColor +message TestPatternSolidColor { + uint32 red = 1; + uint32 green_even = 2; + uint32 green_odd = 3; + uint32 blue = 4; +} diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/video_quality.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/video_quality.proto new file mode 100644 index 000000000..b88b423cc --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/video_quality.proto @@ -0,0 +1,28 @@ +/* + * 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. + */ + +syntax = "proto3"; + +option java_package = "com.google.jetpackcamera.model.proto"; +option java_multiple_files = true; + +enum VideoQuality { + VIDEO_QUALITY_UNSPECIFIED = 0; + VIDEO_QUALITY_SD = 1; + VIDEO_QUALITY_HD = 2; + VIDEO_QUALITY_FHD = 3; + VIDEO_QUALITY_UHD = 4; +} \ No newline at end of file diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/settings/proto_jca_settings.proto b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/settings/proto_jca_settings.proto new file mode 100644 index 000000000..ee77dd5ee --- /dev/null +++ b/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/settings/proto_jca_settings.proto @@ -0,0 +1,51 @@ +/* + * 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. + */ + +syntax = "proto3"; + +import "com/google/jetpackcamera/model/proto/aspect_ratio.proto"; +import "com/google/jetpackcamera/model/proto/stream_config.proto"; +import "com/google/jetpackcamera/model/proto/dark_mode.proto"; +import "com/google/jetpackcamera/model/proto/dynamic_range.proto"; +import "com/google/jetpackcamera/model/proto/flash_mode.proto"; +import "com/google/jetpackcamera/model/proto/image_output_format.proto"; +import "com/google/jetpackcamera/model/proto/lens_facing.proto"; +import "com/google/jetpackcamera/model/proto/stabilization_mode.proto"; +import "com/google/jetpackcamera/model/proto/video_quality.proto"; +import "com/google/jetpackcamera/model/proto/low_light_boost_priority.proto"; + + +option java_package = "com.google.jetpackcamera.settings.proto"; +option java_multiple_files = true; + +message JcaSettings { + // Camera settings + LensFacing default_lens_facing = 1; + FlashMode flash_mode_status = 2; + int32 target_frame_rate = 3; + AspectRatio aspect_ratio_status = 4; + StreamConfig stream_config_status = 5; + StabilizationMode stabilization_mode = 6; + DynamicRange dynamic_range_status = 8; + ImageOutputFormat image_format_status = 10; + uint64 max_video_duration_millis = 11; + VideoQuality video_quality = 12; + bool audio_enabled_status = 13; + LowLightBoostPriority low_light_boost_priority = 14; + + // Non-camera app settings + DarkMode dark_mode_status = 9; +} diff --git a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/MappersTest.kt b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/MappersTest.kt new file mode 100644 index 000000000..8a76a922e --- /dev/null +++ b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/MappersTest.kt @@ -0,0 +1,244 @@ +/* + * 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.AspectRatio +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.model.LowLightBoostPriority +import com.google.jetpackcamera.model.StabilizationMode +import com.google.jetpackcamera.model.StreamConfig +import com.google.jetpackcamera.model.VideoQuality +import com.google.jetpackcamera.model.proto.AspectRatio as AspectRatioProto +import com.google.jetpackcamera.model.proto.DarkMode as DarkModeProto +import com.google.jetpackcamera.model.proto.DynamicRange as DynamicRangeProto +import com.google.jetpackcamera.model.proto.FlashMode as FlashModeProto +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.StreamConfig as StreamConfigProto +import com.google.jetpackcamera.model.proto.VideoQuality as VideoQualityProto +import org.junit.Test + +class MappersTest { + + @Test + fun aspectRatioMapsCorrectly() { + assertThat( + AspectRatio.NINE_SIXTEEN.toProto() + ).isEqualTo(AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN) + assertThat( + AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN.toDomain() + ).isEqualTo(AspectRatio.NINE_SIXTEEN) + + assertThat(AspectRatio.ONE_ONE.toProto()).isEqualTo(AspectRatioProto.ASPECT_RATIO_ONE_ONE) + assertThat(AspectRatioProto.ASPECT_RATIO_ONE_ONE.toDomain()).isEqualTo(AspectRatio.ONE_ONE) + + assertThat( + AspectRatio.THREE_FOUR.toProto() + ).isEqualTo(AspectRatioProto.ASPECT_RATIO_THREE_FOUR) + assertThat( + AspectRatioProto.ASPECT_RATIO_THREE_FOUR.toDomain() + ).isEqualTo(AspectRatio.THREE_FOUR) + + assertThat(AspectRatioProto.UNRECOGNIZED.toDomain()).isEqualTo(AspectRatio.THREE_FOUR) + } + + @Test + fun darkModeMapsCorrectly() { + assertThat(DarkMode.DARK.toProto()).isEqualTo(DarkModeProto.DARK_MODE_DARK) + assertThat(DarkModeProto.DARK_MODE_DARK.toDomain()).isEqualTo(DarkMode.DARK) + + assertThat(DarkMode.LIGHT.toProto()).isEqualTo(DarkModeProto.DARK_MODE_LIGHT) + assertThat(DarkModeProto.DARK_MODE_LIGHT.toDomain()).isEqualTo(DarkMode.LIGHT) + + assertThat(DarkMode.SYSTEM.toProto()).isEqualTo(DarkModeProto.DARK_MODE_SYSTEM) + assertThat(DarkModeProto.DARK_MODE_SYSTEM.toDomain()).isEqualTo(DarkMode.SYSTEM) + + assertThat(DarkModeProto.UNRECOGNIZED.toDomain()).isEqualTo(DarkMode.SYSTEM) + } + + @Test + fun dynamicRangeMapsCorrectly() { + assertThat(DynamicRange.HLG10.toProto()).isEqualTo(DynamicRangeProto.DYNAMIC_RANGE_HLG10) + assertThat(DynamicRangeProto.DYNAMIC_RANGE_HLG10.toDomain()).isEqualTo(DynamicRange.HLG10) + + assertThat(DynamicRange.SDR.toProto()).isEqualTo(DynamicRangeProto.DYNAMIC_RANGE_SDR) + assertThat(DynamicRangeProto.DYNAMIC_RANGE_SDR.toDomain()).isEqualTo(DynamicRange.SDR) + + assertThat(DynamicRangeProto.UNRECOGNIZED.toDomain()).isEqualTo(DynamicRange.SDR) + } + + @Test + fun flashModeMapsCorrectly() { + assertThat(FlashMode.ON.toProto()).isEqualTo(FlashModeProto.FLASH_MODE_ON) + assertThat(FlashModeProto.FLASH_MODE_ON.toDomain()).isEqualTo(FlashMode.ON) + + assertThat(FlashMode.AUTO.toProto()).isEqualTo(FlashModeProto.FLASH_MODE_AUTO) + assertThat(FlashModeProto.FLASH_MODE_AUTO.toDomain()).isEqualTo(FlashMode.AUTO) + + assertThat(FlashMode.OFF.toProto()).isEqualTo(FlashModeProto.FLASH_MODE_OFF) + assertThat(FlashModeProto.FLASH_MODE_OFF.toDomain()).isEqualTo(FlashMode.OFF) + + assertThat( + FlashMode.LOW_LIGHT_BOOST.toProto() + ).isEqualTo(FlashModeProto.FLASH_MODE_LOW_LIGHT_BOOST) + assertThat( + FlashModeProto.FLASH_MODE_LOW_LIGHT_BOOST.toDomain() + ).isEqualTo(FlashMode.LOW_LIGHT_BOOST) + + assertThat(FlashModeProto.UNRECOGNIZED.toDomain()).isEqualTo(FlashMode.OFF) + } + + @Test + fun imageOutputFormatMapsCorrectly() { + assertThat( + ImageOutputFormat.JPEG.toProto() + ).isEqualTo(ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG) + assertThat( + ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG.toDomain() + ).isEqualTo(ImageOutputFormat.JPEG) + + assertThat( + ImageOutputFormat.JPEG_ULTRA_HDR.toProto() + ).isEqualTo(ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR) + assertThat( + ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR.toDomain() + ).isEqualTo(ImageOutputFormat.JPEG_ULTRA_HDR) + + assertThat(ImageOutputFormatProto.UNRECOGNIZED.toDomain()).isEqualTo(ImageOutputFormat.JPEG) + } + + @Test + fun lensFacingMapsCorrectly() { + assertThat(LensFacing.FRONT.toProto()).isEqualTo(LensFacingProto.LENS_FACING_FRONT) + assertThat(LensFacingProto.LENS_FACING_FRONT.toDomain()).isEqualTo(LensFacing.FRONT) + + assertThat(LensFacing.BACK.toProto()).isEqualTo(LensFacingProto.LENS_FACING_BACK) + assertThat(LensFacingProto.LENS_FACING_BACK.toDomain()).isEqualTo(LensFacing.BACK) + + assertThat(LensFacingProto.UNRECOGNIZED.toDomain()).isEqualTo(LensFacing.BACK) + } + + @Test + fun lowLightBoostPriorityMapsCorrectly() { + assertThat( + LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES.toProto() + ).isEqualTo(LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES) + assertThat( + LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES.toDomain() + ).isEqualTo(LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES) + + assertThat( + LowLightBoostPriority.PRIORITIZE_AE_MODE.toProto() + ).isEqualTo(LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_AE_MODE) + assertThat( + LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_AE_MODE.toDomain() + ).isEqualTo(LowLightBoostPriority.PRIORITIZE_AE_MODE) + + assertThat( + LowLightBoostPriorityProto.UNRECOGNIZED.toDomain() + ).isEqualTo(LowLightBoostPriority.PRIORITIZE_AE_MODE) + } + + @Test + fun stabilizationModeMapsCorrectly() { + assertThat( + StabilizationMode.ON.toProto() + ).isEqualTo(StabilizationModeProto.STABILIZATION_MODE_ON) + assertThat( + StabilizationModeProto.STABILIZATION_MODE_ON.toDomain() + ).isEqualTo(StabilizationMode.ON) + + assertThat( + StabilizationMode.OFF.toProto() + ).isEqualTo(StabilizationModeProto.STABILIZATION_MODE_OFF) + assertThat( + StabilizationModeProto.STABILIZATION_MODE_OFF.toDomain() + ).isEqualTo(StabilizationMode.OFF) + + assertThat( + StabilizationMode.HIGH_QUALITY.toProto() + ).isEqualTo(StabilizationModeProto.STABILIZATION_MODE_HIGH_QUALITY) + assertThat( + StabilizationModeProto.STABILIZATION_MODE_HIGH_QUALITY.toDomain() + ).isEqualTo(StabilizationMode.HIGH_QUALITY) + + assertThat( + StabilizationMode.OPTICAL.toProto() + ).isEqualTo(StabilizationModeProto.STABILIZATION_MODE_OPTICAL) + assertThat( + StabilizationModeProto.STABILIZATION_MODE_OPTICAL.toDomain() + ).isEqualTo(StabilizationMode.OPTICAL) + + assertThat( + StabilizationMode.AUTO.toProto() + ).isEqualTo(StabilizationModeProto.STABILIZATION_MODE_AUTO) + assertThat( + StabilizationModeProto.STABILIZATION_MODE_AUTO.toDomain() + ).isEqualTo(StabilizationMode.AUTO) + + assertThat(StabilizationModeProto.UNRECOGNIZED.toDomain()).isEqualTo(StabilizationMode.AUTO) + } + + @Test + fun streamConfigMapsCorrectly() { + assertThat( + StreamConfig.SINGLE_STREAM.toProto() + ).isEqualTo(StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM) + assertThat( + StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM.toDomain() + ).isEqualTo(StreamConfig.SINGLE_STREAM) + + assertThat( + StreamConfig.MULTI_STREAM.toProto() + ).isEqualTo(StreamConfigProto.STREAM_CONFIG_MULTI_STREAM) + assertThat( + StreamConfigProto.STREAM_CONFIG_MULTI_STREAM.toDomain() + ).isEqualTo(StreamConfig.MULTI_STREAM) + + assertThat(StreamConfigProto.UNRECOGNIZED.toDomain()).isEqualTo(StreamConfig.MULTI_STREAM) + } + + @Test + fun videoQualityMapsCorrectly() { + assertThat(VideoQuality.SD.toProto()).isEqualTo(VideoQualityProto.VIDEO_QUALITY_SD) + assertThat(VideoQualityProto.VIDEO_QUALITY_SD.toDomain()).isEqualTo(VideoQuality.SD) + + assertThat(VideoQuality.HD.toProto()).isEqualTo(VideoQualityProto.VIDEO_QUALITY_HD) + assertThat(VideoQualityProto.VIDEO_QUALITY_HD.toDomain()).isEqualTo(VideoQuality.HD) + + assertThat(VideoQuality.FHD.toProto()).isEqualTo(VideoQualityProto.VIDEO_QUALITY_FHD) + assertThat(VideoQualityProto.VIDEO_QUALITY_FHD.toDomain()).isEqualTo(VideoQuality.FHD) + + assertThat(VideoQuality.UHD.toProto()).isEqualTo(VideoQualityProto.VIDEO_QUALITY_UHD) + assertThat(VideoQualityProto.VIDEO_QUALITY_UHD.toDomain()).isEqualTo(VideoQuality.UHD) + + assertThat( + VideoQuality.UNSPECIFIED.toProto() + ).isEqualTo(VideoQualityProto.VIDEO_QUALITY_UNSPECIFIED) + assertThat( + VideoQualityProto.VIDEO_QUALITY_UNSPECIFIED.toDomain() + ).isEqualTo(VideoQuality.UNSPECIFIED) + + assertThat(VideoQualityProto.UNRECOGNIZED.toDomain()).isEqualTo(VideoQuality.UNSPECIFIED) + } +} diff --git a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt new file mode 100644 index 000000000..fc0499dcf --- /dev/null +++ b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt @@ -0,0 +1,231 @@ +/* + * 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 androidx.datastore.core.DataStore +import androidx.datastore.core.DataStoreFactory +import com.google.common.truth.Truth.assertThat +import com.google.jetpackcamera.model.AspectRatio +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.model.LowLightBoostPriority +import com.google.jetpackcamera.model.StabilizationMode +import com.google.jetpackcamera.model.StreamConfig +import com.google.jetpackcamera.model.VideoQuality +import com.google.jetpackcamera.settings.model.CameraAppSettings +import com.google.jetpackcamera.settings.model.DEFAULT_CAMERA_APP_SETTINGS +import com.google.jetpackcamera.settings.proto.JcaSettings +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder + +@OptIn(ExperimentalCoroutinesApi::class) +class ProtoDataStoreSettingsDataSourceTest { + + @get:Rule + val tempFolder = TemporaryFolder() + + private lateinit var testDataStore: DataStore + private lateinit var datastoreScope: CoroutineScope + private lateinit var repository: ProtoDataStoreSettingsDataSource + + @Before + fun setup() { + Dispatchers.setMain(StandardTestDispatcher()) + datastoreScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) + + testDataStore = DataStoreFactory.create( + serializer = ProtoJcaSettingsSerializer, + scope = datastoreScope + ) { + java.io.File(tempFolder.root, "test_jca_settings.pb") + } + repository = ProtoDataStoreSettingsDataSource(jcaSettings = testDataStore) + } + + @After + fun tearDown() { + datastoreScope.cancel() + } + + @Test + fun repository_can_fetch_initial_datastore() = runTest { + val cameraAppSettings: CameraAppSettings = repository.getCurrentDefaultCameraAppSettings() + + advanceUntilIdle() + assertThat(cameraAppSettings).isEqualTo(DEFAULT_CAMERA_APP_SETTINGS) + } + + @Test + fun can_update_dark_mode() = runTest { + val initialDarkModeStatus = repository.getCurrentDefaultCameraAppSettings().darkMode + repository.updateDarkModeStatus(DarkMode.LIGHT) + val newDarkModeStatus = repository.getCurrentDefaultCameraAppSettings().darkMode + + advanceUntilIdle() + assertThat(initialDarkModeStatus).isEqualTo(DarkMode.DARK) + assertThat(newDarkModeStatus).isEqualTo(DarkMode.LIGHT) + } + + @Test + fun can_update_default_to_front_camera() = runTest { + val initialDefaultLensFacing = + repository.getCurrentDefaultCameraAppSettings().cameraLensFacing + repository.updateDefaultLensFacing(LensFacing.FRONT) + val newDefaultLensFacing = repository.getCurrentDefaultCameraAppSettings().cameraLensFacing + advanceUntilIdle() + + assertThat(initialDefaultLensFacing).isEqualTo(LensFacing.BACK) + assertThat(newDefaultLensFacing).isEqualTo(LensFacing.FRONT) + } + + @Test + fun can_update_flash_mode() = runTest { + val initialFlashModeStatus = repository.getCurrentDefaultCameraAppSettings().flashMode + repository.updateFlashModeStatus(FlashMode.ON) + val newFlashModeStatus = repository.getCurrentDefaultCameraAppSettings().flashMode + advanceUntilIdle() + + assertThat(initialFlashModeStatus).isEqualTo(FlashMode.OFF) + assertThat(newFlashModeStatus).isEqualTo(FlashMode.ON) + } + + @Test + fun can_update_dynamic_range() = runTest { + val initialDynamicRange = repository.getCurrentDefaultCameraAppSettings().dynamicRange + repository.updateDynamicRange(dynamicRange = DynamicRange.HLG10) + advanceUntilIdle() + val newDynamicRange = repository.getCurrentDefaultCameraAppSettings().dynamicRange + + assertThat(initialDynamicRange).isEqualTo(DynamicRange.SDR) + assertThat(newDynamicRange).isEqualTo(DynamicRange.HLG10) + } + + @Test + fun can_update_image_format() = runTest { + val initialImageFormat = repository.getCurrentDefaultCameraAppSettings().imageFormat + repository.updateImageFormat(imageFormat = ImageOutputFormat.JPEG_ULTRA_HDR) + advanceUntilIdle() + val newImageFormat = repository.getCurrentDefaultCameraAppSettings().imageFormat + + assertThat(initialImageFormat).isEqualTo(ImageOutputFormat.JPEG) + assertThat(newImageFormat).isEqualTo(ImageOutputFormat.JPEG_ULTRA_HDR) + } + + @Test + fun can_update_aspect_ratio() = runTest { + val initial = repository.getCurrentDefaultCameraAppSettings().aspectRatio + repository.updateAspectRatio(AspectRatio.ONE_ONE) + advanceUntilIdle() + val new = repository.getCurrentDefaultCameraAppSettings().aspectRatio + + assertThat(initial).isEqualTo(AspectRatio.NINE_SIXTEEN) + assertThat(new).isEqualTo(AspectRatio.ONE_ONE) + } + + @Test + fun can_update_stream_config() = runTest { + val initial = repository.getCurrentDefaultCameraAppSettings().streamConfig + repository.updateStreamConfig(StreamConfig.SINGLE_STREAM) + advanceUntilIdle() + val new = repository.getCurrentDefaultCameraAppSettings().streamConfig + + assertThat(initial).isEqualTo(StreamConfig.MULTI_STREAM) + assertThat(new).isEqualTo(StreamConfig.SINGLE_STREAM) + } + + @Test + fun can_update_low_light_boost_priority() = runTest { + val initial = repository.getCurrentDefaultCameraAppSettings().lowLightBoostPriority + repository.updateLowLightBoostPriority( + LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES + ) + advanceUntilIdle() + val new = repository.getCurrentDefaultCameraAppSettings().lowLightBoostPriority + + assertThat(initial).isEqualTo(LowLightBoostPriority.PRIORITIZE_AE_MODE) + assertThat(new).isEqualTo(LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES) + } + + @Test + fun can_update_stabilization_mode() = runTest { + val initial = repository.getCurrentDefaultCameraAppSettings().stabilizationMode + repository.updateStabilizationMode(StabilizationMode.ON) + advanceUntilIdle() + val new = repository.getCurrentDefaultCameraAppSettings().stabilizationMode + + assertThat(initial).isEqualTo(StabilizationMode.AUTO) + assertThat(new).isEqualTo(StabilizationMode.ON) + } + + @Test + fun can_update_target_frame_rate() = runTest { + val initial = repository.getCurrentDefaultCameraAppSettings().targetFrameRate + repository.updateTargetFrameRate(60) + advanceUntilIdle() + val new = repository.getCurrentDefaultCameraAppSettings().targetFrameRate + + assertThat(initial).isEqualTo(DEFAULT_CAMERA_APP_SETTINGS.targetFrameRate) + assertThat(new).isEqualTo(60) + } + + @Test + fun can_update_max_video_duration() = runTest { + val initial = repository.getCurrentDefaultCameraAppSettings().maxVideoDurationMillis + repository.updateMaxVideoDuration(10000L) + advanceUntilIdle() + val new = repository.getCurrentDefaultCameraAppSettings().maxVideoDurationMillis + + assertThat(initial).isEqualTo(0L) // UNLIMITED_VIDEO_DURATION is 0L + assertThat(new).isEqualTo(10000L) + } + + @Test + fun can_update_video_quality() = runTest { + val initial = repository.getCurrentDefaultCameraAppSettings().videoQuality + repository.updateVideoQuality(VideoQuality.FHD) + advanceUntilIdle() + val new = repository.getCurrentDefaultCameraAppSettings().videoQuality + + assertThat(initial).isEqualTo(VideoQuality.UNSPECIFIED) + assertThat(new).isEqualTo(VideoQuality.FHD) + } + + @Test + fun can_update_audio_enabled() = runTest { + val initial = repository.getCurrentDefaultCameraAppSettings().audioEnabled + repository.updateAudioEnabled(false) + advanceUntilIdle() + val new = repository.getCurrentDefaultCameraAppSettings().audioEnabled + + assertThat(initial).isTrue() + assertThat(new).isFalse() + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a9e1c72fb..eeceb82e4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ accompanist = "0.37.3" # See https://developer.android.com/jetpack/androidx/releases/compose-kotlin kotlinPlugin = "2.2.0" androidGradlePlugin = "8.10.1" - +protobufPlugin = "0.9.5" androidxActivityCompose = "1.10.1" androidxAppCompat = "1.7.1" @@ -25,7 +25,6 @@ androidxCamera = "1.5.0-SNAPSHOT" androidxConcurrentFutures = "1.3.0" androidxCoreKtx = "1.16.0" androidxDatastore = "1.1.7" - androidxGraphicsCore = "1.0.3" androidxHiltNavigationCompose = "1.2.0" androidxLifecycle = "2.9.2" @@ -45,7 +44,7 @@ kotlinxAtomicfu = "0.29.0" kotlinxCoroutines = "1.10.2" hilt = "2.57" junit = "4.13.2" - +protobuf = "4.31.1" robolectric = "4.15.1" truth = "1.4.4" testParameterInjector = "1.21" @@ -64,7 +63,7 @@ androidx-annotation = { module = "androidx.annotation:annotation", version.ref = androidx-benchmark-macro-junit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "androidxBenchmark" } androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCoreKtx" } androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "androidxDatastore" } - +androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "androidxDatastore" } androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidxTestEspresso" } androidx-graphics-core = { module = "androidx.graphics:graphics-core", version.ref = "androidxGraphicsCore" } androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidxTestJunit" } @@ -106,7 +105,7 @@ kotlinx-coroutines-play-services = { module = "org.jetbrains.kotlinx:kotlinx-cor play-services-camera-low-light-boost = { module = "com.google.android.gms:play-services-camera-low-light-boost", version.ref = "cameraLowLightBoost" } play-services-tasks = { module = "com.google.android.gms:play-services-tasks", version.ref = "playServicesTasks" } testParameterInjector = { group = "com.google.testparameterinjector", name = "test-parameter-injector", version.ref = "testParameterInjector" } - +protobuf-kotlin-lite = { module = "com.google.protobuf:protobuf-kotlin-lite", version.ref = "protobuf" } androidx-test-core = { module = "androidx.test:core", version.ref = "androidxTestCore" } robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" } @@ -120,6 +119,6 @@ android-library = { id = "com.android.library", version.ref = "androidGradlePlug android-test = { id = "com.android.test", version.ref = "androidGradlePlugin" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlinPlugin" } dagger-hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } - +protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinPlugin" } kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlinPlugin" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 103a86882..e9ad4cedf 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -69,3 +69,4 @@ include(":core:settings:datastore-prefs") include(":core:settings:datastore-prefs:testing") include(":ui:debug") include(":ui:debug:testing") +include(":core:settings:datastore-proto") From 2b213503498574b3fda41c16b938d2a2ff9ddeff Mon Sep 17 00:00:00 2001 From: Trevor McGuire Date: Mon, 29 Jun 2026 20:24:26 +0000 Subject: [PATCH 02/14] chore: split proto generation into standalone modules --- core/model-proto/build.gradle.kts | 76 ++++++++++++++++++ .../model/proto/ModelMappers.kt} | 62 +++++---------- .../model/proto/aspect_ratio.proto | 0 .../model/proto/concurrent_camera_mode.proto | 0 .../jetpackcamera/model/proto/dark_mode.proto | 0 .../model/proto/debug_settings.proto | 0 .../model/proto/dynamic_range.proto | 0 .../model/proto/flash_mode.proto | 0 .../model/proto/image_output_format.proto | 0 .../model/proto/lens_facing.proto | 0 .../proto/low_light_boost_priority.proto | 0 .../model/proto/stabilization_mode.proto | 0 .../model/proto/stream_config.proto | 0 .../model/proto/test_pattern.proto | 0 .../model/proto/video_quality.proto | 0 .../model/proto/ModelMappersTest.kt} | 4 +- .../settings/datastore-proto/build.gradle.kts | 22 +----- .../ProtoDataStoreSettingsDataSource.kt | 9 ++- .../settings/ProtoJcaSettingsSerializer.kt | 12 +-- .../ProtoDataStoreSettingsDataSourceTest.kt | 4 +- core/settings/settings-proto/build.gradle.kts | 77 +++++++++++++++++++ .../jetpackcamera/settings/SettingsMappers.kt | 38 +++++++++ .../settings/camera_app_settings.proto} | 2 +- settings.gradle.kts | 2 + 24 files changed, 231 insertions(+), 77 deletions(-) create mode 100644 core/model-proto/build.gradle.kts rename core/{settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/Mappers.kt => model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt} (78%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/debug_settings.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/dynamic_range.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/test_pattern.proto (100%) rename core/{settings/datastore-proto => model-proto}/src/main/proto/com/google/jetpackcamera/model/proto/video_quality.proto (100%) rename core/{settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/MappersTest.kt => model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt} (99%) create mode 100644 core/settings/settings-proto/build.gradle.kts create mode 100644 core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt rename core/settings/{datastore-proto/src/main/proto/com/google/jetpackcamera/settings/proto_jca_settings.proto => settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto} (98%) diff --git a/core/model-proto/build.gradle.kts b/core/model-proto/build.gradle.kts new file mode 100644 index 000000000..c3a0d3289 --- /dev/null +++ b/core/model-proto/build.gradle.kts @@ -0,0 +1,76 @@ +/* + * 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.protobuf) +} + +android { + namespace = "com.google.jetpackcamera.model.proto" + 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" + } + + flavorDimensions += "flavor" + productFlavors { + create("stable") { + dimension = "flavor" + isDefault = true + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlin { + jvmToolchain(17) + } +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.21.12" + } + generateProtoTasks { + all().forEach { task -> + task.builtins { + create("java") { + option("lite") + } + create("kotlin") { + option("lite") + } + } + } + } +} + +dependencies { + api(project(":core:model")) + api(libs.protobuf.kotlin.lite) + + // Testing + testImplementation(libs.junit) + testImplementation(libs.truth) + testImplementation(libs.kotlinx.coroutines.test) +} diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/Mappers.kt b/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt similarity index 78% rename from core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/Mappers.kt rename to core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt index 47754f1fb..c70c53fca 100644 --- a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/Mappers.kt +++ b/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.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.model.proto import com.google.jetpackcamera.model.AspectRatio import com.google.jetpackcamera.model.DarkMode @@ -35,10 +35,8 @@ import com.google.jetpackcamera.model.proto.LowLightBoostPriority as LowLightBoo import com.google.jetpackcamera.model.proto.StabilizationMode as StabilizationModeProto import com.google.jetpackcamera.model.proto.StreamConfig as StreamConfigProto import com.google.jetpackcamera.model.proto.VideoQuality as VideoQualityProto -import com.google.jetpackcamera.settings.model.CameraAppSettings -import com.google.jetpackcamera.settings.proto.JcaSettings -internal fun AspectRatioProto.toDomain(): AspectRatio { +fun AspectRatioProto.toDomain(): AspectRatio { return when (this) { AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN -> AspectRatio.NINE_SIXTEEN AspectRatioProto.ASPECT_RATIO_ONE_ONE -> AspectRatio.ONE_ONE @@ -48,7 +46,7 @@ internal fun AspectRatioProto.toDomain(): AspectRatio { } } -internal fun AspectRatio.toProto(): AspectRatioProto { +fun AspectRatio.toProto(): AspectRatioProto { return when (this) { AspectRatio.NINE_SIXTEEN -> AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN AspectRatio.ONE_ONE -> AspectRatioProto.ASPECT_RATIO_ONE_ONE @@ -56,7 +54,7 @@ internal fun AspectRatio.toProto(): AspectRatioProto { } } -internal fun DarkModeProto.toDomain(): DarkMode { +fun DarkModeProto.toDomain(): DarkMode { return when (this) { DarkModeProto.DARK_MODE_DARK -> DarkMode.DARK DarkModeProto.DARK_MODE_LIGHT -> DarkMode.LIGHT @@ -65,7 +63,7 @@ internal fun DarkModeProto.toDomain(): DarkMode { } } -internal fun DarkMode.toProto(): DarkModeProto { +fun DarkMode.toProto(): DarkModeProto { return when (this) { DarkMode.DARK -> DarkModeProto.DARK_MODE_DARK DarkMode.LIGHT -> DarkModeProto.DARK_MODE_LIGHT @@ -73,7 +71,7 @@ internal fun DarkMode.toProto(): DarkModeProto { } } -internal fun DynamicRangeProto.toDomain(): DynamicRange { +fun DynamicRangeProto.toDomain(): DynamicRange { return when (this) { DynamicRangeProto.DYNAMIC_RANGE_HLG10 -> DynamicRange.HLG10 DynamicRangeProto.DYNAMIC_RANGE_SDR, @@ -82,14 +80,14 @@ internal fun DynamicRangeProto.toDomain(): DynamicRange { } } -internal fun DynamicRange.toProto(): DynamicRangeProto { +fun DynamicRange.toProto(): DynamicRangeProto { return when (this) { DynamicRange.HLG10 -> DynamicRangeProto.DYNAMIC_RANGE_HLG10 DynamicRange.SDR -> DynamicRangeProto.DYNAMIC_RANGE_SDR } } -internal fun FlashModeProto.toDomain(): FlashMode { +fun FlashModeProto.toDomain(): FlashMode { return when (this) { FlashModeProto.FLASH_MODE_ON -> FlashMode.ON FlashModeProto.FLASH_MODE_AUTO -> FlashMode.AUTO @@ -99,7 +97,7 @@ internal fun FlashModeProto.toDomain(): FlashMode { } } -internal fun FlashMode.toProto(): FlashModeProto { +fun FlashMode.toProto(): FlashModeProto { return when (this) { FlashMode.ON -> FlashModeProto.FLASH_MODE_ON FlashMode.AUTO -> FlashModeProto.FLASH_MODE_AUTO @@ -108,7 +106,7 @@ internal fun FlashMode.toProto(): FlashModeProto { } } -internal fun ImageOutputFormatProto.toDomain(): ImageOutputFormat { +fun ImageOutputFormatProto.toDomain(): ImageOutputFormat { return when (this) { ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR -> ImageOutputFormat.JPEG_ULTRA_HDR @@ -117,7 +115,7 @@ internal fun ImageOutputFormatProto.toDomain(): ImageOutputFormat { } } -internal fun ImageOutputFormat.toProto(): ImageOutputFormatProto { +fun ImageOutputFormat.toProto(): ImageOutputFormatProto { return when (this) { ImageOutputFormat.JPEG_ULTRA_HDR -> ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR @@ -125,7 +123,7 @@ internal fun ImageOutputFormat.toProto(): ImageOutputFormatProto { } } -internal fun LensFacingProto.toDomain(): LensFacing { +fun LensFacingProto.toDomain(): LensFacing { return when (this) { LensFacingProto.LENS_FACING_FRONT -> LensFacing.FRONT LensFacingProto.LENS_FACING_BACK, @@ -133,14 +131,14 @@ internal fun LensFacingProto.toDomain(): LensFacing { } } -internal fun LensFacing.toProto(): LensFacingProto { +fun LensFacing.toProto(): LensFacingProto { return when (this) { LensFacing.FRONT -> LensFacingProto.LENS_FACING_FRONT LensFacing.BACK -> LensFacingProto.LENS_FACING_BACK } } -internal fun LowLightBoostPriorityProto.toDomain(): LowLightBoostPriority { +fun LowLightBoostPriorityProto.toDomain(): LowLightBoostPriority { return when (this) { LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES -> LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES @@ -149,7 +147,7 @@ internal fun LowLightBoostPriorityProto.toDomain(): LowLightBoostPriority { } } -internal fun LowLightBoostPriority.toProto(): LowLightBoostPriorityProto { +fun LowLightBoostPriority.toProto(): LowLightBoostPriorityProto { return when (this) { LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES -> LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES @@ -158,7 +156,7 @@ internal fun LowLightBoostPriority.toProto(): LowLightBoostPriorityProto { } } -internal fun StabilizationModeProto.toDomain(): StabilizationMode { +fun StabilizationModeProto.toDomain(): StabilizationMode { return when (this) { StabilizationModeProto.STABILIZATION_MODE_ON -> StabilizationMode.ON StabilizationModeProto.STABILIZATION_MODE_OFF -> StabilizationMode.OFF @@ -170,7 +168,7 @@ internal fun StabilizationModeProto.toDomain(): StabilizationMode { } } -internal fun StabilizationMode.toProto(): StabilizationModeProto { +fun StabilizationMode.toProto(): StabilizationModeProto { return when (this) { StabilizationMode.ON -> StabilizationModeProto.STABILIZATION_MODE_ON StabilizationMode.OFF -> StabilizationModeProto.STABILIZATION_MODE_OFF @@ -180,7 +178,7 @@ internal fun StabilizationMode.toProto(): StabilizationModeProto { } } -internal fun StreamConfigProto.toDomain(): StreamConfig { +fun StreamConfigProto.toDomain(): StreamConfig { return when (this) { StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM -> StreamConfig.SINGLE_STREAM StreamConfigProto.STREAM_CONFIG_MULTI_STREAM, @@ -189,14 +187,14 @@ internal fun StreamConfigProto.toDomain(): StreamConfig { } } -internal fun StreamConfig.toProto(): StreamConfigProto { +fun StreamConfig.toProto(): StreamConfigProto { return when (this) { StreamConfig.SINGLE_STREAM -> StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM StreamConfig.MULTI_STREAM -> StreamConfigProto.STREAM_CONFIG_MULTI_STREAM } } -internal fun VideoQualityProto.toDomain(): VideoQuality { +fun VideoQualityProto.toDomain(): VideoQuality { return when (this) { VideoQualityProto.VIDEO_QUALITY_SD -> VideoQuality.SD VideoQualityProto.VIDEO_QUALITY_HD -> VideoQuality.HD @@ -207,7 +205,7 @@ internal fun VideoQualityProto.toDomain(): VideoQuality { } } -internal fun VideoQuality.toProto(): VideoQualityProto { +fun VideoQuality.toProto(): VideoQualityProto { return when (this) { VideoQuality.SD -> VideoQualityProto.VIDEO_QUALITY_SD VideoQuality.HD -> VideoQualityProto.VIDEO_QUALITY_HD @@ -216,21 +214,3 @@ internal fun VideoQuality.toProto(): VideoQualityProto { VideoQuality.UNSPECIFIED -> VideoQualityProto.VIDEO_QUALITY_UNSPECIFIED } } - -internal fun JcaSettings.toDomain(): CameraAppSettings { - return CameraAppSettings( - cameraLensFacing = this.defaultLensFacing.toDomain(), - flashMode = this.flashModeStatus.toDomain(), - targetFrameRate = this.targetFrameRate, - aspectRatio = this.aspectRatioStatus.toDomain(), - streamConfig = this.streamConfigStatus.toDomain(), - stabilizationMode = this.stabilizationMode.toDomain(), - dynamicRange = this.dynamicRangeStatus.toDomain(), - imageFormat = this.imageFormatStatus.toDomain(), - maxVideoDurationMillis = this.maxVideoDurationMillis, - videoQuality = this.videoQuality.toDomain(), - audioEnabled = this.audioEnabledStatus, - lowLightBoostPriority = this.lowLightBoostPriority.toDomain(), - darkMode = this.darkModeStatus.toDomain() - ) -} diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/debug_settings.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/debug_settings.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/debug_settings.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/debug_settings.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dynamic_range.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/dynamic_range.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/dynamic_range.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/dynamic_range.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/test_pattern.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/test_pattern.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/test_pattern.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/test_pattern.proto diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/video_quality.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/video_quality.proto similarity index 100% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/model/proto/video_quality.proto rename to core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/video_quality.proto diff --git a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/MappersTest.kt b/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt similarity index 99% rename from core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/MappersTest.kt rename to core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt index 8a76a922e..8e301b685 100644 --- a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/MappersTest.kt +++ b/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.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.model.proto import com.google.common.truth.Truth.assertThat import com.google.jetpackcamera.model.AspectRatio @@ -38,7 +38,7 @@ import com.google.jetpackcamera.model.proto.StreamConfig as StreamConfigProto import com.google.jetpackcamera.model.proto.VideoQuality as VideoQualityProto import org.junit.Test -class MappersTest { +class ModelMappersTest { @Test fun aspectRatioMapsCorrectly() { diff --git a/core/settings/datastore-proto/build.gradle.kts b/core/settings/datastore-proto/build.gradle.kts index 34a4af571..6bdacdb0b 100644 --- a/core/settings/datastore-proto/build.gradle.kts +++ b/core/settings/datastore-proto/build.gradle.kts @@ -16,7 +16,6 @@ plugins { alias(libs.plugins.android.library) alias(libs.plugins.kotlin.android) - alias(libs.plugins.protobuf) } android { @@ -47,28 +46,9 @@ android { } } -protobuf { - protoc { - artifact = "com.google.protobuf:protoc:3.21.12" - } - generateProtoTasks { - all().forEach { task -> - task.builtins { - create("java") { - option("lite") - } - create("kotlin") { - option("lite") - } - } - } - } -} dependencies { - implementation(project(":core:settings")) - implementation(project(":core:model")) - implementation(libs.protobuf.kotlin.lite) + implementation(project(":core:settings:settings-proto")) implementation(libs.androidx.datastore) // Testing diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt index eb6de3c33..99249ffa8 100644 --- a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt @@ -31,7 +31,8 @@ import com.google.jetpackcamera.model.StabilizationMode import com.google.jetpackcamera.model.StreamConfig import com.google.jetpackcamera.model.VideoQuality import com.google.jetpackcamera.settings.model.CameraAppSettings -import com.google.jetpackcamera.settings.proto.JcaSettings +import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSettingsProto +import com.google.jetpackcamera.model.proto.toProto import java.io.File import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -39,12 +40,12 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map class ProtoDataStoreSettingsDataSource( - private val jcaSettings: DataStore + private val jcaSettings: DataStore ) : SettingsDataSource { - private val jcaSettingsFlow: Flow = jcaSettings.data.catch { exception -> + private val jcaSettingsFlow: Flow = jcaSettings.data.catch { exception -> if (exception is java.io.IOException) { - emit(JcaSettings.getDefaultInstance()) + emit(CameraAppSettingsProto.getDefaultInstance()) } else { throw exception } diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt index dc941a9c7..9729badcf 100644 --- a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt @@ -27,13 +27,13 @@ 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.proto.JcaSettings +import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSettingsProto import com.google.protobuf.InvalidProtocolBufferException import java.io.InputStream import java.io.OutputStream -object ProtoJcaSettingsSerializer : Serializer { +object ProtoJcaSettingsSerializer : Serializer { - override val defaultValue: JcaSettings = JcaSettings.newBuilder() + override val defaultValue: CameraAppSettingsProto = CameraAppSettingsProto.newBuilder() .setDarkModeStatus(DarkMode.DARK_MODE_DARK) .setDefaultLensFacing(LensFacing.LENS_FACING_BACK) .setFlashModeStatus(FlashMode.FLASH_MODE_OFF) @@ -47,13 +47,13 @@ object ProtoJcaSettingsSerializer : Serializer { .setAudioEnabledStatus(true) .build() - override suspend fun readFrom(input: InputStream): JcaSettings { + override suspend fun readFrom(input: InputStream): CameraAppSettingsProto { try { - return JcaSettings.parseFrom(input) + return CameraAppSettingsProto.parseFrom(input) } catch (exception: InvalidProtocolBufferException) { throw CorruptionException("Cannot read proto.", exception) } } - override suspend fun writeTo(t: JcaSettings, output: OutputStream) = t.writeTo(output) + override suspend fun writeTo(t: CameraAppSettingsProto, output: OutputStream) = t.writeTo(output) } diff --git a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt index fc0499dcf..1d13c630a 100644 --- a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt +++ b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt @@ -30,7 +30,7 @@ import com.google.jetpackcamera.model.StreamConfig import com.google.jetpackcamera.model.VideoQuality import com.google.jetpackcamera.settings.model.CameraAppSettings import com.google.jetpackcamera.settings.model.DEFAULT_CAMERA_APP_SETTINGS -import com.google.jetpackcamera.settings.proto.JcaSettings +import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSettingsProto import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -52,7 +52,7 @@ class ProtoDataStoreSettingsDataSourceTest { @get:Rule val tempFolder = TemporaryFolder() - private lateinit var testDataStore: DataStore + private lateinit var testDataStore: DataStore private lateinit var datastoreScope: CoroutineScope private lateinit var repository: ProtoDataStoreSettingsDataSource diff --git a/core/settings/settings-proto/build.gradle.kts b/core/settings/settings-proto/build.gradle.kts new file mode 100644 index 000000000..4c2f75846 --- /dev/null +++ b/core/settings/settings-proto/build.gradle.kts @@ -0,0 +1,77 @@ +/* + * 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.protobuf) +} + +android { + namespace = "com.google.jetpackcamera.settings.proto" + 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" + } + + flavorDimensions += "flavor" + productFlavors { + create("stable") { + dimension = "flavor" + isDefault = true + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlin { + jvmToolchain(17) + } +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.21.12" + } + generateProtoTasks { + all().forEach { task -> + task.builtins { + create("java") { + option("lite") + } + create("kotlin") { + option("lite") + } + } + } + } +} + +dependencies { + api(project(":core:settings")) + api(project(":core:model-proto")) + api(libs.protobuf.kotlin.lite) + + // Testing + testImplementation(libs.junit) + testImplementation(libs.truth) + testImplementation(libs.kotlinx.coroutines.test) +} diff --git a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt new file mode 100644 index 000000000..2415872b0 --- /dev/null +++ b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt @@ -0,0 +1,38 @@ +/* + * 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.jetpackcamera.settings.model.CameraAppSettings +import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSettingsProto +import com.google.jetpackcamera.model.proto.toDomain + +fun CameraAppSettingsProto.toDomain(): CameraAppSettings { + return CameraAppSettings( + cameraLensFacing = this.defaultLensFacing.toDomain(), + flashMode = this.flashModeStatus.toDomain(), + targetFrameRate = this.targetFrameRate, + aspectRatio = this.aspectRatioStatus.toDomain(), + streamConfig = this.streamConfigStatus.toDomain(), + stabilizationMode = this.stabilizationMode.toDomain(), + dynamicRange = this.dynamicRangeStatus.toDomain(), + imageFormat = this.imageFormatStatus.toDomain(), + maxVideoDurationMillis = this.maxVideoDurationMillis, + videoQuality = this.videoQuality.toDomain(), + audioEnabled = this.audioEnabledStatus, + lowLightBoostPriority = this.lowLightBoostPriority.toDomain(), + darkMode = this.darkModeStatus.toDomain() + ) +} diff --git a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/settings/proto_jca_settings.proto b/core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto similarity index 98% rename from core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/settings/proto_jca_settings.proto rename to core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto index ee77dd5ee..cd9c0c970 100644 --- a/core/settings/datastore-proto/src/main/proto/com/google/jetpackcamera/settings/proto_jca_settings.proto +++ b/core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto @@ -31,7 +31,7 @@ import "com/google/jetpackcamera/model/proto/low_light_boost_priority.proto"; option java_package = "com.google.jetpackcamera.settings.proto"; option java_multiple_files = true; -message JcaSettings { +message CameraAppSettings { // Camera settings LensFacing default_lens_facing = 1; FlashMode flash_mode_status = 2; diff --git a/settings.gradle.kts b/settings.gradle.kts index e9ad4cedf..eed17b813 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -70,3 +70,5 @@ include(":core:settings:datastore-prefs:testing") include(":ui:debug") include(":ui:debug:testing") include(":core:settings:datastore-proto") +include(":core:model-proto") +include(":core:settings:settings-proto") From 97f9e98ffd5fd9ea113936959f31e333a8956139 Mon Sep 17 00:00:00 2001 From: Trevor McGuire Date: Mon, 29 Jun 2026 20:44:33 +0000 Subject: [PATCH 03/14] Address review comments regarding datastore factory and imports --- .../google/jetpackcamera/AppSettingsModule.kt | 6 +- .../jetpackcamera/model/proto/ModelMappers.kt | 83 +++++++++++++++++++ .../model/proto/ModelMappersTest.kt | 26 ++++++ .../PrefsDataStoreSettingsDataSource.kt | 15 ++++ ...kt => ProtoCameraAppSettingsSerializer.kt} | 11 ++- .../ProtoDataStoreSettingsDataSource.kt | 32 +++---- .../ProtoDataStoreSettingsDataSourceTest.kt | 18 +++- .../jetpackcamera/settings/SettingsMappers.kt | 5 +- .../settings/camera_app_settings.proto | 2 + .../uistateadapter/capture/DisabledReason.kt | 2 +- 10 files changed, 179 insertions(+), 21 deletions(-) rename core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/{ProtoJcaSettingsSerializer.kt => ProtoCameraAppSettingsSerializer.kt} (88%) diff --git a/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt b/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt index 4a4115bb1..4a4336e5a 100644 --- a/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt +++ b/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt @@ -16,6 +16,9 @@ package com.google.jetpackcamera import android.content.Context +import com.google.jetpackcamera.core.common.DefaultCaptureModeOverride +import com.google.jetpackcamera.model.CaptureMode +import com.google.jetpackcamera.settings.ProtoDataStoreSettingsDataSource import com.google.jetpackcamera.settings.SettingsDataSource import dagger.Module import dagger.Provides @@ -32,7 +35,8 @@ object AppSettingsModule { @Singleton fun provideSettingsDataSource( @ApplicationContext context: Context, + @DefaultCaptureModeOverride defaultCaptureMode: CaptureMode ): SettingsDataSource { - return com.google.jetpackcamera.settings.ProtoDataStoreSettingsDataSource.create(context) + return ProtoDataStoreSettingsDataSource.create(context) } } diff --git a/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt b/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt index c70c53fca..6eeafa019 100644 --- a/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt +++ b/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt @@ -16,6 +16,7 @@ package com.google.jetpackcamera.model.proto import com.google.jetpackcamera.model.AspectRatio +import com.google.jetpackcamera.model.ConcurrentCameraMode import com.google.jetpackcamera.model.DarkMode import com.google.jetpackcamera.model.DynamicRange import com.google.jetpackcamera.model.FlashMode @@ -26,6 +27,7 @@ import com.google.jetpackcamera.model.StabilizationMode import com.google.jetpackcamera.model.StreamConfig import com.google.jetpackcamera.model.VideoQuality import com.google.jetpackcamera.model.proto.AspectRatio as AspectRatioProto +import com.google.jetpackcamera.model.proto.ConcurrentCameraMode as ConcurrentCameraModeProto import com.google.jetpackcamera.model.proto.DarkMode as DarkModeProto import com.google.jetpackcamera.model.proto.DynamicRange as DynamicRangeProto import com.google.jetpackcamera.model.proto.FlashMode as FlashModeProto @@ -36,6 +38,9 @@ import com.google.jetpackcamera.model.proto.StabilizationMode as StabilizationMo import com.google.jetpackcamera.model.proto.StreamConfig as StreamConfigProto import com.google.jetpackcamera.model.proto.VideoQuality as VideoQualityProto +/** + * Maps a Proto model to a Domain model. + */ fun AspectRatioProto.toDomain(): AspectRatio { return when (this) { AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN -> AspectRatio.NINE_SIXTEEN @@ -46,6 +51,9 @@ fun AspectRatioProto.toDomain(): AspectRatio { } } +/** + * Maps a Domain model to a Proto model. + */ fun AspectRatio.toProto(): AspectRatioProto { return when (this) { AspectRatio.NINE_SIXTEEN -> AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN @@ -54,6 +62,9 @@ fun AspectRatio.toProto(): AspectRatioProto { } } +/** + * Maps a Proto model to a Domain model. + */ fun DarkModeProto.toDomain(): DarkMode { return when (this) { DarkModeProto.DARK_MODE_DARK -> DarkMode.DARK @@ -63,6 +74,9 @@ fun DarkModeProto.toDomain(): DarkMode { } } +/** + * Maps a Domain model to a Proto model. + */ fun DarkMode.toProto(): DarkModeProto { return when (this) { DarkMode.DARK -> DarkModeProto.DARK_MODE_DARK @@ -71,6 +85,9 @@ fun DarkMode.toProto(): DarkModeProto { } } +/** + * Maps a Proto model to a Domain model. + */ fun DynamicRangeProto.toDomain(): DynamicRange { return when (this) { DynamicRangeProto.DYNAMIC_RANGE_HLG10 -> DynamicRange.HLG10 @@ -80,6 +97,9 @@ fun DynamicRangeProto.toDomain(): DynamicRange { } } +/** + * Maps a Domain model to a Proto model. + */ fun DynamicRange.toProto(): DynamicRangeProto { return when (this) { DynamicRange.HLG10 -> DynamicRangeProto.DYNAMIC_RANGE_HLG10 @@ -87,6 +107,9 @@ fun DynamicRange.toProto(): DynamicRangeProto { } } +/** + * Maps a Proto model to a Domain model. + */ fun FlashModeProto.toDomain(): FlashMode { return when (this) { FlashModeProto.FLASH_MODE_ON -> FlashMode.ON @@ -97,6 +120,9 @@ fun FlashModeProto.toDomain(): FlashMode { } } +/** + * Maps a Domain model to a Proto model. + */ fun FlashMode.toProto(): FlashModeProto { return when (this) { FlashMode.ON -> FlashModeProto.FLASH_MODE_ON @@ -106,6 +132,9 @@ fun FlashMode.toProto(): FlashModeProto { } } +/** + * Maps a Proto model to a Domain model. + */ fun ImageOutputFormatProto.toDomain(): ImageOutputFormat { return when (this) { ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR -> @@ -115,6 +144,9 @@ fun ImageOutputFormatProto.toDomain(): ImageOutputFormat { } } +/** + * Maps a Domain model to a Proto model. + */ fun ImageOutputFormat.toProto(): ImageOutputFormatProto { return when (this) { ImageOutputFormat.JPEG_ULTRA_HDR -> @@ -123,6 +155,9 @@ fun ImageOutputFormat.toProto(): ImageOutputFormatProto { } } +/** + * Maps a Proto model to a Domain model. + */ fun LensFacingProto.toDomain(): LensFacing { return when (this) { LensFacingProto.LENS_FACING_FRONT -> LensFacing.FRONT @@ -131,6 +166,9 @@ fun LensFacingProto.toDomain(): LensFacing { } } +/** + * Maps a Domain model to a Proto model. + */ fun LensFacing.toProto(): LensFacingProto { return when (this) { LensFacing.FRONT -> LensFacingProto.LENS_FACING_FRONT @@ -138,6 +176,9 @@ fun LensFacing.toProto(): LensFacingProto { } } +/** + * Maps a Proto model to a Domain model. + */ fun LowLightBoostPriorityProto.toDomain(): LowLightBoostPriority { return when (this) { LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES -> @@ -147,6 +188,9 @@ fun LowLightBoostPriorityProto.toDomain(): LowLightBoostPriority { } } +/** + * Maps a Domain model to a Proto model. + */ fun LowLightBoostPriority.toProto(): LowLightBoostPriorityProto { return when (this) { LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES -> @@ -156,6 +200,9 @@ fun LowLightBoostPriority.toProto(): LowLightBoostPriorityProto { } } +/** + * Maps a Proto model to a Domain model. + */ fun StabilizationModeProto.toDomain(): StabilizationMode { return when (this) { StabilizationModeProto.STABILIZATION_MODE_ON -> StabilizationMode.ON @@ -168,6 +215,9 @@ fun StabilizationModeProto.toDomain(): StabilizationMode { } } +/** + * Maps a Domain model to a Proto model. + */ fun StabilizationMode.toProto(): StabilizationModeProto { return when (this) { StabilizationMode.ON -> StabilizationModeProto.STABILIZATION_MODE_ON @@ -178,6 +228,9 @@ fun StabilizationMode.toProto(): StabilizationModeProto { } } +/** + * Maps a Proto model to a Domain model. + */ fun StreamConfigProto.toDomain(): StreamConfig { return when (this) { StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM -> StreamConfig.SINGLE_STREAM @@ -187,6 +240,9 @@ fun StreamConfigProto.toDomain(): StreamConfig { } } +/** + * Maps a Domain model to a Proto model. + */ fun StreamConfig.toProto(): StreamConfigProto { return when (this) { StreamConfig.SINGLE_STREAM -> StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM @@ -194,6 +250,9 @@ fun StreamConfig.toProto(): StreamConfigProto { } } +/** + * Maps a Proto model to a Domain model. + */ fun VideoQualityProto.toDomain(): VideoQuality { return when (this) { VideoQualityProto.VIDEO_QUALITY_SD -> VideoQuality.SD @@ -205,6 +264,9 @@ fun VideoQualityProto.toDomain(): VideoQuality { } } +/** + * Maps a Domain model to a Proto model. + */ fun VideoQuality.toProto(): VideoQualityProto { return when (this) { VideoQuality.SD -> VideoQualityProto.VIDEO_QUALITY_SD @@ -214,3 +276,24 @@ fun VideoQuality.toProto(): VideoQualityProto { VideoQuality.UNSPECIFIED -> VideoQualityProto.VIDEO_QUALITY_UNSPECIFIED } } + +/** + * Maps a Proto model to a Domain model. + */ +fun ConcurrentCameraModeProto.toDomain(): ConcurrentCameraMode { + return when (this) { + ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_DUAL -> ConcurrentCameraMode.DUAL + ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_OFF, + ConcurrentCameraModeProto.UNRECOGNIZED -> ConcurrentCameraMode.OFF + } +} + +/** + * Maps a Domain model to a Proto model. + */ +fun ConcurrentCameraMode.toProto(): ConcurrentCameraModeProto { + return when (this) { + ConcurrentCameraMode.DUAL -> ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_DUAL + ConcurrentCameraMode.OFF -> ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_OFF + } +} diff --git a/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt b/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt index 8e301b685..6e7b65ca6 100644 --- a/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt +++ b/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt @@ -17,6 +17,7 @@ package com.google.jetpackcamera.model.proto import com.google.common.truth.Truth.assertThat import com.google.jetpackcamera.model.AspectRatio +import com.google.jetpackcamera.model.ConcurrentCameraMode import com.google.jetpackcamera.model.DarkMode import com.google.jetpackcamera.model.DynamicRange import com.google.jetpackcamera.model.FlashMode @@ -27,6 +28,7 @@ import com.google.jetpackcamera.model.StabilizationMode import com.google.jetpackcamera.model.StreamConfig import com.google.jetpackcamera.model.VideoQuality import com.google.jetpackcamera.model.proto.AspectRatio as AspectRatioProto +import com.google.jetpackcamera.model.proto.ConcurrentCameraMode as ConcurrentCameraModeProto import com.google.jetpackcamera.model.proto.DarkMode as DarkModeProto import com.google.jetpackcamera.model.proto.DynamicRange as DynamicRangeProto import com.google.jetpackcamera.model.proto.FlashMode as FlashModeProto @@ -37,7 +39,10 @@ import com.google.jetpackcamera.model.proto.StabilizationMode as StabilizationMo import com.google.jetpackcamera.model.proto.StreamConfig as StreamConfigProto import com.google.jetpackcamera.model.proto.VideoQuality as VideoQualityProto import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +@RunWith(JUnit4::class) class ModelMappersTest { @Test @@ -241,4 +246,25 @@ class ModelMappersTest { assertThat(VideoQualityProto.UNRECOGNIZED.toDomain()).isEqualTo(VideoQuality.UNSPECIFIED) } + + @Test + fun concurrentCameraModeMapsCorrectly() { + assertThat( + ConcurrentCameraMode.DUAL.toProto() + ).isEqualTo(ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_DUAL) + assertThat( + ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_DUAL.toDomain() + ).isEqualTo(ConcurrentCameraMode.DUAL) + + assertThat( + ConcurrentCameraMode.OFF.toProto() + ).isEqualTo(ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_OFF) + assertThat( + ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_OFF.toDomain() + ).isEqualTo(ConcurrentCameraMode.OFF) + + assertThat( + ConcurrentCameraModeProto.UNRECOGNIZED.toDomain() + ).isEqualTo(ConcurrentCameraMode.OFF) + } } diff --git a/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt b/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt index c4829c6bf..3d63f0850 100644 --- a/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt +++ b/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt @@ -165,6 +165,21 @@ class PrefsDataStoreSettingsDataSource( } companion object { + fun create( + context: android.content.Context, + defaultCaptureModeOverride: CaptureMode + ): SettingsDataSource { + val dataStore = androidx.datastore.preferences.core.PreferenceDataStoreFactory.create( + produceFile = { + java.io.File( + context.filesDir, + "datastore/app_settings.preferences_pb" + ) + } + ) + return PrefsDataStoreSettingsDataSource(dataStore, defaultCaptureModeOverride) + } + private inline fun > String?.toEnumOrDefault(default: T): T { if (this == null) return default return try { diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt similarity index 88% rename from core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt rename to core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt index 9729badcf..4cec9490b 100644 --- a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoJcaSettingsSerializer.kt +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt @@ -19,6 +19,7 @@ import androidx.datastore.core.CorruptionException import androidx.datastore.core.Serializer import com.google.jetpackcamera.model.UNLIMITED_VIDEO_DURATION import com.google.jetpackcamera.model.proto.AspectRatio +import com.google.jetpackcamera.model.proto.ConcurrentCameraMode import com.google.jetpackcamera.model.proto.DarkMode import com.google.jetpackcamera.model.proto.DynamicRange import com.google.jetpackcamera.model.proto.FlashMode @@ -31,7 +32,11 @@ import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSet import com.google.protobuf.InvalidProtocolBufferException import java.io.InputStream import java.io.OutputStream -object ProtoJcaSettingsSerializer : Serializer { + +/** + * Serializer for the [CameraAppSettingsProto] DataStore. + */ +internal object ProtoCameraAppSettingsSerializer : Serializer { override val defaultValue: CameraAppSettingsProto = CameraAppSettingsProto.newBuilder() .setDarkModeStatus(DarkMode.DARK_MODE_DARK) @@ -45,6 +50,7 @@ object ProtoJcaSettingsSerializer : Serializer { .setMaxVideoDurationMillis(UNLIMITED_VIDEO_DURATION) .setVideoQuality(VideoQuality.VIDEO_QUALITY_UNSPECIFIED) .setAudioEnabledStatus(true) + .setConcurrentCameraModeStatus(ConcurrentCameraMode.CONCURRENT_CAMERA_MODE_OFF) .build() override suspend fun readFrom(input: InputStream): CameraAppSettingsProto { @@ -55,5 +61,6 @@ object ProtoJcaSettingsSerializer : Serializer { } } - override suspend fun writeTo(t: CameraAppSettingsProto, output: OutputStream) = t.writeTo(output) + override suspend fun writeTo(t: CameraAppSettingsProto, output: OutputStream) = + t.writeTo(output) } diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt index 99249ffa8..04c5214a7 100644 --- a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt @@ -16,7 +16,6 @@ package com.google.jetpackcamera.settings import android.content.Context -import android.util.Log import androidx.datastore.core.DataStore import androidx.datastore.core.DataStoreFactory import com.google.jetpackcamera.model.AspectRatio @@ -30,26 +29,30 @@ import com.google.jetpackcamera.model.LowLightBoostPriority import com.google.jetpackcamera.model.StabilizationMode import com.google.jetpackcamera.model.StreamConfig import com.google.jetpackcamera.model.VideoQuality +import com.google.jetpackcamera.model.proto.toProto import com.google.jetpackcamera.settings.model.CameraAppSettings import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSettingsProto -import com.google.jetpackcamera.model.proto.toProto import java.io.File import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map +/** + * Settings data source using Proto DataStore. + */ class ProtoDataStoreSettingsDataSource( private val jcaSettings: DataStore ) : SettingsDataSource { - private val jcaSettingsFlow: Flow = jcaSettings.data.catch { exception -> - if (exception is java.io.IOException) { - emit(CameraAppSettingsProto.getDefaultInstance()) - } else { - throw exception + private val jcaSettingsFlow: Flow = + jcaSettings.data.catch { exception -> + if (exception is java.io.IOException) { + emit(CameraAppSettingsProto.getDefaultInstance()) + } else { + throw exception + } } - } override val defaultCameraAppSettings: Flow = jcaSettingsFlow.map { it.toDomain() @@ -163,19 +166,20 @@ class ProtoDataStoreSettingsDataSource( } override suspend fun updateConcurrentCameraMode(concurrentCameraMode: ConcurrentCameraMode) { - // Not implemented because this field was introduced after the proto was removed. - // The DataStore should not be modified to include new fields, as it is only - // meant to keep backward compatibility with the old user data binary schemas. - Log.w(TAG, "Proto datastore does not support concurrent camera mode") + jcaSettings.updateData { currentSettings -> + currentSettings.toBuilder() + .setConcurrentCameraModeStatus(concurrentCameraMode.toProto()) + .build() + } } companion object { private const val TAG = "ProtoSettingsDS" - private const val FILE_LOCATION = "JcaSettings.pb" + private const val FILE_LOCATION = "CameraAppSettings.pb" fun create(context: Context): SettingsDataSource { val dataStore = DataStoreFactory.create( - serializer = ProtoJcaSettingsSerializer, + serializer = ProtoCameraAppSettingsSerializer, produceFile = { File(context.filesDir, "datastore/$FILE_LOCATION") } ) return ProtoDataStoreSettingsDataSource(dataStore) diff --git a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt index 1d13c630a..b4d3f291d 100644 --- a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt +++ b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt @@ -45,7 +45,10 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +@RunWith(JUnit4::class) @OptIn(ExperimentalCoroutinesApi::class) class ProtoDataStoreSettingsDataSourceTest { @@ -62,7 +65,7 @@ class ProtoDataStoreSettingsDataSourceTest { datastoreScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) testDataStore = DataStoreFactory.create( - serializer = ProtoJcaSettingsSerializer, + serializer = ProtoCameraAppSettingsSerializer, scope = datastoreScope ) { java.io.File(tempFolder.root, "test_jca_settings.pb") @@ -228,4 +231,17 @@ class ProtoDataStoreSettingsDataSourceTest { assertThat(initial).isTrue() assertThat(new).isFalse() } + + @Test + fun can_update_concurrent_camera_mode() = runTest { + val initial = repository.getCurrentDefaultCameraAppSettings().concurrentCameraMode + repository.updateConcurrentCameraMode( + com.google.jetpackcamera.model.ConcurrentCameraMode.DUAL + ) + advanceUntilIdle() + val new = repository.getCurrentDefaultCameraAppSettings().concurrentCameraMode + + assertThat(initial).isEqualTo(com.google.jetpackcamera.model.ConcurrentCameraMode.OFF) + assertThat(new).isEqualTo(com.google.jetpackcamera.model.ConcurrentCameraMode.DUAL) + } } diff --git a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt index 2415872b0..41db2d77c 100644 --- a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt +++ b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt @@ -15,9 +15,9 @@ */ package com.google.jetpackcamera.settings +import com.google.jetpackcamera.model.proto.toDomain import com.google.jetpackcamera.settings.model.CameraAppSettings import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSettingsProto -import com.google.jetpackcamera.model.proto.toDomain fun CameraAppSettingsProto.toDomain(): CameraAppSettings { return CameraAppSettings( @@ -33,6 +33,7 @@ fun CameraAppSettingsProto.toDomain(): CameraAppSettings { videoQuality = this.videoQuality.toDomain(), audioEnabled = this.audioEnabledStatus, lowLightBoostPriority = this.lowLightBoostPriority.toDomain(), - darkMode = this.darkModeStatus.toDomain() + darkMode = this.darkModeStatus.toDomain(), + concurrentCameraMode = this.concurrentCameraModeStatus.toDomain() ) } diff --git a/core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto b/core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto index cd9c0c970..584f95105 100644 --- a/core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto +++ b/core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto @@ -26,6 +26,7 @@ import "com/google/jetpackcamera/model/proto/lens_facing.proto"; import "com/google/jetpackcamera/model/proto/stabilization_mode.proto"; import "com/google/jetpackcamera/model/proto/video_quality.proto"; import "com/google/jetpackcamera/model/proto/low_light_boost_priority.proto"; +import "com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto"; option java_package = "com.google.jetpackcamera.settings.proto"; @@ -48,4 +49,5 @@ message CameraAppSettings { // Non-camera app settings DarkMode dark_mode_status = 9; + ConcurrentCameraMode concurrent_camera_mode_status = 15; } diff --git a/ui/uistateadapter/capture/src/main/java/com/google/jetpackcamera/ui/uistateadapter/capture/DisabledReason.kt b/ui/uistateadapter/capture/src/main/java/com/google/jetpackcamera/ui/uistateadapter/capture/DisabledReason.kt index 4d2ba8efb..53e2b403b 100644 --- a/ui/uistateadapter/capture/src/main/java/com/google/jetpackcamera/ui/uistateadapter/capture/DisabledReason.kt +++ b/ui/uistateadapter/capture/src/main/java/com/google/jetpackcamera/ui/uistateadapter/capture/DisabledReason.kt @@ -21,7 +21,7 @@ import com.google.jetpackcamera.ui.uistate.DisableRationale * Represents reasons why a UI component or functionality might be disabled, providing * a string resource ID for user-facing explanation. */ -enum class DisabledReason( +internal enum class DisabledReason( override val reasonTextResId: Int ) : DisableRationale { VIDEO_CAPTURE_EXTERNAL_UNSUPPORTED( From 5f8d32283ba5e7a9a34e178f4af3c6e5e66bd992 Mon Sep 17 00:00:00 2001 From: Trevor McGuire Date: Mon, 29 Jun 2026 22:44:25 +0000 Subject: [PATCH 04/14] Add missing KDoc to SettingsMappers.kt --- .../java/com/google/jetpackcamera/settings/SettingsMappers.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt index 41db2d77c..a2703b713 100644 --- a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt +++ b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt @@ -19,6 +19,9 @@ import com.google.jetpackcamera.model.proto.toDomain import com.google.jetpackcamera.settings.model.CameraAppSettings import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSettingsProto +/** + * Maps a [CameraAppSettingsProto] to a [CameraAppSettings] domain model. + */ fun CameraAppSettingsProto.toDomain(): CameraAppSettings { return CameraAppSettings( cameraLensFacing = this.defaultLensFacing.toDomain(), From 4a780d8c57e8f6dd00c07dd44bb7c9a3dbd97c3e Mon Sep 17 00:00:00 2001 From: Trevor McGuire Date: Mon, 29 Jun 2026 23:18:20 +0000 Subject: [PATCH 05/14] chore: align proto enums with proto3 zero-value best practices Added _UNSPECIFIED = 0 to all proto enums to comply with official proto3 style guide requirements. Updated ModelMappers.kt to handle the new UNSPECIFIED values and safely fallback to defaults. Also added a rule enforcing this to the local styleguide. --- .gemini/styleguide.md | 4 +++- .../google/jetpackcamera/model/proto/ModelMappers.kt | 12 +++++++++--- .../jetpackcamera/model/proto/aspect_ratio.proto | 2 +- .../model/proto/concurrent_camera_mode.proto | 5 +++-- .../google/jetpackcamera/model/proto/dark_mode.proto | 7 ++++--- .../jetpackcamera/model/proto/flash_mode.proto | 9 +++++---- .../model/proto/image_output_format.proto | 5 +++-- .../jetpackcamera/model/proto/lens_facing.proto | 5 +++-- .../model/proto/low_light_boost_priority.proto | 5 +++-- .../model/proto/stabilization_mode.proto | 2 +- .../jetpackcamera/model/proto/stream_config.proto | 2 +- 11 files changed, 36 insertions(+), 22 deletions(-) diff --git a/.gemini/styleguide.md b/.gemini/styleguide.md index 7249c9801..2485db719 100644 --- a/.gemini/styleguide.md +++ b/.gemini/styleguide.md @@ -100,4 +100,6 @@ When reviewing a pull request, focus on the following key areas: * **Prioritize Impact:** Focus on the most important issues first (e.g., architectural flaws, missing tests) before minor stylistic nits. * **Indicate Low Priority:** For minor cosmetic, spacing, or simple typographical suggestions, preface the comment with `nit:` to indicate it is a low-priority polish item. * **Cite Sources:** When suggesting a change based on a best practice or API guideline, link to the relevant official documentation (e.g., developer.android.com) to support your feedback. -* **Tone:** Maintain a helpful, collaborative, concise, and professional tone. \ No newline at end of file +* **Tone:** Maintain a helpful, collaborative, concise, and professional tone. +12. **Proto Enum Best Practices** + * **Zero-Value Requirement:** In accordance with the [Proto3 Style Guide](https://protobuf.dev/programming-guides/style/#enums), the first value of any proto enum must be `0` and should be named `_UNSPECIFIED`. This zero-value acts as the default when a field is missing, preventing implicit fallbacks to a semantically valid choice. diff --git a/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt b/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt index 6eeafa019..e931d014b 100644 --- a/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt +++ b/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt @@ -46,7 +46,7 @@ fun AspectRatioProto.toDomain(): AspectRatio { AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN -> AspectRatio.NINE_SIXTEEN AspectRatioProto.ASPECT_RATIO_ONE_ONE -> AspectRatio.ONE_ONE AspectRatioProto.ASPECT_RATIO_THREE_FOUR, - AspectRatioProto.ASPECT_RATIO_UNDEFINED, + AspectRatioProto.ASPECT_RATIO_UNSPECIFIED, AspectRatioProto.UNRECOGNIZED -> AspectRatio.THREE_FOUR } } @@ -70,6 +70,7 @@ fun DarkModeProto.toDomain(): DarkMode { DarkModeProto.DARK_MODE_DARK -> DarkMode.DARK DarkModeProto.DARK_MODE_LIGHT -> DarkMode.LIGHT DarkModeProto.DARK_MODE_SYSTEM, + DarkModeProto.DARK_MODE_UNSPECIFIED, DarkModeProto.UNRECOGNIZED -> DarkMode.SYSTEM } } @@ -116,6 +117,7 @@ fun FlashModeProto.toDomain(): FlashMode { FlashModeProto.FLASH_MODE_AUTO -> FlashMode.AUTO FlashModeProto.FLASH_MODE_LOW_LIGHT_BOOST -> FlashMode.LOW_LIGHT_BOOST FlashModeProto.FLASH_MODE_OFF, + FlashModeProto.FLASH_MODE_UNSPECIFIED, FlashModeProto.UNRECOGNIZED -> FlashMode.OFF } } @@ -140,6 +142,7 @@ fun ImageOutputFormatProto.toDomain(): ImageOutputFormat { ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR -> ImageOutputFormat.JPEG_ULTRA_HDR ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG, + ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_UNSPECIFIED, ImageOutputFormatProto.UNRECOGNIZED -> ImageOutputFormat.JPEG } } @@ -162,6 +165,7 @@ fun LensFacingProto.toDomain(): LensFacing { return when (this) { LensFacingProto.LENS_FACING_FRONT -> LensFacing.FRONT LensFacingProto.LENS_FACING_BACK, + LensFacingProto.LENS_FACING_UNSPECIFIED, LensFacingProto.UNRECOGNIZED -> LensFacing.BACK } } @@ -184,6 +188,7 @@ fun LowLightBoostPriorityProto.toDomain(): LowLightBoostPriority { LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES -> LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_AE_MODE, + LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_UNSPECIFIED, LowLightBoostPriorityProto.UNRECOGNIZED -> LowLightBoostPriority.PRIORITIZE_AE_MODE } } @@ -210,7 +215,7 @@ fun StabilizationModeProto.toDomain(): StabilizationMode { StabilizationModeProto.STABILIZATION_MODE_HIGH_QUALITY -> StabilizationMode.HIGH_QUALITY StabilizationModeProto.STABILIZATION_MODE_OPTICAL -> StabilizationMode.OPTICAL StabilizationModeProto.STABILIZATION_MODE_AUTO, - StabilizationModeProto.STABILIZATION_MODE_UNDEFINED, + StabilizationModeProto.STABILIZATION_MODE_UNSPECIFIED, StabilizationModeProto.UNRECOGNIZED -> StabilizationMode.AUTO } } @@ -235,7 +240,7 @@ fun StreamConfigProto.toDomain(): StreamConfig { return when (this) { StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM -> StreamConfig.SINGLE_STREAM StreamConfigProto.STREAM_CONFIG_MULTI_STREAM, - StreamConfigProto.STREAM_CONFIG_UNDEFINED, + StreamConfigProto.STREAM_CONFIG_UNSPECIFIED, StreamConfigProto.UNRECOGNIZED -> StreamConfig.MULTI_STREAM } } @@ -284,6 +289,7 @@ fun ConcurrentCameraModeProto.toDomain(): ConcurrentCameraMode { return when (this) { ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_DUAL -> ConcurrentCameraMode.DUAL ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_OFF, + ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_UNSPECIFIED, ConcurrentCameraModeProto.UNRECOGNIZED -> ConcurrentCameraMode.OFF } } diff --git a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto index da8011c35..7c9d2bf27 100644 --- a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto +++ b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/aspect_ratio.proto @@ -20,7 +20,7 @@ option java_package = "com.google.jetpackcamera.model.proto"; option java_multiple_files = true; enum AspectRatio { - ASPECT_RATIO_UNDEFINED = 0; + ASPECT_RATIO_UNSPECIFIED = 0; ASPECT_RATIO_THREE_FOUR = 1; ASPECT_RATIO_NINE_SIXTEEN= 2; ASPECT_RATIO_ONE_ONE = 3; diff --git a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto index 4f50d2524..ead8ea876 100644 --- a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto +++ b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/concurrent_camera_mode.proto @@ -19,6 +19,7 @@ option java_package = "com.google.jetpackcamera.model.proto"; option java_multiple_files = true; enum ConcurrentCameraMode { - CONCURRENT_CAMERA_MODE_OFF = 0; - CONCURRENT_CAMERA_MODE_DUAL = 1; + CONCURRENT_CAMERA_MODE_UNSPECIFIED = 0; + CONCURRENT_CAMERA_MODE_OFF = 1; + CONCURRENT_CAMERA_MODE_DUAL = 2; } diff --git a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto index 8b38ef403..0697f0d9c 100644 --- a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto +++ b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/dark_mode.proto @@ -20,7 +20,8 @@ option java_package = "com.google.jetpackcamera.model.proto"; option java_multiple_files = true; enum DarkMode { - DARK_MODE_SYSTEM = 0; - DARK_MODE_LIGHT= 1; - DARK_MODE_DARK = 2; + DARK_MODE_UNSPECIFIED = 0; + DARK_MODE_SYSTEM = 1; + DARK_MODE_LIGHT= 2; + DARK_MODE_DARK = 3; } \ No newline at end of file diff --git a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto index fc87418e7..e96dc45ad 100644 --- a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto +++ b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/flash_mode.proto @@ -20,8 +20,9 @@ option java_package = "com.google.jetpackcamera.model.proto"; option java_multiple_files = true; enum FlashMode{ - FLASH_MODE_AUTO = 0; - FLASH_MODE_ON = 1; - FLASH_MODE_OFF = 2; - FLASH_MODE_LOW_LIGHT_BOOST = 3; + FLASH_MODE_UNSPECIFIED = 0; + FLASH_MODE_AUTO = 1; + FLASH_MODE_ON = 2; + FLASH_MODE_OFF = 3; + FLASH_MODE_LOW_LIGHT_BOOST = 4; } \ No newline at end of file diff --git a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto index b64556b08..0a6182cf3 100644 --- a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto +++ b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/image_output_format.proto @@ -20,6 +20,7 @@ option java_package = "com.google.jetpackcamera.model.proto"; option java_multiple_files = true; enum ImageOutputFormat { - IMAGE_OUTPUT_FORMAT_JPEG = 0; - IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR = 1; + IMAGE_OUTPUT_FORMAT_UNSPECIFIED = 0; + IMAGE_OUTPUT_FORMAT_JPEG = 1; + IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR = 2; } \ No newline at end of file diff --git a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto index 2e898a4eb..30e7d7e9d 100644 --- a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto +++ b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/lens_facing.proto @@ -20,6 +20,7 @@ option java_package = "com.google.jetpackcamera.model.proto"; option java_multiple_files = true; enum LensFacing { - LENS_FACING_BACK = 0; - LENS_FACING_FRONT = 1; + LENS_FACING_UNSPECIFIED = 0; + LENS_FACING_BACK = 1; + LENS_FACING_FRONT = 2; } \ No newline at end of file diff --git a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto index bd8fd7dbf..9c64fff3e 100644 --- a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto +++ b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/low_light_boost_priority.proto @@ -20,6 +20,7 @@ option java_package = "com.google.jetpackcamera.model.proto"; option java_multiple_files = true; enum LowLightBoostPriority { - LOW_LIGHT_BOOST_PRIORITY_AE_MODE = 0; - LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES = 1; + LOW_LIGHT_BOOST_PRIORITY_UNSPECIFIED = 0; + LOW_LIGHT_BOOST_PRIORITY_AE_MODE = 1; + LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES = 2; } diff --git a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto index bdba01437..24d0eb764 100644 --- a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto +++ b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stabilization_mode.proto @@ -20,7 +20,7 @@ option java_package = "com.google.jetpackcamera.model.proto"; option java_multiple_files = true; enum StabilizationMode { - STABILIZATION_MODE_UNDEFINED = 0; + STABILIZATION_MODE_UNSPECIFIED = 0; STABILIZATION_MODE_AUTO = 1; STABILIZATION_MODE_OFF = 2; STABILIZATION_MODE_ON = 3; diff --git a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto index 28af05d60..d17ca768f 100644 --- a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto +++ b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto @@ -20,7 +20,7 @@ option java_package = "com.google.jetpackcamera.model.proto"; option java_multiple_files = true; enum StreamConfig { - STREAM_CONFIG_UNDEFINED = 0; + STREAM_CONFIG_UNSPECIFIED = 0; STREAM_CONFIG_MULTI_STREAM = 1; STREAM_CONFIG_SINGLE_STREAM = 2; } \ No newline at end of file From 39e86b3762df850c0d69bafd9e6f8b9f2ca80b40 Mon Sep 17 00:00:00 2001 From: Trevor McGuire Date: Mon, 29 Jun 2026 23:20:50 +0000 Subject: [PATCH 06/14] style: address gemini-code-assist review feedback - Set targetFrameRate and lowLightBoostPriority explicitly in ProtoCameraAppSettingsSerializer's defaultValue. - Added KDoc for create() in ProtoDataStoreSettingsDataSource and PrefsDataStoreSettingsDataSource. - Removed unused TAG from ProtoDataStoreSettingsDataSource. - Added Dispatchers.resetMain() to tearDown in ProtoDataStoreSettingsDataSourceTest. --- .../PrefsDataStoreSettingsDataSource.kt | 11 +++++++++++ .../settings/ProtoCameraAppSettingsSerializer.kt | 5 +++++ .../settings/ProtoDataStoreSettingsDataSource.kt | 11 ++++++++++- .../settings/ProtoDataStoreSettingsDataSourceTest.kt | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt b/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt index 3d63f0850..f69b43c33 100644 --- a/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt +++ b/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt @@ -165,6 +165,17 @@ class PrefsDataStoreSettingsDataSource( } companion object { + /** + * Creates an instance of [SettingsDataSource] backed by Preferences DataStore. + * + * Note: To avoid breaking DataStore functionality, ensure that only a single instance + * of [DataStore] is active for the settings file at any time (e.g., by managing this + * instance as a Singleton via dependency injection). + * + * @param context The application context. + * @param defaultCaptureModeOverride The default capture mode override. + * @return A [SettingsDataSource] instance. + */ fun create( context: android.content.Context, defaultCaptureModeOverride: CaptureMode diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt index 4cec9490b..5a6eea2af 100644 --- a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt @@ -25,6 +25,7 @@ import com.google.jetpackcamera.model.proto.DynamicRange import com.google.jetpackcamera.model.proto.FlashMode import com.google.jetpackcamera.model.proto.ImageOutputFormat import com.google.jetpackcamera.model.proto.LensFacing +import com.google.jetpackcamera.model.proto.LowLightBoostPriority as LowLightBoostPriorityProto import com.google.jetpackcamera.model.proto.StabilizationMode import com.google.jetpackcamera.model.proto.StreamConfig import com.google.jetpackcamera.model.proto.VideoQuality @@ -51,6 +52,10 @@ internal object ProtoCameraAppSettingsSerializer : Serializer Date: Mon, 29 Jun 2026 23:33:13 +0000 Subject: [PATCH 07/14] fix: use TARGET_FPS_AUTO constant instead of 0 for target frame rate default --- .../jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt index 5a6eea2af..eae2435a8 100644 --- a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt @@ -17,6 +17,7 @@ package com.google.jetpackcamera.settings import androidx.datastore.core.CorruptionException import androidx.datastore.core.Serializer +import com.google.jetpackcamera.model.TARGET_FPS_AUTO import com.google.jetpackcamera.model.UNLIMITED_VIDEO_DURATION import com.google.jetpackcamera.model.proto.AspectRatio import com.google.jetpackcamera.model.proto.ConcurrentCameraMode @@ -52,7 +53,7 @@ internal object ProtoCameraAppSettingsSerializer : Serializer Date: Mon, 29 Jun 2026 23:36:32 +0000 Subject: [PATCH 08/14] refactor: rename toDomain() to toModel() in proto mappers --- .../jetpackcamera/model/proto/ModelMappers.kt | 22 ++--- .../model/proto/ModelMappersTest.kt | 86 +++++++++---------- .../ProtoDataStoreSettingsDataSource.kt | 4 +- .../jetpackcamera/settings/SettingsMappers.kt | 26 +++--- 4 files changed, 69 insertions(+), 69 deletions(-) diff --git a/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt b/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt index e931d014b..5b9424210 100644 --- a/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt +++ b/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt @@ -41,7 +41,7 @@ import com.google.jetpackcamera.model.proto.VideoQuality as VideoQualityProto /** * Maps a Proto model to a Domain model. */ -fun AspectRatioProto.toDomain(): AspectRatio { +fun AspectRatioProto.toModel(): AspectRatio { return when (this) { AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN -> AspectRatio.NINE_SIXTEEN AspectRatioProto.ASPECT_RATIO_ONE_ONE -> AspectRatio.ONE_ONE @@ -65,7 +65,7 @@ fun AspectRatio.toProto(): AspectRatioProto { /** * Maps a Proto model to a Domain model. */ -fun DarkModeProto.toDomain(): DarkMode { +fun DarkModeProto.toModel(): DarkMode { return when (this) { DarkModeProto.DARK_MODE_DARK -> DarkMode.DARK DarkModeProto.DARK_MODE_LIGHT -> DarkMode.LIGHT @@ -89,7 +89,7 @@ fun DarkMode.toProto(): DarkModeProto { /** * Maps a Proto model to a Domain model. */ -fun DynamicRangeProto.toDomain(): DynamicRange { +fun DynamicRangeProto.toModel(): DynamicRange { return when (this) { DynamicRangeProto.DYNAMIC_RANGE_HLG10 -> DynamicRange.HLG10 DynamicRangeProto.DYNAMIC_RANGE_SDR, @@ -111,7 +111,7 @@ fun DynamicRange.toProto(): DynamicRangeProto { /** * Maps a Proto model to a Domain model. */ -fun FlashModeProto.toDomain(): FlashMode { +fun FlashModeProto.toModel(): FlashMode { return when (this) { FlashModeProto.FLASH_MODE_ON -> FlashMode.ON FlashModeProto.FLASH_MODE_AUTO -> FlashMode.AUTO @@ -137,7 +137,7 @@ fun FlashMode.toProto(): FlashModeProto { /** * Maps a Proto model to a Domain model. */ -fun ImageOutputFormatProto.toDomain(): ImageOutputFormat { +fun ImageOutputFormatProto.toModel(): ImageOutputFormat { return when (this) { ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR -> ImageOutputFormat.JPEG_ULTRA_HDR @@ -161,7 +161,7 @@ fun ImageOutputFormat.toProto(): ImageOutputFormatProto { /** * Maps a Proto model to a Domain model. */ -fun LensFacingProto.toDomain(): LensFacing { +fun LensFacingProto.toModel(): LensFacing { return when (this) { LensFacingProto.LENS_FACING_FRONT -> LensFacing.FRONT LensFacingProto.LENS_FACING_BACK, @@ -183,7 +183,7 @@ fun LensFacing.toProto(): LensFacingProto { /** * Maps a Proto model to a Domain model. */ -fun LowLightBoostPriorityProto.toDomain(): LowLightBoostPriority { +fun LowLightBoostPriorityProto.toModel(): LowLightBoostPriority { return when (this) { LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES -> LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES @@ -208,7 +208,7 @@ fun LowLightBoostPriority.toProto(): LowLightBoostPriorityProto { /** * Maps a Proto model to a Domain model. */ -fun StabilizationModeProto.toDomain(): StabilizationMode { +fun StabilizationModeProto.toModel(): StabilizationMode { return when (this) { StabilizationModeProto.STABILIZATION_MODE_ON -> StabilizationMode.ON StabilizationModeProto.STABILIZATION_MODE_OFF -> StabilizationMode.OFF @@ -236,7 +236,7 @@ fun StabilizationMode.toProto(): StabilizationModeProto { /** * Maps a Proto model to a Domain model. */ -fun StreamConfigProto.toDomain(): StreamConfig { +fun StreamConfigProto.toModel(): StreamConfig { return when (this) { StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM -> StreamConfig.SINGLE_STREAM StreamConfigProto.STREAM_CONFIG_MULTI_STREAM, @@ -258,7 +258,7 @@ fun StreamConfig.toProto(): StreamConfigProto { /** * Maps a Proto model to a Domain model. */ -fun VideoQualityProto.toDomain(): VideoQuality { +fun VideoQualityProto.toModel(): VideoQuality { return when (this) { VideoQualityProto.VIDEO_QUALITY_SD -> VideoQuality.SD VideoQualityProto.VIDEO_QUALITY_HD -> VideoQuality.HD @@ -285,7 +285,7 @@ fun VideoQuality.toProto(): VideoQualityProto { /** * Maps a Proto model to a Domain model. */ -fun ConcurrentCameraModeProto.toDomain(): ConcurrentCameraMode { +fun ConcurrentCameraModeProto.toModel(): ConcurrentCameraMode { return when (this) { ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_DUAL -> ConcurrentCameraMode.DUAL ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_OFF, diff --git a/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt b/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt index 6e7b65ca6..4ce705fb9 100644 --- a/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt +++ b/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt @@ -51,66 +51,66 @@ class ModelMappersTest { AspectRatio.NINE_SIXTEEN.toProto() ).isEqualTo(AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN) assertThat( - AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN.toDomain() + AspectRatioProto.ASPECT_RATIO_NINE_SIXTEEN.toModel() ).isEqualTo(AspectRatio.NINE_SIXTEEN) assertThat(AspectRatio.ONE_ONE.toProto()).isEqualTo(AspectRatioProto.ASPECT_RATIO_ONE_ONE) - assertThat(AspectRatioProto.ASPECT_RATIO_ONE_ONE.toDomain()).isEqualTo(AspectRatio.ONE_ONE) + assertThat(AspectRatioProto.ASPECT_RATIO_ONE_ONE.toModel()).isEqualTo(AspectRatio.ONE_ONE) assertThat( AspectRatio.THREE_FOUR.toProto() ).isEqualTo(AspectRatioProto.ASPECT_RATIO_THREE_FOUR) assertThat( - AspectRatioProto.ASPECT_RATIO_THREE_FOUR.toDomain() + AspectRatioProto.ASPECT_RATIO_THREE_FOUR.toModel() ).isEqualTo(AspectRatio.THREE_FOUR) - assertThat(AspectRatioProto.UNRECOGNIZED.toDomain()).isEqualTo(AspectRatio.THREE_FOUR) + assertThat(AspectRatioProto.UNRECOGNIZED.toModel()).isEqualTo(AspectRatio.THREE_FOUR) } @Test fun darkModeMapsCorrectly() { assertThat(DarkMode.DARK.toProto()).isEqualTo(DarkModeProto.DARK_MODE_DARK) - assertThat(DarkModeProto.DARK_MODE_DARK.toDomain()).isEqualTo(DarkMode.DARK) + assertThat(DarkModeProto.DARK_MODE_DARK.toModel()).isEqualTo(DarkMode.DARK) assertThat(DarkMode.LIGHT.toProto()).isEqualTo(DarkModeProto.DARK_MODE_LIGHT) - assertThat(DarkModeProto.DARK_MODE_LIGHT.toDomain()).isEqualTo(DarkMode.LIGHT) + assertThat(DarkModeProto.DARK_MODE_LIGHT.toModel()).isEqualTo(DarkMode.LIGHT) assertThat(DarkMode.SYSTEM.toProto()).isEqualTo(DarkModeProto.DARK_MODE_SYSTEM) - assertThat(DarkModeProto.DARK_MODE_SYSTEM.toDomain()).isEqualTo(DarkMode.SYSTEM) + assertThat(DarkModeProto.DARK_MODE_SYSTEM.toModel()).isEqualTo(DarkMode.SYSTEM) - assertThat(DarkModeProto.UNRECOGNIZED.toDomain()).isEqualTo(DarkMode.SYSTEM) + assertThat(DarkModeProto.UNRECOGNIZED.toModel()).isEqualTo(DarkMode.SYSTEM) } @Test fun dynamicRangeMapsCorrectly() { assertThat(DynamicRange.HLG10.toProto()).isEqualTo(DynamicRangeProto.DYNAMIC_RANGE_HLG10) - assertThat(DynamicRangeProto.DYNAMIC_RANGE_HLG10.toDomain()).isEqualTo(DynamicRange.HLG10) + assertThat(DynamicRangeProto.DYNAMIC_RANGE_HLG10.toModel()).isEqualTo(DynamicRange.HLG10) assertThat(DynamicRange.SDR.toProto()).isEqualTo(DynamicRangeProto.DYNAMIC_RANGE_SDR) - assertThat(DynamicRangeProto.DYNAMIC_RANGE_SDR.toDomain()).isEqualTo(DynamicRange.SDR) + assertThat(DynamicRangeProto.DYNAMIC_RANGE_SDR.toModel()).isEqualTo(DynamicRange.SDR) - assertThat(DynamicRangeProto.UNRECOGNIZED.toDomain()).isEqualTo(DynamicRange.SDR) + assertThat(DynamicRangeProto.UNRECOGNIZED.toModel()).isEqualTo(DynamicRange.SDR) } @Test fun flashModeMapsCorrectly() { assertThat(FlashMode.ON.toProto()).isEqualTo(FlashModeProto.FLASH_MODE_ON) - assertThat(FlashModeProto.FLASH_MODE_ON.toDomain()).isEqualTo(FlashMode.ON) + assertThat(FlashModeProto.FLASH_MODE_ON.toModel()).isEqualTo(FlashMode.ON) assertThat(FlashMode.AUTO.toProto()).isEqualTo(FlashModeProto.FLASH_MODE_AUTO) - assertThat(FlashModeProto.FLASH_MODE_AUTO.toDomain()).isEqualTo(FlashMode.AUTO) + assertThat(FlashModeProto.FLASH_MODE_AUTO.toModel()).isEqualTo(FlashMode.AUTO) assertThat(FlashMode.OFF.toProto()).isEqualTo(FlashModeProto.FLASH_MODE_OFF) - assertThat(FlashModeProto.FLASH_MODE_OFF.toDomain()).isEqualTo(FlashMode.OFF) + assertThat(FlashModeProto.FLASH_MODE_OFF.toModel()).isEqualTo(FlashMode.OFF) assertThat( FlashMode.LOW_LIGHT_BOOST.toProto() ).isEqualTo(FlashModeProto.FLASH_MODE_LOW_LIGHT_BOOST) assertThat( - FlashModeProto.FLASH_MODE_LOW_LIGHT_BOOST.toDomain() + FlashModeProto.FLASH_MODE_LOW_LIGHT_BOOST.toModel() ).isEqualTo(FlashMode.LOW_LIGHT_BOOST) - assertThat(FlashModeProto.UNRECOGNIZED.toDomain()).isEqualTo(FlashMode.OFF) + assertThat(FlashModeProto.UNRECOGNIZED.toModel()).isEqualTo(FlashMode.OFF) } @Test @@ -119,28 +119,28 @@ class ModelMappersTest { ImageOutputFormat.JPEG.toProto() ).isEqualTo(ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG) assertThat( - ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG.toDomain() + ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG.toModel() ).isEqualTo(ImageOutputFormat.JPEG) assertThat( ImageOutputFormat.JPEG_ULTRA_HDR.toProto() ).isEqualTo(ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR) assertThat( - ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR.toDomain() + ImageOutputFormatProto.IMAGE_OUTPUT_FORMAT_JPEG_ULTRA_HDR.toModel() ).isEqualTo(ImageOutputFormat.JPEG_ULTRA_HDR) - assertThat(ImageOutputFormatProto.UNRECOGNIZED.toDomain()).isEqualTo(ImageOutputFormat.JPEG) + assertThat(ImageOutputFormatProto.UNRECOGNIZED.toModel()).isEqualTo(ImageOutputFormat.JPEG) } @Test fun lensFacingMapsCorrectly() { assertThat(LensFacing.FRONT.toProto()).isEqualTo(LensFacingProto.LENS_FACING_FRONT) - assertThat(LensFacingProto.LENS_FACING_FRONT.toDomain()).isEqualTo(LensFacing.FRONT) + assertThat(LensFacingProto.LENS_FACING_FRONT.toModel()).isEqualTo(LensFacing.FRONT) assertThat(LensFacing.BACK.toProto()).isEqualTo(LensFacingProto.LENS_FACING_BACK) - assertThat(LensFacingProto.LENS_FACING_BACK.toDomain()).isEqualTo(LensFacing.BACK) + assertThat(LensFacingProto.LENS_FACING_BACK.toModel()).isEqualTo(LensFacing.BACK) - assertThat(LensFacingProto.UNRECOGNIZED.toDomain()).isEqualTo(LensFacing.BACK) + assertThat(LensFacingProto.UNRECOGNIZED.toModel()).isEqualTo(LensFacing.BACK) } @Test @@ -149,18 +149,18 @@ class ModelMappersTest { LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES.toProto() ).isEqualTo(LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES) assertThat( - LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES.toDomain() + LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_GOOGLE_PLAY_SERVICES.toModel() ).isEqualTo(LowLightBoostPriority.PRIORITIZE_GOOGLE_PLAY_SERVICES) assertThat( LowLightBoostPriority.PRIORITIZE_AE_MODE.toProto() ).isEqualTo(LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_AE_MODE) assertThat( - LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_AE_MODE.toDomain() + LowLightBoostPriorityProto.LOW_LIGHT_BOOST_PRIORITY_AE_MODE.toModel() ).isEqualTo(LowLightBoostPriority.PRIORITIZE_AE_MODE) assertThat( - LowLightBoostPriorityProto.UNRECOGNIZED.toDomain() + LowLightBoostPriorityProto.UNRECOGNIZED.toModel() ).isEqualTo(LowLightBoostPriority.PRIORITIZE_AE_MODE) } @@ -170,38 +170,38 @@ class ModelMappersTest { StabilizationMode.ON.toProto() ).isEqualTo(StabilizationModeProto.STABILIZATION_MODE_ON) assertThat( - StabilizationModeProto.STABILIZATION_MODE_ON.toDomain() + StabilizationModeProto.STABILIZATION_MODE_ON.toModel() ).isEqualTo(StabilizationMode.ON) assertThat( StabilizationMode.OFF.toProto() ).isEqualTo(StabilizationModeProto.STABILIZATION_MODE_OFF) assertThat( - StabilizationModeProto.STABILIZATION_MODE_OFF.toDomain() + StabilizationModeProto.STABILIZATION_MODE_OFF.toModel() ).isEqualTo(StabilizationMode.OFF) assertThat( StabilizationMode.HIGH_QUALITY.toProto() ).isEqualTo(StabilizationModeProto.STABILIZATION_MODE_HIGH_QUALITY) assertThat( - StabilizationModeProto.STABILIZATION_MODE_HIGH_QUALITY.toDomain() + StabilizationModeProto.STABILIZATION_MODE_HIGH_QUALITY.toModel() ).isEqualTo(StabilizationMode.HIGH_QUALITY) assertThat( StabilizationMode.OPTICAL.toProto() ).isEqualTo(StabilizationModeProto.STABILIZATION_MODE_OPTICAL) assertThat( - StabilizationModeProto.STABILIZATION_MODE_OPTICAL.toDomain() + StabilizationModeProto.STABILIZATION_MODE_OPTICAL.toModel() ).isEqualTo(StabilizationMode.OPTICAL) assertThat( StabilizationMode.AUTO.toProto() ).isEqualTo(StabilizationModeProto.STABILIZATION_MODE_AUTO) assertThat( - StabilizationModeProto.STABILIZATION_MODE_AUTO.toDomain() + StabilizationModeProto.STABILIZATION_MODE_AUTO.toModel() ).isEqualTo(StabilizationMode.AUTO) - assertThat(StabilizationModeProto.UNRECOGNIZED.toDomain()).isEqualTo(StabilizationMode.AUTO) + assertThat(StabilizationModeProto.UNRECOGNIZED.toModel()).isEqualTo(StabilizationMode.AUTO) } @Test @@ -210,41 +210,41 @@ class ModelMappersTest { StreamConfig.SINGLE_STREAM.toProto() ).isEqualTo(StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM) assertThat( - StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM.toDomain() + StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM.toModel() ).isEqualTo(StreamConfig.SINGLE_STREAM) assertThat( StreamConfig.MULTI_STREAM.toProto() ).isEqualTo(StreamConfigProto.STREAM_CONFIG_MULTI_STREAM) assertThat( - StreamConfigProto.STREAM_CONFIG_MULTI_STREAM.toDomain() + StreamConfigProto.STREAM_CONFIG_MULTI_STREAM.toModel() ).isEqualTo(StreamConfig.MULTI_STREAM) - assertThat(StreamConfigProto.UNRECOGNIZED.toDomain()).isEqualTo(StreamConfig.MULTI_STREAM) + assertThat(StreamConfigProto.UNRECOGNIZED.toModel()).isEqualTo(StreamConfig.MULTI_STREAM) } @Test fun videoQualityMapsCorrectly() { assertThat(VideoQuality.SD.toProto()).isEqualTo(VideoQualityProto.VIDEO_QUALITY_SD) - assertThat(VideoQualityProto.VIDEO_QUALITY_SD.toDomain()).isEqualTo(VideoQuality.SD) + assertThat(VideoQualityProto.VIDEO_QUALITY_SD.toModel()).isEqualTo(VideoQuality.SD) assertThat(VideoQuality.HD.toProto()).isEqualTo(VideoQualityProto.VIDEO_QUALITY_HD) - assertThat(VideoQualityProto.VIDEO_QUALITY_HD.toDomain()).isEqualTo(VideoQuality.HD) + assertThat(VideoQualityProto.VIDEO_QUALITY_HD.toModel()).isEqualTo(VideoQuality.HD) assertThat(VideoQuality.FHD.toProto()).isEqualTo(VideoQualityProto.VIDEO_QUALITY_FHD) - assertThat(VideoQualityProto.VIDEO_QUALITY_FHD.toDomain()).isEqualTo(VideoQuality.FHD) + assertThat(VideoQualityProto.VIDEO_QUALITY_FHD.toModel()).isEqualTo(VideoQuality.FHD) assertThat(VideoQuality.UHD.toProto()).isEqualTo(VideoQualityProto.VIDEO_QUALITY_UHD) - assertThat(VideoQualityProto.VIDEO_QUALITY_UHD.toDomain()).isEqualTo(VideoQuality.UHD) + assertThat(VideoQualityProto.VIDEO_QUALITY_UHD.toModel()).isEqualTo(VideoQuality.UHD) assertThat( VideoQuality.UNSPECIFIED.toProto() ).isEqualTo(VideoQualityProto.VIDEO_QUALITY_UNSPECIFIED) assertThat( - VideoQualityProto.VIDEO_QUALITY_UNSPECIFIED.toDomain() + VideoQualityProto.VIDEO_QUALITY_UNSPECIFIED.toModel() ).isEqualTo(VideoQuality.UNSPECIFIED) - assertThat(VideoQualityProto.UNRECOGNIZED.toDomain()).isEqualTo(VideoQuality.UNSPECIFIED) + assertThat(VideoQualityProto.UNRECOGNIZED.toModel()).isEqualTo(VideoQuality.UNSPECIFIED) } @Test @@ -253,18 +253,18 @@ class ModelMappersTest { ConcurrentCameraMode.DUAL.toProto() ).isEqualTo(ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_DUAL) assertThat( - ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_DUAL.toDomain() + ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_DUAL.toModel() ).isEqualTo(ConcurrentCameraMode.DUAL) assertThat( ConcurrentCameraMode.OFF.toProto() ).isEqualTo(ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_OFF) assertThat( - ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_OFF.toDomain() + ConcurrentCameraModeProto.CONCURRENT_CAMERA_MODE_OFF.toModel() ).isEqualTo(ConcurrentCameraMode.OFF) assertThat( - ConcurrentCameraModeProto.UNRECOGNIZED.toDomain() + ConcurrentCameraModeProto.UNRECOGNIZED.toModel() ).isEqualTo(ConcurrentCameraMode.OFF) } } diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt index 2c2f572c0..ee1ac7dca 100644 --- a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt @@ -55,11 +55,11 @@ class ProtoDataStoreSettingsDataSource( } override val defaultCameraAppSettings: Flow = jcaSettingsFlow.map { - it.toDomain() + it.toModel() } override suspend fun getCurrentDefaultCameraAppSettings(): CameraAppSettings = - jcaSettingsFlow.first().toDomain() + jcaSettingsFlow.first().toModel() override suspend fun updateDefaultLensFacing(lensFacing: LensFacing) { jcaSettings.updateData { currentSettings -> diff --git a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt index a2703b713..f9e34386b 100644 --- a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt +++ b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt @@ -15,28 +15,28 @@ */ package com.google.jetpackcamera.settings -import com.google.jetpackcamera.model.proto.toDomain +import com.google.jetpackcamera.model.proto.toModel import com.google.jetpackcamera.settings.model.CameraAppSettings import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSettingsProto /** * Maps a [CameraAppSettingsProto] to a [CameraAppSettings] domain model. */ -fun CameraAppSettingsProto.toDomain(): CameraAppSettings { +fun CameraAppSettingsProto.toModel(): CameraAppSettings { return CameraAppSettings( - cameraLensFacing = this.defaultLensFacing.toDomain(), - flashMode = this.flashModeStatus.toDomain(), + cameraLensFacing = this.defaultLensFacing.toModel(), + flashMode = this.flashModeStatus.toModel(), targetFrameRate = this.targetFrameRate, - aspectRatio = this.aspectRatioStatus.toDomain(), - streamConfig = this.streamConfigStatus.toDomain(), - stabilizationMode = this.stabilizationMode.toDomain(), - dynamicRange = this.dynamicRangeStatus.toDomain(), - imageFormat = this.imageFormatStatus.toDomain(), + aspectRatio = this.aspectRatioStatus.toModel(), + streamConfig = this.streamConfigStatus.toModel(), + stabilizationMode = this.stabilizationMode.toModel(), + dynamicRange = this.dynamicRangeStatus.toModel(), + imageFormat = this.imageFormatStatus.toModel(), maxVideoDurationMillis = this.maxVideoDurationMillis, - videoQuality = this.videoQuality.toDomain(), + videoQuality = this.videoQuality.toModel(), audioEnabled = this.audioEnabledStatus, - lowLightBoostPriority = this.lowLightBoostPriority.toDomain(), - darkMode = this.darkModeStatus.toDomain(), - concurrentCameraMode = this.concurrentCameraModeStatus.toDomain() + lowLightBoostPriority = this.lowLightBoostPriority.toModel(), + darkMode = this.darkModeStatus.toModel(), + concurrentCameraMode = this.concurrentCameraModeStatus.toModel() ) } From 05d22273b09b119ddc7f2b473e1e9359e9ff88f3 Mon Sep 17 00:00:00 2001 From: Trevor McGuire Date: Tue, 30 Jun 2026 19:54:59 +0000 Subject: [PATCH 09/14] refactor: inject ioDispatcher into DataStore and construct CoroutineScope internally --- .../java/com/google/jetpackcamera/AppSettingsModule.kt | 7 +++++-- .../datastoreprefs/PrefsDataStoreSettingsDataSource.kt | 9 ++++++++- .../settings/ProtoDataStoreSettingsDataSource.kt | 8 +++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt b/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt index 4a4336e5a..f458e0416 100644 --- a/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt +++ b/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt @@ -17,6 +17,7 @@ package com.google.jetpackcamera import android.content.Context import com.google.jetpackcamera.core.common.DefaultCaptureModeOverride +import com.google.jetpackcamera.core.common.IODispatcher import com.google.jetpackcamera.model.CaptureMode import com.google.jetpackcamera.settings.ProtoDataStoreSettingsDataSource import com.google.jetpackcamera.settings.SettingsDataSource @@ -26,6 +27,7 @@ import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import javax.inject.Singleton +import kotlinx.coroutines.CoroutineDispatcher @Module @InstallIn(SingletonComponent::class) @@ -35,8 +37,9 @@ object AppSettingsModule { @Singleton fun provideSettingsDataSource( @ApplicationContext context: Context, - @DefaultCaptureModeOverride defaultCaptureMode: CaptureMode + @DefaultCaptureModeOverride defaultCaptureMode: CaptureMode, + @IODispatcher ioDispatcher: CoroutineDispatcher ): SettingsDataSource { - return ProtoDataStoreSettingsDataSource.create(context) + return ProtoDataStoreSettingsDataSource.create(context, ioDispatcher) } } diff --git a/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt b/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt index f69b43c33..4bd95c0c2 100644 --- a/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt +++ b/core/settings/datastore-prefs/src/main/java/com/google/jetpackcamera/core/settings/datastoreprefs/PrefsDataStoreSettingsDataSource.kt @@ -35,6 +35,9 @@ import com.google.jetpackcamera.model.UNLIMITED_VIDEO_DURATION import com.google.jetpackcamera.model.VideoQuality import com.google.jetpackcamera.settings.SettingsDataSource import com.google.jetpackcamera.settings.model.CameraAppSettings +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map @@ -174,13 +177,17 @@ class PrefsDataStoreSettingsDataSource( * * @param context The application context. * @param defaultCaptureModeOverride The default capture mode override. + * @param ioDispatcher The coroutine dispatcher for IO operations. * @return A [SettingsDataSource] instance. */ fun create( context: android.content.Context, - defaultCaptureModeOverride: CaptureMode + defaultCaptureModeOverride: CaptureMode, + ioDispatcher: CoroutineDispatcher ): SettingsDataSource { + val scope = CoroutineScope(ioDispatcher + SupervisorJob()) val dataStore = androidx.datastore.preferences.core.PreferenceDataStoreFactory.create( + scope = scope, produceFile = { java.io.File( context.filesDir, diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt index ee1ac7dca..127ccbfd4 100644 --- a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSource.kt @@ -33,6 +33,9 @@ import com.google.jetpackcamera.model.proto.toProto import com.google.jetpackcamera.settings.model.CameraAppSettings import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSettingsProto import java.io.File +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.first @@ -184,11 +187,14 @@ class ProtoDataStoreSettingsDataSource( * instance as a Singleton via dependency injection). * * @param context The application context. + * @param ioDispatcher The coroutine dispatcher for IO operations. * @return A [SettingsDataSource] instance. */ - fun create(context: Context): SettingsDataSource { + fun create(context: Context, ioDispatcher: CoroutineDispatcher): SettingsDataSource { + val scope = CoroutineScope(ioDispatcher + SupervisorJob()) val dataStore = DataStoreFactory.create( serializer = ProtoCameraAppSettingsSerializer, + scope = scope, produceFile = { File(context.filesDir, "datastore/$FILE_LOCATION") } ) return ProtoDataStoreSettingsDataSource(dataStore) From 2aea3007df51609f18f34da4aba641a33b676800 Mon Sep 17 00:00:00 2001 From: Jetski Date: Wed, 15 Jul 2026 22:43:38 +0000 Subject: [PATCH 10/14] Fix merge conflicts: remove StreamConfig and add missing CameraEffectId and CaptureMode parameters --- .../google/jetpackcamera/AppSettingsModule.kt | 2 +- .../jetpackcamera/model/proto/ModelMappers.kt | 24 - .../model/proto/stream_config.proto | 26 - .../model/proto/ModelMappersTest.kt | 21 - .../ProtoCameraAppSettingsSerializer.kt | 2 - .../ProtoDataStoreSettingsDataSource.kt | 22 +- .../jetpackcamera/settings/SettingsMappers.kt | 9 +- .../settings/camera_app_settings.proto | 3 +- pr537.diff | 718 ++++++++++++++++++ 9 files changed, 741 insertions(+), 86 deletions(-) delete mode 100644 core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto create mode 100644 pr537.diff diff --git a/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt b/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt index f458e0416..aacd9760c 100644 --- a/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt +++ b/app/src/main/java/com/google/jetpackcamera/AppSettingsModule.kt @@ -40,6 +40,6 @@ object AppSettingsModule { @DefaultCaptureModeOverride defaultCaptureMode: CaptureMode, @IODispatcher ioDispatcher: CoroutineDispatcher ): SettingsDataSource { - return ProtoDataStoreSettingsDataSource.create(context, ioDispatcher) + return ProtoDataStoreSettingsDataSource.create(context, defaultCaptureMode, ioDispatcher) } } diff --git a/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt b/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt index 5b9424210..43248ac33 100644 --- a/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt +++ b/core/model-proto/src/main/java/com/google/jetpackcamera/model/proto/ModelMappers.kt @@ -24,7 +24,6 @@ import com.google.jetpackcamera.model.ImageOutputFormat import com.google.jetpackcamera.model.LensFacing import com.google.jetpackcamera.model.LowLightBoostPriority import com.google.jetpackcamera.model.StabilizationMode -import com.google.jetpackcamera.model.StreamConfig import com.google.jetpackcamera.model.VideoQuality import com.google.jetpackcamera.model.proto.AspectRatio as AspectRatioProto import com.google.jetpackcamera.model.proto.ConcurrentCameraMode as ConcurrentCameraModeProto @@ -35,7 +34,6 @@ import com.google.jetpackcamera.model.proto.ImageOutputFormat as ImageOutputForm 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.StreamConfig as StreamConfigProto import com.google.jetpackcamera.model.proto.VideoQuality as VideoQualityProto /** @@ -233,28 +231,6 @@ fun StabilizationMode.toProto(): StabilizationModeProto { } } -/** - * Maps a Proto model to a Domain model. - */ -fun StreamConfigProto.toModel(): StreamConfig { - return when (this) { - StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM -> StreamConfig.SINGLE_STREAM - StreamConfigProto.STREAM_CONFIG_MULTI_STREAM, - StreamConfigProto.STREAM_CONFIG_UNSPECIFIED, - StreamConfigProto.UNRECOGNIZED -> StreamConfig.MULTI_STREAM - } -} - -/** - * Maps a Domain model to a Proto model. - */ -fun StreamConfig.toProto(): StreamConfigProto { - return when (this) { - StreamConfig.SINGLE_STREAM -> StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM - StreamConfig.MULTI_STREAM -> StreamConfigProto.STREAM_CONFIG_MULTI_STREAM - } -} - /** * Maps a Proto model to a Domain model. */ diff --git a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto b/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto deleted file mode 100644 index d17ca768f..000000000 --- a/core/model-proto/src/main/proto/com/google/jetpackcamera/model/proto/stream_config.proto +++ /dev/null @@ -1,26 +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. - */ - -syntax = "proto3"; - -option java_package = "com.google.jetpackcamera.model.proto"; -option java_multiple_files = true; - -enum StreamConfig { - STREAM_CONFIG_UNSPECIFIED = 0; - STREAM_CONFIG_MULTI_STREAM = 1; - STREAM_CONFIG_SINGLE_STREAM = 2; -} \ No newline at end of file diff --git a/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt b/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt index 4ce705fb9..4c25cbf24 100644 --- a/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt +++ b/core/model-proto/src/test/java/com/google/jetpackcamera/model/proto/ModelMappersTest.kt @@ -25,7 +25,6 @@ import com.google.jetpackcamera.model.ImageOutputFormat import com.google.jetpackcamera.model.LensFacing import com.google.jetpackcamera.model.LowLightBoostPriority import com.google.jetpackcamera.model.StabilizationMode -import com.google.jetpackcamera.model.StreamConfig import com.google.jetpackcamera.model.VideoQuality import com.google.jetpackcamera.model.proto.AspectRatio as AspectRatioProto import com.google.jetpackcamera.model.proto.ConcurrentCameraMode as ConcurrentCameraModeProto @@ -36,7 +35,6 @@ import com.google.jetpackcamera.model.proto.ImageOutputFormat as ImageOutputForm 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.StreamConfig as StreamConfigProto import com.google.jetpackcamera.model.proto.VideoQuality as VideoQualityProto import org.junit.Test import org.junit.runner.RunWith @@ -204,25 +202,6 @@ class ModelMappersTest { assertThat(StabilizationModeProto.UNRECOGNIZED.toModel()).isEqualTo(StabilizationMode.AUTO) } - @Test - fun streamConfigMapsCorrectly() { - assertThat( - StreamConfig.SINGLE_STREAM.toProto() - ).isEqualTo(StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM) - assertThat( - StreamConfigProto.STREAM_CONFIG_SINGLE_STREAM.toModel() - ).isEqualTo(StreamConfig.SINGLE_STREAM) - - assertThat( - StreamConfig.MULTI_STREAM.toProto() - ).isEqualTo(StreamConfigProto.STREAM_CONFIG_MULTI_STREAM) - assertThat( - StreamConfigProto.STREAM_CONFIG_MULTI_STREAM.toModel() - ).isEqualTo(StreamConfig.MULTI_STREAM) - - assertThat(StreamConfigProto.UNRECOGNIZED.toModel()).isEqualTo(StreamConfig.MULTI_STREAM) - } - @Test fun videoQualityMapsCorrectly() { assertThat(VideoQuality.SD.toProto()).isEqualTo(VideoQualityProto.VIDEO_QUALITY_SD) diff --git a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt index eae2435a8..527f3c592 100644 --- a/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt +++ b/core/settings/datastore-proto/src/main/java/com/google/jetpackcamera/settings/ProtoCameraAppSettingsSerializer.kt @@ -28,7 +28,6 @@ import com.google.jetpackcamera.model.proto.ImageOutputFormat import com.google.jetpackcamera.model.proto.LensFacing import com.google.jetpackcamera.model.proto.LowLightBoostPriority as LowLightBoostPriorityProto 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.proto.CameraAppSettings as CameraAppSettingsProto import com.google.protobuf.InvalidProtocolBufferException @@ -45,7 +44,6 @@ internal object ProtoCameraAppSettingsSerializer : Serializer + private val jcaSettings: DataStore, + private val defaultCaptureModeOverride: CaptureMode ) : SettingsDataSource { private val jcaSettingsFlow: Flow = @@ -58,11 +60,11 @@ class ProtoDataStoreSettingsDataSource( } override val defaultCameraAppSettings: Flow = jcaSettingsFlow.map { - it.toModel() + it.toModel(defaultCaptureModeOverride) } override suspend fun getCurrentDefaultCameraAppSettings(): CameraAppSettings = - jcaSettingsFlow.first().toModel() + jcaSettingsFlow.first().toModel(defaultCaptureModeOverride) override suspend fun updateDefaultLensFacing(lensFacing: LensFacing) { jcaSettings.updateData { currentSettings -> @@ -96,10 +98,10 @@ class ProtoDataStoreSettingsDataSource( } } - override suspend fun updateStreamConfig(streamConfig: StreamConfig) { + override suspend fun updateSelectedCameraEffect(selectedCameraEffect: CameraEffectId) { jcaSettings.updateData { currentSettings -> currentSettings.toBuilder() - .setStreamConfigStatus(streamConfig.toProto()) + .setSelectedCameraEffect(selectedCameraEffect.value) .build() } } @@ -190,14 +192,18 @@ class ProtoDataStoreSettingsDataSource( * @param ioDispatcher The coroutine dispatcher for IO operations. * @return A [SettingsDataSource] instance. */ - fun create(context: Context, ioDispatcher: CoroutineDispatcher): SettingsDataSource { + fun create( + context: Context, + defaultCaptureModeOverride: CaptureMode, + ioDispatcher: CoroutineDispatcher + ): SettingsDataSource { val scope = CoroutineScope(ioDispatcher + SupervisorJob()) val dataStore = DataStoreFactory.create( serializer = ProtoCameraAppSettingsSerializer, scope = scope, produceFile = { File(context.filesDir, "datastore/$FILE_LOCATION") } ) - return ProtoDataStoreSettingsDataSource(dataStore) + return ProtoDataStoreSettingsDataSource(dataStore, defaultCaptureModeOverride) } } } diff --git a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt index f9e34386b..c70c4593c 100644 --- a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt +++ b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt @@ -15,6 +15,9 @@ */ package com.google.jetpackcamera.settings +import com.google.jetpackcamera.model.CameraEffectId +import com.google.jetpackcamera.model.CaptureMode +import com.google.jetpackcamera.model.NONE_EFFECT_ID import com.google.jetpackcamera.model.proto.toModel import com.google.jetpackcamera.settings.model.CameraAppSettings import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSettingsProto @@ -22,13 +25,15 @@ import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSet /** * Maps a [CameraAppSettingsProto] to a [CameraAppSettings] domain model. */ -fun CameraAppSettingsProto.toModel(): CameraAppSettings { +fun CameraAppSettingsProto.toModel(defaultCaptureModeOverride: CaptureMode): CameraAppSettings { return CameraAppSettings( + captureMode = defaultCaptureModeOverride, + selectedCameraEffect = if (this.selectedCameraEffect.isEmpty()) NONE_EFFECT_ID else CameraEffectId(this.selectedCameraEffect), + cameraLensFacing = this.defaultLensFacing.toModel(), flashMode = this.flashModeStatus.toModel(), targetFrameRate = this.targetFrameRate, aspectRatio = this.aspectRatioStatus.toModel(), - streamConfig = this.streamConfigStatus.toModel(), stabilizationMode = this.stabilizationMode.toModel(), dynamicRange = this.dynamicRangeStatus.toModel(), imageFormat = this.imageFormatStatus.toModel(), diff --git a/core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto b/core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto index 584f95105..9400cda6d 100644 --- a/core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto +++ b/core/settings/settings-proto/src/main/proto/com/google/jetpackcamera/settings/camera_app_settings.proto @@ -17,7 +17,6 @@ syntax = "proto3"; import "com/google/jetpackcamera/model/proto/aspect_ratio.proto"; -import "com/google/jetpackcamera/model/proto/stream_config.proto"; import "com/google/jetpackcamera/model/proto/dark_mode.proto"; import "com/google/jetpackcamera/model/proto/dynamic_range.proto"; import "com/google/jetpackcamera/model/proto/flash_mode.proto"; @@ -38,7 +37,6 @@ message CameraAppSettings { FlashMode flash_mode_status = 2; int32 target_frame_rate = 3; AspectRatio aspect_ratio_status = 4; - StreamConfig stream_config_status = 5; StabilizationMode stabilization_mode = 6; DynamicRange dynamic_range_status = 8; ImageOutputFormat image_format_status = 10; @@ -50,4 +48,5 @@ message CameraAppSettings { // Non-camera app settings DarkMode dark_mode_status = 9; ConcurrentCameraMode concurrent_camera_mode_status = 15; + string selected_camera_effect = 16; } diff --git a/pr537.diff b/pr537.diff new file mode 100644 index 000000000..0e6461f2c --- /dev/null +++ b/pr537.diff @@ -0,0 +1,718 @@ +diff --git a/app/build.gradle.kts b/app/build.gradle.kts +index 2e67075a4..895593394 100644 +--- a/app/build.gradle.kts ++++ b/app/build.gradle.kts +@@ -101,6 +101,7 @@ android { + dependencies { + implementation(libs.androidx.tracing) + implementation(project(":core:common")) ++ implementation(project(":data:common")) + implementation(project(":feature:postcapture")) + // Compose + val composeBom = platform(libs.compose.bom) +@@ -178,7 +179,11 @@ dependencies { + implementation(project(":ui:debug")) + + // Low Light implementations +- implementation(project(":core:camera:low-light-playservices")) ++ implementation(project(":data:camera:low-light")) ++ implementation(project(":data:camera:low-light-playservices")) ++ ++ // Postprocess implementations ++ implementation(project(":data:camera:postprocess")) + } + + // Allow references to generated code +diff --git a/core/camera/low-light/build.gradle.kts b/core/camera/low-light/build.gradle.kts +index cade65c9e..52776e2fa 100644 +--- a/core/camera/low-light/build.gradle.kts ++++ b/core/camera/low-light/build.gradle.kts +@@ -17,8 +17,6 @@ + plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) +- alias(libs.plugins.kotlin.kapt) +- alias(libs.plugins.dagger.hilt.android) + } + + android { +@@ -40,12 +38,5 @@ android { + + dependencies { + implementation(libs.camera.core) +- implementation(libs.dagger.hilt.android) +- kapt(libs.dagger.hilt.compiler) + implementation(libs.kotlinx.coroutines.core) + } +- +-// Allow references to generated code +-kapt { +- correctErrorTypes = true +-} +diff --git a/core/camera/postprocess/build.gradle.kts b/core/camera/postprocess/build.gradle.kts +index ceedef0b7..38692d709 100644 +--- a/core/camera/postprocess/build.gradle.kts ++++ b/core/camera/postprocess/build.gradle.kts +@@ -17,8 +17,6 @@ + plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) +- alias(libs.plugins.kotlin.kapt) +- alias(libs.plugins.dagger.hilt.android) + } + + android { +@@ -37,13 +35,3 @@ android { + jvmToolchain(17) + } + } +- +-dependencies { +- implementation(libs.dagger.hilt.android) +- kapt(libs.dagger.hilt.compiler) +-} +- +-// Allow references to generated code +-kapt { +- correctErrorTypes = true +-} +diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts +index 185217b27..dce5d45b2 100644 +--- a/core/common/build.gradle.kts ++++ b/core/common/build.gradle.kts +@@ -17,8 +17,6 @@ + plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) +- alias(libs.plugins.kotlin.kapt) +- alias(libs.plugins.dagger.hilt.android) + } + + android { +@@ -69,6 +67,7 @@ dependencies { + implementation(libs.androidx.appcompat) + implementation(libs.kotlinx.atomicfu) + implementation(libs.androidx.tracing) ++ implementation("javax.inject:javax.inject:1") + + testImplementation(libs.junit) + testImplementation(libs.truth) +@@ -77,11 +76,4 @@ dependencies { + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + +- // Hilt +- implementation(libs.dagger.hilt.android) +- kapt(libs.dagger.hilt.compiler) +-} +- +-kapt { +- correctErrorTypes = true + } +diff --git a/core/common/src/main/java/com/google/jetpackcamera/core/common/CommonQualifiers.kt b/core/common/src/main/java/com/google/jetpackcamera/core/common/CommonQualifiers.kt +new file mode 100644 +index 000000000..20c11cf6d +--- /dev/null ++++ b/core/common/src/main/java/com/google/jetpackcamera/core/common/CommonQualifiers.kt +@@ -0,0 +1,61 @@ ++/* ++ * 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.core.common ++ ++import javax.inject.Qualifier ++ ++/** ++ * Qualifier for the default file path generator. ++ */ ++@Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER) ++@Qualifier ++@Retention(AnnotationRetention.BINARY) ++annotation class DefaultFilePathGenerator ++ ++/** ++ * Qualifier for the default capture mode override in LocalSettingsRepository. ++ */ ++@Qualifier ++@Retention(AnnotationRetention.BINARY) ++annotation class DefaultCaptureModeOverride ++ ++/** ++ * Qualifier for the default save mode. ++ */ ++@Qualifier ++@Retention(AnnotationRetention.BINARY) ++annotation class DefaultSaveMode ++ ++/** ++ * Qualifier for the default coroutine dispatcher. ++ */ ++@Qualifier ++@Retention(AnnotationRetention.BINARY) ++annotation class DefaultDispatcher ++ ++/** ++ * Qualifier for the IO coroutine dispatcher. ++ */ ++@Qualifier ++@Retention(AnnotationRetention.BINARY) ++annotation class IODispatcher ++ ++/** ++ * Qualifier for the default application-level coroutine scope. ++ */ ++@Qualifier ++@Retention(AnnotationRetention.BINARY) ++annotation class DefaultCoroutineScope +diff --git a/core/settings/build.gradle.kts b/core/settings/build.gradle.kts +index 35c256a56..a5c778046 100644 +--- a/core/settings/build.gradle.kts ++++ b/core/settings/build.gradle.kts +@@ -17,8 +17,6 @@ + plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) +- alias(libs.plugins.kotlin.kapt) +- alias(libs.plugins.dagger.hilt.android) + } + + android { +@@ -46,14 +44,6 @@ android { + dependencies { + implementation(libs.kotlinx.coroutines.core) + +- // Hilt +- implementation(libs.dagger.hilt.android) +- kapt(libs.dagger.hilt.compiler) +- + // Domain models + implementation(project(":core:model")) + } +- +-kapt { +- correctErrorTypes = true +-} +diff --git a/core/settings/datastore-prefs/build.gradle.kts b/core/settings/datastore-prefs/build.gradle.kts +index c0ca9f8d4..c4da99bd2 100644 +--- a/core/settings/datastore-prefs/build.gradle.kts ++++ b/core/settings/datastore-prefs/build.gradle.kts +@@ -77,6 +77,7 @@ dependencies { + // Access Model and Settings Interface + implementation(project(":core:model")) + implementation(project(":core:common")) ++ implementation(project(":data:common")) + implementation(project(":core:settings")) + } + +diff --git a/data/camera/build.gradle.kts b/data/camera/build.gradle.kts +index 8a541423a..711221739 100644 +--- a/data/camera/build.gradle.kts ++++ b/data/camera/build.gradle.kts +@@ -71,6 +71,7 @@ dependencies { + implementation(project(":core:camera:low-light")) + implementation(project(":core:camera:postprocess")) + implementation(project(":core:common")) ++ implementation(project(":data:common")) + implementation(project(":core:model")) + implementation(project(":data:settings")) + implementation(project(":core:settings")) +diff --git a/core/camera/low-light-playservices/build.gradle.kts b/data/camera/low-light-playservices/build.gradle.kts +similarity index 96% +rename from core/camera/low-light-playservices/build.gradle.kts +rename to data/camera/low-light-playservices/build.gradle.kts +index 639fa3e51..d21b0d52a 100644 +--- a/core/camera/low-light-playservices/build.gradle.kts ++++ b/data/camera/low-light-playservices/build.gradle.kts +@@ -22,7 +22,7 @@ plugins { + } + + android { +- namespace = "com.google.jetpackcamera.core.camera.lowlight.playservices" ++ namespace = "com.google.jetpackcamera.data.camera.lowlight.playservices" + compileSdk = libs.versions.compileSdk.get().toInt() + + defaultConfig { +diff --git a/core/camera/low-light-playservices/src/main/AndroidManifest.xml b/data/camera/low-light-playservices/src/main/AndroidManifest.xml +similarity index 100% +rename from core/camera/low-light-playservices/src/main/AndroidManifest.xml +rename to data/camera/low-light-playservices/src/main/AndroidManifest.xml +diff --git a/core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostAvailabilityChecker.kt b/data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostAvailabilityChecker.kt +similarity index 100% +rename from core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostAvailabilityChecker.kt +rename to data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostAvailabilityChecker.kt +diff --git a/core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffect.kt b/data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffect.kt +similarity index 100% +rename from core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffect.kt +rename to data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffect.kt +diff --git a/core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffectProvider.kt b/data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffectProvider.kt +similarity index 100% +rename from core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffectProvider.kt +rename to data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffectProvider.kt +diff --git a/core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostModule.kt b/data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostModule.kt +similarity index 100% +rename from core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostModule.kt +rename to data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostModule.kt +diff --git a/core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostSurfaceProcessor.kt b/data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostSurfaceProcessor.kt +similarity index 100% +rename from core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostSurfaceProcessor.kt +rename to data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostSurfaceProcessor.kt +diff --git a/data/camera/low-light/build.gradle.kts b/data/camera/low-light/build.gradle.kts +new file mode 100644 +index 000000000..1af41b83c +--- /dev/null ++++ b/data/camera/low-light/build.gradle.kts +@@ -0,0 +1,52 @@ ++/* ++ * 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.kotlin.kapt) ++ alias(libs.plugins.dagger.hilt.android) ++} ++ ++android { ++ namespace = "com.google.jetpackcamera.data.camera.lowlight" ++ compileSdk = libs.versions.compileSdk.get().toInt() ++ ++ defaultConfig { ++ minSdk = libs.versions.minSdk.get().toInt() ++ } ++ ++ compileOptions { ++ sourceCompatibility = JavaVersion.VERSION_17 ++ targetCompatibility = JavaVersion.VERSION_17 ++ } ++ kotlin { ++ jvmToolchain(17) ++ } ++} ++ ++dependencies { ++ implementation(project(":core:camera:low-light")) ++ ++ // Hilt ++ implementation(libs.dagger.hilt.android) ++ kapt(libs.dagger.hilt.compiler) ++} ++ ++// Allow references to generated code ++kapt { ++ correctErrorTypes = true ++} +diff --git a/data/camera/low-light/src/main/AndroidManifest.xml b/data/camera/low-light/src/main/AndroidManifest.xml +new file mode 100644 +index 000000000..57317bf89 +--- /dev/null ++++ b/data/camera/low-light/src/main/AndroidManifest.xml +@@ -0,0 +1,18 @@ ++ ++ ++ ++ +diff --git a/core/camera/low-light/src/main/java/com/google/jetpackcamera/core/camera/lowlight/LowLightBoostModule.kt b/data/camera/low-light/src/main/java/com/google/jetpackcamera/data/camera/lowlight/LowLightBoostModule.kt +similarity index 89% +rename from core/camera/low-light/src/main/java/com/google/jetpackcamera/core/camera/lowlight/LowLightBoostModule.kt +rename to data/camera/low-light/src/main/java/com/google/jetpackcamera/data/camera/lowlight/LowLightBoostModule.kt +index 030d18bb6..cf968bb0c 100644 +--- a/core/camera/low-light/src/main/java/com/google/jetpackcamera/core/camera/lowlight/LowLightBoostModule.kt ++++ b/data/camera/low-light/src/main/java/com/google/jetpackcamera/data/camera/lowlight/LowLightBoostModule.kt +@@ -13,8 +13,11 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +-package com.google.jetpackcamera.core.camera.lowlight ++package com.google.jetpackcamera.data.camera.lowlight + ++import com.google.jetpackcamera.core.camera.lowlight.LowLightBoostAvailabilityChecker ++import com.google.jetpackcamera.core.camera.lowlight.LowLightBoostEffectProvider ++import com.google.jetpackcamera.core.camera.lowlight.LowLightBoostFeatureKey + import dagger.Module + import dagger.Provides + import dagger.hilt.InstallIn +diff --git a/data/camera/postprocess/build.gradle.kts b/data/camera/postprocess/build.gradle.kts +new file mode 100644 +index 000000000..94cde397b +--- /dev/null ++++ b/data/camera/postprocess/build.gradle.kts +@@ -0,0 +1,52 @@ ++/* ++ * 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.kotlin.kapt) ++ alias(libs.plugins.dagger.hilt.android) ++} ++ ++android { ++ namespace = "com.google.jetpackcamera.data.camera.postprocess" ++ compileSdk = libs.versions.compileSdk.get().toInt() ++ ++ defaultConfig { ++ minSdk = libs.versions.minSdk.get().toInt() ++ } ++ ++ compileOptions { ++ sourceCompatibility = JavaVersion.VERSION_17 ++ targetCompatibility = JavaVersion.VERSION_17 ++ } ++ kotlin { ++ jvmToolchain(17) ++ } ++} ++ ++dependencies { ++ implementation(project(":core:camera:postprocess")) ++ ++ // Hilt ++ implementation(libs.dagger.hilt.android) ++ kapt(libs.dagger.hilt.compiler) ++} ++ ++// Allow references to generated code ++kapt { ++ correctErrorTypes = true ++} +diff --git a/data/camera/postprocess/src/main/AndroidManifest.xml b/data/camera/postprocess/src/main/AndroidManifest.xml +new file mode 100644 +index 000000000..57317bf89 +--- /dev/null ++++ b/data/camera/postprocess/src/main/AndroidManifest.xml +@@ -0,0 +1,18 @@ ++ ++ ++ ++ +diff --git a/core/camera/postprocess/src/main/java/com/google/jetpackcamera/core/camera/postprocess/PostProcessModule.kt b/data/camera/postprocess/src/main/java/com/google/jetpackcamera/data/camera/postprocess/PostProcessModule.kt +similarity index 88% +rename from core/camera/postprocess/src/main/java/com/google/jetpackcamera/core/camera/postprocess/PostProcessModule.kt +rename to data/camera/postprocess/src/main/java/com/google/jetpackcamera/data/camera/postprocess/PostProcessModule.kt +index d26475400..f7b5f6bdf 100644 +--- a/core/camera/postprocess/src/main/java/com/google/jetpackcamera/core/camera/postprocess/PostProcessModule.kt ++++ b/data/camera/postprocess/src/main/java/com/google/jetpackcamera/data/camera/postprocess/PostProcessModule.kt +@@ -13,8 +13,10 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +-package com.google.jetpackcamera.core.camera.postprocess ++package com.google.jetpackcamera.data.camera.postprocess + ++import com.google.jetpackcamera.core.camera.postprocess.ImagePostProcessor ++import com.google.jetpackcamera.core.camera.postprocess.ImagePostProcessorFeatureKey + import dagger.Module + import dagger.Provides + import dagger.hilt.InstallIn +diff --git a/data/common/build.gradle.kts b/data/common/build.gradle.kts +new file mode 100644 +index 000000000..c95175a5c +--- /dev/null ++++ b/data/common/build.gradle.kts +@@ -0,0 +1,68 @@ ++/* ++ * 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.kotlin.kapt) ++ alias(libs.plugins.dagger.hilt.android) ++} ++ ++android { ++ namespace = "com.google.jetpackcamera.data.common" ++ 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") ++ } ++ ++ flavorDimensions += "flavor" ++ productFlavors { ++ create("stable") { ++ dimension = "flavor" ++ isDefault = true ++ } ++ } ++ ++ compileOptions { ++ sourceCompatibility = JavaVersion.VERSION_17 ++ targetCompatibility = JavaVersion.VERSION_17 ++ } ++ kotlin { ++ jvmToolchain(17) ++ } ++} ++ ++dependencies { ++ implementation(libs.kotlinx.coroutines.core) ++ ++ // Hilt ++ implementation(libs.dagger.hilt.android) ++ kapt(libs.dagger.hilt.compiler) ++ ++ // Project dependencies ++ implementation(project(":core:common")) ++} ++ ++// Allow references to generated code ++kapt { ++ correctErrorTypes = true ++} +diff --git a/data/common/consumer-rules.pro b/data/common/consumer-rules.pro +new file mode 100644 +index 000000000..260809e6c +--- /dev/null ++++ b/data/common/consumer-rules.pro +@@ -0,0 +1 @@ ++# Proguard rules for data:common +diff --git a/data/common/src/main/AndroidManifest.xml b/data/common/src/main/AndroidManifest.xml +new file mode 100644 +index 000000000..57317bf89 +--- /dev/null ++++ b/data/common/src/main/AndroidManifest.xml +@@ -0,0 +1,18 @@ ++ ++ ++ ++ +diff --git a/core/common/src/main/java/com/google/jetpackcamera/core/common/CommonModule.kt b/data/common/src/main/java/com/google/jetpackcamera/data/common/CommonModule.kt +similarity index 63% +rename from core/common/src/main/java/com/google/jetpackcamera/core/common/CommonModule.kt +rename to data/common/src/main/java/com/google/jetpackcamera/data/common/CommonModule.kt +index 998ab951e..da4f7d333 100644 +--- a/core/common/src/main/java/com/google/jetpackcamera/core/common/CommonModule.kt ++++ b/data/common/src/main/java/com/google/jetpackcamera/data/common/CommonModule.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,15 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +-package com.google.jetpackcamera.core.common ++package com.google.jetpackcamera.data.common + ++import com.google.jetpackcamera.core.common.DefaultCoroutineScope ++import com.google.jetpackcamera.core.common.DefaultDispatcher ++import com.google.jetpackcamera.core.common.IODispatcher + import dagger.Module + import dagger.Provides + import dagger.hilt.InstallIn + import dagger.hilt.components.SingletonComponent +-import javax.inject.Qualifier + import javax.inject.Singleton + import kotlinx.coroutines.CoroutineDispatcher + import kotlinx.coroutines.CoroutineScope +@@ -46,31 +48,3 @@ class CommonModule { + fun providesCoroutineScope(@DefaultDispatcher dispatcher: CoroutineDispatcher) = + CoroutineScope(SupervisorJob() + dispatcher) + } +- +-@Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER) +-@Qualifier +-@Retention(AnnotationRetention.BINARY) +-annotation class DefaultFilePathGenerator +- +-/** +- * provides the default [CaptureMode] to override in [LocalSettingsRepository] +- */ +-@Qualifier +-@Retention(AnnotationRetention.BINARY) +-annotation class DefaultCaptureModeOverride +- +-@Qualifier +-@Retention(AnnotationRetention.BINARY) +-annotation class DefaultSaveMode +- +-@Qualifier +-@Retention(AnnotationRetention.BINARY) +-annotation class DefaultDispatcher +- +-@Qualifier +-@Retention(AnnotationRetention.BINARY) +-annotation class IODispatcher +- +-@Qualifier +-@Retention(AnnotationRetention.BINARY) +-annotation class DefaultCoroutineScope +diff --git a/data/media/build.gradle.kts b/data/media/build.gradle.kts +index 91146f6e8..20f9265f0 100644 +--- a/data/media/build.gradle.kts ++++ b/data/media/build.gradle.kts +@@ -89,6 +89,7 @@ dependencies { + + // Project dependencies + implementation(project(":core:common")) ++ implementation(project(":data:common")) + testImplementation(project(":core:common:testing")) + androidTestImplementation(project(":core:common:testing")) + +diff --git a/feature/preview/build.gradle.kts b/feature/preview/build.gradle.kts +index 54ab1c505..8276aa3aa 100644 +--- a/feature/preview/build.gradle.kts ++++ b/feature/preview/build.gradle.kts +@@ -138,6 +138,7 @@ dependencies { + implementation(project(":core:camera")) + implementation(project(":data:camera")) + implementation(project(":core:common")) ++ implementation(project(":data:common")) + implementation(project(":data:media")) + implementation(project(":data:settings")) + implementation(project(":core:settings")) +diff --git a/settings.gradle.kts b/settings.gradle.kts +index 103a86882..2cd5e3aaf 100644 +--- a/settings.gradle.kts ++++ b/settings.gradle.kts +@@ -39,12 +39,14 @@ include(":core:camera") + include(":data:camera") + include(":core:camera:testing") + include(":core:camera:low-light") +-include(":core:camera:low-light-playservices") ++include(":data:camera:low-light") ++include(":data:camera:low-light-playservices") + include(":feature:settings") + include(":data:settings") + include(":data:settings:testing") + include(":data:media") + include(":data:media:testing") ++include(":data:common") + include(":core:common") + include(":core:common:testing") + include(":benchmark") +@@ -62,6 +64,7 @@ include(":core:model") + include(":ui:uistate:postcapture") + include(":ui:uistateadapter:postcapture") + include(":core:camera:postprocess") ++include(":data:camera:postprocess") + include(":ui:controller") + include(":ui:controller:impl") + include(":ui:controller:testing") +diff --git a/ui/components/capture/build.gradle.kts b/ui/components/capture/build.gradle.kts +index d2f9fc5fa..e2f456b45 100644 +--- a/ui/components/capture/build.gradle.kts ++++ b/ui/components/capture/build.gradle.kts +@@ -64,6 +64,9 @@ dependencies { + val composeBom = platform(libs.compose.bom) + implementation(composeBom) + ++ // AndroidX Core KTX ++ implementation(libs.androidx.core.ktx) ++ + // Accompanist - Permissions + implementation(libs.accompanist.permissions) + +@@ -74,9 +77,6 @@ dependencies { + implementation(libs.compose.ui.tooling.preview) + debugImplementation(libs.compose.ui.tooling) + +- // Compose - Integration with ViewModels with Navigation and Hilt +- implementation(libs.hilt.navigation.compose) +- + // CameraX + implementation(libs.camera.core) + implementation(libs.camera.compose) From f826a42270f6f761e8cb8dde90778c04a6f5fb20 Mon Sep 17 00:00:00 2001 From: Jetski Date: Wed, 15 Jul 2026 22:48:17 +0000 Subject: [PATCH 11/14] Fix spotless formatting issues --- .../com/google/jetpackcamera/settings/SettingsMappers.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt index c70c4593c..fdd46fb5b 100644 --- a/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt +++ b/core/settings/settings-proto/src/main/java/com/google/jetpackcamera/settings/SettingsMappers.kt @@ -28,7 +28,11 @@ import com.google.jetpackcamera.settings.proto.CameraAppSettings as CameraAppSet fun CameraAppSettingsProto.toModel(defaultCaptureModeOverride: CaptureMode): CameraAppSettings { return CameraAppSettings( captureMode = defaultCaptureModeOverride, - selectedCameraEffect = if (this.selectedCameraEffect.isEmpty()) NONE_EFFECT_ID else CameraEffectId(this.selectedCameraEffect), + selectedCameraEffect = if (this.selectedCameraEffect.isEmpty()) { + NONE_EFFECT_ID + } else { + CameraEffectId(this.selectedCameraEffect) + }, cameraLensFacing = this.defaultLensFacing.toModel(), flashMode = this.flashModeStatus.toModel(), From 5ec5667e00df85d4841b6d489101ded1a11101b9 Mon Sep 17 00:00:00 2001 From: Jetski Date: Wed, 15 Jul 2026 22:48:27 +0000 Subject: [PATCH 12/14] Remove accidentally committed diff file --- pr537.diff | 718 ----------------------------------------------------- 1 file changed, 718 deletions(-) delete mode 100644 pr537.diff diff --git a/pr537.diff b/pr537.diff deleted file mode 100644 index 0e6461f2c..000000000 --- a/pr537.diff +++ /dev/null @@ -1,718 +0,0 @@ -diff --git a/app/build.gradle.kts b/app/build.gradle.kts -index 2e67075a4..895593394 100644 ---- a/app/build.gradle.kts -+++ b/app/build.gradle.kts -@@ -101,6 +101,7 @@ android { - dependencies { - implementation(libs.androidx.tracing) - implementation(project(":core:common")) -+ implementation(project(":data:common")) - implementation(project(":feature:postcapture")) - // Compose - val composeBom = platform(libs.compose.bom) -@@ -178,7 +179,11 @@ dependencies { - implementation(project(":ui:debug")) - - // Low Light implementations -- implementation(project(":core:camera:low-light-playservices")) -+ implementation(project(":data:camera:low-light")) -+ implementation(project(":data:camera:low-light-playservices")) -+ -+ // Postprocess implementations -+ implementation(project(":data:camera:postprocess")) - } - - // Allow references to generated code -diff --git a/core/camera/low-light/build.gradle.kts b/core/camera/low-light/build.gradle.kts -index cade65c9e..52776e2fa 100644 ---- a/core/camera/low-light/build.gradle.kts -+++ b/core/camera/low-light/build.gradle.kts -@@ -17,8 +17,6 @@ - plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) -- alias(libs.plugins.kotlin.kapt) -- alias(libs.plugins.dagger.hilt.android) - } - - android { -@@ -40,12 +38,5 @@ android { - - dependencies { - implementation(libs.camera.core) -- implementation(libs.dagger.hilt.android) -- kapt(libs.dagger.hilt.compiler) - implementation(libs.kotlinx.coroutines.core) - } -- --// Allow references to generated code --kapt { -- correctErrorTypes = true --} -diff --git a/core/camera/postprocess/build.gradle.kts b/core/camera/postprocess/build.gradle.kts -index ceedef0b7..38692d709 100644 ---- a/core/camera/postprocess/build.gradle.kts -+++ b/core/camera/postprocess/build.gradle.kts -@@ -17,8 +17,6 @@ - plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) -- alias(libs.plugins.kotlin.kapt) -- alias(libs.plugins.dagger.hilt.android) - } - - android { -@@ -37,13 +35,3 @@ android { - jvmToolchain(17) - } - } -- --dependencies { -- implementation(libs.dagger.hilt.android) -- kapt(libs.dagger.hilt.compiler) --} -- --// Allow references to generated code --kapt { -- correctErrorTypes = true --} -diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts -index 185217b27..dce5d45b2 100644 ---- a/core/common/build.gradle.kts -+++ b/core/common/build.gradle.kts -@@ -17,8 +17,6 @@ - plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) -- alias(libs.plugins.kotlin.kapt) -- alias(libs.plugins.dagger.hilt.android) - } - - android { -@@ -69,6 +67,7 @@ dependencies { - implementation(libs.androidx.appcompat) - implementation(libs.kotlinx.atomicfu) - implementation(libs.androidx.tracing) -+ implementation("javax.inject:javax.inject:1") - - testImplementation(libs.junit) - testImplementation(libs.truth) -@@ -77,11 +76,4 @@ dependencies { - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.androidx.espresso.core) - -- // Hilt -- implementation(libs.dagger.hilt.android) -- kapt(libs.dagger.hilt.compiler) --} -- --kapt { -- correctErrorTypes = true - } -diff --git a/core/common/src/main/java/com/google/jetpackcamera/core/common/CommonQualifiers.kt b/core/common/src/main/java/com/google/jetpackcamera/core/common/CommonQualifiers.kt -new file mode 100644 -index 000000000..20c11cf6d ---- /dev/null -+++ b/core/common/src/main/java/com/google/jetpackcamera/core/common/CommonQualifiers.kt -@@ -0,0 +1,61 @@ -+/* -+ * 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.core.common -+ -+import javax.inject.Qualifier -+ -+/** -+ * Qualifier for the default file path generator. -+ */ -+@Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER) -+@Qualifier -+@Retention(AnnotationRetention.BINARY) -+annotation class DefaultFilePathGenerator -+ -+/** -+ * Qualifier for the default capture mode override in LocalSettingsRepository. -+ */ -+@Qualifier -+@Retention(AnnotationRetention.BINARY) -+annotation class DefaultCaptureModeOverride -+ -+/** -+ * Qualifier for the default save mode. -+ */ -+@Qualifier -+@Retention(AnnotationRetention.BINARY) -+annotation class DefaultSaveMode -+ -+/** -+ * Qualifier for the default coroutine dispatcher. -+ */ -+@Qualifier -+@Retention(AnnotationRetention.BINARY) -+annotation class DefaultDispatcher -+ -+/** -+ * Qualifier for the IO coroutine dispatcher. -+ */ -+@Qualifier -+@Retention(AnnotationRetention.BINARY) -+annotation class IODispatcher -+ -+/** -+ * Qualifier for the default application-level coroutine scope. -+ */ -+@Qualifier -+@Retention(AnnotationRetention.BINARY) -+annotation class DefaultCoroutineScope -diff --git a/core/settings/build.gradle.kts b/core/settings/build.gradle.kts -index 35c256a56..a5c778046 100644 ---- a/core/settings/build.gradle.kts -+++ b/core/settings/build.gradle.kts -@@ -17,8 +17,6 @@ - plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) -- alias(libs.plugins.kotlin.kapt) -- alias(libs.plugins.dagger.hilt.android) - } - - android { -@@ -46,14 +44,6 @@ android { - dependencies { - implementation(libs.kotlinx.coroutines.core) - -- // Hilt -- implementation(libs.dagger.hilt.android) -- kapt(libs.dagger.hilt.compiler) -- - // Domain models - implementation(project(":core:model")) - } -- --kapt { -- correctErrorTypes = true --} -diff --git a/core/settings/datastore-prefs/build.gradle.kts b/core/settings/datastore-prefs/build.gradle.kts -index c0ca9f8d4..c4da99bd2 100644 ---- a/core/settings/datastore-prefs/build.gradle.kts -+++ b/core/settings/datastore-prefs/build.gradle.kts -@@ -77,6 +77,7 @@ dependencies { - // Access Model and Settings Interface - implementation(project(":core:model")) - implementation(project(":core:common")) -+ implementation(project(":data:common")) - implementation(project(":core:settings")) - } - -diff --git a/data/camera/build.gradle.kts b/data/camera/build.gradle.kts -index 8a541423a..711221739 100644 ---- a/data/camera/build.gradle.kts -+++ b/data/camera/build.gradle.kts -@@ -71,6 +71,7 @@ dependencies { - implementation(project(":core:camera:low-light")) - implementation(project(":core:camera:postprocess")) - implementation(project(":core:common")) -+ implementation(project(":data:common")) - implementation(project(":core:model")) - implementation(project(":data:settings")) - implementation(project(":core:settings")) -diff --git a/core/camera/low-light-playservices/build.gradle.kts b/data/camera/low-light-playservices/build.gradle.kts -similarity index 96% -rename from core/camera/low-light-playservices/build.gradle.kts -rename to data/camera/low-light-playservices/build.gradle.kts -index 639fa3e51..d21b0d52a 100644 ---- a/core/camera/low-light-playservices/build.gradle.kts -+++ b/data/camera/low-light-playservices/build.gradle.kts -@@ -22,7 +22,7 @@ plugins { - } - - android { -- namespace = "com.google.jetpackcamera.core.camera.lowlight.playservices" -+ namespace = "com.google.jetpackcamera.data.camera.lowlight.playservices" - compileSdk = libs.versions.compileSdk.get().toInt() - - defaultConfig { -diff --git a/core/camera/low-light-playservices/src/main/AndroidManifest.xml b/data/camera/low-light-playservices/src/main/AndroidManifest.xml -similarity index 100% -rename from core/camera/low-light-playservices/src/main/AndroidManifest.xml -rename to data/camera/low-light-playservices/src/main/AndroidManifest.xml -diff --git a/core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostAvailabilityChecker.kt b/data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostAvailabilityChecker.kt -similarity index 100% -rename from core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostAvailabilityChecker.kt -rename to data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostAvailabilityChecker.kt -diff --git a/core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffect.kt b/data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffect.kt -similarity index 100% -rename from core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffect.kt -rename to data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffect.kt -diff --git a/core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffectProvider.kt b/data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffectProvider.kt -similarity index 100% -rename from core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffectProvider.kt -rename to data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostEffectProvider.kt -diff --git a/core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostModule.kt b/data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostModule.kt -similarity index 100% -rename from core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostModule.kt -rename to data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostModule.kt -diff --git a/core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostSurfaceProcessor.kt b/data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostSurfaceProcessor.kt -similarity index 100% -rename from core/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostSurfaceProcessor.kt -rename to data/camera/low-light-playservices/src/main/java/com/google/jetpackcamera/core/camera/lowlight/playservices/PlayServicesLowLightBoostSurfaceProcessor.kt -diff --git a/data/camera/low-light/build.gradle.kts b/data/camera/low-light/build.gradle.kts -new file mode 100644 -index 000000000..1af41b83c ---- /dev/null -+++ b/data/camera/low-light/build.gradle.kts -@@ -0,0 +1,52 @@ -+/* -+ * 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.kotlin.kapt) -+ alias(libs.plugins.dagger.hilt.android) -+} -+ -+android { -+ namespace = "com.google.jetpackcamera.data.camera.lowlight" -+ compileSdk = libs.versions.compileSdk.get().toInt() -+ -+ defaultConfig { -+ minSdk = libs.versions.minSdk.get().toInt() -+ } -+ -+ compileOptions { -+ sourceCompatibility = JavaVersion.VERSION_17 -+ targetCompatibility = JavaVersion.VERSION_17 -+ } -+ kotlin { -+ jvmToolchain(17) -+ } -+} -+ -+dependencies { -+ implementation(project(":core:camera:low-light")) -+ -+ // Hilt -+ implementation(libs.dagger.hilt.android) -+ kapt(libs.dagger.hilt.compiler) -+} -+ -+// Allow references to generated code -+kapt { -+ correctErrorTypes = true -+} -diff --git a/data/camera/low-light/src/main/AndroidManifest.xml b/data/camera/low-light/src/main/AndroidManifest.xml -new file mode 100644 -index 000000000..57317bf89 ---- /dev/null -+++ b/data/camera/low-light/src/main/AndroidManifest.xml -@@ -0,0 +1,18 @@ -+ -+ -+ -+ -diff --git a/core/camera/low-light/src/main/java/com/google/jetpackcamera/core/camera/lowlight/LowLightBoostModule.kt b/data/camera/low-light/src/main/java/com/google/jetpackcamera/data/camera/lowlight/LowLightBoostModule.kt -similarity index 89% -rename from core/camera/low-light/src/main/java/com/google/jetpackcamera/core/camera/lowlight/LowLightBoostModule.kt -rename to data/camera/low-light/src/main/java/com/google/jetpackcamera/data/camera/lowlight/LowLightBoostModule.kt -index 030d18bb6..cf968bb0c 100644 ---- a/core/camera/low-light/src/main/java/com/google/jetpackcamera/core/camera/lowlight/LowLightBoostModule.kt -+++ b/data/camera/low-light/src/main/java/com/google/jetpackcamera/data/camera/lowlight/LowLightBoostModule.kt -@@ -13,8 +13,11 @@ - * See the License for the specific language governing permissions and - * limitations under the License. - */ --package com.google.jetpackcamera.core.camera.lowlight -+package com.google.jetpackcamera.data.camera.lowlight - -+import com.google.jetpackcamera.core.camera.lowlight.LowLightBoostAvailabilityChecker -+import com.google.jetpackcamera.core.camera.lowlight.LowLightBoostEffectProvider -+import com.google.jetpackcamera.core.camera.lowlight.LowLightBoostFeatureKey - import dagger.Module - import dagger.Provides - import dagger.hilt.InstallIn -diff --git a/data/camera/postprocess/build.gradle.kts b/data/camera/postprocess/build.gradle.kts -new file mode 100644 -index 000000000..94cde397b ---- /dev/null -+++ b/data/camera/postprocess/build.gradle.kts -@@ -0,0 +1,52 @@ -+/* -+ * 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.kotlin.kapt) -+ alias(libs.plugins.dagger.hilt.android) -+} -+ -+android { -+ namespace = "com.google.jetpackcamera.data.camera.postprocess" -+ compileSdk = libs.versions.compileSdk.get().toInt() -+ -+ defaultConfig { -+ minSdk = libs.versions.minSdk.get().toInt() -+ } -+ -+ compileOptions { -+ sourceCompatibility = JavaVersion.VERSION_17 -+ targetCompatibility = JavaVersion.VERSION_17 -+ } -+ kotlin { -+ jvmToolchain(17) -+ } -+} -+ -+dependencies { -+ implementation(project(":core:camera:postprocess")) -+ -+ // Hilt -+ implementation(libs.dagger.hilt.android) -+ kapt(libs.dagger.hilt.compiler) -+} -+ -+// Allow references to generated code -+kapt { -+ correctErrorTypes = true -+} -diff --git a/data/camera/postprocess/src/main/AndroidManifest.xml b/data/camera/postprocess/src/main/AndroidManifest.xml -new file mode 100644 -index 000000000..57317bf89 ---- /dev/null -+++ b/data/camera/postprocess/src/main/AndroidManifest.xml -@@ -0,0 +1,18 @@ -+ -+ -+ -+ -diff --git a/core/camera/postprocess/src/main/java/com/google/jetpackcamera/core/camera/postprocess/PostProcessModule.kt b/data/camera/postprocess/src/main/java/com/google/jetpackcamera/data/camera/postprocess/PostProcessModule.kt -similarity index 88% -rename from core/camera/postprocess/src/main/java/com/google/jetpackcamera/core/camera/postprocess/PostProcessModule.kt -rename to data/camera/postprocess/src/main/java/com/google/jetpackcamera/data/camera/postprocess/PostProcessModule.kt -index d26475400..f7b5f6bdf 100644 ---- a/core/camera/postprocess/src/main/java/com/google/jetpackcamera/core/camera/postprocess/PostProcessModule.kt -+++ b/data/camera/postprocess/src/main/java/com/google/jetpackcamera/data/camera/postprocess/PostProcessModule.kt -@@ -13,8 +13,10 @@ - * See the License for the specific language governing permissions and - * limitations under the License. - */ --package com.google.jetpackcamera.core.camera.postprocess -+package com.google.jetpackcamera.data.camera.postprocess - -+import com.google.jetpackcamera.core.camera.postprocess.ImagePostProcessor -+import com.google.jetpackcamera.core.camera.postprocess.ImagePostProcessorFeatureKey - import dagger.Module - import dagger.Provides - import dagger.hilt.InstallIn -diff --git a/data/common/build.gradle.kts b/data/common/build.gradle.kts -new file mode 100644 -index 000000000..c95175a5c ---- /dev/null -+++ b/data/common/build.gradle.kts -@@ -0,0 +1,68 @@ -+/* -+ * 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.kotlin.kapt) -+ alias(libs.plugins.dagger.hilt.android) -+} -+ -+android { -+ namespace = "com.google.jetpackcamera.data.common" -+ 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") -+ } -+ -+ flavorDimensions += "flavor" -+ productFlavors { -+ create("stable") { -+ dimension = "flavor" -+ isDefault = true -+ } -+ } -+ -+ compileOptions { -+ sourceCompatibility = JavaVersion.VERSION_17 -+ targetCompatibility = JavaVersion.VERSION_17 -+ } -+ kotlin { -+ jvmToolchain(17) -+ } -+} -+ -+dependencies { -+ implementation(libs.kotlinx.coroutines.core) -+ -+ // Hilt -+ implementation(libs.dagger.hilt.android) -+ kapt(libs.dagger.hilt.compiler) -+ -+ // Project dependencies -+ implementation(project(":core:common")) -+} -+ -+// Allow references to generated code -+kapt { -+ correctErrorTypes = true -+} -diff --git a/data/common/consumer-rules.pro b/data/common/consumer-rules.pro -new file mode 100644 -index 000000000..260809e6c ---- /dev/null -+++ b/data/common/consumer-rules.pro -@@ -0,0 +1 @@ -+# Proguard rules for data:common -diff --git a/data/common/src/main/AndroidManifest.xml b/data/common/src/main/AndroidManifest.xml -new file mode 100644 -index 000000000..57317bf89 ---- /dev/null -+++ b/data/common/src/main/AndroidManifest.xml -@@ -0,0 +1,18 @@ -+ -+ -+ -+ -diff --git a/core/common/src/main/java/com/google/jetpackcamera/core/common/CommonModule.kt b/data/common/src/main/java/com/google/jetpackcamera/data/common/CommonModule.kt -similarity index 63% -rename from core/common/src/main/java/com/google/jetpackcamera/core/common/CommonModule.kt -rename to data/common/src/main/java/com/google/jetpackcamera/data/common/CommonModule.kt -index 998ab951e..da4f7d333 100644 ---- a/core/common/src/main/java/com/google/jetpackcamera/core/common/CommonModule.kt -+++ b/data/common/src/main/java/com/google/jetpackcamera/data/common/CommonModule.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,15 @@ - * See the License for the specific language governing permissions and - * limitations under the License. - */ --package com.google.jetpackcamera.core.common -+package com.google.jetpackcamera.data.common - -+import com.google.jetpackcamera.core.common.DefaultCoroutineScope -+import com.google.jetpackcamera.core.common.DefaultDispatcher -+import com.google.jetpackcamera.core.common.IODispatcher - import dagger.Module - import dagger.Provides - import dagger.hilt.InstallIn - import dagger.hilt.components.SingletonComponent --import javax.inject.Qualifier - import javax.inject.Singleton - import kotlinx.coroutines.CoroutineDispatcher - import kotlinx.coroutines.CoroutineScope -@@ -46,31 +48,3 @@ class CommonModule { - fun providesCoroutineScope(@DefaultDispatcher dispatcher: CoroutineDispatcher) = - CoroutineScope(SupervisorJob() + dispatcher) - } -- --@Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER) --@Qualifier --@Retention(AnnotationRetention.BINARY) --annotation class DefaultFilePathGenerator -- --/** -- * provides the default [CaptureMode] to override in [LocalSettingsRepository] -- */ --@Qualifier --@Retention(AnnotationRetention.BINARY) --annotation class DefaultCaptureModeOverride -- --@Qualifier --@Retention(AnnotationRetention.BINARY) --annotation class DefaultSaveMode -- --@Qualifier --@Retention(AnnotationRetention.BINARY) --annotation class DefaultDispatcher -- --@Qualifier --@Retention(AnnotationRetention.BINARY) --annotation class IODispatcher -- --@Qualifier --@Retention(AnnotationRetention.BINARY) --annotation class DefaultCoroutineScope -diff --git a/data/media/build.gradle.kts b/data/media/build.gradle.kts -index 91146f6e8..20f9265f0 100644 ---- a/data/media/build.gradle.kts -+++ b/data/media/build.gradle.kts -@@ -89,6 +89,7 @@ dependencies { - - // Project dependencies - implementation(project(":core:common")) -+ implementation(project(":data:common")) - testImplementation(project(":core:common:testing")) - androidTestImplementation(project(":core:common:testing")) - -diff --git a/feature/preview/build.gradle.kts b/feature/preview/build.gradle.kts -index 54ab1c505..8276aa3aa 100644 ---- a/feature/preview/build.gradle.kts -+++ b/feature/preview/build.gradle.kts -@@ -138,6 +138,7 @@ dependencies { - implementation(project(":core:camera")) - implementation(project(":data:camera")) - implementation(project(":core:common")) -+ implementation(project(":data:common")) - implementation(project(":data:media")) - implementation(project(":data:settings")) - implementation(project(":core:settings")) -diff --git a/settings.gradle.kts b/settings.gradle.kts -index 103a86882..2cd5e3aaf 100644 ---- a/settings.gradle.kts -+++ b/settings.gradle.kts -@@ -39,12 +39,14 @@ include(":core:camera") - include(":data:camera") - include(":core:camera:testing") - include(":core:camera:low-light") --include(":core:camera:low-light-playservices") -+include(":data:camera:low-light") -+include(":data:camera:low-light-playservices") - include(":feature:settings") - include(":data:settings") - include(":data:settings:testing") - include(":data:media") - include(":data:media:testing") -+include(":data:common") - include(":core:common") - include(":core:common:testing") - include(":benchmark") -@@ -62,6 +64,7 @@ include(":core:model") - include(":ui:uistate:postcapture") - include(":ui:uistateadapter:postcapture") - include(":core:camera:postprocess") -+include(":data:camera:postprocess") - include(":ui:controller") - include(":ui:controller:impl") - include(":ui:controller:testing") -diff --git a/ui/components/capture/build.gradle.kts b/ui/components/capture/build.gradle.kts -index d2f9fc5fa..e2f456b45 100644 ---- a/ui/components/capture/build.gradle.kts -+++ b/ui/components/capture/build.gradle.kts -@@ -64,6 +64,9 @@ dependencies { - val composeBom = platform(libs.compose.bom) - implementation(composeBom) - -+ // AndroidX Core KTX -+ implementation(libs.androidx.core.ktx) -+ - // Accompanist - Permissions - implementation(libs.accompanist.permissions) - -@@ -74,9 +77,6 @@ dependencies { - implementation(libs.compose.ui.tooling.preview) - debugImplementation(libs.compose.ui.tooling) - -- // Compose - Integration with ViewModels with Navigation and Hilt -- implementation(libs.hilt.navigation.compose) -- - // CameraX - implementation(libs.camera.core) - implementation(libs.camera.compose) From d0ff9a5ef95750e644420119419bab02212b7669 Mon Sep 17 00:00:00 2001 From: Jetski Date: Wed, 15 Jul 2026 22:52:45 +0000 Subject: [PATCH 13/14] Fix ProtoDataStoreSettingsDataSourceTest compilation issue --- .../ProtoDataStoreSettingsDataSourceTest.kt | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt index 1bb913682..d3164afd5 100644 --- a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt +++ b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt @@ -26,7 +26,7 @@ import com.google.jetpackcamera.model.ImageOutputFormat import com.google.jetpackcamera.model.LensFacing import com.google.jetpackcamera.model.LowLightBoostPriority import com.google.jetpackcamera.model.StabilizationMode -import com.google.jetpackcamera.model.StreamConfig +import com.google.jetpackcamera.model.CaptureMode import com.google.jetpackcamera.model.VideoQuality import com.google.jetpackcamera.settings.model.CameraAppSettings import com.google.jetpackcamera.settings.model.DEFAULT_CAMERA_APP_SETTINGS @@ -71,7 +71,10 @@ class ProtoDataStoreSettingsDataSourceTest { ) { java.io.File(tempFolder.root, "test_jca_settings.pb") } - repository = ProtoDataStoreSettingsDataSource(jcaSettings = testDataStore) + repository = ProtoDataStoreSettingsDataSource( + jcaSettings = testDataStore, + defaultCaptureModeOverride = CaptureMode.STANDARD + ) } @After @@ -155,17 +158,6 @@ class ProtoDataStoreSettingsDataSourceTest { assertThat(new).isEqualTo(AspectRatio.ONE_ONE) } - @Test - fun can_update_stream_config() = runTest { - val initial = repository.getCurrentDefaultCameraAppSettings().streamConfig - repository.updateStreamConfig(StreamConfig.SINGLE_STREAM) - advanceUntilIdle() - val new = repository.getCurrentDefaultCameraAppSettings().streamConfig - - assertThat(initial).isEqualTo(StreamConfig.MULTI_STREAM) - assertThat(new).isEqualTo(StreamConfig.SINGLE_STREAM) - } - @Test fun can_update_low_light_boost_priority() = runTest { val initial = repository.getCurrentDefaultCameraAppSettings().lowLightBoostPriority From 0de19f4158925204d83f6067ab4df7c8ecb66341 Mon Sep 17 00:00:00 2001 From: Jetski Date: Wed, 15 Jul 2026 23:05:57 +0000 Subject: [PATCH 14/14] Fix spotless issues in test file --- .../settings/ProtoDataStoreSettingsDataSourceTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt index d3164afd5..6b7cb685b 100644 --- a/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt +++ b/core/settings/datastore-proto/src/test/java/com/google/jetpackcamera/settings/ProtoDataStoreSettingsDataSourceTest.kt @@ -19,6 +19,7 @@ import androidx.datastore.core.DataStore import androidx.datastore.core.DataStoreFactory import com.google.common.truth.Truth.assertThat import com.google.jetpackcamera.model.AspectRatio +import com.google.jetpackcamera.model.CaptureMode import com.google.jetpackcamera.model.DarkMode import com.google.jetpackcamera.model.DynamicRange import com.google.jetpackcamera.model.FlashMode @@ -26,7 +27,6 @@ import com.google.jetpackcamera.model.ImageOutputFormat import com.google.jetpackcamera.model.LensFacing import com.google.jetpackcamera.model.LowLightBoostPriority import com.google.jetpackcamera.model.StabilizationMode -import com.google.jetpackcamera.model.CaptureMode import com.google.jetpackcamera.model.VideoQuality import com.google.jetpackcamera.settings.model.CameraAppSettings import com.google.jetpackcamera.settings.model.DEFAULT_CAMERA_APP_SETTINGS