Skip to content
This repository was archived by the owner on Jun 20, 2023. It is now read-only.

Commit 02a2e14

Browse files
Merge pull request #5616 from corona-warn-app/feature/13208_refactor_datastore_3
Datastore refactoring (EXPOSUREAPP-13208)
2 parents 8c16752 + ae26a21 commit 02a2e14

File tree

132 files changed

+3520
-2618
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

132 files changed

+3520
-2618
lines changed

Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/statistics/Statistics.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ import de.rki.coronawarnapp.util.security.SignatureValidation
2424
import de.rki.coronawarnapp.util.serialization.SerializationModule
2525
import io.mockk.every
2626
import io.mockk.mockk
27+
import kotlinx.coroutines.flow.flowOf
2728
import kotlinx.coroutines.runBlocking
2829
import okhttp3.Cache
2930
import java.time.Instant
3031
import retrofit2.converter.gson.GsonConverterFactory
31-
import testhelpers.mockFlowPreference
3232
import timber.log.Timber
3333

3434
object Statistics {
@@ -58,7 +58,7 @@ object Statistics {
5858

5959
every { preferences.getString(any(), any()) } returns null
6060
every { context.getSharedPreferences(any(), any()) } returns preferences
61-
every { localStatisticsConfigStorage.activeSelections } returns mockFlowPreference(
61+
every { localStatisticsConfigStorage.activeSelections } returns flowOf(
6262
SelectedLocations(
6363
setOf(
6464
SelectedStatisticsLocation.SelectedDistrict(

Corona-Warn-App/src/androidTest/java/testhelpers/TestAndroidModule.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,16 @@ import androidx.datastore.preferences.core.Preferences
66
import androidx.test.platform.app.InstrumentationRegistry
77
import dagger.Module
88
import dagger.Provides
9+
import de.rki.coronawarnapp.covidcertificate.CovidCertificateSettingsDataStore
10+
import de.rki.coronawarnapp.datadonation.analytics.AnalyticsSettingsDataStore
11+
import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionDataStore
12+
import de.rki.coronawarnapp.datadonation.analytics.modules.testresult.AnalyticsExposureWindowsDataStore
913
import de.rki.coronawarnapp.datadonation.survey.SurveySettingsDataStore
1014
import de.rki.coronawarnapp.main.CwaSettingsDataStore
15+
import de.rki.coronawarnapp.presencetracing.LocationPreferencesDataStore
16+
import de.rki.coronawarnapp.presencetracing.LocationSettingsDataStore
1117
import de.rki.coronawarnapp.risk.RiskLevelSettingsDataStore
18+
import de.rki.coronawarnapp.statistics.LocalStatisticsConfigDataStore
1219
import de.rki.coronawarnapp.storage.OnboardingSettingsDataStore
1320
import de.rki.coronawarnapp.storage.TestSettingsDataStore
1421
import de.rki.coronawarnapp.storage.TracingSettingsDataStore
@@ -52,4 +59,32 @@ class TestAndroidModule {
5259
@CwaSettingsDataStore
5360
@Provides
5461
fun provideCwaSettingsDataStore(): DataStore<Preferences> = mockk(relaxed = true)
62+
63+
@AnalyticsSettingsDataStore
64+
@Provides
65+
fun provideAnalyticsSettingsDataStore(): DataStore<Preferences> = mockk(relaxed = true)
66+
67+
@CovidCertificateSettingsDataStore
68+
@Provides
69+
fun provideCovidCertificateSettingsDataStore(): DataStore<Preferences> = mockk(relaxed = true)
70+
71+
@LocationSettingsDataStore
72+
@Provides
73+
fun provideLocationSettingsDataStore(): DataStore<Preferences> = mockk(relaxed = true)
74+
75+
@LocationPreferencesDataStore
76+
@Provides
77+
fun provideLocationPreferencesDataStore(): DataStore<Preferences> = mockk(relaxed = true)
78+
79+
@AnalyticsKeySubmissionDataStore
80+
@Provides
81+
fun provideAnalyticsKeySubmissionDataStore(): DataStore<Preferences> = mockk(relaxed = true)
82+
83+
@AnalyticsExposureWindowsDataStore
84+
@Provides
85+
fun provideAnalyticsExposureWindowsDataStore(): DataStore<Preferences> = mockk(relaxed = true)
86+
87+
@LocalStatisticsConfigDataStore
88+
@Provides
89+
fun provideLocalStatisticsConfigDataStore(): DataStore<Preferences> = mockk(relaxed = true)
5590
}

Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragment.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.view.View
66
import androidx.fragment.app.Fragment
77
import de.rki.coronawarnapp.R
88
import de.rki.coronawarnapp.databinding.FragmentTestDeltaonboardingBinding
9+
import de.rki.coronawarnapp.presencetracing.TraceLocationSettings
910
import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
1011
import de.rki.coronawarnapp.util.di.AutoInject
1112
import de.rki.coronawarnapp.util.ui.viewBinding
@@ -24,9 +25,17 @@ class DeltaOnboardingFragment : Fragment(R.layout.fragment_test_deltaonboarding)
2425
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
2526
super.onViewCreated(view, savedInstanceState)
2627

27-
binding.switchAttendeeOnboarding.isChecked = viewModel.isAttendeeOnboardingDone()
28-
binding.switchVaccinationOnboarding.isChecked = viewModel.isVaccinationRegistrationOnboardingDone()
29-
binding.switchAnalyticsDeltaOnboarding.isChecked = viewModel.isAnalyticsOnboardingDone()
28+
viewModel.isAttendeeOnboardingDone.observe(viewLifecycleOwner) {
29+
binding.switchAttendeeOnboarding.isChecked = it == TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
30+
}
31+
32+
viewModel.isVaccinationRegistrationOnboardingDone.observe(viewLifecycleOwner) {
33+
binding.switchVaccinationOnboarding.isChecked = it
34+
}
35+
36+
viewModel.isAnalyticsOnboardingDone.observe(viewLifecycleOwner) {
37+
binding.switchAnalyticsDeltaOnboarding.isChecked = it != 0L
38+
}
3039

3140
viewModel.isDeltaOnboardingDone.observe(viewLifecycleOwner) {
3241
binding.switchDeltaOnboarding.isChecked = it

Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package de.rki.coronawarnapp.test.deltaonboarding.ui
22

3-
import androidx.lifecycle.LiveData
43
import dagger.assisted.AssistedFactory
54
import dagger.assisted.AssistedInject
65
import de.rki.coronawarnapp.contactdiary.storage.settings.ContactDiarySettings
@@ -23,12 +22,12 @@ class DeltaOnboardingFragmentViewModel @AssistedInject constructor(
2322
dispatcherProvider: DispatcherProvider
2423
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
2524

26-
val changelogVersion: LiveData<Long> = settings.lastChangelogVersion.asLiveData2()
27-
28-
val isContactJournalOnboardingDone: LiveData<Boolean> = contactDiaryUiSettings.isOnboardingDone
29-
.asLiveData2()
30-
31-
val lastNotificationsOnboardingVersionCode: LiveData<Long> = settings.lastNotificationsOnboardingVersionCode.asLiveData2()
25+
val changelogVersion = settings.lastChangelogVersion.asLiveData2()
26+
val isContactJournalOnboardingDone = contactDiaryUiSettings.isOnboardingDone.asLiveData2()
27+
val lastNotificationsOnboardingVersionCode = settings.lastNotificationsOnboardingVersionCode.asLiveData2()
28+
val isAnalyticsOnboardingDone = analyticsSettings.lastOnboardingVersionCode.asLiveData2()
29+
val isVaccinationRegistrationOnboardingDone = covidCertificateSettings.isOnboarded.asLiveData2()
30+
val isAttendeeOnboardingDone = traceLocationSettings.onboardingStatus.asLiveData2()
3231

3332
fun updateChangelogVersion(value: Long) {
3433
launch { settings.updateLastChangelogVersion(value) }
@@ -55,33 +54,24 @@ class DeltaOnboardingFragmentViewModel @AssistedInject constructor(
5554
launch { settings.updateWasInteroperabilityShownAtLeastOnce(value) }
5655
}
5756

58-
fun isAttendeeOnboardingDone() =
59-
traceLocationSettings.onboardingStatus.value == TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
60-
61-
fun setAttendeeOnboardingDone(value: Boolean) {
62-
traceLocationSettings.onboardingStatus.update {
57+
fun setAttendeeOnboardingDone(value: Boolean) = launch {
58+
traceLocationSettings.updateOnboardingStatus(
6359
if (value) TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
6460
else TraceLocationSettings.OnboardingStatus.NOT_ONBOARDED
65-
}
61+
)
6662
}
6763

68-
fun isVaccinationRegistrationOnboardingDone() = covidCertificateSettings.isOnboarded.value
69-
70-
fun setVaccinationRegistrationOnboardingDone(value: Boolean) {
71-
covidCertificateSettings.isOnboarded.update { value }
64+
fun setVaccinationRegistrationOnboardingDone(value: Boolean) = launch {
65+
covidCertificateSettings.updateIsOnboarded(value)
7266
}
7367

74-
fun setNotificationsOnboardingDone(value: Boolean) {
75-
launch {
76-
val version = if (value) BuildConfigWrap.VERSION_CODE else 0L
77-
settings.updateLastNotificationsOnboardingVersionCode(version)
78-
}
68+
fun setNotificationsOnboardingDone(value: Boolean) = launch {
69+
val version = if (value) BuildConfigWrap.VERSION_CODE else 0L
70+
settings.updateLastNotificationsOnboardingVersionCode(version)
7971
}
8072

81-
fun isAnalyticsOnboardingDone() = analyticsSettings.lastOnboardingVersionCode.value != 0L
82-
83-
fun setAnalyticsOnboardingDone(value: Boolean) {
84-
analyticsSettings.lastOnboardingVersionCode.update { if (value) BuildConfigWrap.VERSION_CODE else 0L }
73+
fun setAnalyticsOnboardingDone(value: Boolean) = launch {
74+
analyticsSettings.updateLastOnboardingVersionCode(if (value) BuildConfigWrap.VERSION_CODE else 0L)
8575
}
8676

8777
@AssistedFactory

Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/dsc/ui/DccStateValidationTestViewModel.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ class DccStateValidationTestViewModel @AssistedInject constructor(
6363
}
6464
}
6565

66-
fun resetLastCheckTime() {
67-
covidCertificateSettings.lastDccStateBackgroundCheck.update { Instant.EPOCH }
66+
fun resetLastCheckTime() = launch {
67+
covidCertificateSettings.updateLastDccStateBackgroundCheck(Instant.EPOCH)
6868
}
6969

7070
fun checkValidityNotifications() = launch {
71-
covidCertificateSettings.lastDccStateBackgroundCheck.update { Instant.EPOCH }
71+
covidCertificateSettings.updateLastDccStateBackgroundCheck(Instant.EPOCH)
7272
dccValidityStateNotificationService.showNotificationIfStateChanged()
7373
}
7474

Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestModule.kt

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,36 @@
11
package de.rki.coronawarnapp.coronatest
22

3+
import android.content.Context
4+
import androidx.datastore.core.DataStore
5+
import androidx.datastore.preferences.SharedPreferencesMigration
6+
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
7+
import androidx.datastore.preferences.core.Preferences
8+
import androidx.datastore.preferences.preferencesDataStoreFile
39
import dagger.Binds
410
import dagger.Module
11+
import dagger.Provides
512
import dagger.multibindings.IntoSet
613
import de.rki.coronawarnapp.coronatest.server.VerificationModule
714
import de.rki.coronawarnapp.coronatest.type.PersonalCoronaTestProcessor
815
import de.rki.coronawarnapp.coronatest.type.pcr.PCRTestProcessor
916
import de.rki.coronawarnapp.coronatest.type.rapidantigen.RATestProcessor
1017
import de.rki.coronawarnapp.profile.ProfileModule
18+
import de.rki.coronawarnapp.util.coroutine.AppScope
19+
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
20+
import de.rki.coronawarnapp.util.di.AppContext
1121
import de.rki.coronawarnapp.util.reset.Resettable
22+
import kotlinx.coroutines.CoroutineScope
23+
import kotlinx.coroutines.plus
24+
import javax.inject.Qualifier
25+
import javax.inject.Singleton
1226

1327
@Module(
14-
includes = [CoronaTestModule.ResetModule::class, VerificationModule::class, ProfileModule::class]
28+
includes = [
29+
CoronaTestModule.ResetModule::class,
30+
CoronaTestModule.CoronaTestStorageModule::class,
31+
VerificationModule::class,
32+
ProfileModule::class
33+
]
1534
)
1635
interface CoronaTestModule {
1736

@@ -27,6 +46,27 @@ interface CoronaTestModule {
2746
processor: RATestProcessor
2847
): PersonalCoronaTestProcessor
2948

49+
@Module
50+
object CoronaTestStorageModule {
51+
@Singleton
52+
@CoronaTestStorageDataStore
53+
@Provides
54+
fun provideCoronaTestStorageDataStore(
55+
@AppContext context: Context,
56+
@AppScope appScope: CoroutineScope,
57+
dispatcherProvider: DispatcherProvider
58+
): DataStore<Preferences> = PreferenceDataStoreFactory.create(
59+
scope = appScope + dispatcherProvider.IO,
60+
produceFile = { context.preferencesDataStoreFile(STORAGE_DATASTORE_CORONA_TEST_STORAGE_SETTINGS_NAME) },
61+
migrations = listOf(
62+
SharedPreferencesMigration(
63+
context,
64+
LEGACY_SHARED_PREFS_CORONA_TEST_STORAGE_SETTINGS_NAME
65+
)
66+
)
67+
)
68+
}
69+
3070
@Module
3171
interface ResetModule {
3272

@@ -35,3 +75,11 @@ interface CoronaTestModule {
3575
fun bindResettableCoronaTestRepository(resettable: CoronaTestRepository): Resettable
3676
}
3777
}
78+
79+
@Qualifier
80+
@MustBeDocumented
81+
@Retention(AnnotationRetention.RUNTIME)
82+
annotation class CoronaTestStorageDataStore
83+
84+
private const val LEGACY_SHARED_PREFS_CORONA_TEST_STORAGE_SETTINGS_NAME = "coronatest_localdata"
85+
private const val STORAGE_DATASTORE_CORONA_TEST_STORAGE_SETTINGS_NAME = "corona_test_storage"

Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepository.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class CoronaTestRepository @Inject constructor(
5151
sharingBehavior = SharingStarted.Eagerly,
5252
) {
5353
val legacyTests = legacyMigration.startMigration()
54-
val persistedTests = storage.coronaTests
54+
val persistedTests = storage.getCoronaTests()
5555
legacyTests.plus(persistedTests)
5656
.associateBy { it.identifier }
5757
.also {
@@ -83,7 +83,7 @@ class CoronaTestRepository @Inject constructor(
8383
.onStart { Timber.tag(TAG).d("Observing test data.") }
8484
.onEach {
8585
Timber.tag(TAG).v("CoronaTest data changed: %s", it)
86-
storage.coronaTests = it.values.toSet()
86+
storage.updateCoronaTests(it.values.toSet())
8787
legacyMigration.finishMigration()
8888
contactDiaryRepository.updateTests(it)
8989
}

Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/migration/PCRTestMigration.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
88
import de.rki.coronawarnapp.storage.TracingSettings
99
import de.rki.coronawarnapp.submission.SubmissionSettings
1010
import de.rki.coronawarnapp.util.CWADebug
11+
import kotlinx.coroutines.flow.first
1112
import kotlinx.coroutines.sync.Mutex
1213
import kotlinx.coroutines.sync.withLock
1314
import timber.log.Timber
@@ -28,15 +29,15 @@ class PCRTestMigration @Inject constructor(
2829
isMigrating = true
2930
Timber.tag(TAG).i("startMigration()")
3031

31-
val token: RegistrationToken? = submissionSettings.registrationTokenMigration
32+
val token: RegistrationToken? = submissionSettings.registrationTokenMigration.first()
3233
if (token == null) {
3334
Timber.tag(TAG).d("Nothing to migrate, token was null.")
3435
return emptySet()
3536
} else {
3637
Timber.tag(TAG).i("Migrating token %s", token)
3738
}
3839

39-
val devicePairingSuccessfulAt = submissionSettings.devicePairingSuccessfulAtMigration
40+
val devicePairingSuccessfulAt = submissionSettings.devicePairingSuccessfulAtMigration.first()
4041
Timber.tag(TAG).v("devicePairingSuccessfulAt=%s", devicePairingSuccessfulAt)
4142
if (devicePairingSuccessfulAt == null) {
4243
if (CWADebug.isDeviceForTestersBuild) {
@@ -45,16 +46,16 @@ class PCRTestMigration @Inject constructor(
4546
return emptySet()
4647
}
4748

48-
val isAllowedToSubmitKeys = submissionSettings.isAllowedToSubmitKeysMigration
49+
val isAllowedToSubmitKeys = submissionSettings.isAllowedToSubmitKeysMigration.first()
4950
Timber.tag(TAG).v("isAllowedToSubmitKeys=%s", isAllowedToSubmitKeys)
5051

51-
val isSubmissionSuccessful = submissionSettings.isSubmissionSuccessfulMigration
52+
val isSubmissionSuccessful = submissionSettings.isSubmissionSuccessfulMigration.first()
5253
Timber.tag(TAG).v("isSubmissionSuccessful=%s", isSubmissionSuccessful)
5354

54-
val hasViewedTestResult = submissionSettings.hasViewedTestResultMigration
55+
val hasViewedTestResult = submissionSettings.hasViewedTestResultMigration.first()
5556
Timber.tag(TAG).v("hasViewedTestResult=%s", hasViewedTestResult)
5657

57-
val hasGivenConsent = submissionSettings.hasGivenConsentMigration
58+
val hasGivenConsent = submissionSettings.hasGivenConsentMigration.first()
5859
Timber.tag(TAG).v("hasGivenConsent=%s", hasGivenConsent)
5960

6061
val testResultNotificationSent = tracingSettings.isTestResultAvailableNotificationSentMigration()

0 commit comments

Comments
 (0)