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

Datastore refactoring (EXPOSUREAPP-13208) #5616

Merged
merged 51 commits into from
Nov 23, 2022
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
e8e9b1d
Refactor AnalyticsSettings
schauersbergern Oct 1, 2022
e86c504
Refactor ENFClientLocalData
schauersbergern Oct 4, 2022
46f0533
Refactor CovidCertificateSettings
schauersbergern Oct 5, 2022
373c777
Refactor TraceLocationSettings
schauersbergern Oct 5, 2022
ed6f49f
Refactor TraceLocationPreferences
schauersbergern Oct 5, 2022
d87e404
Merge branch 'release/2.28.x' into feature/13208_refactor_datastore_3
schauersbergern Oct 5, 2022
f7e20b1
Refactor EncryptionErrorResetTool
schauersbergern Oct 6, 2022
a01e176
Refactor AnalyticsKeySubmissionStorage
schauersbergern Oct 10, 2022
f8ae9dd
Change livedata to postvalue
schauersbergern Oct 11, 2022
66a5e3a
refactor AnalyticsTestResultSettings
schauersbergern Oct 20, 2022
ab665dd
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
schauersbergern Oct 21, 2022
2ef5ce3
refactor ValueSetsStorage
schauersbergern Oct 21, 2022
a15a29a
adapt tests
schauersbergern Oct 24, 2022
35ff32e
refactor AnalyticsExposureWindowsSettings
schauersbergern Oct 24, 2022
efcf33d
refactor DownloadDiagnosisKeysSettings
schauersbergern Oct 24, 2022
b1f589e
refactor CoronaTestStorage
schauersbergern Oct 25, 2022
5a79638
update tests
schauersbergern Oct 26, 2022
d0bf680
refactor VaccinationStorage
schauersbergern Oct 26, 2022
ab97ed5
refactor TestCertificateStorage
schauersbergern Oct 26, 2022
15031a1
refactor LocalStatisticsConfigStorage
schauersbergern Oct 27, 2022
607e530
refactor SubmissionSettings
schauersbergern Oct 27, 2022
2567ac5
remove redundant shared preferences
schauersbergern Oct 28, 2022
80433b6
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
schauersbergern Oct 28, 2022
3e8552b
fix tests
schauersbergern Oct 28, 2022
5b8b9cd
fix lint
schauersbergern Oct 28, 2022
720a348
fix tests
schauersbergern Oct 28, 2022
683af4c
fix tests
schauersbergern Oct 28, 2022
e843c9a
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
schauersbergern Oct 28, 2022
09e9b0d
fix tests
schauersbergern Oct 28, 2022
f0ab07d
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
mtwalli Oct 31, 2022
21a299a
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
mtwalli Oct 31, 2022
3cea086
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
mtwalli Oct 31, 2022
5797891
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
mtwalli Oct 31, 2022
c4f404d
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
mtwalli Oct 31, 2022
5151369
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
schauersbergern Nov 2, 2022
973fbf5
revert jackson to gson annotations
schauersbergern Nov 2, 2022
8170ddd
add newline
schauersbergern Nov 2, 2022
8784f5a
Revert ValueSetsStorage back to Gson
schauersbergern Nov 2, 2022
b0dfc1a
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
mtwalli Nov 2, 2022
b1b8d44
Revert Jackson to Gson
schauersbergern Nov 2, 2022
9337097
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
schauersbergern Nov 2, 2022
071bd09
Merge branch 'release/2.29.x' into feature/13208_refactor_datastore_3
mtwalli Nov 8, 2022
0f66a2d
Merge branch 'release/3.0.x' into feature/13208_refactor_datastore_3
schauersbergern Nov 17, 2022
5591386
Merge branch 'release/3.0.x' into feature/13208_refactor_datastore_3
schauersbergern Nov 17, 2022
b3215dd
change legacy data loading plus test
schauersbergern Nov 18, 2022
ea350b2
Merge branch 'release/3.0.x' into feature/13208_refactor_datastore_3
schauersbergern Nov 18, 2022
a5b3c0b
simplify json conversion
schauersbergern Nov 18, 2022
31aa838
fix tests
schauersbergern Nov 18, 2022
5615e28
Merge branch 'release/3.0.x' into feature/13208_refactor_datastore_3
schauersbergern Nov 18, 2022
955e5c2
Merge branch 'release/3.0.x' into feature/13208_refactor_datastore_3
mtwalli Nov 18, 2022
ae26a21
Merge branch 'release/3.0.x' into feature/13208_refactor_datastore_3
mtwalli Nov 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import de.rki.coronawarnapp.util.security.SignatureValidation
import de.rki.coronawarnapp.util.serialization.SerializationModule
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import okhttp3.Cache
import java.time.Instant
import retrofit2.converter.gson.GsonConverterFactory
import testhelpers.mockFlowPreference
import timber.log.Timber

object Statistics {
Expand Down Expand Up @@ -58,7 +58,7 @@ object Statistics {

every { preferences.getString(any(), any()) } returns null
every { context.getSharedPreferences(any(), any()) } returns preferences
every { localStatisticsConfigStorage.activeSelections } returns mockFlowPreference(
every { localStatisticsConfigStorage.activeSelections } returns flowOf(
SelectedLocations(
setOf(
SelectedStatisticsLocation.SelectedDistrict(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@ import androidx.datastore.preferences.core.Preferences
import androidx.test.platform.app.InstrumentationRegistry
import dagger.Module
import dagger.Provides
import de.rki.coronawarnapp.covidcertificate.CovidCertificateSettingsDataStore
import de.rki.coronawarnapp.datadonation.analytics.AnalyticsSettingsDataStore
import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionDataStore
import de.rki.coronawarnapp.datadonation.analytics.modules.testresult.AnalyticsExposureWindowsDataStore
import de.rki.coronawarnapp.datadonation.survey.SurveySettingsDataStore
import de.rki.coronawarnapp.main.CwaSettingsDataStore
import de.rki.coronawarnapp.presencetracing.LocationPreferencesDataStore
import de.rki.coronawarnapp.presencetracing.LocationSettingsDataStore
import de.rki.coronawarnapp.risk.RiskLevelSettingsDataStore
import de.rki.coronawarnapp.statistics.LocalStatisticsConfigDataStore
import de.rki.coronawarnapp.storage.OnboardingSettingsDataStore
import de.rki.coronawarnapp.storage.TestSettingsDataStore
import de.rki.coronawarnapp.storage.TracingSettingsDataStore
Expand Down Expand Up @@ -52,4 +59,32 @@ class TestAndroidModule {
@CwaSettingsDataStore
@Provides
fun provideCwaSettingsDataStore(): DataStore<Preferences> = mockk(relaxed = true)

@AnalyticsSettingsDataStore
@Provides
fun provideAnalyticsSettingsDataStore(): DataStore<Preferences> = mockk(relaxed = true)

@CovidCertificateSettingsDataStore
@Provides
fun provideCovidCertificateSettingsDataStore(): DataStore<Preferences> = mockk(relaxed = true)

@LocationSettingsDataStore
@Provides
fun provideLocationSettingsDataStore(): DataStore<Preferences> = mockk(relaxed = true)

@LocationPreferencesDataStore
@Provides
fun provideLocationPreferencesDataStore(): DataStore<Preferences> = mockk(relaxed = true)

@AnalyticsKeySubmissionDataStore
@Provides
fun provideAnalyticsKeySubmissionDataStore(): DataStore<Preferences> = mockk(relaxed = true)

@AnalyticsExposureWindowsDataStore
@Provides
fun provideAnalyticsExposureWindowsDataStore(): DataStore<Preferences> = mockk(relaxed = true)

@LocalStatisticsConfigDataStore
@Provides
fun provideLocalStatisticsConfigDataStore(): DataStore<Preferences> = mockk(relaxed = true)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.view.View
import androidx.fragment.app.Fragment
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentTestDeltaonboardingBinding
import de.rki.coronawarnapp.presencetracing.TraceLocationSettings
import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.ui.viewBinding
Expand All @@ -24,9 +25,17 @@ class DeltaOnboardingFragment : Fragment(R.layout.fragment_test_deltaonboarding)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.switchAttendeeOnboarding.isChecked = viewModel.isAttendeeOnboardingDone()
binding.switchVaccinationOnboarding.isChecked = viewModel.isVaccinationRegistrationOnboardingDone()
binding.switchAnalyticsDeltaOnboarding.isChecked = viewModel.isAnalyticsOnboardingDone()
viewModel.isAttendeeOnboardingDone.observe(viewLifecycleOwner) {
binding.switchAttendeeOnboarding.isChecked = it == TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
}

viewModel.isVaccinationRegistrationOnboardingDone.observe(viewLifecycleOwner) {
binding.switchVaccinationOnboarding.isChecked = it
}

viewModel.isAnalyticsOnboardingDone.observe(viewLifecycleOwner) {
binding.switchAnalyticsDeltaOnboarding.isChecked = it != 0L
}

viewModel.isDeltaOnboardingDone.observe(viewLifecycleOwner) {
binding.switchDeltaOnboarding.isChecked = it
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.rki.coronawarnapp.test.deltaonboarding.ui

import androidx.lifecycle.LiveData
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.contactdiary.storage.settings.ContactDiarySettings
Expand All @@ -23,12 +22,12 @@ class DeltaOnboardingFragmentViewModel @AssistedInject constructor(
dispatcherProvider: DispatcherProvider
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {

val changelogVersion: LiveData<Long> = settings.lastChangelogVersion.asLiveData2()

val isContactJournalOnboardingDone: LiveData<Boolean> = contactDiaryUiSettings.isOnboardingDone
.asLiveData2()

val lastNotificationsOnboardingVersionCode: LiveData<Long> = settings.lastNotificationsOnboardingVersionCode.asLiveData2()
val changelogVersion = settings.lastChangelogVersion.asLiveData2()
val isContactJournalOnboardingDone = contactDiaryUiSettings.isOnboardingDone.asLiveData2()
val lastNotificationsOnboardingVersionCode = settings.lastNotificationsOnboardingVersionCode.asLiveData2()
val isAnalyticsOnboardingDone = analyticsSettings.lastOnboardingVersionCode.asLiveData2()
val isVaccinationRegistrationOnboardingDone = covidCertificateSettings.isOnboarded.asLiveData2()
val isAttendeeOnboardingDone = traceLocationSettings.onboardingStatus.asLiveData2()

fun updateChangelogVersion(value: Long) {
launch { settings.updateLastChangelogVersion(value) }
Expand All @@ -55,33 +54,24 @@ class DeltaOnboardingFragmentViewModel @AssistedInject constructor(
launch { settings.updateWasInteroperabilityShownAtLeastOnce(value) }
}

fun isAttendeeOnboardingDone() =
traceLocationSettings.onboardingStatus.value == TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0

fun setAttendeeOnboardingDone(value: Boolean) {
traceLocationSettings.onboardingStatus.update {
fun setAttendeeOnboardingDone(value: Boolean) = launch {
traceLocationSettings.updateOnboardingStatus(
if (value) TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
else TraceLocationSettings.OnboardingStatus.NOT_ONBOARDED
}
)
}

fun isVaccinationRegistrationOnboardingDone() = covidCertificateSettings.isOnboarded.value

fun setVaccinationRegistrationOnboardingDone(value: Boolean) {
covidCertificateSettings.isOnboarded.update { value }
fun setVaccinationRegistrationOnboardingDone(value: Boolean) = launch {
covidCertificateSettings.updateIsOnboarded(value)
}

fun setNotificationsOnboardingDone(value: Boolean) {
launch {
val version = if (value) BuildConfigWrap.VERSION_CODE else 0L
settings.updateLastNotificationsOnboardingVersionCode(version)
}
fun setNotificationsOnboardingDone(value: Boolean) = launch {
val version = if (value) BuildConfigWrap.VERSION_CODE else 0L
settings.updateLastNotificationsOnboardingVersionCode(version)
}

fun isAnalyticsOnboardingDone() = analyticsSettings.lastOnboardingVersionCode.value != 0L

fun setAnalyticsOnboardingDone(value: Boolean) {
analyticsSettings.lastOnboardingVersionCode.update { if (value) BuildConfigWrap.VERSION_CODE else 0L }
fun setAnalyticsOnboardingDone(value: Boolean) = launch {
analyticsSettings.updateLastOnboardingVersionCode(if (value) BuildConfigWrap.VERSION_CODE else 0L)
}

@AssistedFactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ class DccStateValidationTestViewModel @AssistedInject constructor(
}
}

fun resetLastCheckTime() {
covidCertificateSettings.lastDccStateBackgroundCheck.update { Instant.EPOCH }
fun resetLastCheckTime() = launch {
covidCertificateSettings.updateLastDccStateBackgroundCheck(Instant.EPOCH)
}

fun checkValidityNotifications() = launch {
covidCertificateSettings.lastDccStateBackgroundCheck.update { Instant.EPOCH }
covidCertificateSettings.updateLastDccStateBackgroundCheck(Instant.EPOCH)
dccValidityStateNotificationService.showNotificationIfStateChanged()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
package de.rki.coronawarnapp.coronatest

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.SharedPreferencesMigration
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStoreFile
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.multibindings.IntoSet
import de.rki.coronawarnapp.coronatest.server.VerificationModule
import de.rki.coronawarnapp.coronatest.type.PersonalCoronaTestProcessor
import de.rki.coronawarnapp.coronatest.type.pcr.PCRTestProcessor
import de.rki.coronawarnapp.coronatest.type.rapidantigen.RATestProcessor
import de.rki.coronawarnapp.profile.ProfileModule
import de.rki.coronawarnapp.util.coroutine.AppScope
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.di.AppContext
import de.rki.coronawarnapp.util.reset.Resettable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.plus
import javax.inject.Qualifier
import javax.inject.Singleton

@Module(
includes = [CoronaTestModule.ResetModule::class, VerificationModule::class, ProfileModule::class]
includes = [
CoronaTestModule.ResetModule::class,
CoronaTestModule.CoronaTestStorageModule::class,
VerificationModule::class,
ProfileModule::class
]
)
interface CoronaTestModule {

Expand All @@ -27,6 +46,27 @@ interface CoronaTestModule {
processor: RATestProcessor
): PersonalCoronaTestProcessor

@Module
object CoronaTestStorageModule {
@Singleton
@CoronaTestStorageDataStore
@Provides
fun provideCoronaTestStorageDataStore(
@AppContext context: Context,
@AppScope appScope: CoroutineScope,
dispatcherProvider: DispatcherProvider
): DataStore<Preferences> = PreferenceDataStoreFactory.create(
scope = appScope + dispatcherProvider.IO,
produceFile = { context.preferencesDataStoreFile(STORAGE_DATASTORE_CORONA_TEST_STORAGE_SETTINGS_NAME) },
migrations = listOf(
SharedPreferencesMigration(
context,
LEGACY_SHARED_PREFS_CORONA_TEST_STORAGE_SETTINGS_NAME
)
)
)
}

@Module
interface ResetModule {

Expand All @@ -35,3 +75,11 @@ interface CoronaTestModule {
fun bindResettableCoronaTestRepository(resettable: CoronaTestRepository): Resettable
}
}

@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class CoronaTestStorageDataStore

private const val LEGACY_SHARED_PREFS_CORONA_TEST_STORAGE_SETTINGS_NAME = "coronatest_localdata"
private const val STORAGE_DATASTORE_CORONA_TEST_STORAGE_SETTINGS_NAME = "corona_test_storage"
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class CoronaTestRepository @Inject constructor(
sharingBehavior = SharingStarted.Eagerly,
) {
val legacyTests = legacyMigration.startMigration()
val persistedTests = storage.coronaTests
val persistedTests = storage.getCoronaTests()
legacyTests.plus(persistedTests)
.associateBy { it.identifier }
.also {
Expand Down Expand Up @@ -83,7 +83,7 @@ class CoronaTestRepository @Inject constructor(
.onStart { Timber.tag(TAG).d("Observing test data.") }
.onEach {
Timber.tag(TAG).v("CoronaTest data changed: %s", it)
storage.coronaTests = it.values.toSet()
storage.updateCoronaTests(it.values.toSet())
legacyMigration.finishMigration()
contactDiaryRepository.updateTests(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
import de.rki.coronawarnapp.storage.TracingSettings
import de.rki.coronawarnapp.submission.SubmissionSettings
import de.rki.coronawarnapp.util.CWADebug
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import timber.log.Timber
Expand All @@ -28,15 +29,15 @@ class PCRTestMigration @Inject constructor(
isMigrating = true
Timber.tag(TAG).i("startMigration()")

val token: RegistrationToken? = submissionSettings.registrationTokenMigration
val token: RegistrationToken? = submissionSettings.registrationTokenMigration.first()
if (token == null) {
Timber.tag(TAG).d("Nothing to migrate, token was null.")
return emptySet()
} else {
Timber.tag(TAG).i("Migrating token %s", token)
}

val devicePairingSuccessfulAt = submissionSettings.devicePairingSuccessfulAtMigration
val devicePairingSuccessfulAt = submissionSettings.devicePairingSuccessfulAtMigration.first()
Timber.tag(TAG).v("devicePairingSuccessfulAt=%s", devicePairingSuccessfulAt)
if (devicePairingSuccessfulAt == null) {
if (CWADebug.isDeviceForTestersBuild) {
Expand All @@ -45,16 +46,16 @@ class PCRTestMigration @Inject constructor(
return emptySet()
}

val isAllowedToSubmitKeys = submissionSettings.isAllowedToSubmitKeysMigration
val isAllowedToSubmitKeys = submissionSettings.isAllowedToSubmitKeysMigration.first()
Timber.tag(TAG).v("isAllowedToSubmitKeys=%s", isAllowedToSubmitKeys)

val isSubmissionSuccessful = submissionSettings.isSubmissionSuccessfulMigration
val isSubmissionSuccessful = submissionSettings.isSubmissionSuccessfulMigration.first()
Timber.tag(TAG).v("isSubmissionSuccessful=%s", isSubmissionSuccessful)

val hasViewedTestResult = submissionSettings.hasViewedTestResultMigration
val hasViewedTestResult = submissionSettings.hasViewedTestResultMigration.first()
Timber.tag(TAG).v("hasViewedTestResult=%s", hasViewedTestResult)

val hasGivenConsent = submissionSettings.hasGivenConsentMigration
val hasGivenConsent = submissionSettings.hasGivenConsentMigration.first()
Timber.tag(TAG).v("hasGivenConsent=%s", hasGivenConsent)

val testResultNotificationSent = tracingSettings.isTestResultAvailableNotificationSentMigration()
Expand Down
Loading