diff --git a/.circleci/config.yml b/.circleci/config.yml
index 939ec23a96d88b817af35289015454d878139d38..c2f4e39956f230b2ccb2b7f43529e1165981f391 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -508,7 +508,7 @@ jobs:
       - store_artifacts:
           path: /tmp/instrumentation_tests_device.zip
           destination: zips/instrumentation_tests_device.zip
-
+  # Keep it until Firebase Test Lab proves reliability
   device_screenshots:
     macos:
       xcode: "12.3.0"
@@ -550,6 +550,65 @@ jobs:
           path: /tmp/device_screenshots.zip
           destination: zips/device_screenshots.zip
 
+  firebase_screenshots:
+    resource_class: xlarge
+    docker:
+      - image: circleci/android:api-28
+    steps:
+      - skip-for-external-pull-requests
+      - setup-google-cloud
+      - checkout
+      - restore-gradle-cache
+      - restore-android-build-cache
+      - run-gradle-cmd:
+          desc: Build APKs for screenshots
+          cmd: >
+            :Corona-Warn-App:assembleDebug
+            :Corona-Warn-App:assembleAndroidTest
+      - run:
+          name: Setup Testlab environment
+          command: |
+            echo "export BUCKETDIR=\"`date "+%Y-%m-%d-%H:%M:%S:%3N"`-${RANDOM}\"" >> $BASH_ENV
+            source $BASH_ENV
+            echo "$BUCKETDIR is setup."
+      - run:
+          name: Test with Firebase Test Lab
+          command: |
+            echo "Using bucketdir $BUCKETDIR"
+            sudo gcloud firebase test android run \
+              --type instrumentation \
+              --app Corona-Warn-App/build/outputs/apk/deviceForTesters/debug/*.apk \
+              --test Corona-Warn-App/build/outputs/apk/androidTest/deviceForTesters/debug/*.apk \
+              --results-dir ${BUCKETDIR} \
+              --results-bucket ${GOOGLE_PROJECT_ID}-circleci-android \
+              --environment-variables clearPackageData=true \
+              --test-targets "annotation testhelpers.Screenshot" \
+              --timeout 20m \
+              --device-ids flame \
+              --os-version-ids 29 \
+              --locales de_DE,en_US \
+              --orientations portrait \
+              --no-record-video
+          no_output_timeout: 30m
+      - run:
+          name: Create directory to store test results
+          command: mkdir firebase-screenshots
+          when: always
+      - run:
+          name: Install gsutil dependency and copy test results data
+          command: |
+            sudo pip install -U crcmod
+            sudo gsutil -m cp -R -U gs://${GOOGLE_PROJECT_ID}-circleci-android/${BUCKETDIR}/flame* firebase-screenshots
+          when: always
+      - store_test_results:
+          path: ./firebase-screenshots
+      - compress-path:
+          input: ./firebase-screenshots
+          output: /tmp/screenshots.zip
+      - store_artifacts:
+          path: /tmp/screenshots.zip
+          destination: zips/screenshots.zip
+
 #######################
 # Workflow section
 # Job execution orders
@@ -588,7 +647,7 @@ workflows:
                 - /^v.*/
             branches:
               ignore: /.*/
-      - device_screenshots:
+      - firebase_screenshots:
           filters:
             tags:
               only:
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/MainActivityTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/MainActivityTest.kt
index 647ff840aaa8c4dbe467e13d4ea26dc7ecf7a2b9..d457ee7eb3f591ca3d179da0f3dfe81b0e627c4b 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/MainActivityTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/MainActivityTest.kt
@@ -17,6 +17,7 @@ import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings
 import de.rki.coronawarnapp.contactdiary.ui.overview.ContactDiaryOverviewFragment
 import de.rki.coronawarnapp.contactdiary.ui.overview.ContactDiaryOverviewViewModel
 import de.rki.coronawarnapp.contactdiary.ui.overview.adapter.ListItem
+import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsScheduler
 import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler
 import de.rki.coronawarnapp.environment.EnvironmentSetup
 import de.rki.coronawarnapp.main.CWASettings
@@ -440,4 +441,10 @@ class MainProviderModule {
         mockk<ContactDiaryWorkScheduler>(relaxed = true).apply {
             every { schedulePeriodic() } just Runs
         }
+
+    @Provides
+    fun dataDonationAnalyticsScheduler(): DataDonationAnalyticsScheduler =
+        mockk<DataDonationAnalyticsScheduler>(relaxed = true).apply {
+            every { schedulePeriodic() } just Runs
+        }
 }
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragmentTest.kt
index fcb9c09305419dfade9a40174ccf8a3d09c049e1..37e5a4d49af8069975cbe544e3fd203ad12f2cca 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragmentTest.kt
@@ -39,8 +39,10 @@ class OnboardingFragmentTest : BaseUITest() {
         launchFragmentInContainer2<OnboardingFragment>()
         takeScreenshot<OnboardingFragment>()
 
-        onView(withId(R.id.onboarding_easy_language)).perform(scrollTo())
-        takeScreenshot<OnboardingFragment>("2")
+        if (showEasyLanguageLink()) {
+            onView(withId(R.id.onboarding_easy_language)).perform(scrollTo())
+            takeScreenshot<OnboardingFragment>("2")
+        }
     }
 }
 
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingDetailsFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingDetailsFragmentTest.kt
index cd1ae371d21040b73673b24272918215fea7f634..b9da670a20ca57ebbddf6ba6492d4687e788f5dc 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingDetailsFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingDetailsFragmentTest.kt
@@ -4,6 +4,7 @@ import androidx.lifecycle.MutableLiveData
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import dagger.Module
 import dagger.android.ContributesAndroidInjector
+import de.rki.coronawarnapp.datadonation.survey.Surveys
 import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.storage.TracingRepository
 import de.rki.coronawarnapp.tracing.GeneralTracingStatus
@@ -24,12 +25,12 @@ import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import testhelpers.BaseUITest
-import testhelpers.takeScreenshot
 import testhelpers.Screenshot
 import testhelpers.SystemUIDemoModeRule
 import testhelpers.TestDispatcherProvider
 import testhelpers.launchFragment2
 import testhelpers.launchFragmentInContainer2
+import testhelpers.takeScreenshot
 import tools.fastlane.screengrab.locale.LocaleTestRule
 
 @RunWith(AndroidJUnit4::class)
@@ -41,6 +42,7 @@ class TracingDetailsFragmentTest : BaseUITest() {
     @MockK lateinit var tracingDetailsItemProvider: TracingDetailsItemProvider
     @MockK lateinit var tracingStateProviderFactory: TracingStateProvider.Factory
     @MockK lateinit var tracingRepository: TracingRepository
+    @MockK lateinit var surveys: Surveys
 
     private lateinit var viewModel: TracingDetailsFragmentViewModel
 
@@ -63,7 +65,8 @@ class TracingDetailsFragmentTest : BaseUITest() {
                 riskLevelStorage = riskLevelStorage,
                 tracingDetailsItemProvider = tracingDetailsItemProvider,
                 tracingStateProviderFactory = tracingStateProviderFactory,
-                tracingRepository = tracingRepository
+                tracingRepository = tracingRepository,
+                surveys = surveys
             )
         )
 
diff --git a/Corona-Warn-App/src/androidTest/java/testhelpers/BaseUITest.kt b/Corona-Warn-App/src/androidTest/java/testhelpers/BaseUITest.kt
index a8c26e949e888c86e9a9f2e60fb7fd1f1a8176e4..ad347acdb141a78f9fa9e3132e25fe99dc894bcf 100644
--- a/Corona-Warn-App/src/androidTest/java/testhelpers/BaseUITest.kt
+++ b/Corona-Warn-App/src/androidTest/java/testhelpers/BaseUITest.kt
@@ -1,11 +1,20 @@
 package testhelpers
 
+import android.Manifest
+import androidx.test.rule.GrantPermissionRule
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
+import org.junit.Rule
 import testhelpers.viewmodels.MockViewModelModule
 
 abstract class BaseUITest : BaseTest() {
 
+    @get:Rule
+    val permissionRule: GrantPermissionRule = GrantPermissionRule.grant(
+        Manifest.permission.READ_EXTERNAL_STORAGE,
+        Manifest.permission.WRITE_EXTERNAL_STORAGE
+    )
+
     inline fun <reified T : CWAViewModel> setupMockViewModel(factory: CWAViewModelFactory<T>) {
         MockViewModelModule.CREATORS[T::class.java] = factory
     }
diff --git a/Corona-Warn-App/src/androidTest/java/testhelpers/ScreenShotter.kt b/Corona-Warn-App/src/androidTest/java/testhelpers/ScreenShotter.kt
index e7076a69636b134b9e8fb5a545b19836c801fea5..4d9f4cea6269d3119a667f9373c88bac80d0c3db 100644
--- a/Corona-Warn-App/src/androidTest/java/testhelpers/ScreenShotter.kt
+++ b/Corona-Warn-App/src/androidTest/java/testhelpers/ScreenShotter.kt
@@ -1,13 +1,23 @@
 package testhelpers
 
 import android.app.Activity
+import android.graphics.Bitmap
 import android.os.Bundle
+import android.provider.Settings
+import android.util.Log
 import androidx.annotation.StyleRes
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentFactory
 import androidx.test.espresso.ViewAction
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import de.rki.coronawarnapp.R
 import tools.fastlane.screengrab.Screengrab
+import tools.fastlane.screengrab.ScreenshotCallback
+import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
+import tools.fastlane.screengrab.file.Chmod
+import java.io.BufferedOutputStream
+import java.io.File
+import java.io.FileOutputStream
 
 /**
  * Waits for 2 sec and captures a screenshot
@@ -18,7 +28,18 @@ inline fun <reified T> takeScreenshot(suffix: String = "", delay: Long = SCREENS
     Thread.sleep(delay)
     val simpleName = T::class.simpleName
     val name = if (suffix.isEmpty()) simpleName else simpleName.plus("_$suffix")
-    Screengrab.screenshot(name)
+
+    val contentResolver = getInstrumentation().targetContext.contentResolver
+    val testLabSetting = Settings.System.getString(contentResolver, "firebase.test.lab")
+    if ("true" == testLabSetting) {
+        Screengrab.screenshot(
+            name,
+            UiAutomatorScreenshotStrategy(),
+            SDCardCallback
+        )
+    } else {
+        Screengrab.screenshot(name)
+    }
 }
 
 /**
@@ -36,3 +57,35 @@ inline fun <reified F : Fragment> captureScreenshot(
     launchFragmentInContainer2<F>(fragmentArgs, themeResId, factory)
     takeScreenshot<F>(suffix)
 }
+
+/**
+ * Saves screenshots on the device's sdcard
+ */
+object SDCardCallback : ScreenshotCallback {
+    private const val ROOT_DIRECTORY = "/sdcard"
+    private const val SCREENSHOTS_DIRECTORY = "screenshots"
+    private const val SCREENSHOT_FORMAT = ".png"
+    private const val IMAGE_QUALITY = 100
+
+    override fun screenshotCaptured(screenshotName: String, screenshot: Bitmap) {
+        try {
+            val directory = File(ROOT_DIRECTORY, SCREENSHOTS_DIRECTORY)
+            if (!directory.exists()) {
+                directory.mkdirs()
+            }
+            val screenshotFile = File(directory, screenshotName + SCREENSHOT_FORMAT)
+            if (!screenshotFile.exists()) {
+                screenshotFile.createNewFile()
+            }
+
+            BufferedOutputStream(FileOutputStream(screenshotFile)).use {
+                screenshot.compress(Bitmap.CompressFormat.PNG, IMAGE_QUALITY, it)
+                Chmod.chmodPlusR(screenshotFile)
+                screenshot.recycle()
+            }
+            Log.d("Screengrab", "Captured screenshot \"${screenshotFile.name}\"")
+        } catch (e: Exception) {
+            throw RuntimeException("Unable to capture screenshot.", e)
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/androidTest/java/testhelpers/ScreenshotUnderTest.kt b/Corona-Warn-App/src/androidTest/java/testhelpers/ScreenshotUnderTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7d1de56b8f35ddf027530b819add8a7bccd228d7
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/testhelpers/ScreenshotUnderTest.kt
@@ -0,0 +1,15 @@
+package testhelpers
+
+/**
+ * Similar to [Screenshot]. it is helpful during development and testing process to filter
+ * the test currently being implemented.
+ * In fastlane folder. replace `Screenshot` with `ScreenshotUnderTest` in Screengrabfile
+ *
+ * Note: this is only for testing purposes and should NOT be used in final tests
+ */
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+@Target(
+    AnnotationTarget.FUNCTION,
+    AnnotationTarget.CLASS
+)
+annotation class ScreenshotUnderTest
diff --git a/Corona-Warn-App/src/debug/AndroidManifest.xml b/Corona-Warn-App/src/debug/AndroidManifest.xml
index 26a521d64d1103520a4dd6c6130a7f248e939d2e..97058d1d3ae50643a01ff82ebd99e98b1322b9ed 100644
--- a/Corona-Warn-App/src/debug/AndroidManifest.xml
+++ b/Corona-Warn-App/src/debug/AndroidManifest.xml
@@ -15,4 +15,8 @@
         android:name="android.permission.CHANGE_CONFIGURATION"
         tools:ignore="ProtectedPermissions" />
 
+    <application
+        android:requestLegacyExternalStorage="true"
+        tools:node="merge" />
+
 </manifest>
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/bugreporting/reporter/DefaultBugReporter.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/bugreporting/reporter/DefaultBugReporter.kt
index 50bf3b51d4bdd295fc4b0d231ddbf9b0d86d5a86..c195019c58bf43968777d327f9ea4013f25ee389 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/bugreporting/reporter/DefaultBugReporter.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/bugreporting/reporter/DefaultBugReporter.kt
@@ -20,7 +20,7 @@ class DefaultBugReporter @Inject constructor(
 ) : BugReporter {
 
     override fun report(throwable: Throwable, tag: String?, info: String?) {
-        Timber.e(throwable, "Processing reported bug (info=$info) from $tag.")
+        Timber.v("Processing reported bug (info=$info) from $tag: $throwable")
         scope.launch(context = dispatcherProvider.IO) {
             val event = processor.processor(throwable, tag, info)
             repository.save(event)
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/CrashReportAdapter.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/CrashReportAdapter.kt
index afdfb4358aa590da76289fb57cf592c9b0efc2f1..6577ece9d20679eadf04e6505c23e2b930b2a6f3 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/CrashReportAdapter.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/CrashReportAdapter.kt
@@ -37,8 +37,8 @@ class CrashReportAdapter(private val itemClickListener: (bugEvent: BugEvent) ->
     class CrashHolder(private val binding: ViewCrashreportListItemBinding) :
         RecyclerView.ViewHolder(binding.root) {
         fun bind(bugEvent: BugEvent, pos: Int) {
-            binding.crashReportTitle = "Error #${pos + 1}"
-            binding.message = bugEvent.exceptionMessage
+            binding.crashReportTitle = "#${pos + 1} ${bugEvent.exceptionClass}"
+            binding.message = bugEvent.info ?: bugEvent.exceptionMessage
             binding.crashReportDateFormatted =
                 bugEvent.createdAt.toDateTime(DateTimeZone.getDefault()).toString()
                     .replace("T", "  ")
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt
index fa6cd1d6b836870396f0b3f16c5c30e2179c100c..26659a70227711ac3798bacb43f4e89b198f3212 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt
@@ -6,7 +6,6 @@ import android.view.View
 import android.widget.RadioButton
 import android.widget.RadioGroup
 import android.widget.Toast
-import androidx.annotation.StringRes
 import androidx.core.app.ShareCompat
 import androidx.core.view.ViewCompat
 import androidx.core.view.children
@@ -18,6 +17,7 @@ import de.rki.coronawarnapp.datadonation.survey.SurveyException
 import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
 import de.rki.coronawarnapp.util.DialogHelper
 import de.rki.coronawarnapp.util.di.AutoInject
+import de.rki.coronawarnapp.util.tryHumanReadableError
 import de.rki.coronawarnapp.util.ui.observe2
 import de.rki.coronawarnapp.util.ui.viewBindingLazy
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
@@ -111,7 +111,15 @@ class DataDonationTestFragment : Fragment(R.layout.fragment_test_datadonation),
         }
 
         vm.showErrorDialog.observe2(this) {
-            showErrorDialog(it)
+            val humanReadableError = it.tryHumanReadableError(requireContext())
+            val dialog = DialogHelper.DialogInstance(
+                context = requireContext(),
+                title = R.string.datadonation_details_survey_consent_error_dialog_title,
+                message = humanReadableError.description,
+                positiveButton = R.string.datadonation_details_survey_consent_error_dialog_pos_button,
+                cancelable = false
+            )
+            DialogHelper.showDialog(dialog)
         }
 
         vm.currentSafetyNetExceptionType.observe2(this) { type ->
@@ -153,6 +161,14 @@ class DataDonationTestFragment : Fragment(R.layout.fragment_test_datadonation),
 
             surveyExceptionSimulationButton.setOnClickListener { vm.showSurveyErrorDialog() }
         }
+
+        vm.isSafetyNetTimeCheckSkipped.observe2(this) {
+            binding.disableSafetynetToggle.isChecked = it
+        }
+
+        binding.disableSafetynetToggle.setOnClickListener {
+            vm.toggleSkipSafetyNetTimeCheck()
+        }
     }
 
     private fun RadioGroup.addRadioButton(text: String) {
@@ -170,19 +186,6 @@ class DataDonationTestFragment : Fragment(R.layout.fragment_test_datadonation),
         }
     }
 
-    private fun showErrorDialog(@StringRes stringRes: Int) {
-        context?.let {
-            val dialog = DialogHelper.DialogInstance(
-                context = it,
-                title = R.string.datadonation_details_survey_consent_error_dialog_title,
-                message = stringRes,
-                positiveButton = R.string.datadonation_details_survey_consent_error_dialog_pos_button,
-                cancelable = false
-            )
-            DialogHelper.showDialog(dialog)
-        }
-    }
-
     companion object {
         val MENU_ITEM = TestMenuItem(
             title = "Data Donation",
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragmentViewModel.kt
index e209b4fe84fe3eee00b9c28ce24567490d187023..711cb5f5bd7adcba37acf7a786f23f1fe9ad42be 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragmentViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragmentViewModel.kt
@@ -1,6 +1,5 @@
 package de.rki.coronawarnapp.test.datadonation.ui
 
-import androidx.annotation.StringRes
 import androidx.lifecycle.asLiveData
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
@@ -13,11 +12,10 @@ import de.rki.coronawarnapp.datadonation.safetynet.CWASafetyNet
 import de.rki.coronawarnapp.datadonation.safetynet.DeviceAttestation
 import de.rki.coronawarnapp.datadonation.safetynet.SafetyNetClientWrapper
 import de.rki.coronawarnapp.datadonation.safetynet.SafetyNetException
-import de.rki.coronawarnapp.datadonation.safetynet.errorMsgRes
 import de.rki.coronawarnapp.datadonation.storage.OTPRepository
 import de.rki.coronawarnapp.datadonation.survey.SurveyException
-import de.rki.coronawarnapp.datadonation.survey.errorMsgRes
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
+import de.rki.coronawarnapp.storage.TestSettings
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
@@ -35,7 +33,8 @@ class DataDonationTestFragmentViewModel @AssistedInject constructor(
     private val lastAnalyticsSubmissionLogger: LastAnalyticsSubmissionLogger,
     private val cwaSafetyNet: CWASafetyNet,
     otpRepository: OTPRepository,
-    private val appConfigProvider: AppConfigProvider
+    private val appConfigProvider: AppConfigProvider,
+    private val testSettings: TestSettings
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
     val infoEvents = SingleLiveEvent<String>()
@@ -55,6 +54,9 @@ class DataDonationTestFragmentViewModel @AssistedInject constructor(
     private val lastAnalyticsDataInternal = MutableStateFlow<LastAnalyticsSubmission?>(null)
     val lastAnalyticsData = lastAnalyticsDataInternal.asLiveData(context = dispatcherProvider.Default)
 
+    val isSafetyNetTimeCheckSkipped = testSettings.skipSafetyNetTimeCheck.flow
+        .asLiveData(context = dispatcherProvider.Default)
+
     val otp: String = otpRepository.otpAuthorizationResult?.toString() ?: "No OTP generated and authorized yet"
 
     val surveyConfig = appConfigProvider.currentConfig
@@ -68,7 +70,7 @@ class DataDonationTestFragmentViewModel @AssistedInject constructor(
     private val currentSurveyExceptionTypeInternal = MutableStateFlow(SurveyException.Type.values().first())
     val currentSurveyExceptionType = currentSurveyExceptionTypeInternal.asLiveData(context = dispatcherProvider.Default)
 
-    val showErrorDialog = SingleLiveEvent<@StringRes Int>()
+    val showErrorDialog = SingleLiveEvent<Exception>()
 
     fun createSafetyNetReport() {
         launch {
@@ -158,14 +160,21 @@ class DataDonationTestFragmentViewModel @AssistedInject constructor(
         }
     }
 
+    fun toggleSkipSafetyNetTimeCheck() {
+        testSettings.skipSafetyNetTimeCheck.update { !it }
+    }
+
     fun selectSafetyNetExceptionType(type: SafetyNetException.Type) {
         currentSafetyNetExceptionTypeInternal.value = type
     }
 
     fun showSafetyNetErrorDialog() {
-        currentSafetyNetExceptionTypeInternal.value.run {
-            SafetyNetException(this, "simulated")
-        }.also { showErrorDialog.postValue(it.errorMsgRes()) }
+        showErrorDialog.postValue(
+            SafetyNetException(
+                type = currentSafetyNetExceptionTypeInternal.value,
+                message = "simulated"
+            )
+        )
     }
 
     fun selectSurveyExceptionType(type: SurveyException.Type) {
@@ -173,9 +182,9 @@ class DataDonationTestFragmentViewModel @AssistedInject constructor(
     }
 
     fun showSurveyErrorDialog() {
-        currentSurveyExceptionTypeInternal.value.run {
-            SurveyException(this)
-        }.also { showErrorDialog.postValue(it.errorMsgRes()) }
+        showErrorDialog.postValue(
+            SurveyException(type = currentSurveyExceptionTypeInternal.value)
+        )
     }
 
     @AssistedFactory
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt
index 07bfd4404b3f7c606c6a15b1c64b415fd6f15063..45d0b05c577a8851b7c938e2c7de45edc36cc89b 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt
@@ -69,6 +69,7 @@ class DebugOptionsFragment : Fragment(R.layout.fragment_test_debugoptions), Auto
                 environmentCdnurlDownload.text = "Download CDN:\n${state.urlDownload}"
                 environmentCdnurlSubmission.text = "Submission CDN:\n${state.urlSubmission}"
                 environmentCdnurlVerification.text = "Verification CDN:\n${state.urlVerification}"
+                environmentUrlDatadonation.text = "DataDonation:\n${state.urlDataDonation}"
             }
         }
         vm.environmentChangeEvent.observe2(this) {
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt
index c25c26364c059bf220127e4f89a04f43fbe4c2bf..fb3a8ded80765be7fe43f2487775ff3bfcfa9b2a 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt
@@ -7,7 +7,8 @@ data class EnvironmentState(
     val available: List<EnvironmentSetup.Type>,
     val urlSubmission: String,
     val urlDownload: String,
-    val urlVerification: String
+    val urlVerification: String,
+    val urlDataDonation: String
 ) {
     companion object {
         internal fun EnvironmentSetup.toEnvironmentState() = EnvironmentState(
@@ -15,7 +16,8 @@ data class EnvironmentState(
             available = EnvironmentSetup.Type.values().toList(),
             urlSubmission = submissionCdnUrl,
             urlDownload = downloadCdnUrl,
-            urlVerification = verificationCdnUrl
+            urlVerification = verificationCdnUrl,
+            urlDataDonation = dataDonationCdnUrl
         )
     }
 }
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_appconfig.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_appconfig.xml
index e150e870a96e3ee9a4f0fa60b80860e97b29955a..176b70daeb0aa28c41453addb0bf861b5d3ab1a1 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_appconfig.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_appconfig.xml
@@ -4,7 +4,6 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     tools:ignore="HardcodedText">
 
     <LinearLayout
@@ -84,7 +83,6 @@
             <com.google.android.material.switchmaterial.SwitchMaterial
                 android:id="@+id/fake_correct_devicetime_toggle"
                 android:layout_width="match_parent"
-                app:thumbTint="@color/colorAccent"
                 android:layout_height="0dp"
                 android:layout_marginTop="@dimen/spacing_tiny"
                 android:layout_weight="1"
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_datadonation.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_datadonation.xml
index 39be37917e3c0b7bf881565b0a5c9f0fdba64875..077d1f73f03a61ed5acceb7a6acfeb0c8c22e9e3 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_datadonation.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_datadonation.xml
@@ -257,6 +257,29 @@
                     app:layout_constraintTop_toBottomOf="@id/survey_exception_simulation_radio_group" />
             </androidx.constraintlayout.widget.ConstraintLayout>
 
+            <LinearLayout
+                style="@style/Card"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/spacing_tiny"
+                android:orientation="vertical">
+
+                <com.google.android.material.switchmaterial.SwitchMaterial
+                    android:id="@+id/disable_safetynet_toggle"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:layout_marginTop="@dimen/spacing_tiny"
+                    android:layout_weight="1"
+                    android:text="Skip 24H SafetyNet Check" />
+
+                <TextView
+                    style="@style/TextAppearance.AppCompat.Caption"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/spacing_tiny"
+                    android:text="This disables the 24H time since valid time check for SafetyNet attestation" />
+            </LinearLayout>
+
             <androidx.constraintlayout.widget.ConstraintLayout
                 android:id="@+id/last_analytics_container"
                 style="@style/Card"
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml
index cca12450d9fee3eafa2d51795b793186606cf4b7..cedba81d312970d03e1c16c12dbdb69b669439e3 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml
@@ -104,6 +104,17 @@
                     app:layout_constraintTop_toBottomOf="@+id/environment_cdnurl_submission"
                     tools:text="Verification: ?" />
 
+                <TextView
+                    android:id="@+id/environment_url_datadonation"
+                    style="@style/body2"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/spacing_tiny"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toBottomOf="@+id/environment_cdnurl_verification"
+                    tools:text="DataDonation: ?" />
+
                 <RadioGroup
                     android:id="@+id/environment_toggle_group"
                     android:layout_width="match_parent"
@@ -113,7 +124,7 @@
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toBottomOf="@+id/environment_cdnurl_verification" />
+                    app:layout_constraintTop_toBottomOf="@+id/environment_url_datadonation" />
             </androidx.constraintlayout.widget.ConstraintLayout>
 
         </LinearLayout>
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/view_crashreport_list_item.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/view_crashreport_list_item.xml
index a301fc4ec15a1ed76dc32162324ebe40725e5777..6181e924cf9c9998e78d6ffd53ff64a554c6ef88 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/view_crashreport_list_item.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/view_crashreport_list_item.xml
@@ -57,13 +57,13 @@
 
             <TextView
                 android:id="@+id/textViewCrashReportShortMessage"
-                style="@style/body1"
+                style="@style/TextAppearance.MaterialComponents.Caption"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
-                android:layout_marginTop="24dp"
+                android:layout_marginTop="4dp"
                 android:ellipsize="end"
                 android:inputType="none"
-                android:maxLines="1"
+                android:maxLines="4"
                 android:text="@{message}"
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintStart_toStartOf="parent"
diff --git a/Corona-Warn-App/src/main/assets/default_app_config_android.bin b/Corona-Warn-App/src/main/assets/default_app_config_android.bin
index e94bea0e57dec2d532f9642e5f52f9426e52d028..71db85788c2beff255f07410e14f0ec2bbea4bbb 100644
Binary files a/Corona-Warn-App/src/main/assets/default_app_config_android.bin and b/Corona-Warn-App/src/main/assets/default_app_config_android.bin differ
diff --git a/Corona-Warn-App/src/main/assets/default_app_config_android.sha256 b/Corona-Warn-App/src/main/assets/default_app_config_android.sha256
index f352a96630405e9b9b44ae0e7a5d3fb960223c66..dcbdbc7b85dbed0619623f041c6f02d32ae7ede1 100644
--- a/Corona-Warn-App/src/main/assets/default_app_config_android.sha256
+++ b/Corona-Warn-App/src/main/assets/default_app_config_android.sha256
@@ -1 +1 @@
-827fb746a1128e465d65ec77030fdf38c823dec593ae18aed55195069cf8b701
\ No newline at end of file
+12d0b93c0c02c6870ef75c173a53a8ffb9cab6828fbf22e751053329c425eef2
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/assets/privacy_de.html b/Corona-Warn-App/src/main/assets/privacy_de.html
index d17edfff0e4758ab0ca38941c5fad244524c5d8b..5c74854411dfcaa60bedc13db1ddf09989400b2d 100644
--- a/Corona-Warn-App/src/main/assets/privacy_de.html
+++ b/Corona-Warn-App/src/main/assets/privacy_de.html
@@ -114,7 +114,10 @@
     das System bei der Risiko-Ermittlung, der Warnung anderer und dem Abruf des Testergebnisses
     keine Daten erfasst, die es dem RKI oder anderen Nutzern
     ermöglichen, auf Ihre Identität, Ihren Namen, Ihren Standort oder andere
-    persönliche Details zu schließen. Die App verzichtet daher auch grundsätzlich auf
+    persönliche Details zu schließen.
+</p>
+<p>
+    Die App verzichtet daher auch grundsätzlich auf
     jegliche Auswertung Ihres Nutzungsverhaltens durch Analyse-Tools. Nur wenn Sie ausdrücklich der
     freiwilligen Datenspende zustimmen, werden bestimmte Daten über Ihre Nutzung der App an das RKI
     übermittelt (siehe hierzu Punkt 5 e.).
@@ -381,11 +384,13 @@
     Ihr Smartphone erzeugt hierbei eine eindeutige Kennung und sendet diese an den Anbieter Ihres
     Betriebssystems (wenn Sie ein Android-Smartphone verwenden, werden Daten an Google übermittelt;
     wenn Sie ein iPhone verwenden, werden Daten an Apple übermittelt). Die Kennung enthält
-    Informationen über die Version Ihres Smartphones und die Version der App. Weitere Angaben aus
-    der App, z.B. Begegnungsdaten, erhält der Anbieter Ihres Betriebssystems nicht. Die Anbieter des
-    Betriebssystems nutzen die Kennung, um die Echtheit Ihrer App gegenüber dem RKI zu bestätigen.
-    Die Nutzung der Funktion zur Bestätigung der Echtheit ist freiwillig. Wenn Sie mit der
-    Bestätigung der Echtheit Ihrer App nicht einverstanden sind, kann es jedoch sein, dass Ihnen
+    Informationen über die Version Ihres Smartphones und die Version der App. Möglicherweise kann
+    der Anbieter Ihres Betriebssystems anhand der Kennung auf Ihre Identität schließen und
+    nachvollziehen, dass die Echtheitsprüfung Ihres Smartphones stattgefunden hat. Weitere Angaben
+    aus der App, z.B. Begegnungsdaten, erhält der Anbieter Ihres Betriebssystems nicht. Die Anbieter
+    des Betriebssystems nutzen die Kennung, um die Echtheit Ihrer App gegenüber dem RKI zu
+    bestätigen. Die Nutzung der Funktion zur Bestätigung der Echtheit ist freiwillig. Wenn Sie mit
+    der Bestätigung der Echtheit Ihrer App nicht einverstanden sind, kann es jedoch sein, dass Ihnen
     andere Funktionen der App nicht zur Verfügung stehen.
 </p>
 <h1>
@@ -674,6 +679,12 @@
     Befragungen teilnehmen, deren App ordnungsgemäß funktioniert. Auf diese Weise wird
     sichergestellt, dass die Statistiken und Befragungsergebnisse nicht verfälscht werden.
 </p>
+<p>
+    Bitte beachten Sie, dass der Anbieter Ihres Betriebssystems möglicherweise nachvollziehen kann,
+    dass die Echtheitsprüfung Ihres Smartphones stattgefunden hat und dadurch auf Ihre Identität
+    schließen kann. Weiteren Angaben über Ihre Nutzung der Corona-Warn-App erhält der Anbieter Ihres
+    Betriebssystems jedoch nicht.
+</p>
 <h1>
     7. Wie funktioniert das länderübergreifende Warnsystem?
 </h1>
@@ -905,17 +916,17 @@
     Geschäftsreise) abgerufen werden.
 </p>
 <p>
-    Zudem kann es Rahmen der Bestätigung der Echtheit Ihrer App zu einer Übermittlung von Daten in
-    ein Land außerhalb der EU kommen. Die von Ihrem Smartphone erzeugte Kennung, die Informationen
-    über die Version Ihres Smartphones und der App enthält, wird einmalig an den
+    Zudem kann es im Rahmen der Bestätigung der Echtheit Ihrer App zu einer Übermittlung von Daten
+    in ein Land außerhalb der EU kommen. Die von Ihrem Smartphone erzeugte Kennung, die
+    Informationen über die Version Ihres Smartphones und der App enthält, wird an den
     Betriebssystemanbieter Ihres Smartphones (Apple oder Google) übermittelt. Dabei kann es auch zu
-    einer Datenübermittlung in die USA kommen. Dort besteht kein dem europäischen Recht
-    entsprechendes angemessenes Datenschutzniveau und Ihre europäischen Datenschutzrechte können
-    eventuell nicht durchgesetzt werden. Insbesondere besteht die Möglichkeit, dass
-    US-Sicherheitsbehörden auf die übermittelten Daten beim Betriebssystemanbieter zugreifen und
-    diese auswerten, beispielsweise indem sie Daten mit anderen Informationen verknüpfen. Dies
-    betrifft jedoch nur die übermittelte Kennung. Weitere Angaben aus der App, beispielsweise
-    Begegnungsdaten, sind davon nicht erfasst.
+    einer Datenübermittlung in Drittländer, insbesondere in die USA, 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 auf die übermittelten Daten beim
+    Betriebssystemanbieter zugreifen und diese auswerten, beispielsweise indem sie Daten mit anderen
+    Informationen verknüpfen. Dies betrifft jedoch nur die übermittelte Kennung. Weitere Angaben aus
+    der App, beispielsweise Begegnungsdaten, sind davon nicht erfasst.
 </p>
 <p>
     Im Ãœbrigen werden die von der App
@@ -1078,5 +1089,5 @@
     datenschutz@rki.de.
 </p>
 <p>
-    Stand: 24.02.2021
+    Stand: 01.03.2021
 </p>
diff --git a/Corona-Warn-App/src/main/assets/privacy_en.html b/Corona-Warn-App/src/main/assets/privacy_en.html
index 089c8366c71b139592c7fd9f4a875edba5d96670..379e081aabfe86cd3b2b0672daa6c3597c40ddbf 100644
--- a/Corona-Warn-App/src/main/assets/privacy_en.html
+++ b/Corona-Warn-App/src/main/assets/privacy_en.html
@@ -276,7 +276,7 @@
     tracing purposes, and how you can provide it.
 </p>
 <h2>
-    e. Share Data
+    e. Data sharing
 </h2>
 <p>
     If you enable the data sharing feature, the app will transmit various data about your use of
@@ -370,7 +370,9 @@
     system. Your smartphone generates a unique identifier and sends it to your operating system
     provider (if you use an Android smartphone, data is transmitted to Google; if you use an iPhone,
     data is transmitted to Apple). The identifier contains information about the version of your
-    smartphone and the version of the app. Your operating system provider does not receive any other
+    smartphone and the version of the app. It is possible for your operating system provider to
+    infer your identity from the identifier and learn that your smartphone has been authenticated.
+    Your operating system provider does not receive any other
     information, such as exposure data, from the app. Your operating system provider will use the
     identifier to confirm the authenticity of your app to the RKI. Using the feature for confirming
     the authenticity of your app is voluntary. However, if you do not agree to having the
@@ -598,7 +600,7 @@
     the risk of causing undetected infections.
 </p>
 <h2>
-    f. Share Data
+    f. Data sharing
 </h2>
 <p>
     Share Data is an additional feature of the app. The usage data and other voluntary
@@ -651,9 +653,14 @@
 </h2>
 <p>
     A feature of your smartphone’s operating system is used to confirm the authenticity of your app.
-    This ensures that only app users whose app is functioning properly can donate their data or
+    This ensures that only app users whose app is functioning properly can share their data or
     participate in surveys. This prevents the statistics and survey results from being distorted.
 </p>
+<p>
+    Please note that your operating system provider may be able to tell that your smartphone has
+    been authenticated and may therefore be able to infer your identity. However, your operating
+    system provider will not receive any further information about your use of the Corona-Warn-App.
+</p>
 <h1>
     7. How does the transnational warning system work?
 </h1>
@@ -880,23 +887,25 @@
 <p>
     If you activate the warning feature, please note that users can retrieve
     the latest positive lists regardless of where they are (even if they are
-    abroad on holiday or on a business trip, for example). Otherwise, the data
-    transmitted by the app is processed exclusively on servers in Germany or in
-    another country in the EU (or the European Economic Area), which are
-    therefore subject to the strict requirements of the General Data Protection
-    Regulation (GDPR).
+    abroad on holiday or on a business trip, for example).
 </p>
 <p>
     In addition, the confirmation of the authenticity of your app may involve the transfer of data
     to a country outside the EU. The identifier generated by your smartphone, which contains
-    information about the version of your smartphone and the app, will be transmitted once to the
+    information about the version of your smartphone and the app, will be transmitted to the
     provider of your smartphone’s operating system (Apple or Google). This may result in data being
-    transferred to the US. There, the level of data protection is not considered adequate under
-    European law and it may not be possible to enforce your European data protection rights. In
-    particular, there is a possibility that once the transmitted data reaches the operating system
-    provider, it may be accessed and analysed by US security authorities, for example by linking the
-    data with other information. However, this only concerns the submitted identifier. It does not
-    concern other information from the app, such as exposure data.
+    transferred to third countries, in particular the US. There, the level of data protection may
+    not be considered equivalent under European law and it may not be possible to enforce your
+    European data protection rights. In particular, there is a possibility that once the transmitted
+    data reaches the operating system provider, it may be accessed and analysed by security
+    authorities in the third country, for example by linking the data with other information.
+    However, this only concerns the submitted identifier. It does not concern other information from
+    the app, such as exposure data.
+</p>
+<p>
+    Otherwise, the data transmitted by the app is processed exclusively on servers in Germany or in
+    another country in the EU (or the European Economic Area), which are therefore subject to the
+    strict requirements of the General Data Protection Regulation (GDPR).
 </p>
 <h1>
     12. How can you withdraw your consent?
@@ -1040,5 +1049,5 @@
     13353 Berlin, or by emailing datenschutz@rki.de.
 </p>
 <p>
-    Last amended: 24 February 2021
+    Last amended: 01 March 2021
 </p>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/assets/privacy_tr.html b/Corona-Warn-App/src/main/assets/privacy_tr.html
index e9a984ffa8eb406001ae62fe00327bd2bc7cd828..31ca70cf54ecdba84986828ae501ae4a07808ff6 100644
--- a/Corona-Warn-App/src/main/assets/privacy_tr.html
+++ b/Corona-Warn-App/src/main/assets/privacy_tr.html
@@ -367,12 +367,13 @@ Temas güncesinin kullanılması isteğe bağlıdır. Veri girişlerinin temas g
     yararlanılır. Bu bağlamda akıllı telefonunuz tarafından benzersiz bir kimlik kodu oluşturulur ve
     bunu işletim sisteminizin sağlayıcısına gönderir (bir Android akıllı telefon kullanıyorsanız, bu
     veriler Google’a, iPhone kullanıyorsanız Apple’a aktarılır). Bu kimlik kodu, akıllı
-    telefonunuzun sürümü ve Uygulama hakkında veriler içerir. Uygulamadan karşılaşma verileri gibi
-    başka bilgiler İşletim sisteminizin sağlayıcısına gönderilmez. İşletim sisteminin sağlayıcısı,
-    Uygulamanızın orijinal olduğunu RKI’ye doğrulamak için bu kimlik kodunu kullanır.
-    Orijinalliğinin doğrulanmasını sağlayan bu işlevin kullanılması isteğe bağlıdır. Ancak
-    Uygulamanızın orijinalliğinin doğrulanmasını kabul etmezseniz, Uygulamanın başka bazı işlevleri
-    sizin için sunulmayabilir.
+    telefonunuzun sürümü ve Uygulama hakkında veriler içerir. İşletim sisteminizin sağlayıcısı,
+    kimlik kodunuz üzerinden kim olduğunuzu ortaya çıkarabilir ve akıllı telefonunuzun orijinallik
+    kontrolünün yapıldığını anlayabilir. Uygulamadan karşılaşma verileri gibi başka bilgiler İşletim
+    sisteminizin sağlayıcısına gönderilmez. İşletim sisteminin sağlayıcısı, Uygulamanızın orijinal
+    olduğunu RKI’ye doğrulamak için bu kimlik kodunu kullanır. Orijinalliğinin doğrulanmasını
+    sağlayan bu işlevin kullanılması isteğe bağlıdır. Ancak Uygulamanızın orijinalliğinin
+    doğrulanmasını kabul etmezseniz, Uygulamanın başka bazı işlevleri sizin için sunulmayabilir.
 </p>
 <h1>
     6. Verileriniz niçin işleniyor?
@@ -651,7 +652,10 @@ Temas güncesinin kullanılması isteğe bağlıdır. Veri girişlerinin temas g
     Uygulamanızın orijinalliğinin doğrulanması için akıllı telefonunuzun işletim sisteminin bir
     işlevi kullanılır. Bu sayede sadece uygulaması düzgün çalışan Uygulama kullanıcılarının veri
     bağışına veya anketlere katılması mümkün kılınır. Böylece istatistiklerin ve anket sonuçlarının
-    tahrif edilmesinin önüne geçilir.
+    tahrif edilmesinin önüne geçilir. Lütfen işletim sisteminizin sağlayıcısının muhtemelen akıllı
+    telefonunuzun orijinallik kontrolünün yapıldığını anlayabileceğini ve bu nedenle kimliğinizi
+    ortaya çıkarabileceğini unutmayın. Ancak, işletim sisteminizin sağlayıcısı Corona-Warn-App
+    kullanımınız hakkında daha fazla bilgi almaz.
 </p>
 <h1>
     7. Sınır ötesi uyarı sistemi nasıl çalışır?
@@ -881,13 +885,13 @@ Temas güncesinin kullanılması isteğe bağlıdır. Veri girişlerinin temas g
     Ayrıca, Uygulamanızın orijinalliğinin doğrulanması kapsamında verilerin AB dışındaki bir ülkeye
     aktarılması söz konusu olabilir. Akıllı telefonunuz tarafından oluşturulan ve akıllı
     telefonunuzun ve Uygulamanın sürümüyle ilgili bilgileri içeren kimlik kodu, akıllı telefonunuzun
-    işletim sisteminin sağlayıcısına (Apple veya Google) bir kez aktarılır. Bu süreçte verilerin
-    ABD’ye aktarılması da söz konusu olabilir. Orada Avrupa hukukuna uygun kişisel verilerin koruma
-    seviyesi bulunmamaktadır ve Avrupa’daki veri koruma haklarınız uygulanmayabilir. Bu bağlamda
-    özellikle ABD güvenlik makamlarının işletim sistemi sağlayıcısına aktarılan bu verilere erişme
-    ve örneğin verileri diğer bilgilerle ilişkilendirerek bunları değerlendirmeye alma olasılığı
-    bulunmaktadır. Ancak bu, yalnızca aktarılan kimlik kodlarını etkiler. Karşılaşma verileri gibi
-    Uygulamadaki diğer veriler bu prosedüre dahil edilmez.
+    işletim sisteminin sağlayıcısına (Apple veya Google) aktarılır. Bu süreçte verilerin üçüncü bir
+    ülkeye, özellikle ABD’ye aktarılması da söz konusu olabilir. Orada Avrupa hukukuna karşılık
+    gelen kişisel verilerin koruma seviyesi bulunmayabilir ve Avrupa’daki veri koruma haklarınız
+    uygulanmayabilir. Bu bağlamda özellikle güvenlik makamlarının işletim sistemi sağlayıcısına
+    aktarılan bu verilere erişme ve örneğin verileri diğer bilgilerle ilişkilendirerek bunları
+    değerlendirmeye alma olasılığı bulunmaktadır. Ancak bu, yalnızca aktarılan kimlik kodlarını
+    etkiler. Karşılaşma verileri gibi Uygulamadaki diğer veriler bu prosedüre dahil edilmez.
 </p>
 <p> Ancak Uygulama tarafından aktarılan veriler, sadece Almanya’daki sunucularda veya
     bir diğer AB (veya Avrupa Ekonomik Alanı) ülkesindeki sunucularda işlenir,
@@ -1038,5 +1042,5 @@ Temas güncesinin kullanılması isteğe bağlıdır. Veri girişlerinin temas g
     veya e-posta yoluyla: datenschutz@rki.de.
 </p>
 <p>
-    Baskı 24.02.2021
+    Baskı 01.03.2021
 </p>
\ No newline at end of file
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 92b10563715bedf2b8562702e87df6219bd57bc7..f797cf5b89cd738c7f47d106b854ef1f2ec08064 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
@@ -92,7 +92,6 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
                 deadmanNotificationScheduler.schedulePeriodic()
             }
             contactDiaryWorkScheduler.schedulePeriodic()
-            dataDonationAnalyticsScheduler.schedulePeriodic()
         }
 
         deviceTimeHandler.launch()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReporter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReporter.kt
index 31913f27d014b3340462b4271e205d07c03b9c90..a831191bb91c4857d39f7876770c8e26219bb3b6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReporter.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReporter.kt
@@ -9,7 +9,7 @@ interface BugReporter {
 }
 
 fun Throwable.reportProblem(tag: String? = null, info: String? = null) {
-    Timber.tag("BugReporter").v(this, "report(tag=$tag, info=$info)")
+    Timber.tag(tag ?: "BugReporter").e(this, info)
 
     if (CWADebug.isAUnitTest) return
     val reporter = AppInjector.component.bugReporter
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt
index d989e8146ceca7b951e43f8b005ad9c3a20e1108..15bbc81bdc3ca0ba7302bdecb7440d01772035d9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt
@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.contactdiary.retention
 import androidx.work.ExistingPeriodicWorkPolicy
 import androidx.work.WorkManager
 import dagger.Reusable
+import timber.log.Timber
 import javax.inject.Inject
 
 @Reusable
@@ -16,6 +17,7 @@ class ContactDiaryWorkScheduler @Inject constructor(
      * Replace with new if older work exists.
      */
     fun schedulePeriodic() {
+        Timber.d("ContactDiaryWorkScheduler schedulePeriodic()")
         // Create unique work and enqueue
         workManager.enqueueUniquePeriodicWork(
             PERIODIC_WORK_NAME,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/OTPAuthorizationResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/OTPAuthorizationResult.kt
index 4cf4427828dafc0c9653f0862e2dc6f2fcb18b31..f99851e7b28f6d8ea18481acdde8f7f5cee9dc32 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/OTPAuthorizationResult.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/OTPAuthorizationResult.kt
@@ -12,5 +12,10 @@ data class OTPAuthorizationResult(
     @SerializedName("authorized")
     val authorized: Boolean,
     @SerializedName("redeemedAt")
-    val redeemedAt: Instant
-)
+    val redeemedAt: Instant,
+    @SerializedName("invalidated")
+    val invalidated: Boolean = false
+) {
+
+    fun toInvalidatedInstance() = copy(invalidated = true)
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/OneTimePassword.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/OneTimePassword.kt
index bdd5fef0303cef83dc74709ae1d5f549c7de593a..8bf382bdc68a73c396037fd39004d87c93451e11 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/OneTimePassword.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/OneTimePassword.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.datadonation
 
 import androidx.annotation.Keep
 import com.google.gson.annotations.SerializedName
+import de.rki.coronawarnapp.server.protocols.internal.ppdd.EdusOtp
 import org.joda.time.Instant
 import java.util.UUID
 
@@ -14,5 +15,10 @@ data class OneTimePassword(
 ) {
 
     @Transient
-    val payloadForRequest = uuid.toString().toByteArray()
+    val edusOneTimePassword: EdusOtp.EDUSOneTimePassword = EdusOtp.EDUSOneTimePassword.newBuilder()
+        .setOtp(uuid.toString())
+        .build()
+
+    @Transient
+    val payloadForRequest: ByteArray = edusOneTimePassword.toByteArray()
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/Analytics.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/Analytics.kt
index 151e182bff636c866c915766c776e9f001bc7380..dab8333ca7fc18e204efa713891a1fad97f1b70f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/Analytics.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/Analytics.kt
@@ -3,18 +3,22 @@ package de.rki.coronawarnapp.datadonation.analytics
 import androidx.annotation.VisibleForTesting
 import de.rki.coronawarnapp.appconfig.AnalyticsConfig
 import de.rki.coronawarnapp.appconfig.AppConfigProvider
+import de.rki.coronawarnapp.bugreporting.reportProblem
 import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule
 import de.rki.coronawarnapp.datadonation.analytics.server.DataDonationAnalyticsServer
 import de.rki.coronawarnapp.datadonation.analytics.storage.AnalyticsSettings
 import de.rki.coronawarnapp.datadonation.analytics.storage.LastAnalyticsSubmissionLogger
 import de.rki.coronawarnapp.datadonation.safetynet.DeviceAttestation
+import de.rki.coronawarnapp.datadonation.safetynet.SafetyNetException
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaDataRequestAndroid
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.util.TimeStamper
+import kotlinx.coroutines.TimeoutCancellationException
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.withTimeout
 import org.joda.time.Hours
 import org.joda.time.Instant
 import timber.log.Timber
@@ -35,57 +39,69 @@ class Analytics @Inject constructor(
 ) {
     private val submissionLockoutMutex = Mutex()
 
-    private suspend fun trySubmission(analyticsConfig: AnalyticsConfig, ppaData: PpaData.PPADataAndroid): Boolean {
-        try {
+    private suspend fun trySubmission(analyticsConfig: AnalyticsConfig, ppaData: PpaData.PPADataAndroid): Result {
+        return try {
             val ppaAttestationRequest = PPADeviceAttestationRequest(
                 ppaData = ppaData
             )
 
-            Timber.d("Starting safety net device attestation")
+            Timber.tag(TAG).d("Starting safety net device attestation")
 
             val attestation = deviceAttestation.attest(ppaAttestationRequest)
 
             attestation.requirePass(analyticsConfig.safetyNetRequirements)
 
-            Timber.d("Safety net attestation passed")
+            Timber.tag(TAG).d("Safety net attestation passed")
 
             val ppaContainer = PpaDataRequestAndroid.PPADataRequestAndroid.newBuilder()
                 .setAuthentication(attestation.accessControlProtoBuf)
                 .setPayload(ppaData)
                 .build()
 
-            Timber.d("Starting analytics upload")
+            Timber.tag(TAG).d("Starting analytics upload")
 
             dataDonationAnalyticsServer.uploadAnalyticsData(ppaContainer)
 
-            Timber.d("Analytics upload finished")
+            Timber.tag(TAG).d("Analytics upload finished")
 
-            return true
+            Result(successful = true)
         } catch (err: Exception) {
-            Timber.e(err, "Error during analytics submission")
-            return false
+            err.reportProblem(tag = TAG, info = "An error occurred during analytics submission")
+            val retry = err is SafetyNetException && err.type == SafetyNetException.Type.ATTESTATION_REQUEST_FAILED
+            Result(successful = false, shouldRetry = retry)
         }
     }
 
     suspend fun collectContributions(ppaDataBuilder: PpaData.PPADataAndroid.Builder): List<DonorModule.Contribution> {
         val request: DonorModule.Request = object : DonorModule.Request {}
 
-        val contributions = donorModules.map {
-            Timber.d("Beginning donation for module: %s", it::class.simpleName)
-            it.beginDonation(request)
+        val contributions = donorModules.mapNotNull {
+            val moduleName = it::class.simpleName
+            Timber.tag(TAG).d("Beginning donation for module: %s", moduleName)
+            try {
+                it.beginDonation(request)
+            } catch (e: Exception) {
+                e.reportProblem(TAG, "beginDonation($request): $moduleName failed")
+                null
+            }
         }
 
         contributions.forEach {
-            Timber.d("Injecting contribution: %s", it::class.simpleName)
-            it.injectData(ppaDataBuilder)
+            val moduleName = it::class.simpleName
+            Timber.tag(TAG).d("Injecting contribution: %s", moduleName)
+            try {
+                it.injectData(ppaDataBuilder)
+            } catch (e: Exception) {
+                e.reportProblem(TAG, "injectData($ppaDataBuilder): $moduleName failed")
+            }
         }
 
         return contributions
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    suspend fun submitAnalyticsData(analyticsConfig: AnalyticsConfig) {
-        Timber.d("Starting analytics submission")
+    suspend fun submitAnalyticsData(analyticsConfig: AnalyticsConfig): Result {
+        Timber.tag(TAG).d("Starting analytics submission")
 
         val ppaDataBuilder = PpaData.PPADataAndroid.newBuilder()
 
@@ -93,14 +109,28 @@ class Analytics @Inject constructor(
 
         val analyticsProto = ppaDataBuilder.build()
 
-        val success = trySubmission(analyticsConfig, analyticsProto)
+        val result = try {
+            // 6min, if attestation and/or submission takes longer than that,
+            // then we want to give modules still time to cleanup and get into a consistent state.
+            withTimeout(360_000) {
+                trySubmission(analyticsConfig, analyticsProto)
+            }
+        } catch (e: TimeoutCancellationException) {
+            Timber.tag(TAG).e(e, "trySubmission() timed out after 360s.")
+            Result(successful = false, shouldRetry = true)
+        }
 
         contributions.forEach {
-            Timber.d("Finishing contribution: %s", it::class.simpleName)
-            it.finishDonation(success)
+            val moduleName = it::class.simpleName
+            Timber.tag(TAG).d("Finishing contribution($result) for %s", moduleName)
+            try {
+                it.finishDonation(result.successful)
+            } catch (e: Exception) {
+                e.reportProblem(TAG, "finishDonation($result): $moduleName failed")
+            }
         }
 
-        if (success) {
+        if (result.successful) {
             settings.lastSubmittedTimestamp.update {
                 timeStamper.nowUTC
             }
@@ -108,11 +138,12 @@ class Analytics @Inject constructor(
             logger.storeAnalyticsData(analyticsProto)
         }
 
-        Timber.d("Finished analytics submission success=%s", success)
+        Timber.tag(TAG).d("Finished analytics submission result=%s", result)
+        return result
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    suspend fun stopDueToNoAnalyticsConfig(analyticsConfig: AnalyticsConfig): Boolean {
+    fun stopDueToNoAnalyticsConfig(analyticsConfig: AnalyticsConfig): Boolean {
         return !analyticsConfig.analyticsEnabled
     }
 
@@ -122,7 +153,7 @@ class Analytics @Inject constructor(
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    suspend fun stopDueToProbabilityToSubmit(analyticsConfig: AnalyticsConfig): Boolean {
+    fun stopDueToProbabilityToSubmit(analyticsConfig: AnalyticsConfig): Boolean {
         val submitRoll = Random.nextDouble(0.0, 1.0)
         return submitRoll > analyticsConfig.probabilityToSubmit
     }
@@ -137,40 +168,39 @@ class Analytics @Inject constructor(
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     fun stopDueToTimeSinceOnboarding(): Boolean {
         val onboarding = LocalData.onboardingCompletedTimestamp()?.let { Instant.ofEpochMilli(it) } ?: return true
-        return onboarding.plus(Hours.hours(ONBOARDING_DELAY_HOURS).toStandardDuration())
-            .isAfter(timeStamper.nowUTC)
+        return onboarding.plus(Hours.hours(ONBOARDING_DELAY_HOURS).toStandardDuration()).isAfter(timeStamper.nowUTC)
     }
 
-    suspend fun submitIfWanted() = submissionLockoutMutex.withLock {
-        Timber.d("Checking analytics conditions")
+    suspend fun submitIfWanted(): Result = submissionLockoutMutex.withLock {
+        Timber.tag(TAG).d("Checking analytics conditions")
         val analyticsConfig: AnalyticsConfig = appConfigProvider.getAppConfig().analytics
 
         if (stopDueToNoAnalyticsConfig(analyticsConfig)) {
-            Timber.w("Aborting Analytics submission due to noAnalyticsConfig")
-            return
+            Timber.tag(TAG).w("Aborting Analytics submission due to noAnalyticsConfig")
+            return@withLock Result(successful = false)
         }
 
         if (stopDueToNoUserConsent()) {
-            Timber.w("Aborting Analytics submission due to noUserConsent")
-            return
+            Timber.tag(TAG).w("Aborting Analytics submission due to noUserConsent")
+            return@withLock Result(successful = false)
         }
 
         if (stopDueToProbabilityToSubmit(analyticsConfig)) {
-            Timber.w("Aborting Analytics submission due to probabilityToSubmit")
-            return
+            Timber.tag(TAG).w("Aborting Analytics submission due to probabilityToSubmit")
+            return@withLock Result(successful = false)
         }
 
         if (stopDueToLastSubmittedTimestamp()) {
-            Timber.w("Aborting Analytics submission due to lastSubmittedTimestamp")
-            return
+            Timber.tag(TAG).w("Aborting Analytics submission due to lastSubmittedTimestamp")
+            return@withLock Result(successful = false)
         }
 
         if (stopDueToTimeSinceOnboarding()) {
-            Timber.w("Aborting Analytics submission due to timeSinceOnboarding")
-            return
+            Timber.tag(TAG).w("Aborting Analytics submission due to timeSinceOnboarding")
+            return@withLock Result(successful = false)
         }
 
-        submitAnalyticsData(analyticsConfig)
+        return@withLock submitAnalyticsData(analyticsConfig)
     }
 
     private suspend fun deleteAllData() = submissionLockoutMutex.withLock {
@@ -192,7 +222,13 @@ class Analytics @Inject constructor(
     fun isAnalyticsEnabledFlow(): Flow<Boolean> =
         settings.analyticsEnabled.flow
 
+    data class Result(
+        val successful: Boolean,
+        val shouldRetry: Boolean = false
+    )
+
     companion object {
+        private val TAG = Analytics::class.java.simpleName
         private const val LAST_SUBMISSION_MIN_AGE_HOURS = 23
         private const val ONBOARDING_DELAY_HOURS = 24
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposureriskmetadata/ExposureRiskMetadataDonor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposureriskmetadata/ExposureRiskMetadataDonor.kt
index f37919da329465cc397752371df1aa7eb0719ee3..47b17821aaff71159b1d46c699fe23f0b25a7ac3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposureriskmetadata/ExposureRiskMetadataDonor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposureriskmetadata/ExposureRiskMetadataDonor.kt
@@ -7,6 +7,7 @@ import de.rki.coronawarnapp.risk.RiskState
 import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.risk.tryLatestResultsWithDefaults
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
 import kotlinx.coroutines.flow.first
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -27,13 +28,14 @@ class ExposureRiskMetadataDonor @Inject constructor(
             .lastCalculated
 
         val riskLevelForMetadata = lastRiskResult.toMetadataRiskLevel()
+        val mostRecentDateAtRiskLevel = lastRiskResult.lastRiskEncounterAt?.seconds ?: -1
 
         val newMetadata = PpaData.ExposureRiskMetadata.newBuilder()
             .setRiskLevel(riskLevelForMetadata)
             .setRiskLevelChangedComparedToPreviousSubmission(previousMetadata?.riskLevel != riskLevelForMetadata)
-            .setMostRecentDateAtRiskLevel(lastRiskResult.calculatedAt.millis)
+            .setMostRecentDateAtRiskLevel(mostRecentDateAtRiskLevel)
             .setDateChangedComparedToPreviousSubmission(
-                previousMetadata?.mostRecentDateAtRiskLevel != lastRiskResult.calculatedAt.millis
+                previousMetadata?.mostRecentDateAtRiskLevel != mostRecentDateAtRiskLevel
             )
             .build()
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/server/DataDonationAnalyticsApiV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/server/DataDonationAnalyticsApiV1.kt
index d0b2ac212bcabccd5fd19da54abc13ac2252f771..7343e9808f039422bebdc8f4a13e5eec3760bb72 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/server/DataDonationAnalyticsApiV1.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/server/DataDonationAnalyticsApiV1.kt
@@ -9,7 +9,7 @@ import retrofit2.http.POST
 interface DataDonationAnalyticsApiV1 {
 
     data class DataDonationAnalyticsResponse(
-        @SerializedName("errorState") val errorState: String?
+        @SerializedName("errorCode") val errorCode: String?
     )
 
     @POST("/version/v1/android/dat")
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/server/DataDonationAnalyticsServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/server/DataDonationAnalyticsServer.kt
index ae2269d961e4fd3105a0689b7a773f8ca290d0c4..ef23e998bfcf5e06b624128737f15893e5918c87 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/server/DataDonationAnalyticsServer.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/server/DataDonationAnalyticsServer.kt
@@ -22,7 +22,7 @@ class DataDonationAnalyticsServer @Inject constructor(
         return when (code) {
             204 -> Timber.d("Analytics upload completed successfully")
             400, 401, 403 -> {
-                val explanation = response.body()?.errorState ?: "Unknown clientside error"
+                val explanation = response.body()?.errorCode ?: "Unknown clientside error"
                 throw AnalyticsException(message = explanation).also {
                     Timber.w(it, "Analytics upload failed with 40X")
                 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/AnalyticsSettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/AnalyticsSettings.kt
index 7edd80d04f8fafeaa6235afa576bf3f438ce5a73..9c240c16e7269c78546b020de46897865fa7d329 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/AnalyticsSettings.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/AnalyticsSettings.kt
@@ -4,6 +4,7 @@ import android.content.Context
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData.ExposureRiskMetadata
 import de.rki.coronawarnapp.util.di.AppContext
+import de.rki.coronawarnapp.util.preferences.clearAndNotify
 import de.rki.coronawarnapp.util.preferences.createFlowPreference
 import okio.ByteString.Companion.decodeBase64
 import okio.ByteString.Companion.toByteString
@@ -89,6 +90,8 @@ class AnalyticsSettings @Inject constructor(
         defaultValue = false
     )
 
+    fun clear() = prefs.clearAndNotify()
+
     companion object {
         private const val PREVIOUS_EXPOSURE_RISK_METADATA = "exposurerisk.metadata.previous"
         private const val PKEY_USERINFO_AGEGROUP = "userinfo.agegroup"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsPeriodicWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsPeriodicWorker.kt
index c964f618cc1c50400fa516c0a7a6abc646df42c6..0920f50625cd7cc07b9d2262d701b3e7a82b5716 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsPeriodicWorker.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsPeriodicWorker.kt
@@ -20,8 +20,7 @@ class DataDonationAnalyticsPeriodicWorker @AssistedInject constructor(
     @Assisted context: Context,
     @Assisted workerParams: WorkerParameters,
     private val analytics: Analytics
-) :
-    CoroutineWorker(context, workerParams) {
+) : CoroutineWorker(context, workerParams) {
 
     override suspend fun doWork(): Result {
         Timber.tag(TAG).d("Background job started. Run attempt: $runAttemptCount")
@@ -31,15 +30,19 @@ class DataDonationAnalyticsPeriodicWorker @AssistedInject constructor(
 
             return Result.failure()
         }
-        var result = Result.success()
-        try {
-            analytics.submitIfWanted()
+
+        return try {
+            val analyticsResult = analytics.submitIfWanted()
+            Timber.tag(TAG).d("submitIfWanted() finished: %s", analyticsResult)
+            when {
+                analyticsResult.successful -> Result.success()
+                analyticsResult.shouldRetry -> Result.retry()
+                else -> Result.failure()
+            }
         } catch (e: Exception) {
-            Timber.tag(TAG).d(e)
-            result = Result.retry()
+            Timber.tag(TAG).w(e, "submitIfWanted() failed unexpectedly")
+            Result.failure()
         }
-
-        return result
     }
 
     @AssistedFactory
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsScheduler.kt
index 7483d2c46e6c76ca358ca12932b834a45aa33f2a..d4442e6890d606c91786ee01a9673fff21a141a1 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsScheduler.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsScheduler.kt
@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.datadonation.analytics.worker
 import androidx.work.ExistingPeriodicWorkPolicy
 import androidx.work.WorkManager
 import dagger.Reusable
+import timber.log.Timber
 import javax.inject.Inject
 
 /**
@@ -22,12 +23,14 @@ class DataDonationAnalyticsScheduler @Inject constructor(
      * Enqueue background analytics submission periodic work
      */
     fun schedulePeriodic() {
-        val additionalDelay = timeCalculation.getDelay()
+        val initialDelay = timeCalculation.getDelay()
+        // TODO Replace with logic that checks if already scheduled workManager. workManager.getWorkInfosByTag()
+        Timber.d("schedulePeriodic() initialDelay(if not yet scheduled)=%s", initialDelay)
         // Create unique work and enqueue
         workManager.enqueueUniquePeriodicWork(
             PERIODIC_WORK_NAME,
             ExistingPeriodicWorkPolicy.KEEP,
-            workBuilder.buildPeriodicWork(additionalDelay)
+            workBuilder.buildPeriodicWork(initialDelay)
         )
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsWorkBuilder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsWorkBuilder.kt
index 5b5e92550c4c675ba438037de8f4023da37918e0..4360da23c6755b223a8891b5fdc9faa809537839 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsWorkBuilder.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsWorkBuilder.kt
@@ -1,6 +1,8 @@
 package de.rki.coronawarnapp.datadonation.analytics.worker
 
 import androidx.work.BackoffPolicy
+import androidx.work.Constraints
+import androidx.work.NetworkType
 import androidx.work.PeriodicWorkRequest
 import androidx.work.PeriodicWorkRequestBuilder
 import dagger.Reusable
@@ -12,13 +14,13 @@ import javax.inject.Inject
 
 @Reusable
 class DataDonationAnalyticsWorkBuilder @Inject constructor() {
-    fun buildPeriodicWork(additionalDelay: Duration): PeriodicWorkRequest =
+    fun buildPeriodicWork(initialDelay: Duration): PeriodicWorkRequest =
         PeriodicWorkRequestBuilder<DataDonationAnalyticsPeriodicWorker>(
             DateTimeConstants.HOURS_PER_DAY.toLong(),
             TimeUnit.HOURS
         )
             .setInitialDelay(
-                DateTimeConstants.HOURS_PER_DAY.toLong() + additionalDelay.standardHours,
+                initialDelay.standardHours,
                 TimeUnit.HOURS
             )
             .setBackoffCriteria(
@@ -26,5 +28,11 @@ class DataDonationAnalyticsWorkBuilder @Inject constructor() {
                 BackgroundConstants.BACKOFF_INITIAL_DELAY,
                 TimeUnit.MINUTES
             )
+            .setConstraints(buildConstraints())
+            .build()
+
+    private fun buildConstraints() =
+        Constraints.Builder()
+            .setRequiredNetworkType(NetworkType.CONNECTED)
             .build()
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/CWASafetyNet.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/CWASafetyNet.kt
index bd5e04ec1aefc5f52b1b64856bdf00029aa0d2b5..e29f43cc5c8ea7baca9a7cd4b3f4a409ce4e2b83 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/CWASafetyNet.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/CWASafetyNet.kt
@@ -6,11 +6,14 @@ import de.rki.coronawarnapp.appconfig.AppConfigProvider
 import de.rki.coronawarnapp.appconfig.ConfigData
 import de.rki.coronawarnapp.datadonation.safetynet.SafetyNetException.Type
 import de.rki.coronawarnapp.main.CWASettings
-import de.rki.coronawarnapp.util.HashExtensions
+import de.rki.coronawarnapp.storage.TestSettings
+import de.rki.coronawarnapp.util.CWADebug
 import de.rki.coronawarnapp.util.HashExtensions.toSHA256
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.di.AppContext
 import de.rki.coronawarnapp.util.gplay.GoogleApiVersion
+import okio.ByteString
+import okio.ByteString.Companion.decodeHex
 import okio.ByteString.Companion.toByteString
 import org.joda.time.Duration
 import org.joda.time.Instant
@@ -27,7 +30,8 @@ class CWASafetyNet @Inject constructor(
     private val appConfigProvider: AppConfigProvider,
     private val googleApiVersion: GoogleApiVersion,
     private val cwaSettings: CWASettings,
-    private val timeStamper: TimeStamper
+    private val timeStamper: TimeStamper,
+    private val testSettings: TestSettings
 ) : DeviceAttestation {
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
@@ -36,9 +40,10 @@ class CWASafetyNet @Inject constructor(
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    fun calculateNonce(salt: ByteArray, payload: ByteArray): String {
+    fun calculateNonce(salt: ByteArray, payload: ByteArray): ByteString {
         val concat = salt + payload
-        return concat.toSHA256(format = HashExtensions.Format.BASE64)
+        // Default format is hex.
+        return concat.toSHA256().decodeHex()
     }
 
     override suspend fun attest(request: DeviceAttestation.Request): DeviceAttestation.Result {
@@ -55,10 +60,16 @@ class CWASafetyNet @Inject constructor(
             }
         }
 
+        val skip24hCheck = CWADebug.isDeviceForTestersBuild && testSettings.skipSafetyNetTimeCheck.value
+        val nowUTC = timeStamper.nowUTC
         val firstReliableTimeStamp = cwaSettings.firstReliableDeviceTime
+        val timeSinceOnboarding = Duration(firstReliableTimeStamp, nowUTC)
+        Timber.d("firstReliableTimeStamp=%s, now=%s", firstReliableTimeStamp, nowUTC)
+        Timber.d("skip24hCheck=%b, timeSinceOnboarding=%dh", skip24hCheck, timeSinceOnboarding.standardHours)
+
         if (firstReliableTimeStamp == Instant.EPOCH) {
             throw SafetyNetException(Type.TIME_SINCE_ONBOARDING_UNVERIFIED, "No first reliable timestamp available")
-        } else if (Duration(firstReliableTimeStamp, timeStamper.nowUTC) < Duration.standardHours(24)) {
+        } else if (!skip24hCheck && timeSinceOnboarding < Duration.standardHours(24)) {
             throw SafetyNetException(Type.TIME_SINCE_ONBOARDING_UNVERIFIED, "Time since first reliable timestamp <24h")
         }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetClientWrapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetClientWrapper.kt
index 6a36b54dc86562968267dda427fcb2bc1950ea9a..f1b732d2640e529df3d79d7667492bf8c58081a9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetClientWrapper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetClientWrapper.kt
@@ -10,13 +10,14 @@ import dagger.Reusable
 import de.rki.coronawarnapp.datadonation.safetynet.SafetyNetException.Type
 import de.rki.coronawarnapp.environment.EnvironmentSetup
 import kotlinx.coroutines.TimeoutCancellationException
+import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlinx.coroutines.withTimeout
+import okio.ByteString
 import okio.ByteString.Companion.decodeBase64
 import timber.log.Timber
 import javax.inject.Inject
 import kotlin.coroutines.resume
 import kotlin.coroutines.resumeWithException
-import kotlin.coroutines.suspendCoroutine
 
 @Reusable
 class SafetyNetClientWrapper @Inject constructor(
@@ -26,9 +27,9 @@ class SafetyNetClientWrapper @Inject constructor(
 
     suspend fun attest(nonce: ByteArray): Report {
         val response = try {
-            withTimeout(30 * 1000L) { callClient(nonce) }
+            withTimeout(180_000) { callClient(nonce) }
         } catch (e: TimeoutCancellationException) {
-            throw SafetyNetException(Type.ATTESTATION_FAILED, "Attestation timeout.", e)
+            throw SafetyNetException(Type.ATTESTATION_REQUEST_FAILED, "Attestation timeout (us).", e)
         }
 
         val jwsResult = response.jwsResult ?: throw SafetyNetException(
@@ -72,22 +73,46 @@ class SafetyNetClientWrapper @Inject constructor(
         return JsonParser.parseString(rawJson).asJsonObject
     }
 
-    private suspend fun callClient(nonce: ByteArray): SafetyNetApi.AttestationResponse = suspendCoroutine { cont ->
-        safetyNetClient.attest(nonce, environmentSetup.safetyNetApiKey)
-            .addOnSuccessListener {
-                Timber.tag(TAG).v("Attestation finished with %s", it)
-                cont.resume(it)
-            }
-            .addOnFailureListener {
-                Timber.tag(TAG).w(it, "Attestation failed.")
-                val wrappedError = if (it is ApiException && it.statusCode == CommonStatusCodes.NETWORK_ERROR) {
-                    SafetyNetException(Type.ATTESTATION_REQUEST_FAILED, "Network error", it)
-                } else {
-                    SafetyNetException(Type.ATTESTATION_FAILED, "SafetyNet client returned an error.", it)
+    private suspend fun callClient(nonce: ByteArray): SafetyNetApi.AttestationResponse =
+        suspendCancellableCoroutine { cont ->
+            safetyNetClient.attest(nonce, environmentSetup.safetyNetApiKey)
+                .addOnSuccessListener {
+                    Timber.tag(TAG).v("Attestation finished with %s", it)
+                    cont.resume(it)
                 }
-                cont.resumeWithException(wrappedError)
-            }
-    }
+                .addOnFailureListener {
+                    Timber.tag(TAG).w(it, "Attestation failed.")
+                    val defaultError =
+                        SafetyNetException(Type.ATTESTATION_FAILED, "SafetyNet client returned an error.", it)
+
+                    if (it !is ApiException) {
+                        cont.resumeWithException(defaultError)
+                        return@addOnFailureListener
+                    }
+
+                    val apiError = when (it.statusCode) {
+                        CommonStatusCodes.TIMEOUT -> SafetyNetException(
+                            Type.ATTESTATION_REQUEST_FAILED,
+                            "Timeout (them)",
+                            it
+                        )
+                        // com.google.android.gms.common.api.ApiException: 20:
+                        // The connection to Google Play services was lost due to service disconnection.
+                        // Last reason for disconnect: Timing out service connection.
+                        CommonStatusCodes.CONNECTION_SUSPENDED_DURING_CALL,
+                        CommonStatusCodes.RECONNECTION_TIMED_OUT_DURING_UPDATE,
+                        CommonStatusCodes.RECONNECTION_TIMED_OUT,
+                        CommonStatusCodes.NETWORK_ERROR -> SafetyNetException(
+                            Type.ATTESTATION_REQUEST_FAILED,
+                            "Network error (${it.statusCode})",
+                            it
+                        )
+                        else -> defaultError
+                    }
+
+                    cont.resumeWithException(apiError)
+                }
+        }
 
     data class Report(
         val jwsResult: String,
@@ -95,7 +120,7 @@ class SafetyNetClientWrapper @Inject constructor(
         val body: JsonObject,
         val signature: ByteArray
     ) {
-        val nonce: String? = body.get("nonce")?.asString?.decodeBase64()?.utf8()
+        val nonce: ByteString? = body.get("nonce")?.asString?.decodeBase64()
 
         val apkPackageName: String? = body.get("apkPackageName")?.asString
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetException.kt
index 083c7626612af2bfaeac77bc082319b69cf12680..f75598ff0c050fd6a32ce4c51eca99aef13ed7a8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetException.kt
@@ -1,12 +1,38 @@
 package de.rki.coronawarnapp.datadonation.safetynet
 
+import android.content.Context
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.util.HasHumanReadableError
+import de.rki.coronawarnapp.util.HumanReadableError
 
 class SafetyNetException constructor(
     val type: Type,
     message: String? = null,
     cause: Throwable? = null
-) : Exception("$type: $message", cause) {
+) : Exception("$type: $message", cause), HasHumanReadableError {
+
+    override fun toHumanReadableError(context: Context): HumanReadableError {
+        val messageRes = when (type) {
+            Type.APK_PACKAGE_NAME_MISMATCH,
+            Type.ATTESTATION_FAILED,
+            Type.ATTESTATION_REQUEST_FAILED,
+            Type.DEVICE_TIME_UNVERIFIED,
+            Type.NONCE_MISMATCH ->
+                R.string.datadonation_details_survey_consent_error_TRY_AGAIN_LATER
+            Type.BASIC_INTEGRITY_REQUIRED,
+            Type.CTS_PROFILE_MATCH_REQUIRED,
+            Type.EVALUATION_TYPE_BASIC_REQUIRED,
+            Type.EVALUATION_TYPE_HARDWARE_BACKED_REQUIRED ->
+                R.string.datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED
+            Type.DEVICE_TIME_INCORRECT ->
+                R.string.datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME
+            Type.PLAY_SERVICES_VERSION_MISMATCH ->
+                R.string.datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES
+            Type.TIME_SINCE_ONBOARDING_UNVERIFIED ->
+                R.string.datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED
+        }
+        return HumanReadableError(description = context.getString(messageRes, type))
+    }
 
     enum class Type {
         // TRY_AGAIN_LATER (Text Key)
@@ -32,23 +58,3 @@ class SafetyNetException constructor(
         TIME_SINCE_ONBOARDING_UNVERIFIED
     }
 }
-
-fun SafetyNetException.errorMsgRes(): Int = when (type) {
-    SafetyNetException.Type.APK_PACKAGE_NAME_MISMATCH,
-    SafetyNetException.Type.ATTESTATION_FAILED,
-    SafetyNetException.Type.ATTESTATION_REQUEST_FAILED,
-    SafetyNetException.Type.DEVICE_TIME_UNVERIFIED,
-    SafetyNetException.Type.NONCE_MISMATCH ->
-        R.string.datadonation_details_survey_consent_error_TRY_AGAIN_LATER
-    SafetyNetException.Type.BASIC_INTEGRITY_REQUIRED,
-    SafetyNetException.Type.CTS_PROFILE_MATCH_REQUIRED,
-    SafetyNetException.Type.EVALUATION_TYPE_BASIC_REQUIRED,
-    SafetyNetException.Type.EVALUATION_TYPE_HARDWARE_BACKED_REQUIRED ->
-        R.string.datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED
-    SafetyNetException.Type.DEVICE_TIME_INCORRECT ->
-        R.string.datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME
-    SafetyNetException.Type.PLAY_SERVICES_VERSION_MISMATCH ->
-        R.string.datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES
-    SafetyNetException.Type.TIME_SINCE_ONBOARDING_UNVERIFIED ->
-        R.string.datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/SurveyException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/SurveyException.kt
index e7967fd5d4765621da9797e06e7b2f36cc9ab8f4..884715f69fd62aa69e5926964454589630439f1e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/SurveyException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/SurveyException.kt
@@ -1,21 +1,27 @@
 package de.rki.coronawarnapp.datadonation.survey
 
+import android.content.Context
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.util.HasHumanReadableError
+import de.rki.coronawarnapp.util.HumanReadableError
 
 class SurveyException constructor(
     val type: Type,
     message: String? = null,
     cause: Throwable? = null
-) : Exception("$type: $message", cause) {
+) : Exception("$type: $message", cause), HasHumanReadableError {
+
+    override fun toHumanReadableError(context: Context): HumanReadableError {
+        val messageRes = when (type) {
+            Type.ALREADY_PARTICIPATED_THIS_MONTH ->
+                R.string.datadonation_details_survey_consent_error_ALREADY_PARTICIPATED
+            Type.OTP_NOT_AUTHORIZED -> R.string.datadonation_details_survey_consent_error_TRY_AGAIN_LATER
+        }
+        return HumanReadableError(description = context.getString(messageRes, type))
+    }
 
     enum class Type {
         ALREADY_PARTICIPATED_THIS_MONTH,
         OTP_NOT_AUTHORIZED
     }
 }
-
-fun SurveyException.errorMsgRes(): Int = when (type) {
-    SurveyException.Type.ALREADY_PARTICIPATED_THIS_MONTH ->
-        R.string.datadonation_details_survey_consent_error_ALREADY_PARTICIPATED
-    SurveyException.Type.OTP_NOT_AUTHORIZED -> R.string.datadonation_details_survey_consent_error_TRY_AGAIN_LATER
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/SurveySettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/SurveySettings.kt
index 228b75aa90a94823144c1946038ef3666e1bd64e..bf804128e1815ec72818c5c59e28707197ea04db 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/SurveySettings.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/SurveySettings.kt
@@ -52,6 +52,7 @@ class SurveySettings @Inject constructor(
                     requireNotNull(result.uuid)
                     requireNotNull(result.authorized)
                     requireNotNull(result.redeemedAt)
+                    requireNotNull(result.invalidated)
                     return result
                 }
                 return null
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/Surveys.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/Surveys.kt
index bf2bf4f0b4deaf919a6cc3b44784dd787e790b0f..f792b7d75942f553f9d3bc45ea68bb245f466017 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/Surveys.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/Surveys.kt
@@ -37,6 +37,36 @@ class Surveys @Inject constructor(
             }
     }
 
+    suspend fun isConsentNeeded(type: Type): ConsentResult {
+
+        when (type) {
+            Type.HIGH_RISK_ENCOUNTER -> {
+
+                // If no OTP was ever authorized, we need a consent.
+                val authResult = oneTimePasswordRepo.otpAuthorizationResult ?: return ConsentResult.Needed
+
+                // If we already have an authorized OTP for this high-risk state
+                // we can skip the consent and directly show the url in the browser.
+                // We know that the otp belongs to the current high-risk state, because the authResult gets
+                // invalidated on high to low risk state transitions.
+                if (authResult.authorized && !authResult.invalidated) {
+                    val surveyLink = urlProvider.provideUrl(type, authResult.uuid)
+                    return ConsentResult.AlreadyGiven(surveyLink)
+                }
+
+                // Finally, we need a consent for stored OTPs where the authorization failed (authorized == false)
+                // or when the app shows a new high-risk card (and therefore authResult was previously invalidated when the
+                // risk changed from high to low)
+                return ConsentResult.Needed
+            }
+        }
+    }
+
+    sealed class ConsentResult {
+        object Needed : ConsentResult()
+        data class AlreadyGiven(val surveyLink: String) : ConsentResult()
+    }
+
     suspend fun requestDetails(type: Type): Survey {
         val config = appConfigProvider.getAppConfig().survey
         Timber.v("Requested survey: %s", config)
@@ -62,7 +92,11 @@ class Surveys @Inject constructor(
 
         // request validation from server
         val errorCode = surveyServer.authOTP(oneTimePassword, attestationResult).errorCode
-        val result = OTPAuthorizationResult(oneTimePassword.uuid, errorCode == null, now)
+        val result = OTPAuthorizationResult(
+            uuid = oneTimePassword.uuid,
+            authorized = errorCode == null,
+            redeemedAt = now
+        )
         oneTimePasswordRepo.otpAuthorizationResult = result
 
         if (result.authorized) {
@@ -76,9 +110,10 @@ class Surveys @Inject constructor(
     }
 
     fun resetSurvey(type: Type) {
-        if (type == Type.HIGH_RISK_ENCOUNTER) {
-            Timber.d("Discarding one time password for survey about previous high-risk state.")
-            oneTimePasswordRepo.clear()
+        val authResult = oneTimePasswordRepo.otpAuthorizationResult
+        if (type == Type.HIGH_RISK_ENCOUNTER && authResult != null) {
+            Timber.d("Invalidating one time password for survey about previous high-risk state.")
+            oneTimePasswordRepo.otpAuthorizationResult = authResult.toInvalidatedInstance()
         }
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentFragment.kt
index 28f400fe95db220e74aac93356877d6c8a2e49b9..2042fb57bd8372625789e06181417b388d08dea8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentFragment.kt
@@ -2,7 +2,6 @@ package de.rki.coronawarnapp.datadonation.survey.consent
 
 import android.os.Bundle
 import android.view.View
-import androidx.annotation.StringRes
 import androidx.fragment.app.DialogFragment
 import androidx.fragment.app.Fragment
 import androidx.navigation.fragment.navArgs
@@ -73,16 +72,16 @@ class SurveyConsentFragment : Fragment(R.layout.survey_consent_fragment), AutoIn
         }
 
         vm.showErrorDialog.observe2(this) {
-            showErrorDialog(it.msgRes)
+            showErrorDialog(it.errorMessage.get(requireContext()))
         }
     }
 
-    private fun showErrorDialog(@StringRes stringRes: Int) {
+    private fun showErrorDialog(message: String) {
         context?.let {
             val dialog = DialogHelper.DialogInstance(
                 context = it,
                 title = R.string.datadonation_details_survey_consent_error_dialog_title,
-                message = stringRes,
+                message = message,
                 positiveButton = R.string.datadonation_details_survey_consent_error_dialog_pos_button,
                 cancelable = false
             )
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentViewModel.kt
index d4a5e4c3a482322e7d576af051e41c3745d8d168..bdeb643704e7b45640a7754d91e3d910e1ebb3b8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentViewModel.kt
@@ -1,19 +1,18 @@
 package de.rki.coronawarnapp.datadonation.survey.consent
 
-import androidx.annotation.StringRes
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.asLiveData
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.datadonation.safetynet.SafetyNetException
-import de.rki.coronawarnapp.datadonation.safetynet.errorMsgRes
-import de.rki.coronawarnapp.datadonation.survey.SurveyException
 import de.rki.coronawarnapp.datadonation.survey.Surveys
-import de.rki.coronawarnapp.datadonation.survey.errorMsgRes
+import de.rki.coronawarnapp.util.HasHumanReadableError
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
+import de.rki.coronawarnapp.util.toResolvingString
+import de.rki.coronawarnapp.util.ui.LazyString
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
+import de.rki.coronawarnapp.util.ui.toResolvingString
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -52,9 +51,9 @@ class SurveyConsentViewModel @AssistedInject constructor(
             State.Success(survey)
         } catch (e: Exception) {
             val errorMsg = when (e) {
-                is SafetyNetException -> e.errorMsgRes()
-                is SurveyException -> e.errorMsgRes()
-                else -> R.string.datadonation_details_survey_consent_error_TRY_AGAIN_LATER
+                is HasHumanReadableError -> e.toResolvingString()
+                else ->
+            R.string.datadonation_details_survey_consent_error_TRY_AGAIN_LATER.toResolvingString(e.javaClass.simpleName)
             }
             Timber.e(e)
             State.Error(errorMsg)
@@ -76,7 +75,7 @@ class SurveyConsentViewModel @AssistedInject constructor(
         object Loading : State()
 
         data class Error(
-            @StringRes val msgRes: Int
+            val errorMessage: LazyString
         ) : State()
 
         data class Success(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/server/SurveyServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/server/SurveyServer.kt
index e345914ef6cc453ebd5fed21a12844a1dd06f86f..3feba5a87b53142e47e7a422e5d25ff06271d53b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/server/SurveyServer.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/server/SurveyServer.kt
@@ -1,10 +1,8 @@
 package de.rki.coronawarnapp.datadonation.survey.server
 
-import com.google.protobuf.ByteString
 import dagger.Lazy
 import de.rki.coronawarnapp.datadonation.OneTimePassword
 import de.rki.coronawarnapp.datadonation.safetynet.DeviceAttestation
-import de.rki.coronawarnapp.server.protocols.internal.ppdd.EdusOtp
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.EdusOtpRequestAndroid
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import kotlinx.coroutines.withContext
@@ -28,11 +26,7 @@ class SurveyServer @Inject constructor(
         Timber.d("authOTP()")
 
         val dataDonationPayload = EdusOtpRequestAndroid.EDUSOneTimePasswordRequestAndroid.newBuilder()
-            .setPayload(
-                EdusOtp.EDUSOneTimePassword.newBuilder()
-                    .setOtp(data.uuid.toString())
-                    .setOtpBytes(ByteString.copyFrom(data.payloadForRequest))
-            )
+            .setPayload(data.edusOneTimePassword)
             .setAuthentication(deviceAttestation.accessControlProtoBuf)
             .build()
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt
index db52d23dcd0803b00a9500e8e4efec8c017b756a..b545c807ec7d29864850a5c770e6ffd08100da77 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt
@@ -8,6 +8,7 @@ import de.rki.coronawarnapp.environment.EnvironmentSetup
 import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.TrackedExposureDetection
 import de.rki.coronawarnapp.risk.RollbackItem
+import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.task.Task
 import de.rki.coronawarnapp.task.TaskCancellationException
 import de.rki.coronawarnapp.task.TaskFactory
@@ -25,6 +26,7 @@ import java.util.Date
 import javax.inject.Inject
 import javax.inject.Provider
 
+@Suppress("ReturnCount")
 class DownloadDiagnosisKeysTask @Inject constructor(
     private val enfClient: ENFClient,
     private val environmentSetup: EnvironmentSetup,
@@ -111,6 +113,11 @@ class DownloadDiagnosisKeysTask @Inject constructor(
             // remember version code of this execution for next time
             settings.updateLastVersionCodeToCurrent()
 
+            if (LocalData.isAllowedToSubmitDiagnosisKeys()) {
+                Timber.tag(TAG).i("task aborted, positive test result")
+                return object : Task.Result {}
+            }
+
             Timber.tag(TAG).d("Attempting submission to ENF")
             val isSubmissionSuccessful = enfClient.provideDiagnosisKeys(
                 availableKeyFiles,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt
index b54b8d76836122d6620b318e14c22a7632f27e71..ba9ca0de7a51413d35f153e6f23a8b16029e36c4 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt
@@ -29,55 +29,81 @@ import okhttp3.Response
 import timber.log.Timber
 import java.net.SocketTimeoutException
 import java.net.UnknownHostException
-import javax.net.ssl.HttpsURLConnection
+import javax.net.ssl.HttpsURLConnection.HTTP_ACCEPTED
+import javax.net.ssl.HttpsURLConnection.HTTP_BAD_GATEWAY
+import javax.net.ssl.HttpsURLConnection.HTTP_BAD_REQUEST
+import javax.net.ssl.HttpsURLConnection.HTTP_CONFLICT
+import javax.net.ssl.HttpsURLConnection.HTTP_CREATED
+import javax.net.ssl.HttpsURLConnection.HTTP_FORBIDDEN
+import javax.net.ssl.HttpsURLConnection.HTTP_GATEWAY_TIMEOUT
+import javax.net.ssl.HttpsURLConnection.HTTP_GONE
+import javax.net.ssl.HttpsURLConnection.HTTP_INTERNAL_ERROR
+import javax.net.ssl.HttpsURLConnection.HTTP_NOT_FOUND
+import javax.net.ssl.HttpsURLConnection.HTTP_NOT_IMPLEMENTED
+import javax.net.ssl.HttpsURLConnection.HTTP_NO_CONTENT
+import javax.net.ssl.HttpsURLConnection.HTTP_OK
+import javax.net.ssl.HttpsURLConnection.HTTP_UNAUTHORIZED
+import javax.net.ssl.HttpsURLConnection.HTTP_UNAVAILABLE
+import javax.net.ssl.HttpsURLConnection.HTTP_UNSUPPORTED_TYPE
+import javax.net.ssl.HttpsURLConnection.HTTP_VERSION
 
 class HttpErrorParser : Interceptor {
     override fun intercept(chain: Interceptor.Chain): Response {
         try {
             val response = chain.proceed(chain.request())
 
-            val message: String? = try {
-                if (response.isSuccessful) {
-                    null
-                } else {
-                    response.message
-                }
+            if (response.isSuccessful) {
+                return response
+            }
+
+            val statusMessage: String? = try {
+                response.message
             } catch (e: Exception) {
-                Timber.w("Failed to get http error message.")
+                Timber.w("Failed to get http status-message.")
                 null
             }
+
+            val body: String? = try {
+                response.peekBody(2048).string()
+            } catch (e: Exception) {
+                Timber.w("Failed to get http error body.")
+                null
+            }
+
+            val errorDetails = "$statusMessage body=$body'"
+
             return when (val code = response.code) {
-                HttpsURLConnection.HTTP_OK -> response
-                HttpsURLConnection.HTTP_CREATED -> response
-                HttpsURLConnection.HTTP_ACCEPTED -> response
-                HttpsURLConnection.HTTP_NO_CONTENT -> response
-                HttpsURLConnection.HTTP_BAD_REQUEST -> throw BadRequestException(message)
-                HttpsURLConnection.HTTP_UNAUTHORIZED -> throw UnauthorizedException(message)
-                HttpsURLConnection.HTTP_FORBIDDEN -> throw ForbiddenException(message)
-                HttpsURLConnection.HTTP_NOT_FOUND -> throw NotFoundException(message)
-                HttpsURLConnection.HTTP_CONFLICT -> throw ConflictException(message)
-                HttpsURLConnection.HTTP_GONE -> throw GoneException(message)
-                HttpsURLConnection.HTTP_UNSUPPORTED_TYPE -> throw UnsupportedMediaTypeException(message)
-                429 -> throw TooManyRequestsException(message)
-                HttpsURLConnection.HTTP_INTERNAL_ERROR -> throw InternalServerErrorException(message)
-                HttpsURLConnection.HTTP_NOT_IMPLEMENTED -> throw NotImplementedException(message)
-                HttpsURLConnection.HTTP_BAD_GATEWAY -> throw BadGatewayException(message)
-                HttpsURLConnection.HTTP_UNAVAILABLE -> throw ServiceUnavailableException(message)
-                HttpsURLConnection.HTTP_GATEWAY_TIMEOUT -> throw GatewayTimeoutException(message)
-                HttpsURLConnection.HTTP_VERSION -> throw HTTPVersionNotSupported(message)
-                511 -> throw NetworkAuthenticationRequiredException(message)
-                598 -> throw NetworkReadTimeoutException(message)
-                599 -> throw NetworkConnectTimeoutException(message)
+                HTTP_OK -> response
+                HTTP_CREATED -> response
+                HTTP_ACCEPTED -> response
+                HTTP_NO_CONTENT -> response
+                HTTP_BAD_REQUEST -> throw BadRequestException(errorDetails)
+                HTTP_UNAUTHORIZED -> throw UnauthorizedException(errorDetails)
+                HTTP_FORBIDDEN -> throw ForbiddenException(errorDetails)
+                HTTP_NOT_FOUND -> throw NotFoundException(errorDetails)
+                HTTP_CONFLICT -> throw ConflictException(errorDetails)
+                HTTP_GONE -> throw GoneException(errorDetails)
+                HTTP_UNSUPPORTED_TYPE -> throw UnsupportedMediaTypeException(errorDetails)
+                429 -> throw TooManyRequestsException(errorDetails)
+                HTTP_INTERNAL_ERROR -> throw InternalServerErrorException(errorDetails)
+                HTTP_NOT_IMPLEMENTED -> throw NotImplementedException(errorDetails)
+                HTTP_BAD_GATEWAY -> throw BadGatewayException(errorDetails)
+                HTTP_UNAVAILABLE -> throw ServiceUnavailableException(errorDetails)
+                HTTP_GATEWAY_TIMEOUT -> throw GatewayTimeoutException(errorDetails)
+                HTTP_VERSION -> throw HTTPVersionNotSupported(errorDetails)
+                511 -> throw NetworkAuthenticationRequiredException(errorDetails)
+                598 -> throw NetworkReadTimeoutException(errorDetails)
+                599 -> throw NetworkConnectTimeoutException(errorDetails)
                 else -> {
-                    if (code in 100..199) throw CwaInformationalNotSupportedError(code, message)
+                    if (code in 100..199) throw CwaInformationalNotSupportedError(code, errorDetails)
                     if (code in 200..299) throw CwaSuccessResponseWithCodeMismatchNotSupportedError(
                         code,
-                        message
+                        errorDetails
                     )
-                    if (code in 300..399) throw CwaRedirectNotSupportedError(code, message)
-                    if (code in 400..499) throw CwaClientError(code, message)
-                    if (code in 500..599) throw CwaServerError(code, message)
-                    throw CwaWebException(code, message)
+                    if (code in 300..399) throw CwaRedirectNotSupportedError(code, errorDetails)
+                    if (code in 400..499) throw CwaClientError(code, errorDetails)
+                    if (code in 500..599) throw CwaServerError(code, errorDetails)
+                    throw CwaWebException(code, errorDetails)
                 }
             }
         } catch (err: SocketTimeoutException) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt
index bb0241ab522a1d6772c9543051210eab935a7372..2452ac44b62c3ab3b127e9e083ff96a803bcd373 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt
@@ -157,16 +157,21 @@ class DefaultTEKHistoryProvider @Inject constructor(
         }
     }
 
-    // Timeout after 20 sec if receiver did not get called
+    // Timeout after 5 sec if receiver did not get called
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    internal suspend fun getPreAuthorizedExposureKeys(): List<TemporaryExposureKey> = withTimeout(20_000) {
+    internal suspend fun getPreAuthorizedExposureKeys(): List<TemporaryExposureKey> = withTimeout(5_000) {
         coroutineScope {
             // Register receiver before hitting the API to avoid race conditions
             val deferredIntent = async { awaitReceivedBroadcast() }
             client.requestPreAuthorizedTemporaryExposureKeyRelease().await()
-            Timber.i("requestPreAuthorizedTemporaryExposureKeyRelease is done")
+            Timber.i("Pre-Auth requestPreAuthorizedTemporaryExposureKeyRelease is done")
+            val startTime = System.currentTimeMillis()
+            Timber.i("Pre-Auth Receiver StartTime:$startTime")
             val intent = deferredIntent.await()
-            Timber.d("getPreAuthorizedExposureKeys():intent=%s", intent)
+            val endTime = System.currentTimeMillis()
+            Timber.i("Pre-Auth Receiver EndTime:$endTime")
+            Timber.i("Pre-Auth Receiver WaitingTime:${endTime - startTime}")
+            Timber.d("Pre-Auth getPreAuthorizedExposureKeys():intent=%s", intent)
             intent.getParcelableArrayListExtra(EXTRA_TEMPORARY_EXPOSURE_KEY_LIST) ?: emptyList()
         }
     }
@@ -175,7 +180,7 @@ class DefaultTEKHistoryProvider @Inject constructor(
         val receiver = object : BroadcastReceiver() {
             override fun onReceive(context: Context, intent: Intent) {
                 cont.resume(intent)
-                Timber.d("unregisterReceiver")
+                Timber.d("Pre-Auth unregisterReceiver")
                 context.unregisterReceiver(this)
             }
         }
@@ -184,7 +189,7 @@ class DefaultTEKHistoryProvider @Inject constructor(
             IntentFilter(ACTION_PRE_AUTHORIZE_RELEASE_PHONE_UNLOCKED)
         )
         cont.invokeOnCancellation {
-            Timber.d(it, "unregisterReceiver")
+            Timber.d(it, "Pre-Auth  unregisterReceiver")
             context.unregisterReceiver(receiver)
         }
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TestSettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TestSettings.kt
index e9bb38c8485ad88263fb1fbdbabf6551036a3010..c0099d3a3f1550da855c969ff4c5e8ce6b0a289e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TestSettings.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TestSettings.kt
@@ -35,6 +35,11 @@ class TestSettings @Inject constructor(
         writer = FlowPreference.gsonWriter(gson)
     )
 
+    val skipSafetyNetTimeCheck = prefs.createFlowPreference(
+        key = "safetynet.skip.timecheck",
+        defaultValue = false
+    )
+
     enum class FakeExposureWindowTypes {
         @SerializedName("DISABLED")
         DISABLED,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragment.kt
index b21bf698e80c4186fd840cca67e761700809b76f..7732c39381124be8d7f5fa910e53c814247d6d56 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragment.kt
@@ -8,6 +8,7 @@ import androidx.recyclerview.widget.DefaultItemAnimator
 import androidx.recyclerview.widget.LinearLayoutManager
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.TracingDetailsFragmentLayoutBinding
+import de.rki.coronawarnapp.util.ExternalActionHelper
 import de.rki.coronawarnapp.util.di.AutoInject
 import de.rki.coronawarnapp.util.lists.diffutil.update
 import de.rki.coronawarnapp.util.ui.doNavigate
@@ -55,6 +56,10 @@ class TracingDetailsFragment : Fragment(R.layout.tracing_details_fragment_layout
                 is TracingDetailsNavigationEvents.NavigateToSurveyConsentFragment -> doNavigate(
                     TracingDetailsFragmentDirections.actionRiskDetailsFragmentToSurveyConsentFragment(it.type)
                 )
+                is TracingDetailsNavigationEvents.NavigateToSurveyUrlInBrowser -> ExternalActionHelper.openUrl(
+                    this,
+                    it.url
+                )
             }
         }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragmentViewModel.kt
index df6725509fbc286e8108d1f01abe82866a2596c0..e7fa208798eaa4d03d3ace92c00d141d499ae932 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragmentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragmentViewModel.kt
@@ -4,6 +4,9 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.asLiveData
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.datadonation.survey.Surveys
+import de.rki.coronawarnapp.datadonation.survey.Surveys.ConsentResult.AlreadyGiven
+import de.rki.coronawarnapp.datadonation.survey.Surveys.ConsentResult.Needed
 import de.rki.coronawarnapp.risk.RiskState
 import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.risk.tryLatestResultsWithDefaults
@@ -42,7 +45,8 @@ class TracingDetailsFragmentViewModel @AssistedInject constructor(
     riskLevelStorage: RiskLevelStorage,
     tracingDetailsItemProvider: TracingDetailsItemProvider,
     tracingStateProviderFactory: TracingStateProvider.Factory,
-    private val tracingRepository: TracingRepository
+    private val tracingRepository: TracingRepository,
+    private val surveys: Surveys
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
     private val tracingStateProvider by lazy { tracingStateProviderFactory.create(isDetailsMode = true) }
@@ -108,7 +112,20 @@ class TracingDetailsFragmentViewModel @AssistedInject constructor(
     fun onItemClicked(item: DetailsItem) {
         when (item) {
             is UserSurveyBox.Item ->
-                routeToScreen.postValue(TracingDetailsNavigationEvents.NavigateToSurveyConsentFragment(item.type))
+                launch {
+                    when (val consentResult = surveys.isConsentNeeded(Surveys.Type.HIGH_RISK_ENCOUNTER)) {
+                        is Needed -> routeToScreen.postValue(
+                            TracingDetailsNavigationEvents.NavigateToSurveyConsentFragment(
+                                item.type
+                            )
+                        )
+                        is AlreadyGiven -> routeToScreen.postValue(
+                            TracingDetailsNavigationEvents.NavigateToSurveyUrlInBrowser(
+                                consentResult.surveyLink
+                            )
+                        )
+                    }
+                }
         }
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsNavigationEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsNavigationEvents.kt
index 221ebc91e8e9ebd767706a140276e2647c3f1749..9ba870a63c02d6048d225a6d84114e3061e8e730 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsNavigationEvents.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsNavigationEvents.kt
@@ -3,5 +3,6 @@ package de.rki.coronawarnapp.tracing.ui.details
 import de.rki.coronawarnapp.datadonation.survey.Surveys
 
 sealed class TracingDetailsNavigationEvents {
-    class NavigateToSurveyConsentFragment(val type: Surveys.Type) : TracingDetailsNavigationEvents()
+    data class NavigateToSurveyConsentFragment(val type: Surveys.Type) : TracingDetailsNavigationEvents()
+    data class NavigateToSurveyUrlInBrowser(val url: String) : TracingDetailsNavigationEvents()
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt
index c9204ce988c03634c8bab244d36cdc4f818f0c0a..a0c2547e99906dc956149bebca5d47edf4e317a5 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt
@@ -17,6 +17,7 @@ import dagger.android.HasAndroidInjector
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.contactdiary.retention.ContactDiaryWorkScheduler
 import de.rki.coronawarnapp.databinding.ActivityMainBinding
+import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsScheduler
 import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.ui.base.startActivitySafely
@@ -61,6 +62,7 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector {
     @Inject lateinit var powerManagement: PowerManagement
     @Inject lateinit var deadmanScheduler: DeadmanNotificationScheduler
     @Inject lateinit var contactDiaryWorkScheduler: ContactDiaryWorkScheduler
+    @Inject lateinit var dataDonationAnalyticsScheduler: DataDonationAnalyticsScheduler
 
     override fun onCreate(savedInstanceState: Bundle?) {
         AppInjector.setup(this)
@@ -108,6 +110,7 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector {
         scheduleWork()
         vm.doBackgroundNoiseCheck()
         contactDiaryWorkScheduler.schedulePeriodic()
+        dataDonationAnalyticsScheduler.schedulePeriodic()
         if (!LocalData.isAllowedToSubmitDiagnosisKeys()) {
             deadmanScheduler.schedulePeriodic()
         }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt
index 1bceda1f85eca90f326d9e60b62821ae39104f5b..6a265ce44d9184285e656b5dc74af6a4e4076ccc 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt
@@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentSubmissionTestResultAvailableBinding
 import de.rki.coronawarnapp.tracing.ui.TracingConsentDialog
+import de.rki.coronawarnapp.ui.submission.SubmissionBlockingDialog
 import de.rki.coronawarnapp.util.DialogHelper
 import de.rki.coronawarnapp.util.di.AutoInject
 import de.rki.coronawarnapp.util.ui.doNavigate
@@ -16,6 +17,7 @@ import de.rki.coronawarnapp.util.ui.observe2
 import de.rki.coronawarnapp.util.ui.viewBindingLazy
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
+import timber.log.Timber
 import javax.inject.Inject
 
 /**
@@ -27,10 +29,13 @@ class SubmissionTestResultAvailableFragment : Fragment(R.layout.fragment_submiss
     @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
     private val vm: SubmissionTestResultAvailableViewModel by cwaViewModels { viewModelFactory }
     private val binding: FragmentSubmissionTestResultAvailableBinding by viewBindingLazy()
+    private lateinit var keyRetrievalProgress: SubmissionBlockingDialog
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
+        keyRetrievalProgress = SubmissionBlockingDialog(requireContext())
+
         val backCallback = object : OnBackPressedCallback(true) {
             override fun handleOnBackPressed() = vm.goBack()
         }
@@ -49,6 +54,12 @@ class SubmissionTestResultAvailableFragment : Fragment(R.layout.fragment_submiss
             binding.submissionTestResultAvailableConsentStatus.consent = it
         }
 
+        vm.showKeyRetrievalProgress.observe2(this) { show ->
+            Timber.i("SubmissionTestResult:showKeyRetrievalProgress:$show")
+            keyRetrievalProgress.setState(show)
+            binding.submissionTestResultAvailableProceedButton.isEnabled = !show
+        }
+
         binding.apply {
             submissionTestResultAvailableProceedButton.setOnClickListener { vm.proceed() }
             submissionTestResultAvailableConsentStatus.setOnClickListener { vm.goConsent() }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt
index 380d7a84cdd912fe61dfc35392a6c9897977e9e6..9d122d70c945df4436468b3246aba2727db44107 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt
@@ -32,6 +32,7 @@ class SubmissionTestResultAvailableViewModel @AssistedInject constructor(
     val consent = consentFlow.asLiveData(dispatcherProvider.Default)
     val showPermissionRequest = SingleLiveEvent<(Activity) -> Unit>()
     val showCloseDialog = SingleLiveEvent<Unit>()
+    val showKeyRetrievalProgress = SingleLiveEvent<Boolean>()
     val showTracingConsentDialog = SingleLiveEvent<(Boolean) -> Unit>()
 
     private val tekHistoryUpdater = tekHistoryUpdaterFactory.create(
@@ -44,6 +45,8 @@ class SubmissionTestResultAvailableViewModel @AssistedInject constructor(
                     SubmissionTestResultAvailableFragmentDirections
                         .actionSubmissionTestResultAvailableFragmentToSubmissionTestResultConsentGivenFragment()
                 )
+
+                showKeyRetrievalProgress.postValue(false)
             }
 
             override fun onTEKPermissionDeclined() {
@@ -51,14 +54,17 @@ class SubmissionTestResultAvailableViewModel @AssistedInject constructor(
                     SubmissionTestResultAvailableFragmentDirections
                         .actionSubmissionTestResultAvailableFragmentToSubmissionTestResultNoConsentFragment()
                 )
+                showKeyRetrievalProgress.postValue(false)
             }
 
             override fun onTracingConsentRequired(onConsentResult: (given: Boolean) -> Unit) {
                 showTracingConsentDialog.postValue(onConsentResult)
+                showKeyRetrievalProgress.postValue(false)
             }
 
             override fun onPermissionRequired(permissionRequest: (Activity) -> Unit) {
                 showPermissionRequest.postValue(permissionRequest)
+                showKeyRetrievalProgress.postValue(false)
             }
 
             override fun onError(error: Throwable) {
@@ -67,6 +73,7 @@ class SubmissionTestResultAvailableViewModel @AssistedInject constructor(
                     exceptionCategory = ExceptionCategory.EXPOSURENOTIFICATION,
                     prefix = "SubmissionTestResultAvailableViewModel"
                 )
+                showKeyRetrievalProgress.postValue(false)
             }
         }
     )
@@ -96,6 +103,7 @@ class SubmissionTestResultAvailableViewModel @AssistedInject constructor(
     }
 
     fun proceed() {
+        showKeyRetrievalProgress.value = true
         launch {
             if (consentFlow.first()) {
                 tekHistoryUpdater.updateTEKHistoryOrRequestPermission()
@@ -109,6 +117,7 @@ class SubmissionTestResultAvailableViewModel @AssistedInject constructor(
     }
 
     fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        showKeyRetrievalProgress.value = true
         tekHistoryUpdater.handleActivityResult(requestCode, resultCode, data)
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModel.kt
index bf7306dae8e383771de71a6040e67caba25b5268..85af09cf324159ace2456eb156beb62d47331314 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModel.kt
@@ -1,5 +1,7 @@
 package de.rki.coronawarnapp.ui.submission.symptoms.calendar
 
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MediatorLiveData
 import androidx.lifecycle.asLiveData
 import androidx.navigation.NavDirections
 import dagger.assisted.Assisted
@@ -29,8 +31,17 @@ class SubmissionSymptomCalendarViewModel @AssistedInject constructor(
 
     val routeToScreen = SingleLiveEvent<NavDirections>()
     val showCancelDialog = SingleLiveEvent<Unit>()
-    val showUploadDialog = autoSubmission.isSubmissionRunning
-        .asLiveData(context = dispatcherProvider.Default)
+    private val mediatorShowUploadDialog = MediatorLiveData<Boolean>()
+
+    init {
+        mediatorShowUploadDialog.addSource(
+            autoSubmission.isSubmissionRunning.asLiveData(context = dispatcherProvider.Default)
+        ) { show ->
+            mediatorShowUploadDialog.postValue(show)
+        }
+    }
+
+    val showUploadDialog: LiveData<Boolean> = mediatorShowUploadDialog
 
     fun onLastSevenDaysStart() {
         updateSymptomStart(Symptoms.StartOf.LastSevenDays)
@@ -88,6 +99,8 @@ class SubmissionSymptomCalendarViewModel @AssistedInject constructor(
             } catch (e: Exception) {
                 Timber.tag(TAG).e(e, "performSubmission() failed.")
             } finally {
+                Timber.i("Hide uploading progress and navigate to HomeFragment")
+                mediatorShowUploadDialog.postValue(false)
                 routeToScreen.postValue(
                     SubmissionSymptomCalendarFragmentDirections.actionSubmissionSymptomCalendarFragmentToMainFragment()
                 )
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt
index 5aef9891bc0113c36ed32cd435026028d1a7db30..2fd6b41f222745ebcd9ab224706efd87d14d5a27 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt
@@ -8,6 +8,7 @@ import androidx.fragment.app.Fragment
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentSubmissionNoConsentPositiveOtherWarningBinding
 import de.rki.coronawarnapp.tracing.ui.TracingConsentDialog
+import de.rki.coronawarnapp.ui.submission.SubmissionBlockingDialog
 import de.rki.coronawarnapp.util.DialogHelper
 import de.rki.coronawarnapp.util.di.AutoInject
 import de.rki.coronawarnapp.util.ui.doNavigate
@@ -38,6 +39,8 @@ class SubmissionResultPositiveOtherWarningNoConsentFragment :
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
+        val keysRetrievalProgress = SubmissionBlockingDialog(requireContext())
+
         binding.submissionPositiveOtherWarningNoConsentButtonNext.setOnClickListener {
             viewModel.onConsentButtonClicked()
         }
@@ -49,6 +52,11 @@ class SubmissionResultPositiveOtherWarningNoConsentFragment :
             doNavigate(it)
         }
 
+        viewModel.keysRetrievalProgress.observe2(this) { show ->
+            keysRetrievalProgress.setState(show)
+            binding.submissionPositiveOtherWarningNoConsentButtonNext.isEnabled = !show
+        }
+
         viewModel.showPermissionRequest.observe2(this) { permissionRequest ->
             permissionRequest.invoke(requireActivity())
         }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt
index 08289e0cd776ee1e9a98e45f15a6571811e9064f..4fe9eb0c0a6f39d578dca6e962211c4e5eca8f02 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt
@@ -32,6 +32,8 @@ class SubmissionResultPositiveOtherWarningNoConsentViewModel @AssistedInject con
 
     val routeToScreen = SingleLiveEvent<NavDirections>()
 
+    val keysRetrievalProgress = SingleLiveEvent<Boolean>()
+
     val showPermissionRequest = SingleLiveEvent<(Activity) -> Unit>()
 
     val showEnableTracingEvent = SingleLiveEvent<Unit>()
@@ -46,7 +48,7 @@ class SubmissionResultPositiveOtherWarningNoConsentViewModel @AssistedInject con
             override fun onTEKAvailable(teks: List<TemporaryExposureKey>) {
                 Timber.d("onTEKAvailable(tek.size=%d)", teks.size)
                 autoSubmission.updateMode(AutoSubmission.Mode.MONITOR)
-
+                keysRetrievalProgress.postValue(false)
                 routeToScreen.postValue(
                     SubmissionResultPositiveOtherWarningNoConsentFragmentDirections
                         .actionSubmissionResultPositiveOtherWarningNoConsentFragmentToSubmissionResultReadyFragment()
@@ -54,18 +56,22 @@ class SubmissionResultPositiveOtherWarningNoConsentViewModel @AssistedInject con
             }
 
             override fun onTEKPermissionDeclined() {
+                keysRetrievalProgress.postValue(false)
                 // stay on screen
             }
 
             override fun onTracingConsentRequired(onConsentResult: (given: Boolean) -> Unit) {
+                keysRetrievalProgress.postValue(false)
                 showTracingConsentDialog.postValue(onConsentResult)
             }
 
             override fun onPermissionRequired(permissionRequest: (Activity) -> Unit) {
+                keysRetrievalProgress.postValue(false)
                 showPermissionRequest.postValue(permissionRequest)
             }
 
             override fun onError(error: Throwable) {
+                keysRetrievalProgress.postValue(false)
                 Timber.e(error, "Couldn't access temporary exposure key history.")
                 error.report(ExceptionCategory.EXPOSURENOTIFICATION, "Failed to obtain TEKs.")
             }
@@ -80,6 +86,7 @@ class SubmissionResultPositiveOtherWarningNoConsentViewModel @AssistedInject con
     }
 
     fun onConsentButtonClicked() {
+        keysRetrievalProgress.value = true
         submissionRepository.giveConsentToSubmission()
         launch {
             if (enfClient.isTracingEnabled.first()) {
@@ -98,6 +105,7 @@ class SubmissionResultPositiveOtherWarningNoConsentViewModel @AssistedInject con
     }
 
     fun handleActivityRersult(requestCode: Int, resultCode: Int, data: Intent?) {
+        keysRetrievalProgress.value = true
         tekHistoryUpdater.handleActivityResult(requestCode, resultCode, data)
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt
index b2c0555a70b90f928b90d414379154c12adcc23e..28805584195cbb5958de45501a85d5321d82a8e2 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt
@@ -5,6 +5,8 @@ import android.content.Context
 import de.rki.coronawarnapp.appconfig.AppConfigProvider
 import de.rki.coronawarnapp.contactdiary.storage.ContactDiaryPreferences
 import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository
+import de.rki.coronawarnapp.datadonation.analytics.Analytics
+import de.rki.coronawarnapp.datadonation.analytics.storage.AnalyticsSettings
 import de.rki.coronawarnapp.datadonation.survey.SurveySettings
 import de.rki.coronawarnapp.diagnosiskeys.download.DownloadDiagnosisKeysSettings
 import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository
@@ -40,7 +42,9 @@ class DataReset @Inject constructor(
     private var contactDiaryPreferences: ContactDiaryPreferences,
     private val cwaSettings: CWASettings,
     private val statisticsProvider: StatisticsProvider,
-    private val surveySettings: SurveySettings
+    private val surveySettings: SurveySettings,
+    private val analyticsSettings: AnalyticsSettings,
+    private val analytics: Analytics
 ) {
 
     private val mutex = Mutex()
@@ -59,6 +63,9 @@ class DataReset @Inject constructor(
         // Shared Preferences Reset
         SecurityHelper.resetSharedPrefs()
 
+        // Triggers deletion of all analytics contributed data
+        analytics.setAnalyticsEnabled(false)
+
         // Reset the current states stored in LiveData
         submissionRepository.reset()
         keyCacheRepository.clear()
@@ -69,6 +76,7 @@ class DataReset @Inject constructor(
         contactDiaryPreferences.clear()
         cwaSettings.clear()
         surveySettings.clear()
+        analyticsSettings.clear()
 
         // Clear contact diary database
         contactDiaryRepository.clear()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/HasHumanReadableError.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/HasHumanReadableError.kt
index 82f66fda53b9599b39dd156620343d52cdb97de6..37eebfda6663da7d3587233005b48d36899a5d7e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/HasHumanReadableError.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/HasHumanReadableError.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.util
 
 import android.content.Context
+import de.rki.coronawarnapp.util.ui.LazyString
 
 interface HasHumanReadableError {
     fun toHumanReadableError(context: Context): HumanReadableError
@@ -19,3 +20,7 @@ fun Throwable.tryHumanReadableError(context: Context): HumanReadableError = when
         )
     }
 }
+
+fun HasHumanReadableError.toResolvingString() = object : LazyString {
+    override fun get(context: Context): String = toHumanReadableError(context).description
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt
index d529dc873981f17a7beedcedbf4be6725215beaa..05090cb511b29a6a47f37ce59ce1af4b6cd49a7b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt
@@ -85,4 +85,6 @@ object TimeAndDateExtensions {
     fun Instant.toLocalDate(): LocalDate = this.toDateTime(DateTimeZone.UTC).toLocalDate()
 
     fun Instant.toLocalTime(): LocalTime = this.toDateTime(DateTimeZone.UTC).toLocalTime()
+
+    val Instant.seconds get() = TimeUnit.MILLISECONDS.toSeconds(millis)
 }
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_ppa.xml b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_ppa.xml
index c3027b02364029dc3b6d420aeb2df1f0616c32fd..464d8c50f8ee5babb217b25ac47cb0f9f474a57e 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_ppa.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_ppa.xml
@@ -62,42 +62,30 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
 
-                <androidx.appcompat.widget.AppCompatImageView
-                    android:id="@+id/onboarding_illustration"
-                    android:layout_width="0dp"
-                    android:layout_height="wrap_content"
-                    android:layout_marginTop="18dp"
-                    android:contentDescription="@string/onboarding_ppa_illustration_description"
-                    android:focusable="true"
-                    app:layout_constraintEnd_toEndOf="parent"
-                    app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toTopOf="parent"
-                    app:srcCompat="@drawable/ic_illustration_ppa" />
-
                 <TextView
-                    android:id="@+id/onboarding_body"
+                    android:id="@+id/onboarding_body_short"
                     style="@style/body1"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginStart="@dimen/guideline_start"
-                    android:layout_marginTop="35dp"
+                    android:layout_marginTop="14dp"
                     android:layout_marginEnd="@dimen/guideline_end"
-                    android:contentDescription="@string/onboarding_ppa_body"
+                    android:contentDescription="@string/onboarding_ppa_body_short"
                     android:focusable="true"
-                    android:text="@string/onboarding_ppa_body"
-                    app:layout_constraintEnd_toEndOf="@id/body_end"
-                    app:layout_constraintStart_toStartOf="@id/body_start"
-                    app:layout_constraintTop_toBottomOf="@+id/onboarding_illustration" />
+                    android:text="@string/onboarding_ppa_body_short"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toTopOf="parent" />
 
                 <androidx.constraintlayout.widget.ConstraintLayout
                     android:id="@+id/federal_state_row"
                     style="@style/row"
+                    android:layout_marginTop="28dp"
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="28dp"
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toBottomOf="@+id/onboarding_body">
+                    app:layout_constraintTop_toBottomOf="@+id/onboarding_body_short">
 
                     <TextView
                         android:id="@+id/federal_state_row_subtitle"
@@ -228,16 +216,31 @@
                     app:layout_constraintStart_toStartOf="parent"
                     app:layout_constraintTop_toBottomOf="@+id/age_group_row" />
 
+                <TextView
+                    android:id="@+id/onboarding_body_long"
+                    style="@style/body1"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/guideline_start"
+                    android:layout_marginTop="31dp"
+                    android:layout_marginEnd="@dimen/guideline_end"
+                    android:contentDescription="@string/onboarding_ppa_body"
+                    android:focusable="true"
+                    android:text="@string/onboarding_ppa_body"
+                    app:layout_constraintEnd_toEndOf="@id/body_end"
+                    app:layout_constraintStart_toStartOf="@id/body_start"
+                    app:layout_constraintTop_toBottomOf="@+id/age_group_row" />
+
                 <androidx.constraintlayout.widget.ConstraintLayout
                     android:id="@+id/consent_layout"
                     style="@style/cardTracing"
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="42dp"
+                    android:layout_marginTop="32dp"
                     android:orientation="vertical"
                     app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
                     app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
-                    app:layout_constraintTop_toBottomOf="@+id/age_group_row">
+                    app:layout_constraintTop_toBottomOf="@+id/onboarding_body_long">
 
                     <TextView
                         android:id="@+id/legal_title"
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_ppa.xml b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_ppa.xml
index b0600543c04b6fef6f7b61dd53e687cd15f8d307..bd4f247b1a02d8edb40a9dec2995681519711807 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_ppa.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_ppa.xml
@@ -53,18 +53,6 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
 
-                <androidx.appcompat.widget.AppCompatImageView
-                    android:id="@+id/onboarding_illustration"
-                    android:layout_width="0dp"
-                    android:layout_height="wrap_content"
-                    android:layout_marginTop="18dp"
-                    android:contentDescription="@string/onboarding_ppa_illustration_description"
-                    android:focusable="true"
-                    app:layout_constraintEnd_toEndOf="parent"
-                    app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toTopOf="parent"
-                    app:srcCompat="@drawable/ic_illustration_ppa" />
-
                 <TextView
                     android:id="@+id/onboarding_headline"
                     style="@style/headline4"
@@ -76,21 +64,21 @@
                     android:contentDescription="@string/onboarding_ppa_headline"
                     android:focusable="true"
                     android:text="@string/onboarding_ppa_headline"
-                    app:layout_constraintEnd_toEndOf="@id/body_end"
-                    app:layout_constraintStart_toStartOf="@id/body_start"
-                    app:layout_constraintTop_toBottomOf="@+id/onboarding_illustration" />
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toTopOf="parent" />
 
                 <TextView
-                    android:id="@+id/onboarding_body"
+                    android:id="@+id/onboarding_body_short"
                     style="@style/body1"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginStart="@dimen/guideline_start"
                     android:layout_marginTop="35dp"
                     android:layout_marginEnd="@dimen/guideline_end"
-                    android:contentDescription="@string/onboarding_ppa_body"
+                    android:contentDescription="@string/onboarding_ppa_body_short"
                     android:focusable="true"
-                    android:text="@string/onboarding_ppa_body"
+                    android:text="@string/onboarding_ppa_body_short"
                     app:layout_constraintEnd_toEndOf="@id/body_end"
                     app:layout_constraintStart_toStartOf="@id/body_start"
                     app:layout_constraintTop_toBottomOf="@+id/onboarding_headline" />
@@ -103,7 +91,7 @@
                     android:layout_height="wrap_content"
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toBottomOf="@+id/onboarding_body">
+                    app:layout_constraintTop_toBottomOf="@+id/onboarding_body_short">
 
                     <TextView
                         android:id="@+id/federal_state_row_subtitle"
@@ -234,16 +222,31 @@
                     app:layout_constraintStart_toStartOf="parent"
                     app:layout_constraintTop_toBottomOf="@+id/age_group_row" />
 
+                <TextView
+                    android:id="@+id/onboarding_body_long"
+                    style="@style/body1"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/guideline_start"
+                    android:layout_marginTop="47dp"
+                    android:layout_marginEnd="@dimen/guideline_end"
+                    android:contentDescription="@string/onboarding_ppa_body"
+                    android:focusable="true"
+                    android:text="@string/onboarding_ppa_body"
+                    app:layout_constraintEnd_toEndOf="@id/body_end"
+                    app:layout_constraintStart_toStartOf="@id/body_start"
+                    app:layout_constraintTop_toBottomOf="@+id/age_group_row" />
+
                 <androidx.constraintlayout.widget.ConstraintLayout
                     android:id="@+id/consent_layout"
                     style="@style/cardTracing"
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="42dp"
+                    android:layout_marginTop="34dp"
                     android:orientation="vertical"
                     app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
                     app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
-                    app:layout_constraintTop_toBottomOf="@+id/age_group_row">
+                    app:layout_constraintTop_toBottomOf="@+id/onboarding_body_long">
 
                     <TextView
                         android:id="@+id/legal_title"
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_settings_privacy_preserving_analytics.xml b/Corona-Warn-App/src/main/res/layout/fragment_settings_privacy_preserving_analytics.xml
index 366ae243143786dcfccecbb55812dde07a48c16f..21731d367ee1d3f4849102e6fe107334e371ba31 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_settings_privacy_preserving_analytics.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_settings_privacy_preserving_analytics.xml
@@ -48,21 +48,6 @@
                     app:layout_constraintTop_toTopOf="parent"
                     app:srcCompat="@drawable/ic_illustration_ppa" />
 
-                <TextView
-                    android:id="@+id/onboarding_headline"
-                    style="@style/headline4"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginStart="@dimen/guideline_start"
-                    android:layout_marginTop="@dimen/spacing_small"
-                    android:layout_marginEnd="@dimen/guideline_end"
-                    android:contentDescription="@string/onboarding_ppa_headline"
-                    android:focusable="true"
-                    android:text="@string/onboarding_ppa_headline"
-                    app:layout_constraintEnd_toEndOf="@id/body_end"
-                    app:layout_constraintStart_toStartOf="@id/body_start"
-                    app:layout_constraintTop_toBottomOf="@+id/onboarding_illustration" />
-
                 <TextView
                     android:id="@+id/onboarding_body"
                     style="@style/body1"
@@ -76,7 +61,7 @@
                     android:text="@string/onboarding_ppa_body"
                     app:layout_constraintEnd_toEndOf="@id/body_end"
                     app:layout_constraintStart_toStartOf="@id/body_start"
-                    app:layout_constraintTop_toBottomOf="@+id/onboarding_headline" />
+                    app:layout_constraintTop_toBottomOf="@+id/onboarding_illustration" />
 
                 <include
                     android:id="@+id/settings_ppa_switch_row"
@@ -237,7 +222,7 @@
                     style="@style/cardTracing"
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="@dimen/spacing_large"
+                    android:layout_marginTop="32dp"
                     android:orientation="vertical"
                     app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
                     app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
@@ -249,9 +234,9 @@
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
                         android:layout_marginEnd="@dimen/spacing_small"
-                        android:contentDescription="@string/onboarding_ppa_consent_title"
+                        android:contentDescription="@string/ppa_onboarding_privacy_information_title"
                         android:focusable="true"
-                        android:text="@string/onboarding_ppa_consent_title"
+                        android:text="@string/ppa_onboarding_privacy_information_title"
                         app:layout_constraintEnd_toEndOf="parent"
                         app:layout_constraintStart_toStartOf="parent"
                         app:layout_constraintTop_toTopOf="parent" />
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml b/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml
index 972f77a2523ffb55b703ce6181129c8f05576f8b..430e1f7fa7a4cacd6fd4e419c02a6c5d03ab2196 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml
@@ -17,8 +17,8 @@
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/settings_tracing_container"
+        invisible="@{loggedPeriod == null || settingsTracingState == null}"
         android:layout_width="match_parent"
-        invisible="@{loggedPeriod == null || settingsTracingState== null}"
         android:layout_height="match_parent"
         android:contentDescription="@string/settings_tracing_title"
         android:focusable="true">
@@ -28,9 +28,9 @@
             style="@style/CWAToolbar.Close"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            app:layout_constraintTop_toTopOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
             app:title="@string/settings_tracing_title" />
 
         <ScrollView
@@ -88,6 +88,7 @@
                     app:layout_constraintStart_toStartOf="parent"
                     app:layout_constraintTop_toBottomOf="@id/information_details_header_headline"
                     app:showDivider="@{true}"
+                    app:status="@{settingsTracingState.isTracingSwitchChecked()}"
                     app:statusText="@{settingsTracingState.getTracingStatusText(context)}"
                     app:subtitle="@{@string/settings_tracing_title}" />
 
@@ -141,10 +142,10 @@
 
                     <include
                         android:id="@+id/settings_tracing_status_location"
+                        gone="@{!settingsTracingState.isLocationCardVisible()}"
                         layout="@layout/include_tracing_status_card_location"
                         android:layout_width="0dp"
                         android:layout_height="wrap_content"
-                        gone="@{!settingsTracingState.isLocationCardVisible()}"
                         app:buttonText="@{@string/settings_tracing_status_location_button}"
                         app:headline="@{@string/settings_tracing_status_location_headline}"
                         app:icon="@{@drawable/ic_location}"
@@ -154,10 +155,10 @@
 
                     <include
                         android:id="@+id/settings_tracing_status_bluetooth"
+                        gone="@{!settingsTracingState.isBluetoothCardVisible()}"
                         layout="@layout/include_tracing_status_card"
                         android:layout_width="0dp"
                         android:layout_height="wrap_content"
-                        gone="@{!settingsTracingState.isBluetoothCardVisible()}"
                         app:body="@{@string/settings_tracing_status_bluetooth_body}"
                         app:buttonText="@{@string/settings_tracing_status_bluetooth_button}"
                         app:headline="@{@string/settings_tracing_status_bluetooth_headline}"
@@ -169,42 +170,42 @@
                     <TextView
                         android:id="@+id/risk_details_period_logged_body_notice"
                         style="@style/subtitleMedium"
+                        gone="@{!settingsTracingState.isTracingStatusTextVisible()}"
                         android:layout_width="0dp"
                         android:layout_height="wrap_content"
                         android:layout_marginTop="@dimen/spacing_tiny"
                         android:focusable="true"
-                        gone="@{!settingsTracingState.isTracingStatusTextVisible()}"
                         android:text="@string/risk_details_information_body_period_logged"
-                        app:layout_constraintStart_toStartOf="@+id/guideline_start"
                         app:layout_constraintEnd_toStartOf="@+id/guideline_end"
+                        app:layout_constraintStart_toStartOf="@+id/guideline_start"
                         app:layout_constraintTop_toBottomOf="@+id/settings_tracing_status_bluetooth" />
 
                     <TextView
                         android:id="@+id/risk_details_period_logged_subtitle"
                         style="@style/subtitle"
+                        gone="@{!settingsTracingState.isTracingStatusTextVisible()}"
                         android:layout_width="0dp"
                         android:layout_height="wrap_content"
-                        android:layout_marginTop="@dimen/spacing_normal"
                         android:layout_marginStart="@dimen/spacing_small"
+                        android:layout_marginTop="@dimen/spacing_normal"
                         android:focusable="true"
-                        gone="@{!settingsTracingState.isTracingStatusTextVisible()}"
                         android:text="@{loggedPeriod.getRiskActiveTracingDaysInRetentionPeriodLogged(context)}"
-                        app:layout_constraintStart_toEndOf="@+id/risk_details_investigation_period_circle_progress"
                         app:layout_constraintEnd_toStartOf="@+id/guideline_end"
+                        app:layout_constraintStart_toEndOf="@+id/risk_details_investigation_period_circle_progress"
                         app:layout_constraintTop_toBottomOf="@+id/risk_details_period_logged_body_notice" />
 
                     <de.rki.coronawarnapp.ui.view.CircleProgress
                         android:id="@+id/risk_details_investigation_period_circle_progress"
+                        gone="@{!settingsTracingState.isTracingStatusTextVisible()}"
                         android:layout_width="@dimen/spacing_huge"
                         android:layout_height="@dimen/spacing_huge"
-                        gone="@{!settingsTracingState.isTracingStatusTextVisible()}"
                         android:importantForAccessibility="no"
                         app:circleWidth="@dimen/circle_large_width"
-                        app:layout_constraintTop_toTopOf="@+id/risk_details_period_logged_subtitle"
                         app:layout_constraintBottom_toBottomOf="@+id/risk_details_period_logged_subtitle"
                         app:layout_constraintStart_toStartOf="@+id/guideline_start"
+                        app:layout_constraintTop_toTopOf="@+id/risk_details_period_logged_subtitle"
                         app:progress="@{loggedPeriod.activeTracingDaysInRetentionPeriod}"
-                        app:progressColor="@{loggedPeriod.getProgressColor(context)}"/>
+                        app:progressColor="@{loggedPeriod.getProgressColor(context)}" />
 
                     <include layout="@layout/merge_guidelines_card" />
 
diff --git a/Corona-Warn-App/src/main/res/layout/new_release_info_screen_fragment.xml b/Corona-Warn-App/src/main/res/layout/new_release_info_screen_fragment.xml
index a28280e788de0f35b133d912b211aefa4a4de60b..37fffb2c75f60994682f29d81acb6cf8536f53a1 100644
--- a/Corona-Warn-App/src/main/res/layout/new_release_info_screen_fragment.xml
+++ b/Corona-Warn-App/src/main/res/layout/new_release_info_screen_fragment.xml
@@ -57,8 +57,7 @@
                     android:focusable="true"
                     android:text="@string/release_info_version_title"
                     app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toBottomOf="@id/new_release_info_illustration"
-                    tools:text="@string/release_info_version_title" />
+                    app:layout_constraintTop_toBottomOf="@id/new_release_info_illustration" />
 
                 <TextView
                     style="@style/subtitleMedium"
@@ -72,8 +71,7 @@
                     android:text="@string/release_info_version_body"
                     app:layout_constraintStart_toStartOf="parent"
                     app:layout_constraintTop_toBottomOf="@id/headline"
-                    app:layout_constraintEnd_toEndOf="parent"
-                    tools:text="@string/release_info_version_body" />
+                    app:layout_constraintEnd_toEndOf="parent" />
 
                 <androidx.recyclerview.widget.RecyclerView
                     android:id="@+id/recycler_view"
@@ -95,12 +93,11 @@
                     android:layout_height="wrap_content"
                     android:layout_margin="@dimen/spacing_normal"
                     android:focusable="true"
-                    android:text="@string/release_info_version_body"
+                    android:text="@string/new_release_bottom"
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
                     app:layout_constraintEnd_toEndOf="parent"
-                    app:layout_constraintTop_toBottomOf="@id/recycler_view"
-                    tools:text="@string/new_release_bottom" />
+                    app:layout_constraintTop_toBottomOf="@id/recycler_view" />
 
             </androidx.constraintlayout.widget.ConstraintLayout>
 
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 fa9512b0c64f03ff987f4543d2f31c87309af04b..f05ceb616eafe5dea2ba8cb70c7a7557e5b10e56 100644
--- a/Corona-Warn-App/src/main/res/values-bg/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/strings.xml
@@ -323,8 +323,8 @@
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"Ако се тествате, ще получите допълнителна информация относно процедурата за тестване в ЧЗВ."</string>
-    <!-- XTXT: Explanation screen increased risk level link label -->
-    <string name="risk_details_increased_risk_faq_link_label">"ЧЗВ: Процедура за тестване"</string>
+    <!-- XTXT: Explanation screen increased risk level link label - HAS TO MATCH the link text above -->
+    <string name="risk_details_increased_risk_faq_link_label">"ЧЗВ"</string>
     <!-- XTXT: Explains user about increased risk level: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#further_details -->
     <string name="risk_details_increased_risk_faq_url">"https://www.coronawarn.app/en/faq/#red_card_how_to_test"</string>
 
@@ -496,9 +496,9 @@
     <!-- XACT: onboarding(tracing) - illustraction description, header image -->
     <string name="onboarding_tracing_illustration_description">"Трима души са активирали регистрирането на излагания на риск и контактите им един с друг ще бъдат записани."</string>
     <!-- XHED: onboarding(tracing) - location explanation for bluetooth headline -->
-    <string name="onboarding_tracing_location_headline">"Разрешаване на достъп до данните за местоположение"</string>
+    <string name="onboarding_tracing_location_headline">"Активиране на настройките за местоположение"</string>
     <!-- XTXT: onboarding(tracing) - location explanation for bluetooth body text -->
-    <string name="onboarding_tracing_location_body">"Не може да бъде осъществен достъп до Вашето местоположение. За да използвате Bluetooth, Google и/или Android изискват от Вас да предоставите достъп до местоположението на смартфона си."</string>
+    <string name="onboarding_tracing_location_body">"Приложението не може да определи къде се намирате, но някои версии на Android изискват настройката за местоположение да бъде активирана, за да използват режима на Bluetooth с ниска консумация на енергия."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_location_button">"Към настройките на устройството"</string>
     <!-- XACT: Onboarding (test) page title -->
@@ -526,6 +526,8 @@
     <string name="onboarding_ppa_illustration_description">"Човек държи смартфон в ръка"</string>
     <!-- XHED: onboarding privacy preserving analytics (ppa) - headline -->
     <string name="onboarding_ppa_headline">"Споделяне на данни"</string>
+    <!-- XTXT: onboarding privacy preserving analytics (ppa) - body short text -->
+    <string name="onboarding_ppa_body_short">"Покажете ни как използвате приложението. Това ще ни помогне да оценим неговата ефективност."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - body text -->
     <string name="onboarding_ppa_body">"Можете да ни помогнете да подобрим приложението Corona-Warn-App, като споделите с института „Роберт Кох“ данните за Вашето използване на приложението. Това ще помогне на института да оцени ефективността му, както и да подобри функциите и удобството при неговото използване."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - state title -->
@@ -537,7 +539,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - age title -->
     <string name="onboarding_ppa_age_title">"Вашата възраст (незадължително)"</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
-    <string name="onboarding_ppa_more_info_title">"Подробна информация относно обработката на тези данни и рисковете относно защитата на данните в САЩ"</string>
+    <string name="onboarding_ppa_more_info_title">"Подробна информация относно обработката на тези данни и рисковете относно защитата на данните в САЩ и други държави."</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - donate button -->
     <string name="onboarding_ppa_consent_donate_button">"Споделяне на данни"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - dont donate button -->
@@ -550,7 +552,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - more info - title -->
     <string name="onboarding_ppa_more_info_data_processing_title">"Обработка на данните в процеса на споделяне на данни"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing body -->
-    <string name="onboarding_ppa_more_info_data_processing_body">"Ако предоставите съгласие за споделяне, приложението изпраща ежедневно различни Ваши данни до института „Роберт Кох“. Предадените данни ще бъдат анализирани за различни цели:"</string>
+    <string name="onboarding_ppa_more_info_data_processing_body">"Ако се съгласите да споделяте свои данни, приложението изпраща ежедневно такива до института „Роберт Кох“. Те ще ни помогнат да оценим ефективността на приложението, а извършеният върху тях анализ ще подпомогне следните подобрения:"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 1 -->
     <string name="onboarding_ppa_more_info_data_processing_point_1_text">"Подобряване на регистрирането на излагания - Бихме искали да подобрим точността и надеждността на техническото изчисление на рисковете от заразяване. За тази цел ще направим оценка на информацията относно излаганията на риск и предупрежденията, които виждате. Това ще ни даде възможност да подобрим метода на изчисление."</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 2 -->
@@ -1794,21 +1796,21 @@
     <string name="datadonation_details_survey_consent_details_title">"Подробна информация относно обработката на данни при участие в анкетата"</string>
 
     <!-- XHED: Dialog error title for survey request error informations 1 -->
-    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"Часът, показван от Вашия смартфон, не съответства на текущия час. Моля, коригирайте това в настройките на устройството си. Код на грешката: {0}."</string>
+    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"Часът, показван от Вашия смартфон, не съответства на текущия час. Моля, коригирайте това в настройките на устройството. Код на грешката: %1$s."</string>
     <!-- XHED: Dialog error title for survey request error informations 2-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"Анкетата не може да бъде извлечена. Код на грешката: {0}."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"Анкетата не може да бъде извлечена. Код на грешката: %1$s."</string>
     <!-- XHED: Dialog error title for survey request error informations 3-->
-    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"Анкетата не може да бъде извлечена в момента. Моля, актуализирайте Google Play Services. Код на грешката: {0}."</string>
+    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"Анкетата не може да бъде извлечена в момента. Моля, актуализирайте Google Play Services. Код на грешката: %1$s."</string>
     <!-- XHED: Dialog error title for survey request error informations 4-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"Анкетата не може да бъде извлечена в момента. Моля, опитайте по-късно. Код на грешката: {0}."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"Анкетата не може да бъде извлечена в момента. Моля, опитайте по-късно. Код на грешката: %1$s."</string>
     <!-- XHED: Dialog error title for survey request error informations 5-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"Анкетата не може да бъде извлечена поради причини, свързани със сигурността. Може да попълните анкетата отново през следващия календарен месец. Код на грешката: {0}."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"Анкетата не може да бъде извлечена поради причини, свързани със сигурността. Може да попълните анкетата отново през следващия календарен месец. Код на грешката: %1$s."</string>
     <!-- XHED: Dialog error title for survey request error informations 6-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Анкетата не може да бъде извлечена на Вашето устройство. Код на грешката: {0}."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Благодарим Ви, че се опитахте да помогнете! За съжаление, използвате устройство, което по технически причини не поддържа анкетното проучване. Код на грешката: %1$s."</string>
     <!-- XHED: Dialog error title for survey request error informations 7-->
-    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"От съображения за сигурност можете да участвате в анкетата най-рано 24 часа, след като инсталирате или актуализирате приложението. Код на грешката: {0}."</string>
+    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"От съображения за сигурност можете да участвате в анкетата най-рано 24 часа, след като инсталирате или актуализирате приложението. Код на грешката: %1$s"</string>
     <!-- XHED: Dialog error title for survey request error informations 8-->
-    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"Вече сте попълнили анкетата. Може да правите това само веднъж месечно. Код на грешката: {0}."</string>
+    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"Вече сте попълнили анкетата. Може да правите това само веднъж месечно. Код на грешката: %1$s."</string>
 
     <!-- XHED: Dialog error title for survey request error informations dialog-->
     <string name="datadonation_details_survey_consent_error_dialog_title">"Грешка"</string>
diff --git a/Corona-Warn-App/src/main/res/values-de/legal_strings.xml b/Corona-Warn-App/src/main/res/values-de/legal_strings.xml
index aae4f6bd89d5973fb6657c6b76e503a0a2f61b08..de6248a18b15efc04b890a2fe7e2beca24aee64d 100644
--- a/Corona-Warn-App/src/main/res/values-de/legal_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/legal_strings.xml
@@ -53,7 +53,7 @@
     <!-- XHED: Title for the consent displayed above the button in the survey consent screen -->
     <string name="datadonation_details_survey_consent_info_card_title">"Ihr Einverständnis"</string>
     <!-- XTXT: Text for the consent body displayed above the button in the survey consent screen -->
-    <string name="datadonation_details_survey_consent_info_card_body">"Durch Antippen von „Einverstanden“ willigen Sie ein:\n\nBevor Ihnen der Teilnahmelink angezeigt werden kann, wird die Echtheit Ihrer App hierbei einmalig geprüft. Dazu wird durch Ihr Smartphone eine eindeutige Kennung erzeugt und an Google in die USA übermittelt, damit Google die Echtheit Ihrer App gegenüber dem RKI bestätigen kann. Die Kennung enthält Informationen über die Version Ihres Smartphones und der App. Weitere Angaben aus der App erhält Google  hierbei nicht. So wird sichergestellt, dass jeder Nutzer nur einmal an der Befragung teilnehmen kann und die Statistiken nicht verfälscht werden."</string>
+    <string name="datadonation_details_survey_consent_info_card_body">"Durch Antippen von „Einverstanden“ willigen Sie ein:\n\nBevor Ihnen der Teilnahmelink angezeigt werden kann, wird die Echtheit Ihrer App hierbei einmalig geprüft. Dazu wird durch Ihr Smartphone eine eindeutige Kennung erzeugt und an Google in die USA oder andere Drittländer übermittelt, damit Google die Echtheit Ihrer App gegenüber dem RKI bestätigen kann. Die Kennung enthält Informationen über die Version Ihres Smartphones und der App. Google kann damit möglicherweise auf Ihre Identität schließen und nachvollziehen, dass die Echtheitsprüfung Ihres Smartphones stattgefunden hat. Weitere Angaben aus der App erhält Google hierbei nicht. So wird sichergestellt, dass jeder Nutzer nur einmal an der Befragung teilnehmen kann und die Statistiken nicht verfälscht werden."</string>
     <!-- XTXT: First bullet point in the consent body displayed above the button in the survey consent screen -->
     <string name="datadonation_details_survey_consent_bullet_point_one">"Ihr Einverständnis ist freiwillig. Sie können die App vollständig nutzen, auch wenn Sie Ihr Einverständnis für die Zwecke der Befragung nicht erteilen."</string>
     <!-- XTXT: Second bullet point in the consent body displayed above the button in the survey consent screen -->
@@ -65,23 +65,25 @@
     <!-- XHED: Title for the information box in the survey consent detail screen -->
     <string name="datadonation_survey_consent_details_title">"Prüfung der Echtheit und Drittlandsübermittlung"</string>
     <!-- XTXT: Text for the information box in the survey consent detail screen -->
-    <string name="datadonation_survey_consent_details_text">"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 zu verhindern, dass Nutzer mehrfach der Befragung teilnehmen und so die Ergebnisse der Befragung verfälschen. Die Kennung wird hier einmalig an Google übermittelt. Dabei kann es auch zu einer Datenübermittlung in die USA kommen. Dort besteht kein dem europäischen Recht angemessenes Datenschutzniveau und Ihre europäischen Datenschutzrechte können eventuell nicht durchgesetzt werden. Insbesondere besteht die Möglichkeit, dass US-Sicherheitsbehörden, 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 weiteren Angaben über Ihre Teilnahme an der Befragung erhält Google nicht. Wenn Sie mit der Drittlandsübermittlung nicht einverstanden sind, tippen Sie bitte nicht „Einverstanden“ an. Sie können die App weiterhin nutzen, eine Teilnahme an dieser Befragung ist dann jedoch nicht möglich."</string>
+    <string name="datadonation_survey_consent_details_text">"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 zu verhindern, dass Nutzer mehrfach der Befragung teilnehmen und so die Ergebnisse der Befragung verfälschen. Die Kennung wird hier 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 weiteren Angaben über Ihre Teilnahme an der Befragung 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.\n\nWenn Sie mit der Drittlandsübermittlung nicht einverstanden sind, tippen Sie bitte nicht „Einverstanden“ an. Sie können die App weiterhin nutzen, eine Teilnahme an dieser Befragung ist dann jedoch nicht möglich."</string>
 
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
     <string name="ppa_onboarding_consent_title" translatable="false">"Ihr Einverständnis"</string>
     <!-- XTXT: Body for Privacy-preserving Analytics onboarding -->
-    <string name="ppa_onboarding_privacy_information_body" translatable="false">"Indem Sie oben „Datenspende“ aktivieren, willigen Sie ein:\n\nDie App übermittelt täglich von ihr erfasste Angaben an das RKI. Die Daten betreffen angezeigte Risiko-Begegnungen und Warnungen, durch Sie abgerufene Testergebnisse, ob Sie andere Nutzer gewarnt haben sowie Angaben über das Betriebssystem Ihres Smartphones. Wenn Sie oben weitere Angaben gemacht haben (Region, Altersgruppe), werden auch diese an das RKI übermittelt.\n\nDas RKI wird diese Daten zu Statistiken zusammenfassen und auswerten, um die Wirksamkeit und Funktionsweise der App zu bewerten und Rückschlüsse auf das Pandemiegeschehen zu ziehen. Die dabei gefundenen Erkenntnisse helfen bei der Verbesserung der Funktionen und Nutzerfreundlichkeit der App sowie bei der Steuerung anderer Maßnahmen der Pandemiebekämpfung.\n\nBevor Ihre Daten ausgewertet werden, muss sichergestellt sein, dass jede an der Datenspende teilnehmende App nur einmal gezählt wird und die Statistiken nicht verfälscht werden. Hierfür muss die Echtheit Ihrer App geprüft werden. Dazu wird durch Ihr Smartphone eine eindeutige Kennung erzeugt und an Google in die USA übermittelt, damit Google die Echtheit Ihrer App gegenüber dem RKI bestätigen kann. Die Kennung enthält Informationen über die Version Ihres Smartphones und der App. Weitere Angaben aus der App erhält Google hierbei nicht.\n\nSie können Ihr Einverständnis jederzeit zurücknehmen, indem Sie „Daten spenden" in den Einstellungen der App deaktivieren."</string>
+    <string name="ppa_onboarding_privacy_information_body" translatable="false">"Indem Sie „Datenspende“ aktivieren, willigen Sie ein:\n\nDie App übermittelt täglich von ihr erfasste Angaben an das RKI. Die Daten betreffen angezeigte Risiko-Begegnungen und Warnungen, durch Sie abgerufene Testergebnisse, ob Sie andere Nutzer gewarnt haben sowie Angaben über das Betriebssystem Ihres Smartphones. Wenn Sie oben weitere Angaben gemacht haben (Region, Altersgruppe), werden auch diese an das RKI übermittelt.\n\nDas RKI wird diese Daten zu Statistiken zusammenfassen und auswerten, um die Wirksamkeit und Funktionsweise der App zu bewerten und Rückschlüsse auf das Pandemiegeschehen zu ziehen. Die dabei gefundenen Erkenntnisse helfen bei der Verbesserung der Funktionen und Nutzerfreundlichkeit der App sowie bei der Steuerung anderer Maßnahmen der Pandemiebekämpfung.\n\nBevor Ihre Daten ausgewertet werden, muss sichergestellt sein, dass jede an der Datenspende teilnehmende App nur einmal gezählt wird und die Statistiken nicht verfälscht werden. Hierfür muss die Echtheit Ihrer App geprüft werden. Dazu wird durch Ihr Smartphone eine eindeutige Kennung erzeugt und an Google in die USA oder andere Drittländer übermittelt, damit Google die Echtheit Ihrer App gegenüber dem RKI bestätigen kann. Die Kennung enthält Informationen über die Version Ihres Smartphones und der App. Google kann damit möglicherweise auf Ihre Identität schließen und nachvollziehen, dass die Echtheitsprüfung Ihres Smartphones stattgefunden hat. Weitere Angaben aus der App erhält Google hierbei nicht.\n\nSie können Ihr Einverständnis jederzeit zurücknehmen, indem Sie „Daten spenden" in den Einstellungen der App deaktivieren."</string>
     <!-- XTXT: Body point consent for Privacy-preserving Analytics -->
-    <string name="ppa_onboarding_privacy_information_point_consent" translatable="false">"Ihr Einverständnis ist freiwillig. Sie können die App auch nutzen, wenn Sie Ihr Einverständnis nicht erteilen."</string>
+    <string name="ppa_onboarding_privacy_information_point_consent" translatable="false">"Ihr Einverständnis ist freiwillig. Sie können die App auch nutzen, wenn Sie Ihr Einverständnis nicht erteilt haben."</string>
     <!-- XTXT: Body point identity for Privacy-preserving Analytics -->
-    <string name="ppa_onboarding_privacy_information_point_identity" translatable="false">"Wenn Sie Daten über Ihre App-Nutzung spenden, bleibt Ihre Identität weiterhin geschützt. Das RKI erfährt also nicht, wer Sie sind oder wen Sie getroffen haben. Es werden auch keine Profile gebildet."</string>
+    <string name="ppa_onboarding_privacy_information_point_identity" translatable="false">"Wenn Sie Daten über Ihre App-Nutzung spenden, bleibt Ihre Identität gegenüber dem RKI weiterhin geschützt. Das RKI erfährt also nicht, wer Sie sind oder wen Sie getroffen haben. Es werden auch keine Profile gebildet."</string>
     <!-- XTXT: Body point sixteen for Privacy-preserving Analytics -->
     <string name="ppa_onboarding_privacy_information_point_sixteen" translatable="false">"Sie können Ihr Einverständnis abgeben, wenn Sie mindestens 16 Jahre alt sind."</string>
     <!-- XHED: Title for Privacy-preserving Analytics additional info  -->
     <string name="ppa_onboarding_more_info_title" translatable="false">"Prüfung der Echtheit und Drittlandsübermittlung"</string>
     <!-- XTXT: Body for Privacy-preserving Analytics additional info -->
-    <string name="ppa_onboarding_more_info_body" translatable="false">"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 zu verhindern, dass Nutzer mehrfach der Befragung teilnehmen und so die Ergebnisse der Befragung verfälschen. Die Kennung wird hier einmalig an Google übermittelt. Dabei kann es auch zu einer Datenübermittlung in die USA kommen. Dort besteht kein dem europäischen Recht angemessenes Datenschutzniveau und Ihre europäischen Datenschutzrechte können eventuell nicht durchgesetzt werden. Insbesondere besteht die Möglichkeit, dass US-Sicherheitsbehörden, 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 weiteren Angaben über Ihre Teilnahme an der Befragung erhält Google nicht.\nWenn Sie mit der Drittlandsübermittlung nicht einverstanden sind, tippen Sie bitte nicht „Einverstanden“ an. Sie können die App weiterhin nutzen, eine Teilnahme an dieser Befragung ist dann jedoch nicht möglich."</string>
+    <string name="ppa_onboarding_more_info_body" translatable="false">"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 zu verhindern, dass Nutzer mehrfach der Befragung teilnehmen und so die Ergebnisse der Befragung verfälschen. Die Kennung wird hier 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 weiteren Angaben über Ihre Teilnahme an der Befragung 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.\n\nWenn Sie mit der Drittlandsübermittlung nicht einverstanden sind, tippen Sie bitte nicht „Einverstanden“ an. Sie können die App weiterhin nutzen, eine Teilnahme an dieser Befragung ist dann jedoch nicht möglich."</string>
+    <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
+    <string name="ppa_onboarding_privacy_information_title" translatable="false">"Ihr Einverständnis"</string>
     <!-- XTXT: Body for Privacy-preserving Analytics settings -->
-    <string name="ppa_settings_privacy_information_body" translatable="false">"Indem Sie oben „Datenspende“ aktivieren, willigen Sie ein:\n\nDie App übermittelt täglich von ihr erfasste Angaben an das RKI. Die Daten betreffen angezeigte Risiko-Begegnungen und Warnungen, durch Sie abgerufene Testergebnisse, ob Sie andere Nutzer gewarnt haben sowie Angaben über das Betriebssystem Ihres Smartphones. Wenn Sie oben weitere Angaben gemacht haben (Region, Altersgruppe), werden auch diese an das RKI übermittelt.\n\nDas RKI wird diese Daten zu Statistiken zusammenfassen und auswerten, um die Wirksamkeit und Funktionsweise der App zu bewerten und Rückschlüsse auf das Pandemiegeschehen zu ziehen. Die dabei gefundenen Erkenntnisse helfen bei der Verbesserung der Funktionen und Nutzerfreundlichkeit der App sowie bei der Steuerung anderer Maßnahmen der Pandemiebekämpfung.\n\nBevor Ihre Daten ausgewertet werden, muss sichergestellt sein, dass jede an der Datenspende teilnehmende App nur einmal gezählt wird und die Statistiken nicht verfälscht werden. Hierfür muss die Echtheit Ihrer App geprüft werden. Dazu wird durch Ihr Smartphone eine eindeutige Kennung erzeugt und an Google in die USA übermittelt, damit Google die Echtheit Ihrer App gegenüber dem RKI bestätigen kann. Die Kennung enthält Informationen über die Version Ihres Smartphones und der App. Weitere Angaben aus der App erhält Google hierbei nicht.\n\nSie können Ihr Einverständnis jederzeit zurücknehmen, indem Sie oben „Datenspende“ deaktivieren."</string>
+    <string name="ppa_settings_privacy_information_body" translatable="false">"Indem Sie oben „Datenspende“ aktivieren, willigen Sie ein:\n\nDie App übermittelt täglich von ihr erfasste Angaben an das RKI. Die Daten betreffen angezeigte Risiko-Begegnungen und Warnungen, durch Sie abgerufene Testergebnisse, ob Sie andere Nutzer gewarnt haben sowie Angaben über das Betriebssystem Ihres Smartphones. Wenn Sie oben weitere Angaben gemacht haben (Region, Altersgruppe), werden auch diese an das RKI übermittelt.\n\nDas RKI wird diese Daten zu Statistiken zusammenfassen und auswerten, um die Wirksamkeit und Funktionsweise der App zu bewerten und Rückschlüsse auf das Pandemiegeschehen zu ziehen. Die dabei gefundenen Erkenntnisse helfen bei der Verbesserung der Funktionen und Nutzerfreundlichkeit der App sowie bei der Steuerung anderer Maßnahmen der Pandemiebekämpfung.\n\nBevor Ihre Daten ausgewertet werden, muss sichergestellt sein, dass jede an der Datenspende teilnehmende App nur einmal gezählt wird und die Statistiken nicht verfälscht werden. Hierfür muss die Echtheit Ihrer App geprüft werden. Dazu wird durch Ihr Smartphone eine eindeutige Kennung erzeugt und an Google in die USA oder andere Drittländer übermittelt, damit Google die Echtheit Ihrer App gegenüber dem RKI bestätigen kann. Die Kennung enthält Informationen über die Version Ihres Smartphones und der App. Google kann damit möglicherweise auf Ihre Identität schließen und nachvollziehen, dass die Echtheitsprüfung Ihres Smartphones stattgefunden hat.\nWeitere Angaben aus der App erhält Google hierbei nicht.\n\nSie können Ihr Einverständnis jederzeit zurücknehmen, indem Sie oben „Datenspende“ deaktivieren."</string>
 
 </resources>
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 642286debd8608ede12626707e795f8c710fd91d..baa753516352ada5d7007222af7e080782478cba 100644
--- a/Corona-Warn-App/src/main/res/values-de/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/strings.xml
@@ -324,7 +324,7 @@
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"Falls Sie sich testen lassen, finden Sie weitere Informationen in der FAQ zum Testablauf."</string>
-    <!-- XTXT: Explanation screen increased risk level link label -->
+    <!-- XTXT: Explanation screen increased risk level link label - HAS TO MATCH the link text above -->
     <string name="risk_details_increased_risk_faq_link_label">"FAQ zum Testablauf"</string>
     <!-- XTXT: Explains user about increased risk level: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#further_details -->
     <string name="risk_details_increased_risk_faq_url">"https://www.coronawarn.app/de/faq/#red_card_how_to_test"</string>
@@ -523,12 +523,12 @@
     <!-- XACT: onboarding(notifications) - illustraction description, header image -->
     <string name="onboarding_notifications_illustration_description">"Eine Frau erhält eine Mitteilung von ihrer Corona-Warn-App."</string>
 
-    <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
-    <string name="onboarding_ppa_consent_title">"Ihr Einverständnis"</string>
     <!-- XACT: onboarding privacy preserving analytics (ppa) - illustraction description, header image -->
     <string name="onboarding_ppa_illustration_description">"Darstellung einer Person, die ihr Smartphone in der Hand hält"</string>
     <!-- XHED: onboarding privacy preserving analytics (ppa) - headline -->
     <string name="onboarding_ppa_headline">"Datenspende"</string>
+    <!-- XTXT: onboarding privacy preserving analytics (ppa) - body short text -->
+    <string name="onboarding_ppa_body_short">"Teilen Sie Daten über Ihre App-Nutzung mit uns und helfen Sie uns so, die Wirksamkeit der App zu bewerten."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - body text -->
     <string name="onboarding_ppa_body">"Sie können uns helfen, die Corona-Warn-App zu verbessern. Teilen Sie Daten über Ihre App-Nutzung mit dem RKI. Sie helfen damit dem RKI bei der Bewertung der Wirksamkeit der App. Ihre Daten ermöglichen außerdem, die Funktionen und Nutzerfreundlichkeit der App zu verbessern."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - state title -->
@@ -540,7 +540,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - age title -->
     <string name="onboarding_ppa_age_title">"Ihr Alter (optional)"</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
-    <string name="onboarding_ppa_more_info_title">"Ausführliche Informationen zu dieser Datenverarbeitung und den Datenschutzrisiken in den USA"</string>
+    <string name="onboarding_ppa_more_info_title">"Ausführliche Informationen zu dieser Datenverarbeitung und den Datenschutzrisiken in den USA und anderen Drittländern"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - donate button -->
     <string name="onboarding_ppa_consent_donate_button">"Daten spenden"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - dont donate button -->
@@ -553,7 +553,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - more info - title -->
     <string name="onboarding_ppa_more_info_data_processing_title">"Datenverarbeitung im Rahmen der Datenspende"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing body -->
-    <string name="onboarding_ppa_more_info_data_processing_body">"Im Rahmen der Datenspende übermittelt die App verschiedene Daten täglich an das RKI. Die übermittelten Daten werden zu unterschiedlichen Zwecken ausgewertet:"</string>
+    <string name="onboarding_ppa_more_info_data_processing_body">"Im Rahmen der Datenspende übermittelt die App verschiedene Daten täglich an das RKI. Die übermittelten Daten dienen der Bewertung der Wirksamkeit der App und sie werden ausgewertet, um folgende Verbesserungen zu ermöglichen:"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 1 -->
     <string name="onboarding_ppa_more_info_data_processing_point_1_text">"Verbesserung der Risiko-Ermittlung – Die Genauigkeit und Zuverlässigkeit der technischen Berechnung der Ansteckungsrisiken sollen verbessert werden. Hierfür werden Angaben über Risiko-Begegnungen und Ihnen angezeigte Warnungen ausgewertet. In der Folge kann die Berechnungsmethode verfeinert werden."</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 2 -->
@@ -1797,21 +1797,21 @@
     <string name="datadonation_details_survey_consent_details_title">"Ausführliche Informationen zur Datenverarbeitung bei der Teilnahme an der Befragung"</string>
 
     <!-- XHED: Dialog error title for survey request error informations 1 -->
-    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"Die Uhrzeit Ihres Smartphones stimmt nicht mit der aktuellen Zeit überein. Bitte korrigieren Sie die Uhrzeit in den Einstellungen Ihres Smartphones (Fehlercode {0})."</string>
+    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"Die Uhrzeit Ihres Smartphones stimmt nicht mit der aktuellen Zeit überein. Bitte korrigieren Sie die Uhrzeit in den Einstellungen Ihres Smartphones (Fehlercode %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 2-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"Die Befragung kann nicht aufgerufen werden (Fehlercode {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"Die Befragung kann nicht aufgerufen werden (Fehlercode %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 3-->
-    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"Die Befragung kann aktuell nicht aufgerufen werden. Bitte aktualisieren Sie die Google Play Services (Fehlercode {0})."</string>
+    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"Die Befragung kann aktuell nicht aufgerufen werden. Bitte aktualisieren Sie die Google Play Services (Fehlercode %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 4-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"Die Befragung kann aktuell nicht aufgerufen werden. Bitte versuchen Sie es später noch mal (Fehlercode {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"Die Befragung kann aktuell nicht aufgerufen werden. Bitte versuchen Sie es später noch mal (Fehlercode %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 5-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"Die Befragung konnte aus Sicherheitsgründen nicht aufgerufen werden. Sie können im nächsten Kalendermonat wieder teilnehmen (Fehlercode {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"Die Befragung konnte aus Sicherheitsgründen nicht aufgerufen werden. Sie können im nächsten Kalendermonat wieder teilnehmen (Fehlercode %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 6-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Danke, dass Sie mithelfen wollen. Leider verwenden Sie ein Smartphone, mit dem Sie aus technischen Gründen nicht an der Umfrage teilnehmen können. (Fehlercode {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Danke, dass Sie mithelfen wollen. Leider verwenden Sie ein Smartphone, mit dem Sie aus technischen Gründen nicht an der Umfrage teilnehmen können. (Fehlercode %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 7-->
-    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"Aus Sicherheitsgründen können Sie erst 24 Stunden, nachdem Sie die App installiert oder aktualisiert haben, an der Befragung teilnehmen (Fehlercode {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"Aus Sicherheitsgründen können Sie erst 24 Stunden, nachdem Sie die App installiert oder aktualisiert haben, an der Befragung teilnehmen (Fehlercode %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 8-->
-    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"Sie haben bereits an der Befragung teilgenommen. Sie können nur einmal im Monat an der Befragung teilnehmen (Fehlercode {0})."</string>
+    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"Sie haben bereits an der Befragung teilgenommen. Sie können nur einmal im Monat an der Befragung teilnehmen (Fehlercode %1$s)."</string>
 
     <!-- XHED: Dialog error title for survey request error informations dialog-->
     <string name="datadonation_details_survey_consent_error_dialog_title">"Fehler"</string>
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 8cf84fc5222ac19b312f61dc30d0f1cf97495abd..0330f3c7b7f0bab25bccdc3ad621f791477b9178 100644
--- a/Corona-Warn-App/src/main/res/values-en/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/strings.xml
@@ -323,8 +323,8 @@
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"If you get tested, you will find additional information about the testing procedure in the FAQ."</string>
-    <!-- XTXT: Explanation screen increased risk level link label -->
-    <string name="risk_details_increased_risk_faq_link_label">"FAQ: Testing Procedure"</string>
+    <!-- XTXT: Explanation screen increased risk level link label - HAS TO MATCH the link text above -->
+    <string name="risk_details_increased_risk_faq_link_label">"FAQ"</string>
     <!-- XTXT: Explains user about increased risk level: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#further_details -->
     <string name="risk_details_increased_risk_faq_url">"https://www.coronawarn.app/en/faq/#red_card_how_to_test"</string>
 
@@ -339,7 +339,7 @@
     <!-- XHED: risk details - infection risk headline, below behaviors -->
     <string name="risk_details_headline_infection_risk">"Risk of Infection"</string>
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
-    <string name="risk_details_headline_period_logged">"Period logged"</string>
+    <string name="risk_details_headline_period_logged">"Period Logged"</string>
     <!-- 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 -->
@@ -496,9 +496,9 @@
     <!-- XACT: onboarding(tracing) - illustraction description, header image -->
     <string name="onboarding_tracing_illustration_description">"Three persons have activated exposure logging on their smartphones, which will log their encounters with each other."</string>
     <!-- XHED: onboarding(tracing) - location explanation for bluetooth headline -->
-    <string name="onboarding_tracing_location_headline">"Allow location access"</string>
+    <string name="onboarding_tracing_location_headline">"Activate Location Setting"</string>
     <!-- XTXT: onboarding(tracing) - location explanation for bluetooth body text -->
-    <string name="onboarding_tracing_location_body">"Your location cannot be accessed. Google and/or Android requires access to your smartphone’s location to use Bluetooth."</string>
+    <string name="onboarding_tracing_location_body">"Your device location cannot be determined by the app, but the device location setting must be activated to use Bluetooth Low Energy in some Android versions."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_location_button">"Open Device Settings"</string>
     <!-- XACT: Onboarding (test) page title -->
@@ -526,6 +526,8 @@
     <string name="onboarding_ppa_illustration_description">"A person is holding a smartphone in their hand"</string>
     <!-- XHED: onboarding privacy preserving analytics (ppa) - headline -->
     <string name="onboarding_ppa_headline">"Share Data"</string>
+    <!-- XTXT: onboarding privacy preserving analytics (ppa) - body short text -->
+    <string name="onboarding_ppa_body_short">"Let us know how you use the app and help us to assess its effectiveness."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - body text -->
     <string name="onboarding_ppa_body">"You can help us to improve the Corona-Warn-App. Share the data about your app usage with the RKI. This will help the RKI assess the app’s effectiveness. Your data will also help to improve the features and usability of the app."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - state title -->
@@ -537,7 +539,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - age title -->
     <string name="onboarding_ppa_age_title">"Your age (optional)"</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
-    <string name="onboarding_ppa_more_info_title">"Detailed Information about This Data Processing and Data Protection Risks in the U.S."</string>
+    <string name="onboarding_ppa_more_info_title">"Detailed Information about This Data Processing and Data Protection Risks in the U.S. and Other Third Countries"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - donate button -->
     <string name="onboarding_ppa_consent_donate_button">"Share Data"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - dont donate button -->
@@ -550,7 +552,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - more info - title -->
     <string name="onboarding_ppa_more_info_data_processing_title">"Data Processing in the Data Sharing Process"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing body -->
-    <string name="onboarding_ppa_more_info_data_processing_body">"If you consent to share your data, the app sends various data to the RKI each day. The transmitted data will be analyzed for a variety of purposes:"</string>
+    <string name="onboarding_ppa_more_info_data_processing_body">"If you consent to share your data, the app sends various data to the RKI each day. The transmitted data will help us assess the effectiveness of the app and will be analyzed to support the following improvements:"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 1 -->
     <string name="onboarding_ppa_more_info_data_processing_point_1_text">"Improved exposure logging – We want to improve the accuracy and reliability of the technical calculation of infection risks. To do so, we will evaluate information about risk exposures and the warnings you see. As a result, we will be able to refine the calculation method."</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 2 -->
@@ -1794,21 +1796,21 @@
     <string name="datadonation_details_survey_consent_details_title">"Detailed Information on Data Processing Involved in Taking the Survey"</string>
 
     <!-- XHED: Dialog error title for survey request error informations 1 -->
-    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"The time on your smartphone does not match the current time. Please correct the time in your smartphone settings (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"The time on your smartphone does not match the current time. Please correct the time in your smartphone settings (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 2-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"The survey cannot be retrieved (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"The survey cannot be retrieved (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 3-->
-    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"The survey cannot be retrieved right now. Please update the Google Play Services (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"The survey cannot be retrieved right now. Please update the Google Play Services (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 4-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"The survey cannot be retrieved right now. Please try again later (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"The survey cannot be retrieved right now. Please try again later (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 5-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"The survey cannot be retrieved due to security reasons. You can take the survey again in the next calendar month (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"The survey cannot be retrieved due to security reasons. You can take the survey again in the next calendar month (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 6-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"The survey could not be retrieved on your smartphone (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Thank you for wanting to help. Unfortunately, you use a smartphone that does not support the survey for technical reasons (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 7-->
-    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"For security reasons, you cannot take the survey less than 24 hours after you install or update the app (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"For security reasons, you cannot take the survey less than 24 hours after you install or update the app (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 8-->
-    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"You have already taken the survey. You can only take the survey once per month (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"You have already taken the survey. You can only take the survey once per month (error code %1$s)."</string>
 
     <!-- XHED: Dialog error title for survey request error informations dialog-->
     <string name="datadonation_details_survey_consent_error_dialog_title">"Error"</string>
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 0223e645bd3251a38d72f15a671e15062e66eddd..51bc65f9f9367f7eb5203b610216feb3ef871ec3 100644
--- a/Corona-Warn-App/src/main/res/values-pl/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/strings.xml
@@ -323,8 +323,8 @@
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"Jeśli poddasz się testowi, dodatkowe informacje na temat procedury testowania znajdziesz w „Często zadawanych pytaniach”."</string>
-    <!-- XTXT: Explanation screen increased risk level link label -->
-    <string name="risk_details_increased_risk_faq_link_label">"Często zadawane pytania: Procedura testowania"</string>
+    <!-- XTXT: Explanation screen increased risk level link label - HAS TO MATCH the link text above -->
+    <string name="risk_details_increased_risk_faq_link_label">"Często zadawanych pytaniach"</string>
     <!-- XTXT: Explains user about increased risk level: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#further_details -->
     <string name="risk_details_increased_risk_faq_url">"https://www.coronawarn.app/en/faq/#red_card_how_to_test"</string>
 
@@ -496,9 +496,9 @@
     <!-- XACT: onboarding(tracing) - illustraction description, header image -->
     <string name="onboarding_tracing_illustration_description">"Trzy osoby aktywowały rejestrowanie narażenia na swoich smartfonach, które będą rejestrować ich wzajemne kontakty."</string>
     <!-- XHED: onboarding(tracing) - location explanation for bluetooth headline -->
-    <string name="onboarding_tracing_location_headline">"Zezwól na dostęp do lokalizacji"</string>
+    <string name="onboarding_tracing_location_headline">"Aktywuj ustawienie lokalizacji"</string>
     <!-- XTXT: onboarding(tracing) - location explanation for bluetooth body text -->
-    <string name="onboarding_tracing_location_body">"Nie można uzyskać dostępu do Twojej lokalizacji. Google i/lub Android wymaga dostępu do lokalizacji Twojego smartfona w celu użycia Bluetooth."</string>
+    <string name="onboarding_tracing_location_body">"Aplikacja nie może ustalić lokalizacji urządzenia, której ustawienie musi być aktywowane w niektórych wersjach Androida, aby możliwe było korzystanie z technologii Bluetooth Low Energy."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_location_button">"Otwórz ustawienia urządzenia"</string>
     <!-- XACT: Onboarding (test) page title -->
@@ -526,6 +526,8 @@
     <string name="onboarding_ppa_illustration_description">"Osoba trzyma w dłoni smartfon"</string>
     <!-- XHED: onboarding privacy preserving analytics (ppa) - headline -->
     <string name="onboarding_ppa_headline">"Udostępnij dane"</string>
+    <!-- XTXT: onboarding privacy preserving analytics (ppa) - body short text -->
+    <string name="onboarding_ppa_body_short">"Podziel się z nami informacjami na temat korzystania z aplikacji i pomóż nam ocenić jej skuteczność."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - body text -->
     <string name="onboarding_ppa_body">"Możesz pomóc nam ulepszyć aplikację Corona-Warn-App. Udostępnij dane o korzystaniu z aplikacji instytutowi RKI, który będzie mógł wówczas ocenić jej skuteczność. Twoje dane pomogą również ulepszyć funkcje i użyteczność tej aplikacji."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - state title -->
@@ -537,7 +539,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - age title -->
     <string name="onboarding_ppa_age_title">"Twój wiek (opcjonalnie)"</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
-    <string name="onboarding_ppa_more_info_title">"Szczegółowe informacje o ryzyku związanym z przetwarzaniem i ochroną danych w USA"</string>
+    <string name="onboarding_ppa_more_info_title">"Szczegółowe informacje o ryzyku związanym z przetwarzaniem i ochroną danych w USA i innych krajach trzecich"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - donate button -->
     <string name="onboarding_ppa_consent_donate_button">"Udostępnij dane"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - dont donate button -->
@@ -550,7 +552,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - more info - title -->
     <string name="onboarding_ppa_more_info_data_processing_title">"Przetwarzanie danych w procesie udostępniania danych"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing body -->
-    <string name="onboarding_ppa_more_info_data_processing_body">"Jeśli wyrazisz zgodę na udostępnienie swoich danych, aplikacja będzie codziennie wysyłać różne dane do RKI. Przekazane dane będą analizowane w różnych celach:"</string>
+    <string name="onboarding_ppa_more_info_data_processing_body">"Jeśli wyrazisz zgodę na udostępnienie swoich danych, aplikacja będzie codziennie wysyłać różne dane do RKI. Przesłane dane pomogą nam ocenić skuteczność aplikacji i będą analizowane w celu wprowadzenia następujących ulepszeń:"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 1 -->
     <string name="onboarding_ppa_more_info_data_processing_point_1_text">"Ulepszone rejestrowanie narażenia – Chcemy poprawić dokładność i wiarygodność technicznych obliczeń ryzyka zakażenia. Aby to osiągnąć, będziemy analizować otrzymywane przez Ciebie informacje o narażeniu na ryzyko i ostrzeżenia. Pozwoli to nam udoskonalić metodę obliczeń."</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 2 -->
@@ -1794,21 +1796,21 @@
     <string name="datadonation_details_survey_consent_details_title">"Szczegółowe informacje na temat przetwarzania danych związanego z ankietą"</string>
 
     <!-- XHED: Dialog error title for survey request error informations 1 -->
-    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"Czas na Twoim smartfonie nie zgadza się z aktualnym czasem. Popraw czas w ustawieniach swojego smartfona (kod błędu {0})."</string>
+    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"Czas na Twoim smartfonie nie zgadza się z aktualnym czasem. Popraw czas w ustawieniach swojego smartfona (kod błędu %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 2-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"Nie można pobrać ankiety (kod błędu {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"Nie można pobrać ankiety (kod błędu %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 3-->
-    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"W tej chwili nie można pobrać ankiety. Zaktualizuj usługi Google Play (kod błędu {0})."</string>
+    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"W tej chwili nie można pobrać ankiety. Zaktualizuj usługi Google Play (kod błędu %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 4-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"W tej chwili nie można pobrać ankiety. Spróbuj ponownie później (kod błędu {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"W tej chwili nie można pobrać ankiety. Spróbuj ponownie później (kod błędu %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 5-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"Ankiety nie można pobrać ze względów bezpieczeństwa. Możesz ponownie wypełnić ankietę w następnym miesiącu kalendarzowym (kod błędu {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"Ankiety nie można pobrać ze względów bezpieczeństwa. Możesz ponownie wypełnić ankietę w następnym miesiącu kalendarzowym (kod błędu %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 6-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Nie udało się pobrać ankiety na smartfon (kod błędu {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Dziękujemy za chęć pomocy. Niestety, korzystasz ze smartfona, który nie obsługuje ankiety z powodów technicznych (kod błędu %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 7-->
-    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"Ze względów bezpieczeństwa nie możesz wypełnić ankiety wcześniej niż 24 godziny po zainstalowaniu lub zaktualizowaniu aplikacji (kod błędu {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"Ze względów bezpieczeństwa nie możesz wypełnić ankiety wcześniej niż po upływie 24 godzin od zainstalowania lub zaktualizowania aplikacji (kod błędu %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 8-->
-    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"Wypełniłeś(-aś) już ankietę. Ankietę można wypełnić tylko raz w miesiącu (kod błędu {0})."</string>
+    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"Wypełniłeś(-aś) już ankietę. Ankietę można wypełnić tylko raz w miesiącu (kod błędu %1$s)."</string>
 
     <!-- XHED: Dialog error title for survey request error informations dialog-->
     <string name="datadonation_details_survey_consent_error_dialog_title">"BÅ‚Ä…d"</string>
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 d67b2dbb535362717b648e39bf3f8601f8f7f018..e29be8d41f483ea294dcf04f97dcbd3e28617c81 100644
--- a/Corona-Warn-App/src/main/res/values-ro/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/strings.xml
@@ -323,8 +323,8 @@
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"Dacă vă testați, veți găsi mai multe informații despre procedura de testare în Întrebările frecvente."</string>
-    <!-- XTXT: Explanation screen increased risk level link label -->
-    <string name="risk_details_increased_risk_faq_link_label">"Întrebări frecvente: Procedura de testare"</string>
+    <!-- XTXT: Explanation screen increased risk level link label - HAS TO MATCH the link text above -->
+    <string name="risk_details_increased_risk_faq_link_label">"Întrebările frecvente"</string>
     <!-- XTXT: Explains user about increased risk level: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#further_details -->
     <string name="risk_details_increased_risk_faq_url">"https://www.coronawarn.app/en/faq/#red_card_how_to_test"</string>
 
@@ -496,9 +496,9 @@
     <!-- XACT: onboarding(tracing) - illustraction description, header image -->
     <string name="onboarding_tracing_illustration_description">"Trei persoane și-au activat pe smartphone înregistrarea în jurnal a expunerilor, ceea ce va duce la înregistrarea întâlnirilor lor."</string>
     <!-- XHED: onboarding(tracing) - location explanation for bluetooth headline -->
-    <string name="onboarding_tracing_location_headline">"Permiteți accesul la locație"</string>
+    <string name="onboarding_tracing_location_headline">"Activați setarea locației"</string>
     <!-- XTXT: onboarding(tracing) - location explanation for bluetooth body text -->
-    <string name="onboarding_tracing_location_body">"Locația dvs. nu poate fi accesată. Google și/sau Android necesită acces la locația smartphone-ului dvs. pentru a utiliza Bluetooth-ul."</string>
+    <string name="onboarding_tracing_location_body">"Locația dispozitivului dvs. nu poate fi determinată de aplicație, dar setarea locației dispozitivului trebuie să fie activată pentru a utiliza Bluetooth Low Energy pe unele versiuni Android."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_location_button">"Deschideți configurările dispozitivului"</string>
     <!-- XACT: Onboarding (test) page title -->
@@ -526,6 +526,8 @@
     <string name="onboarding_ppa_illustration_description">"O persoană ține un smartphone în mână"</string>
     <!-- XHED: onboarding privacy preserving analytics (ppa) - headline -->
     <string name="onboarding_ppa_headline">"Partajare date"</string>
+    <!-- XTXT: onboarding privacy preserving analytics (ppa) - body short text -->
+    <string name="onboarding_ppa_body_short">"Spuneți-ne cum utilizați aplicația și ajutați-ne să evaluăm eficacitatea acesteia."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - body text -->
     <string name="onboarding_ppa_body">"Ne puteți ajuta să îmbunătățim aplicația Corona-Warn. Partajați datele dvs. despre utilizarea aplicației cu institutul RKI. Astfel, ajutați RKI să evalueze eficacitatea aplicației. De asemenea, datele dvs. vor ajuta la îmbunătățirea caracteristicilor și utilizării aplicației."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - state title -->
@@ -537,7 +539,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - age title -->
     <string name="onboarding_ppa_age_title">"Vârsta dvs. (opțional)"</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
-    <string name="onboarding_ppa_more_info_title">"Informații detaliate despre prelucrarea acestor date și riscurile privind prelucrarea datelor în SUA"</string>
+    <string name="onboarding_ppa_more_info_title">"Informații detaliate despre prelucrarea acestor date și riscurile privind prelucrarea datelor din SUA și din alte țări terțe"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - donate button -->
     <string name="onboarding_ppa_consent_donate_button">"Partajare date"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - dont donate button -->
@@ -550,7 +552,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - more info - title -->
     <string name="onboarding_ppa_more_info_data_processing_title">"Prelucrarea datelor în procesul de partajare a datelor"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing body -->
-    <string name="onboarding_ppa_more_info_data_processing_body">"Dacă sunteți de acord să partajați datele dvs., aplicația trimite diverse date către RKI în fiecare zi. Datele transmise vor fi analizate în scopuri variate:"</string>
+    <string name="onboarding_ppa_more_info_data_processing_body">"Dacă sunteți de acord să partajați datele dvs., aplicația trimite diverse date către RKI în fiecare zi. Datele transmise ne vor ajuta să evaluăm eficacitatea aplicației și vor fi analizate pentru a permite următoarele îmbunătățiri:"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 1 -->
     <string name="onboarding_ppa_more_info_data_processing_point_1_text">"Îmbunătățirea înregistrării în jurnal a expunerilor – Dorim să îmbunătățim precizia și încrederea calculului tehnic al riscurilor de infectare. Pentru aceasta, vom evalua informațiile despre expunerile la risc și avertizările pe care le vedeți. Drept rezultat, vom putea rafina metoda de calcul."</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 2 -->
@@ -1794,21 +1796,21 @@
     <string name="datadonation_details_survey_consent_details_title">"Informații detaliate despre prelucrarea datelor utilizate în timpul participării la sondaj"</string>
 
     <!-- XHED: Dialog error title for survey request error informations 1 -->
-    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"Ora de pe smartphone-ul dvs. nu corespunde cu ora curentă. Vă rugăm să corectați ora în setările smartphone-ului dvs. (cod de eroare {0})."</string>
+    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"Ora de pe smartphone-ul dvs. nu corespunde cu ora curentă. Vă rugăm să corectați ora în setările smartphone-ului dvs. (cod de eroare %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 2-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"Nu se poate obține sondajul (cod de eroare {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"Nu se poate obține sondajul (cod de eroare %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 3-->
-    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"Nu se poate obține sondajul chiar acum. Actualizați serviciile Google Play (cod de eroare {0})."</string>
+    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"Nu se poate obține sondajul chiar acum. Actualizați serviciile Google Play (cod de eroare %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 4-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"Nu se poate obține sondajul chiar acum. Încercați din nou mai târziu (cod de eroare {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"Nu se poate obține sondajul chiar acum. Încercați din nou mai târziu (cod de eroare %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 5-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"Nu se poate obține sondajul din cauza unor motive de securitate. Puteți participa din nou la sondaj în următoarea lună calendaristică (cod de eroare {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"Nu se poate obține sondajul din cauza unor motive de securitate. Puteți participa din nou la sondaj în următoarea lună calendaristică (cod de eroare %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 6-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Nu s-a putut obține sondajul pe smartphone-ul dvs. (cod de eroare {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Vă mulțumim pentru că doriți să ajutați. Din păcate, utilizați un smartphone care nu acceptă sondajul, din motive tehnice (cod de eroare %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 7-->
-    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"Din motive de securitate, nu puteți participa la sondaj mai devreme de 24 de ore de la instalarea aplicației sau de la actualizarea aplicației (cod de eroare {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"Din motive de securitate, nu puteți participa la sondaj mai devreme de 24 de ore de la instalarea aplicației sau de la actualizarea aplicației (cod de eroare %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 8-->
-    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"Ați participat deja la sondaj. Puteți participa la sondaj doar o dată pe lună (cod de eroare {0})."</string>
+    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"Ați participat deja la sondaj. Puteți participa la sondaj doar o dată pe lună (cod de eroare %1$s)."</string>
 
     <!-- XHED: Dialog error title for survey request error informations dialog-->
     <string name="datadonation_details_survey_consent_error_dialog_title">"Eroare"</string>
diff --git a/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml b/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml
index 08d66e742492648bac01db91e6b521b29190fc34..fa8eaf35084395b3eb504c95483ecbf6b8265be4 100644
--- a/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml
@@ -53,7 +53,7 @@
     <!-- XHED: Title for the consent displayed above the button in the survey consent screen -->
     <string name="datadonation_details_survey_consent_info_card_title">"Rıza beyanınız"</string>
     <!-- XTXT: Text for the consent body displayed above the button in the survey consent screen -->
-    <string name="datadonation_details_survey_consent_info_card_body">"“Kabul ediyorum” seçeneğine tıklayarak, şunlara onay vermiş olursunuz:\n\nKatılım linki size gösterilmeden önce, Uygulamanızın orijinal olup olmadığı bir kez kontrol edilir. Bunun için, akıllı telefonunuz tarafından benzersiz bir kimlik kodu oluşturulur ve Google’ın Uygulamanızın orijinal ürün olduğunu RKI’ye doğrulaması için ABD’deki Google’e aktarılır. Bu kimlik kodu, akıllı telefonunuzun sürümü ve Uygulama hakkında veriler içerir. Google, Uygulamadan daha fazla bilgi almaz. Bu sayede her kullanıcının ankete sadece bir kez katılabilmesi ve istatistiklerin yanlış sonuçlar vermemesi sağlanır."</string>
+    <string name="datadonation_details_survey_consent_info_card_body">"“Kabul ediyorum” seçeneğine tıklayarak, şunlara onay vermiş olursunuz:\n\nKatılım linki size gösterilmeden önce, Uygulamanızın orijinal olup olmadığı bir kez kontrol edilir. Bunun için, akıllı telefonunuz tarafından benzersiz bir kimlik kodu oluşturulur ve Google’ın Uygulamanızın orijinal ürün olduğunu RKI’ye doğrulaması için ABD’deki veya diğer bir üçüncü ülkedeki Google’e aktarılır. Bu kimlik kodu, akıllı telefonunuzun sürümü ve Uygulama hakkında veriler içerir. Google, böylece kim olduğunuzu ortaya çıkarabilir ve akıllı telefonunuzun orijinallik kontrolünün yapıldığını anlayabilir. Google, Uygulamadan daha fazla bilgi almaz. Bu sayede her kullanıcının ankete sadece bir kez katılabilmesi ve istatistiklerin yanlış sonuçlar vermemesi sağlanır."</string>
     <!-- XTXT: First bullet point in the consent body displayed above the button in the survey consent screen -->
     <string name="datadonation_details_survey_consent_bullet_point_one">"Verdiğiniz rıza beyanı, isteğe bağlı gerçekleşmektedir. Anketin amaçları doğrultusunda rıza beyanında bulunmasanız bile Uygulamayı eksiksiz olarak kullanabilirsiniz."</string>
     <!-- XTXT: Second bullet point in the consent body displayed above the button in the survey consent screen -->
@@ -65,24 +65,25 @@
     <!-- XHED: Title for the information box in the survey consent detail screen -->
     <string name="datadonation_survey_consent_details_title">"Orijinallik doğrulanması ve üçüncü ülkelere aktarım"</string>
     <!-- XTXT: Text for the information box in the survey consent detail screen -->
-    <string name="datadonation_survey_consent_details_text">"Uygulamanızın orijinal olduğunu onaylamak adına akıllı telefonunuz, akıllı telefonunuzun sürümü ve Uygulamaya ilişkin veriler içeren benzersiz bir kimlik kodu oluşturur. Kullanıcıların ankete birden çok kez katılmasını ve böylece anket sonuçlarını tahrif etmesini önlemek için bu kodun oluşturulması gerekmektedir. Bu kimlik kodları, sadece bir kez Google’e aktarılır. Bu süreçte verilerin ABD’ye aktarılması da söz konusu olabilir. Orada Avrupa hukukuna uygun kişisel verilerin koruma seviyesi bulunmamaktadır ve Avrupa’daki veri koruma haklarınız uygulanmayabilir. Bu bağlamda özellikle ABD güvenlik makamlarının, somut bir şüphe olmasa bile, Google’e aktarılan bu verilere erişme ve örneğin verileri diğer bilgilerle ilişkilendirerek bunları değerlendirmeye alma olasılığı bulunmaktadır. Bu durum sadece Google’e aktarılan kimlik kodları için söz konusudur. Google ankete katılımız ile ilgili daha fazla bilgi almaz."</string>
+    <string name="datadonation_survey_consent_details_text">"Uygulamanızın orijinal olduğunu onaylamak adına akıllı telefonunuz, akıllı telefonunuzun sürümü ve Uygulamaya ilişkin veriler içeren benzersiz bir kimlik kodu oluşturur. Kullanıcıların ankete birden çok kez katılmasını ve böylece anket sonuçlarını tahrif etmesini önlemek için bu kodun oluşturulması gerekmektedir. Bu kimlik kodları, sadece bir kez Google’e aktarılır. Bu süreçte verilerin ABD’ye veya üçüncü bir ülkeye aktarılması da söz konusu olabilir. Orada muhtemelen Avrupa hukuku standartlarına uygun kişisel verilerin koruma seviyesi bulunmayabilir ve Avrupa’daki veri koruma haklarınız uygulanmayabilir. Bu bağlamda özellikle üçüncü ülke güvenlik makamlarının, somut bir şüphe olmasa bile, Google’e aktarılan bu verilere erişme ve örneğin verileri diğer bilgilerle ilişkilendirerek bunları değerlendirmeye alma olasılığı bulunmaktadır. Bu durum sadece Google’e aktarılan kimlik kodları için söz konusudur. Google ankete katılımız ile ilgili daha fazla bilgi almaz. Ancak, Google kimlik kodunuz üzerinden kim olduğunuzu ortaya çıkarabilir ve akıllı telefonunuzun orijinallik kontrolünün yapıldığını anlayabilir."</string>
 
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
     <string name="ppa_onboarding_consent_title" translatable="false">"Rıza beyanınız"</string>
     <!-- XTXT: Body for Privacy-preserving Analytics onboarding -->
-    <string name="ppa_onboarding_privacy_information_body" translatable="false">"“Kabul ediyorum” seçeneğine tıklayarak, şunlara onay vermiş olursunuz:\n\ Uygulama, topladığı bilgileri her gün RKI’ye aktarır.  Bunlar, görüntülenen riskli karşılaşmalar ve uyarılar, size gönderilen test sonuçları, diğer kullanıcıları uyarıp uyarmadığınız ve akıllı telefonunuzun işletim sistemine ilişkin verilerdir. Ayrıca başka bilgiler de verdiyseniz (bölge, yaş grubu gibi), bunlar da RKI’ye aktarılır.\n\ RKI, Uygulamanın etki gücünü ve işlevselliğini değerlendirmek ve pandemi hakkında yeni çıkarımlar elde etmek için, bu verileri birleştirecek ve istatistikler olarak değerlendirecektir. Bu süreçte edinilen bulgular, Uygulamanın işlevlerini ve kullanım kolaylığını iyileştirmenin yanı sıra pandemiye karşı mücadele için diğer önlemlerin yönlendirilmesine yardımcı olmaktadır.\n\ Verilerinizin değerlendirilmesinden önce, veri bağışına katılan her Uygulamanın yalnızca bir kez sayıma alındığı ve istatistiklerin tahrif edilmediği kontrol edilir. Bu bağlamda Uygulamanızın orijinal olduğunun incelenmesi gerekmektedir. Bunun için, akıllı telefonunuz tarafından benzersiz bir kimlik kodu oluşturulur ve Google’ın Uygulamanızın orijinal ürün olduğunu RKI’ye doğrulaması için ABD’deki Google’a aktarılır. Bu kimlik kodu, akıllı telefonunuzun sürümü ve Uygulama hakkında veriler içerir. Google, Uygulamadan daha fazla bilgi almaz.\n\ Uygulamanın ayarlarından “Verileri bağışla” seçeneğini devre dışı bırakarak istediğiniz zaman vermiş olduğunuz rızayı geri alabilirsiniz."</string>
+    <string name="ppa_onboarding_privacy_information_body" translatable="false">"“Kabul ediyorum” seçeneğine tıklayarak, şunlara onay vermiş olursunuz:\n\nUygulama, topladığı bilgileri her gün RKI’ye aktarır. Bunlar, görüntülenen riskli karşılaşmalar ve uyarılar, size gönderilen test sonuçları, diğer kullanıcıları uyarıp uyarmadığınız ve akıllı telefonunuzun işletim sistemine ilişkin verilerdir. Ayrıca başka bilgiler de verdiyseniz (bölge, yaş grubu gibi), bunlar da RKI’ye aktarılır.\n\nRKI, Uygulamanın etki gücünü ve işlevselliğini değerlendirmek ve pandemi hakkında yeni çıkarımlar elde etmek için, bu verileri birleştirecek ve istatistikler olarak değerlendirecektir. Bu süreçte edinilen bulgular, Uygulamanın işlevlerini ve kullanım kolaylığını iyileştirmenin yanı sıra pandemiye karşı mücadele için diğer önlemlerin yönlendirilmesine yardımcı olmaktadır.\n\nVerilerinizin değerlendirilmesinden önce, veri bağışına katılan her Uygulamanın yalnızca bir kez sayıma alındığı ve istatistiklerin tahrif edilmediği kontrol edilir. Bu bağlamda Uygulamanızın orijinal olduğunun incelenmesi gerekmektedir. Bunun için, akıllı telefonunuz tarafından benzersiz bir kimlik kodu oluşturulur ve Google’ın Uygulamanızın orijinal ürün olduğunu RKI’ye doğrulaması için ABD’deki veya diğer bir üçüncü ülkedeki Google’a aktarılır. Bu kimlik kodu, akıllı telefonunuzun sürümü ve Uygulama hakkında veriler içerir. Google böylece kim olduğunuzu ortaya çıkarabilir ve akıllı telefonunuzun orijinallik kontrolünün yapıldığını anlayabilir. Google, Uygulamadan daha fazla bilgi almaz.\n\nUygulamanın ayarlarından “Verileri bağışla” seçeneğini devre dışı bırakarak istediğiniz zaman vermiş olduğunuz rızayı geri alabilirsiniz."</string>
     <!-- XTXT: Body point consent for Privacy-preserving Analytics -->
-    <string name="ppa_onboarding_privacy_information_point_consent" translatable="false">"Verdiğiniz rıza beyanı, isteğe bağlı gerçekleşmektedir.  Rızanızı vermezseniz de Uygulamayı kullanabilirsiniz."</string>
+    <string name="ppa_onboarding_privacy_information_point_consent" translatable="false">"Verdiğiniz rıza beyanı, isteğe bağlı gerçekleşmektedir. Rızanızı vermezseniz de Uygulamayı kullanabilirsiniz."</string>
     <!-- XTXT: Body point identity for Privacy-preserving Analytics -->
-    <string name="ppa_onboarding_privacy_information_point_identity" translatable="false">"Uygulama kullanımınızla ilgili veri bağışında bulunursanız, kimliğinizin korunması sürdürülür. RKI, kim olduğunuzu veya kiminle karşılaştığınızı öğrenmez. Profil oluşturma da yapılmaz."</string>
+    <string name="ppa_onboarding_privacy_information_point_identity" translatable="false">"Uygulama kullanımınızla ilgili veri bağışında bulunursanız, RKI nezdinde kimliğinizin korunması sürdürülür. RKI, kim olduğunuzu veya kiminle karşılaştığınızı öğrenmez. Profil oluşturma da yapılmaz."</string>
     <!-- XTXT: Body point sixteen for Privacy-preserving Analytics -->
     <string name="ppa_onboarding_privacy_information_point_sixteen" translatable="false">"En azından 16 yaşında iseniz, rıza beyanında bulunabilirsiniz."</string>
     <!-- XHED: Title for Privacy-preserving Analytics additional info  -->
     <string name="ppa_onboarding_more_info_title" translatable="false">"Orijinallik doğrulanması ve üçüncü ülkelere aktarım"</string>
     <!-- XTXT: Body for Privacy-preserving Analytics additional info -->
-    <string name="ppa_onboarding_more_info_body" translatable="false">"Uygulamanızın orijinal olduğunu onaylamak adına akıllı telefonunuz, akıllı telefonunuzun sürümü ve Uygulamaya ilişkin veriler içeren benzersiz bir kimlik kodu oluşturur. Verilerin birden fazla veya suistimal amaçlı RKI’ye aktarılmasını ve dolayısıyla analiz sonuçlarının tahrif edilmesini önlemek için bu kodun oluşturulması gerekmektedir. Bu kimlik kodları, Google’e aktarılır. Bu süreçte verilerin ABD’ye aktarılması da söz konusu olabilir. Orada Avrupa hukukuna uygun kişisel verilerin koruma seviyesi bulunmamaktadır ve Avrupa’daki veri koruma haklarınız uygulanmayabilir. Bu bağlamda özellikle ABD güvenlik makamlarının, somut bir şüphe olmasa bile, Google’e aktarılan bu verilere erişme ve örneğin verileri diğer bilgilerle ilişkilendirerek bunları değerlendirmeye alma olasılığı bulunmaktadır. Bu durum sadece Google’e  aktarılan kimlik kodları için söz konusudur. Google Corona-Warn-App kullanımınız ile ilgili daha fazla bilgi almaz.\Üçüncü ülkelere aktarımı kabul etmiyorsanız, lütfen “Kabul ediyorum” seçeneğine tıklamayın. Buna rağmen Uygulamayı kullanmaya devam edebilirsiniz, ancak veri bağışında bulunamazsınız."</string>
+    <string name="ppa_onboarding_more_info_body" translatable="false">"Uygulamanızın orijinal olduğunu onaylamak adına akıllı telefonunuz, akıllı telefonunuzun sürümü ve Uygulamaya ilişkin veriler içeren benzersiz bir kimlik kodu oluşturur. Verilerin birden fazla veya suistimal amaçlı RKI’ye aktarılmasını ve dolayısıyla analiz sonuçlarının tahrif edilmesini önlemek için bu kodun oluşturulması gerekmektedir. Bu kimlik kodları, Google’e aktarılır. Bu süreçte verilerin ABD’ye aktarılması da söz konusu olabilir. Orada muhtemelen Avrupa hukuku standartlarına uygun kişisel verilerin koruma seviyesi bulunmayabilir ve Avrupa’daki veri koruma haklarınız uygulanmayabilir. Bu bağlamda özellikle üçüncü ülkelerdeki güvenlik makamlarının, somut bir şüphe olmasa bile, Google’e aktarılan bu verilere erişme ve örneğin verileri diğer bilgilerle ilişkilendirerek bunları değerlendirmeye alma olasılığı bulunmaktadır. Bu durum sadece Google’e aktarılan kimlik kodları için söz konusudur. Google Corona-Warn-App kullanımınız ile ilgili daha fazla bilgi almaz.xAncak, Google kimlik kodunuz üzerinden kim olduğunuzu ortaya çıkarabilir ve akıllı telefonunuzun orijinallik kontrolünün yapıldığını anlayabilir. Üçüncü ülkelere aktarımı kabul etmiyorsanız, lütfen “Kabul ediyorum” seçeneğine tıklamayın. Buna rağmen Uygulamayı kullanmaya devam edebilirsiniz, ancak veri bağışında bulunamazsınız."</string>
+    <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
+    <string name="ppa_onboarding_privacy_information_title" translatable="false">"Rıza beyanınız"</string>
     <!-- XTXT: Body for Privacy-preserving Analytics settings -->
-    <string name="ppa_settings_privacy_information_body" translatable="false">"Yukarıdaki “Veri bağışı" seçeneğini etkinleştirerek, şunlara onay vermiş olursunuz:\n\Uygulama, topladığı bilgileri her gün RKI’ye aktarır.  Bunlar, görüntülenen riskli karşılaşmalar ve uyarılar, size gönderilen test sonuçları, diğer kullanıcıları uyarıp uyarmadığınız ve akıllı telefonunuzun işletim sistemine ilişkin verilerdir. Ayrıca başka bilgiler de verdiyseniz (bölge, yaş grubu gibi), bunlar da RKI’ye aktarılır.\n\nRKI, Uygulamanın etki gücünü ve işlevselliğini değerlendirmek ve pandemi hakkında yeni çıkarımlar elde etmek için, bu verileri birleştirecek ve istatistikler olarak değerlendirecektir. Bu süreçte edinilen bulgular, Uygulamanın işlevlerini ve kullanım kolaylığını iyileştirmenin yanı sıra pandemiye karşı mücadele için diğer önlemlerin yönlendirilmesine yardımcı olmaktadır.\n\nVerilerinizin değerlendirilmesinden önce, veri bağışına katılan her Uygulamanın yalnızca bir kez sayıma alındığı ve istatistiklerin tahrif edilmediği kontrol edilir. Bu bağlamda Uygulamanızın orijinal olduğunun incelenmesi gerekmektedir. Bunun için, akıllı telefonunuz tarafından benzersiz bir kimlik kodu oluşturulur ve Google’ın Uygulamanızın orijinal ürün olduğunu RKI’ye doğrulaması için ABD’deki Google’e aktarılır. Bu kimlik kodu, akıllı telefonunuzun sürümü ve Uygulama hakkında veriler içerir. Google, Uygulamadan daha fazla bilgi almaz.\n\n Yukarıdaki “Veri bağışı” seçeneğini devre dışı bırakarak, verdiğiniz rıza beyanını geri alabilirsiniz Yukarıdaki “Veri bağışı” seçeneğini devre dışı bırakarak, verdiğiniz rıza beyanını geri alabilirsiniz."</string>
-
+    <string name="ppa_settings_privacy_information_body" translatable="false">"Yukarıdaki “Veri bağışı" seçeneğini etkinleştirerek, şunlara onay vermiş olursunuz:\n\nUygulama, topladığı bilgileri her gün RKI’ye aktarır. Bunlar, görüntülenen riskli karşılaşmalar ve uyarılar, size gönderilen test sonuçları, diğer kullanıcıları uyarıp uyarmadığınız ve akıllı telefonunuzun işletim sistemine ilişkin verilerdir. Ayrıca başka bilgiler de verdiyseniz (bölge, yaş grubu gibi), bunlar da RKI’ye aktarılır.\n\nRKI, Uygulamanın etki gücünü ve işlevselliğini değerlendirmek ve pandemi hakkında yeni çıkarımlar elde etmek için, bu verileri birleştirecek ve istatistikler olarak değerlendirecektir. Bu süreçte edinilen bulgular, Uygulamanın işlevlerini ve kullanım kolaylığını iyileştirmenin yanı sıra pandemiye karşı mücadele için diğer önlemlerin yönlendirilmesine yardımcı olmaktadır.\n\nVerilerinizin değerlendirilmesinden önce, veri bağışına katılan her Uygulamanın yalnızca bir kez sayıma alındığı ve istatistiklerin tahrif edilmediği kontrol edilir. Bu bağlamda Uygulamanızın orijinal olduğunun incelenmesi gerekmektedir. Bunun için, akıllı telefonunuz tarafından benzersiz bir kimlik kodu oluşturulur ve Google’ın Uygulamanızın orijinal ürün olduğunu RKI’ye doğrulaması için ABD’deki veya diğer bir üçüncü ülkeye Google’e aktarılır. Bu kimlik kodu, akıllı telefonunuzun sürümü ve Uygulama hakkında veriler içerir. Google, böylece kim olduğunuzu ortaya çıkarabilir ve akıllı telefonunuzun orijinallik kontrolünün yapıldığını anlayabilir. Google, Uygulamadan daha fazla bilgi almaz.\n\nYukarıdaki “Veri bağışı” seçeneğini devre dışı bırakarak, verdiğiniz rıza beyanını geri alabilirsiniz."</string>
 
 </resources>
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 dd8f24235a186e8d7aef069e57bc1d4e0e9e564d..dbb190211959b7022cf7bb1981658c5c2c0bca48 100644
--- a/Corona-Warn-App/src/main/res/values-tr/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/strings.xml
@@ -339,7 +339,7 @@
     <!-- XHED: risk details - infection risk headline, below behaviors -->
     <string name="risk_details_headline_infection_risk">"Enfeksiyon Riski"</string>
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
-    <string name="risk_details_headline_period_logged">"Dönem günlüğe kaydedildi"</string>
+    <string name="risk_details_headline_period_logged">"Dönem Günlüğe Kaydedildi"</string>
     <!-- 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 -->
@@ -496,9 +496,9 @@
     <!-- XACT: onboarding(tracing) - illustraction description, header image -->
     <string name="onboarding_tracing_illustration_description">"Üç kişi akıllı telefonlarında maruz kalma günlüğünü etkinleştirdi ve birbirleri ile karşılaşmaları günlüğe kaydedilecektir."</string>
     <!-- XHED: onboarding(tracing) - location explanation for bluetooth headline -->
-    <string name="onboarding_tracing_location_headline">"Konum eriÅŸimine izin ver"</string>
+    <string name="onboarding_tracing_location_headline">"Konum Ayarını Etkinleştir"</string>
     <!-- XTXT: onboarding(tracing) - location explanation for bluetooth body text -->
-    <string name="onboarding_tracing_location_body">"Konumunuza erişilemiyor. Bluetooth\'u kullanmak için Google ve/veya Android\'in akıllı telefonunuzun konumuna erişmesi gerekiyor."</string>
+    <string name="onboarding_tracing_location_body">"Uygulama, cihazınızın konumunu belirleyemiyor ancak bazı Android sürümlerinde Bluetooth Düşük Enerji işlevinin kullanılması için cihazın konum ayarının etkinleştirilmesi gereklidir."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_location_button">"Cihaz Ayarlarını Aç"</string>
     <!-- XACT: Onboarding (test) page title -->
@@ -526,6 +526,8 @@
     <string name="onboarding_ppa_illustration_description">"Bir kişi elinde akıllı telefon tutuyor"</string>
     <!-- XHED: onboarding privacy preserving analytics (ppa) - headline -->
     <string name="onboarding_ppa_headline">"Verileri PaylaÅŸ"</string>
+    <!-- XTXT: onboarding privacy preserving analytics (ppa) - body short text -->
+    <string name="onboarding_ppa_body_short">"Uygulamayı nasıl kullandığınızı belirtin ve uygulamanın etkinliğini değerlendirmemize yardımcı olun."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - body text -->
     <string name="onboarding_ppa_body">"Corona-Warn-App’i iyileştirmemize yardımcı olabilirsiniz. Uygulamayı kullanımınız hakkındaki verileri RKI ile paylaşın. Bu, RKI’nin uygulamanın etkinliğini değerlendirmesine yardımcı olacaktır. Verileriniz aynı zamanda uygulamanın özelliklerinin ve kullanılabilirliğinin iyileştirilmesine yardımcı olacaktır."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - state title -->
@@ -537,7 +539,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - age title -->
     <string name="onboarding_ppa_age_title">"Yaşınız (isteğe bağlı)"</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
-    <string name="onboarding_ppa_more_info_title">"ABD’de Veri İşleme ve Veri Koruma Riskleri Hakkında Ayrıntılı Bilgiler"</string>
+    <string name="onboarding_ppa_more_info_title">"ABD’de ve Diğer Üçüncü Ülkelerde Veri İşleme ve Veri Koruma Riskleri Hakkında Ayrıntılı Bilgiler"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - donate button -->
     <string name="onboarding_ppa_consent_donate_button">"Verileri PaylaÅŸ"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - dont donate button -->
@@ -550,7 +552,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - more info - title -->
     <string name="onboarding_ppa_more_info_data_processing_title">"Veri Paylaşma Sürecinde Veri İşleme"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing body -->
-    <string name="onboarding_ppa_more_info_data_processing_body">"Verilerinizi paylaşma izni vermeniz halinde uygulama RKI’ye her gün çeşitli veriler gönderir. Aktarılan veriler çeşitli amaçlarla analiz edilir:"</string>
+    <string name="onboarding_ppa_more_info_data_processing_body">"Verilerinizi paylaşma izni vermeniz halinde uygulama RKI’ye her gün çeşitli veriler gönderir. Aktarılan veriler, uygulamanın etkinliğini değerlendirmemize yardımcı olacaktır ve çeşitli amaçlarla analiz edilecektir:"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 1 -->
     <string name="onboarding_ppa_more_info_data_processing_point_1_text">"İyileştirilmiş maruz kalma günlüğü – Teknik olarak enfeksiyon risklerini hesaplama doğruluğunu ve güvenilirliğini iyileştirmek istiyoruz. Bunun için, maruz kalma riskleri ve size gösterilen uyarlar hakkındaki bilgileri değerlendireceğiniz. Bunun sonucunda, hesaplama yöntemini geliştirebileceğiz."</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 2 -->
@@ -1794,21 +1796,21 @@
     <string name="datadonation_details_survey_consent_details_title">"Anketi Yanıtlamaya İlişkin Veri İşleme Hakkında Ayrıntılı Bilgiler"</string>
 
     <!-- XHED: Dialog error title for survey request error informations 1 -->
-    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"Akıllı telefonunuzun saati, geçerli saat ile eşleşmiyor. Lütfen akıllı telefonunuzun saatini düzeltin (hata kodu: {0})."</string>
+    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"Akıllı telefonunuzun saati, geçerli saat ile eşleşmiyor. Lütfen akıllı telefonunuzun saatini düzeltin (hata kodu: %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 2-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"Anket alınamıyor (hata kodu: {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"Anket alınamıyor (hata kodu: %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 3-->
-    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"Anket şu anda alınamıyor. Lütfen Google Plat Hizmetlerini güncelleyin (hata kodu: {0})."</string>
+    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"Anket şu anda alınamıyor. Lütfen Google Plat Hizmetlerini güncelleyin (hata kodu: %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 4-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"Anket şu anda alınamıyor. Lütfen daha sonra tekrar deneyin (hata kodu: {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"Anket şu anda alınamıyor. Lütfen daha sonra tekrar deneyin (hata kodu: %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 5-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"Güvenlik nedenleriyle anket alınamıyor. Sonraki takvim ayında anketi yeniden yanıtlayabilirsiniz (hata kodu: {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"Güvenlik nedenleriyle anket alınamıyor. Sonraki takvim ayında anketi yeniden yanıtlayabilirsiniz (hata kodu: %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 6-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Anket akıllı telefonunuzda alınamıyor (hata kodu: {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Yardımcı olmak istediğiniz için teşekkür ederiz. Ne yazık ki teknik nedenlerle anketi desteklemeyen bir akıllı telefon kullanıyorsunuz (hata kodu %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 7-->
-    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"Güvenlik nedenleriyle uygulamayı yüklemenizin veya güncellemenizin üzerinden en az 24 saat geçmeden anketi yanıtlayamazsınız (hata kodu: {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"Güvenlik nedenleriyle uygulamayı yüklemenizin veya güncellemenizin üzerinden en az 24 saat geçmeden anketi yanıtlayamazsınız (hata kodu: %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 8-->
-    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"Anketi zaten yanıtladınız. Anketi yalnızca ayda bir kez yanıtlayabilirsiniz (hata kodu: {0})."</string>
+    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"Anketi zaten yanıtladınız. Anketi yalnızca ayda bir kez yanıtlayabilirsiniz (hata kodu: %1$s)."</string>
 
     <!-- XHED: Dialog error title for survey request error informations dialog-->
     <string name="datadonation_details_survey_consent_error_dialog_title">"Hata"</string>
diff --git a/Corona-Warn-App/src/main/res/values/legal_strings.xml b/Corona-Warn-App/src/main/res/values/legal_strings.xml
index 526d9eb99d52547a9dff854dc94ed3b552baf719..1b7680961b5f22d45112d8a2fe248a307fb69fad 100644
--- a/Corona-Warn-App/src/main/res/values/legal_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/legal_strings.xml
@@ -54,7 +54,7 @@
     <!-- XHED: Title for the consent displayed above the button in the survey consent screen -->
     <string name="datadonation_details_survey_consent_info_card_title" translatable="false">"Your Consent"</string>
     <!-- XTXT: Text for the consent body displayed above the button in the survey consent screen -->
-    <string name="datadonation_details_survey_consent_info_card_body" translatable="false">"By tapping on “Accept”, you consent to the following:\n\nBefore your participation link can be shown to you, the authenticity of your app is checked once. For this purpose, a unique identifier is generated by your smartphone and transmitted to Google in the U.S., so that Google can confirm the authenticity of your app to the RKI. The identifier contains information about the version of your smartphone and the app. Google does not receive any other information from the app during this process. This ensures that each user can only participate in the survey once, so as not to distort the statistics."</string>
+    <string name="datadonation_details_survey_consent_info_card_body" translatable="false">"By tapping on “Accept”, you consent to the following:\n\nBefore your participation link can be shown to you, the authenticity of your app is checked once. For this purpose, a unique identifier is generated by your smartphone and transmitted to Google in the U.S. or other third countries, so that Google can confirm the authenticity of your app to the RKI. The identifier contains information about the version of your smartphone and the app. On this basis, Apple [Google] may be able to infer your identity and learn that your smartphone has been authenticated. Google does not receive any other information from the app during this process. This ensures that each user can only participate in the survey once, so as not to distort the statistics."</string>
     <!-- XTXT: First bullet point in the consent body displayed above the button in the survey consent screen -->
     <string name="datadonation_details_survey_consent_bullet_point_one" translatable="false">"Your consent is voluntary. If you do not give your consent for the purposes of the survey, you will still be able to use the whole app."</string>
     <!-- XTXT: Second bullet point in the consent body displayed above the button in the survey consent screen -->
@@ -66,23 +66,25 @@
     <!-- XHED: Title for the information box in the survey consent detail screen -->
     <string name="datadonation_survey_consent_details_title" translatable="false">"Verification of Authenticity and Transfer to a Third Country"</string>
     <!-- XTXT: Text for the information box in the survey consent detail screen -->
-    <string name="datadonation_survey_consent_details_text" translatable="false">"To confirm the authenticity of your app, your smartphone will generate a unique identifier that contains information about the version of your smartphone and the app. This is necessary to prevent users from participating in the survey more than once, as this could distort the results of the survey. Once generated, the identifier will be transmitted once to Google. This may result in data being transferred to the U.S. There, the level of data protection is not considered adequate under European law and it may not be possible to enforce your European data protection rights. In particular, there is a possibility that once the transmitted data reaches Google, it may be accessed and analyzed by U.S. security authorities, even if they have no specific grounds for suspicion, for example by linking the data with other information. This only concerns the identifier sent to Google. Google will not receive the other information about your participation in the survey."</string>
+    <string name="datadonation_survey_consent_details_text" translatable="false">"To confirm the authenticity of your app, your smartphone will generate a unique identifier that contains information about the version of your smartphone and the app. This is necessary to prevent users from participating in the survey more than once, as this could distort the results of the survey. Once generated, the identifier will be transmitted once to Google. This may result in data being transferred to the U.S. or other third countries. There, the level of data protection may not be considered equivalent under European law and it may not be possible to enforce your European data protection rights. In particular, there is a possibility that once the transmitted data reaches Google, it may be accessed and analyzed by security authorities in the third country, even if they have no specific grounds for suspicion, for example by linking the data with other information. This only concerns the identifier sent to Google. Google will not receive the other information about your participation in the survey. It may however be possible for Apple [Google] to infer your identity from the identifier and learn that your smartphone has been authenticated. "</string>
 
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
     <string name="ppa_onboarding_consent_title" translatable="false">"Your Consent"</string>
     <!-- XTXT: Body for Privacy-preserving Analytics onboarding -->
- <string name="ppa_onboarding_privacy_information_body" translatable="false">"By tapping on “Accept”, you consent to the following:\n\nThe app will transmit information it records to the RKI, on a daily basis. The data concerns possible exposures and warnings that have been displayed to you, test results you have retrieved, and whether you have warned other users, and information about your smartphone’s operating system. If you have provided further details above (region, age group), then the RKI will also receive this information.\n\nThe RKI will compile this data into statistics and analyze it to assess the effectiveness and functioning of the app, and draw conclusions regarding the pandemic. The resulting knowledge will help to improve the app’s features and make it more user-friendly, as well as to inform other pandemic response measures.\n\nBefore your data is analyzed, it is necessary to ensure that each app that shares data is only counted once, so as not to distort the statistics. This is why the authenticity of your app needs to be verified. For this purpose, a unique identifier is generated by your smartphone and transmitted to Google in the U.S., so that Google can confirm the authenticity of your app to the RKI. The identifier contains information about the version of your smartphone and the app. Google does not receive any other information from the app during this process.\n\You can withdraw your consent at any time by disabling the data sharing feature in the app's settings."</string>
-    <!-- XTXT: Body point consent for Privacy-preserving Analytics -->
+ <string name="ppa_onboarding_privacy_information_body" translatable="false">"By tapping on “Accept”, you consent to the following:\n\nThe app will transmit information it records to the RKI, on a daily basis. The data concerns possible exposures and warnings that have been displayed to you, test results you have retrieved, and whether you have warned other users, and information about your smartphone’s operating system. If you have provided further details above (region, age group), then the RKI will also receive this information.\n\nThe RKI will compile this data into statistics and analyze it to assess the effectiveness and functioning of the app, and draw conclusions regarding the pandemic. The resulting knowledge will help to improve the app’s features and make it more user-friendly, as well as to inform other pandemic response measures.\n\nBefore your data is analyzed, it is necessary to ensure that each app that shares data is only counted once, so as not to distort the statistics. This is why the authenticity of your app needs to be verified. For this purpose, a unique identifier is generated by your smartphone and transmitted to Google in the U.S. or other third countries, so that Google can confirm the authenticity of your app to the RKI. The identifier contains information about the version of your smartphone and the app. On this basis, Google may be able to infer your identity and learn that your smartphone has been authenticated. Google does not receive any other information from the app during this process.\n\nYou can withdraw your consent at any time by disabling the data sharing feature in the app's settings."</string>
+ <!-- XTXT: Body point consent for Privacy-preserving Analytics -->
  <string name="ppa_onboarding_privacy_information_point_consent" translatable="false">"Your consent is voluntary. If you do not give your consent, you will still be able to use the app."</string>
-    <!-- XTXT: Body point identity for Privacy-preserving Analytics -->
- <string name="ppa_onboarding_privacy_information_point_identity" translatable="false">"Your identity will still be protected if you share data about your use of the app. This means the RKI will not find out who you are or who you have met. No profiles will be created either."</string>
-    <!-- XTXT: Body point sixteen for Privacy-preserving Analytics -->
+ <!-- XTXT: Body point identity for Privacy-preserving Analytics -->
+ <string name="ppa_onboarding_privacy_information_point_identity" translatable="false">"If you share data about your use of the app, your identity will still be kept secret from the RKI. This means the RKI will not find out who you are or who you have met. No profiles will be created either."</string>
+ <!-- XTXT: Body point sixteen for Privacy-preserving Analytics -->
  <string name="ppa_onboarding_privacy_information_point_sixteen" translatable="false">"You need to be at least 16 years old to give your consent."</string>
-    <!-- XHED: Title for Privacy-preserving Analytics additional info  -->
+ <!-- XHED: Title for Privacy-preserving Analytics additional info  -->
  <string name="ppa_onboarding_more_info_title" translatable="false">"Verification of authenticity and transfer to a third country"</string>
-    <!-- XTXT: Body for Privacy-preserving Analytics additional info -->
- <string name="ppa_onboarding_more_info_body" translatable="false">"To confirm the authenticity of your app, your smartphone will generate a unique identifier that contains information about the version of your smartphone and the app. This is necessary to prevent data from being transmitted to the RKI more than once or in an unauthorised manner, as this could distort the results of the analysis. The identifier will be transmitted to Google. This may result in data being transferred to the U.S. There, the level of data protection is not considered adequate under European law and it may not be possible to enforce your European data protection rights. In particular, there is a possibility that once the transmitted data reaches Google, it may be accessed and analyzed by U.S. security authorities, even if they have no specific grounds for suspicion, for example by linking the data with other information. This only concerns the identifier sent to Google. Google will not receive the other information about how you use the Corona-Warn-App.\If you do not consent to this transfer of your data to a third country, please do not tap on “Accept”. You will still be able to use the app, but not the data sharing feature."</string>
-    <!-- XTXT: Body for Privacy-preserving Analytics settings -->
- <string name="ppa_settings_privacy_information_body" translatable="false">"By enabling “Share Data” above, you consent to the following:\n\nThe app will transmit information it records to the RKI, on a daily basis. The data concerns possible exposures and warnings that have been displayed to you, test results you have retrieved, and whether you have warned other users, and information about your smartphone’s operating system. If you have provided further details above (region, age group), then the RKI will also receive this information.\n\nThe RKI will compile this data into statistics and analyze it to assess the effectiveness and functioning of the app, and draw conclusions regarding the pandemic. The resulting knowledge will help to improve the app’s features and make it more user-friendly, as well as to inform other pandemic response measures.\n\nBefore your data is analyzed, it is necessary to ensure that each app that shares data is only counted once, so as not to distort the statistics. This is why the authenticity of your app needs to be verified. For this purpose, a unique identifier is generated by your smartphone and transmitted to Google  in the U.S., so that Google can confirm the authenticity of your app to the RKI. The identifier contains information about the version of your smartphone and the app. Google does not receive any other information from the app during this process.\n\n You can withdraw your consent at any time by disabling “Share Data” above."</string>
+ <!-- XTXT: Body for Privacy-preserving Analytics additional info -->
+ <string name="ppa_onboarding_more_info_body" translatable="false">"To confirm the authenticity of your app, your smartphone will generate a unique identifier that contains information about the version of your smartphone and the app. This is necessary to prevent data from being transmitted to the RKI more than once or in an unauthorised manner, as this could distort the results of the analysis. The identifier will be transmitted to Google. This may result in data being transferred to the U.S. or other third countries. There, the level of data protection may not be considered equivalent under European law and it may not be possible to enforce your European data protection rights. In particular, there is a possibility that once the transmitted data reaches Google, it may be accessed and analyzed by security authorities in the third country, even if they have no specific grounds for suspicion, for example by linking the data with other information. This only concerns the identifier sent to Google. Google will not receive the other information about how you use the Corona-Warn-App. It may however be possible for Google to infer your identity from the identifier and learn that your smartphone has been authenticated.\n\nIf you do not consent to this transfer of your data to a third country, please do not tap on “Accept”. You will still be able to use the app, but not the data sharing feature."</string>
+ <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
+ <string name="ppa_onboarding_privacy_information_title" translatable="false">"Your Consent"</string>
+ <!-- XTXT: Body for Privacy-preserving Analytics settings -->
+ <string name="ppa_settings_privacy_information_body" translatable="false">"By enabling “Share Data” above, you consent to the following:\n\nThe app will transmit information it records to the RKI, on a daily basis. The data concerns possible exposures and warnings that have been displayed to you, test results you have retrieved, and whether you have warned other users, and information about your smartphone’s operating system. If you have provided further details above (region, age group), then the RKI will also receive this information.\n\nThe RKI will compile this data into statistics and analyze it to assess the effectiveness and functioning of the app, and draw conclusions regarding the pandemic. The resulting knowledge will help to improve the app’s features and make it more user-friendly, as well as to inform other pandemic response measures.\n\nBefore your data is analyzed, it is necessary to ensure that each app that shares data is only counted once, so as not to distort the statistics. This is why the authenticity of your app needs to be verified. For this purpose, a unique identifier is generated by your smartphone and transmitted to Google in the U.S. or other third countries, so that Google can confirm the authenticity of your app to the RKI. The identifier contains information about the version of your smartphone and the app. On this basis, Google may be able to infer your identity and learn that your smartphone has been authenticated. Google does not receive any other information from the app during this process.\n\n You can withdraw your consent at any time by disabling “Share Data” above."</string>
 
 </resources>
diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml
index db9fe666995e47ba54004b5667fd15f1180741b7..de1bd20084af2a084408b0bc6b3b8c904a8b6e2a 100644
--- a/Corona-Warn-App/src/main/res/values/strings.xml
+++ b/Corona-Warn-App/src/main/res/values/strings.xml
@@ -334,8 +334,8 @@
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"If you get tested, you will find additional information about the testing procedure in the FAQ."</string>
-    <!-- XTXT: Explanation screen increased risk level link label -->
-    <string name="risk_details_increased_risk_faq_link_label">"FAQ: Testing Procedure"</string>
+    <!-- XTXT: Explanation screen increased risk level link label - HAS TO MATCH the link text above -->
+    <string name="risk_details_increased_risk_faq_link_label">"FAQ"</string>
     <!-- XTXT: Explains user about increased risk level: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#further_details -->
     <string name="risk_details_increased_risk_faq_url">"https://www.coronawarn.app/en/faq/#red_card_how_to_test"</string>
 
@@ -350,7 +350,7 @@
     <!-- XHED: risk details - infection risk headline, below behaviors -->
     <string name="risk_details_headline_infection_risk">"Risk of Infection"</string>
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
-    <string name="risk_details_headline_period_logged">"Period logged"</string>
+    <string name="risk_details_headline_period_logged">"Period Logged"</string>
     <!-- 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 -->
@@ -508,9 +508,9 @@
     <!-- XACT: onboarding(tracing) - illustraction description, header image -->
     <string name="onboarding_tracing_illustration_description">"Three persons have activated exposure logging on their smartphones, which will log their encounters with each other."</string>
     <!-- XHED: onboarding(tracing) - location explanation for bluetooth headline -->
-    <string name="onboarding_tracing_location_headline">"Allow location access"</string>
+    <string name="onboarding_tracing_location_headline">"Activate Location Setting"</string>
     <!-- XTXT: onboarding(tracing) - location explanation for bluetooth body text -->
-    <string name="onboarding_tracing_location_body">"Your location cannot be accessed. Google and/or Android requires access to your smartphone’s location to use Bluetooth."</string>
+    <string name="onboarding_tracing_location_body">"Your device location cannot be determined by the app, but the device location setting must be activated to use Bluetooth Low Energy in some Android versions."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_location_button">"Open Device Settings"</string>
     <!-- XACT: Onboarding (test) page title -->
@@ -534,12 +534,12 @@
     <!-- XACT: onboarding(notifications) - illustraction description, header image -->
     <string name="onboarding_notifications_illustration_description">"A woman receives a notification from her Corona-Warn-App."</string>
 
-    <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
-    <string name="onboarding_ppa_consent_title">"Ihr Einverständnis"</string>
     <!-- XACT: onboarding privacy preserving analytics (ppa) - illustraction description, header image -->
     <string name="onboarding_ppa_illustration_description">"A person is holding a smartphone in their hand"</string>
     <!-- XHED: onboarding privacy preserving analytics (ppa) - headline -->
     <string name="onboarding_ppa_headline">"Share Data"</string>
+    <!-- XTXT: onboarding privacy preserving analytics (ppa) - body short text -->
+    <string name="onboarding_ppa_body_short">"Let us know how you use the app and help us to assess its effectiveness."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - body text -->
     <string name="onboarding_ppa_body">"You can help us to improve the Corona-Warn-App. Share the data about your app usage with the RKI. This will help the RKI assess the app’s effectiveness. Your data will also help to improve the features and usability of the app."</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - state title -->
@@ -551,7 +551,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - age title -->
     <string name="onboarding_ppa_age_title">"Your age (optional)"</string>
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - consent title -->
-    <string name="onboarding_ppa_more_info_title">"Detailed Information about This Data Processing and Data Protection Risks in the U.S."</string>
+    <string name="onboarding_ppa_more_info_title">"Detailed Information about This Data Processing and Data Protection Risks in the U.S. and Other Third Countries"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - donate button -->
     <string name="onboarding_ppa_consent_donate_button">"Share Data"</string>
     <!-- XBUT: onboarding privacy preserving analytics (ppa) - dont donate button -->
@@ -564,7 +564,7 @@
     <!-- XTXT: onboarding privacy preserving analytics (ppa) - more info - title -->
     <string name="onboarding_ppa_more_info_data_processing_title">"Data Processing in the Data Sharing Process"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing body -->
-    <string name="onboarding_ppa_more_info_data_processing_body">"If you consent to share your data, the app sends various data to the RKI each day. The transmitted data will be analyzed for a variety of purposes:"</string>
+    <string name="onboarding_ppa_more_info_data_processing_body">"If you consent to share your data, the app sends various data to the RKI each day. The transmitted data will help us assess the effectiveness of the app and will be analyzed to support the following improvements:"</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 1 -->
     <string name="onboarding_ppa_more_info_data_processing_point_1_text">"Improved exposure logging – We want to improve the accuracy and reliability of the technical calculation of infection risks. To do so, we will evaluate information about risk exposures and the warnings you see. As a result, we will be able to refine the calculation method."</string>
     <!-- YTXT: onboarding privacy preserving analytics (ppa) - more info - data processing point 2 -->
@@ -1812,21 +1812,21 @@
     <string name="datadonation_details_survey_consent_details_title">"Detailed Information on Data Processing Involved in Taking the Survey"</string>
 
     <!-- XHED: Dialog error title for survey request error informations 1 -->
-    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"The time on your smartphone does not match the current time. Please correct the time in your smartphone settings (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_CHANGE_DEVICE_TIME">"The time on your smartphone does not match the current time. Please correct the time in your smartphone settings (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 2-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"The survey cannot be retrieved (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_SUPPORTED">"The survey cannot be retrieved (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 3-->
-    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"The survey cannot be retrieved right now. Please update the Google Play Services (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_UPDATE_PLAY_SERVICES">"The survey cannot be retrieved right now. Please update the Google Play Services (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 4-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"The survey cannot be retrieved right now. Please try again later (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_LATER">"The survey cannot be retrieved right now. Please try again later (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 5-->
-    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"The survey cannot be retrieved due to security reasons. You can take the survey again in the next calendar month (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TRY_AGAIN_NEXT_MONTH">"The survey cannot be retrieved due to security reasons. You can take the survey again in the next calendar month (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 6-->
-    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"The survey could not be retrieved on your smartphone (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_DEVICE_NOT_TRUSTED">"Thank you for wanting to help. Unfortunately, you use a smartphone that does not support the survey for technical reasons (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 7-->
-    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"For security reasons, you cannot take the survey less than 24 hours after you install or update the app (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_TIME_SINCE_ONBOARDING_UNVERIFIED">"For security reasons, you cannot take the survey less than 24 hours after you install or update the app (error code %1$s)."</string>
     <!-- XHED: Dialog error title for survey request error informations 8-->
-    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"You have already taken the survey. You can only take the survey once per month (error code {0})."</string>
+    <string name="datadonation_details_survey_consent_error_ALREADY_PARTICIPATED">"You have already taken the survey. You can only take the survey once per month (error code %1$s)."</string>
 
     <!-- XHED: Dialog error title for survey request error informations dialog-->
     <string name="datadonation_details_survey_consent_error_dialog_title">"Error"</string>
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/sources/fallback/DefaultAppConfigSanityCheck.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/sources/fallback/DefaultAppConfigSanityCheck.kt
index 65fbea7326413eafe856079034c1ce49a0f81438..2a21d798e23c7a76a303650af05b6607037dbdeb 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/sources/fallback/DefaultAppConfigSanityCheck.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/sources/fallback/DefaultAppConfigSanityCheck.kt
@@ -44,7 +44,7 @@ class DefaultAppConfigSanityCheck : BaseTest() {
     fun `current default matches checksum`() {
         val config = context.assets.open(configName).readBytes()
         val sha256 = context.assets.open(checkSumName).readBytes().toString(Charsets.UTF_8)
-        sha256 shouldBe "827fb746a1128e465d65ec77030fdf38c823dec593ae18aed55195069cf8b701"
+        sha256 shouldBe "12d0b93c0c02c6870ef75c173a53a8ffb9cab6828fbf22e751053329c425eef2"
         config.toSHA256() shouldBe sha256
     }
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/BugReporterTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/BugReporterTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bab37d8a115cfd9bb161127c31c1b7b294a4315a
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/BugReporterTest.kt
@@ -0,0 +1,19 @@
+package de.rki.coronawarnapp.bugreporting
+
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class BugReporterTest : BaseTest() {
+
+    @Test
+    fun `test emtpy tag`() {
+        // This just tests the timber statement
+        Exception().reportProblem(info = "info")
+    }
+
+    @Test
+    fun `test empty info and tag`() {
+        // This just tests the timber statement
+        Exception().reportProblem()
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/OneTimePasswordTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/OneTimePasswordTest.kt
index b8b9fda93b84e002cf8e02b10a5d943dc55a072e..6614c0122d97aee7ace11e468434195c22e4a0a0 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/OneTimePasswordTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/OneTimePasswordTest.kt
@@ -1,18 +1,24 @@
 package de.rki.coronawarnapp.datadonation
 
+import de.rki.coronawarnapp.server.protocols.internal.ppdd.EdusOtp
 import io.kotest.matchers.shouldBe
 import okio.ByteString.Companion.decodeBase64
-import org.junit.Test
+import org.junit.jupiter.api.Test
 import java.util.UUID
 
 class OneTimePasswordTest {
 
     @Test
     fun `payload generation`() {
-        val otpPayload =
-            OneTimePassword(UUID.fromString("15cff19f-af26-41bc-94f2-c1a65075e894"))
-                .payloadForRequest
-        val expected = "MTVjZmYxOWYtYWYyNi00MWJjLTk0ZjItYzFhNjUwNzVlODk0".decodeBase64()!!.toByteArray()
-        otpPayload shouldBe expected
+        val uuid = UUID.fromString("15cff19f-af26-41bc-94f2-c1a65075e894")
+        val otp = OneTimePassword(uuid)
+
+        val protoBuf = EdusOtp.EDUSOneTimePassword.newBuilder().setOtp(uuid.toString()).build()
+        val protoBufRaw = "CiQxNWNmZjE5Zi1hZjI2LTQxYmMtOTRmMi1jMWE2NTA3NWU4OTQ=".decodeBase64()!!.toByteArray()
+        otp.apply {
+            edusOneTimePassword shouldBe protoBuf
+            payloadForRequest shouldBe protoBuf.toByteArray()
+            payloadForRequest shouldBe protoBufRaw
+        }
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/AnalyticsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/AnalyticsTest.kt
index 74de382bd2ff6241da82fc0cf6ee7930c942500d..306ff85627dfbb7a37afd3a54ae02c870bd3f07c 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/AnalyticsTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/AnalyticsTest.kt
@@ -7,15 +7,18 @@ import de.rki.coronawarnapp.appconfig.SafetyNetRequirements
 import de.rki.coronawarnapp.appconfig.SafetyNetRequirementsContainer
 import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule
 import de.rki.coronawarnapp.datadonation.analytics.modules.exposureriskmetadata.ExposureRiskMetadataDonor
+import de.rki.coronawarnapp.datadonation.analytics.modules.usermetadata.UserMetadataDonor
 import de.rki.coronawarnapp.datadonation.analytics.server.DataDonationAnalyticsServer
 import de.rki.coronawarnapp.datadonation.analytics.storage.AnalyticsSettings
 import de.rki.coronawarnapp.datadonation.analytics.storage.LastAnalyticsSubmissionLogger
 import de.rki.coronawarnapp.datadonation.safetynet.DeviceAttestation
+import de.rki.coronawarnapp.datadonation.safetynet.SafetyNetException
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaDataRequestAndroid
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpacAndroid
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.util.TimeStamper
+import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
 import io.mockk.clearAllMocks
@@ -24,8 +27,11 @@ import io.mockk.coVerify
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
 import io.mockk.just
+import io.mockk.mockk
 import io.mockk.mockkObject
 import io.mockk.spyk
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.test.runBlockingTest
 import org.joda.time.Days
 import org.joda.time.Instant
 import org.junit.jupiter.api.AfterEach
@@ -71,6 +77,8 @@ class AnalyticsTest : BaseTest() {
         every { LocalData.onboardingCompletedTimestamp() } returns twoDaysAgo.millis
 
         every { analyticsConfig.safetyNetRequirements } returns SafetyNetRequirementsContainer()
+
+        coEvery { dataDonationAnalyticsServer.uploadAnalyticsData(any()) } just Runs
     }
 
     @AfterEach
@@ -78,14 +86,12 @@ class AnalyticsTest : BaseTest() {
         clearAllMocks()
     }
 
-    private fun createDonorModules(): Set<DonorModule> = setOf(exposureRiskMetadataDonor)
-
-    private fun createInstance() = spyk(
+    private fun createInstance(modules: Set<DonorModule> = setOf(exposureRiskMetadataDonor)) = spyk(
         Analytics(
             dataDonationAnalyticsServer = dataDonationAnalyticsServer,
             appConfigProvider = appConfigProvider,
             deviceAttestation = deviceAttestation,
-            donorModules = createDonorModules(),
+            donorModules = modules,
             settings = settings,
             logger = lastAnalyticsSubmissionLogger,
             timeStamper = timeStamper
@@ -99,7 +105,11 @@ class AnalyticsTest : BaseTest() {
         val analytics = createInstance()
 
         runBlockingTest2 {
-            analytics.submitIfWanted()
+            val result = analytics.submitIfWanted()
+            result.apply {
+                successful shouldBe false
+                shouldRetry shouldBe false
+            }
         }
 
         coVerify(exactly = 1) {
@@ -119,7 +129,11 @@ class AnalyticsTest : BaseTest() {
         val analytics = createInstance()
 
         runBlockingTest2 {
-            analytics.submitIfWanted()
+            val result = analytics.submitIfWanted()
+            result.apply {
+                successful shouldBe false
+                shouldRetry shouldBe false
+            }
         }
 
         coVerify(exactly = 1) {
@@ -140,7 +154,11 @@ class AnalyticsTest : BaseTest() {
         val analytics = createInstance()
 
         runBlockingTest2 {
-            analytics.submitIfWanted()
+            val result = analytics.submitIfWanted()
+            result.apply {
+                successful shouldBe false
+                shouldRetry shouldBe false
+            }
         }
 
         coVerify(exactly = 1) {
@@ -162,7 +180,11 @@ class AnalyticsTest : BaseTest() {
         val analytics = createInstance()
 
         runBlockingTest2 {
-            analytics.submitIfWanted()
+            val result = analytics.submitIfWanted()
+            result.apply {
+                successful shouldBe false
+                shouldRetry shouldBe false
+            }
         }
 
         coVerify(exactly = 1) {
@@ -185,7 +207,11 @@ class AnalyticsTest : BaseTest() {
         val analytics = createInstance()
 
         runBlockingTest2 {
-            analytics.submitIfWanted()
+            val result = analytics.submitIfWanted()
+            result.apply {
+                successful shouldBe false
+                shouldRetry shouldBe false
+            }
         }
 
         coVerify(exactly = 1) {
@@ -233,12 +259,14 @@ class AnalyticsTest : BaseTest() {
                 override fun requirePass(requirements: SafetyNetRequirements) {}
             }
 
-        coEvery { dataDonationAnalyticsServer.uploadAnalyticsData(any()) } just Runs
-
         val analytics = createInstance()
 
         runBlockingTest2 {
-            analytics.submitIfWanted()
+            val result = analytics.submitIfWanted()
+            result.apply {
+                successful shouldBe true
+                shouldRetry shouldBe false
+            }
         }
 
         coVerify(exactly = 1) {
@@ -246,4 +274,185 @@ class AnalyticsTest : BaseTest() {
             dataDonationAnalyticsServer.uploadAnalyticsData(analyticsRequest)
         }
     }
+
+    @Test
+    fun `despite error on beginDonation modules can still cleanup`() {
+        val userMetadataDonor = mockk<UserMetadataDonor>().apply {
+            coEvery { beginDonation(any()) } throws Exception("KABOOM!")
+        }
+        val modules = setOf(exposureRiskMetadataDonor, userMetadataDonor)
+
+        val mockExposureRisk = mockk<DonorModule.Contribution>().apply {
+            coEvery { injectData(any()) } just Runs
+            coEvery { finishDonation(any()) } just Runs
+        }
+        coEvery { exposureRiskMetadataDonor.beginDonation(any()) } returns mockExposureRisk
+
+        coEvery { deviceAttestation.attest(any()) } returns object : DeviceAttestation.Result {
+            override val accessControlProtoBuf: PpacAndroid.PPACAndroid
+                get() = PpacAndroid.PPACAndroid.getDefaultInstance()
+
+            override fun requirePass(requirements: SafetyNetRequirements) {}
+        }
+
+        val analytics = createInstance(modules = modules)
+
+        runBlockingTest {
+            analytics.submitIfWanted()
+        }
+
+        coVerify(exactly = 1) {
+            userMetadataDonor.beginDonation(any())
+
+            exposureRiskMetadataDonor.beginDonation(any())
+            mockExposureRisk.injectData(any())
+            mockExposureRisk.finishDonation(true)
+
+            analytics.submitAnalyticsData(any())
+        }
+    }
+
+    @Test
+    fun `despite errors during donation modules can still cleanup`() {
+        val userMetaDataDonation = mockk<DonorModule.Contribution>().apply {
+            coEvery { injectData(any()) } throws Exception("KAPOW!")
+            coEvery { finishDonation(any()) } throws Exception("CRUNCH!")
+        }
+        val userMetadataDonor = mockk<UserMetadataDonor>().apply {
+            coEvery { beginDonation(any()) } returns userMetaDataDonation
+        }
+        val modules = setOf(exposureRiskMetadataDonor, userMetadataDonor)
+
+        val exposureRiskDonation = mockk<ExposureRiskMetadataDonor.ExposureRiskMetadataContribution>().apply {
+            coEvery { injectData(any()) } just Runs
+            coEvery { finishDonation(any()) } just Runs
+        }
+        coEvery { exposureRiskMetadataDonor.beginDonation(any()) } returns exposureRiskDonation
+
+        coEvery { deviceAttestation.attest(any()) } returns object : DeviceAttestation.Result {
+            override val accessControlProtoBuf: PpacAndroid.PPACAndroid
+                get() = PpacAndroid.PPACAndroid.getDefaultInstance()
+
+            override fun requirePass(requirements: SafetyNetRequirements) {}
+        }
+
+        val analytics = createInstance(modules = modules)
+
+        runBlockingTest {
+            analytics.submitIfWanted()
+        }
+
+        coVerify(exactly = 1) {
+            exposureRiskMetadataDonor.beginDonation(any())
+            exposureRiskDonation.injectData(any())
+            exposureRiskDonation.finishDonation(true)
+
+            userMetadataDonor.beginDonation(any())
+            userMetaDataDonation.injectData(any())
+            userMetaDataDonation.finishDonation(true)
+
+            analytics.submitAnalyticsData(any())
+        }
+    }
+
+    @Test
+    fun `we catch safetynet timeout and enable retry`() {
+        val exposureRiskDonation = mockk<ExposureRiskMetadataDonor.ExposureRiskMetadataContribution>().apply {
+            coEvery { injectData(any()) } just Runs
+            coEvery { finishDonation(any()) } just Runs
+        }
+        coEvery { exposureRiskMetadataDonor.beginDonation(any()) } returns exposureRiskDonation
+
+        coEvery { deviceAttestation.attest(any()) } throws SafetyNetException(
+            type = SafetyNetException.Type.ATTESTATION_REQUEST_FAILED,
+            "Timeout???",
+            cause = Exception()
+        )
+
+        val analytics = createInstance()
+
+        runBlockingTest {
+            val result = analytics.submitIfWanted()
+            result.successful shouldBe false
+            result.shouldRetry shouldBe true
+        }
+
+        coVerify(exactly = 1) {
+            exposureRiskMetadataDonor.beginDonation(any())
+            exposureRiskDonation.injectData(any())
+            exposureRiskDonation.finishDonation(false)
+        }
+
+        coVerify(exactly = 0) { dataDonationAnalyticsServer.uploadAnalyticsData(any()) }
+    }
+
+    @Test
+    fun `overall submission can timeout on safetynet and still allow modules to cleanup`() {
+        val exposureRiskDonation = mockk<ExposureRiskMetadataDonor.ExposureRiskMetadataContribution>().apply {
+            coEvery { injectData(any()) } just Runs
+            coEvery { finishDonation(any()) } just Runs
+        }
+        coEvery { exposureRiskMetadataDonor.beginDonation(any()) } returns exposureRiskDonation
+
+        coEvery { deviceAttestation.attest(any()) } coAnswers {
+            // Timeout should be 360s
+            delay(370_000)
+            mockk()
+        }
+
+        val analytics = createInstance()
+
+        runBlockingTest {
+            val result = analytics.submitIfWanted()
+            result.successful shouldBe false
+            result.shouldRetry shouldBe true
+        }
+
+        coVerify(exactly = 1) {
+            exposureRiskMetadataDonor.beginDonation(any())
+            exposureRiskDonation.injectData(any())
+            exposureRiskDonation.finishDonation(false)
+        }
+
+        coVerify(exactly = 0) {
+            dataDonationAnalyticsServer.uploadAnalyticsData(any())
+        }
+    }
+
+    @Test
+    fun `overall submission can timeout on upload and still allow modules to cleanup`() {
+        val exposureRiskDonation = mockk<ExposureRiskMetadataDonor.ExposureRiskMetadataContribution>().apply {
+            coEvery { injectData(any()) } just Runs
+            coEvery { finishDonation(any()) } just Runs
+        }
+        coEvery { exposureRiskMetadataDonor.beginDonation(any()) } returns exposureRiskDonation
+
+        coEvery { deviceAttestation.attest(any()) } returns object : DeviceAttestation.Result {
+            override val accessControlProtoBuf: PpacAndroid.PPACAndroid
+                get() = PpacAndroid.PPACAndroid.getDefaultInstance()
+
+            override fun requirePass(requirements: SafetyNetRequirements) {}
+        }
+
+        coEvery { dataDonationAnalyticsServer.uploadAnalyticsData(any()) } coAnswers {
+            // Timeout should be 360s
+            delay(370_000)
+            mockk()
+        }
+
+        val analytics = createInstance()
+
+        runBlockingTest {
+            val result = analytics.submitIfWanted()
+            result.successful shouldBe false
+            result.shouldRetry shouldBe true
+        }
+
+        coVerify(exactly = 1) {
+            exposureRiskMetadataDonor.beginDonation(any())
+            exposureRiskDonation.injectData(any())
+            exposureRiskDonation.finishDonation(false)
+            dataDonationAnalyticsServer.uploadAnalyticsData(any())
+        }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/ExposureRiskMetadataDonorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/ExposureRiskMetadataDonorTest.kt
index 33a064d6713352439410677d29352dc7482338c8..2ae64c468af8852f5eda27236680901da2e19b61 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/ExposureRiskMetadataDonorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/ExposureRiskMetadataDonorTest.kt
@@ -7,6 +7,7 @@ import de.rki.coronawarnapp.risk.RiskLevelResult
 import de.rki.coronawarnapp.risk.result.AggregatedRiskResult
 import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.clearAllMocks
@@ -27,12 +28,16 @@ class ExposureRiskMetadataDonorTest : BaseTest() {
     @MockK lateinit var highAggregatedRiskResult: AggregatedRiskResult
     @MockK lateinit var lowAggregatedRiskResult: AggregatedRiskResult
 
+    private val baseDate: Instant = Instant.ofEpochMilli(101010)
+
     @BeforeEach
     fun setup() {
         MockKAnnotations.init(this)
 
         every { highAggregatedRiskResult.isIncreasedRisk() } returns true
+        every { highAggregatedRiskResult.mostRecentDateWithHighRisk } returns baseDate
         every { lowAggregatedRiskResult.isIncreasedRisk() } returns false
+        every { lowAggregatedRiskResult.mostRecentDateWithHighRisk } returns baseDate
     }
 
     @AfterEach
@@ -60,11 +65,9 @@ class ExposureRiskMetadataDonorTest : BaseTest() {
 
     @Test
     fun `risk metadata is properly collected`() {
-        val recentDate = Instant.now()
-
         val expectedMetadata = PpaData.ExposureRiskMetadata.newBuilder()
             .setRiskLevel(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
-            .setMostRecentDateAtRiskLevel(recentDate.millis)
+            .setMostRecentDateAtRiskLevel(baseDate.seconds)
             .setRiskLevelChangedComparedToPreviousSubmission(true)
             .setDateChangedComparedToPreviousSubmission(true)
             .build()
@@ -75,12 +78,12 @@ class ExposureRiskMetadataDonorTest : BaseTest() {
                 createRiskLevelResult(
                     aggregatedRiskResult = highAggregatedRiskResult,
                     failureReason = null,
-                    calculatedAt = recentDate
+                    calculatedAt = baseDate
                 ),
                 createRiskLevelResult(
                     aggregatedRiskResult = lowAggregatedRiskResult,
                     failureReason = RiskLevelResult.FailureReason.UNKNOWN,
-                    calculatedAt = recentDate
+                    calculatedAt = baseDate
                 )
             )
         )
@@ -100,18 +103,16 @@ class ExposureRiskMetadataDonorTest : BaseTest() {
 
     @Test
     fun `risk metadata change is properly collected`() {
-        val recentDate = Instant.now()
-
         val initialMetadata = PpaData.ExposureRiskMetadata.newBuilder()
             .setRiskLevel(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
-            .setMostRecentDateAtRiskLevel(recentDate.millis)
+            .setMostRecentDateAtRiskLevel(baseDate.seconds)
             .setRiskLevelChangedComparedToPreviousSubmission(true)
             .setDateChangedComparedToPreviousSubmission(true)
             .build()
 
         val expectedMetadata = PpaData.ExposureRiskMetadata.newBuilder()
             .setRiskLevel(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
-            .setMostRecentDateAtRiskLevel(recentDate.millis)
+            .setMostRecentDateAtRiskLevel(baseDate.seconds)
             .setRiskLevelChangedComparedToPreviousSubmission(false)
             .setDateChangedComparedToPreviousSubmission(false)
             .build()
@@ -123,12 +124,12 @@ class ExposureRiskMetadataDonorTest : BaseTest() {
                 createRiskLevelResult(
                     aggregatedRiskResult = highAggregatedRiskResult,
                     failureReason = null,
-                    calculatedAt = recentDate
+                    calculatedAt = baseDate
                 ),
                 createRiskLevelResult(
                     aggregatedRiskResult = lowAggregatedRiskResult,
                     failureReason = RiskLevelResult.FailureReason.UNKNOWN,
-                    calculatedAt = recentDate
+                    calculatedAt = baseDate
                 )
             )
         )
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsPeriodicWorkerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsPeriodicWorkerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2ea4a82db16288a86dc944bad41944940386f3d6
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/worker/DataDonationAnalyticsPeriodicWorkerTest.kt
@@ -0,0 +1,70 @@
+package de.rki.coronawarnapp.datadonation.analytics.worker
+
+import android.content.Context
+import androidx.work.ListenableWorker
+import androidx.work.WorkerParameters
+import de.rki.coronawarnapp.datadonation.analytics.Analytics
+import de.rki.coronawarnapp.worker.BackgroundConstants
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.clearAllMocks
+import io.mockk.coEvery
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.impl.annotations.RelaxedMockK
+import kotlinx.coroutines.test.runBlockingTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class DataDonationAnalyticsPeriodicWorkerTest : BaseTest() {
+
+    @MockK lateinit var context: Context
+    @MockK lateinit var analytics: Analytics
+    @RelaxedMockK lateinit var workerParams: WorkerParameters
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+    }
+
+    @AfterEach
+    fun teardown() {
+        clearAllMocks()
+    }
+
+    private fun createWorker() = DataDonationAnalyticsPeriodicWorker(
+        context = context,
+        workerParams = workerParams,
+        analytics = analytics
+    )
+
+    @Test
+    fun `if result says retry, do retry`() = runBlockingTest {
+        coEvery { analytics.submitIfWanted() } returns Analytics.Result(successful = false, shouldRetry = true)
+        createWorker().doWork() shouldBe ListenableWorker.Result.Retry()
+
+        coEvery { analytics.submitIfWanted() } returns Analytics.Result(successful = false, shouldRetry = false)
+        createWorker().doWork() shouldBe ListenableWorker.Result.Failure()
+
+        coEvery { analytics.submitIfWanted() } returns Analytics.Result(successful = true, shouldRetry = false)
+        createWorker().doWork() shouldBe ListenableWorker.Result.Success()
+    }
+
+    @Test
+    fun `maximum of 2 retry attemtps`() = runBlockingTest {
+        val worker = createWorker()
+        worker.runAttemptCount shouldBe 0
+
+        every { worker.runAttemptCount } returns BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD + 1
+
+        worker.doWork() shouldBe ListenableWorker.Result.Failure()
+    }
+
+    @Test
+    fun `unexpected errors do not cause a retry`() = runBlockingTest {
+        coEvery { analytics.submitIfWanted() } throws Exception("SURPRISE!!!")
+        createWorker().doWork() shouldBe ListenableWorker.Result.Failure()
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/safetynet/CWASafetyNetTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/safetynet/CWASafetyNetTest.kt
index 2cab39c71d9bd36af645990198e301cc84b038e2..9b04b9a50707d5d219c25e3f941be2bd0b5bcea7 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/safetynet/CWASafetyNetTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/safetynet/CWASafetyNetTest.kt
@@ -6,11 +6,15 @@ import de.rki.coronawarnapp.appconfig.ConfigData
 import de.rki.coronawarnapp.environment.EnvironmentSetup
 import de.rki.coronawarnapp.main.CWASettings
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.EdusOtp
+import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpacAndroid
+import de.rki.coronawarnapp.storage.TestSettings
+import de.rki.coronawarnapp.util.CWADebug
 import de.rki.coronawarnapp.util.HashExtensions.Format.BASE64
 import de.rki.coronawarnapp.util.HashExtensions.toSHA256
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.gplay.GoogleApiVersion
+import io.kotest.assertions.throwables.shouldNotThrowAny
 import io.kotest.assertions.throwables.shouldThrow
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
@@ -20,6 +24,7 @@ import io.mockk.coVerify
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
 import io.mockk.mockk
+import io.mockk.mockkObject
 import kotlinx.coroutines.test.runBlockingTest
 import okio.ByteString.Companion.decodeBase64
 import org.joda.time.Duration
@@ -28,6 +33,7 @@ import org.junit.jupiter.api.AfterEach
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
+import testhelpers.preferences.mockFlowPreference
 import java.security.SecureRandom
 import kotlin.random.Random
 
@@ -44,14 +50,18 @@ class CWASafetyNetTest : BaseTest() {
 
     @MockK lateinit var appConfigProvider: AppConfigProvider
     @MockK lateinit var appConfigData: ConfigData
+    @MockK lateinit var testSettings: TestSettings
 
     private val defaultPayload = "Computer says no.".toByteArray()
     private val firstSalt = "LMK0jFCu/lOzl07ZHmtOqQ==".decodeBase64()!!
-    private val defaultNonce = (firstSalt.toByteArray() + defaultPayload).toSHA256(format = BASE64)
+    private val defaultNonce = (firstSalt.toByteArray() + defaultPayload).toSHA256(format = BASE64).decodeBase64()!!
 
     @BeforeEach
     fun setup() {
         MockKAnnotations.init(this)
+        mockkObject(CWADebug)
+        every { CWADebug.isDeviceForTestersBuild } returns false
+
         every { environmentSetup.safetyNetApiKey } returns "very safe"
         coEvery { safetyNetClientWrapper.attest(any()) } returns clientReport
         every { secureRandom.nextBytes(any()) } answers {
@@ -75,6 +85,8 @@ class CWASafetyNetTest : BaseTest() {
 
         every { cwaSettings.firstReliableDeviceTime } returns Instant.EPOCH.plus(Duration.standardDays(7))
         every { timeStamper.nowUTC } returns Instant.EPOCH.plus(Duration.standardDays(8))
+
+        every { testSettings.skipSafetyNetTimeCheck } returns mockFlowPreference(false)
     }
 
     @AfterEach
@@ -89,7 +101,8 @@ class CWASafetyNetTest : BaseTest() {
         appConfigProvider = appConfigProvider,
         googleApiVersion = googleApiVersion,
         timeStamper = timeStamper,
-        cwaSettings = cwaSettings
+        cwaSettings = cwaSettings,
+        testSettings = testSettings
     )
 
     @Test
@@ -109,7 +122,7 @@ class CWASafetyNetTest : BaseTest() {
             salt,
             payload
         )
-        nonce shouldBe "M2EqczgxveKiptESiBNRmKqxYv5raTdzyeSZyzsCvjg="
+        nonce shouldBe "M2EqczgxveKiptESiBNRmKqxYv5raTdzyeSZyzsCvjg=".decodeBase64()
     }
 
     @Test
@@ -122,7 +135,7 @@ class CWASafetyNetTest : BaseTest() {
         otp.otp shouldBe "hello-world"
 
         val nonce = createInstance().calculateNonce(salt, payload)
-        nonce shouldBe "ANjVoDcS8v8iQdlNrcxehSggE9WZwIp7VNpjoU7cPsg="
+        nonce shouldBe "ANjVoDcS8v8iQdlNrcxehSggE9WZwIp7VNpjoU7cPsg=".decodeBase64()
     }
 
     @Test
@@ -134,7 +147,20 @@ class CWASafetyNetTest : BaseTest() {
             salt,
             payload
         )
-        nonce shouldBe "Alzb6UASmHCdnnT0M8pQv5bQ/r/+lfS/jb760+ikhxc="
+        nonce shouldBe "Alzb6UASmHCdnnT0M8pQv5bQ/r/+lfS/jb760+ikhxc=".decodeBase64()
+    }
+
+    @Test
+    fun `nonce matches server calculation - serverstyle - PPA Payload`() {
+        // Server get's base64 encoded data and has to decode it first.
+        val salt = "Ri0AXC9U+b9hE58VqupI8Q==".decodeBase64()!!.toByteArray()
+        val payload = "Eg0IAxABGMGFyOT6LiABOgkIBBDdj6AFGAI=".decodeBase64()!!.toByteArray()
+
+        val ppa = PpaData.PPADataAndroid.parseFrom(payload)
+        ppa.exposureRiskMetadataSetList.first().riskLevel shouldBe PpaData.PPARiskLevel.RISK_LEVEL_HIGH
+
+        val nonce = createInstance().calculateNonce(salt, payload)
+        nonce shouldBe "bd6kMfLKby3pzEqW8go1ZgmHN/bU1p/4KG6+1GeB288=".decodeBase64()
     }
 
     @Test
@@ -142,7 +168,7 @@ class CWASafetyNetTest : BaseTest() {
         val payload = "Computer says no.".toByteArray()
         val salt = "Don't be so salty".toByteArray()
         val nonce = createInstance().calculateNonce(salt, payload)
-        nonce shouldBe (salt + payload).toSHA256(format = BASE64)
+        nonce shouldBe (salt + payload).toSHA256(format = BASE64).decodeBase64()
     }
 
     @Test
@@ -172,7 +198,7 @@ class CWASafetyNetTest : BaseTest() {
 
     @Test
     fun `request nonce must match response nonce`() = runBlockingTest {
-        every { clientReport.nonce } returns "missmatch"
+        every { clientReport.nonce } returns "missmatch".decodeBase64()
         val exception = shouldThrow<SafetyNetException> {
             createInstance().attest(TestAttestationRequest("Computer says no.".toByteArray()))
         }
@@ -208,6 +234,27 @@ class CWASafetyNetTest : BaseTest() {
         exception.type shouldBe SafetyNetException.Type.TIME_SINCE_ONBOARDING_UNVERIFIED
     }
 
+    @Test
+    fun `24h since onboarding can be skipped on deviceForTester builds`() = runBlockingTest {
+        every { timeStamper.nowUTC } returns Instant.EPOCH
+
+        shouldThrow<SafetyNetException> {
+            createInstance().attest(TestAttestationRequest("Computer says no.".toByteArray()))
+        }.type shouldBe SafetyNetException.Type.TIME_SINCE_ONBOARDING_UNVERIFIED
+
+        every { testSettings.skipSafetyNetTimeCheck } returns mockFlowPreference(true)
+
+        shouldThrow<SafetyNetException> {
+            createInstance().attest(TestAttestationRequest("Computer says no.".toByteArray()))
+        }.type shouldBe SafetyNetException.Type.TIME_SINCE_ONBOARDING_UNVERIFIED
+
+        every { CWADebug.isDeviceForTestersBuild } returns true
+
+        shouldNotThrowAny {
+            createInstance().attest(TestAttestationRequest("Computer says no.".toByteArray()))
+        }
+    }
+
     @Test
     fun `first reliable devicetime timestamp needs to be set`() = runBlockingTest {
         every { cwaSettings.firstReliableDeviceTime } returns Instant.EPOCH
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetClientWrapperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetClientWrapperTest.kt
index bfb6411eb77d9527a06eb820d603d07872972211..707950e24843cceaa4a085088aa593da6e8c4961 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetClientWrapperTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/safetynet/SafetyNetClientWrapperTest.kt
@@ -24,7 +24,6 @@ import org.junit.jupiter.api.AfterEach
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
-import testhelpers.coroutines.runBlockingTest2
 import testhelpers.gms.MockGMSTask
 import java.io.IOException
 
@@ -74,7 +73,7 @@ class SafetyNetClientWrapperTest : BaseTest() {
     }
 
     @Test
-    fun `attestation can time out`() = runBlockingTest2(ignoreActive = true) {
+    fun `attestation can time out`() = runBlockingTest {
         every { safetyNetClient.attest(any(), any()) } returns MockGMSTask.timeout()
 
         val resultAsync = async {
@@ -83,10 +82,8 @@ class SafetyNetClientWrapperTest : BaseTest() {
             }
         }
 
-        advanceTimeBy(31 * 1000L)
-
         val error = resultAsync.await()
-        error.type shouldBe SafetyNetException.Type.ATTESTATION_FAILED
+        error.type shouldBe SafetyNetException.Type.ATTESTATION_REQUEST_FAILED
         error.cause shouldBe instanceOf(TimeoutCancellationException::class)
     }
 
@@ -148,7 +145,7 @@ class SafetyNetClientWrapperTest : BaseTest() {
                 body shouldBe JsonParser.parseString(JWS_BODY)
                 signature shouldBe JWS_SIGNATURE_BASE64.decodeBase64()!!.toByteArray()
 
-                nonce shouldBe "AAAAAAAAAAAAAAAAAAAAAA==".decodeBase64()?.utf8()
+                nonce shouldBe "AAAAAAAAAAAAAAAAAAAAAA==".decodeBase64()
                 apkPackageName shouldBe "de.rki.coronawarnapp.test"
                 basicIntegrity shouldBe false
                 ctsProfileMatch shouldBe false
@@ -164,7 +161,7 @@ class SafetyNetClientWrapperTest : BaseTest() {
             createInstance().attest("hodl".toByteArray()).apply {
                 body shouldBe JsonParser.parseString(JWS_BODY_MINIMAL)
 
-                nonce shouldBe "AAAAAAAAAAAAAAAAAAAAAA==".decodeBase64()?.utf8()
+                nonce shouldBe "AAAAAAAAAAAAAAAAAAAAAA==".decodeBase64()
                 apkPackageName shouldBe "de.rki.coronawarnapp.test"
                 basicIntegrity shouldBe false
                 ctsProfileMatch shouldBe false
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/survey/SurveySettingsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/survey/SurveySettingsTest.kt
index ba9894c5f47557708907931935a218e32e8f2a65..6fd1b7161a4109a3cc916257aa5cac7da5627207 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/survey/SurveySettingsTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/survey/SurveySettingsTest.kt
@@ -101,7 +101,8 @@ class SurveySettingsTest : BaseTest() {
                 {
                     "uuid":"e103c755-0975-4588-a639-d0cd1ba421a1",
                     "authorized": true,
-                    "redeemedAt": 1612381217443
+                    "redeemedAt": 1612381217443,
+                    "invalidated": true
                 }
             """.trimIndent()
         ).apply()
@@ -111,6 +112,7 @@ class SurveySettingsTest : BaseTest() {
         value!!.uuid.toString() shouldBe "e103c755-0975-4588-a639-d0cd1ba421a1"
         value.authorized shouldBe true
         value.redeemedAt.millis shouldBe 1612381217443
+        value.invalidated shouldBe true
     }
 
     @Test
@@ -133,14 +135,15 @@ class SurveySettingsTest : BaseTest() {
         val redeemedAt = Instant.ofEpochMilli(1612381217445)
 
         val instance = SurveySettings(context, baseGson)
-        instance.otpAuthorizationResult = OTPAuthorizationResult(uuid, authorized, redeemedAt)
+        instance.otpAuthorizationResult = OTPAuthorizationResult(uuid, authorized, redeemedAt, false)
 
         val value = preferences.getString("otp_result", null)
         value shouldBe """
             {
               "uuid": "e103c755-0975-4588-a639-d0cd1ba421a0",
               "authorized": false,
-              "redeemedAt": 1612381217445
+              "redeemedAt": 1612381217445,
+              "invalidated": false
             }
         """.trimIndent()
     }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTaskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTaskTest.kt
index c22593689bdb3fb649c31a47c0c244abc18a0b52..df2e2ce3dae0471911328808e994e452581ab29a 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTaskTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTaskTest.kt
@@ -8,6 +8,7 @@ import de.rki.coronawarnapp.environment.BuildConfigWrap
 import de.rki.coronawarnapp.environment.EnvironmentSetup
 import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.TrackedExposureDetection
+import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.util.TimeStamper
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
@@ -54,6 +55,8 @@ class DownloadDiagnosisKeysTaskTest : BaseTest() {
 
         mockkObject(BuildConfigWrap)
         every { BuildConfigWrap.VERSION_CODE } returns 1080005
+        mockkObject(LocalData)
+        every { LocalData.isAllowedToSubmitDiagnosisKeys() } returns false
 
         availableKey1.apply {
             every { path } returns File("availableKey1")
@@ -230,4 +233,20 @@ class DownloadDiagnosisKeysTaskTest : BaseTest() {
             enfClient.provideDiagnosisKeys(any(), any())
         }
     }
+
+    @Test
+    fun `we do not submit keys if user got positive test results`() = runBlockingTest {
+        every { LocalData.isAllowedToSubmitDiagnosisKeys() } returns true
+
+        createInstance().run(DownloadDiagnosisKeysTask.Arguments())
+
+        coVerifySequence {
+            enfClient.isTracingEnabled
+            enfClient.latestTrackedExposureDetection()
+        }
+
+        coVerify(exactly = 0) {
+            enfClient.provideDiagnosisKeys(any(), any())
+        }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/HttpErrorParserTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/HttpErrorParserTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6e5c4b649ed8ecb5423233f2fb4eaa710c884641
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/HttpErrorParserTest.kt
@@ -0,0 +1,126 @@
+package de.rki.coronawarnapp.http
+
+import de.rki.coronawarnapp.exception.http.CwaWebException
+import io.kotest.assertions.throwables.shouldThrow
+import io.kotest.matchers.shouldBe
+import io.kotest.matchers.string.shouldContain
+import io.mockk.MockKAnnotations
+import io.mockk.clearAllMocks
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.mockk
+import okhttp3.Interceptor
+import okhttp3.MediaType.Companion.toMediaTypeOrNull
+import okhttp3.Protocol
+import okhttp3.Request
+import okhttp3.Response
+import okhttp3.ResponseBody.Companion.toResponseBody
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class HttpErrorParserTest : BaseTest() {
+
+    @MockK lateinit var chain: Interceptor.Chain
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        every { chain.request() } returns mockk()
+    }
+
+    @AfterEach
+    fun teardown() {
+        clearAllMocks()
+    }
+
+    private val baseResponse: Response.Builder
+        get() = Response.Builder().apply {
+            protocol(Protocol.HTTP_1_1)
+            Request.Builder().apply {
+                url("http://url.url")
+            }.build().let { request(it) }
+        }
+
+    @Test
+    fun `normal response`() {
+        val response = baseResponse.apply {
+            code(200)
+            message("")
+        }.build()
+        every { chain.proceed(any()) } returns response
+        HttpErrorParser().intercept(chain) shouldBe response
+    }
+
+    @Test
+    fun `error without message`() {
+        val response = baseResponse.apply {
+            code(404)
+            message("")
+        }.build()
+        every { chain.proceed(any()) } returns response
+        val exception = shouldThrow<CwaWebException> { HttpErrorParser().intercept(chain) }
+        exception.statusCode shouldBe 404
+        exception.message shouldContain "code=404 message= body=null"
+    }
+
+    @Test
+    fun `error with message`() {
+        val response = baseResponse.apply {
+            code(403)
+            message("Forbidden")
+        }.build()
+        every { chain.proceed(any()) } returns response
+        val exception = shouldThrow<CwaWebException> { HttpErrorParser().intercept(chain) }
+        exception.statusCode shouldBe 403
+        exception.message shouldContain "message=Forbidden"
+        exception.message shouldContain "body=null"
+    }
+
+    @Test
+    fun `error in body`() {
+        val response = baseResponse.apply {
+            code(500)
+            message("")
+            body("{\"errorCode\":\"APK_CERTIFICATE_MISMATCH\"}".toResponseBody("application/json".toMediaTypeOrNull()))
+        }.build()
+        every { chain.proceed(any()) } returns response
+        val exception = shouldThrow<CwaWebException> { HttpErrorParser().intercept(chain) }
+        exception.statusCode shouldBe 500
+        exception.message shouldContain "message= "
+        exception.message shouldContain "body={\"errorCode\":\"APK_CERTIFICATE_MISMATCH\"}"
+    }
+
+    @Test
+    fun `error in message and body`() {
+        val response = baseResponse.apply {
+            code(501)
+            message("Error")
+            body("{\"errorCode\":\"APK_CERTIFICATE_MISMATCH\"}".toResponseBody("application/json".toMediaTypeOrNull()))
+        }.build()
+        every { chain.proceed(any()) } returns response
+        val exception = shouldThrow<CwaWebException> { HttpErrorParser().intercept(chain) }
+        exception.statusCode shouldBe 501
+        exception.message shouldContain "message=Error"
+        exception.message shouldContain "body={\"errorCode\":\"APK_CERTIFICATE_MISMATCH\"}"
+    }
+
+    @Test
+    fun `oversized errors are handled`() {
+        val response = baseResponse.apply {
+            code(501)
+            message("")
+            body(
+                (1..5000).joinToString { "1" }.toResponseBody()
+            )
+        }.build()
+        every { chain.proceed(any()) } returns response
+        val exception = shouldThrow<CwaWebException> { HttpErrorParser().intercept(chain) }
+        exception.statusCode shouldBe 501
+        val start = exception.message!!.indexOf("body=")
+        val body = exception.message!!.substring(start + "body=".length)
+        body.length shouldBe 2049
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt
index abdd453e5edc54d71868b7c23fd3dc9412215ea6..9d4aa696bf426187d313f2d46a45c2ae9a90c1f6 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt
@@ -212,14 +212,14 @@ class DefaultTEKHistoryProviderTest : BaseTest() {
     }
 
     @Test
-    fun `ENFV1_8 pre authorized key release timeout after 20 seconds`() {
+    fun `ENFV1_8 pre authorized key release timeout after 5 seconds`() {
         coEvery { enfVersion.isAtLeast(ENFVersion.V1_8) } returns true
         every { client.requestPreAuthorizedTemporaryExposureKeyRelease() } returns MockGMSTask.timeout()
         verify(exactly = 0) { context.unregisterReceiver(any()) }
 
         runBlockingTest {
             val deferred = async { createInstance().getPreAuthorizedExposureKeys() }
-            advanceTimeBy(21_000)
+            advanceTimeBy(6_000)
             deferred.getCompletionExceptionOrNull() shouldBe instanceOf(TimeoutCancellationException::class)
         }
 
@@ -228,7 +228,7 @@ class DefaultTEKHistoryProviderTest : BaseTest() {
     }
 
     @Test
-    fun `ENFV1_8 pre authorized key release broadcast receiver timeout after 20 seconds`() {
+    fun `ENFV1_8 pre authorized key release broadcast receiver timeout after 5 seconds`() {
         coEvery { enfVersion.isAtLeast(ENFVersion.V1_8) } returns true
 
         // We don't call onReceive
@@ -241,7 +241,7 @@ class DefaultTEKHistoryProviderTest : BaseTest() {
 
         runBlockingTest {
             val deferred = async { createInstance().getPreAuthorizedExposureKeys() }
-            advanceTimeBy(21_000)
+            advanceTimeBy(6_000)
             deferred.getCompletionExceptionOrNull() shouldBe instanceOf(TimeoutCancellationException::class)
         }
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/TimeAndDateExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/TimeAndDateExtensionsTest.kt
index 55039c606fede0fde6b9eadd6f5a2bdc4de1f289..bffa97b6513e12370c53a3d0900235720cdcbd93 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/TimeAndDateExtensionsTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/TimeAndDateExtensionsTest.kt
@@ -4,6 +4,8 @@ import de.rki.coronawarnapp.CoronaWarnApplication
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.ageInDays
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.calculateDays
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.getCurrentHourUTC
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
+import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.mockkObject
 import io.mockk.unmockkAll
@@ -13,24 +15,29 @@ import org.joda.time.DateTime
 import org.joda.time.DateTimeZone
 import org.joda.time.Instant
 import org.joda.time.LocalDate
-import org.junit.After
-import org.junit.Assert
-import org.junit.Before
-import org.junit.Test
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
 import java.util.concurrent.TimeUnit
 
 /**
  * TimeAndDateExtensions test.
  */
 
-class TimeAndDateExtensionsTest {
+class TimeAndDateExtensionsTest : BaseTest() {
 
-    @Before
+    @BeforeEach
     fun setUp() {
         MockKAnnotations.init(this)
         mockkObject(CoronaWarnApplication)
     }
 
+    @AfterEach
+    fun cleanUp() {
+        unmockkAll()
+    }
+
     @Test
     fun getCurrentHourUTCTest() {
         val result = getCurrentHourUTC()
@@ -48,28 +55,26 @@ class TimeAndDateExtensionsTest {
 
     @Test
     fun test_daysAgo() {
-        Assert.assertEquals(
-            0,
-            LocalDate(2012, 3, 4).ageInDays(
-                LocalDate(2012, 3, 4)
-            )
-        )
-        Assert.assertEquals(
-            2,
-            LocalDate(2013, 12, 31).ageInDays(
-                LocalDate(2014, 1, 2)
-            )
-        )
-        Assert.assertEquals(
-            3,
-            LocalDate(2014, 5, 2).ageInDays(
-                LocalDate(2014, 5, 5)
-            )
-        )
+        LocalDate(2012, 3, 4).ageInDays(
+            LocalDate(2012, 3, 4)
+        ) shouldBe 0
+
+        LocalDate(2013, 12, 31).ageInDays(
+            LocalDate(2014, 1, 2)
+        ) shouldBe 2
+
+        LocalDate(2014, 5, 2).ageInDays(
+            LocalDate(2014, 5, 5)
+        ) shouldBe 3
     }
 
-    @After
-    fun cleanUp() {
-        unmockkAll()
+    @Test
+    fun `instant seconds extension`() {
+        Instant.ofEpochMilli(-1).seconds shouldBe 0
+        Instant.ofEpochMilli(0).seconds shouldBe 0
+        Instant.ofEpochMilli(999).seconds shouldBe 0
+        Instant.ofEpochMilli(1000).seconds shouldBe 1
+        Instant.ofEpochMilli(1999).seconds shouldBe 1
+        Instant.ofEpochMilli(2000).seconds shouldBe 2
     }
 }
diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt
index 2e38ca455a29ba71aeae62febc1759557badd09c..e511f7bdb08327311abd5b460c9aa22a63deb008 100644
--- a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt
+++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt
@@ -39,6 +39,7 @@ class DebugOptionsFragmentViewModelTest : BaseTest() {
         every { environmentSetup.submissionCdnUrl } returns "submissionUrl"
         every { environmentSetup.downloadCdnUrl } returns "downloadUrl"
         every { environmentSetup.verificationCdnUrl } returns "verificationUrl"
+        every { environmentSetup.dataDonationCdnUrl } returns "dataDonationUrl"
 
         every { environmentSetup.currentEnvironment = any() } answers {
             currentEnvironment = arg(0)
diff --git a/fastlane/Screengrabfile b/fastlane/Screengrabfile
index d048aff245234ffdc4efc8fb38a6dd7e9dcccf1f..d914a83a9879e904443a5b827e01c809330c07cf 100644
--- a/fastlane/Screengrabfile
+++ b/fastlane/Screengrabfile
@@ -1,4 +1,4 @@
-locales ['de-DE', 'en-US', 'tr-TR', 'bg-BG', 'pl-PL', 'ro-RO']
+locales ['de-DE', 'en-US']
 use_adb_root true
 clear_previous_screenshots true
 app_package_name 'de.rki.coronawarnapp.test'