diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt
index 5f2f3a274e85e9c145fb7c1cab7cf55586869160..383ad820a7bc2d2ce99f9951c6d4e9cf23da06cb 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt
@@ -30,7 +30,7 @@ import de.rki.coronawarnapp.tracing.ui.statusbar.TracingHeaderState
 import de.rki.coronawarnapp.ui.main.home.items.FAQCard
 import de.rki.coronawarnapp.ui.main.home.items.HomeItem
 import de.rki.coronawarnapp.ui.statistics.Statistics
-import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
 import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import io.mockk.MockKAnnotations
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
index d57407ef4e48d7f63255544a925d6fdae4e261a8..1424f07424a203095617263ea68c00219f6c235d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
@@ -21,9 +21,8 @@ import de.rki.coronawarnapp.exception.reporting.ErrorReportReceiver
 import de.rki.coronawarnapp.exception.reporting.ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL
 import de.rki.coronawarnapp.notification.NotificationHelper
 import de.rki.coronawarnapp.risk.RiskLevelChangeDetector
-import de.rki.coronawarnapp.submission.SubmissionSettings
 import de.rki.coronawarnapp.storage.OnboardingSettings
-import de.rki.coronawarnapp.storage.preferences.EncryptedPreferencesMigration
+import de.rki.coronawarnapp.submission.SubmissionSettings
 import de.rki.coronawarnapp.submission.auto.AutoSubmission
 import de.rki.coronawarnapp.task.TaskController
 import de.rki.coronawarnapp.util.CWADebug
@@ -62,7 +61,6 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
     @Inject lateinit var autoSubmission: AutoSubmission
     @Inject lateinit var submissionSettings: SubmissionSettings
     @Inject lateinit var onboardingSettings: OnboardingSettings
-    @Inject lateinit var encryptedPreferencesMigration: EncryptedPreferencesMigration
 
     @LogHistoryTree @Inject lateinit var rollingLogHistory: Timber.Tree
 
@@ -71,12 +69,15 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
         super.onCreate()
         CWADebug.init(this)
 
-        Timber.v("onCreate(): Initializing Dagger")
-        AppInjector.init(this)
+        AppInjector.init(this).let { compPreview ->
+            Timber.v("Calling EncryptedPreferencesMigration.doMigration()")
+            compPreview.encryptedMigration.doMigration()
 
-        CWADebug.initAfterInjection(component)
+            CWADebug.initAfterInjection(compPreview)
 
-        encryptedPreferencesMigration.doMigration()
+            Timber.v("Completing application injection")
+            compPreview.inject(this)
+        }
 
         BackgroundWorkScheduler.init(component)
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/ContactDiaryRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/ContactDiaryRepository.kt
index d2685422c75f1161e171c2fc4a5316c7ffd85542..c37acddbee5b455fb54e3b5a1f9f689f6f164d21 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/ContactDiaryRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/ContactDiaryRepository.kt
@@ -22,7 +22,11 @@ interface ContactDiaryRepository {
     val locationVisits: Flow<List<ContactDiaryLocationVisit>>
     fun locationVisitsForDate(date: LocalDate): Flow<List<ContactDiaryLocationVisit>>
     suspend fun addLocationVisit(contactDiaryLocationVisit: ContactDiaryLocationVisit)
-    suspend fun updateLocationVisit(contactDiaryLocationVisit: ContactDiaryLocationVisit)
+    suspend fun updateLocationVisit(
+        visitId: Long,
+        update: (ContactDiaryLocationVisit) -> ContactDiaryLocationVisit
+    )
+
     suspend fun deleteLocationVisit(contactDiaryLocationVisit: ContactDiaryLocationVisit)
     suspend fun deleteLocationVisits(contactDiaryLocationVisits: List<ContactDiaryLocationVisit>)
     suspend fun deleteAllLocationVisits()
@@ -39,7 +43,11 @@ interface ContactDiaryRepository {
     val personEncounters: Flow<List<ContactDiaryPersonEncounter>>
     fun personEncountersForDate(date: LocalDate): Flow<List<ContactDiaryPersonEncounter>>
     suspend fun addPersonEncounter(contactDiaryPersonEncounter: ContactDiaryPersonEncounter)
-    suspend fun updatePersonEncounter(contactDiaryPersonEncounter: ContactDiaryPersonEncounter)
+    suspend fun updatePersonEncounter(
+        encounterId: Long,
+        update: (ContactDiaryPersonEncounter) -> ContactDiaryPersonEncounter
+    )
+
     suspend fun deletePersonEncounter(contactDiaryPersonEncounter: ContactDiaryPersonEncounter)
     suspend fun deletePersonEncounters(contactDiaryPersonEncounters: List<ContactDiaryPersonEncounter>)
     suspend fun deleteAllPersonEncounters()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt
index b4a1e1efa058075f393ef3fd6c18b11110ea7bbf..e94102ed82addadc6217416651ab874248d45ae0 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt
@@ -11,8 +11,10 @@ import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryLocationVisitDa
 import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryPersonDao
 import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryPersonEncounterDao
 import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryLocationEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryLocationVisit
 import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryLocationVisitEntity
 import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryLocationVisitSortedList
+import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryPersonEncounter
 import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryPersonEncounterEntity
 import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryPersonEncounterSortedList
 import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryPersonEntity
@@ -108,10 +110,14 @@ class DefaultContactDiaryRepository @Inject constructor(
         contactDiaryLocationVisitDao.insert(contactDiaryLocationVisitEntity)
     }
 
-    override suspend fun updateLocationVisit(contactDiaryLocationVisit: ContactDiaryLocationVisit) {
-        executeWhenIdNotDefault(contactDiaryLocationVisit.id) {
-            val contactDiaryLocationVisitEntity = contactDiaryLocationVisit.toContactDiaryLocationVisitEntity()
-            contactDiaryLocationVisitDao.update(contactDiaryLocationVisitEntity)
+    override suspend fun updateLocationVisit(
+        visitId: Long,
+        update: (ContactDiaryLocationVisit) -> ContactDiaryLocationVisit
+    ) {
+        executeWhenIdNotDefault(visitId) {
+            val original = contactDiaryLocationVisitDao.entityForId(visitId)
+            val updatedVisit = update(original.toContactDiaryLocationVisit())
+            contactDiaryLocationVisitDao.update(updatedVisit.toContactDiaryLocationVisitEntity())
         }
     }
 
@@ -202,10 +208,14 @@ class DefaultContactDiaryRepository @Inject constructor(
         contactDiaryPersonEncounterDao.insert(contactDiaryPersonEncounterEntity)
     }
 
-    override suspend fun updatePersonEncounter(contactDiaryPersonEncounter: ContactDiaryPersonEncounter) {
-        executeWhenIdNotDefault(contactDiaryPersonEncounter.id) {
-            val contactDiaryPersonEncounterEntity = contactDiaryPersonEncounter.toContactDiaryPersonEncounterEntity()
-            contactDiaryPersonEncounterDao.update(contactDiaryPersonEncounterEntity)
+    override suspend fun updatePersonEncounter(
+        encounterId: Long,
+        update: (ContactDiaryPersonEncounter) -> ContactDiaryPersonEncounter
+    ) {
+        executeWhenIdNotDefault(encounterId) {
+            val original = contactDiaryPersonEncounterDao.entityForId(encounterId)
+            val updatedEncounter = update(original.toContactDiaryPersonEncounter())
+            contactDiaryPersonEncounterDao.update(updatedEncounter.toContactDiaryPersonEncounterEntity())
         }
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListViewModel.kt
index 76950a4124614d5c14863ba6f63aa49d33c7e12c..874d073130c504d9620a5a079d587899e9c66c59 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListViewModel.kt
@@ -99,9 +99,11 @@ class ContactDiaryLocationListViewModel @AssistedInject constructor(
         item: DiaryLocationListItem,
         duration: Duration?
     ) {
-        val visit = item.visit?.toEditableVariant() ?: return
+        val visit = item.visit ?: return
         launchOnAppScope {
-            contactDiaryRepository.updateLocationVisit(visit.copy(duration = duration))
+            contactDiaryRepository.updateLocationVisit(visit.id) {
+                it.toEditableVariant().copy(duration = duration)
+            }
         }
     }
 
@@ -109,10 +111,12 @@ class ContactDiaryLocationListViewModel @AssistedInject constructor(
         item: DiaryLocationListItem,
         circumstances: String
     ) {
-        val visit = item.visit?.toEditableVariant() ?: return
+        val visit = item.visit ?: return
         val sanitized = circumstances.trim().trimToLength(250)
         launchOnAppScope {
-            contactDiaryRepository.updateLocationVisit(visit.copy(circumstances = sanitized))
+            contactDiaryRepository.updateLocationVisit(visit.id) {
+                it.toEditableVariant().copy(circumstances = sanitized)
+            }
         }
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListViewModel.kt
index a0add62e4ef1b7334a00817de8a6f1397651cea3..1e60f3f349564e6d5334ad8d515f94f4ae856c04 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListViewModel.kt
@@ -95,9 +95,11 @@ class ContactDiaryPersonListViewModel @AssistedInject constructor(
         duration: ContactDiaryPersonEncounter.DurationClassification?
     ) {
         Timber.d("onDurationChanged(item=%s, duration=%s)", item, duration)
-        val encounter = item.personEncounter?.toEditableVariant() ?: return
+        val encounter = item.personEncounter ?: return
         launchOnAppScope {
-            contactDiaryRepository.updatePersonEncounter(encounter.copy(durationClassification = duration))
+            contactDiaryRepository.updatePersonEncounter(encounter.id) {
+                it.toEditableVariant().copy(durationClassification = duration)
+            }
         }
     }
 
@@ -112,9 +114,11 @@ class ContactDiaryPersonListViewModel @AssistedInject constructor(
         withMask: Boolean?
     ) {
         Timber.d("onWithmaskChanged(item=%s, withMask=%s)", item, withMask)
-        val encounter = item.personEncounter?.toEditableVariant() ?: return
+        val encounter = item.personEncounter ?: return
         launchOnAppScope {
-            contactDiaryRepository.updatePersonEncounter(encounter.copy(withMask = withMask))
+            contactDiaryRepository.updatePersonEncounter(encounter.id) {
+                it.toEditableVariant().copy(withMask = withMask)
+            }
         }
     }
 
@@ -123,9 +127,11 @@ class ContactDiaryPersonListViewModel @AssistedInject constructor(
         wasOutside: Boolean?
     ) {
         Timber.d("onWasOutsideChanged(item=%s, onWasOutside=%s)", item, wasOutside)
-        val encounter = item.personEncounter?.toEditableVariant() ?: return
+        val encounter = item.personEncounter ?: return
         launchOnAppScope {
-            contactDiaryRepository.updatePersonEncounter(encounter.copy(wasOutside = wasOutside))
+            contactDiaryRepository.updatePersonEncounter(encounter.id) {
+                it.toEditableVariant().copy(wasOutside = wasOutside)
+            }
         }
     }
 
@@ -134,10 +140,12 @@ class ContactDiaryPersonListViewModel @AssistedInject constructor(
         circumstances: String
     ) {
         Timber.d("onCircumstancesChanged(item=%s, circumstances=%s)", item, circumstances)
-        val encounter = item.personEncounter?.toEditableVariant() ?: return
+        val encounter = item.personEncounter ?: return
         launchOnAppScope {
             val sanitized = circumstances.trim().trimToLength(250)
-            contactDiaryRepository.updatePersonEncounter(encounter.copy(circumstances = sanitized))
+            contactDiaryRepository.updatePersonEncounter(encounter.id) {
+                it.toEditableVariant().copy(circumstances = sanitized)
+            }
         }
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/adapter/day/DayDataNestedAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/adapter/day/DayDataNestedAdapter.kt
index b0cc6fb871c794021930ae919214725af1a11d9b..6de2a0cceec2ec82c2952544f8bd7bf982f35115 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/adapter/day/DayDataNestedAdapter.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/adapter/day/DayDataNestedAdapter.kt
@@ -53,7 +53,7 @@ class DayDataNestedAdapter : BaseAdapter<DayDataNestedAdapter.NestedItemViewHold
             mutableListOf<String>().apply {
                 duration?.run {
                     if (duration != Duration.ZERO) {
-                        val durationSuffix = context.getString(R.string.contact_diary_overview_location_duration_suffix)
+                        val durationSuffix = context.getString(R.string.contact_diary_location_visit_duration_hour)
                         add(toReadableDuration(suffix = durationSuffix))
                     }
                 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/common/Calculations.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/common/Calculations.kt
index 25531761c63d7553637cce94d1418271e1f927d3..e4bf062aff616dfd3b93d89885cc04ee79dfc14c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/common/Calculations.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/common/Calculations.kt
@@ -8,8 +8,9 @@ fun calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
     lastChangeCheckedRiskLevelTimestamp: Instant?,
     testRegisteredAt: Instant?
 ): Int {
-    val lastChangeCheckedRiskLevelDate = lastChangeCheckedRiskLevelTimestamp?.toLocalDate() ?: return 0
-    val testRegisteredAtDate = testRegisteredAt?.toLocalDate() ?: return 0
+    val lastChangeCheckedRiskLevelDate = lastChangeCheckedRiskLevelTimestamp?.toLocalDate() ?: return -1
+    val testRegisteredAtDate = testRegisteredAt?.toLocalDate() ?: return -1
+    if (lastChangeCheckedRiskLevelDate.isAfter(testRegisteredAtDate)) return -1
     return Days.daysBetween(
         lastChangeCheckedRiskLevelDate,
         testRegisteredAtDate
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollector.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollector.kt
index 138e26fa4fd7b0076569ae63527f2ca5d0479487..81529146337c67d83d97488a976bd00f81ebb0cb 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollector.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollector.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission
 
+import de.rki.coronawarnapp.datadonation.analytics.common.calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration
 import de.rki.coronawarnapp.datadonation.analytics.common.toMetadataRiskLevel
 import de.rki.coronawarnapp.datadonation.analytics.storage.AnalyticsSettings
 import de.rki.coronawarnapp.risk.RiskLevelSettings
@@ -54,6 +55,13 @@ class AnalyticsKeySubmissionCollector @Inject constructor(
                 }
             }
         }
+
+        analyticsKeySubmissionStorage.daysSinceMostRecentDateAtRiskLevelAtTestRegistration.update {
+            calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
+                riskLevelSettings.lastChangeCheckedRiskLevelTimestamp,
+                testRegisteredAt
+            )
+        }
     }
 
     fun reportSubmitted() {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepository.kt
index b2d639381ce9edda8d010567061a65ffbf3a8d16..cad4c220a7ee0a8d45a97ceef7786642a5758b4e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepository.kt
@@ -1,15 +1,10 @@
 package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission
 
-import de.rki.coronawarnapp.datadonation.analytics.common.calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration
-import de.rki.coronawarnapp.risk.RiskLevelSettings
 import org.joda.time.Duration
-import org.joda.time.Instant
 import javax.inject.Inject
-import kotlin.math.max
 
 class AnalyticsKeySubmissionRepository @Inject constructor(
-    private val storage: AnalyticsKeySubmissionStorage,
-    private val riskLevelSettings: RiskLevelSettings
+    private val storage: AnalyticsKeySubmissionStorage
 ) {
     val testResultReceivedAt: Long
         get() = storage.testResultReceivedAt.value
@@ -42,16 +37,23 @@ class AnalyticsKeySubmissionRepository @Inject constructor(
         get() = storage.advancedConsentGiven.value
 
     val hoursSinceTestResult: Int
-        get() = Duration.millis(max(submittedAt - testResultReceivedAt, 0)).toStandardHours().hours
+        get() {
+            if (submittedAt <= 0) return -1
+            if (testResultReceivedAt <= 0) return -1
+            if (submittedAt < testResultReceivedAt) return -1
+            return Duration.millis(submittedAt - testResultReceivedAt).toStandardHours().hours
+        }
 
     val hoursSinceTestRegistration: Int
-        get() = Duration.millis(max(submittedAt - testRegisteredAt, 0L)).toStandardHours().hours
+        get() {
+            if (submittedAt <= 0) return -1
+            if (testRegisteredAt <= 0) return -1
+            if (submittedAt < testRegisteredAt) return -1
+            return Duration.millis(submittedAt - testRegisteredAt).toStandardHours().hours
+        }
 
     val daysSinceMostRecentDateAtRiskLevelAtTestRegistration: Int
-        get() = calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
-            riskLevelSettings.lastChangeCheckedRiskLevelTimestamp,
-            Instant.ofEpochMilli(testRegisteredAt)
-        )
+        get() = storage.daysSinceMostRecentDateAtRiskLevelAtTestRegistration.value
 
     val hoursSinceHighRiskWarningAtTestRegistration: Int
         get() = storage.hoursSinceHighRiskWarningAtTestRegistration.value
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionStorage.kt
index 085c5fe727216fee0a3f963e2548ac568412cf70..48fb47afea4097015b1594ba611ac4f935b588e9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionStorage.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionStorage.kt
@@ -73,6 +73,11 @@ class AnalyticsKeySubmissionStorage @Inject constructor(
         defaultValue = -1
     )
 
+    val daysSinceMostRecentDateAtRiskLevelAtTestRegistration = prefs.createFlowPreference(
+        key = "analytics_key_submission_daysSinceMostRecentDateAtRiskLevelAtTestRegistration",
+        defaultValue = -1
+    )
+
     fun clear() {
         prefs.clearAndNotify()
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt
index 34f8be0bb2a6df2029de72f0de6a2888206da592..4cf07f10e528732e5e7c71c6fc973c3cfb792983 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt
@@ -3,13 +3,10 @@ package de.rki.coronawarnapp.datadonation.analytics.modules.registeredtest
 import de.rki.coronawarnapp.datadonation.analytics.common.calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration
 import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule
 import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings
-import de.rki.coronawarnapp.risk.RiskLevelSettings
-import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
 import de.rki.coronawarnapp.submission.SubmissionSettings
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.formatter.TestResult
-import kotlinx.coroutines.flow.first
 import org.joda.time.Duration
 import org.joda.time.Instant
 import timber.log.Timber
@@ -19,8 +16,6 @@ import javax.inject.Singleton
 @Singleton
 class TestResultDonor @Inject constructor(
     private val testResultDonorSettings: TestResultDonorSettings,
-    private val riskLevelSettings: RiskLevelSettings,
-    private val riskLevelStorage: RiskLevelStorage,
     private val timeStamper: TimeStamper,
     private val submissionSettings: SubmissionSettings
 ) : DonorModule {
@@ -28,42 +23,66 @@ class TestResultDonor @Inject constructor(
     override suspend fun beginDonation(request: DonorModule.Request): DonorModule.Contribution {
         val scannedAfterConsent = testResultDonorSettings.testScannedAfterConsent.value
         if (!scannedAfterConsent) {
-            Timber.d("Skipping TestResultMetadata donation (testScannedAfterConsent=%s)", scannedAfterConsent)
+            Timber.d("Skipping TestResultMetadata donation (scannedAfterConsent=%s)", scannedAfterConsent)
             return TestResultMetadataNoContribution
         }
 
         val timestampAtRegistration = submissionSettings.initialTestResultReceivedAt
-
         if (timestampAtRegistration == null) {
-            Timber.d("Skipping TestResultMetadata donation timestampAtRegistration isn't found")
+            Timber.d("Skipping TestResultMetadata donation (timestampAtRegistration is missing)")
             return TestResultMetadataNoContribution
         }
 
-        val configHours = request
-            .currentConfig
-            .analytics
-            .hoursSinceTestRegistrationToSubmitTestResultMetadata
-
-        val hoursSinceTestRegistrationTime = Duration(timestampAtRegistration, timeStamper.nowUTC).standardHours.toInt()
-        val isDiffHoursMoreThanConfigHoursForPendingTest = hoursSinceTestRegistrationTime >= configHours
+        val testResultAtRegistration = testResultDonorSettings.testResultAtRegistration.value
+        if (testResultAtRegistration == null) {
+            Timber.d("Skipping TestResultMetadata donation (testResultAtRegistration is missing)")
+            return TestResultMetadataNoContribution
+        }
 
-        val testResultAtRegistration =
-            testResultDonorSettings.testResultAtRegistration.value ?: return TestResultMetadataNoContribution
+        val lastChangeCheckedRiskLevelTimestamp = testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel.value
+        if (lastChangeCheckedRiskLevelTimestamp == null) {
+            Timber.d("Skipping TestResultMetadata donation (lastChangeCheckedRiskLevelTimestamp is missing)")
+            return TestResultMetadataNoContribution
+        }
 
         val daysSinceMostRecentDateAtRiskLevelAtTestRegistration =
             calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
-                riskLevelSettings.lastChangeCheckedRiskLevelTimestamp,
+                lastChangeCheckedRiskLevelTimestamp,
                 timestampAtRegistration
             )
 
+        Timber.i(
+            "daysSinceMostRecentDateAtRiskLevelAtTestRegistration: %s",
+            daysSinceMostRecentDateAtRiskLevelAtTestRegistration
+        )
+
         val riskLevelAtRegistration = testResultDonorSettings.riskLevelAtTestRegistration.value
+        val highRiskResultCalculatedAt = testResultDonorSettings.riskLevelTurnedRedTime.value
 
         val hoursSinceHighRiskWarningAtTestRegistration =
             if (riskLevelAtRegistration == PpaData.PPARiskLevel.RISK_LEVEL_LOW) {
                 DEFAULT_HOURS_SINCE_HIGH_RISK_WARNING
             } else {
-                calculatedHoursSinceHighRiskWarning(timestampAtRegistration)
+                if (highRiskResultCalculatedAt == null) {
+                    Timber.d("Skipping TestResultMetadata donation (highRiskResultCalculatedAt is missing)")
+                    return TestResultMetadataNoContribution
+                }
+
+                Timber.i(
+                    "highRiskResultCalculatedAt: %s, timestampAtRegistration: %s",
+                    highRiskResultCalculatedAt,
+                    timestampAtRegistration
+                )
+                calculatedHoursSinceHighRiskWarning(highRiskResultCalculatedAt, timestampAtRegistration)
             }
+        Timber.i(
+            "hoursSinceHighRiskWarningAtTestRegistration: %s",
+            hoursSinceHighRiskWarningAtTestRegistration
+        )
+
+        val configHours = request.currentConfig.analytics.hoursSinceTestRegistrationToSubmitTestResultMetadata
+        val hoursSinceTestRegistrationTime = Duration(timestampAtRegistration, timeStamper.nowUTC).standardHours.toInt()
+        val isDiffHoursMoreThanConfigHoursForPendingTest = hoursSinceTestRegistrationTime >= configHours
 
         return when {
             /**
@@ -134,8 +153,13 @@ class TestResultDonor @Inject constructor(
     ): DonorModule.Contribution {
         val finalTestResultReceivedAt = testResultDonorSettings.finalTestResultReceivedAt.value
         val hoursSinceTestRegistrationTime = if (finalTestResultReceivedAt != null) {
-            Duration(registrationTime, finalTestResultReceivedAt).standardHours.toInt()
+            Timber.i("finalTestResultReceivedAt: %s", finalTestResultReceivedAt)
+            Timber.i("registrationTime: %s", registrationTime)
+            Duration(registrationTime, finalTestResultReceivedAt).standardHours.toInt().also {
+                Timber.i("Calculated hoursSinceTestRegistrationTime: %s", it)
+            }
         } else {
+            Timber.i("Default hoursSinceTestRegistrationTime")
             DEFAULT_HOURS_SINCE_TEST_REGISTRATION_TIME
         }
 
@@ -153,14 +177,10 @@ class TestResultDonor @Inject constructor(
         return TestResultMetadataContribution(testResultMetaData, ::cleanUp)
     }
 
-    private suspend fun calculatedHoursSinceHighRiskWarning(registrationTime: Instant): Int {
-        val highRiskResultCalculatedAt = riskLevelStorage
-            .latestAndLastSuccessful
-            .first()
-            .filter { it.isIncreasedRisk }
-            .minByOrNull { it.calculatedAt }
-            ?.calculatedAt ?: return DEFAULT_HOURS_SINCE_HIGH_RISK_WARNING
-
+    private fun calculatedHoursSinceHighRiskWarning(
+        highRiskResultCalculatedAt: Instant,
+        registrationTime: Instant
+    ): Int {
         return Duration(
             highRiskResultCalculatedAt,
             registrationTime
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/TestResultDonorSettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/TestResultDonorSettings.kt
index 11b76710c64c003c3c22715ce996e2afaee6d2f3..ccc15cb891da84070ffc49410ffcb03cc6acafff 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/TestResultDonorSettings.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/TestResultDonorSettings.kt
@@ -65,6 +65,34 @@ class TestResultDonorSettings @Inject constructor(
         }
     )
 
+    val mostRecentDateWithHighOrLowRiskLevel = prefs.createFlowPreference(
+        key = PREFS_KEY_MOST_RECENT_WITH_HIGH_OR_LOW_RISK_LEVEL,
+        reader = { key ->
+            getLong(key, 0L).let {
+                if (it != 0L) {
+                    Instant.ofEpochMilli(it)
+                } else null
+            }
+        },
+        writer = { key, value ->
+            putLong(key, value?.millis ?: 0L)
+        }
+    )
+
+    val riskLevelTurnedRedTime = prefs.createFlowPreference(
+        key = PREFS_KEY_RISK_LEVEL_TURNED_RED_TIME,
+        reader = { key ->
+            getLong(key, 0L).let {
+                if (it != 0L) {
+                    Instant.ofEpochMilli(it)
+                } else null
+            }
+        },
+        writer = { key, value ->
+            putLong(key, value?.millis ?: 0L)
+        }
+    )
+
     fun saveTestResultDonorDataAtRegistration(testResult: TestResult, lastRiskResult: RiskLevelResult) {
         testScannedAfterConsent.update { true }
         testResultAtRegistration.update { testResult }
@@ -82,5 +110,8 @@ class TestResultDonorSettings @Inject constructor(
         private const val PREFS_KEY_TEST_RESULT_AT_REGISTRATION = "testResultDonor.testResultAtRegistration"
         private const val PREFS_KEY_RISK_LEVEL_AT_REGISTRATION = "testResultDonor.riskLevelAtRegistration"
         private const val PREFS_KEY_FINAL_TEST_RESULT_RECEIVED_AT = "testResultDonor.finalTestResultReceivedAt"
+        private const val PREFS_KEY_RISK_LEVEL_TURNED_RED_TIME = "testResultDonor.riskLevelTurnedRedTime"
+        private const val PREFS_KEY_MOST_RECENT_WITH_HIGH_OR_LOW_RISK_LEVEL =
+            "testResultDonor.mostRecentWithHighOrLowRiskLevel"
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/main/CWASettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/main/CWASettings.kt
index e335d18c8d841cfbacf6813521731ef5a3908e3f..86a3b42668eb0f9d689b5b70307a3403d991a863 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/main/CWASettings.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/main/CWASettings.kt
@@ -25,6 +25,10 @@ class CWASettings @Inject constructor(
         get() = prefs.getBoolean(PKEY_DEVICE_TIME_INCORRECT_ACK, false)
         set(value) = prefs.edit { putBoolean(PKEY_DEVICE_TIME_INCORRECT_ACK, value) }
 
+    var wasTracingExplanationDialogShown: Boolean
+        get() = prefs.getBoolean(PKEY_TRACING_DIALOG_SHOWN, false)
+        set(value) = prefs.edit { putBoolean(PKEY_TRACING_DIALOG_SHOWN, value) }
+
     var wasInteroperabilityShownAtLeastOnce: Boolean
         get() = prefs.getBoolean(PKEY_INTEROPERABILITY_SHOWED_AT_LEAST_ONCE, false)
         set(value) = prefs.edit { putBoolean(PKEY_INTEROPERABILITY_SHOWED_AT_LEAST_ONCE, value) }
@@ -50,12 +54,12 @@ class CWASettings @Inject constructor(
 
     val isNotificationsRiskEnabled = prefs.createFlowPreference(
         key = PKEY_NOTIFICATIONS_RISK_ENABLED,
-        defaultValue = false
+        defaultValue = true
     )
 
     val isNotificationsTestEnabled = prefs.createFlowPreference(
         key = PKEY_NOTIFICATIONS_TEST_ENABLED,
-        defaultValue = false
+        defaultValue = true
     )
 
     val lastChangelogVersion = prefs.createFlowPreference(
@@ -69,6 +73,7 @@ class CWASettings @Inject constructor(
 
     companion object {
         private const val PKEY_DEVICE_TIME_INCORRECT_ACK = "devicetime.incorrect.acknowledged"
+        private const val PKEY_TRACING_DIALOG_SHOWN = "tracing.dialog.shown"
         private const val PKEY_INTEROPERABILITY_SHOWED_AT_LEAST_ONCE = "interoperability.showed"
         private const val PKEY_DEVICE_TIME_FIRST_RELIABLE = "devicetime.correct.first"
         private const val PKEY_DEVICE_TIME_LAST_STATE_CHANGE_TIME = "devicetime.laststatechange.timestamp"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetector.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetector.kt
index 8a6fe31799602ee50ff2aabe8522054b497c6d00..fbee2b6d4a04294dee741b7565c18047c0cb5631 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetector.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetector.kt
@@ -4,6 +4,7 @@ import android.content.Context
 import androidx.annotation.VisibleForTesting
 import androidx.core.app.NotificationManagerCompat
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings
 import de.rki.coronawarnapp.datadonation.survey.Surveys
 import de.rki.coronawarnapp.notification.NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
 import de.rki.coronawarnapp.notification.NotificationHelper
@@ -34,7 +35,8 @@ class RiskLevelChangeDetector @Inject constructor(
     private val notificationHelper: NotificationHelper,
     private val surveys: Surveys,
     private val submissionSettings: SubmissionSettings,
-    private val tracingSettings: TracingSettings
+    private val tracingSettings: TracingSettings,
+    private val testResultDonorSettings: TestResultDonorSettings
 ) {
 
     fun launch() {
@@ -65,9 +67,54 @@ class RiskLevelChangeDetector @Inject constructor(
 
         val oldRiskState = oldResult.riskState
         val newRiskState = newResult.riskState
-
         Timber.d("Last state was $oldRiskState and current state is $newRiskState")
 
+        // Check sending a notification when risk level changes
+        checkSendingNotification(oldRiskState, newRiskState)
+
+        // Save Survey related data based on the risk state
+        saveSurveyRiskState(oldRiskState, newRiskState, newResult)
+
+        // Save TestDonor risk level timestamps
+        saveTestDonorRiskLevelAnalytics(newResult)
+    }
+
+    private fun saveTestDonorRiskLevelAnalytics(
+        newRiskState: RiskLevelResult
+    ) {
+        // Save riskLevelTurnedRedTime if not already set before for high risk detection
+        Timber.i("riskLevelTurnedRedTime=%s", testResultDonorSettings.riskLevelTurnedRedTime.value)
+        if (testResultDonorSettings.riskLevelTurnedRedTime.value == null) {
+            if (newRiskState.isIncreasedRisk) {
+                testResultDonorSettings.riskLevelTurnedRedTime.update {
+                    newRiskState.calculatedAt
+                }
+                Timber.i(
+                    "riskLevelTurnedRedTime: newRiskState=%s, riskLevelTurnedRedTime=%s",
+                    newRiskState.riskState,
+                    newRiskState.calculatedAt
+                )
+            }
+        }
+
+        // Save most recent date of high or low risks
+        if (newRiskState.riskState in listOf(RiskState.INCREASED_RISK, RiskState.LOW_RISK)) {
+            Timber.i(
+                "mostRecentDateWithHighOrLowRiskLevel: newRiskState=%s, lastRiskEncounterAt=%s",
+                newRiskState.riskState,
+                newRiskState.lastRiskEncounterAt
+            )
+
+            testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel.update {
+                newRiskState.lastRiskEncounterAt
+            }
+        }
+    }
+
+    private suspend fun checkSendingNotification(
+        oldRiskState: RiskState,
+        newRiskState: RiskState
+    ) {
         if (hasHighLowLevelChanged(oldRiskState, newRiskState) && !submissionSettings.isSubmissionSuccessful) {
             Timber.d("Notification Permission = ${notificationManagerCompat.areNotificationsEnabled()}")
 
@@ -82,7 +129,13 @@ class RiskLevelChangeDetector @Inject constructor(
 
             Timber.d("Risk level changed and notification sent. Current Risk level is $newRiskState")
         }
+    }
 
+    private fun saveSurveyRiskState(
+        oldRiskState: RiskState,
+        newRiskState: RiskState,
+        newResult: RiskLevelResult
+    ) {
         if (oldRiskState == RiskState.INCREASED_RISK && newRiskState == RiskState.LOW_RISK) {
             tracingSettings.isUserToBeNotifiedOfLoweredRiskLevel.update { true }
             Timber.d("Risk level changed LocalData is updated. Current Risk level is $newRiskState")
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt
index 0bdfeb13edd4bfc6c51bd722fbc0ebd21d0cdaf5..e9ab8acd4b9393d7fadcb47c61347a08d1ea3c2d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt
@@ -83,8 +83,8 @@ class RiskLevelTask @Inject constructor(
             Timber.d("The current time is %s", it)
         }
 
-        if (submissionSettings.isAllowedToSubmitKeys) {
-            Timber.i("Positive test result, skip risk calculation")
+        if (submissionSettings.isAllowedToSubmitKeys && submissionSettings.hasViewedTestResult.value) {
+            Timber.i("Positive test result and user has seen it, skip risk calculation")
             return RiskLevelTaskResult(
                 calculatedAt = nowUTC,
                 failureReason = FailureReason.POSITIVE_TEST_RESULT
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/preferences/EncryptedPreferencesHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/preferences/EncryptedPreferencesHelper.kt
deleted file mode 100644
index 45b15c4d4b07e2cfc3fe60a6c82221d300dfbca1..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/preferences/EncryptedPreferencesHelper.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package de.rki.coronawarnapp.storage.preferences
-
-import android.content.SharedPreferences
-import android.content.pm.ApplicationInfo
-import androidx.core.content.edit
-import de.rki.coronawarnapp.exception.CwaSecurityException
-import de.rki.coronawarnapp.util.security.EncryptedPreferencesFactory
-import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool
-import de.rki.coronawarnapp.util.security.SecurityConstants
-import java.io.File
-import javax.inject.Inject
-
-class EncryptedPreferencesHelper @Inject constructor(
-    private val applicationInfo: ApplicationInfo,
-    factory: EncryptedPreferencesFactory,
-    encryptionErrorResetTool: EncryptionErrorResetTool
-) {
-
-    private val encryptedPreferencesFile by lazy {
-        File(applicationInfo.dataDir)
-            .resolve("shared_prefs/${SecurityConstants.ENCRYPTED_SHARED_PREFERENCES_FILE}.xml")
-    }
-
-    val encryptedSharedPreferencesInstance: SharedPreferences? by lazy {
-        withSecurityCatch {
-            try {
-                if (encryptedPreferencesFile.exists()) {
-                    factory.create(SecurityConstants.ENCRYPTED_SHARED_PREFERENCES_FILE)
-                } else {
-                    null
-                }
-            } catch (e: Exception) {
-                encryptionErrorResetTool.isResetNoticeToBeShown = true
-                null
-            }
-        }
-    }
-
-    fun clean() {
-        encryptedSharedPreferencesInstance?.edit(true) {
-            clear()
-        }
-        encryptedPreferencesFile.delete()
-    }
-
-    private fun <T> withSecurityCatch(doInCatch: () -> T) = try {
-        doInCatch.invoke()
-    } catch (e: Exception) {
-        throw CwaSecurityException(e)
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt
index 392fcd548e782a4f8cbd0eef0e9ee28c12e931fb..38edfe9df56b54a02f9e8f0f580a80090e5a8b34 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt
@@ -124,6 +124,7 @@ class SubmissionRepository @Inject constructor(
     }
 
     suspend fun asyncRegisterDeviceViaTAN(tan: String) {
+        analyticsKeySubmissionCollector.reset()
         val registrationData = submissionService.asyncRegisterDeviceViaTAN(tan)
         submissionSettings.registrationToken.update {
             registrationData.registrationToken
@@ -136,6 +137,7 @@ class SubmissionRepository @Inject constructor(
     }
 
     suspend fun asyncRegisterDeviceViaGUID(guid: String): TestResult {
+        analyticsKeySubmissionCollector.reset()
         val registrationData = submissionService.asyncRegisterDeviceViaGUID(guid)
         submissionSettings.registrationToken.update {
             registrationData.registrationToken
@@ -163,6 +165,16 @@ class SubmissionRepository @Inject constructor(
             deadmanNotificationScheduler.cancelScheduledWork()
         }
 
+        // https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-4484
+        // User removed a test before 1.11 where due to a bug the timestamp was not removed.
+        if (submissionSettings.initialTestResultReceivedAt != null &&
+            submissionSettings.registrationToken.value != null &&
+            submissionSettings.devicePairingSuccessfulAt == null
+        ) {
+            Timber.tag(TAG).w("User has stale initialTestResultReceivedAt, fixing EXPOSUREAPP-4484.")
+            submissionSettings.initialTestResultReceivedAt = null
+        }
+
         val initialTestResultReceivedTimestamp = submissionSettings.initialTestResultReceivedAt
 
         if (initialTestResultReceivedTimestamp == null) {
@@ -188,7 +200,6 @@ class SubmissionRepository @Inject constructor(
     fun removeTestFromDevice() {
         submissionSettings.hasViewedTestResult.update { false }
         submissionSettings.hasGivenConsent.update { false }
-        analyticsKeySubmissionCollector.reset()
         revokeConsentToSubmission()
         submissionSettings.registrationToken.update { null }
         submissionSettings.devicePairingSuccessfulAt = null
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/TracingExplanationDialog.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/TracingExplanationDialog.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7ebebc73a22e6aef5ae2753807fa505df2e42540
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/TracingExplanationDialog.kt
@@ -0,0 +1,35 @@
+package de.rki.coronawarnapp.tracing.ui
+
+import android.content.Context
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.ui.main.home.HomeFragment
+import de.rki.coronawarnapp.util.DialogHelper
+import javax.inject.Inject
+
+class TracingExplanationDialog @Inject constructor(
+    private val homeFragment: HomeFragment
+) {
+    private val context: Context
+        get() = homeFragment.requireContext()
+
+    fun show(onPositive: () -> Unit) {
+
+        val infoPeriodLogged =
+            context.getString(R.string.risk_details_information_body_period_logged)
+        val infoPeriodLoggedAssessment =
+            context.getString(R.string.risk_details_information_body_period_logged_assessment)
+        val infoFAQ = context.getString(R.string.risk_details_explanation_dialog_faq_body)
+
+        val data = DialogHelper.DialogInstance(
+            context = context,
+            title = context.getString(R.string.risk_details_explanation_dialog_title),
+            message = "$infoPeriodLogged\n$infoPeriodLoggedAssessment\n\n$infoFAQ",
+            positiveButton = context.getString(R.string.errors_generic_button_positive),
+            negativeButton = null,
+            cancelable = null,
+            positiveButtonFunction = onPositive,
+            negativeButtonFunction = {}
+        )
+        DialogHelper.showDialog(data)
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt
index d08a82cd6f66f888f36a0a9a95cdcc59b78b44a7..3c6852ad0031d6b01c70d7df4cc03e7b0b0510ee 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt
@@ -9,6 +9,7 @@ import androidx.recyclerview.widget.DefaultItemAnimator
 import androidx.recyclerview.widget.LinearLayoutManager
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.HomeFragmentLayoutBinding
+import de.rki.coronawarnapp.tracing.ui.TracingExplanationDialog
 import de.rki.coronawarnapp.ui.main.home.popups.DeviceTimeIncorrectDialog
 import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat
 import de.rki.coronawarnapp.util.DialogHelper
@@ -40,6 +41,7 @@ class HomeFragment : Fragment(R.layout.home_fragment_layout), AutoInject {
     val binding: HomeFragmentLayoutBinding by viewBindingLazy()
 
     @Inject lateinit var homeMenu: HomeMenu
+    @Inject lateinit var tracingExplanationDialog: TracingExplanationDialog
     @Inject lateinit var deviceTimeIncorrectDialog: DeviceTimeIncorrectDialog
 
     private val homeAdapter = HomeAdapter()
@@ -91,6 +93,11 @@ class HomeFragment : Fragment(R.layout.home_fragment_layout), AutoInject {
                 HomeFragmentEvents.ShowReactivateRiskCheckDialog -> {
                     showReactivateRiskCheckDialog()
                 }
+                HomeFragmentEvents.ShowTracingExplanation -> {
+                    tracingExplanationDialog.show {
+                        vm.tracingExplanationWasShown()
+                    }
+                }
             }
         }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt
index c99db2506808087fa7d0f2a9a658bee8b84aafd7..45f581002f78709b070aa97ea686d628b72f9188 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt
@@ -2,6 +2,8 @@ package de.rki.coronawarnapp.ui.main.home
 
 sealed class HomeFragmentEvents {
 
+    object ShowTracingExplanation : HomeFragmentEvents()
+
     object ShowErrorResetDialog : HomeFragmentEvents()
 
     object ShowDeleteTestDialog : HomeFragmentEvents()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
index 0c72da282baddaed96138f6756ab8620763cc3b6..53da0dee2c310489f588b9cf8cfa137d1dcd7026 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
@@ -48,13 +48,14 @@ import de.rki.coronawarnapp.tracing.ui.homecards.TracingProgressCard
 import de.rki.coronawarnapp.tracing.ui.statusbar.TracingHeaderState
 import de.rki.coronawarnapp.tracing.ui.statusbar.toHeaderState
 import de.rki.coronawarnapp.ui.main.home.HomeFragmentEvents.ShowErrorResetDialog
+import de.rki.coronawarnapp.ui.main.home.HomeFragmentEvents.ShowTracingExplanation
 import de.rki.coronawarnapp.ui.main.home.items.FAQCard
 import de.rki.coronawarnapp.ui.main.home.items.HomeItem
 import de.rki.coronawarnapp.ui.main.home.items.ReenableRiskCard
 import de.rki.coronawarnapp.util.DeviceUIState
 import de.rki.coronawarnapp.util.NetworkRequestWrapper.Companion.withSuccess
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
-import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
 import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
@@ -99,6 +100,9 @@ class HomeFragmentViewModel @AssistedInject constructor(
             if (errorResetTool.isResetNoticeToBeShown) {
                 popupEvents.postValue(ShowErrorResetDialog)
             }
+            if (!cwaSettings.wasTracingExplanationDialogShown) {
+                popupEvents.postValue(ShowTracingExplanation)
+            }
         }
     }
 
@@ -311,6 +315,10 @@ class HomeFragmentViewModel @AssistedInject constructor(
         cwaSettings.wasDeviceTimeIncorrectAcknowledged = true
     }
 
+    fun tracingExplanationWasShown() {
+        cwaSettings.wasTracingExplanationDialogShown = true
+    }
+
     @AssistedFactory
     interface Factory : SimpleCWAViewModelFactory<HomeFragmentViewModel>
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt
index 9cfc42f4eb2fac80e98b96c934975aeb17e90f36..a008516956732dc82157556906387f2e4206b736 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt
@@ -36,6 +36,7 @@ object CWADebug {
     }
 
     fun initAfterInjection(component: ApplicationComponent) {
+        Timber.v("initAfterInjection(%s)", component)
         // TODO ¯\_(ツ)_/¯
         if (isDeviceForTestersBuild) {
             debugLogger.setInjectionIsReady(component)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/UncaughtExceptionLogger.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/UncaughtExceptionLogger.kt
index f7557924b1dada96fa221eb94ec53a28a6396af8..b7a8db6c2d8f80d67a13c55363314b968873102b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/UncaughtExceptionLogger.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/UncaughtExceptionLogger.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.util.debug
 
+import de.rki.coronawarnapp.bugreporting.reportProblem
 import de.rki.coronawarnapp.util.CWADebug
 import timber.log.Timber
 
@@ -12,15 +13,24 @@ class UncaughtExceptionLogger(
     }
 
     override fun uncaughtException(thread: Thread, error: Throwable) {
-        Timber.tag(thread.name).e(error, "Uncaught exception!")
+        val sourceTag = thread.name
+        Timber.tag(sourceTag).e(error, "Uncaught exception!")
+
+        try {
+            error.reportProblem(tag = sourceTag, "Uncaught exception!")
+        } catch (e: Exception) {
+            Timber.e(e, "reportProblem() failed!?")
+        }
+
         try {
             if (CWADebug.isLogging) {
                 // Make sure this crash is written before killing the app.
                 Thread.sleep(1500)
             }
         } catch (e: Exception) {
-            Timber.w("Couldn't delay exception for debug logger.")
+            Timber.w(e, "Couldn't delay exception for debug logger.")
         }
+
         wrappedHandler?.uncaughtException(thread, error)
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AppInjector.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AppInjector.kt
index 2c63e6eff976b62809dffa04ffacb214778e37c2..12e80b7d71a2160007838ec7639c1c8136769b47 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AppInjector.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AppInjector.kt
@@ -13,9 +13,11 @@ import timber.log.Timber
 object AppInjector {
     lateinit var component: ApplicationComponent
 
-    fun init(app: CoronaWarnApplication) {
-        component = DaggerApplicationComponent.factory().create(app)
-        component.inject(app)
+    fun init(app: CoronaWarnApplication): ApplicationComponent {
+        Timber.v("Initializing Dagger (%s)", app)
+        return DaggerApplicationComponent.factory().create(app).also {
+            component = it
+        }
     }
 
     fun setup(activity: Activity) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
index a2c6ec3d39243cc97bae7269e18dbe1bb09fbde2..dbc57fbeb57043aa52ef75185797fdaae410f5ed 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
@@ -36,8 +36,9 @@ import de.rki.coronawarnapp.util.coroutine.AppCoroutineScope
 import de.rki.coronawarnapp.util.coroutine.AppScope
 import de.rki.coronawarnapp.util.coroutine.CoroutineModule
 import de.rki.coronawarnapp.util.device.DeviceModule
-import de.rki.coronawarnapp.util.security.EncryptedPreferencesFactory
-import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptedPreferencesFactory
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptedPreferencesMigration
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
 import de.rki.coronawarnapp.util.security.SecurityModule
 import de.rki.coronawarnapp.util.serialization.SerializationModule
 import de.rki.coronawarnapp.util.worker.WorkerBinder
@@ -102,6 +103,8 @@ interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> {
 
     fun inject(backgroundWorkScheduler: BackgroundWorkScheduler)
 
+    val encryptedMigration: EncryptedPreferencesMigration
+
     @Component.Factory
     interface Factory {
         fun create(@BindsInstance app: CoronaWarnApplication): ApplicationComponent
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesFactory.kt
similarity index 96%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactory.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesFactory.kt
index 317e3e765f7dd4fe0c60c33f9761ca9e4e2756fc..cd3ec57e86f27d00201f8815f2600f70622c58c1 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactory.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesFactory.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.util.security
+package de.rki.coronawarnapp.util.encryptionmigration
 
 import android.content.Context
 import android.content.SharedPreferences
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesHelper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b585815035c1daba44401b83b28b9f471a8572f3
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesHelper.kt
@@ -0,0 +1,53 @@
+package de.rki.coronawarnapp.util.encryptionmigration
+
+import android.content.SharedPreferences
+import android.content.pm.ApplicationInfo
+import androidx.core.content.edit
+import timber.log.Timber
+import java.io.File
+import javax.inject.Inject
+
+class EncryptedPreferencesHelper @Inject constructor(
+    private val applicationInfo: ApplicationInfo,
+    factory: EncryptedPreferencesFactory
+) {
+
+    private val preferenceFile by lazy {
+        File(applicationInfo.dataDir)
+            .resolve("shared_prefs/$ENCRYPTED_SHARED_PREFERENCES_FILE.xml")
+    }
+
+    val instance: SharedPreferences? by lazy {
+        if (preferenceFile.exists()) {
+            factory.create(ENCRYPTED_SHARED_PREFERENCES_FILE)
+        } else {
+            null
+        }
+    }
+
+    fun clean() {
+        try {
+            instance?.edit(true) {
+                Timber.d("Clearing all encrypted preference values.")
+                clear()
+                Timber.d("Preference values have been cleared.")
+            }
+        } catch (e: Exception) {
+            Timber.w("Failed to clear encrypted preferences.")
+        }
+
+        if (preferenceFile.exists()) {
+            if (preferenceFile.delete()) {
+                Timber.i("Encrypted preference file deleted.")
+            } else {
+                Timber.e("Encrypted preference could not be deleted.")
+            }
+        } else {
+            Timber.d("Encrypted preference file did not exist.")
+        }
+    }
+
+    companion object {
+        private const val ENCRYPTED_SHARED_PREFERENCES_FILE = "shared_preferences_cwa"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/preferences/EncryptedPreferencesMigration.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigration.kt
similarity index 51%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/preferences/EncryptedPreferencesMigration.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigration.kt
index cda45aade8aba1a42b5211b52bbfab33d807f92e..64929458b059e6c40a2ea3e1705d438707916f80 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/preferences/EncryptedPreferencesMigration.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigration.kt
@@ -1,8 +1,10 @@
-package de.rki.coronawarnapp.storage.preferences
+package de.rki.coronawarnapp.util.encryptionmigration
 
 import android.content.Context
 import android.content.SharedPreferences
 import android.database.sqlite.SQLiteDatabase
+import androidx.annotation.VisibleForTesting
+import de.rki.coronawarnapp.bugreporting.reportProblem
 import de.rki.coronawarnapp.main.CWASettings
 import de.rki.coronawarnapp.storage.OnboardingSettings
 import de.rki.coronawarnapp.storage.TracingSettings
@@ -15,34 +17,41 @@ import javax.inject.Inject
 
 class EncryptedPreferencesMigration @Inject constructor(
     @AppContext private val context: Context,
-    private val encryptedPreferencesHelper: EncryptedPreferencesHelper,
+    private val encryptedPreferences: EncryptedPreferencesHelper,
     private val cwaSettings: CWASettings,
     private val submissionSettings: SubmissionSettings,
     private val tracingSettings: TracingSettings,
-    private val onboardingSettings: OnboardingSettings
+    private val onboardingSettings: OnboardingSettings,
+    private val errorResetTool: EncryptionErrorResetTool
 ) {
 
     fun doMigration() {
         Timber.d("Migration start")
         try {
-            copyData()
-            cleanData()
+            encryptedPreferences.instance?.let { copyData(it) }
         } catch (e: Exception) {
-            Timber.e(e, "Migration was not successful")
+            e.reportProblem(tag = this::class.simpleName, info = "Migration failed")
+            errorResetTool.isResetNoticeToBeShown = true
+        } finally {
+            try {
+                encryptedPreferences.clean()
+            } catch (e: Exception) {
+                e.reportProblem(tag = this::class.simpleName, info = "Encryption data clean up failed")
+            }
         }
         try {
             dropDatabase()
         } catch (e: Exception) {
-            Timber.e(e, "Database removing was not successful")
+            e.reportProblem(tag = this::class.simpleName, info = "Database removing failed")
         }
         Timber.d("Migration finish")
     }
 
-    private fun copyData() {
-        val encryptedSharedPreferences = encryptedPreferencesHelper.encryptedSharedPreferencesInstance ?: return
-        Timber.d("EncryptedPreferences are available")
+    private fun copyData(encryptedSharedPreferences: SharedPreferences) {
+        Timber.i("copyData(): EncryptedPreferences are available")
         SettingsLocalData(encryptedSharedPreferences).apply {
             cwaSettings.wasInteroperabilityShownAtLeastOnce = wasInteroperabilityShown()
+            cwaSettings.wasTracingExplanationDialogShown = wasTracingExplanationDialogShown()
             cwaSettings.isNotificationsRiskEnabled.update { isNotificationsRiskEnabled() }
             cwaSettings.isNotificationsTestEnabled.update { isNotificationsTestEnabled() }
             cwaSettings.numberOfRemainingSharePositiveTestResultReminders =
@@ -72,23 +81,30 @@ class EncryptedPreferencesMigration @Inject constructor(
             submissionSettings.isSubmissionSuccessful = numberOfSuccessfulSubmissions() >= 1
             submissionSettings.isAllowedToSubmitKeys = isAllowedToSubmitDiagnosisKeys()
         }
-    }
-
-    private fun cleanData() {
-        encryptedPreferencesHelper.clean()
+        Timber.i("copyData(): EncryptedPreferences have been copied.")
     }
 
     private fun dropDatabase() {
         val file = context.getDatabasePath("coronawarnapp-db")
-        if (file.exists()) {
-            Timber.d("Removing database $file")
-            SQLiteDatabase.deleteDatabase(file)
+        if (!file.exists()) {
+            Timber.d("Encrypted database does not exist.")
+            return
+        }
+
+        Timber.i("Removing database $file")
+        if (SQLiteDatabase.deleteDatabase(file)) {
+            Timber.i("Legacy encrypted database was deleted.")
+        } else {
+            Timber.e("Legacy encrypted database could not be deleted.")
         }
     }
 
-    private class SettingsLocalData(private val sharedPreferences: SharedPreferences) {
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    class SettingsLocalData(private val sharedPreferences: SharedPreferences) {
 
-        fun wasInteroperabilityShown() = sharedPreferences.getBoolean(PREFERENCE_INTEROPERABILITY_WAS_USED, false)
+        fun wasInteroperabilityShown() = sharedPreferences.getBoolean(PKEY_INTEROPERABILITY_WAS_USED, false)
+
+        fun wasTracingExplanationDialogShown() = sharedPreferences.getBoolean(PKEY_TRACING_EXPLANATION_WAS_SHOWN, false)
 
         fun isNotificationsRiskEnabled(): Boolean = sharedPreferences.getBoolean(PKEY_NOTIFICATIONS_RISK_ENABLED, true)
 
@@ -98,15 +114,25 @@ class EncryptedPreferencesMigration @Inject constructor(
             sharedPreferences.getInt(PKEY_POSITIVE_TEST_RESULT_REMINDER_COUNT, Int.MIN_VALUE)
 
         companion object {
-            private const val PREFERENCE_INTEROPERABILITY_WAS_USED = "preference_interoperability_is_used_at_least_once"
-            private const val PKEY_NOTIFICATIONS_RISK_ENABLED = "preference_notifications_risk_enabled"
-            private const val PKEY_NOTIFICATIONS_TEST_ENABLED = "preference_notifications_test_enabled"
-            private const val PKEY_POSITIVE_TEST_RESULT_REMINDER_COUNT =
-                "preference_positive_test_result_reminder_count"
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_INTEROPERABILITY_WAS_USED = "preference_interoperability_is_used_at_least_once"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_TRACING_EXPLANATION_WAS_SHOWN = "preference_risk_days_explanation_shown"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_NOTIFICATIONS_RISK_ENABLED = "preference_notifications_risk_enabled"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_NOTIFICATIONS_TEST_ENABLED = "preference_notifications_test_enabled"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_POSITIVE_TEST_RESULT_REMINDER_COUNT = "preference_positive_test_result_reminder_count"
         }
     }
 
-    private class OnboardingLocalData(private val sharedPreferences: SharedPreferences) {
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    class OnboardingLocalData(private val sharedPreferences: SharedPreferences) {
         fun onboardingCompletedTimestamp(): Long? {
             val timestamp = sharedPreferences.getLong(PKEY_ONBOARDING_COMPLETED_TIMESTAMP, 0L)
 
@@ -117,12 +143,16 @@ class EncryptedPreferencesMigration @Inject constructor(
         fun isBackgroundCheckDone(): Boolean = sharedPreferences.getBoolean(PKEY_BACKGROUND_CHECK_DONE, false)
 
         companion object {
-            private const val PKEY_ONBOARDING_COMPLETED_TIMESTAMP = "preference_onboarding_completed_timestamp"
-            private const val PKEY_BACKGROUND_CHECK_DONE = "preference_background_check_done"
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_ONBOARDING_COMPLETED_TIMESTAMP = "preference_onboarding_completed_timestamp"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_BACKGROUND_CHECK_DONE = "preference_background_check_done"
         }
     }
 
-    private class TracingLocalData(private val sharedPreferences: SharedPreferences) {
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    class TracingLocalData(private val sharedPreferences: SharedPreferences) {
 
         fun initialPollingForTestResultTimeStamp() = sharedPreferences.getLong(PKEY_POOLING_TEST_RESULT_STARTED, 0L)
 
@@ -133,14 +163,22 @@ class EncryptedPreferencesMigration @Inject constructor(
         fun initialTracingActivationTimestamp(): Long = sharedPreferences.getLong(PKEY_TRACING_ACTIVATION_TIME, 0L)
 
         companion object {
-            private const val PKEY_POOLING_TEST_RESULT_STARTED = "preference_polling_test_result_started"
-            private const val PKEY_TEST_RESULT_NOTIFICATION = "preference_test_result_notification"
-            private const val PKEY_HAS_RISK_STATUS_LOWERED = "preference_has_risk_status_lowered"
-            private const val PKEY_TRACING_ACTIVATION_TIME = "preference_initial_tracing_activation_time"
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_POOLING_TEST_RESULT_STARTED = "preference_polling_test_result_started"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_TEST_RESULT_NOTIFICATION = "preference_test_result_notification"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_HAS_RISK_STATUS_LOWERED = "preference_has_risk_status_lowered"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_TRACING_ACTIVATION_TIME = "preference_initial_tracing_activation_time"
         }
     }
 
-    private class SubmissionLocalData(private val sharedPreferences: SharedPreferences) {
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    class SubmissionLocalData(private val sharedPreferences: SharedPreferences) {
         fun registrationToken(): String? = sharedPreferences.getString(PKEY_REGISTRATION_TOKEN, null)
 
         fun initialTestResultReceivedTimestamp(): Long? {
@@ -157,11 +195,20 @@ class EncryptedPreferencesMigration @Inject constructor(
         fun isAllowedToSubmitDiagnosisKeys(): Boolean = sharedPreferences.getBoolean(PKEY_IS_ALLOWED_TO_SUBMIT, false)
 
         companion object {
-            private const val PKEY_REGISTRATION_TOKEN = "preference_registration_token"
-            private const val PKEY_INITIAL_RESULT_RECEIVED_TIME = "preference_initial_result_received_time"
-            private const val PKEY_DEVICE_PARING_SUCCESSFUL_TIME = "preference_device_pairing_successful_time"
-            private const val PKEY_NUMBER_SUCCESSFUL_SUBMISSIONS = "preference_number_successful_submissions"
-            private const val PKEY_IS_ALLOWED_TO_SUBMIT = "preference_is_allowed_to_submit_diagnosis_keys"
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_REGISTRATION_TOKEN = "preference_registration_token"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_INITIAL_RESULT_RECEIVED_TIME = "preference_initial_result_received_time"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_DEVICE_PARING_SUCCESSFUL_TIME = "preference_device_pairing_successful_time"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_NUMBER_SUCCESSFUL_SUBMISSIONS = "preference_number_successful_submissions"
+
+            @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+            const val PKEY_IS_ALLOWED_TO_SUBMIT = "preference_is_allowed_to_submit_diagnosis_keys"
         }
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptionErrorResetTool.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptionErrorResetTool.kt
similarity index 69%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptionErrorResetTool.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptionErrorResetTool.kt
index fd87b8a0ab525bacf7f0e9640088e7e87aedc36d..fd432a8b6191c943c72bf1af70ff82d1e29c3214 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptionErrorResetTool.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptionErrorResetTool.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.util.security
+package de.rki.coronawarnapp.util.encryptionmigration
 
 import android.content.Context
 import android.content.SharedPreferences
@@ -16,12 +16,12 @@ class EncryptionErrorResetTool @Inject constructor(
     }
 
     var isResetNoticeToBeShown: Boolean
-        get() = prefs.getBoolean(PKEY_EA1851_SHOW_RESET_NOTICE, false)
+        get() = prefs.getBoolean(PKEY_EA2850_SHOW_RESET_NOTICE, false)
         set(value) = prefs.edit {
-            putBoolean(PKEY_EA1851_SHOW_RESET_NOTICE, value)
+            putBoolean(PKEY_EA2850_SHOW_RESET_NOTICE, value)
         }
 
     companion object {
-        private const val PKEY_EA1851_SHOW_RESET_NOTICE = "ea1851.reset.shownotice"
+        private const val PKEY_EA2850_SHOW_RESET_NOTICE = "ea2850.reset.shownotice"
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/SecurityConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/SecurityConstants.kt
index 03bffdb2867296613d131f024afafeb9ffbe440d..61ec34895b73e83eb1400d283c0920d69ae7ce04 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/SecurityConstants.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/SecurityConstants.kt
@@ -2,6 +2,5 @@ package de.rki.coronawarnapp.util.security
 
 object SecurityConstants {
     const val DIGEST_ALGORITHM = "SHA-256"
-    const val ENCRYPTED_SHARED_PREFERENCES_FILE = "shared_preferences_cwa"
     const val EXPORT_FILE_SIGNATURE_VERIFICATION_ALGORITHM = "SHA256withECDSA"
 }
diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_overview_nested_list_item.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_overview_nested_list_item.xml
index 12835781db094e25a966de1c3d5b4c89f9f50675..ed7070c5e2c0ae5249f7db018303815e1fe79676 100644
--- a/Corona-Warn-App/src/main/res/layout/contact_diary_overview_nested_list_item.xml
+++ b/Corona-Warn-App/src/main/res/layout/contact_diary_overview_nested_list_item.xml
@@ -34,7 +34,6 @@
         android:ellipsize="end"
         android:focusable="true"
         android:maxLines="3"
-        app:layout_constraintBottom_toBottomOf="@+id/contact_diary_overview_element_image"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toEndOf="@+id/contact_diary_overview_element_image"
         app:layout_constraintTop_toTopOf="@+id/contact_diary_overview_element_image"
diff --git a/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml
index f5bac17c00372220f5e49c9b49af495e3c1aa3a9..58eeab260a9ff94589579c7c9cfbab9b29ac2b73 100644
--- a/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml
@@ -11,7 +11,7 @@
     <string name="contact_diary_person_list_no_items_title">"Все още няма въведени лица"</string>
     <string name="contact_diary_person_list_no_items_subtitle">"Създайте лице и го добавете към Вашия дневник на контактите."</string>
     <string name="contact_diary_add_person_title">"Лице"</string>
-    <string name="contact_diary_add_person_text_input_name_hint">"Име, фамилия"</string>
+    <string name="contact_diary_add_person_text_input_name_hint">"Име"</string>
     <string name="contact_diary_add_text_input_phone_hint">"Телефон"</string>
     <string name="contact_diary_add_text_input_email_hint">"Имейл"</string>
     <string name="contact_diary_add_person_save_button">"Запазване"</string>
@@ -171,6 +171,8 @@
 
     <!-- XBUT: Option - person encounter - inside-->
     <string name="contact_diary_location_visit_duration_label">"Продължителност"</string>
+    <!-- XTXT: Option - location encounter - duration in hours label-->
+    <string name="contact_diary_location_visit_duration_hour">"ч"</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Забележка (напр. препълнено)"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml
index 2b1c8215a61f296bdabe9ccd3f4b739573b5737d..66499d99ee2cc8250d19f113bbb8ba576658e2d8 100644
--- a/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml
@@ -17,25 +17,21 @@
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
         <item>"Швейцария е добавена към международното регистриране на излаганията на риск"</item>
-        <item>"Генериране на отчети за грешки"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
         <item>"Потребителите на Corona-Warn-App вече могат да разменят криптирани случайни идентификатори с потребителите на официалното приложение за борба с коронавируса в Швейцария. Това означава, че потребителите там също могат да изпращат и получават предупреждения."</item>
-        <item>"Вече можете да генерирате отчети за грешките при поискване от техническата поддръжка и да записвате стъпките, които изпълнявате в приложението. Това ще улесни анализа на техническите грешки и ще ускори коригирането им."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
-        <item/>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
-        <item/>
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-bg/strings.xml b/Corona-Warn-App/src/main/res/values-bg/strings.xml
index 498b4a70adc6927a2bfcbac7324d23829ba114a6..bb2c2492c76fa29fd6c60622c01eefd48983f54c 100644
--- a/Corona-Warn-App/src/main/res/values-bg/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/strings.xml
@@ -302,13 +302,14 @@
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
     <string name="risk_details_subtitle_period_logged">"Този период се включва в изчислението."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->
+<!--    Dialog part 1-->
     <string name="risk_details_information_body_period_logged">"Вашият риск от заразяване може да се изчисли само за периодите, в които регистрирането на излаганията на риск е било активно. Ето защо тази функция трябва да бъде активирана постоянно. Регистрирането на контактите Ви покрива последните 14 дни."</string>
     <!-- XTXT: risk details - infection period logged information body, under 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_under_14_days">"Приложението Corona-Warn-App е инсталирано преди %s дни. Рискът да сте се заразили се изчислява за периодите, през които е било активно регистрирането на контактите Ви. Ако сте били в близост до други хора и регистрирането на излаганията е било активно, рискът да сте се заразили ще бъде изчислен."</string>
     <!-- XTXT: risk details - infection period logged information body, over 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_over_14_days">"Ако регистрирането на контактите Ви е било активно, когато сте се срещали с други хора, рискът да сте се заразили през този период ще бъде изчислен."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->	    <!-- XTXT: risk details - infection period logged information body, under 14 days -->
-    <string name="risk_details_information_body_period_logged_assessment">"Регистрирането на излагания на риск покрива последните 14 дни. За този период от време функцията е била активна на Вашия смартфон в продължение на %1$s дни. Приложението изтрива автоматично по-старите регистри, тъй като те вече не могат да служат за предотвратяване на заразяването."</string>
+    <string name="risk_details_information_body_period_logged_assessment">"Приложението изтрива автоматично по-старите регистри, тъй като те вече не могат да служат за предотвратяване на заразяването."</string>
     <!-- XTXT: risk details - infection period days logged/14 -->
     <string name="risk_details_information_active_tracing_days_circle_progress">"%s/14"</string>
     <!-- XHED: risk details - how your risk level was calculated, below behaviors -->
@@ -318,15 +319,13 @@
     <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors -->
     <string name="risk_details_information_body_outdated_risk">"Регистърът на излаганията на риск не е обновяван повече от 24 часа."</string>
     <!-- YTXT: risk details - low risk explanation text -->
-    <string name="risk_details_information_body_low_risk">"Вашето ниво на риск от заразяване е ниско, защото нямате регистрирани контакти с лица, които впоследствие са били диагностицирани с COVID-19, или ако сте имали такива, те са били краткотрайни и от по-голямо разстояние."</string>
+    <string name="risk_details_information_body_low_risk">"Вашето ниво на риск от заразяване е ниско, защото нямате регистрирани контакти с лица, които впоследствие са били диагностицирани с коронавирус, или ако сте имали такива, те са били краткотрайни и от по-голямо разстояние."</string>
     <!-- YTXT: risk details - low risk explanation text with encounter with low risk -->
     <string name="risk_details_information_body_low_risk_with_encounter">"Рискът от заразяване се изчислява локално на смартфона Ви въз основа на регистрираните данни за излагане. Изчислението включва също така разстоянието от и продължителността на всички контакти с лица, диагностицирани с коронавирус, както и възможността им да заразят околните. Никой освен Вас не може да види или да получи данни за Вашето ниво на риск."</string>
-    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
-    <string name="risk_details_explanation_dialog_faq_body">"За повече информация вижте страницата „ЧЗВ“."</string>
     <!-- XLNK: FAQ URL pointing to the faq page in german. Need to use the URL for english for all other languages-->
     <string name="risk_details_explanation_faq_link">"https://www.coronawarn.app/en/faq/#encounter_but_green"</string>
     <!-- YTXT: risk details - increased risk explanation text with variable date since last contact -->
-    <string name="risk_details_information_body_increased_risk_date">"Нивото на риска Ви от заразяване е повишено, защото сте имали продължителен и близък контакт с поне едно лице, диагностицирано с COVID-19."</string>
+    <string name="risk_details_information_body_increased_risk_date">"Нивото на риска Ви от заразяване е повишено, защото сте имали продължителен и близък контакт с поне едно лице, диагностицирано с коронавирус."</string>
     <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact -->
     <plurals name="risk_details_information_body_increased_risk">
         <item quantity="one">"Нивото на риска Ви от заразяване е повишено, защото преди %1$s дни сте имали продължителен и близък контакт с поне едно лице, диагностицирано с коронавирус."</item>
@@ -347,6 +346,10 @@
     <!-- XACT: risk details page title -->
     <string name="risk_details_accessibility_title">"Вашият статус на риск"</string>
 
+    <!-- XHED: one time risk explanation dialog title  -->
+    <string name="risk_details_explanation_dialog_title">"Информация относно функционалността за регистриране на излагания на риск"</string>
+    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
+    <string name="risk_details_explanation_dialog_faq_body">"За повече информация вижте страницата „ЧЗВ“."</string>
     <!-- XHED: risk details - deadman notification title -->
     <string name="risk_details_deadman_notification_title">"Вашият статус на риск"</string>
     <!-- YTXT: risk details - deadman notification text -->
@@ -861,8 +864,22 @@
     <string name="debugging_debuglog_status_not_recording">"Неактивно"</string>
     <!-- YTXT: Describtion for current logging status text if a debug log is not being recorded -->
     <string name="debugging_debuglog_status_additional_infos">"Текущ размер: %1$s (без компресия)"</string>
+
+    <!-- XHED: Title for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_title">"Удостоверяване на автентичността и пренос на данни в други държави"</string>
+    <!-- YTXT: First section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_first_section">"За да бъде потвърдена автентичността на приложението Ви, Вашето устройство генерира уникален идентификатор с информация за версията на устройството и приложението. Това гарантира, че само лицата, които действително използват приложението Corona-Warn-App, могат да изпращат данни до техническата поддръжка и изключва възможността за манипулиране на отчетите. За тази цел идентификаторът се изпраща до Google. При този процес е възможно да бъдат изпратени данни до САЩ или други държави, чието ниво на защита на данните може да не съответства на европейското. По тази причина е възможно да не можете да упражните своите права относно защитата на данните, предвидени в европейското законодателство. По конкретно, службите за сигурност в съответната държава биха могли да осъществят достъп до данните и да ги анализират с Google, независимо от липсата на основание за това, както и да свържат тези данни с друга информация. Това касае само идентификатора, който се изпраща до Google. Google не получава информацията от Вашия отчет за грешките, но е възможно да определи Вашата самоличност на база на идентификатора и чрез проследяване да установи, че проверката за автентичност е извършена на Вашето устройство."</string>
+    <!-- YTXT: Second section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_second_section">"Ако не сте съгласни данните Ви да бъдат пренасяни в други държави, моля не докосвайте бутона “Приемане и изпращане”. В този случай ще можете да използвате приложението, но не и да изпращате отчети за грешки."</string>
+
+    <!-- YTXT: Dialog title if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_title">"Желаете ли да спрете анализа на грешките?"</string>
     <!-- YTXT: Dialog message if the log recording is stopped, and thus deleted. -->
-    <string name="debugging_debuglog_stop_confirmation_message">"Отчетът за грешките е изтрит. Вашето локално копие на отчета, ако сте запазили такова, не е изтрито."</string>
+    <string name="debugging_debuglog_stop_confirmation_message">"Ако потвърдите, всички записани данни ще бъдат изтрити. Вашето локално копие на отчета за грешките, ако сте запазили такова, няма да бъде изтрито."</string>
+    <!-- YTXT: Dialog confirmation button if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_confirmation_button">"Спиране на анализа"</string>
+    <!-- YTXT: Dialog discard button if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_discard_button">"Продължаване на анализа"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"Необходими са поне 200 MB памет, за да се стартира анализа на грешките. Моля, освободете място."</string>
     <!-- XHED: Dialog title if a user has stored a debug log locally -->
@@ -871,7 +888,6 @@
     <string name="debugging_debuglog_localexport_message">"Анализът на грешките е запазен локално."</string>
     <!-- YTXT: Dialog message if local export has failed -->
     <string name="debugging_debuglog_localexport_error_message">"Отчетът за грешките не беше запазен. Моля, проверете дали има достатъчно свободна памет."</string>
-
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Подробна информация относно изпращането на отчети за грешки"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values-de/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-de/contact_diary_strings.xml
index 14b896c15e64f5f50dbff1c922fc46ebbe75be0f..5b15ac7a2a8af86ac0c7dde49ebabc1eebcdc3f2 100644
--- a/Corona-Warn-App/src/main/res/values-de/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/contact_diary_strings.xml
@@ -12,7 +12,7 @@
     <string name="contact_diary_person_list_no_items_title">"Noch keine Personen vorhanden"</string>
     <string name="contact_diary_person_list_no_items_subtitle">"Legen Sie eine Person an und fügen Sie sie in Ihrem Kontakt-Tagebuch hinzu."</string>
     <string name="contact_diary_add_person_title">"Person"</string>
-    <string name="contact_diary_add_person_text_input_name_hint">"Vorname, Nachname"</string>
+    <string name="contact_diary_add_person_text_input_name_hint">"Name"</string>
     <string name="contact_diary_add_text_input_phone_hint">"Telefon"</string>
     <string name="contact_diary_add_text_input_email_hint">"E-Mail"</string>
     <string name="contact_diary_add_person_save_button">"Speichern"</string>
@@ -172,6 +172,8 @@
 
     <!-- XBUT: Option - person encounter - inside-->
     <string name="contact_diary_location_visit_duration_label">Dauer</string>
+    <!-- XTXT: Option - location encounter - duration in hours label-->
+    <string name="contact_diary_location_visit_duration_hour">"Std."</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">Notiz (z.B. sehr voll)</string>
 </resources>
diff --git a/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml
index 55e4acd124fa1a726e68920c53a1a10419efc773..fc43df339c62d57793aa4c2bfbbde19252c350ef 100644
--- a/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml
@@ -17,14 +17,14 @@
 
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
-        <item>Länderübergreifende Risiko-Ermittlung um Schweiz erweitert </item>
-        <item>Erstellung von Fehlerberichten</item>
+        <item>Länderübergreifende Risiko-Ermittlung um Schweiz erweitert</item>
+        <item>Änderung der Risikokarten</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
         <item>Die Corona-Warn-App nutzende Personen können nun auch verschlüsselte Zufalls-IDs mit Personen austauschen, die die offizielle Warn-App der Schweiz nutzen. Somit können Warnungen an App nutzende Personen in der Schweiz geschickt sowie von ihnen empfangen werden.</item>
-        <item>Sie können nun nach Aufforderung des technischen Supports einen Fehlerbericht erstellen und die Schritte aufzeichnen, die Sie in der App ausführen. Mögliche technische Fehler können so besser analysiert und schneller behoben werden. </item>
+        <item>Auf den Risikokarten entfällt die Anzeige der Anzahl aktiver Tage bzw. dass die App dauerhaft aktiv ist.</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
diff --git a/Corona-Warn-App/src/main/res/values-de/strings.xml b/Corona-Warn-App/src/main/res/values-de/strings.xml
index 964add2daa2f2a0cec4d6479af6c654e9a58cb26..7e1eea15b050b7302ec1a6e26ecc91b6be3094b2 100644
--- a/Corona-Warn-App/src/main/res/values-de/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/strings.xml
@@ -267,7 +267,7 @@
     <!-- XHED: risk details - headline, how a user should act -->
     <string name="risk_details_headline_behavior">"Verhalten"</string>
     <!-- XHED: risk details - multiline headline, bold, how to act correct -->
-    <string name="risk_details_subtitle_behavior">"So verhalten Sie sich richtig:"</string>
+    <string name="risk_details_subtitle_behavior">"So verhalten Sie sich richtig."</string>
     <!-- XMSG: risk details - go/stay home, something like a bullet point -->
     <string name="risk_details_behavior_body_stay_home">"Begeben Sie sich, wenn möglich, nach Hause bzw. bleiben Sie zu Hause."</string>
     <!-- XMSG: risk details - get in touch with the corresponding people, something like a bullet point -->
@@ -303,13 +303,14 @@
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
     <string name="risk_details_subtitle_period_logged">"Dieser Zeitraum wird berücksichtigt."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->
+<!--    Dialog part 1-->
     <string name="risk_details_information_body_period_logged">"Die Berechnung des Infektionsrisikos kann nur für die Zeiträume erfolgen, an denen die Risiko-Ermittlung aktiv war. Die Risiko- Ermittlung sollte daher dauerhaft aktiv sein. Für Ihre Risiko-Ermittlung wird der Zeitraum der letzten 14 Tage betrachtet."</string>
     <!-- XTXT: risk details - infection period logged information body, under 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_under_14_days">"Die Corona-Warn-App ist seit %s Tagen installiert. Das Infektionsrisiko wird für Zeiträume berechnet, in denen die Risiko-Ermittlung aktiv ist. Wenn Sie andere Personen getroffen haben und die Risiko-Ermittlung aktiv war, wird Ihr Infektions-Risiko berechnet."</string>
     <!-- XTXT: risk details - infection period logged information body, over 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_over_14_days">"Wenn die Risiko-Ermittlung zu Zeiten in denen sie andere Personen getroffen haben aktiv war, kann die Berechnung des Infektionsrisikos für diesen Zeitraum erfolgen."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->	    <!-- XTXT: risk details - infection period logged information body, under 14 days -->
-    <string name="risk_details_information_body_period_logged_assessment">"Für Ihre Risiko-Ermittlung wird nur der Zeitraum der letzten 14 Tage betrachtet. In diesem Zeitraum war Ihre Risiko-Ermittlung für eine Gesamtdauer von %1$s Tagen aktiv. Ältere Tage werden automatisch gelöscht, da sie aus Sicht des Infektionsschutzes nicht mehr relevant sind."</string>
+    <string name="risk_details_information_body_period_logged_assessment">"Ältere Tage werden automatisch gelöscht, da sie aus Sicht des Infektionsschutzes nicht mehr relevant sind."</string>
     <!-- XTXT: risk details - infection period days logged/14 -->
     <string name="risk_details_information_active_tracing_days_circle_progress">"%s/14"</string>
     <!-- XHED: risk details - how your risk level was calculated, below behaviors -->
@@ -322,8 +323,6 @@
     <string name="risk_details_information_body_low_risk">"Sie haben ein niedriges Infektionsrisiko, da keine Begegnung mit nachweislich Corona-positiv getesteten Personen aufgezeichnet wurde oder sich Ihre Begegnung auf kurze Zeit und einen größeren Abstand beschränkt hat."</string>
     <!-- YTXT: risk details - low risk explanation text with encounter with low risk -->
     <string name="risk_details_information_body_low_risk_with_encounter">"Das Infektionsrisiko wird anhand der Daten der Risiko-Ermittlung unter Berücksichtigung des Abstands und der Dauer von Begegnungen mit nachweislich Corona-positiv getesteten Personen sowie deren vermutlicher Infektiosität lokal auf Ihrem Smartphone berechnet. Ihr Infektionsrisiko ist für niemanden einsehbar und wird nicht weitergegeben."</string>
-    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
-    <string name="risk_details_explanation_dialog_faq_body">"Weitere Informationen finden Sie in den FAQ."</string>
     <!-- XLNK: FAQ URL pointing to the faq page in german. Need to use the URL for english for all other languages-->
     <string name="risk_details_explanation_faq_link">"https://www.coronawarn.app/de/faq/#encounter_but_green"</string>
     <!-- YTXT: risk details - increased risk explanation text with variable date since last contact -->
@@ -348,6 +347,10 @@
     <!-- XACT: risk details page title -->
     <string name="risk_details_accessibility_title">"Ihr Risikostatus"</string>
 
+    <!-- XHED: one time risk explanation dialog title  -->
+    <string name="risk_details_explanation_dialog_title">"Information zur Funktionsweise der Risiko-Ermittlung"</string>
+    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
+    <string name="risk_details_explanation_dialog_faq_body">"Weitere Informationen finden Sie in den FAQ."</string>
     <!-- XHED: risk details - deadman notification title -->
     <string name="risk_details_deadman_notification_title">"Ihr Risikostatus"</string>
     <!-- YTXT: risk details - deadman notification text -->
@@ -1916,7 +1919,7 @@
     <!-- XHED: Duration dialog title -->
     <string name="duration_dialog_title">Dauer</string>
     <!-- XBUT: Duration dialog cancel button -->
-    <string name="duration_dialog_cancel_button">Cancel</string>
+    <string name="duration_dialog_cancel_button">Abbrechen</string>
     <!-- XBUT: Duration dialog ok button -->
     <string name="duration_dialog_ok_button">OK</string>
     <!-- NOTR -->
diff --git a/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml
index a22bfd48628ca00e49482eb0232fe4069fe7cac8..04adc0cbda65628fae2abfe1344b441960330109 100644
--- a/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml
@@ -11,7 +11,7 @@
     <string name="contact_diary_person_list_no_items_title">"No people defined yet"</string>
     <string name="contact_diary_person_list_no_items_subtitle">"Create a person and add them to your contact journal."</string>
     <string name="contact_diary_add_person_title">"Person"</string>
-    <string name="contact_diary_add_person_text_input_name_hint">"First name, last name"</string>
+    <string name="contact_diary_add_person_text_input_name_hint">"Name"</string>
     <string name="contact_diary_add_text_input_phone_hint">"Phone"</string>
     <string name="contact_diary_add_text_input_email_hint">"e-mail"</string>
     <string name="contact_diary_add_person_save_button">"Save"</string>
@@ -171,6 +171,8 @@
 
     <!-- XBUT: Option - person encounter - inside-->
     <string name="contact_diary_location_visit_duration_label">"Duration"</string>
+    <!-- XTXT: Option - location encounter - duration in hours label-->
+    <string name="contact_diary_location_visit_duration_hour">"hrs"</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Note (e.g. very full)"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml
index a38294582a252128ce8c879e7f0876c1d713e2b3..36c5c5426805e97d153731b2a688da698836ee23 100644
--- a/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml
@@ -17,25 +17,21 @@
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
         <item>"Switzerland Added to Transnational Exposure Logging"</item>
-        <item>"Generation of Error Reports"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
         <item>"Corona-Warn-App users can now exchange encrypted random IDs with users of the official warning app in Switzerland. This means warnings can now be sent to and received from app users in Switzerland."</item>
-        <item>"You can now generate an error report, upon request by technical support, and record the steps that you perform in the app. This will make it easier to analyze technical errors and correct them more quickly."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
-        <item/>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
-        <item/>
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-en/strings.xml b/Corona-Warn-App/src/main/res/values-en/strings.xml
index d21b9aeb089913ffc7d1e701b4293a6ab9c9c404..e5206e48b57afe72226a41661833b2acc1457844 100644
--- a/Corona-Warn-App/src/main/res/values-en/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/strings.xml
@@ -302,13 +302,14 @@
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
     <string name="risk_details_subtitle_period_logged">"This period is included in the calculation."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->
+<!--    Dialog part 1-->
     <string name="risk_details_information_body_period_logged">"Your risk of infection can be calculated only for periods during which exposure logging was active. The logging feature should therefore remain active permanently. Exposure logging covers the last 14 days."</string>
     <!-- XTXT: risk details - infection period logged information body, under 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_under_14_days">"The Corona-Warn-App was installed %s ago. Your risk of infection is calculated for the periods during which exposure logging was active. If you have encountered other people and exposure logging was active, your risk of infection is calculated."</string>
     <!-- XTXT: risk details - infection period logged information body, over 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_over_14_days">"If exposure logging was active in times during which you encountered other people, your risk of infection can be calculated for this period."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->	    <!-- XTXT: risk details - infection period logged information body, under 14 days -->
-    <string name="risk_details_information_body_period_logged_assessment">"Exposure logging covers the past 14 days. During this time, the logging feature on your smartphone was active for %1$s days. The app automatically deletes older logs, as these are no longer relevant for infection prevention."</string>
+    <string name="risk_details_information_body_period_logged_assessment">"The app automatically deletes older logs, as these are no longer relevant for infection prevention."</string>
     <!-- XTXT: risk details - infection period days logged/14 -->
     <string name="risk_details_information_active_tracing_days_circle_progress">"%s/14"</string>
     <!-- XHED: risk details - how your risk level was calculated, below behaviors -->
@@ -318,15 +319,13 @@
     <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors -->
     <string name="risk_details_information_body_outdated_risk">"Your exposure logging could not be updated for more than 24 hours."</string>
     <!-- YTXT: risk details - low risk explanation text -->
-    <string name="risk_details_information_body_low_risk">"You have a low risk of infection because no exposure to people later diagnosed with COVID-19 was logged, or because your encounters were only for a short time and at a greater distance."</string>
+    <string name="risk_details_information_body_low_risk">"You have a low risk of infection because no exposure to people later diagnosed with coronavirus was logged, or because your encounters were only for a short time and at a greater distance."</string>
     <!-- YTXT: risk details - low risk explanation text with encounter with low risk -->
     <string name="risk_details_information_body_low_risk_with_encounter">"The risk of infection is calculated locally on your smartphone, using exposure logging data. The calculation also takes into account distance and duration of any exposure to persons diagnosed with coronavirus, as well as their potential infectiousness. Your risk of infection cannot be seen by or passed on to anyone else."</string>
-    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
-    <string name="risk_details_explanation_dialog_faq_body">"For further information, please see our FAQ page."</string>
     <!-- XLNK: FAQ URL pointing to the faq page in german. Need to use the URL for english for all other languages-->
     <string name="risk_details_explanation_faq_link">"https://www.coronawarn.app/en/faq/#encounter_but_green"</string>
     <!-- YTXT: risk details - increased risk explanation text with variable date since last contact -->
-    <string name="risk_details_information_body_increased_risk_date">"You have an increased risk of infection because you were exposed over a longer period of time and at close proximity to at least one person diagnosed with COVID-19."</string>
+    <string name="risk_details_information_body_increased_risk_date">"You have an increased risk of infection because you were exposed over a longer period of time and at close proximity to at least one person diagnosed with coronavirus."</string>
     <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact -->
     <plurals name="risk_details_information_body_increased_risk">
         <item quantity="one">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with coronavirus."</item>
@@ -347,6 +346,10 @@
     <!-- XACT: risk details page title -->
     <string name="risk_details_accessibility_title">"Your Risk Status"</string>
 
+    <!-- XHED: one time risk explanation dialog title  -->
+    <string name="risk_details_explanation_dialog_title">"Information about exposure logging functionality"</string>
+    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
+    <string name="risk_details_explanation_dialog_faq_body">"For further information, please see our FAQ page."</string>
     <!-- XHED: risk details - deadman notification title -->
     <string name="risk_details_deadman_notification_title">"Your Risk Status"</string>
     <!-- YTXT: risk details - deadman notification text -->
@@ -861,8 +864,22 @@
     <string name="debugging_debuglog_status_not_recording">"Inactive"</string>
     <!-- YTXT: Describtion for current logging status text if a debug log is not being recorded -->
     <string name="debugging_debuglog_status_additional_infos">"Current size: %1$s (uncompressed)"</string>
+
+    <!-- XHED: Title for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_title">"Verification of Authenticity and Data Transfer to Third Countries"</string>
+    <!-- YTXT: First section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_first_section">"To confirm the authenticity of your app, your smartphone generates a unique identifier that contains information about the version of your smartphone and the app. This is necessary to ensure that only people who actually use the Corona-Warn-App can send data to technical support and rule out manipulated error reports. To do so, the identifier is sent to Google. In this process, data may be transferred to the U.S. or other third countries, where the level of data privacy may not correspond to European law and you may not be able to enforce your European rights to data privacy. In particular, security services in the third country could access and analyze the data with Google, even if there is no grounds for suspicion, and link this data with other information, for example. This only involves the identifier that is sent to Google. Google does not receive the information from your error report, however, Google may be able to determine your identity based on the identifier and track that the authenticity check was performed on your smartphone."</string>
+    <!-- YTXT: Second section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_second_section">"If you do not consent to this transfer of your data to a third country, please do not tap on “Accept and Send”. You will still be able to use the app, but you cannot send error reports."</string>
+
+    <!-- YTXT: Dialog title if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_title">"Stop the error analysis?"</string>
     <!-- YTXT: Dialog message if the log recording is stopped, and thus deleted. -->
-    <string name="debugging_debuglog_stop_confirmation_message">"The error report was deleted. If you have saved a local copy of the error report, it was not deleted."</string>
+    <string name="debugging_debuglog_stop_confirmation_message">"If you do so, all recorded data will be deleted. If you have saved a local copy of the error report, it will not be deleted."</string>
+    <!-- YTXT: Dialog confirmation button if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_confirmation_button">"Stop Analysis"</string>
+    <!-- YTXT: Dialog discard button if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_discard_button">"Continue Analysis"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"You need at least 200 MB of memory to start the error analysis. Please free up memory."</string>
     <!-- XHED: Dialog title if a user has stored a debug log locally -->
@@ -871,7 +888,6 @@
     <string name="debugging_debuglog_localexport_message">"The error analysis was saved locally."</string>
     <!-- YTXT: Dialog message if local export has failed -->
     <string name="debugging_debuglog_localexport_error_message">"The attempt to save the error report failed. Please check whether enough memory is available."</string>
-
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Detailed Information on Sending Error Reports"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values-pl/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-pl/contact_diary_strings.xml
index e5e2c254fd356e1a863dc83095273658a237032e..6311de577d870a2f9caf2eb764b960133e8ee37c 100644
--- a/Corona-Warn-App/src/main/res/values-pl/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/contact_diary_strings.xml
@@ -11,7 +11,7 @@
     <string name="contact_diary_person_list_no_items_title">"Nie zdefiniowano jeszcze żadnych osób"</string>
     <string name="contact_diary_person_list_no_items_subtitle">"Utwórz osobę i dodaj ją do dziennika kontaktów."</string>
     <string name="contact_diary_add_person_title">"Osoba"</string>
-    <string name="contact_diary_add_person_text_input_name_hint">"ImiÄ™, nazwisko"</string>
+    <string name="contact_diary_add_person_text_input_name_hint">"ImiÄ™ i nazwisko"</string>
     <string name="contact_diary_add_text_input_phone_hint">"Telefon"</string>
     <string name="contact_diary_add_text_input_email_hint">"E-mail"</string>
     <string name="contact_diary_add_person_save_button">"Zapisz"</string>
@@ -171,6 +171,8 @@
 
     <!-- XBUT: Option - person encounter - inside-->
     <string name="contact_diary_location_visit_duration_label">"Czas trwania"</string>
+    <!-- XTXT: Option - location encounter - duration in hours label-->
+    <string name="contact_diary_location_visit_duration_hour">"godz."</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Uwaga (np. bardzo pełny)"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml
index 5bc9b0023e7e19071f869c456e2e5f2844c2b34e..1c75cff3d82b6ecbf567a85f0e9b94c1c245fdc9 100644
--- a/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml
@@ -17,25 +17,21 @@
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
         <item>"Do międzynarodowego rejestrowania narażenia dodano Szwajcarię."</item>
-        <item>"Generowanie raportów o błędach"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
         <item>"Użytkownicy aplikacji Corona-Warn-App mogą teraz wymieniać zaszyfrowane losowe identyfikatory z użytkownikami oficjalnej aplikacji ostrzegawczej w Szwajcarii. Oznacza to, że ostrzeżenia mogą być teraz wysyłane do użytkowników aplikacji w Szwajcarii i od nich odbierane."</item>
-        <item>"Na prośbę działu wsparcia technicznego możesz teraz wygenerować raport o błędach i zapisać czynności wykonane w aplikacji. Ułatwi to analizę błędów technicznych i przyśpieszy ich usuwanie."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
-        <item/>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
-        <item/>
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-pl/strings.xml b/Corona-Warn-App/src/main/res/values-pl/strings.xml
index 37ffe028420b7ee05fc4b06555231732833cf717..c6761ed9046e131ba3baa8af40abac8c6c5138f5 100644
--- a/Corona-Warn-App/src/main/res/values-pl/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/strings.xml
@@ -302,13 +302,14 @@
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
     <string name="risk_details_subtitle_period_logged">"Ten okres jest uwzględniony w obliczeniu."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->
+<!--    Dialog part 1-->
     <string name="risk_details_information_body_period_logged">"Ryzyko zakażenia można obliczyć tylko dla okresów, w których rejestrowanie narażenia było aktywne. Dlatego też funkcja rejestrowania powinna być stale aktywna. Rejestrowanie narażenia obejmuje 14 ostatnich dni."</string>
     <!-- XTXT: risk details - infection period logged information body, under 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_under_14_days">"Aplikacja Corona-Warn-App została zainstalowana %s temu. Ryzyko zakażenia jest obliczane dla okresów, w których aktywne było rejestrowanie narażenia. Oblicza się je w przypadku kontaktowania się z innymi ludźmi przy aktywnej funkcji rejestrowania narażenia."</string>
     <!-- XTXT: risk details - infection period logged information body, over 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_over_14_days">"Jeśli rejestrowanie narażenia było aktywne podczas kontaktowania się z innymi ludźmi, można obliczyć ryzyko zakażenia dla tego okresu."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->	    <!-- XTXT: risk details - infection period logged information body, under 14 days -->
-    <string name="risk_details_information_body_period_logged_assessment">"Rejestrowanie narażenia obejmuje ostatnie 14 dni. W tym czasie funkcja rejestrowania w Twoim smartfonie była aktywna przez %1$s dni. Aplikacja automatycznie usuwa starsze dzienniki, ponieważ nie są one już istotne dla zapobiegania zakażeniom."</string>
+    <string name="risk_details_information_body_period_logged_assessment">"Aplikacja automatycznie usuwa starsze dzienniki, ponieważ nie są one już istotne dla zapobiegania zakażeniom."</string>
     <!-- XTXT: risk details - infection period days logged/14 -->
     <string name="risk_details_information_active_tracing_days_circle_progress">"%s/14"</string>
     <!-- XHED: risk details - how your risk level was calculated, below behaviors -->
@@ -318,15 +319,13 @@
     <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors -->
     <string name="risk_details_information_body_outdated_risk">"Rejestrowanie narażenia nie mogło zostać zaktualizowane przez okres dłuższy niż 24 godziny."</string>
     <!-- YTXT: risk details - low risk explanation text -->
-    <string name="risk_details_information_body_low_risk">"Masz niskie ryzyko zakażenia, ponieważ nie zarejestrowano narażenia na kontakt z osobami, u których później zdiagnozowano COVID-19, lub ponieważ Twoje kontakty trwały krótko przy zachowaniu odpowiednio dużej odległości."</string>
+    <string name="risk_details_information_body_low_risk">"Masz niskie ryzyko zakażenia, ponieważ nie zarejestrowano narażenia na kontakt z osobami, u których później zdiagnozowano koronawirusa, lub ponieważ Twoje kontakty trwały krótko przy zachowaniu odpowiednio dużej odległości."</string>
     <!-- YTXT: risk details - low risk explanation text with encounter with low risk -->
     <string name="risk_details_information_body_low_risk_with_encounter">"Ryzyko zakażenia jest obliczane lokalnie na Twoim smartfonie na podstawie danych rejestrowania narażenia. Ta kalkulacja uwzględnia również dystans i czas trwania narażenia na kontakt z osobami, u których zdiagnozowano koronawirusa, a także ich potencjalną zakaźność. Twoje ryzyko zakażenia nie jest widoczne dla nikogo ani nikomu przekazywane."</string>
-    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
-    <string name="risk_details_explanation_dialog_faq_body">"Więcej informacji znajduje się na naszej stronie „Często zadawane pytania”."</string>
     <!-- XLNK: FAQ URL pointing to the faq page in german. Need to use the URL for english for all other languages-->
     <string name="risk_details_explanation_faq_link">"https://www.coronawarn.app/en/faq/#encounter_but_green"</string>
     <!-- YTXT: risk details - increased risk explanation text with variable date since last contact -->
-    <string name="risk_details_information_body_increased_risk_date">"Masz podwyższone ryzyko zakażenia, ponieważ byłeś(-aś) narażony(-a) na dłuższy, bliski kontakt z co najmniej jedną osobą, u której zdiagnozowano COVID-19."</string>
+    <string name="risk_details_information_body_increased_risk_date">"Masz podwyższone ryzyko zakażenia, ponieważ byłeś(-aś) narażony(-a) na dłuższy, bliski kontakt z co najmniej jedną osobą, u której zdiagnozowano koronawirusa."</string>
     <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact -->
     <plurals name="risk_details_information_body_increased_risk">
         <item quantity="one">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dzień temu byłeś(-aś) narażony(-a) na dłuższy, bliski kontakt z co najmniej jedną osobą, u której zdiagnozowano koronawirusa."</item>
@@ -347,6 +346,10 @@
     <!-- XACT: risk details page title -->
     <string name="risk_details_accessibility_title">"Twój status ryzyka"</string>
 
+    <!-- XHED: one time risk explanation dialog title  -->
+    <string name="risk_details_explanation_dialog_title">"Informacje o funkcjonalności rejestrowania narażenia"</string>
+    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
+    <string name="risk_details_explanation_dialog_faq_body">"Więcej informacji znajduje się na naszej stronie „Często zadawane pytania”."</string>
     <!-- XHED: risk details - deadman notification title -->
     <string name="risk_details_deadman_notification_title">"Twój status ryzyka"</string>
     <!-- YTXT: risk details - deadman notification text -->
@@ -861,8 +864,22 @@
     <string name="debugging_debuglog_status_not_recording">"Nieaktywne"</string>
     <!-- YTXT: Describtion for current logging status text if a debug log is not being recorded -->
     <string name="debugging_debuglog_status_additional_infos">"Bieżący rozmiar: %1$s (nieskompresowane)"</string>
+
+    <!-- XHED: Title for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_title">"Weryfikacja autentyczności i przekazywanie danych do krajów trzecich"</string>
+    <!-- YTXT: First section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_first_section">"Aby potwierdzić autentyczność aplikacji, smartfon generuje unikalny identyfikator zawierający informacje o wersji smartfona i aplikacji. Jest to konieczne w celu zapewnienia, by tylko osoby, które faktycznie używają aplikacji Corona-Warn-App mogły wysyłać dane do pomocy technicznej, i wykluczenia zmanipulowanych raportów o błędach. W tym celu identyfikator jest wysyłany do Google. W tym procesie dane mogą być przekazywane do Stanów Zjednoczonych lub innych krajów trzecich, gdzie poziom prywatności danych może nie odpowiadać prawu europejskiemu i możesz nie być w stanie wyegzekwować swoich europejskich praw do prywatności danych. W szczególności organy ds. bezpieczeństwa w kraju trzecim mogłyby uzyskać dostęp do danych i analizować je przy pomocy Google, nawet jeśli nie ma podstaw do podejrzeń, i na przykład łączyć te dane z innymi informacjami. Dotyczy to tylko identyfikatora wysyłanego do Google. Google nie otrzymuje informacji z Twojego raportu o błędzie, może jednak określić Twoją tożsamość na podstawie identyfikatora i poprzez prześledzenie danych ustalić, że sprawdzanie autentyczności zostało przeprowadzone na Twoim smartfonie."</string>
+    <!-- YTXT: Second section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_second_section">"Jeśli nie wyrażasz zgody na przekazanie swoich danych do kraju trzeciego, nie klikaj opcji „Akceptuj i wyślij”. Nadal będziesz mieć możliwość korzystania z aplikacji, ale wysyłanie raportów o błędach będzie niemożliwe."</string>
+
+    <!-- YTXT: Dialog title if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_title">"Zatrzymać analizę błędu?"</string>
     <!-- YTXT: Dialog message if the log recording is stopped, and thus deleted. -->
-    <string name="debugging_debuglog_stop_confirmation_message">"Raport o błędzie został usunięty. Jeśli zapisano lokalną kopię raportu o błędzie, nie została ona usunięta."</string>
+    <string name="debugging_debuglog_stop_confirmation_message">"Jeśli to zrobisz, wszystkie zapisane dane zostaną usunięte. Jeśli zapisano lokalną kopię raportu o błędzie, nie zostanie ona usunięta."</string>
+    <!-- YTXT: Dialog confirmation button if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_confirmation_button">"Zatrzymaj analizÄ™"</string>
+    <!-- YTXT: Dialog discard button if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_discard_button">"Kontynuuj analizÄ™"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"Aby rozpocząć analizę błędu, potrzebujesz co najmniej 200 MB pamięci. Zwolnij pamięć."</string>
     <!-- XHED: Dialog title if a user has stored a debug log locally -->
@@ -871,7 +888,6 @@
     <string name="debugging_debuglog_localexport_message">"Analiza błędu została zapisana lokalnie."</string>
     <!-- YTXT: Dialog message if local export has failed -->
     <string name="debugging_debuglog_localexport_error_message">"Próba zapisania raportu o błędzie nie powiodła się. Sprawdź, czy dostępna jest wystarczająca ilość pamięci."</string>
-
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Szczegółowe informacje na temat wysyłania raportów o błędach"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml
index c20ccc9263e7b6b1efc1b3f84ab5e9454564b60a..9f9b2d09386e71ee7441376f754ce609fc69ec49 100644
--- a/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml
@@ -11,7 +11,7 @@
     <string name="contact_diary_person_list_no_items_title">"Nicio persoană definită deocamdată"</string>
     <string name="contact_diary_person_list_no_items_subtitle">"Creați o persoană și adăugați-o la jurnalul dvs. de contacte."</string>
     <string name="contact_diary_add_person_title">"Persoană"</string>
-    <string name="contact_diary_add_person_text_input_name_hint">"Prenume, nume"</string>
+    <string name="contact_diary_add_person_text_input_name_hint">"Nume"</string>
     <string name="contact_diary_add_text_input_phone_hint">"Telefon"</string>
     <string name="contact_diary_add_text_input_email_hint">"e-mail"</string>
     <string name="contact_diary_add_person_save_button">"Salvare"</string>
@@ -171,6 +171,8 @@
 
     <!-- XBUT: Option - person encounter - inside-->
     <string name="contact_diary_location_visit_duration_label">"Durată"</string>
+    <!-- XTXT: Option - location encounter - duration in hours label-->
+    <string name="contact_diary_location_visit_duration_hour">"ore"</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Notă (de ex., foarte plin)"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml
index b94156bacd13e0489712e0d481d712c0f3b60e90..0229a5b41b90a83927a9fedaf274d2eb05ca7f40 100644
--- a/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml
@@ -17,25 +17,21 @@
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
         <item>"A fost adăugată Elveția la înregistrarea transnațională a expunerilor în jurnal"</item>
-        <item>"Generarea rapoartelor de erori"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
         <item>"Utilizatorii aplicației Corona-Warn pot schimba acum ID-uri aleatorii criptate cu utilizatorii aplicației oficiale de avertizare din Elveția. Aceasta înseamnă că avertizările pot fi acum trimise și primite de utilizatorii aplicației din Elveția."</item>
-        <item>"Acum puteți genera un raport de erori, la cerere de la suportul tehnic, și puteți înregistra etapele pe care le efectuați în aplicație. Această acțiune va facilita analizarea erorilor tehnice și corecția mai rapidă a acestora."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
-        <item/>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
-        <item/>
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-ro/strings.xml b/Corona-Warn-App/src/main/res/values-ro/strings.xml
index ce6862eda5e9ecc090476dddc2648c28bec826a7..3510d8122bc8d3faf590e06b8a16bb5a93ac0077 100644
--- a/Corona-Warn-App/src/main/res/values-ro/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/strings.xml
@@ -302,13 +302,14 @@
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
     <string name="risk_details_subtitle_period_logged">"Această perioadă este inclusă în calcul."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->
+<!--    Dialog part 1-->
     <string name="risk_details_information_body_period_logged">"Riscul dvs. de infectare poate fi calculat doar pentru perioadele în care a fost activă înregistrarea în jurnal a expunerilor. Prin urmare, caracteristica de înregistrare în jurnal trebuie să rămână permanent activă. Înregistrarea în jurnal a expunerilor acoperă ultimele 14 zile."</string>
     <!-- XTXT: risk details - infection period logged information body, under 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_under_14_days">"Aplicația Corona-Warn a fost instalată acum %s. Riscul dvs. de infectare este calculat pentru perioadele în care înregistrarea în jurnal a expunerilor a fost activă. Dacă v-ați întâlnit cu alte persoane și înregistrarea în jurnal a expunerilor a fost activă, este calculat riscul dvs. de infectare."</string>
     <!-- XTXT: risk details - infection period logged information body, over 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_over_14_days">"Dacă înregistrarea în jurnal a expunerilor a fost activă pe durata în care v-ați întâlnit cu alte persoane, riscul dvs. de infectare poate fi calculat pentru această perioadă."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->	    <!-- XTXT: risk details - infection period logged information body, under 14 days -->
-    <string name="risk_details_information_body_period_logged_assessment">"Înregistrarea în jurnal a expunerilor acoperă ultimele 14 zile. În această perioadă, caracteristica de înregistrare în jurnal de pe smartphone-ul dvs. a fost activă timp de %1$s zile. Aplicația șterge automat înregistrările mai vechi din jurnal, întrucât acestea nu mai sunt relevante pentru prevenirea infectării."</string>
+    <string name="risk_details_information_body_period_logged_assessment">"Aplicația șterge automat înregistrările mai vechi din jurnal, întrucât acestea nu mai sunt relevante pentru prevenirea infectării."</string>
     <!-- XTXT: risk details - infection period days logged/14 -->
     <string name="risk_details_information_active_tracing_days_circle_progress">"%s/14"</string>
     <!-- XHED: risk details - how your risk level was calculated, below behaviors -->
@@ -318,15 +319,13 @@
     <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors -->
     <string name="risk_details_information_body_outdated_risk">"Înregistrarea în jurnal a expunerilor dvs. nu a putut fi actualizată timp de peste 24 de ore."</string>
     <!-- YTXT: risk details - low risk explanation text -->
-    <string name="risk_details_information_body_low_risk">"Aveți un risc redus de infectare deoarece nu a fost înregistrată nicio expunere la persoane diagnosticate ulterior cu COVID-19 sau întâlnirile dvs. au fost limitate la o perioadă scurtă și la o distanță mai mare."</string>
+    <string name="risk_details_information_body_low_risk">"Aveți un risc redus de infectare deoarece nu a fost înregistrată nicio expunere la persoane diagnosticate ulterior cu coronavirus sau întâlnirile dvs. au fost limitate la o perioadă scurtă și la o distanță mai mare."</string>
     <!-- YTXT: risk details - low risk explanation text with encounter with low risk -->
     <string name="risk_details_information_body_low_risk_with_encounter">"Riscul de infectare este calculat local pe smartphone-ul dvs., utilizând datele de înregistrare în jurnal a expunerilor. Calculul poate ține cont și de distanța și durata expunerii la persoane diagnosticate cu coronavirus, precum și de potențiala contagiozitate a acestora. Riscul dvs. de infectare nu poate fi observat sau transmis mai departe niciunei alte persoane."</string>
-    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
-    <string name="risk_details_explanation_dialog_faq_body">"Pentru mai multe informații, consultați pagina noastră de întrebări frecvente."</string>
     <!-- XLNK: FAQ URL pointing to the faq page in german. Need to use the URL for english for all other languages-->
     <string name="risk_details_explanation_faq_link">"https://www.coronawarn.app/en/faq/#encounter_but_green"</string>
     <!-- YTXT: risk details - increased risk explanation text with variable date since last contact -->
-    <string name="risk_details_information_body_increased_risk_date">"Aveți un risc crescut de infectare deoarece ați fost expus ultima dată pe o perioadă mai lungă de timp și în strânsă proximitate cu cel puțin o persoană diagnosticată cu COVID-19."</string>
+    <string name="risk_details_information_body_increased_risk_date">"Aveți un risc crescut de infectare deoarece ați fost expus ultima dată pe o perioadă mai lungă de timp și în strânsă proximitate cu cel puțin o persoană diagnosticată cu coronavirus."</string>
     <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact -->
     <plurals name="risk_details_information_body_increased_risk">
         <item quantity="one">"Aveți un risc crescut de infectare deoarece ați fost expus ultima dată acum %1$s zi pe o perioadă mai lungă de timp și în strânsă proximitate cu cel puțin o persoană diagnosticată cu coronavirus."</item>
@@ -347,6 +346,10 @@
     <!-- XACT: risk details page title -->
     <string name="risk_details_accessibility_title">"Starea riscului dvs."</string>
 
+    <!-- XHED: one time risk explanation dialog title  -->
+    <string name="risk_details_explanation_dialog_title">"Informații despre funcționalitatea de înregistrare în jurnal a expunerilor"</string>
+    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
+    <string name="risk_details_explanation_dialog_faq_body">"Pentru mai multe informații, consultați pagina noastră de întrebări frecvente."</string>
     <!-- XHED: risk details - deadman notification title -->
     <string name="risk_details_deadman_notification_title">"Starea riscului dvs."</string>
     <!-- YTXT: risk details - deadman notification text -->
@@ -861,8 +864,22 @@
     <string name="debugging_debuglog_status_not_recording">"Inactivă"</string>
     <!-- YTXT: Describtion for current logging status text if a debug log is not being recorded -->
     <string name="debugging_debuglog_status_additional_infos">"Mărime curentă: %1$s (necomprimat)"</string>
+
+    <!-- XHED: Title for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_title">"Verificarea autenticității și a transferului de date către țări terțe"</string>
+    <!-- YTXT: First section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_first_section">"Pentru a confirma autenticitatea aplicației dvs., smartphone-ul dvs. generează un identificator unic ce conține informații despre versiunea smartphone-ului și a aplicației. Acest lucru este necesar pentru a ne asigura că doar persoanele care utilizează efectiv aplicația Corona-Warn pot trimite date la suportul tehnic și să excludem rapoartele de erori manipulate. În acest scop, identificatorul este trimis la Google. În acest proces, pot fi transferate date în SUA sau în alte țări terțe, unde nivelul de confidențialitate a datelor poate să nu corespundă cu legislația europeană și se poate să nu vă puteți exercita drepturile europene în ceea ce privește confidențialitatea datelor. În special, serviciile de securitate din țările terțe ar putea să vă acceseze și să vă analizeze datele de la Google, chiar dacă nu există temei de suspiciune, și pot, de exemplu, lega aceste date de alte informații. Acest lucru se referă doar la identificatorul care este trimis la Google. Google nu primește informațiile din raportul dvs. de erori, însă Google ar putea determina identitatea dvs. pe baza identificatorului și ar putea urmări că a fost efectuată verificarea autenticității pe smartphone-ul dvs."</string>
+    <!-- YTXT: Second section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_second_section">"Dacă nu sunteți de acord cu acest transfer al datelor dvs. către o țară terță, nu apăsați pe „Sunt de acord și trimitere”. Veți putea utiliza aplicația în continuare, dar nu veți putea trimite rapoarte de erori."</string>
+
+    <!-- YTXT: Dialog title if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_title">"Opriți analiza erorilor?"</string>
     <!-- YTXT: Dialog message if the log recording is stopped, and thus deleted. -->
-    <string name="debugging_debuglog_stop_confirmation_message">"Raportul de erori a fost șters. Dacă ați salvat o copie locală a raportului de erori, nu a fost ștearsă."</string>
+    <string name="debugging_debuglog_stop_confirmation_message">"Dacă faceți acest lucru, toate datele înregistrate vor fi șterse. Dacă ați salvat o copie locală a raportului de erori, aceasta nu va fi ștearsă."</string>
+    <!-- YTXT: Dialog confirmation button if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_confirmation_button">"Oprire analiză"</string>
+    <!-- YTXT: Dialog discard button if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_discard_button">"Continuare analiză"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"Aveți nevoie de cel puțin 200 MB de memorie pentru a începe analiza erorilor. Eliberați memorie."</string>
     <!-- XHED: Dialog title if a user has stored a debug log locally -->
@@ -871,7 +888,6 @@
     <string name="debugging_debuglog_localexport_message">"Analiza erorilor a fost salvată local."</string>
     <!-- YTXT: Dialog message if local export has failed -->
     <string name="debugging_debuglog_localexport_error_message">"Încercarea de a salva un raport de erori a eșuat. Verificați dacă este disponibilă suficientă memorie."</string>
-
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Informații detaliate despre trimiterea rapoartelor de erori"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml
index 2f3e132f5c7cb581c4766568271ba070be369230..1507f027e54926a40bbf899ee12e63f249d00b2c 100644
--- a/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml
@@ -11,7 +11,7 @@
     <string name="contact_diary_person_list_no_items_title">"Henüz hiçbir kişi tanımlanmadı"</string>
     <string name="contact_diary_person_list_no_items_subtitle">"Bir kişi oluşturun ve temas güncenize ekleyin."</string>
     <string name="contact_diary_add_person_title">"KiÅŸi"</string>
-    <string name="contact_diary_add_person_text_input_name_hint">"Ad, soyadı"</string>
+    <string name="contact_diary_add_person_text_input_name_hint">"Ad"</string>
     <string name="contact_diary_add_text_input_phone_hint">"Telefon"</string>
     <string name="contact_diary_add_text_input_email_hint">"e-posta"</string>
     <string name="contact_diary_add_person_save_button">"Kaydet"</string>
@@ -171,6 +171,8 @@
 
     <!-- XBUT: Option - person encounter - inside-->
     <string name="contact_diary_location_visit_duration_label">"Süre"</string>
+    <!-- XTXT: Option - location encounter - duration in hours label-->
+    <string name="contact_diary_location_visit_duration_hour">"sa"</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Not (ör. çok dolu)"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml
index 6a75176cfdb4ecc1c98f0bf00c5dfeef5d2dbc3d..eccf0f24383e3914eddc7c32f54b5c1bd057d595 100644
--- a/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml
@@ -17,25 +17,21 @@
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
         <item>"Uluslararası Maruz Kalma Günlüğüne İsviçre Eklendi"</item>
-        <item>"Hata Raporlarının Oluşturulması"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
         <item>"Corona-Warn-App kullanıcıları artık şifrelenmiş rastgele kimlikleri, İsviçre’de resmi uyarı uygulamasının kullanıcıları ile değiştirebilir. Buna göre, artık İsviçre’deki uygulama kullanıcıları ile uyarı alışverişi yapılabilir."</item>
-        <item>"Artık teknik destek talebi üzerine bir hata raporu oluşturabilir ve uygulamada gerçekleştirdiğiniz adımları kaydedebilirsiniz. Bu sayede teknik hataların analiz edilmesi ve daha kısa süre içinde düzeltilmesi kolaylaştırılacaktır."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
-        <item/>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
-        <item/>
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-tr/strings.xml b/Corona-Warn-App/src/main/res/values-tr/strings.xml
index f408e7698649008c23232c2964420735064486cf..a9d5088a21fe8c4c03457109785beb8af9e9f1f9 100644
--- a/Corona-Warn-App/src/main/res/values-tr/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/strings.xml
@@ -302,13 +302,14 @@
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
     <string name="risk_details_subtitle_period_logged">"Bu dönem hesaplamaya dahil edildi."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->
+<!--    Dialog part 1-->
     <string name="risk_details_information_body_period_logged">"Enfeksiyon riskiniz yalnızca maruz kalma günlüğünün etkin olduğu dönemler için hesaplanabilir. Bu nedenle günlüğe kaydetme özelliğinin sürekli etkin kalması gerekir. Maruz kalma günlüğü son 14 günü kapsar."</string>
     <!-- XTXT: risk details - infection period logged information body, under 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_under_14_days">"Corona-Warn-App %s gün önce yüklendi. Enfeksiyon riskiniz, maruz kalma günlüğünün etkin olduğu dönemler için hesaplanır. Başka insanlarla karşılaşmışsanız ve bu sırada maruz kalma günlüğü etkindiyse enfeksiyon riskiniz hesaplanır."</string>
     <!-- XTXT: risk details - infection period logged information body, over 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_over_14_days">"Maruz kalma günlüğü başka insanlarla karşılaştığınız sırada etkindiyse bu dönem için enfeksiyon riskiniz hesaplanabilir."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->	    <!-- XTXT: risk details - infection period logged information body, under 14 days -->
-    <string name="risk_details_information_body_period_logged_assessment">"Maruz kalma günlüğü son 14 günü kapsar. Bu süre boyunca akıllı telefonunuzdaki günlüğe kaydetme özelliği %1$s gün etkindi. Uygulama, enfeksiyondan korunma için artık ilgili olmadığından daha eski kayıtları otomatik olarak siler."</string>
+    <string name="risk_details_information_body_period_logged_assessment">"Uygulama, enfeksiyondan korunma için artık ilgili olmadığından daha eski kayıtları otomatik olarak siler."</string>
     <!-- XTXT: risk details - infection period days logged/14 -->
     <string name="risk_details_information_active_tracing_days_circle_progress">"%s/14"</string>
     <!-- XHED: risk details - how your risk level was calculated, below behaviors -->
@@ -318,15 +319,13 @@
     <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors -->
     <string name="risk_details_information_body_outdated_risk">"Maruz kalma günlüğünüz 24 saatten uzun süre için güncellenemedi."</string>
     <!-- YTXT: risk details - low risk explanation text -->
-    <string name="risk_details_information_body_low_risk">"Daha sonra COVID-19 tanısı konan kişilere maruz kaldığınıza dair bir günlük kaydı oluşturulmadığı veya bu kişilerle yalnızca kısa süreyle ve uzak mesafeden karşılaştığınız için enfeksiyon riskiniz düşüktür."</string>
+    <string name="risk_details_information_body_low_risk">"Daha sonra koronavirüs tanısı konan kişilere maruz kaldığınıza dair bir günlük kaydı oluşturulmadığı veya bu kişilerle yalnızca kısa süreyle ve uzak mesafeden karşılaştığınız için enfeksiyon riskiniz düşüktür."</string>
     <!-- YTXT: risk details - low risk explanation text with encounter with low risk -->
     <string name="risk_details_information_body_low_risk_with_encounter">"Enfeksiyon riskiniz, maruz kalma günlüğünün verileri kullanılarak yerel olarak akıllı telefonunuzda hesaplanır. Hesaplamada koronavirüs tanısı konan kişilere maruz kalma mesafesi ve süresinin yanında potansiyel enfeksiyon bulaştırma durumu da göz önünde bulundurulur. Enfeksiyon riskiniz bir başkası tarafından görüntülenemez ya da bir başkasına aktarılamaz."</string>
-    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
-    <string name="risk_details_explanation_dialog_faq_body">"Daha fazla bilgi için lütfen SSS sayfamıza bakın."</string>
     <!-- XLNK: FAQ URL pointing to the faq page in german. Need to use the URL for english for all other languages-->
     <string name="risk_details_explanation_faq_link">"https://www.coronawarn.app/en/faq/#encounter_but_green"</string>
     <!-- YTXT: risk details - increased risk explanation text with variable date since last contact -->
-    <string name="risk_details_information_body_increased_risk_date">"COVID-19 tanısı konan en az bir kişiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaşadığınız için enfeksiyon riskiniz daha yüksektir."</string>
+    <string name="risk_details_information_body_increased_risk_date">"Koronavirüs tanısı konan en az bir kişiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaşadığınız için enfeksiyon riskiniz daha yüksektir."</string>
     <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact -->
     <plurals name="risk_details_information_body_increased_risk">
         <item quantity="one">"En son %1$s gün önce, koronavirüs tanısı konan en az bir kişiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaşadığınız için enfeksiyon riskiniz daha yüksektir."</item>
@@ -347,6 +346,10 @@
     <!-- XACT: risk details page title -->
     <string name="risk_details_accessibility_title">"Risk Durumunuz"</string>
 
+    <!-- XHED: one time risk explanation dialog title  -->
+    <string name="risk_details_explanation_dialog_title">"Maruz kalma günlüğü işlevi hakkında bilgi"</string>
+    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
+    <string name="risk_details_explanation_dialog_faq_body">"Daha fazla bilgi için lütfen SSS sayfamıza bakın."</string>
     <!-- XHED: risk details - deadman notification title -->
     <string name="risk_details_deadman_notification_title">"Risk Durumunuz"</string>
     <!-- YTXT: risk details - deadman notification text -->
@@ -861,8 +864,22 @@
     <string name="debugging_debuglog_status_not_recording">"Etkin DeÄŸil"</string>
     <!-- YTXT: Describtion for current logging status text if a debug log is not being recorded -->
     <string name="debugging_debuglog_status_additional_infos">"Geçerli boyut: %1$s (sıkıştırılmamış)"</string>
+
+    <!-- XHED: Title for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_title">"Orijinallik Doğrulaması ve Üçüncü Ülkelere Veri Aktarımı"</string>
+    <!-- YTXT: First section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_first_section">"Akıllı telefonunuz, uygulamanızın orijinalliğini teyit etmek için akıllı telefonunuzun ve uygulamanızın sürümüne ilişkin bilgileri içeren bir benzersiz tanıtıcı oluşturur. Bu, teknik destek birimine yalnızca Corona-Warn-App’i gerçekten kullanan kişilerin veri aktarabilmesini ve üzerinde oynanmış hata raporlarının ortadan kaldırılabilmesini sağlamak için gereklidir. Bunun için, tanıtıcı Google’a gönderilir. Bu işlem kapsamında veriler, ABD’ye veya veri gizliliği düzeyinin Avrupa kanunlarına uygun olmadığı ve veri gizliliği konusunda Avrupa’daki haklarınızı kullanamayabileceğiniz başka üçüncü ülkelere aktarılabilir. Özellikle, üçüncü ülkedeki güvenlik servisleri herhangi bir şüphe sebebi olmasa bile verilere erişebilir, Google ile verileri analiz edebilir ve bu verileri örneğin başka bilgilerle bağlantılandırabilir. Buna yalnızca Google’a gönderilen tanıtıcı dahildir. Google hata raporunuzda yer alan bilgileri almaz ancak tanıtıcıya göre kimliğinizi belirleyebilir ve akıllı telefonunuzda orijinallik kontrolünün yapıldığını takip edebilir."</string>
+    <!-- YTXT: Second section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
+    <string name="debugging_debuglog_legal_privacy_card_second_section">"Verilerinizin üçüncü bir ülkeye aktarılmasına izin vermiyorsanız lütfen “Kabul Et ve Gönder” öğesine dokunmayın. Uygulamayı kullanmaya devam edebileceksiniz ancak hata raporlarını gönderemeyeceksiniz."</string>
+
+    <!-- YTXT: Dialog title if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_title">"Hata analizi durdurulsun mu?"</string>
     <!-- YTXT: Dialog message if the log recording is stopped, and thus deleted. -->
-    <string name="debugging_debuglog_stop_confirmation_message">"Hata raporu silinmiş. Hata raporunun yerel bir kopyasını kaydettiyseniz bu kopya silinmemiştir."</string>
+    <string name="debugging_debuglog_stop_confirmation_message">"Bunu seçerseniz kaydedilen tüm veriler silinir. Hata raporunun yerel bir kopyasını kaydettiyseniz bu kopya silinmez."</string>
+    <!-- YTXT: Dialog confirmation button if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_confirmation_button">"Analizi Durdur"</string>
+    <!-- YTXT: Dialog discard button if the log recording is stopped, and thus deleted. -->
+    <string name="debugging_debuglog_stop_confirmation_discard_button">"Analizi Devam Ettir"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"Hata analizini başlatmak için en az 200 MB bellek alanınızın olması gerekir. Lütfen belleği boşaltın."</string>
     <!-- XHED: Dialog title if a user has stored a debug log locally -->
@@ -871,7 +888,6 @@
     <string name="debugging_debuglog_localexport_message">"Hata analizi yerel olarak kaydedilmiÅŸtir."</string>
     <!-- YTXT: Dialog message if local export has failed -->
     <string name="debugging_debuglog_localexport_error_message">"Hata raporunu kaydetme denemesi başarısız oldu. Lütfen yeterli bellek alanı olup olmadığını kontrol edin."</string>
-
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Hata Raporlarını Gönderme Konusunda Ayrıntılı Bilgi"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml
index 83bd6e5955907c1d696fb6e148eb5709a6e2ab80..cb4764e53467542422f6af1f59ab458ce1268a68 100644
--- a/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml
@@ -12,7 +12,7 @@
     <string name="contact_diary_person_list_no_items_title">"No people defined yet"</string>
     <string name="contact_diary_person_list_no_items_subtitle">"Create a person and add them to your contact journal."</string>
     <string name="contact_diary_add_person_title">"Person"</string>
-    <string name="contact_diary_add_person_text_input_name_hint">"First name, last name"</string>
+    <string name="contact_diary_add_person_text_input_name_hint">"Name"</string>
     <string name="contact_diary_add_text_input_phone_hint">"Phone"</string>
     <string name="contact_diary_add_text_input_email_hint">"e-mail"</string>
     <string name="contact_diary_add_person_save_button">"Save"</string>
@@ -146,8 +146,6 @@
     <string name="contact_diary_export_location_duration_prefix" translatable="false">"Dauer"</string>
     <!-- XTXT: Location duration postfix in the contact journal export-->
     <string name="contact_diary_export_location_duration_suffix" translatable="false">"h"</string>
-    <!-- XTXT: Location duration prefix in the contact journal overview-->
-    <string name="contact_diary_overview_location_duration_suffix" translatable="false">"Std."</string>
 
     <!-- XHED: Title for the contact diary comment info screen -->
     <string name="contact_diary_comment_info_screen_title">"Note"</string>
@@ -201,6 +199,8 @@
 
     <!-- XBUT: Option - person encounter - inside-->
     <string name="contact_diary_location_visit_duration_label">"Duration"</string>
+    <!-- XTXT: Option - location encounter - duration in hours label-->
+    <string name="contact_diary_location_visit_duration_hour">"hrs"</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Note (e.g. very full)"</string>
 </resources>
diff --git a/Corona-Warn-App/src/main/res/values/release_info_strings.xml b/Corona-Warn-App/src/main/res/values/release_info_strings.xml
index 304fd087ff53e1a48c2f599221162111d9748122..b9eb2ce9a87edcd502e4b15a48d15bbcbf705dbc 100644
--- a/Corona-Warn-App/src/main/res/values/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/release_info_strings.xml
@@ -18,25 +18,25 @@
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
         <item>"Switzerland Added to Transnational Exposure Logging"</item>
-        <item>"Generation of Error Reports"</item>
+        <item>Änderung der Risikokarten</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
         <item>"Corona-Warn-App users can now exchange encrypted random IDs with users of the official warning app in Switzerland. This means warnings can now be sent to and received from app users in Switzerland."</item>
-        <item>"You can now generate an error report, upon request by technical support, and record the steps that you perform in the app. This will make it easier to analyze technical errors and correct them more quickly."</item>
+        <item>Auf den Risikokarten entfällt die Anzeige der Anzahl aktiver Tage bzw. dass die App dauerhaft aktiv ist.</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
-        <item/>
+        <item />
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
-        <item/>
+        <item />
     </string-array>
 
 </resources>
diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml
index ab3d6252c0e7a00591e69b2fcabac9f9b3c87283..15f0e3a8057ecd49476685ca1868a67f94a7d14c 100644
--- a/Corona-Warn-App/src/main/res/values/strings.xml
+++ b/Corona-Warn-App/src/main/res/values/strings.xml
@@ -307,13 +307,14 @@
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
     <string name="risk_details_subtitle_period_logged">"This period is included in the calculation."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->
+<!--    Dialog part 1-->
     <string name="risk_details_information_body_period_logged">"Your risk of infection can be calculated only for periods during which exposure logging was active. The logging feature should therefore remain active permanently. Exposure logging covers the last 14 days."</string>
     <!-- XTXT: risk details - infection period logged information body, under 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_under_14_days">"The Corona-Warn-App was installed %s ago. Your risk of infection is calculated for the periods during which exposure logging was active. If you have encountered other people and exposure logging was active, your risk of infection is calculated."</string>
     <!-- XTXT: risk details - infection period logged information body, over 14 days -->
     <string name="risk_details_information_body_period_logged_assessment_over_14_days">"If exposure logging was active in times during which you encountered other people, your risk of infection can be calculated for this period."</string>
     <!-- XHED: risk details - infection period logged information body, below behaviors -->        <!-- XTXT: risk details - infection period logged information body, under 14 days -->
-    <string name="risk_details_information_body_period_logged_assessment">"Exposure logging covers the past 14 days. During this time, the logging feature on your smartphone was active for %1$s days. The app automatically deletes older logs, as these are no longer relevant for infection prevention."</string>
+    <string name="risk_details_information_body_period_logged_assessment">"The app automatically deletes older logs, as these are no longer relevant for infection prevention."</string>
     <!-- XTXT: risk details - infection period days logged/14 -->
     <string name="risk_details_information_active_tracing_days_circle_progress">"%s/14"</string>
     <!-- XHED: risk details - how your risk level was calculated, below behaviors -->
@@ -323,11 +324,11 @@
     <!-- XMSG: risk details - risk calculation wasn't possible for 24h, below behaviors -->
     <string name="risk_details_information_body_outdated_risk">"Your exposure logging could not be updated for more than 24 hours."</string>
     <!-- YTXT: risk details - low risk explanation text -->
-    <string name="risk_details_information_body_low_risk">"You have a low risk of infection because no exposure to people later diagnosed with COVID-19 was logged, or because your encounters were only for a short time and at a greater distance."</string>
+    <string name="risk_details_information_body_low_risk">"You have a low risk of infection because no exposure to people later diagnosed with coronavirus was logged, or because your encounters were only for a short time and at a greater distance."</string>
     <!-- YTXT: risk details - low risk explanation text with encounter with low risk -->
     <string name="risk_details_information_body_low_risk_with_encounter">"The risk of infection is calculated locally on your smartphone, using exposure logging data. The calculation also takes into account distance and duration of any exposure to persons diagnosed with coronavirus, as well as their potential infectiousness. Your risk of infection cannot be seen by or passed on to anyone else."</string>
     <!-- YTXT: risk details - increased risk explanation text with variable date since last contact -->
-    <string name="risk_details_information_body_increased_risk_date">"You have an increased risk of infection because you were exposed over a longer period of time and at close proximity to at least one person diagnosed with COVID-19."</string>
+    <string name="risk_details_information_body_increased_risk_date">"You have an increased risk of infection because you were exposed over a longer period of time and at close proximity to at least one person diagnosed with coronavirus."</string>
     <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact -->
     <plurals name="risk_details_information_body_increased_risk">
         <item quantity="one">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with coronavirus."</item>
@@ -348,6 +349,11 @@
     <!-- XACT: risk details page title -->
     <string name="risk_details_accessibility_title">"Your Risk Status"</string>
 
+    <!-- XHED: one time risk explanation dialog title  -->
+    <string name="risk_details_explanation_dialog_title">"Information about exposure logging functionality"</string>
+    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
+    <string name="risk_details_explanation_dialog_faq_body">"For further information, please see our FAQ page."</string>
+
     <!-- XHED: risk details - deadman notification title -->
     <string name="risk_details_deadman_notification_title">"Your Risk Status"</string>
     <!-- YTXT: risk details - deadman notification text -->
@@ -638,8 +644,6 @@
     <string name="settings_tracing_status_connection_headline">"Open Internet connection"</string>
     <!-- XTXT: settings(tracing) - explains user what to do on card if connection is disabled -->
     <string name="settings_tracing_status_connection_body">"Exposure logging requires an Internet connection to calculate your risk of infection. Please turn on Wi-Fi or mobile data in your device settings."</string>
-    <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information-->
-    <string name="risk_details_explanation_dialog_faq_body">"For further information, please see our FAQ page."</string>
     <!-- XLNK: FAQ URL pointing to the faq page in german. Need to use the URL for english for all other languages-->
     <string name="risk_details_explanation_faq_link">"https://www.coronawarn.app/en/faq/#encounter_but_green"</string>
     <!-- XBUT: settings(tracing) - go to operating system settings button on card -->
@@ -871,20 +875,20 @@
     <string name="debugging_debuglog_status_additional_infos">"Current size: %1$s (uncompressed)"</string>
 
     <!-- XHED: Title for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
-    <string name="debugging_debuglog_legal_privacy_card_title">"Prüfung der Echtheit und Drittlandsübermittlung"</string>
+    <string name="debugging_debuglog_legal_privacy_card_title">"Verification of Authenticity and Data Transfer to Third Countries"</string>
     <!-- YTXT: First section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
-    <string name="debugging_debuglog_legal_privacy_card_first_section">"Um die Echtheit Ihrer App zu bestätigen, erzeugt Ihr Smartphone eine eindeutige Kennung, die Informationen über die Version Ihres Smartphones und der App enthält. Das ist erforderlich, um sicherzustellen, dass nur Nutzer Daten auf diesem Weg an den technischen Support übersenden, die tatsächlich die Corona-Warn-App nutzen und nicht manipulierte Fehlerberichte bereitstellen. Die Kennung wird dafür einmalig an Google übermittelt. Dabei kann es auch zu einer Datenübermittlung in die USA oder andere Drittländer kommen. Dort besteht möglicherweise kein dem europäischen Recht entsprechendes Datenschutzniveau und Ihre europäischen Datenschutzrechte können eventuell nicht durchgesetzt werden. Insbesondere besteht die Möglichkeit, dass Sicherheitsbehörden im Drittland, auch ohne einen konkreten Verdacht, auf die übermittelten Daten bei Google zugreifen und diese auswerten, beispielsweise indem sie Daten mit anderen Informationen verknüpfen. Dies betrifft nur die an Google übermittelte Kennung. Die Angaben aus Ihrem Fehlerbericht erhält Google nicht. Möglicherweise kann Google jedoch anhand der Kennung auf Ihre Identität schließen und nachvollziehen, dass die Echtheitsprüfung Ihres Smartphones stattgefunden hat."</string>
+    <string name="debugging_debuglog_legal_privacy_card_first_section">"To confirm the authenticity of your app, your smartphone generates a unique identifier that contains information about the version of your smartphone and the app. This is necessary to ensure that only people who actually use the Corona-Warn-App can send data to technical support and rule out manipulated error reports. To do so, the identifier is sent to Google. In this process, data may be transferred to the U.S. or other third countries, where the level of data privacy may not correspond to European law and you may not be able to enforce your European rights to data privacy. In particular, security services in the third country could access and analyze the data with Google, even if there is no grounds for suspicion, and link this data with other information, for example. This only involves the identifier that is sent to Google. Google does not receive the information from your error report, however, Google may be able to determine your identity based on the identifier and track that the authenticity check was performed on your smartphone."</string>
     <!-- YTXT: Second section for debug legal screen privacy card - LEGAL STRING MOVED TO THIS FILE ON PURPOSE FOR TRANSLATION -->
-    <string name="debugging_debuglog_legal_privacy_card_second_section">"Wenn Sie mit der Drittlandsübermittlung nicht einverstanden sind, tippen Sie bitte nicht „Einverstanden und senden“ an. Sie können die App weiterhin nutzen, eine Übersendung des Fehlerberichtes über die App ist dann jedoch nicht möglich."</string>
+    <string name="debugging_debuglog_legal_privacy_card_second_section">"If you do not consent to this transfer of your data to a third country, please do not tap on “Accept and Send”. You will still be able to use the app, but you cannot send error reports."</string>
 
     <!-- YTXT: Dialog title if the log recording is stopped, and thus deleted. -->
-    <string name="debugging_debuglog_stop_confirmation_title">"Wollen Sie die Fehleranalyse wirklich stoppen?"</string>
+    <string name="debugging_debuglog_stop_confirmation_title">"Stop the error analysis?"</string>
     <!-- YTXT: Dialog message if the log recording is stopped, and thus deleted. -->
-    <string name="debugging_debuglog_stop_confirmation_message">"The error report was deleted. If you have saved a local copy of the error report, it was not deleted."</string>
+    <string name="debugging_debuglog_stop_confirmation_message">"If you do so, all recorded data will be deleted. If you have saved a local copy of the error report, it will not be deleted."</string>
     <!-- YTXT: Dialog confirmation button if the log recording is stopped, and thus deleted. -->
-    <string name="debugging_debuglog_stop_confirmation_confirmation_button">"Analyse stoppen"</string>
+    <string name="debugging_debuglog_stop_confirmation_confirmation_button">"Stop Analysis"</string>
     <!-- YTXT: Dialog discard button if the log recording is stopped, and thus deleted. -->
-    <string name="debugging_debuglog_stop_confirmation_discard_button">"Analyse fortführen"</string>
+    <string name="debugging_debuglog_stop_confirmation_discard_button">"Continue Analysis"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"You need at least 200 MB of memory to start the error analysis. Please free up memory."</string>
     <!-- XHED: Dialog title if a user has stored a debug log locally -->
@@ -893,7 +897,6 @@
     <string name="debugging_debuglog_localexport_message">"The error analysis was saved locally."</string>
     <!-- YTXT: Dialog message if local export has failed -->
     <string name="debugging_debuglog_localexport_error_message">"The attempt to save the error report failed. Please check whether enough memory is available."</string>
-
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Detailed Information on Sending Error Reports"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/common/PpaDataExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/common/PpaDataExtensionsTest.kt
index e189bf3933a15a736213cf6371c8dd9ec56c5904..14295ba7d88a14545b343306437daba3cc41f5ad 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/common/PpaDataExtensionsTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/common/PpaDataExtensionsTest.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.datadonation.analytics.common
 
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
 import io.kotest.matchers.shouldBe
+import org.joda.time.Instant
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 
@@ -26,4 +27,60 @@ class PpaDataExtensionsTest : BaseTest() {
         PpaData.PPAFederalState.FEDERAL_STATE_SH.federalStateShortName shouldBe "SH"
         PpaData.PPAFederalState.FEDERAL_STATE_TH.federalStateShortName shouldBe "TH"
     }
+
+    @Test
+    fun `days since most recent date at risk level at test registration are calculated correctly`() {
+        val march15At2200 = Instant.parse("2021-03-15T22:00:00.000Z")
+        val march17At0500 = Instant.parse("2021-03-17T05:00:00.000Z")
+        calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
+            lastChangeCheckedRiskLevelTimestamp = march15At2200,
+            testRegisteredAt = march17At0500
+        ) shouldBe 2
+    }
+
+    @Test
+    fun `days between most recent risk level change and test registration should be 0 if on same day`() {
+        val march15At0500 = Instant.parse("2021-03-15T05:00:00.000Z")
+        val march15At2200 = Instant.parse("2021-03-15T22:00:00.000Z")
+        calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
+            lastChangeCheckedRiskLevelTimestamp = march15At0500,
+            testRegisteredAt = march15At2200
+        ) shouldBe 0
+    }
+
+    @Test
+    fun `days should be -1 if lastChangeCheckedRiskLevelTimestamp is null`() {
+        val march15At0500 = Instant.parse("2021-03-15T05:00:00.000Z")
+        calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
+            lastChangeCheckedRiskLevelTimestamp = null,
+            testRegisteredAt = march15At0500
+        ) shouldBe -1
+    }
+
+    @Test
+    fun `days should be -1 if testRegisteredAt is null`() {
+        val march15At0500 = Instant.parse("2021-03-15T05:00:00.000Z")
+        calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
+            lastChangeCheckedRiskLevelTimestamp = march15At0500,
+            testRegisteredAt = null
+        ) shouldBe -1
+    }
+
+    @Test
+    fun `days should be -1 if both are null`() {
+        calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
+            lastChangeCheckedRiskLevelTimestamp = null,
+            testRegisteredAt = null
+        ) shouldBe -1
+    }
+
+    @Test
+    fun `days should be -1 if order is reversed`() {
+        val march20At2200 = Instant.parse("2021-03-20T22:00:00.000Z")
+        val march10At0500 = Instant.parse("2021-03-10T05:00:00.000Z")
+        calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
+            lastChangeCheckedRiskLevelTimestamp = march20At2200,
+            testRegisteredAt = march10At0500
+        ) shouldBe -1
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollectorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollectorTest.kt
index fe9666112e81d20e74876399cd76ef22b47b0ada..859cf662132c0e10231b12ede552934534fe0a2b 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollectorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollectorTest.kt
@@ -7,14 +7,18 @@ import de.rki.coronawarnapp.risk.RiskState
 import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.util.TimeStamper
 import io.mockk.MockKAnnotations
+import io.mockk.Runs
 import io.mockk.coEvery
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
+import io.mockk.just
 import io.mockk.verify
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runBlockingTest
+import org.joda.time.Days
 import org.joda.time.Hours
 import org.joda.time.Instant
+import org.joda.time.LocalTime
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
@@ -53,13 +57,24 @@ class AnalyticsKeySubmissionCollectorTest : BaseTest() {
         val riskLevelAtTestRegistration = mockFlowPreference(-1)
         every { analyticsKeySubmissionStorage.riskLevelAtTestRegistration } returns riskLevelAtTestRegistration
         val hoursSinceHighRiskWarningAtTestRegistration = mockFlowPreference(-1)
-        every { analyticsKeySubmissionStorage.hoursSinceHighRiskWarningAtTestRegistration } returns hoursSinceHighRiskWarningAtTestRegistration
+        every { analyticsKeySubmissionStorage.hoursSinceHighRiskWarningAtTestRegistration } returns
+            hoursSinceHighRiskWarningAtTestRegistration
+        coEvery {
+            riskLevelSettings.lastChangeCheckedRiskLevelTimestamp
+        } returns now
+            .minus(Days.days(2).toStandardDuration()).toDateTime().toLocalDate()
+            .toDateTime(LocalTime(22, 0)).toInstant()
+        val daysSinceMostRecentDateAtRiskLevelAtTestRegistration = mockFlowPreference(0)
+        every { analyticsKeySubmissionStorage.daysSinceMostRecentDateAtRiskLevelAtTestRegistration } returns
+            daysSinceMostRecentDateAtRiskLevelAtTestRegistration
+        every { analyticsKeySubmissionStorage.clear() } just Runs
         runBlockingTest {
             val collector = createInstance()
             collector.reportTestRegistered()
             verify { testRegisteredAt.update(any()) }
             verify { riskLevelAtTestRegistration.update(any()) }
             verify { hoursSinceHighRiskWarningAtTestRegistration.update(any()) }
+            verify { daysSinceMostRecentDateAtRiskLevelAtTestRegistration.update(any()) }
         }
     }
 
@@ -119,6 +134,7 @@ class AnalyticsKeySubmissionCollectorTest : BaseTest() {
         coEvery { analyticsSettings.analyticsEnabled.value } returns true
         val flow = mockFlowPreference(now.millis)
         every { analyticsKeySubmissionStorage.testResultReceivedAt } returns flow
+
         runBlockingTest {
             val collector = createInstance()
             collector.reportPositiveTestResultReceived()
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepositoryTest.kt
index bbb25be9800a339a9614195855606218a98c33a5..c9f23258a33df6779e3f12989a9dd4f05436fc1b 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepositoryTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepositoryTest.kt
@@ -1,14 +1,11 @@
 package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission
 
-import de.rki.coronawarnapp.risk.RiskLevelSettings
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.coEvery
 import io.mockk.impl.annotations.MockK
-import org.joda.time.Days
 import org.joda.time.Hours
 import org.joda.time.Instant
-import org.joda.time.LocalTime
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
@@ -16,7 +13,6 @@ import testhelpers.BaseTest
 class AnalyticsKeySubmissionRepositoryTest : BaseTest() {
 
     @MockK lateinit var storage: AnalyticsKeySubmissionStorage
-    @MockK lateinit var riskLevelSettings: RiskLevelSettings
 
     private val now = Instant.now()
 
@@ -26,8 +22,7 @@ class AnalyticsKeySubmissionRepositoryTest : BaseTest() {
     }
 
     private fun createInstance() = AnalyticsKeySubmissionRepository(
-        storage,
-        riskLevelSettings
+        storage
     )
 
     @Test
@@ -39,27 +34,35 @@ class AnalyticsKeySubmissionRepositoryTest : BaseTest() {
     }
 
     @Test
-    fun `hours since test result when not submitted should be 0`() {
+    fun `hours since test result when not submitted should be -1`() {
         coEvery { storage.submittedAt.value } returns -1
         coEvery { storage.testResultReceivedAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis
         val repository = createInstance()
-        repository.hoursSinceTestResult shouldBe 0
+        repository.hoursSinceTestResult shouldBe -1
     }
 
     @Test
-    fun `hours since test result when not received or submitted should be 0`() {
+    fun `hours since test result should be -1 when testResultReceivedAt is missing`() {
+        coEvery { storage.submittedAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis
+        coEvery { storage.testResultReceivedAt.value } returns -1
+        val repository = createInstance()
+        repository.hoursSinceTestResult shouldBe -1
+    }
+
+    @Test
+    fun `hours since test result when not received or submitted should be -1`() {
         coEvery { storage.submittedAt.value } returns -1
         coEvery { storage.testResultReceivedAt.value } returns -1
         val repository = createInstance()
-        repository.hoursSinceTestResult shouldBe 0
+        repository.hoursSinceTestResult shouldBe -1
     }
 
     @Test
-    fun `hours since test result should be 0 when dates have been manipulated`() {
+    fun `hours since test result should be -1 when dates have been manipulated`() {
         coEvery { storage.submittedAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis
         coEvery { storage.testResultReceivedAt.value } returns now.millis
         val repository = createInstance()
-        repository.hoursSinceTestResult shouldBe 0
+        repository.hoursSinceTestResult shouldBe -1
     }
 
     @Test
@@ -71,47 +74,18 @@ class AnalyticsKeySubmissionRepositoryTest : BaseTest() {
     }
 
     @Test
-    fun `hours since test registration should be 0 if not submitted`() {
+    fun `hours since test registration should be -1 if not submitted`() {
         coEvery { storage.submittedAt.value } returns -1
         coEvery { storage.testRegisteredAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis
         val repository = createInstance()
-        repository.hoursSinceTestRegistration shouldBe 0
+        repository.hoursSinceTestRegistration shouldBe -1
     }
 
     @Test
-    fun `days since most recent date at risk level at test registration are calculated correctly`() {
-        coEvery {
-            riskLevelSettings.lastChangeCheckedRiskLevelTimestamp
-        } returns now
-            .minus(Days.days(2).toStandardDuration()).toDateTime().toLocalDate()
-            .toDateTime(LocalTime(22, 0)).toInstant()
-        coEvery { storage.testRegisteredAt.value } returns
-            now.toDateTime().toLocalDate().toDateTime(LocalTime(5, 0)).millis
-        val repository = createInstance()
-        repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 2
-    }
-
-    @Test
-    fun `days between most recent risk level change and test registration should be 0 if on same day`() {
-        coEvery {
-            riskLevelSettings.lastChangeCheckedRiskLevelTimestamp
-        } returns now
-            .toDateTime().toLocalDate()
-            .toDateTime(LocalTime(13, 0)).toInstant()
-        coEvery { storage.testRegisteredAt.value } returns
-            now.toDateTime().toLocalDate().toDateTime(LocalTime(14, 0)).millis
-        val repository = createInstance()
-        repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 0
-    }
-
-    @Test
-    fun `days should be 0 if lastChangeCheckedRiskLevelTimestamp is null`() {
-        coEvery {
-            riskLevelSettings.lastChangeCheckedRiskLevelTimestamp
-        } returns null
-        coEvery { storage.testRegisteredAt.value } returns
-            now.toDateTime().toLocalDate().toDateTime(LocalTime(14, 0)).millis
+    fun `hours since test registration should be -1 if testRegisteredAt is missing`() {
+        coEvery { storage.submittedAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis
+        coEvery { storage.testRegisteredAt.value } returns -1
         val repository = createInstance()
-        repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 0
+        repository.hoursSinceTestRegistration shouldBe -1
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonorTest.kt
index f128a602166778abbbcae049ec4a8e24a0fefd15..ac97cc321836a06795df3bb79985366634134468 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonorTest.kt
@@ -4,8 +4,6 @@ import de.rki.coronawarnapp.appconfig.AnalyticsConfig
 import de.rki.coronawarnapp.appconfig.ConfigData
 import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule
 import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings
-import de.rki.coronawarnapp.risk.RiskLevelSettings
-import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
 import de.rki.coronawarnapp.submission.SubmissionSettings
 import de.rki.coronawarnapp.util.TimeStamper
@@ -31,8 +29,6 @@ import testhelpers.preferences.mockFlowPreference
 
 class TestResultDonorTest : BaseTest() {
     @MockK lateinit var testResultDonorSettings: TestResultDonorSettings
-    @MockK lateinit var riskLevelSettings: RiskLevelSettings
-    @MockK lateinit var riskLevelStorage: RiskLevelStorage
     @MockK lateinit var timeStamper: TimeStamper
     @MockK lateinit var submissionSettings: SubmissionSettings
 
@@ -43,16 +39,16 @@ class TestResultDonorTest : BaseTest() {
     @BeforeEach
     fun setUp() {
         MockKAnnotations.init(this, true)
+        with(testResultDonorSettings) {
+            every { mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(baseTime)
+            every { riskLevelTurnedRedTime } returns mockFlowPreference(baseTime)
+            every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_LOW)
+        }
         every { timeStamper.nowUTC } returns baseTime
-        every { riskLevelSettings.lastChangeCheckedRiskLevelTimestamp } returns baseTime
-        every { testResultDonorSettings.riskLevelAtTestRegistration } returns
-            mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_LOW)
         every { submissionSettings.initialTestResultReceivedAt } returns baseTime
 
         testResultDonor = TestResultDonor(
             testResultDonorSettings,
-            riskLevelSettings,
-            riskLevelStorage,
             timeStamper,
             submissionSettings
         )
@@ -108,7 +104,9 @@ class TestResultDonorTest : BaseTest() {
 
             val timeDayBefore = baseTime.minus(Duration.standardDays(1))
             every { submissionSettings.initialTestResultReceivedAt } returns timeDayBefore
-            every { riskLevelSettings.lastChangeCheckedRiskLevelTimestamp } returns timeDayBefore
+            every { testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(
+                timeDayBefore
+            )
 
             val donation = testResultDonor.beginDonation(TestRequest)
             donation.shouldBeInstanceOf<TestResultDonor.TestResultMetadataContribution>()
@@ -141,6 +139,86 @@ class TestResultDonorTest : BaseTest() {
         }
     }
 
+    @Test
+    fun `No donation when test is  POSITIVE and HighRisk but riskLevelTurnedRedTime is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.POSITIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(null)
+                every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
+    @Test
+    fun `No donation when test is NEGATIVE and HighRisk but riskLevelTurnedRedTime is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.NEGATIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(null)
+                every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
+    @Test
+    fun `No donation when test is  POSITIVE and HighRisk but mostRecentDateWithHighOrLowRiskLevel is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.POSITIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(baseTime)
+                every { mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(null)
+                every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
+    @Test
+    fun `No donation when test is NEGATIVE and HighRisk but mostRecentDateWithHighOrLowRiskLevel is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.NEGATIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(baseTime)
+                every { mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(null)
+                every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
+    @Test
+    fun `No donation when test is  POSITIVE and LowRisk but mostRecentDateWithHighOrLowRiskLevel is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.POSITIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(null)
+                every { mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(null)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
+    @Test
+    fun `No donation when test is NEGATIVE and LowRisk but mostRecentDateWithHighOrLowRiskLevel is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.NEGATIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(null)
+                every { mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(null)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
     @Test
     fun `Donation is collected when test result is NEGATIVE`() {
         runBlockingTest {
@@ -160,6 +238,61 @@ class TestResultDonorTest : BaseTest() {
         }
     }
 
+    @Test
+    fun `Scenario 1 LowRisk`() = runBlockingTest {
+        with(testResultDonorSettings) {
+            every { testScannedAfterConsent } returns mockFlowPreference(true)
+            every { testResultAtRegistration } returns mockFlowPreference(TestResult.NEGATIVE)
+            every { finalTestResultReceivedAt } returns mockFlowPreference(
+                Instant.parse("2021-03-20T20:00:00Z")
+            )
+            every { riskLevelTurnedRedTime } returns mockFlowPreference(null) // No High risk
+            every { mostRecentDateWithHighOrLowRiskLevel } returns
+                mockFlowPreference(Instant.parse("2021-03-18T00:00:00Z"))
+            every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_LOW)
+        }
+        every { timeStamper.nowUTC } returns Instant.parse("2021-03-20T00:00:00Z")
+        every { submissionSettings.initialTestResultReceivedAt } returns Instant.parse("2021-03-20T00:00:00Z")
+
+        val donation = testResultDonor.beginDonation(TestRequest)
+        donation.shouldBeInstanceOf<TestResultDonor.TestResultMetadataContribution>()
+        with(donation.testResultMetadata) {
+            testResult shouldBe PpaData.PPATestResult.TEST_RESULT_NEGATIVE
+            hoursSinceTestRegistration shouldBe 20 // hours
+            riskLevelAtTestRegistration shouldBe PpaData.PPARiskLevel.RISK_LEVEL_LOW
+            hoursSinceHighRiskWarningAtTestRegistration shouldBe -1 // expected for low risk
+            daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 2 // days
+        }
+    }
+
+    @Test
+    fun `Scenario 2 HighRisk`() = runBlockingTest {
+        with(testResultDonorSettings) {
+            every { testScannedAfterConsent } returns mockFlowPreference(true)
+            every { testResultAtRegistration } returns mockFlowPreference(TestResult.POSITIVE)
+            every { finalTestResultReceivedAt } returns mockFlowPreference(
+                Instant.parse("2021-03-20T20:00:00Z")
+            )
+            every { riskLevelTurnedRedTime } returns mockFlowPreference(Instant.parse("2021-03-01T00:00:00Z"))
+            every { mostRecentDateWithHighOrLowRiskLevel } returns
+                mockFlowPreference(Instant.parse("2021-03-18T00:00:00Z"))
+            every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
+        }
+
+        every { timeStamper.nowUTC } returns Instant.parse("2021-03-20T00:00:00Z")
+        every { submissionSettings.initialTestResultReceivedAt } returns Instant.parse("2021-03-20T00:00:00Z")
+
+        val donation = testResultDonor.beginDonation(TestRequest)
+        donation.shouldBeInstanceOf<TestResultDonor.TestResultMetadataContribution>()
+        with(donation.testResultMetadata) {
+            testResult shouldBe PpaData.PPATestResult.TEST_RESULT_POSITIVE
+            hoursSinceTestRegistration shouldBe 20 // hours
+            riskLevelAtTestRegistration shouldBe PpaData.PPARiskLevel.RISK_LEVEL_HIGH
+            hoursSinceHighRiskWarningAtTestRegistration shouldBe 456 // 19 days in hours
+            daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 2 // days
+        }
+    }
+
     @Test
     fun deleteData() = runBlockingTest {
         every { testResultDonorSettings.clear() } just Runs
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/home/HomeFragmentViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/home/HomeFragmentViewModelTest.kt
index fe35faf99c0c09ab909c1ce2a86c2edbd7a928b6..2dfc0688e88b7f1cc9f70dcf67b7b2da182359a6 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/home/HomeFragmentViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/home/HomeFragmentViewModelTest.kt
@@ -22,7 +22,7 @@ import de.rki.coronawarnapp.ui.main.home.HomeFragmentViewModel
 import de.rki.coronawarnapp.util.DeviceUIState.PAIRED_POSITIVE
 import de.rki.coronawarnapp.util.DeviceUIState.PAIRED_POSITIVE_TELETAN
 import de.rki.coronawarnapp.util.NetworkRequestWrapper
-import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
 import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt
index 7840e75c702b5a957a8c5d2689f819849551791f..786c13b0c1fe916c2b248b5e8860c34d5cf922c1 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt
@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.risk
 import android.content.Context
 import androidx.core.app.NotificationManagerCompat
 import com.google.android.gms.nearby.exposurenotification.ExposureWindow
+import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings
 import de.rki.coronawarnapp.datadonation.survey.Surveys
 import de.rki.coronawarnapp.notification.NotificationHelper
 import de.rki.coronawarnapp.risk.RiskState.CALCULATION_FAILED
@@ -23,6 +24,7 @@ import io.mockk.coVerifySequence
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
 import io.mockk.just
+import io.mockk.mockk
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runBlockingTest
@@ -43,6 +45,7 @@ class RiskLevelChangeDetectorTest : BaseTest() {
     @MockK lateinit var surveys: Surveys
     @MockK lateinit var submissionSettings: SubmissionSettings
     @MockK lateinit var tracingSettings: TracingSettings
+    @MockK lateinit var testResultDonorSettings: TestResultDonorSettings
 
     @BeforeEach
     fun setup() {
@@ -52,18 +55,27 @@ class RiskLevelChangeDetectorTest : BaseTest() {
         every { submissionSettings.isSubmissionSuccessful } returns false
         every { foregroundState.isInForeground } returns flowOf(true)
         every { notificationManagerCompat.areNotificationsEnabled() } returns true
+
         every { riskLevelSettings.lastChangeCheckedRiskLevelTimestamp = any() } just Runs
         every { riskLevelSettings.lastChangeCheckedRiskLevelTimestamp } returns null
+
+        every { riskLevelSettings.lastChangeToHighRiskLevelTimestamp = any() } just Runs
+        every { riskLevelSettings.lastChangeToHighRiskLevelTimestamp } returns null
+
         coEvery { surveys.resetSurvey(Surveys.Type.HIGH_RISK_ENCOUNTER) } just Runs
+
+        every { testResultDonorSettings.riskLevelTurnedRedTime } returns mockFlowPreference(null)
+        every { testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(null)
     }
 
     private fun createRiskLevel(
         riskState: RiskState,
-        calculatedAt: Instant = Instant.EPOCH
+        calculatedAt: Instant = Instant.EPOCH,
+        aggregatedRiskResult: AggregatedRiskResult? = null
     ): RiskLevelResult = object : RiskLevelResult {
         override val riskState: RiskState = riskState
         override val calculatedAt: Instant = calculatedAt
-        override val aggregatedRiskResult: AggregatedRiskResult? = null
+        override val aggregatedRiskResult: AggregatedRiskResult? = aggregatedRiskResult
         override val failureReason: RiskLevelResult.FailureReason? = null
         override val exposureWindows: List<ExposureWindow>? = null
         override val matchedKeyCount: Int = 0
@@ -82,7 +94,8 @@ class RiskLevelChangeDetectorTest : BaseTest() {
         notificationHelper = notificationHelper,
         surveys = surveys,
         submissionSettings = submissionSettings,
-        tracingSettings = tracingSettings
+        tracingSettings = tracingSettings,
+        testResultDonorSettings = testResultDonorSettings
     )
 
     @Test
@@ -193,6 +206,89 @@ class RiskLevelChangeDetectorTest : BaseTest() {
         }
     }
 
+    @Test
+    fun `riskLevelTurnedRedTime is only set once`() {
+        testResultDonorSettings.riskLevelTurnedRedTime.update { Instant.EPOCH.plus(1) }
+
+        every { riskLevelStorage.latestRiskLevelResults } returns flowOf(
+            listOf(
+                createRiskLevel(
+                    INCREASED_RISK,
+                    calculatedAt = Instant.EPOCH.plus(2),
+                    aggregatedRiskResult = mockk<AggregatedRiskResult>().apply {
+                        every { isIncreasedRisk() } returns true
+                    }
+                ),
+                createRiskLevel(LOW_RISK, calculatedAt = Instant.EPOCH)
+            )
+        )
+
+        runBlockingTest {
+            val instance = createInstance(scope = this)
+            instance.launch()
+            advanceUntilIdle()
+        }
+
+        testResultDonorSettings.riskLevelTurnedRedTime.value shouldBe Instant.EPOCH.plus(1)
+
+        testResultDonorSettings.riskLevelTurnedRedTime.update { null }
+
+        runBlockingTest {
+            val instance = createInstance(scope = this)
+            instance.launch()
+            advanceUntilIdle()
+        }
+
+        testResultDonorSettings.riskLevelTurnedRedTime.value shouldBe Instant.EPOCH.plus(2)
+    }
+
+    @Test
+    fun `mostRecentDateWithHighOrLowRiskLevel is updated every time`() {
+        every { riskLevelStorage.latestRiskLevelResults } returns flowOf(
+            listOf(
+                createRiskLevel(
+                    INCREASED_RISK,
+                    calculatedAt = Instant.EPOCH.plus(1),
+                    aggregatedRiskResult = mockk<AggregatedRiskResult>().apply {
+                        every { mostRecentDateWithHighRisk } returns Instant.EPOCH.plus(10)
+                        every { isIncreasedRisk() } returns true
+                    }
+                ),
+                createRiskLevel(LOW_RISK, calculatedAt = Instant.EPOCH)
+            )
+        )
+
+        runBlockingTest {
+            val instance = createInstance(scope = this)
+            instance.launch()
+            advanceUntilIdle()
+        }
+
+        testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel.value shouldBe Instant.EPOCH.plus(10)
+
+        every { riskLevelStorage.latestRiskLevelResults } returns flowOf(
+            listOf(
+                createRiskLevel(
+                    INCREASED_RISK,
+                    calculatedAt = Instant.EPOCH.plus(1),
+                    aggregatedRiskResult = mockk<AggregatedRiskResult>().apply {
+                        every { mostRecentDateWithLowRisk } returns Instant.EPOCH.plus(20)
+                        every { isIncreasedRisk() } returns false
+                    }
+                ),
+                createRiskLevel(LOW_RISK, calculatedAt = Instant.EPOCH)
+            )
+        )
+
+        runBlockingTest {
+            val instance = createInstance(scope = this)
+            instance.launch()
+            advanceUntilIdle()
+        }
+
+        testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel.value shouldBe Instant.EPOCH.plus(20)
+    }
+
     @Test
     fun `evaluate risk level change detection function`() {
         RiskLevelChangeDetector.hasHighLowLevelChanged(CALCULATION_FAILED, CALCULATION_FAILED) shouldBe false
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt
index 28cf7f0f7f8327649644c8b907bebe7033c87694..aa31b2ba8774a2eac7d20f7a6f51e57ea1d62e42 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt
@@ -204,7 +204,7 @@ class RiskLevelTaskTest : BaseTest() {
     }
 
     @Test
-    fun `risk calculation is skipped if positive test is registered`() = runBlockingTest {
+    fun `risk calculation is skipped if positive test is registered and viewed`() = runBlockingTest {
         val cachedKey = mockk<CachedKey>().apply {
             every { info } returns mockk<CachedKeyInfo>().apply {
                 every { toDateTime() } returns DateTime.parse("2020-12-28").minusDays(1)
@@ -216,6 +216,7 @@ class RiskLevelTaskTest : BaseTest() {
         every { backgroundModeStatus.isAutoModeEnabled } returns flowOf(false)
         every { timeStamper.nowUTC } returns now
         every { submissionSettings.isAllowedToSubmitKeys } returns true
+        every { submissionSettings.hasViewedTestResult.value } returns true
 
         createTask().run(arguments) shouldBe RiskLevelTaskResult(
             calculatedAt = now,
@@ -223,6 +224,35 @@ class RiskLevelTaskTest : BaseTest() {
         )
     }
 
+    @Test
+    fun `risk calculation is not skipped if positive test is registered and not viewed`() = runBlockingTest {
+        val cachedKey = mockk<CachedKey>().apply {
+            every { info } returns mockk<CachedKeyInfo>().apply {
+                every { toDateTime() } returns DateTime.parse("2020-12-28").minusDays(1)
+            }
+        }
+        val now = Instant.parse("2020-12-28")
+        val aggregatedRiskResult = mockk<AggregatedRiskResult>().apply {
+            every { isIncreasedRisk() } returns true
+        }
+
+        coEvery { keyCacheRepository.getAllCachedKeys() } returns listOf(cachedKey)
+        coEvery { enfClient.exposureWindows() } returns listOf()
+        every { riskLevels.calculateRisk(any(), any()) } returns null
+        every { riskLevels.aggregateResults(any(), any()) } returns aggregatedRiskResult
+        every { timeStamper.nowUTC } returns now
+        coEvery { analyticsExposureWindowCollector.reportRiskResultsPerWindow(any()) } just Runs
+        every { submissionSettings.isAllowedToSubmitKeys } returns true
+        every { submissionSettings.hasViewedTestResult.value } returns false
+
+        createTask().run(arguments) shouldBe RiskLevelTaskResult(
+            calculatedAt = now,
+            failureReason = null,
+            aggregatedRiskResult = aggregatedRiskResult,
+            listOf()
+        )
+    }
+
     @Test
     fun `risk calculation returns aggregated risk result`() = runBlockingTest {
         val cachedKey = mockk<CachedKey>().apply {
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt
index 31f62170a700594e6b68beb6e7f3039da3154d4f..119b38c92ecfddec8871cc31c2bd86136e767960 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt
@@ -14,9 +14,9 @@ import de.rki.coronawarnapp.util.NetworkRequestWrapper
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.di.AppInjector
 import de.rki.coronawarnapp.util.di.ApplicationComponent
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptedPreferencesFactory
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
 import de.rki.coronawarnapp.util.formatter.TestResult
-import de.rki.coronawarnapp.util.security.EncryptedPreferencesFactory
-import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
@@ -80,12 +80,15 @@ class SubmissionRepositoryTest : BaseTest() {
 
         every { submissionSettings.devicePairingSuccessfulAt = any() } just Runs
         every { submissionSettings.initialTestResultReceivedAt } returns resultReceivedTimeStamp
+        every { submissionSettings.initialTestResultReceivedAt = any() } just Runs
 
         every { submissionSettings.hasGivenConsent } returns mockFlowPreference(false)
         every { submissionSettings.hasViewedTestResult } returns mockFlowPreference(false)
         every { submissionSettings.symptoms } returns mockFlowPreference(Symptoms.NO_INFO_GIVEN)
         every { submissionSettings.clear() } just Runs
 
+        every { submissionSettings.devicePairingSuccessfulAt } returns null
+
         every { taskController.tasks } returns emptyFlow()
 
         coEvery { tekHistoryStorage.clear() } just Runs
@@ -118,10 +121,8 @@ class SubmissionRepositoryTest : BaseTest() {
             tracingSettings.isTestResultAvailableNotificationSent = capture(isTestResultAvailableNotificationSent)
         } answers {}
 
-        every { submissionSettings.initialTestResultReceivedAt = any() } just Runs
         every { submissionSettings.isAllowedToSubmitKeys = any() } just Runs
         every { submissionSettings.isSubmissionSuccessful = any() } just Runs
-        every { analyticsKeySubmissionCollector.reset() } just Runs
 
         submissionRepository.removeTestFromDevice()
 
@@ -141,6 +142,7 @@ class SubmissionRepositoryTest : BaseTest() {
     fun registrationWithGUIDSucceeds() = runBlockingTest {
         coEvery { submissionService.asyncRegisterDeviceViaGUID(guid) } returns registrationData
         coEvery { analyticsKeySubmissionCollector.reportTestRegistered() } just Runs
+        every { analyticsKeySubmissionCollector.reset() } just Runs
 
         val submissionRepository = createInstance(scope = this)
 
@@ -161,6 +163,7 @@ class SubmissionRepositoryTest : BaseTest() {
         coEvery { submissionService.asyncRegisterDeviceViaTAN(tan) } returns registrationData
         coEvery { analyticsKeySubmissionCollector.reportTestRegistered() } just Runs
         every { analyticsKeySubmissionCollector.reportRegisteredWithTeleTAN() } just Runs
+        every { analyticsKeySubmissionCollector.reset() } just Runs
 
         val submissionRepository = createInstance(scope = this)
 
@@ -276,4 +279,55 @@ class SubmissionRepositoryTest : BaseTest() {
 
         coVerify(exactly = 0) { submissionService.asyncRequestTestResult(any()) }
     }
+
+    @Test
+    fun `EXPOSUREAPP-4484 is fixed`() = runBlockingTest {
+        every { timeStamper.nowUTC } returns Instant.EPOCH
+
+        var initialTimeStamp = Instant.EPOCH.plus(9999)
+        every { submissionSettings.initialTestResultReceivedAt } answers { initialTimeStamp }
+        every { submissionSettings.initialTestResultReceivedAt = any() } answers { initialTimeStamp = arg(0) }
+
+        every { submissionSettings.registrationToken } returns mockFlowPreference("token")
+        every { submissionSettings.devicePairingSuccessfulAt } returns null
+
+        val submissionRepository = createInstance(scope = this)
+
+        submissionRepository.updateTestResult(TestResult.NEGATIVE)
+
+        verify {
+            submissionSettings.initialTestResultReceivedAt = null
+            submissionSettings.initialTestResultReceivedAt = Instant.EPOCH
+        }
+
+        initialTimeStamp shouldBe Instant.EPOCH
+    }
+
+    @Test
+    fun `EXPOSUREAPP-4484 has specific conditions`() = runBlockingTest {
+        val submissionRepository = createInstance(scope = this)
+
+        every { submissionSettings.initialTestResultReceivedAt } returns Instant.ofEpochMilli(1234)
+        every { submissionSettings.registrationToken } returns mockFlowPreference("token")
+        // This needs to be null to trigger the fix
+        every { submissionSettings.devicePairingSuccessfulAt } returns Instant.ofEpochMilli(5678)
+
+        submissionRepository.updateTestResult(TestResult.NEGATIVE)
+
+        every { submissionSettings.initialTestResultReceivedAt } returns Instant.ofEpochMilli(1234)
+        // This needs to be non null to trigger the fix
+        every { submissionSettings.registrationToken } returns mockFlowPreference(null)
+        every { submissionSettings.devicePairingSuccessfulAt } returns null
+
+        submissionRepository.updateTestResult(TestResult.NEGATIVE)
+
+        // This needs to be non null to trigger the fix
+        every { submissionSettings.initialTestResultReceivedAt } returns null
+        every { submissionSettings.registrationToken } returns mockFlowPreference("token")
+        every { submissionSettings.devicePairingSuccessfulAt } returns null
+
+        submissionRepository.updateTestResult(TestResult.NEGATIVE)
+
+        verify(exactly = 0) { submissionSettings.initialTestResultReceivedAt = null }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigrationTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigrationTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bc18a0cf95c56e371fc70394f66f767ce40f307d
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigrationTest.kt
@@ -0,0 +1,165 @@
+package de.rki.coronawarnapp.util.encryptionmigration
+
+import android.content.Context
+import android.content.SharedPreferences
+import androidx.core.content.edit
+import de.rki.coronawarnapp.main.CWASettings
+import de.rki.coronawarnapp.storage.OnboardingSettings
+import de.rki.coronawarnapp.storage.TracingSettings
+import de.rki.coronawarnapp.submission.SubmissionSettings
+import io.kotest.assertions.throwables.shouldNotThrowAny
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.Runs
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.just
+import io.mockk.mockk
+import org.joda.time.Instant
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseIOTest
+import testhelpers.preferences.MockSharedPreferences
+import testhelpers.preferences.mockFlowPreference
+import java.io.File
+
+class EncryptedPreferencesMigrationTest : BaseIOTest() {
+    @MockK lateinit var context: Context
+    @MockK lateinit var encryptedPreferencesHelper: EncryptedPreferencesHelper
+    @MockK lateinit var cwaSettings: CWASettings
+    @MockK lateinit var submissionSettings: SubmissionSettings
+    @MockK lateinit var tracingSettings: TracingSettings
+    @MockK lateinit var onboardingSettings: OnboardingSettings
+    @MockK lateinit var encryptedErrorResetTool: EncryptionErrorResetTool
+
+    private val testDir = File(IO_TEST_BASEDIR, this::class.java.simpleName)
+    private val dbFile = File(testDir, "database.sql")
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        testDir.mkdirs()
+    }
+
+    @AfterEach
+    fun teardown() {
+        testDir.deleteRecursively()
+    }
+
+    private fun createInstance() = EncryptedPreferencesMigration(
+        context = context,
+        encryptedPreferences = encryptedPreferencesHelper,
+        cwaSettings = cwaSettings,
+        submissionSettings = submissionSettings,
+        tracingSettings = tracingSettings,
+        onboardingSettings = onboardingSettings,
+        errorResetTool = encryptedErrorResetTool
+    )
+
+    private fun createOldPreferences() = MockSharedPreferences().also {
+        it.edit {
+            // SettingsLocalData
+            putBoolean(EncryptedPreferencesMigration.SettingsLocalData.PKEY_INTEROPERABILITY_WAS_USED, true)
+            putBoolean(EncryptedPreferencesMigration.SettingsLocalData.PKEY_TRACING_EXPLANATION_WAS_SHOWN, true)
+            putBoolean(EncryptedPreferencesMigration.SettingsLocalData.PKEY_NOTIFICATIONS_RISK_ENABLED, false)
+            putBoolean(EncryptedPreferencesMigration.SettingsLocalData.PKEY_NOTIFICATIONS_TEST_ENABLED, false)
+            putInt(
+                EncryptedPreferencesMigration.SettingsLocalData.PKEY_POSITIVE_TEST_RESULT_REMINDER_COUNT,
+                Int.MAX_VALUE
+            )
+
+            // OnboardingLocalData
+            putLong(EncryptedPreferencesMigration.OnboardingLocalData.PKEY_ONBOARDING_COMPLETED_TIMESTAMP, 10101010L)
+            putBoolean(EncryptedPreferencesMigration.OnboardingLocalData.PKEY_BACKGROUND_CHECK_DONE, true)
+
+            // TracingLocalData
+            putLong(EncryptedPreferencesMigration.TracingLocalData.PKEY_POOLING_TEST_RESULT_STARTED, 10101010L)
+            putBoolean(EncryptedPreferencesMigration.TracingLocalData.PKEY_TEST_RESULT_NOTIFICATION, true)
+            putBoolean(EncryptedPreferencesMigration.TracingLocalData.PKEY_HAS_RISK_STATUS_LOWERED, true)
+            putLong(EncryptedPreferencesMigration.TracingLocalData.PKEY_TRACING_ACTIVATION_TIME, 10101010L)
+
+            // SubmissionLocalData
+            putString(EncryptedPreferencesMigration.SubmissionLocalData.PKEY_REGISTRATION_TOKEN, "super_secret_token")
+            putLong(EncryptedPreferencesMigration.SubmissionLocalData.PKEY_INITIAL_RESULT_RECEIVED_TIME, 10101010L)
+            putLong(EncryptedPreferencesMigration.SubmissionLocalData.PKEY_DEVICE_PARING_SUCCESSFUL_TIME, 10101010L)
+            putInt(EncryptedPreferencesMigration.SubmissionLocalData.PKEY_NUMBER_SUCCESSFUL_SUBMISSIONS, 1)
+            putBoolean(EncryptedPreferencesMigration.SubmissionLocalData.PKEY_IS_ALLOWED_TO_SUBMIT, true)
+        }
+    }
+
+    @Test
+    fun `is migration successful`() {
+        every { context.getDatabasePath("coronawarnapp-db") } returns dbFile
+        every { encryptedPreferencesHelper.clean() } just Runs
+
+        val oldPreferences = createOldPreferences()
+        every { encryptedPreferencesHelper.instance } returns oldPreferences
+
+        // SettingsLocalData
+        every { cwaSettings.wasInteroperabilityShownAtLeastOnce = true } just Runs
+        every { cwaSettings.wasTracingExplanationDialogShown = true } just Runs
+        val mockRiskPreference = mockFlowPreference(true)
+        every { cwaSettings.isNotificationsRiskEnabled } returns mockRiskPreference
+        val mockTestPreference = mockFlowPreference(true)
+        every { cwaSettings.isNotificationsTestEnabled } returns mockTestPreference
+        every { cwaSettings.numberOfRemainingSharePositiveTestResultReminders = Int.MAX_VALUE } just Runs
+
+        // OnboardingLocalData
+        every { onboardingSettings.onboardingCompletedTimestamp = Instant.ofEpochMilli(10101010L) } just Runs
+        every { onboardingSettings.isBackgroundCheckDone = true } just Runs
+
+        // TracingLocalData
+        every { tracingSettings.initialPollingForTestResultTimeStamp = 10101010L } just Runs
+        every { tracingSettings.isTestResultAvailableNotificationSent = true } just Runs
+        val mockNotificationPreference = mockFlowPreference(false)
+        every { tracingSettings.isUserToBeNotifiedOfLoweredRiskLevel } returns mockNotificationPreference
+        every { tracingSettings.isConsentGiven = true } just Runs
+
+        // SubmissionLocalData
+        val mockRegtokenPreference = mockFlowPreference<String?>(null)
+        every { submissionSettings.registrationToken } returns mockRegtokenPreference
+        every { submissionSettings.initialTestResultReceivedAt = Instant.ofEpochMilli(10101010L) } just Runs
+        every { submissionSettings.devicePairingSuccessfulAt = Instant.ofEpochMilli(10101010L) } just Runs
+        every { submissionSettings.isSubmissionSuccessful = true } just Runs
+        every { submissionSettings.isAllowedToSubmitKeys = true } just Runs
+
+        val migrationInstance = createInstance()
+
+        migrationInstance.doMigration()
+
+        // SettingsLocalData
+        mockRiskPreference.value shouldBe false
+        mockTestPreference.value shouldBe false
+
+        // TracingLocalData
+        mockNotificationPreference.value shouldBe true
+
+        // SubmissionLocalData
+        mockRegtokenPreference.value shouldBe "super_secret_token"
+    }
+
+    @Test
+    fun `error during migration will be caught`() {
+        every { context.getDatabasePath("coronawarnapp-db") } returns dbFile
+
+        val mockPrefs = mockk<SharedPreferences>()
+        every {
+            mockPrefs.getBoolean(
+                EncryptedPreferencesMigration.SettingsLocalData.PKEY_INTEROPERABILITY_WAS_USED,
+                false
+            )
+        } throws Exception("No one expects the spanish inquisition")
+
+        every { encryptedPreferencesHelper.instance } returns mockPrefs
+        every { encryptedPreferencesHelper.clean() } just Runs
+
+        every { encryptedErrorResetTool.isResetNoticeToBeShown = true } just Runs
+
+        shouldNotThrowAny {
+            val instance = createInstance()
+            instance.doMigration()
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactoryTest.kt
index dc37e11dfe7312d08cf5ae20eb12c9d8a6c1a77a..8ca6a803feab0998a0010866b371caa29c6ac1b2 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactoryTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactoryTest.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.util.security
 
 import android.content.Context
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptedPreferencesFactory
 import io.kotest.assertions.throwables.shouldNotThrowAny
 import io.mockk.Called
 import io.mockk.MockKAnnotations
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/DiagnosisTestResultRetrievalPeriodicWorkerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/DiagnosisTestResultRetrievalPeriodicWorkerTest.kt
index 2547fd7543ba824ef0c7cb14acfe1036a2ae4343..6a9c9d4a7777a3e330104b772f6fba992888eeef 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/DiagnosisTestResultRetrievalPeriodicWorkerTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/DiagnosisTestResultRetrievalPeriodicWorkerTest.kt
@@ -15,9 +15,9 @@ import de.rki.coronawarnapp.util.TimeAndDateExtensions.daysToMilliseconds
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.di.AppInjector
 import de.rki.coronawarnapp.util.di.ApplicationComponent
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptedPreferencesFactory
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
 import de.rki.coronawarnapp.util.formatter.TestResult
-import de.rki.coronawarnapp.util.security.EncryptedPreferencesFactory
-import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool
 import de.rki.coronawarnapp.worker.BackgroundWorkScheduler.stop
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
diff --git a/README.md b/README.md
index 178eb8b25c72280aa477f8a895f8481d0e634a58..d87a39c44dabe90de7707a91137f5df9ba8af0a5 100644
--- a/README.md
+++ b/README.md
@@ -78,18 +78,20 @@ The German government has asked SAP and Deutsche Telekom to develop the Corona-W
 
 ## Repositories
 
-| Repository          | Description                                                           |
-| ------------------- | --------------------------------------------------------------------- |
-| [cwa-documentation] | Project overview, general documentation, and white papers.            |
-| [cwa-app-ios]       | Native iOS app using the Apple/Google exposure notification API.      |
-| [cwa-app-android]   | Native Android app using the Apple/Google exposure notification API.  |
-| [cwa-wishlist]      | Community feature requests.                                           |
-| [cwa-website]       | The official website for the Corona-Warn-App                          |
-| [cwa-server]        | Backend implementation for the Apple/Google exposure notification API.|
-| [cwa-verification-server] | Backend implementation of the verification process.             |
-| [cwa-verification-portal] | The portal to interact with the verification server             |
-| [cwa-verification-iam]    | The identity and access management to interact with the verification server |
-| [cwa-testresult-server]   | Receives the test results from connected laboratories           |
+| Repository                | Description                                                                  |
+| ------------------------- | ---------------------------------------------------------------------------- |
+| [cwa-documentation]       | Project overview, general documentation, and white papers.                   |
+| [cwa-app-ios]             | Native iOS app using the Apple/Google exposure notification API.             |
+| [cwa-app-android]         | Native Android app using the Apple/Google exposure notification API.         |
+| [cwa-wishlist]            | Community feature requests.                                                  |
+| [cwa-website]             | The official website for the Corona-Warn-App.                                |
+| [cwa-server]              | Backend implementation for the Apple/Google exposure notification API.       |
+| [cwa-ppa-server]          | Backend implementation for the privacy-preserving analytics server.          |
+| [cwa-verification-server] | Backend implementation of the verification process.                          |
+| [cwa-verification-portal] | The portal to interact with the verification server.                         |
+| [cwa-verification-iam]    | The identity and access management to interact with the verification server. |
+| [cwa-testresult-server]   | Receives the test results from connected laboratories.                       |
+| [cwa-log-upload]          | The log upload service is the counterpart of the log upload in the app.      |
 
 [cwa-documentation]: https://github.com/corona-warn-app/cwa-documentation
 [cwa-app-ios]: https://github.com/corona-warn-app/cwa-app-ios
@@ -97,10 +99,13 @@ The German government has asked SAP and Deutsche Telekom to develop the Corona-W
 [cwa-wishlist]: https://github.com/corona-warn-app/cwa-wishlist
 [cwa-website]: https://github.com/corona-warn-app/cwa-website
 [cwa-server]: https://github.com/corona-warn-app/cwa-server
+[cwa-ppa-server]: https://github.com/corona-warn-app/cwa-ppa-server
 [cwa-verification-server]: https://github.com/corona-warn-app/cwa-verification-server
 [cwa-verification-portal]: https://github.com/corona-warn-app/cwa-verification-portal
 [cwa-verification-iam]: https://github.com/corona-warn-app/cwa-verification-iam
 [cwa-testresult-server]: https://github.com/corona-warn-app/cwa-testresult-server
+[cwa-log-upload]: https://github.com/corona-warn-app/cwa-log-upload
+
 
 ## Licensing