summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson@mullvad.net>2024-12-19 13:49:20 +0100
committerDavid Göransson <david.goransson@mullvad.net>2024-12-19 13:49:20 +0100
commitccd7525a21676967574e0469ece35ec236bed200 (patch)
tree632677c4c72b389aa543c1e44909a2e961c29c93 /android
parent83b08bf485a753f63d8dbe6101740f42efda6bc4 (diff)
parent3c259a8001ce5725e4953c7901628a21839afd93 (diff)
downloadmullvadvpn-ccd7525a21676967574e0469ece35ec236bed200.tar.xz
mullvadvpn-ccd7525a21676967574e0469ece35ec236bed200.zip
Merge branch 'migrate-from-sharedpreferences-to-datastore-droid-1688'
Diffstat (limited to 'android')
-rw-r--r--android/app/build.gradle.kts28
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt26
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/PrivacyDisclaimerRepository.kt15
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesMigration.kt31
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesRepository.kt32
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesSerializer.kt21
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt14
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/PrivacyDisclaimerViewModel.kt7
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplashViewModel.kt6
-rw-r--r--android/app/src/main/proto/user_prefs.proto6
-rw-r--r--android/gradle/libs.versions.toml14
-rw-r--r--android/gradle/verification-metadata.xml73
-rw-r--r--android/lib/daemon-grpc/build.gradle.kts2
13 files changed, 222 insertions, 53 deletions
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index cb5737e3ff..5fed7575d4 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -12,6 +12,7 @@ plugins {
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.kotlin.ksp)
alias(libs.plugins.compose)
+ alias(libs.plugins.protobuf.core)
id(Dependencies.junit5AndroidPluginId) version Versions.junit5Plugin
}
@@ -55,11 +56,7 @@ android {
}
}
- playConfigs {
- register("playStagemoleRelease") {
- enabled = true
- }
- }
+ playConfigs { register("playStagemoleRelease") { enabled = true } }
androidResources {
@Suppress("UnstableApiUsage")
@@ -222,8 +219,7 @@ android {
}
val variantName = name
- val capitalizedVariantName =
- variantName.toString().capitalized()
+ val capitalizedVariantName = variantName.toString().capitalized()
val artifactName = "MullvadVPN-${versionName}${artifactSuffix}"
tasks.register<Copy>("create${capitalizedVariantName}DistApk") {
@@ -316,7 +312,8 @@ tasks.create("printVersion") {
play {
serviceAccountCredentials.set(file("$credentialsPath/play-api-key.json"))
- // Disable for all flavors by default. Only specific flavors should be enabled using PlayConfigs.
+ // Disable for all flavors by default. Only specific flavors should be enabled using
+ // PlayConfigs.
enabled = false
// This property refers to the Publishing API (not git).
commit = true
@@ -326,6 +323,19 @@ play {
userFraction = 1.0
}
+protobuf {
+ protoc { artifact = libs.plugins.protobuf.protoc.get().toString() }
+ plugins {
+ create("java") { artifact = libs.plugins.grpc.protoc.gen.grpc.java.get().toString() }
+ }
+ generateProtoTasks {
+ all().forEach {
+ it.plugins { create("java") { option("lite") } }
+ it.builtins { create("kotlin") { option("lite") } }
+ }
+ }
+}
+
dependencies {
implementation(projects.lib.common)
implementation(projects.lib.daemonGrpc)
@@ -345,6 +355,7 @@ dependencies {
implementation(libs.commons.validator)
implementation(libs.androidx.activity.compose)
+ implementation(libs.androidx.datastore)
implementation(libs.androidx.ktx)
implementation(libs.androidx.coresplashscreen)
implementation(libs.androidx.lifecycle.runtime)
@@ -370,6 +381,7 @@ dependencies {
implementation(libs.kotlin.reflect)
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines.android)
+ implementation(libs.protobuf.kotlin.lite)
// UI tooling
implementation(libs.compose.ui.tooling.preview)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
index b111db10b2..650ee67eaa 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
@@ -2,8 +2,9 @@ package net.mullvad.mullvadvpn.di
import android.content.ComponentName
import android.content.Context
-import android.content.SharedPreferences
import android.content.pm.PackageManager
+import androidx.datastore.core.DataStore
+import androidx.datastore.dataStore
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import net.mullvad.mullvadvpn.BuildConfig
@@ -20,7 +21,6 @@ import net.mullvad.mullvadvpn.repository.ChangelogRepository
import net.mullvad.mullvadvpn.repository.CustomListsRepository
import net.mullvad.mullvadvpn.repository.InAppNotificationController
import net.mullvad.mullvadvpn.repository.NewDeviceRepository
-import net.mullvad.mullvadvpn.repository.PrivacyDisclaimerRepository
import net.mullvad.mullvadvpn.repository.ProblemReportRepository
import net.mullvad.mullvadvpn.repository.RelayListFilterRepository
import net.mullvad.mullvadvpn.repository.RelayListRepository
@@ -28,6 +28,10 @@ import net.mullvad.mullvadvpn.repository.RelayOverridesRepository
import net.mullvad.mullvadvpn.repository.SettingsRepository
import net.mullvad.mullvadvpn.repository.SplashCompleteRepository
import net.mullvad.mullvadvpn.repository.SplitTunnelingRepository
+import net.mullvad.mullvadvpn.repository.UserPreferences
+import net.mullvad.mullvadvpn.repository.UserPreferencesMigration
+import net.mullvad.mullvadvpn.repository.UserPreferencesRepository
+import net.mullvad.mullvadvpn.repository.UserPreferencesSerializer
import net.mullvad.mullvadvpn.repository.WireguardConstraintsRepository
import net.mullvad.mullvadvpn.ui.MainActivity
import net.mullvad.mullvadvpn.ui.serviceconnection.AppVersionInfoRepository
@@ -99,16 +103,13 @@ import net.mullvad.mullvadvpn.viewmodel.location.SearchLocationViewModel
import net.mullvad.mullvadvpn.viewmodel.location.SelectLocationListViewModel
import net.mullvad.mullvadvpn.viewmodel.location.SelectLocationViewModel
import org.apache.commons.validator.routines.InetAddressValidator
-import org.koin.android.ext.koin.androidApplication
import org.koin.android.ext.koin.androidContext
import org.koin.core.module.dsl.viewModel
import org.koin.core.qualifier.named
import org.koin.dsl.module
val uiModule = module {
- single<SharedPreferences>(named(APP_PREFERENCES_NAME)) {
- androidApplication().getSharedPreferences(APP_PREFERENCES_NAME, Context.MODE_PRIVATE)
- }
+ single<DataStore<UserPreferences>> { androidContext().userPreferencesStore }
single<PackageManager> { androidContext().packageManager }
single<String>(named(SELF_PACKAGE_NAME)) { androidContext().packageName }
@@ -126,11 +127,7 @@ val uiModule = module {
single { androidContext().contentResolver }
single { ChangelogRepository(get()) }
- single {
- PrivacyDisclaimerRepository(
- androidContext().getSharedPreferences(APP_PREFERENCES_NAME, Context.MODE_PRIVATE)
- )
- }
+ single { UserPreferencesRepository(get()) }
single { SettingsRepository(get()) }
single { MullvadProblemReport(get()) }
single { RelayOverridesRepository(get()) }
@@ -272,3 +269,10 @@ val uiModule = module {
const val SELF_PACKAGE_NAME = "SELF_PACKAGE_NAME"
const val APP_PREFERENCES_NAME = "${BuildConfig.APPLICATION_ID}.app_preferences"
const val BOOT_COMPLETED_RECEIVER_COMPONENT_NAME = "BOOT_COMPLETED_RECEIVER_COMPONENT_NAME"
+
+private val Context.userPreferencesStore: DataStore<UserPreferences> by
+ dataStore(
+ fileName = APP_PREFERENCES_NAME,
+ serializer = UserPreferencesSerializer,
+ produceMigrations = UserPreferencesMigration::migrations,
+ )
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/PrivacyDisclaimerRepository.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/PrivacyDisclaimerRepository.kt
deleted file mode 100644
index db1ad220e3..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/PrivacyDisclaimerRepository.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.mullvad.mullvadvpn.repository
-
-import android.content.SharedPreferences
-
-private const val IS_PRIVACY_DISCLOSURE_ACCEPTED_KEY = "is_privacy_disclosure_accepted"
-
-class PrivacyDisclaimerRepository(private val sharedPreferences: SharedPreferences) {
- fun hasAcceptedPrivacyDisclosure(): Boolean {
- return sharedPreferences.getBoolean(IS_PRIVACY_DISCLOSURE_ACCEPTED_KEY, false)
- }
-
- fun setPrivacyDisclosureAccepted() {
- sharedPreferences.edit().putBoolean(IS_PRIVACY_DISCLOSURE_ACCEPTED_KEY, true).apply()
- }
-}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesMigration.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesMigration.kt
new file mode 100644
index 0000000000..c92d9d393a
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesMigration.kt
@@ -0,0 +1,31 @@
+package net.mullvad.mullvadvpn.repository
+
+import android.content.Context
+import androidx.datastore.core.DataMigration
+import androidx.datastore.migrations.SharedPreferencesMigration
+import androidx.datastore.migrations.SharedPreferencesView
+import net.mullvad.mullvadvpn.di.APP_PREFERENCES_NAME
+
+private const val IS_PRIVACY_DISCLOSURE_ACCEPTED_KEY_SHARED_PREF_KEY =
+ "is_privacy_disclosure_accepted"
+
+data object UserPreferencesMigration {
+ fun migrations(context: Context): List<DataMigration<UserPreferences>> =
+ listOf(
+ SharedPreferencesMigration(
+ context,
+ sharedPreferencesName = APP_PREFERENCES_NAME,
+ keysToMigrate = setOf(IS_PRIVACY_DISCLOSURE_ACCEPTED_KEY_SHARED_PREF_KEY),
+ ) { sharedPrefs: SharedPreferencesView, currentData: UserPreferences ->
+ val privacyDisclosureAccepted =
+ sharedPrefs.getBoolean(
+ IS_PRIVACY_DISCLOSURE_ACCEPTED_KEY_SHARED_PREF_KEY,
+ false,
+ )
+ currentData
+ .toBuilder()
+ .setIsPrivacyDisclosureAccepted(privacyDisclosureAccepted)
+ .build()
+ }
+ )
+}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesRepository.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesRepository.kt
new file mode 100644
index 0000000000..f3e6a72b64
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesRepository.kt
@@ -0,0 +1,32 @@
+package net.mullvad.mullvadvpn.repository
+
+import androidx.datastore.core.DataStore
+import co.touchlab.kermit.Logger
+import java.io.IOException
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.first
+
+class UserPreferencesRepository(private val userPreferences: DataStore<UserPreferences>) {
+
+ // Note: this should not be made into a StateFlow. See:
+ // https://developer.android.com/reference/kotlin/androidx/datastore/core/DataStore#data()
+ val preferencesFlow: Flow<UserPreferences> =
+ userPreferences.data.catch { exception ->
+ // dataStore.data throws an IOException when an error is encountered when reading data
+ if (exception is IOException) {
+ Logger.e("Error reading user preferences file, falling back to default.", exception)
+ emit(UserPreferences.getDefaultInstance())
+ } else {
+ throw exception
+ }
+ }
+
+ suspend fun preferences(): UserPreferences = preferencesFlow.first()
+
+ suspend fun setPrivacyDisclosureAccepted() {
+ userPreferences.updateData { prefs ->
+ prefs.toBuilder().setIsPrivacyDisclosureAccepted(true).build()
+ }
+ }
+}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesSerializer.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesSerializer.kt
new file mode 100644
index 0000000000..97348fd0cc
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/UserPreferencesSerializer.kt
@@ -0,0 +1,21 @@
+package net.mullvad.mullvadvpn.repository
+
+import androidx.datastore.core.CorruptionException
+import androidx.datastore.core.Serializer
+import com.google.protobuf.InvalidProtocolBufferException
+import java.io.InputStream
+import java.io.OutputStream
+
+object UserPreferencesSerializer : Serializer<UserPreferences> {
+ override val defaultValue: UserPreferences = UserPreferences.getDefaultInstance()
+
+ override suspend fun readFrom(input: InputStream): UserPreferences {
+ try {
+ return UserPreferences.parseFrom(input)
+ } catch (exception: InvalidProtocolBufferException) {
+ throw CorruptionException("Cannot read proto", exception)
+ }
+ }
+
+ override suspend fun writeTo(t: UserPreferences, output: OutputStream) = t.writeTo(output)
+}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
index 4007b09ecd..76ec06d6cf 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
@@ -33,8 +33,8 @@ import net.mullvad.mullvadvpn.lib.endpoint.getApiEndpointConfigurationExtras
import net.mullvad.mullvadvpn.lib.model.PrepareError
import net.mullvad.mullvadvpn.lib.model.Prepared
import net.mullvad.mullvadvpn.lib.theme.AppTheme
-import net.mullvad.mullvadvpn.repository.PrivacyDisclaimerRepository
import net.mullvad.mullvadvpn.repository.SplashCompleteRepository
+import net.mullvad.mullvadvpn.repository.UserPreferencesRepository
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
import net.mullvad.mullvadvpn.viewmodel.MullvadAppViewModel
import org.koin.android.ext.android.inject
@@ -55,7 +55,7 @@ class MainActivity : ComponentActivity(), AndroidScopeComponent {
private val apiEndpointFromIntentHolder by inject<ApiEndpointFromIntentHolder>()
private val mullvadAppViewModel by inject<MullvadAppViewModel>()
- private val privacyDisclaimerRepository by inject<PrivacyDisclaimerRepository>()
+ private val userPreferencesRepository by inject<UserPreferencesRepository>()
private val serviceConnectionManager by inject<ServiceConnectionManager>()
private val splashCompleteRepository by inject<SplashCompleteRepository>()
private val managementService by inject<ManagementService>()
@@ -93,7 +93,7 @@ class MainActivity : ComponentActivity(), AndroidScopeComponent {
// https://medium.com/@lepicekmichal/android-background-service-without-hiccup-501e4479110f
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
- if (privacyDisclaimerRepository.hasAcceptedPrivacyDisclosure()) {
+ if (userPreferencesRepository.preferences().isPrivacyDisclosureAccepted) {
bindService()
}
}
@@ -103,7 +103,7 @@ class MainActivity : ComponentActivity(), AndroidScopeComponent {
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
lifecycleScope.launch {
- if (privacyDisclaimerRepository.hasAcceptedPrivacyDisclosure()) {
+ if (userPreferencesRepository.preferences().isPrivacyDisclosureAccepted) {
// If service is to be started wait for it to be connected before dismissing Splash
// screen
managementService.connectionState
@@ -121,8 +121,10 @@ class MainActivity : ComponentActivity(), AndroidScopeComponent {
override fun onStop() {
super.onStop()
- if (privacyDisclaimerRepository.hasAcceptedPrivacyDisclosure()) {
- serviceConnectionManager.unbind()
+ lifecycleScope.launch {
+ if (userPreferencesRepository.preferences().isPrivacyDisclosureAccepted) {
+ serviceConnectionManager.unbind()
+ }
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/PrivacyDisclaimerViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/PrivacyDisclaimerViewModel.kt
index d2500bc94d..11800791d2 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/PrivacyDisclaimerViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/PrivacyDisclaimerViewModel.kt
@@ -5,18 +5,17 @@ import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
-import net.mullvad.mullvadvpn.repository.PrivacyDisclaimerRepository
+import net.mullvad.mullvadvpn.repository.UserPreferencesRepository
data class PrivacyDisclaimerViewState(val isStartingService: Boolean, val isPlayBuild: Boolean)
class PrivacyDisclaimerViewModel(
- private val privacyDisclaimerRepository: PrivacyDisclaimerRepository,
+ private val userPreferencesRepository: UserPreferencesRepository,
isPlayBuild: Boolean,
) : ViewModel() {
@@ -40,8 +39,8 @@ class PrivacyDisclaimerViewModel(
val uiSideEffect = _uiSideEffect.receiveAsFlow()
fun setPrivacyDisclosureAccepted() {
- privacyDisclaimerRepository.setPrivacyDisclosureAccepted()
viewModelScope.launch {
+ userPreferencesRepository.setPrivacyDisclosureAccepted()
if (!_isStartingService.value) {
_isStartingService.update { true }
_uiSideEffect.send(PrivacyDisclaimerUiSideEffect.StartService)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplashViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplashViewModel.kt
index a196d4ae90..0ed85c94cd 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplashViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplashViewModel.kt
@@ -16,13 +16,13 @@ import net.mullvad.mullvadvpn.constant.ACCOUNT_EXPIRY_TIMEOUT_MS
import net.mullvad.mullvadvpn.lib.model.DeviceState
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.lib.shared.DeviceRepository
-import net.mullvad.mullvadvpn.repository.PrivacyDisclaimerRepository
import net.mullvad.mullvadvpn.repository.SplashCompleteRepository
+import net.mullvad.mullvadvpn.repository.UserPreferencesRepository
data class SplashScreenState(val splashComplete: Boolean = false)
class SplashViewModel(
- private val privacyDisclaimerRepository: PrivacyDisclaimerRepository,
+ private val userPreferencesRepository: UserPreferencesRepository,
private val accountRepository: AccountRepository,
private val deviceRepository: DeviceRepository,
private val splashCompleteRepository: SplashCompleteRepository,
@@ -37,7 +37,7 @@ class SplashViewModel(
val uiState: StateFlow<SplashScreenState> = _uiState
private suspend fun getStartDestination(): SplashUiSideEffect {
- if (!privacyDisclaimerRepository.hasAcceptedPrivacyDisclosure()) {
+ if (!userPreferencesRepository.preferences().isPrivacyDisclosureAccepted) {
return SplashUiSideEffect.NavigateToPrivacyDisclaimer
}
diff --git a/android/app/src/main/proto/user_prefs.proto b/android/app/src/main/proto/user_prefs.proto
new file mode 100644
index 0000000000..3a7e79285f
--- /dev/null
+++ b/android/app/src/main/proto/user_prefs.proto
@@ -0,0 +1,6 @@
+syntax = "proto3";
+
+option java_package = "net.mullvad.mullvadvpn.repository";
+option java_multiple_files = true;
+
+message UserPreferences { bool is_privacy_disclosure_accepted = 1; }
diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml
index 0a4b42d804..16a900284e 100644
--- a/android/gradle/libs.versions.toml
+++ b/android/gradle/libs.versions.toml
@@ -13,6 +13,7 @@ androidx-activitycompose = "1.9.3"
androidx-appcompat = "1.7.0"
androidx-ktx = "1.15.0"
androidx-coresplashscreen = "1.1.0-rc01"
+androidx-datastore = "1.1.1"
androidx-espresso = "3.6.1"
androidx-lifecycle = "2.8.7"
androidx-test = "1.6.1"
@@ -33,7 +34,6 @@ compose-material3 = "1.3.1"
grpc = "1.69.0"
grpc-kotlin = "1.4.1"
grpc-kotlin-jar = "1.4.1:jdk8@jar"
-grpc-protobuf = "4.29.1"
# Koin
koin = "4.0.0"
@@ -51,7 +51,8 @@ kotlinx = "1.9.0"
kotlinx-serialization = "2.1.0"
# Protobuf
-protobuf = "0.9.4"
+protobuf-gradle-plugin = "0.9.4"
+protobuf = "4.29.1"
# Misc
commonsvalidator = "1.9.0"
@@ -81,6 +82,7 @@ android-volley = { module = "com.android.volley:volley", version.ref = "android-
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activitycompose" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
androidx-coresplashscreen = { module = "androidx.core:core-splashscreen", version.ref = "androidx-coresplashscreen" }
+androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "androidx-datastore" }
androidx-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-espresso" }
androidx-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-ktx" }
androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" }
@@ -119,7 +121,9 @@ grpc-okhttp = { module = "io.grpc:grpc-okhttp", version.ref = "grpc" }
grpc-android = { module = "io.grpc:grpc-android", version.ref = "grpc" }
grpc-kotlin-stub = { module = "io.grpc:grpc-kotlin-stub", version.ref = "grpc-kotlin" }
grpc-protobuf-lite = { module = "io.grpc:grpc-protobuf-lite", version.ref = "grpc" }
-grpc-protobuf-kotlin-lite = { module = "com.google.protobuf:protobuf-kotlin-lite", version.ref = "grpc-protobuf" }
+
+# Protobuf
+protobuf-kotlin-lite = { module = "com.google.protobuf:protobuf-kotlin-lite", version.ref = "protobuf" }
# Koin
koin = { module = "io.insert-koin:koin-core", version.ref = "koin" }
@@ -177,8 +181,8 @@ kotlin-ksp = { id = "com.google.devtools.ksp", version.ref = "kotlin-ksp" }
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlinx-serialization" }
# Protobuf
-protobuf-core = { id = "com.google.protobuf", version.ref = "protobuf" }
-protobuf-protoc = { id = "com.google.protobuf:protoc", version.ref = "grpc-protobuf" }
+protobuf-core = { id = "com.google.protobuf", version.ref = "protobuf-gradle-plugin" }
+protobuf-protoc = { id = "com.google.protobuf:protoc", version.ref = "protobuf" }
# gRPC
grpc-protoc-gen-grpc-java = { id = "io.grpc:protoc-gen-grpc-java", version.ref = "grpc" }
diff --git a/android/gradle/verification-metadata.xml b/android/gradle/verification-metadata.xml
index f4f8e29109..bf6ad40f17 100644
--- a/android/gradle/verification-metadata.xml
+++ b/android/gradle/verification-metadata.xml
@@ -177,6 +177,7 @@
<trusting group="androidx.constraintlayout"/>
<trusting group="androidx.core"/>
<trusting group="androidx.databinding"/>
+ <trusting group="androidx.datastore"/>
<trusting group="androidx.fragment"/>
<trusting group="androidx.graphics"/>
<trusting group="androidx.lifecycle"/>
@@ -1478,6 +1479,70 @@
<sha256 value="b2431cbbe38d0a31e001b7c34f52f69a323fc9ec573b6afe5893daced5ab3285" origin="Generated by Gradle"/>
</artifact>
</component>
+ <component group="androidx.datastore" name="datastore" version="1.1.1">
+ <artifact name="datastore-1.1.1.module">
+ <sha256 value="2b621afac7661b553fffc1b1341a005ab077b2ea2908076ddbabe5fefbf89294" origin="Generated by Gradle"/>
+ </artifact>
+ <artifact name="datastore-metadata-1.1.1.jar">
+ <sha256 value="4ab4086b6359ea81eb359451f0f005c78bc508d75c070555154cdf6313b0e1cb" origin="Generated by Gradle"/>
+ </artifact>
+ </component>
+ <component group="androidx.datastore" name="datastore-android" version="1.1.1">
+ <artifact name="datastore-android-1.1.1.module">
+ <sha256 value="723ee8ccf48382511221da21e0a3efdcdcf58b1de4894fddac405a1481119c25" origin="Generated by Gradle"/>
+ </artifact>
+ <artifact name="datastore-release.aar">
+ <sha256 value="fce724038fea3bdef7b0d1aaf10cda6614b61bec66571750cc9be7048b950119" origin="Generated by Gradle"/>
+ </artifact>
+ </component>
+ <component group="androidx.datastore" name="datastore-core" version="1.1.1">
+ <artifact name="datastore-core-1.1.1.module">
+ <sha256 value="6ef39025e574d01a1aec000ef8d416368f1e8e15929c4fd746a383cefb36ae4e" origin="Generated by Gradle"/>
+ </artifact>
+ <artifact name="datastore-core-metadata-1.1.1.jar">
+ <sha256 value="dfdcb0213751b038b5486a178d3e7f7f8cd0ce7d2888a0ba6a9f3bd1c9f16b7c" origin="Generated by Gradle"/>
+ </artifact>
+ </component>
+ <component group="androidx.datastore" name="datastore-core-android" version="1.1.1">
+ <artifact name="datastore-core-android-1.1.1.module">
+ <sha256 value="1df2659237979a7fb6a9ca8816b29ebda552bccf12b731a10ccd3ea296a5bc1a" origin="Generated by Gradle"/>
+ </artifact>
+ <artifact name="datastore-core-release.aar">
+ <sha256 value="883abc911e4b14119959e44e20a520523f59c303e834d6b325007b3ee5e9cb6c" origin="Generated by Gradle"/>
+ </artifact>
+ </component>
+ <component group="androidx.datastore" name="datastore-core-jvm" version="1.1.1">
+ <artifact name="datastore-core-jvm-1.1.1.jar">
+ <sha256 value="30819f32f0cda25a2fc2e7c4a12045753e48b6b04cd126a1a42f010e441e022c" origin="Generated by Gradle"/>
+ </artifact>
+ <artifact name="datastore-core-jvm-1.1.1.module">
+ <sha256 value="a4d1374322e61a0b6e517976f15c23519c3787069dd8de8577176b073af47b3a" origin="Generated by Gradle"/>
+ </artifact>
+ </component>
+ <component group="androidx.datastore" name="datastore-core-okio" version="1.1.1">
+ <artifact name="datastore-core-okio-1.1.1.module">
+ <sha256 value="e0e3e9e6429888f30c7e56e800decc0383a20e9baee505eea883574dfa0bd275" origin="Generated by Gradle"/>
+ </artifact>
+ <artifact name="datastore-core-okio-metadata-1.1.1.jar">
+ <sha256 value="117beb462cad6a885864fe0296ed8cfee509da08d064c44d226efbd60538599b" origin="Generated by Gradle"/>
+ </artifact>
+ </component>
+ <component group="androidx.datastore" name="datastore-core-okio-jvm" version="1.1.1">
+ <artifact name="datastore-core-okio-jvm-1.1.1.jar">
+ <sha256 value="5071d03c7be9555fd81e5bd522b490a06a89694e4b937f307da72bc74e33c34a" origin="Generated by Gradle"/>
+ </artifact>
+ <artifact name="datastore-core-okio-jvm-1.1.1.module">
+ <sha256 value="aef93f3081dbd8563e12ce375f065399fbc7563992c64be2214cefe2b4f1a2c2" origin="Generated by Gradle"/>
+ </artifact>
+ </component>
+ <component group="androidx.datastore" name="datastore-jvm" version="1.1.1">
+ <artifact name="datastore-jvm-1.1.1.jar">
+ <sha256 value="bbd2d9f6c8bcf5a7ae97b999bc6641ef304224b7392b4cea26b9cf87d7cb0281" origin="Generated by Gradle"/>
+ </artifact>
+ <artifact name="datastore-jvm-1.1.1.module">
+ <sha256 value="e160533ba047931ddce738026f9189c1266f3e9c3d79ded9ec9404e84280a49a" origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="androidx.drawerlayout" name="drawerlayout" version="1.0.0">
<artifact name="drawerlayout-1.0.0.aar">
<sha256 value="9402442cdc5a43cf62fb14f8cf98c63342d4d9d9b805c8033c6cf7e802749ac1" origin="Generated by Gradle"/>
@@ -3707,6 +3772,9 @@
<artifact name="okio-3.4.0.module">
<sha256 value="69173608417a2113e6fa6afeb7b4540b20df70cfda3fa16c73aaa4fa702ffad3" origin="Generated by Gradle"/>
</artifact>
+ <artifact name="okio-metadata-3.4.0-all.jar">
+ <sha256 value="73570416f75fd20e1269c17c588884c3d1d1098a5cf4a15ccae3f4e1ab08329e" origin="Generated by Gradle"/>
+ </artifact>
</component>
<component group="com.squareup.okio" name="okio" version="3.6.0">
<artifact name="okio-3.6.0.module">
@@ -5810,6 +5878,11 @@
<sha256 value="858828bc5191b9e602affa14e01d66489dafb08c4c18d2faee3cbed7ba7d9992" origin="Generated by Gradle"/>
</artifact>
</component>
+ <component group="org.jetbrains.kotlin" name="kotlin-stdlib-common" version="1.9.21">
+ <artifact name="kotlin-stdlib-common-1.9.21.module">
+ <sha256 value="68dc8e84aa05f5278c16505247d71346d3512b9edadd41f613d657c94c59993b" origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-common" version="1.9.23">
<artifact name="kotlin-stdlib-common-1.9.23.module">
<sha256 value="8639f005fa9977aef08c32fc8e7a2779da22ee262464d7273298aafd483715cd" origin="Generated by Gradle"/>
diff --git a/android/lib/daemon-grpc/build.gradle.kts b/android/lib/daemon-grpc/build.gradle.kts
index e1807c9d34..9383121547 100644
--- a/android/lib/daemon-grpc/build.gradle.kts
+++ b/android/lib/daemon-grpc/build.gradle.kts
@@ -73,7 +73,7 @@ dependencies {
implementation(libs.grpc.android)
implementation(libs.grpc.kotlin.stub)
implementation(libs.grpc.protobuf.lite)
- implementation(libs.grpc.protobuf.kotlin.lite)
+ implementation(libs.protobuf.kotlin.lite)
implementation(libs.arrow)
implementation(libs.arrow.optics)