diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt
index 6a90f9e2132e68c155bbe1691ea4d197f793da50..8966f716c4a63d2fd8142e319f03d034822c223a 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt
@@ -165,7 +165,8 @@ object HomeData {
         val TEST_SUBMISSION_DONE_ITEM = PcrTestSubmissionDoneCard.Item(
             state = SubmissionDone(
                 testRegisteredAt = Instant.now()
-            )
+            ),
+            onClickAction = {}
         )
     }
 }
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragmentTest.kt
index aa15d484e3d19014de85adbf21aa08caf8ac0c7e..f80a5891dac19a7ad99103df39d43fd339c3b14a 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragmentTest.kt
@@ -8,6 +8,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import dagger.Module
 import dagger.android.ContributesAndroidInjector
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.submission.Symptoms
@@ -54,6 +55,7 @@ class SubmissionSymptomCalendarFragmentTest : BaseUITest() {
         viewModel = spyk(
             SubmissionSymptomCalendarViewModel(
                 Symptoms.Indication.POSITIVE,
+                CoronaTest.Type.PCR,
                 TestDispatcherProvider(),
                 submissionRepository,
                 autoSubmission,
@@ -65,7 +67,10 @@ class SubmissionSymptomCalendarFragmentTest : BaseUITest() {
         }
         setupMockViewModel(
             object : SubmissionSymptomCalendarViewModel.Factory {
-                override fun create(symptomIndication: Symptoms.Indication): SubmissionSymptomCalendarViewModel = viewModel
+                override fun create(
+                    symptomIndication: Symptoms.Indication,
+                    testType: CoronaTest.Type
+                ): SubmissionSymptomCalendarViewModel = viewModel
             }
         )
     }
@@ -80,7 +85,8 @@ class SubmissionSymptomCalendarFragmentTest : BaseUITest() {
     fun capture_fragment() {
         captureScreenshot<SubmissionSymptomCalendarFragment>(
             fragmentArgs = SubmissionSymptomCalendarFragmentArgs(
-                Symptoms.Indication.POSITIVE
+                Symptoms.Indication.POSITIVE,
+                CoronaTest.Type.PCR
             ).toBundle()
         )
 
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomIntroFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomIntroFragmentTest.kt
index b1bf713e0d6302806fa5a017014fbafbcc7e981e..eea3e2c4694675bfed5f4eea8c5473365dacf017 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomIntroFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomIntroFragmentTest.kt
@@ -9,11 +9,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import dagger.Module
 import dagger.android.ContributesAndroidInjector
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.submission.Symptoms
 import de.rki.coronawarnapp.submission.auto.AutoSubmission
 import de.rki.coronawarnapp.ui.submission.symptoms.introduction.SubmissionSymptomIntroductionFragment
+import de.rki.coronawarnapp.ui.submission.symptoms.introduction.SubmissionSymptomIntroductionFragmentArgs
 import de.rki.coronawarnapp.ui.submission.symptoms.introduction.SubmissionSymptomIntroductionViewModel
 import io.mockk.MockKAnnotations
 import io.mockk.every
@@ -58,7 +60,8 @@ class SubmissionSymptomIntroFragmentTest : BaseUITest() {
                 TestDispatcherProvider(),
                 submissionRepository,
                 autoSubmission,
-                analyticsKeySubmissionCollector
+                analyticsKeySubmissionCollector,
+                CoronaTest.Type.PCR
             )
         )
         with(viewModel) {
@@ -66,7 +69,7 @@ class SubmissionSymptomIntroFragmentTest : BaseUITest() {
         }
         setupMockViewModel(
             object : SubmissionSymptomIntroductionViewModel.Factory {
-                override fun create(): SubmissionSymptomIntroductionViewModel = viewModel
+                override fun create(testType: CoronaTest.Type): SubmissionSymptomIntroductionViewModel = viewModel
             }
         )
     }
@@ -78,12 +81,20 @@ class SubmissionSymptomIntroFragmentTest : BaseUITest() {
 
     @Test
     fun launch_fragment() {
-        launchFragment2<SubmissionSymptomIntroductionFragment>()
+        launchFragment2<SubmissionSymptomIntroductionFragment>(
+            fragmentArgs = SubmissionSymptomIntroductionFragmentArgs(
+                CoronaTest.Type.PCR
+            ).toBundle()
+        )
     }
 
     @Test
     fun testSymptomNextClicked() {
-        launchFragmentInContainer2<SubmissionSymptomIntroductionFragment>()
+        launchFragmentInContainer2<SubmissionSymptomIntroductionFragment>(
+            fragmentArgs = SubmissionSymptomIntroductionFragmentArgs(
+                CoronaTest.Type.PCR
+            ).toBundle()
+        )
         onView(withId(R.id.symptom_button_next))
             .perform(click())
     }
@@ -91,7 +102,11 @@ class SubmissionSymptomIntroFragmentTest : BaseUITest() {
     @Test
     @Screenshot
     fun capture_fragment() {
-        captureScreenshot<SubmissionSymptomIntroductionFragment>()
+        captureScreenshot<SubmissionSymptomIntroductionFragment>(
+            fragmentArgs = SubmissionSymptomIntroductionFragmentArgs(
+                CoronaTest.Type.PCR
+            ).toBundle()
+        )
         onView(withId(R.id.target_button_verify))
             .perform(scrollTo())
         takeScreenshot<SubmissionSymptomIntroductionFragment>("2")
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultConsentGivenFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultConsentGivenFragmentTest.kt
index ee50cc5942512829c9b1d2b97dadc71e10bc6819..0a46163947b83aa2efa20f98966ddd6dbbd19496 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultConsentGivenFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultConsentGivenFragmentTest.kt
@@ -14,8 +14,8 @@ import dagger.android.ContributesAndroidInjector
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.submission.auto.AutoSubmission
 import de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNegativeFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNegativeFragmentTest.kt
index 4086ecd6d3cfaa4e29942c3a22c6bce1013b78a4..5439d17591b1392ad69982468357bf208cd4fc5d 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNegativeFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNegativeFragmentTest.kt
@@ -6,7 +6,7 @@ import dagger.Module
 import dagger.android.ContributesAndroidInjector
 import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState
 import de.rki.coronawarnapp.ui.submission.testresult.negative.SubmissionTestResultNegativeFragment
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNoConsentGivenFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNoConsentGivenFragmentTest.kt
index 17de3dcefa6c55abad85cce5cbfedab66367dd3b..8ccf0d97fc63042291fae1d597143cff30ddea52 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNoConsentGivenFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNoConsentGivenFragmentTest.kt
@@ -6,8 +6,8 @@ import dagger.Module
 import dagger.android.ContributesAndroidInjector
 import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState
 import de.rki.coronawarnapp.ui.submission.testresult.positive.SubmissionTestResultConsentGivenFragmentArgs
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt
index ee6dd0085f2953971e9d69e6db99ea8120b27bc9..bffe60b0633d30cd6f696155623dc440c94ce330 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt
@@ -6,8 +6,8 @@ import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings
 import de.rki.coronawarnapp.environment.BuildConfigWrap
-import de.rki.coronawarnapp.presencetracing.TraceLocationSettings
 import de.rki.coronawarnapp.main.CWASettings
+import de.rki.coronawarnapp.presencetracing.TraceLocationSettings
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
@@ -50,14 +50,13 @@ class DeltaOnboardingFragmentViewModel @AssistedInject constructor(
     }
 
     fun isAttendeeOnboardingDone() =
-        traceLocationSettings.onboardingStatus == TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
+        traceLocationSettings.onboardingStatus.value == TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
 
     fun setAttendeeOnboardingDone(value: Boolean) {
-        traceLocationSettings.onboardingStatus =
-            if (value)
-                TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
-            else
-                TraceLocationSettings.OnboardingStatus.NOT_ONBOARDED
+        traceLocationSettings.onboardingStatus.update {
+            if (value) TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
+            else TraceLocationSettings.OnboardingStatus.NOT_ONBOARDED
+        }
     }
 
     @AssistedFactory
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/hometestcards/ui/HomeTestCardsFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/hometestcards/ui/HomeTestCardsFragmentViewModel.kt
index d4676cb5a038497c7547067f24d91da65ae576b9..a91ab2477efe5d3a744713b3dac6397d3d03be1a 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/hometestcards/ui/HomeTestCardsFragmentViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/hometestcards/ui/HomeTestCardsFragmentViewModel.kt
@@ -46,7 +46,7 @@ class HomeTestCardsFragmentViewModel @AssistedInject constructor(
             PcrTestErrorCard.Item(SubmissionStatePCR.TestError) {},
             PcrTestNegativeCard.Item(SubmissionStatePCR.TestNegative(Instant.now())) {},
             PcrTestPositiveCard.Item(SubmissionStatePCR.TestPositive(Instant.now())) {},
-            PcrTestSubmissionDoneCard.Item(SubmissionStatePCR.SubmissionDone(Instant.now())),
+            PcrTestSubmissionDoneCard.Item(SubmissionStatePCR.SubmissionDone(Instant.now())) {},
             RapidTestPendingCard.Item(SubmissionStateRAT.TestPending) {},
             RapidTestReadyCard.Item(SubmissionStateRAT.TestResultReady) {},
             RapidTestInvalidCard.Item(SubmissionStateRAT.TestInvalid) {},
@@ -54,7 +54,7 @@ class HomeTestCardsFragmentViewModel @AssistedInject constructor(
             RapidTestErrorCard.Item(SubmissionStateRAT.TestError) {},
             RapidTestNegativeCard.Item(SubmissionStateRAT.TestNegative(Instant.now())) {},
             RapidTestPositiveCard.Item(SubmissionStateRAT.TestPositive(Instant.now())) {},
-            RapidTestSubmissionDoneCard.Item(SubmissionStateRAT.SubmissionDone(Instant.now()))
+            RapidTestSubmissionDoneCard.Item(SubmissionStateRAT.SubmissionDone(Instant.now())) {}
         )
     )
 
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt
index d8968b77d5260df6292fb3eb131ad0e9685fa404..844ca50ad281430fcca6ae8e1df30f9a262597ac 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt
@@ -122,23 +122,25 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
             riskLevel = latestCalc.riskState,
             riskLevelLastSuccessfulCalculated = latestSuccessfulCalc.riskState,
             matchedKeyCount = latestCalc.matchedKeyCount,
-            daysSinceLastExposure = latestCalc.daysWithEncounters,
+            noOfDaysWithExposures = if (latestCalc.riskState == RiskState.INCREASED_RISK)
+                latestCalc.ewAggregatedRiskResult?.numberOfDaysWithHighRisk ?: 0
+            else latestCalc.ewAggregatedRiskResult?.numberOfDaysWithLowRisk ?: 0,
             lastKeySubmission = latestSubmission?.startedAt
         )
     }.asLiveData()
 
-    private suspend fun createAdditionalRiskCalcInfo(
+    private fun createAdditionalRiskCalcInfo(
         lastTimeRiskLevelCalculation: Instant,
         riskLevel: RiskState,
         riskLevelLastSuccessfulCalculated: RiskState,
         matchedKeyCount: Int,
-        daysSinceLastExposure: Int,
+        noOfDaysWithExposures: Int,
         lastKeySubmission: Instant?
     ): String = StringBuilder()
         .appendLine("Risk Level: $riskLevel")
         .appendLine("Last successful Risk Level: $riskLevelLastSuccessfulCalculated")
         .appendLine("Matched key count: $matchedKeyCount")
-        .appendLine("Days since last Exposure: $daysSinceLastExposure days")
+        .appendLine("Days with exposures: $noOfDaysWithExposures days")
         .appendLine("Last key submission: $lastKeySubmission")
         .appendLine("Last time risk level calculation $lastTimeRiskLevelCalculation")
         .toString()
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 b2d67700ee839cee11b6e2e8dabbe454500ea6ab..61a3c11368011a9e30387a568b32cbe9e4661fb5 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
@@ -17,14 +17,20 @@ import de.rki.coronawarnapp.bugreporting.loghistory.LogHistoryTree
 import de.rki.coronawarnapp.contactdiary.retention.ContactDiaryWorkScheduler
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.coronatest.notification.ShareTestResultNotificationService
+import de.rki.coronawarnapp.coronatest.type.pcr.execution.PCRResultScheduler
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultScheduler
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.notification.RATTestResultAvailableNotificationService
 import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsScheduler
 import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler
 import de.rki.coronawarnapp.exception.reporting.ErrorReportReceiver
 import de.rki.coronawarnapp.exception.reporting.ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL
 import de.rki.coronawarnapp.notification.GeneralNotifications
 import de.rki.coronawarnapp.presencetracing.checkins.checkout.auto.AutoCheckOut
+import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingRiskWorkScheduler
 import de.rki.coronawarnapp.presencetracing.storage.retention.TraceLocationDbCleanUpScheduler
 import de.rki.coronawarnapp.risk.RiskLevelChangeDetector
+import de.rki.coronawarnapp.risk.execution.ExposureWindowRiskWorkScheduler
 import de.rki.coronawarnapp.storage.OnboardingSettings
 import de.rki.coronawarnapp.submission.auto.AutoSubmission
 import de.rki.coronawarnapp.task.TaskController
@@ -33,7 +39,6 @@ import de.rki.coronawarnapp.util.WatchdogService
 import de.rki.coronawarnapp.util.device.ForegroundState
 import de.rki.coronawarnapp.util.di.AppInjector
 import de.rki.coronawarnapp.util.di.ApplicationComponent
-import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.launchIn
@@ -68,8 +73,13 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
     @Inject lateinit var onboardingSettings: OnboardingSettings
     @Inject lateinit var autoCheckOut: AutoCheckOut
     @Inject lateinit var traceLocationDbCleanupScheduler: TraceLocationDbCleanUpScheduler
-    @Inject lateinit var backgroundWorkScheduler: BackgroundWorkScheduler
     @Inject lateinit var shareTestResultNotificationService: ShareTestResultNotificationService
+    @Inject lateinit var exposureWindowRiskWorkScheduler: ExposureWindowRiskWorkScheduler
+    @Inject lateinit var presenceTracingRiskWorkScheduler: PresenceTracingRiskWorkScheduler
+    @Inject lateinit var pcrTestResultScheduler: PCRResultScheduler
+    @Inject lateinit var raTestResultScheduler: RAResultScheduler
+    @Inject lateinit var pcrTestResultAvailableNotificationService: PCRTestResultAvailableNotificationService
+    @Inject lateinit var raTestResultAvailableNotificationService: RATTestResultAvailableNotificationService
 
     @LogHistoryTree @Inject lateinit var rollingLogHistory: Timber.Tree
 
@@ -115,6 +125,18 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
             contactDiaryWorkScheduler.schedulePeriodic()
         }
 
+        Timber.v("Setting up risk work schedulers.")
+        exposureWindowRiskWorkScheduler.setup()
+        presenceTracingRiskWorkScheduler.setup()
+
+        Timber.v("Setting up test result work schedulers.")
+        pcrTestResultScheduler.setup()
+        raTestResultScheduler.setup()
+
+        Timber.v("Setting up test result available notification services.")
+        pcrTestResultAvailableNotificationService.setup()
+        raTestResultAvailableNotificationService.setup()
+
         deviceTimeHandler.launch()
         configChangeDetector.launch()
         riskLevelChangeDetector.launch()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/location/ContactDiaryAddLocationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/location/ContactDiaryAddLocationFragment.kt
index 0a27b0f12f5b6fdf078015815167b6190a528c45..bc0aa5196e4d3bf50bdea60654275aa4ad8913a1 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/location/ContactDiaryAddLocationFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/location/ContactDiaryAddLocationFragment.kt
@@ -58,7 +58,6 @@ class ContactDiaryAddLocationFragment : Fragment(R.layout.contact_diary_add_loca
                     DialogHelper.showDialog(deleteLocationConfirmationDialog)
                 }
                 locationSaveButton.setOnClickListener {
-                    it.hideKeyboard()
                     viewModel.updateLocation(
                         location,
                         phoneNumber = binding.locationPhoneInput.text.toString(),
@@ -71,7 +70,6 @@ class ContactDiaryAddLocationFragment : Fragment(R.layout.contact_diary_add_loca
             binding.apply {
                 locationDeleteButton.visibility = View.GONE
                 locationSaveButton.setOnClickListener {
-                    it.hideKeyboard()
                     viewModel.addLocation(
                         phoneNumber = binding.locationPhoneInput.text.toString(),
                         emailAddress = binding.locationEmailInput.text.toString()
@@ -84,7 +82,6 @@ class ContactDiaryAddLocationFragment : Fragment(R.layout.contact_diary_add_loca
             locationNameInputEdit.focusAndShowKeyboard()
 
             locationCloseButton.setOnClickListener {
-                it.hideKeyboard()
                 viewModel.closePressed()
             }
             locationNameInputEdit.doAfterTextChanged {
@@ -105,6 +102,7 @@ class ContactDiaryAddLocationFragment : Fragment(R.layout.contact_diary_add_loca
         }
 
         viewModel.shouldClose.observe2(this) {
+            binding.root.hideKeyboard()
             popBackStack()
         }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/person/ContactDiaryAddPersonFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/person/ContactDiaryAddPersonFragment.kt
index 88004506f32bd558f5300c5543bc00f94329801b..6379a87784dbd0f727ee8246d3de1233cf4904c7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/person/ContactDiaryAddPersonFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/person/ContactDiaryAddPersonFragment.kt
@@ -60,7 +60,6 @@ class ContactDiaryAddPersonFragment :
                     DialogHelper.showDialog(deletePersonConfirmationDialog)
                 }
                 personSaveButton.setOnClickListener {
-                    it.hideKeyboard()
                     viewModel.updatePerson(
                         person,
                         phoneNumber = binding.personPhoneNumberInput.text.toString(),
@@ -72,7 +71,6 @@ class ContactDiaryAddPersonFragment :
         } else {
             binding.personDeleteButton.visibility = View.GONE
             binding.personSaveButton.setOnClickListener {
-                it.hideKeyboard()
                 viewModel.addPerson(
                     phoneNumber = binding.personPhoneNumberInput.text.toString(),
                     emailAddress = binding.personEmailInput.text.toString()
@@ -84,7 +82,6 @@ class ContactDiaryAddPersonFragment :
             personNameInput.focusAndShowKeyboard()
 
             personCloseButton.setOnClickListener {
-                it.hideKeyboard()
                 viewModel.closePressed()
             }
             personNameInput.doAfterTextChanged {
@@ -105,6 +102,7 @@ class ContactDiaryAddPersonFragment :
         }
 
         viewModel.shouldClose.observe2(this) {
+            binding.root.hideKeyboard()
             popBackStack()
         }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepositoryExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepositoryExtensions.kt
index 8237875c2262584de2afbacaaf9c6e735221b9ef..b7a7d6ae325b0532a13dd3e4af231c21120d5070 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepositoryExtensions.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepositoryExtensions.kt
@@ -24,3 +24,11 @@ val CoronaTestRepository.latestRAT: Flow<RACoronaTest?>
             } as? RACoronaTest
         }
         .distinctUntilChanged()
+
+/**
+ * Should we keep the background workers for our risk results running?
+ */
+val CoronaTestRepository.isRiskCalculationNecessary: Flow<Boolean>
+    get() = coronaTests.map { tests ->
+        tests.none { it.isPositive }
+    }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/migration/PCRTestMigration.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/migration/PCRTestMigration.kt
index 851c81cd75815948ad67746b31df4bc4e98d6d71..b17da90d567138dfbfcfc35321c107ea49ad02c5 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/migration/PCRTestMigration.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/migration/PCRTestMigration.kt
@@ -65,6 +65,7 @@ class PCRTestMigration @Inject constructor(
             identifier = LEGACY_IDENTIFIER,
             registrationToken = token,
             registeredAt = devicePairingSuccessfulAt,
+            lastUpdatedAt = devicePairingSuccessfulAt,
             testResult = when (isAllowedToSubmitKeys) {
                 true -> CoronaTestResult.PCR_POSITIVE
                 else -> CoronaTestResult.PCR_OR_RAT_PENDING
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
index 2765647ace33c830b23204f4d1bfa98ce890b64a..02353dcc1c56b302960768f6c690b45cb8ba04fd 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
@@ -22,9 +22,16 @@ interface CoronaTest {
 
     val isPending: Boolean
 
+    /**
+     * Has this test reached it's final state, i.e. can polling be stopped?
+     */
+    val isFinal: Boolean
+
     val testResultReceivedAt: Instant?
     val testResult: CoronaTestResult
 
+    val lastUpdatedAt: Instant
+
     // TODO why do we need this PER test
     val isAdvancedConsentGiven: Boolean
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/common/ResultScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/common/ResultScheduler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ec82a67bee20feea0983a739491668e70d9343f0
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/common/ResultScheduler.kt
@@ -0,0 +1,28 @@
+package de.rki.coronawarnapp.coronatest.type.common
+
+import androidx.work.WorkInfo
+import androidx.work.WorkManager
+import de.rki.coronawarnapp.util.coroutine.await
+import java.util.concurrent.TimeUnit
+
+open class ResultScheduler(
+    private val workManager: WorkManager,
+) {
+
+    internal suspend fun isScheduled(workerName: String) =
+        workManager.getWorkInfosForUniqueWork(workerName)
+            .await()
+            .any { it.isScheduled }
+
+    internal val WorkInfo.isScheduled: Boolean
+        get() = state == WorkInfo.State.RUNNING || state == WorkInfo.State.ENQUEUED
+
+    companion object {
+        /**
+         * Kind initial delay in minutes for periodic work for accessibility reason
+         *
+         * @see TimeUnit.SECONDS
+         */
+        internal const val TEST_RESULT_PERIODIC_INITIAL_DELAY = 10L
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/TestResultAvailableNotificationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/common/TestResultAvailableNotificationService.kt
similarity index 78%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/TestResultAvailableNotificationService.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/common/TestResultAvailableNotificationService.kt
index db751afd8659e75c4e6c9619f7b86ba60692742a..b6e85bebc655114e7f1b5c25aea02dd645f9c43e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/TestResultAvailableNotificationService.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/common/TestResultAvailableNotificationService.kt
@@ -1,12 +1,14 @@
-package de.rki.coronawarnapp.notification
+package de.rki.coronawarnapp.coronatest.type.common
 
 import android.content.Context
-import androidx.annotation.IdRes
 import androidx.navigation.NavDeepLinkBuilder
 import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.main.CWASettings
+import de.rki.coronawarnapp.notification.GeneralNotifications
+import de.rki.coronawarnapp.notification.NotificationId
 import de.rki.coronawarnapp.ui.main.MainActivity
+import de.rki.coronawarnapp.ui.submission.testresult.pending.SubmissionTestResultPendingFragmentArgs
 import de.rki.coronawarnapp.util.device.ForegroundState
 import de.rki.coronawarnapp.util.notifications.setContentTextExpandable
 import kotlinx.coroutines.flow.first
@@ -20,11 +22,10 @@ open class TestResultAvailableNotificationService(
     private val notificationHelper: GeneralNotifications,
     private val cwaSettings: CWASettings,
     private val notificationId: NotificationId,
-    @IdRes private val destination: Int
 ) {
 
-    suspend fun showTestResultAvailableNotification(testResult: CoronaTestResult) {
-        Timber.d("showTestResultAvailableNotification(testResult=%s)", testResult)
+    suspend fun showTestResultAvailableNotification(test: CoronaTest) {
+        Timber.d("showTestResultAvailableNotification(test=%s)", test)
 
         if (foregroundState.isInForeground.first()) {
             Timber.d("App in foreground, skipping notification.")
@@ -39,6 +40,11 @@ open class TestResultAvailableNotificationService(
         val pendingIntent = navDeepLinkBuilderProvider.get().apply {
             setGraph(R.navigation.nav_graph)
             setComponentName(MainActivity::class.java)
+            setArguments(
+                SubmissionTestResultPendingFragmentArgs(
+                    testType = test.type
+                ).toBundle()
+            )
             /*
              * The pending result fragment will forward to the correct screen
              * Because we can't save the test result at the moment (legal),
@@ -48,7 +54,7 @@ open class TestResultAvailableNotificationService(
              * By letting the forwarding happen via the PendingResultFragment,
              * we have a common location to retrieve the test result.
              */
-            setDestination(destination)
+            setDestination(R.id.submissionTestResultPendingFragment)
         }.createPendingIntent()
 
         val notification = notificationHelper.newBaseBuilder().apply {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt
index 6c03147679533ab7bbc0740d85ab20c5aa0aa01a..78c38a1d8bbd7db4fd170f1452f6d226b6c0975d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt
@@ -38,6 +38,9 @@ data class PCRCoronaTest(
     @SerializedName("testResult")
     override val testResult: CoronaTestResult,
 
+    @SerializedName("lastUpdatedAt")
+    override val lastUpdatedAt: Instant,
+
     @Transient override val isProcessing: Boolean = false,
     @Transient override val lastError: Throwable? = null,
 ) : CoronaTest {
@@ -45,6 +48,9 @@ data class PCRCoronaTest(
     override val type: CoronaTest.Type
         get() = CoronaTest.Type.PCR
 
+    override val isFinal: Boolean
+        get() = testResult == CoronaTestResult.PCR_REDEEMED
+
     override val isPositive: Boolean
         get() = testResult == CoronaTestResult.PCR_POSITIVE
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessor.kt
index 59848afdd093d0bb04c1dfcf49e8b2410aa2b9c2..88cd240a69b8b3b32f85299bd645dc620953c6b6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessor.kt
@@ -18,7 +18,6 @@ import de.rki.coronawarnapp.coronatest.tan.CoronaTestTAN
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.coronatest.type.CoronaTestProcessor
 import de.rki.coronawarnapp.coronatest.type.CoronaTestService
-import de.rki.coronawarnapp.coronatest.worker.execution.PCRResultScheduler
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.datadonation.analytics.modules.registeredtest.TestResultDataCollector
 import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler
@@ -26,6 +25,8 @@ import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.http.CwaWebException
 import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.util.TimeStamper
+import de.rki.coronawarnapp.worker.BackgroundConstants
+import org.joda.time.Duration
 import org.joda.time.Instant
 import timber.log.Timber
 import javax.inject.Inject
@@ -37,7 +38,6 @@ class PCRProcessor @Inject constructor(
     private val analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector,
     private val testResultDataCollector: TestResultDataCollector,
     private val deadmanNotificationScheduler: DeadmanNotificationScheduler,
-    private val pcrTestResultScheduler: PCRResultScheduler,
 ) : CoronaTestProcessor {
 
     override val type: CoronaTest.Type = CoronaTest.Type.PCR
@@ -81,13 +81,12 @@ class PCRProcessor @Inject constructor(
 
         analyticsKeySubmissionCollector.reportTestRegistered()
 
-        if (testResult == PCR_OR_RAT_PENDING) {
-            pcrTestResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = true)
-        }
+        val now = timeStamper.nowUTC
 
         return PCRCoronaTest(
             identifier = request.identifier,
-            registeredAt = timeStamper.nowUTC,
+            registeredAt = now,
+            lastUpdatedAt = now,
             registrationToken = response.registrationToken,
             testResult = testResult,
             testResultReceivedAt = determineReceivedDate(null, testResult),
@@ -117,8 +116,9 @@ class PCRProcessor @Inject constructor(
             }
 
             test.copy(
-                testResult = newTestResult,
+                testResult = check60PlusDays(test, newTestResult),
                 testResultReceivedAt = determineReceivedDate(test, newTestResult),
+                lastUpdatedAt = timeStamper.nowUTC,
                 lastError = null
             )
         } catch (e: Exception) {
@@ -130,6 +130,19 @@ class PCRProcessor @Inject constructor(
         }
     }
 
+    // After 60 days, the previously EXPIRED test is deleted from the server, and it will return pending again.
+    private fun check60PlusDays(test: CoronaTest, newResult: CoronaTestResult): CoronaTestResult {
+        val calculateDays = Duration(test.registeredAt, timeStamper.nowUTC).standardDays
+        Timber.tag(TAG).d("Calculated test age: %d days", calculateDays)
+
+        return if (newResult == PCR_OR_RAT_PENDING && calculateDays >= BackgroundConstants.POLLING_VALIDITY_MAX_DAYS) {
+            Timber.tag(TAG).d("$calculateDays is exceeding the maximum polling duration")
+            PCR_REDEEMED
+        } else {
+            newResult
+        }
+    }
+
     private fun determineReceivedDate(oldTest: PCRCoronaTest?, newTestResult: CoronaTestResult): Instant? = when {
         oldTest != null && FINAL_STATES.contains(oldTest.testResult) -> oldTest.testResultReceivedAt
         FINAL_STATES.contains(newTestResult) -> timeStamper.nowUTC
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/execution/PCRResultRetrievalWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/execution/PCRResultRetrievalWorker.kt
new file mode 100644
index 0000000000000000000000000000000000000000..74c5e98d67fe5a1bbaf3e5fc138846e167dbc4f6
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/execution/PCRResultRetrievalWorker.kt
@@ -0,0 +1,65 @@
+package de.rki.coronawarnapp.coronatest.type.pcr.execution
+
+import android.content.Context
+import androidx.work.CoroutineWorker
+import androidx.work.WorkerParameters
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.latestPCRT
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
+import de.rki.coronawarnapp.util.worker.InjectedWorkerFactory
+import de.rki.coronawarnapp.worker.BackgroundConstants
+import kotlinx.coroutines.flow.first
+import timber.log.Timber
+
+/**
+ * Diagnosis test result retrieval by periodic polling
+ */
+class PCRResultRetrievalWorker @AssistedInject constructor(
+    @Assisted val context: Context,
+    @Assisted workerParams: WorkerParameters,
+    private val coronaTestRepository: CoronaTestRepository,
+) : CoroutineWorker(context, workerParams) {
+
+    override suspend fun doWork(): Result {
+        Timber.tag(TAG).d("$id: doWork() started. Run attempt: $runAttemptCount")
+
+        if (runAttemptCount > BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD) {
+            Timber.tag(TAG).d("$id doWork() failed after $runAttemptCount attempts. Resuming at normal period.")
+            return Result.failure()
+        }
+
+        try {
+            val pcrTest = coronaTestRepository.latestPCRT.first()
+            Timber.tag(TAG).v("Current PCR test: %s", pcrTest)
+
+            if (pcrTest == null) {
+                // PCRResultScheduler will cancel us if test is null or test.isFinal == true
+                Timber.tag(TAG).d(" $id Stopping worker, there is no PCR test.")
+                return Result.success()
+            }
+
+            Timber.tag(TAG).d(" $id Running task.")
+            val coronaTest = coronaTestRepository.refresh(
+                type = CoronaTest.Type.PCR
+            ).single() as PCRCoronaTest
+            val testResult = coronaTest.testResult
+            Timber.tag(TAG).d("$id: Test result retrieved is $testResult")
+
+            return Result.success()
+        } catch (e: Exception) {
+            Timber.tag(TAG).e(e, "Test result retrieval worker failed.")
+            return Result.retry()
+        }
+    }
+
+    @AssistedFactory
+    interface Factory : InjectedWorkerFactory<PCRResultRetrievalWorker>
+
+    companion object {
+        private val TAG = PCRResultRetrievalWorker::class.java.simpleName
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/execution/PCRResultScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/execution/PCRResultScheduler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..32f1e570bbf8a4093ce5cffd585239ab5a549b7a
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/execution/PCRResultScheduler.kt
@@ -0,0 +1,105 @@
+package de.rki.coronawarnapp.coronatest.type.pcr.execution
+
+import androidx.annotation.VisibleForTesting
+import androidx.work.BackoffPolicy
+import androidx.work.Constraints
+import androidx.work.ExistingPeriodicWorkPolicy
+import androidx.work.NetworkType
+import androidx.work.PeriodicWorkRequestBuilder
+import androidx.work.WorkManager
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.latestPCRT
+import de.rki.coronawarnapp.coronatest.type.common.ResultScheduler
+import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
+import de.rki.coronawarnapp.util.coroutine.AppScope
+import de.rki.coronawarnapp.worker.BackgroundConstants
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import timber.log.Timber
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class PCRResultScheduler @Inject constructor(
+    @AppScope private val appScope: CoroutineScope,
+    private val workManager: WorkManager,
+    private val coronaTestRepository: CoronaTestRepository,
+) : ResultScheduler(
+    workManager = workManager
+) {
+
+    @VisibleForTesting
+    internal val shouldBePolling = coronaTestRepository.latestPCRT
+        .map { test: PCRCoronaTest? ->
+            if (test == null) return@map false
+            !test.isFinal
+        }
+        .distinctUntilChanged()
+
+    fun setup() {
+        Timber.tag(TAG).i("setup() - PCRResultScheduler")
+        shouldBePolling
+            .onEach { shouldBePolling ->
+                Timber.tag(TAG).d("Polling state change: shouldBePolling=$shouldBePolling")
+                setPcrPeriodicTestPollingEnabled(enabled = shouldBePolling)
+            }
+            .launchIn(appScope)
+    }
+
+    internal suspend fun setPcrPeriodicTestPollingEnabled(enabled: Boolean) {
+        Timber.tag(TAG).i("setPcrPeriodicTestPollingEnabled(enabled=$enabled)")
+        if (enabled) {
+            val isScheduled = isScheduled(PCR_TESTRESULT_WORKER_UNIQUEUNAME)
+            Timber.tag(TAG).d("isScheduled=$isScheduled")
+
+            Timber.tag(TAG).d("enqueueUniquePeriodicWork PCR_TESTRESULT_WORKER_UNIQUEUNAME")
+            workManager.enqueueUniquePeriodicWork(
+                PCR_TESTRESULT_WORKER_UNIQUEUNAME,
+                ExistingPeriodicWorkPolicy.KEEP,
+                buildPcrTestResultRetrievalPeriodicWork()
+            )
+        } else {
+            Timber.tag(TAG).d("cancelWorker()")
+            workManager.cancelUniqueWork(PCR_TESTRESULT_WORKER_UNIQUEUNAME)
+        }
+    }
+
+    private fun buildPcrTestResultRetrievalPeriodicWork() =
+        PeriodicWorkRequestBuilder<PCRResultRetrievalWorker>(
+            getPcrTestResultRetrievalPeriodicWorkTimeInterval(),
+            TimeUnit.MINUTES
+        )
+            .addTag(PCR_TESTRESULT_WORKER_TAG)
+            .setConstraints(
+                Constraints.Builder().apply {
+                    setRequiredNetworkType(NetworkType.CONNECTED)
+                }.build()
+            )
+            .setInitialDelay(
+                TEST_RESULT_PERIODIC_INITIAL_DELAY,
+                TimeUnit.SECONDS
+            ).setBackoffCriteria(
+                BackoffPolicy.LINEAR,
+                BackgroundConstants.KIND_DELAY,
+                TimeUnit.MINUTES
+            )
+            .build()
+
+    companion object {
+        private const val PCR_TESTRESULT_WORKER_TAG = "DIAGNOSIS_TEST_RESULT_PERIODIC_WORKER"
+        private const val PCR_TESTRESULT_WORKER_UNIQUEUNAME = "DiagnosisTestResultBackgroundPeriodicWork"
+
+        private const val TAG = "PCRTestResultScheduler"
+
+        private const val MINUTES_IN_DAY = 1440
+        private const val DIAGNOSIS_TEST_RESULT_RETRIEVAL_TRIES_PER_DAY = 12
+
+        @VisibleForTesting
+        internal fun getPcrTestResultRetrievalPeriodicWorkTimeInterval() =
+            (MINUTES_IN_DAY / DIAGNOSIS_TEST_RESULT_RETRIEVAL_TRIES_PER_DAY).toLong()
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/notification/PCRTestResultAvailableNotificationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/notification/PCRTestResultAvailableNotificationService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d8d631cb6882dac0f50ed6f9592be76f620ec28c
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/notification/PCRTestResultAvailableNotificationService.kt
@@ -0,0 +1,77 @@
+package de.rki.coronawarnapp.coronatest.type.pcr.notification
+
+import android.content.Context
+import androidx.navigation.NavDeepLinkBuilder
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.latestPCRT
+import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
+import de.rki.coronawarnapp.coronatest.type.common.TestResultAvailableNotificationService
+import de.rki.coronawarnapp.main.CWASettings
+import de.rki.coronawarnapp.notification.GeneralNotifications
+import de.rki.coronawarnapp.notification.NotificationConstants
+import de.rki.coronawarnapp.util.coroutine.AppScope
+import de.rki.coronawarnapp.util.device.ForegroundState
+import de.rki.coronawarnapp.util.di.AppContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Provider
+import javax.inject.Singleton
+
+@Singleton
+class PCRTestResultAvailableNotificationService @Inject constructor(
+    @AppContext context: Context,
+    foregroundState: ForegroundState,
+    navDeepLinkBuilderProvider: Provider<NavDeepLinkBuilder>,
+    private val notificationHelper: GeneralNotifications,
+    cwaSettings: CWASettings,
+    private val coronaTestRepository: CoronaTestRepository,
+    @AppScope private val appScope: CoroutineScope,
+) : TestResultAvailableNotificationService(
+    context,
+    foregroundState,
+    navDeepLinkBuilderProvider,
+    notificationHelper,
+    cwaSettings,
+    NotificationConstants.PCR_TEST_RESULT_AVAILABLE_NOTIFICATION_ID
+) {
+    fun setup() {
+        Timber.tag(TAG).d("setup() - PCRTestResultAvailableNotificationService")
+
+        coronaTestRepository.latestPCRT
+            .onEach { _ ->
+                val test = coronaTestRepository.latestPCRT.first()
+                if (test == null) {
+                    cancelTestResultAvailableNotification()
+                    return@onEach
+                }
+
+                val alreadySent = test.isResultAvailableNotificationSent
+                val isInteresting = INTERESTING_STATES.contains(test.testResult)
+                Timber.tag(TAG).v("alreadySent=$alreadySent, isInteresting=$isInteresting")
+
+                if (!alreadySent && isInteresting) {
+                    coronaTestRepository.updateResultNotification(identifier = test.identifier, sent = true)
+                    showTestResultAvailableNotification(test)
+                    notificationHelper.cancelCurrentNotification(
+                        NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
+                    )
+                } else {
+                    cancelTestResultAvailableNotification()
+                }
+            }
+            .launchIn(appScope)
+    }
+
+    companion object {
+        private val INTERESTING_STATES = setOf(
+            CoronaTestResult.PCR_NEGATIVE,
+            CoronaTestResult.PCR_POSITIVE,
+            CoronaTestResult.PCR_INVALID,
+        )
+        private val TAG = PCRTestResultAvailableNotificationService::class.java.simpleName
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RACoronaTest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RACoronaTest.kt
index 8bb272b108fc3fa5ab88699f8ae3fb2d4c3d534a..6e353f9b996d7bc56855c91a13ebd4e1ef4e9351 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RACoronaTest.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RACoronaTest.kt
@@ -43,6 +43,9 @@ data class RACoronaTest(
     @SerializedName("testResultReceivedAt")
     override val testResultReceivedAt: Instant? = null,
 
+    @SerializedName("lastUpdatedAt")
+    override val lastUpdatedAt: Instant,
+
     @SerializedName("testResult")
     override val testResult: CoronaTestResult,
 
@@ -50,13 +53,13 @@ data class RACoronaTest(
     val testedAt: Instant,
 
     @SerializedName("firstName")
-    val firstName: String?,
+    val firstName: String? = null,
 
     @SerializedName("lastName")
-    val lastName: String?,
+    val lastName: String? = null,
 
     @SerializedName("dateOfBirth")
-    val dateOfBirth: LocalDate?,
+    val dateOfBirth: LocalDate? = null,
 
     @Transient override val isProcessing: Boolean = false,
     @Transient override val lastError: Throwable? = null,
@@ -83,6 +86,9 @@ data class RACoronaTest(
             }
         }
 
+    override val isFinal: Boolean
+        get() = testResult == RAT_REDEEMED
+
     override val isPositive: Boolean
         get() = testResult == RAT_POSITIVE
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensions.kt
index 598d434590a5f7523820adcc5273c33aaf1a32e2..523b6f2a00fedbfc9ca08d03d5fb3023cb30f43a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensions.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensions.kt
@@ -9,6 +9,7 @@ import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest.State.POSI
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest.State.REDEEMED
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.SubmissionStateRAT.FetchingResult
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.SubmissionStateRAT.NoTest
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.SubmissionStateRAT.SubmissionDone
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.SubmissionStateRAT.TestError
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.SubmissionStateRAT.TestInvalid
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.SubmissionStateRAT.TestNegative
@@ -21,6 +22,7 @@ import org.joda.time.Instant
 
 fun RACoronaTest?.toSubmissionState(nowUTC: Instant = Instant.now(), coronaTestConfig: CoronaTestConfig) = when {
     this == null -> NoTest
+    isSubmitted -> SubmissionDone(testRegisteredAt = registeredAt)
     isProcessing -> FetchingResult
     lastError != null -> if (lastError is CwaServerError) TestPending else TestInvalid
     else -> when (getState(nowUTC, coronaTestConfig)) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessor.kt
index fea68d8229308ecac7e352995eb4a4a2544a6a34..9454ce480a3b245046b45d89fa89be69281cf4bd 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessor.kt
@@ -17,11 +17,12 @@ import de.rki.coronawarnapp.coronatest.tan.CoronaTestTAN
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.coronatest.type.CoronaTestProcessor
 import de.rki.coronawarnapp.coronatest.type.CoronaTestService
-import de.rki.coronawarnapp.coronatest.worker.execution.RAResultScheduler
 import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.http.CwaWebException
 import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.util.TimeStamper
+import de.rki.coronawarnapp.worker.BackgroundConstants
+import org.joda.time.Duration
 import org.joda.time.Instant
 import timber.log.Timber
 import javax.inject.Inject
@@ -30,7 +31,6 @@ import javax.inject.Inject
 class RapidAntigenProcessor @Inject constructor(
     private val timeStamper: TimeStamper,
     private val submissionService: CoronaTestService,
-    private val resultScheduler: RAResultScheduler,
 ) : CoronaTestProcessor {
 
     override val type: CoronaTest.Type = CoronaTest.Type.RAPID_ANTIGEN
@@ -43,13 +43,12 @@ class RapidAntigenProcessor @Inject constructor(
 
         val testResult = registrationData.testResult.validOrThrow()
 
-        if (testResult == PCR_OR_RAT_PENDING || testResult == RAT_PENDING) {
-            resultScheduler.setRatResultPeriodicPollingMode(mode = RAResultScheduler.RatPollingMode.PHASE1)
-        }
+        val now = timeStamper.nowUTC
 
         return RACoronaTest(
             identifier = request.identifier,
-            registeredAt = timeStamper.nowUTC,
+            registeredAt = now,
+            lastUpdatedAt = now,
             registrationToken = registrationData.registrationToken,
             testResult = testResult,
             testResultReceivedAt = determineReceivedDate(null, testResult),
@@ -82,11 +81,13 @@ class RapidAntigenProcessor @Inject constructor(
                 return test
             }
 
-            val testResult = submissionService.asyncRequestTestResult(test.registrationToken)
-            Timber.tag(TAG).d("Test result was %s", testResult)
+            val newTestResult = submissionService.asyncRequestTestResult(test.registrationToken)
+            Timber.tag(TAG).d("Test result was %s", newTestResult)
 
             test.copy(
-                testResult = testResult,
+                testResult = check60PlusDays(test, newTestResult),
+                testResultReceivedAt = determineReceivedDate(test, newTestResult),
+                lastUpdatedAt = timeStamper.nowUTC,
                 lastError = null
             )
         } catch (e: Exception) {
@@ -98,6 +99,22 @@ class RapidAntigenProcessor @Inject constructor(
         }
     }
 
+    // After 60 days, the previously EXPIRED test is deleted from the server, and it will return pending again.
+    private fun check60PlusDays(test: CoronaTest, newResult: CoronaTestResult): CoronaTestResult {
+        val calculateDays = Duration(test.registeredAt, timeStamper.nowUTC).standardDays
+        Timber.tag(TAG).d("Calculated test age: %d days", calculateDays)
+
+        return if (
+            (newResult == PCR_OR_RAT_PENDING || newResult == RAT_PENDING) &&
+            calculateDays >= BackgroundConstants.POLLING_VALIDITY_MAX_DAYS
+        ) {
+            Timber.tag(TAG).d("$calculateDays is exceeding the maximum polling duration")
+            RAT_REDEEMED
+        } else {
+            newResult
+        }
+    }
+
     override suspend fun onRemove(toBeRemoved: CoronaTest) {
         Timber.tag(TAG).v("onRemove(toBeRemoved=%s)", toBeRemoved)
         // Currently nothing to do
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/RAResultRetrievalWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/execution/RAResultRetrievalWorker.kt
similarity index 50%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/RAResultRetrievalWorker.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/execution/RAResultRetrievalWorker.kt
index 4ee68a0d4632e2625969346105aa15b2322aa085..f390af2d9402a3847e19e32251bb96a3764a1d7e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/RAResultRetrievalWorker.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/execution/RAResultRetrievalWorker.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.coronatest.worker
+package de.rki.coronawarnapp.coronatest.type.rapidantigen.execution
 
 import android.content.Context
 import androidx.work.CoroutineWorker
@@ -9,10 +9,8 @@ import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.coronatest.latestRAT
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
-import de.rki.coronawarnapp.coronatest.worker.execution.RAResultScheduler
-import de.rki.coronawarnapp.coronatest.worker.execution.RAResultScheduler.RatPollingMode.DISABLED
-import de.rki.coronawarnapp.coronatest.worker.execution.RAResultScheduler.RatPollingMode.PHASE1
-import de.rki.coronawarnapp.coronatest.worker.execution.RAResultScheduler.RatPollingMode.PHASE2
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultScheduler.RatPollingMode.PHASE1
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultScheduler.RatPollingMode.PHASE2
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.worker.InjectedWorkerFactory
 import de.rki.coronawarnapp.worker.BackgroundConstants
@@ -35,56 +33,41 @@ class RAResultRetrievalWorker @AssistedInject constructor(
         Timber.tag(TAG).d("$id: doWork() started. Run attempt: $runAttemptCount")
 
         if (runAttemptCount > BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD) {
-            Timber.tag(TAG).d("$id doWork() failed after $runAttemptCount attempts. Rescheduling")
-
-            ratResultScheduler.setRatResultPeriodicPollingMode(mode = ratResultScheduler.ratResultPeriodicPollingMode)
-            Timber.tag(TAG).d("$id Rescheduled background worker")
-
+            Timber.tag(TAG).d("$id doWork() failed after $runAttemptCount attempts. Resuming at normal period.")
             return Result.failure()
         }
 
-        // checking abort conditions
-        val rat = coronaTestRepository.latestRAT.first()
-        if (rat == null) {
-            Timber.tag(TAG).w("There is no RAT test available!?")
-            disablePolling()
-            return Result.success()
-        } else {
+        try {
+            val rat = coronaTestRepository.latestRAT.first()
+            Timber.tag(TAG).v("Current RA test: %s", rat)
+
+            if (rat == null) {
+                // RAResultScheduler will cancel us if the test is null or isFinal==true
+                Timber.tag(TAG).w("There is no RapidAntigen test available!?")
+                return Result.success()
+            }
+
+            coronaTestRepository.refresh(CoronaTest.Type.RAPID_ANTIGEN)
+
             val nowUTC = timeStamper.nowUTC
             val days = Duration(rat.registeredAt, nowUTC).standardDays
             val minutes = Duration(rat.registeredAt, nowUTC).standardMinutes
             val isPhase1 = ratResultScheduler.ratResultPeriodicPollingMode == PHASE1
             Timber.tag(TAG).d("Calculated days: %d", days)
-            when {
-                rat.isResultAvailableNotificationSent -> {
-                    Timber.tag(TAG).d("$id: Notification already sent.")
-                    disablePolling()
-                }
-                rat.isViewed -> {
-                    Timber.tag(TAG).d("$id: Test result has already been viewed.")
-                    disablePolling()
-                }
-                days >= BackgroundConstants.POLLING_VALIDITY_MAX_DAYS -> {
-                    Timber.tag(TAG).d("$id $days is exceeding the maximum polling duration")
-                    disablePolling()
-                }
-                isPhase1 && minutes >= RAT_POLLING_END_OF_PHASE1_MINUTES -> {
-                    Timber.tag(TAG).d("$id $minutes minutes - time for a phase 2!")
-                    ratResultScheduler.setRatResultPeriodicPollingMode(mode = PHASE2)
-                }
-                else -> {
-                    coronaTestRepository.refresh(CoronaTest.Type.RAPID_ANTIGEN)
-                }
+
+            // Time for phase2?
+            if (isPhase1 && minutes >= RAT_POLLING_END_OF_PHASE1_MINUTES) {
+                Timber.tag(TAG).d("$id $minutes minutes - time for a phase 2!")
+                ratResultScheduler.setRatResultPeriodicPollingMode(mode = PHASE2)
             }
+
             return Result.success()
+        } catch (e: Exception) {
+            Timber.tag(TAG).e(e, "Test result retrieval worker failed.")
+            return Result.retry()
         }
     }
 
-    private fun disablePolling() {
-        ratResultScheduler.setRatResultPeriodicPollingMode(mode = DISABLED)
-        Timber.tag(TAG).d("$id: polling disabled")
-    }
-
     @AssistedFactory
     interface Factory : InjectedWorkerFactory<RAResultRetrievalWorker>
 
@@ -93,8 +76,6 @@ class RAResultRetrievalWorker @AssistedInject constructor(
 
         /**
          * The time when rat polling is switched to a larger interval
-         *
-         * @see TimeUnit.MINUTES
          */
         private const val RAT_POLLING_END_OF_PHASE1_MINUTES = 90
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/execution/RAResultScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/execution/RAResultScheduler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0b5c894f2c8f3bcdce19ac42e1fd83fb453ccf59
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/execution/RAResultScheduler.kt
@@ -0,0 +1,127 @@
+package de.rki.coronawarnapp.coronatest.type.rapidantigen.execution
+
+import androidx.work.BackoffPolicy
+import androidx.work.Constraints
+import androidx.work.ExistingPeriodicWorkPolicy
+import androidx.work.NetworkType
+import androidx.work.PeriodicWorkRequest
+import androidx.work.PeriodicWorkRequestBuilder
+import androidx.work.WorkManager
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.latestRAT
+import de.rki.coronawarnapp.coronatest.type.common.ResultScheduler
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultScheduler.RatPollingMode.DISABLED
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultScheduler.RatPollingMode.PHASE1
+import de.rki.coronawarnapp.util.coroutine.AppScope
+import de.rki.coronawarnapp.worker.BackgroundConstants
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import timber.log.Timber
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class RAResultScheduler @Inject constructor(
+    @AppScope private val appScope: CoroutineScope,
+    private val workManager: WorkManager,
+    private val coronaTestRepository: CoronaTestRepository,
+) : ResultScheduler(
+    workManager = workManager
+) {
+
+    private var ratWorkerMode = DISABLED
+    val ratResultPeriodicPollingMode
+        get() = ratWorkerMode
+
+    enum class RatPollingMode {
+        DISABLED,
+        PHASE1,
+        PHASE2
+    }
+
+    fun setup() {
+        Timber.tag(TAG).d("setup() - RAResultScheduler")
+        coronaTestRepository.latestRAT
+            .map { test: RACoronaTest? ->
+                if (test == null) return@map false
+                !test.isFinal
+            }
+            .distinctUntilChanged()
+            .onEach { shouldBePolling ->
+                val isScheduled = isScheduled(RAT_RESULT_WORKER_UNIQUEUNAME)
+                Timber.tag(TAG).d("Polling state change: shouldBePolling=$shouldBePolling, isScheduled=$isScheduled")
+
+                if (shouldBePolling && isScheduled) {
+                    Timber.tag(TAG).d("We are already scheduled, no changing MODE.")
+                } else if (shouldBePolling && !isScheduled) {
+                    Timber.tag(TAG).d("We should be polling, but are not scheduled, scheduling...")
+                    setRatResultPeriodicPollingMode(PHASE1)
+                } else {
+                    Timber.tag(TAG).d("We should not be polling, canceling...")
+                    setRatResultPeriodicPollingMode(DISABLED)
+                }
+            }
+            .launchIn(appScope)
+    }
+
+    internal fun setRatResultPeriodicPollingMode(mode: RatPollingMode) {
+        Timber.tag(TAG).i("setRatResultPeriodicPollingMode(mode=%s)", mode)
+        ratWorkerMode = mode
+        if (mode == DISABLED) {
+            Timber.tag(TAG).d("cancelWorker()")
+            workManager.cancelUniqueWork(RAT_RESULT_WORKER_UNIQUEUNAME)
+        } else {
+            // no check for already running workers!
+            // worker must be replaced by next phase instance
+            Timber.tag(TAG).d("Queueing rat result worker (RAT_RESULT_PERIODIC_WORKER)")
+            workManager.enqueueUniquePeriodicWork(
+                RAT_RESULT_WORKER_UNIQUEUNAME,
+                ExistingPeriodicWorkPolicy.REPLACE,
+                buildRatResultRetrievalPeriodicWork(mode)
+            )
+        }
+    }
+
+    private fun buildRatResultRetrievalPeriodicWork(pollingMode: RatPollingMode): PeriodicWorkRequest {
+        val repeatInterval = if (pollingMode == PHASE1) {
+            ratResultRetrievalPeriodicWorkPhase1IntervalInMinutes
+        } else {
+            ratResultRetrievalPeriodicWorkPhase2IntervalInMinutes
+        }
+        return PeriodicWorkRequestBuilder<RAResultRetrievalWorker>(
+            repeatInterval,
+            TimeUnit.MINUTES
+        )
+            .addTag(RAT_RESULT_WORKER_TAG)
+            .setConstraints(
+                Constraints.Builder().apply {
+                    setRequiredNetworkType(NetworkType.CONNECTED)
+                }.build()
+            )
+            .setInitialDelay(
+                TEST_RESULT_PERIODIC_INITIAL_DELAY,
+                TimeUnit.SECONDS
+            ).setBackoffCriteria(
+                BackoffPolicy.LINEAR,
+                BackgroundConstants.KIND_DELAY,
+                TimeUnit.MINUTES
+            )
+            .build()
+    }
+
+    companion object {
+        private const val RAT_RESULT_WORKER_TAG = "RAT_RESULT_PERIODIC_WORKER"
+        private const val RAT_RESULT_WORKER_UNIQUEUNAME = "RatResultRetrievalWorker"
+
+        private const val TAG = "RAResultScheduler"
+
+        private const val ratResultRetrievalPeriodicWorkPhase1IntervalInMinutes = 15L
+
+        private const val ratResultRetrievalPeriodicWorkPhase2IntervalInMinutes = 90L
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/notification/RATTestResultAvailableNotificationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/notification/RATTestResultAvailableNotificationService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b7d5a0886b296ad610d713b5f1c5c798093e775a
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/notification/RATTestResultAvailableNotificationService.kt
@@ -0,0 +1,78 @@
+package de.rki.coronawarnapp.coronatest.type.rapidantigen.notification
+
+import android.content.Context
+import androidx.navigation.NavDeepLinkBuilder
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.latestPCRT
+import de.rki.coronawarnapp.coronatest.latestRAT
+import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
+import de.rki.coronawarnapp.coronatest.type.common.TestResultAvailableNotificationService
+import de.rki.coronawarnapp.main.CWASettings
+import de.rki.coronawarnapp.notification.GeneralNotifications
+import de.rki.coronawarnapp.notification.NotificationConstants
+import de.rki.coronawarnapp.util.coroutine.AppScope
+import de.rki.coronawarnapp.util.device.ForegroundState
+import de.rki.coronawarnapp.util.di.AppContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Provider
+import javax.inject.Singleton
+
+@Singleton
+class RATTestResultAvailableNotificationService @Inject constructor(
+    @AppContext context: Context,
+    foregroundState: ForegroundState,
+    navDeepLinkBuilderProvider: Provider<NavDeepLinkBuilder>,
+    private val notificationHelper: GeneralNotifications,
+    cwaSettings: CWASettings,
+    private val coronaTestRepository: CoronaTestRepository,
+    @AppScope private val appScope: CoroutineScope,
+) : TestResultAvailableNotificationService(
+    context,
+    foregroundState,
+    navDeepLinkBuilderProvider,
+    notificationHelper,
+    cwaSettings,
+    NotificationConstants.RAT_TEST_RESULT_AVAILABLE_NOTIFICATION_ID,
+) {
+    fun setup() {
+        Timber.tag(TAG).d("setup() - RATTestResultAvailableNotificationService")
+
+        coronaTestRepository.latestPCRT
+            .onEach { _ ->
+                val test = coronaTestRepository.latestRAT.first()
+                if (test == null) {
+                    cancelTestResultAvailableNotification()
+                    return@onEach
+                }
+
+                val alreadySent = test.isResultAvailableNotificationSent
+                val isInteresting = INTERESTING_STATES.contains(test.testResult)
+                Timber.tag(TAG).v("alreadySent=$alreadySent, isInteresting=$isInteresting")
+
+                if (!alreadySent && isInteresting) {
+                    coronaTestRepository.updateResultNotification(identifier = test.identifier, sent = true)
+                    showTestResultAvailableNotification(test)
+                    notificationHelper.cancelCurrentNotification(
+                        NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
+                    )
+                } else {
+                    cancelTestResultAvailableNotification()
+                }
+            }
+            .launchIn(appScope)
+    }
+
+    companion object {
+        private val INTERESTING_STATES = setOf(
+            CoronaTestResult.RAT_NEGATIVE,
+            CoronaTestResult.RAT_POSITIVE,
+            CoronaTestResult.RAT_INVALID,
+        )
+        private val TAG = RATTestResultAvailableNotificationService::class.java.simpleName
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/PCRResultRetrievalWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/PCRResultRetrievalWorker.kt
deleted file mode 100644
index 4fe1c6e554dff212609bbe328386491e11a3f2ef..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/PCRResultRetrievalWorker.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-package de.rki.coronawarnapp.coronatest.worker
-
-import android.content.Context
-import androidx.work.CoroutineWorker
-import androidx.work.WorkerParameters
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import de.rki.coronawarnapp.coronatest.CoronaTestRepository
-import de.rki.coronawarnapp.coronatest.latestPCRT
-import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
-import de.rki.coronawarnapp.coronatest.type.CoronaTest
-import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
-import de.rki.coronawarnapp.coronatest.worker.execution.PCRResultScheduler
-import de.rki.coronawarnapp.notification.GeneralNotifications
-import de.rki.coronawarnapp.notification.NotificationConstants
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
-import de.rki.coronawarnapp.util.TimeStamper
-import de.rki.coronawarnapp.util.worker.InjectedWorkerFactory
-import de.rki.coronawarnapp.worker.BackgroundConstants
-import kotlinx.coroutines.flow.first
-import org.joda.time.Duration
-import org.joda.time.Instant
-import timber.log.Timber
-
-/**
- * Diagnosis test result retrieval by periodic polling
- */
-class PCRResultRetrievalWorker @AssistedInject constructor(
-    @Assisted val context: Context,
-    @Assisted workerParams: WorkerParameters,
-    private val testResultAvailableNotificationService: PCRTestResultAvailableNotificationService,
-    private val notificationHelper: GeneralNotifications,
-    private val coronaTestRepository: CoronaTestRepository,
-    private val timeStamper: TimeStamper,
-    private val testResultScheduler: PCRResultScheduler,
-) : CoroutineWorker(context, workerParams) {
-
-    override suspend fun doWork(): Result {
-        Timber.tag(TAG).d("$id: doWork() started. Run attempt: $runAttemptCount")
-
-        if (runAttemptCount > BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD) {
-            Timber.tag(TAG).d("$id doWork() failed after $runAttemptCount attempts. Rescheduling")
-
-            testResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = true)
-            Timber.tag(TAG).d("$id Rescheduled background worker")
-
-            return Result.failure()
-        }
-        var result = Result.success()
-        try {
-            if (abortConditionsMet(timeStamper.nowUTC)) {
-                Timber.tag(TAG).d(" $id Stopping worker.")
-                disablePolling()
-            } else {
-                Timber.tag(TAG).d(" $id Running worker.")
-
-                val coronaTest = coronaTestRepository.refresh(
-                    type = CoronaTest.Type.PCR
-                ).single() as PCRCoronaTest
-                val testResult = coronaTest.testResult
-
-                Timber.tag(TAG).d("$id: Test Result retrieved is $testResult")
-
-                if (testResult == CoronaTestResult.PCR_NEGATIVE ||
-                    testResult == CoronaTestResult.PCR_POSITIVE ||
-                    testResult == CoronaTestResult.PCR_INVALID
-                ) {
-                    sendTestResultAvailableNotification(coronaTest)
-                    cancelRiskLevelScoreNotification()
-                    Timber.tag(TAG)
-                        .d("$id: Test Result available - notification sent & risk level notification canceled")
-                    disablePolling()
-                }
-            }
-        } catch (e: Exception) {
-            Timber.tag(TAG).e(e, "Test result retrieval worker failed.")
-            result = Result.retry()
-        }
-
-        Timber.tag(TAG).d("$id: doWork() finished with %s", result)
-
-        return result
-    }
-
-    private suspend fun abortConditionsMet(nowUTC: Instant): Boolean {
-        val pcrTest = coronaTestRepository.latestPCRT.first()
-        if (pcrTest == null) {
-            Timber.tag(TAG).w("There is no PCR available!?")
-            return true
-        }
-
-        if (pcrTest.isResultAvailableNotificationSent) {
-            Timber.tag(TAG).d("$id: Notification already sent.")
-            return true
-        }
-
-        if (pcrTest.isViewed) {
-            Timber.tag(TAG).d("$id: Test result has already been viewed.")
-            return true
-        }
-
-        val calculateDays = Duration(pcrTest.registeredAt, nowUTC).standardDays
-        Timber.tag(TAG).d("Calculated days: %d", calculateDays)
-
-        if (calculateDays >= BackgroundConstants.POLLING_VALIDITY_MAX_DAYS) {
-            Timber.tag(TAG).d("$id $calculateDays is exceeding the maximum polling duration")
-            return true
-        }
-
-        return false
-    }
-
-    private suspend fun sendTestResultAvailableNotification(coronaTest: CoronaTest) {
-        testResultAvailableNotificationService.showTestResultAvailableNotification(coronaTest.testResult)
-        coronaTestRepository.updateResultNotification(identifier = coronaTest.identifier, sent = true)
-    }
-
-    private fun cancelRiskLevelScoreNotification() {
-        notificationHelper.cancelCurrentNotification(
-            NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
-        )
-    }
-
-    private fun disablePolling() {
-        testResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = false)
-        Timber.tag(TAG).d("$id: polling disabled")
-    }
-
-    @AssistedFactory
-    interface Factory : InjectedWorkerFactory<PCRResultRetrievalWorker>
-
-    companion object {
-        private val TAG = PCRResultRetrievalWorker::class.java.simpleName
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/execution/PCRResultScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/execution/PCRResultScheduler.kt
deleted file mode 100644
index c9e83f1f8cee7401b3efa962fd750f979ad60fa3..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/execution/PCRResultScheduler.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-package de.rki.coronawarnapp.coronatest.worker.execution
-
-import androidx.annotation.VisibleForTesting
-import androidx.work.BackoffPolicy
-import androidx.work.ExistingPeriodicWorkPolicy
-import androidx.work.PeriodicWorkRequestBuilder
-import androidx.work.WorkInfo
-import androidx.work.WorkManager
-import dagger.Reusable
-import de.rki.coronawarnapp.coronatest.worker.PCRResultRetrievalWorker
-import de.rki.coronawarnapp.util.coroutine.await
-import de.rki.coronawarnapp.worker.BackgroundConstants
-import de.rki.coronawarnapp.worker.BackgroundConstants.DIAGNOSIS_TEST_RESULT_RETRIEVAL_TRIES_PER_DAY
-import de.rki.coronawarnapp.worker.BackgroundConstants.MINUTES_IN_DAY
-import de.rki.coronawarnapp.worker.BackgroundWorkHelper
-import kotlinx.coroutines.runBlocking
-import timber.log.Timber
-import java.util.concurrent.TimeUnit
-import javax.inject.Inject
-
-@Reusable
-class PCRResultScheduler @Inject constructor(
-    private val workManager: WorkManager,
-) {
-
-    private suspend fun isPcrScheduled() =
-        workManager.getWorkInfosForUniqueWork(PCR_TESTRESULT_WORKER_UNIQUEUNAME)
-            .await()
-            .any { it.isScheduled }
-
-    private val WorkInfo.isScheduled: Boolean
-        get() = state == WorkInfo.State.RUNNING || state == WorkInfo.State.ENQUEUED
-
-    fun setPcrPeriodicTestPollingEnabled(enabled: Boolean) {
-        if (enabled) {
-            // TODO Refactor runBlocking away
-            val isScheduled = runBlocking { isPcrScheduled() }
-            if (isScheduled) {
-                Timber.tag(TAG).w("Already scheduled, skipping")
-                return
-            }
-            Timber.tag(TAG).i("Queueing pcr test result worker (DIAGNOSIS_TEST_RESULT_PERIODIC_WORKER)")
-            workManager.enqueueUniquePeriodicWork(
-                PCR_TESTRESULT_WORKER_UNIQUEUNAME,
-                ExistingPeriodicWorkPolicy.REPLACE,
-                buildPcrTestResultRetrievalPeriodicWork()
-            )
-        } else {
-            Timber.tag(TAG).d("cancelWorker()")
-            workManager.cancelUniqueWork(PCR_TESTRESULT_WORKER_UNIQUEUNAME)
-        }
-    }
-
-    private fun buildPcrTestResultRetrievalPeriodicWork() =
-        PeriodicWorkRequestBuilder<PCRResultRetrievalWorker>(
-            getPcrTestResultRetrievalPeriodicWorkTimeInterval(),
-            TimeUnit.MINUTES
-        )
-            .addTag(PCR_TESTRESULT_WORKER_TAG)
-            .setConstraints(BackgroundWorkHelper.getConstraintsForDiagnosisKeyOneTimeBackgroundWork())
-            .setInitialDelay(
-                DIAGNOSIS_TEST_RESULT_PERIODIC_INITIAL_DELAY,
-                TimeUnit.SECONDS
-            ).setBackoffCriteria(
-                BackoffPolicy.LINEAR,
-                BackgroundConstants.KIND_DELAY,
-                TimeUnit.MINUTES
-            )
-            .build()
-
-    companion object {
-        /**
-         * Kind initial delay in minutes for periodic work for accessibility reason
-         *
-         * @see TimeUnit.SECONDS
-         */
-        private const val DIAGNOSIS_TEST_RESULT_PERIODIC_INITIAL_DELAY = 10L
-        private const val PCR_TESTRESULT_WORKER_TAG = "DIAGNOSIS_TEST_RESULT_PERIODIC_WORKER"
-        private const val PCR_TESTRESULT_WORKER_UNIQUEUNAME = "DiagnosisTestResultBackgroundPeriodicWork"
-
-        private const val TAG = "PCRTestResultScheduler"
-
-        /**
-         * Calculate the time for pcr diagnosis key retrieval periodic work
-         *
-         * @return Long
-         *
-         * @see BackgroundConstants.MINUTES_IN_DAY
-         */
-        @VisibleForTesting
-        internal fun getPcrTestResultRetrievalPeriodicWorkTimeInterval() =
-            (MINUTES_IN_DAY / DIAGNOSIS_TEST_RESULT_RETRIEVAL_TRIES_PER_DAY).toLong()
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/execution/RAResultScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/execution/RAResultScheduler.kt
deleted file mode 100644
index f1253c501f3a21b05be9f7ada1404e67ab3e7902..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/worker/execution/RAResultScheduler.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-package de.rki.coronawarnapp.coronatest.worker.execution
-
-import androidx.work.BackoffPolicy
-import androidx.work.ExistingPeriodicWorkPolicy
-import androidx.work.PeriodicWorkRequest
-import androidx.work.PeriodicWorkRequestBuilder
-import androidx.work.WorkManager
-import dagger.Reusable
-import de.rki.coronawarnapp.coronatest.worker.RAResultRetrievalWorker
-import de.rki.coronawarnapp.coronatest.worker.execution.RAResultScheduler.RatPollingMode.DISABLED
-import de.rki.coronawarnapp.coronatest.worker.execution.RAResultScheduler.RatPollingMode.PHASE1
-import de.rki.coronawarnapp.worker.BackgroundConstants
-import de.rki.coronawarnapp.worker.BackgroundWorkHelper
-import timber.log.Timber
-import java.util.concurrent.TimeUnit
-import javax.inject.Inject
-
-@Reusable
-class RAResultScheduler @Inject constructor(
-    private val workManager: WorkManager,
-) {
-
-    private var ratWorkerMode = DISABLED
-    val ratResultPeriodicPollingMode
-        get() = ratWorkerMode
-
-    enum class RatPollingMode {
-        DISABLED,
-        PHASE1,
-        PHASE2
-    }
-
-    fun setRatResultPeriodicPollingMode(mode: RatPollingMode) {
-        ratWorkerMode = mode
-        if (mode == DISABLED) {
-            Timber.tag(TAG).d("cancelWorker()")
-            workManager.cancelUniqueWork(RAT_RESULT_WORKER_UNIQUEUNAME)
-        } else {
-            // no check for already running workers!
-            // worker must be replaced by next phase instance
-            Timber.tag(TAG).i("Queueing rat result worker (RAT_RESULT_PERIODIC_WORKER)")
-            workManager.enqueueUniquePeriodicWork(
-                RAT_RESULT_WORKER_UNIQUEUNAME,
-                ExistingPeriodicWorkPolicy.REPLACE,
-                buildRatResultRetrievalPeriodicWork(mode)
-            )
-        }
-    }
-
-    private fun buildRatResultRetrievalPeriodicWork(pollingMode: RatPollingMode): PeriodicWorkRequest {
-        val repeatInterval = if (pollingMode == PHASE1) {
-            ratResultRetrievalPeriodicWorkPhase1IntervalInMinutes
-        } else {
-            ratResultRetrievalPeriodicWorkPhase2IntervalInMinutes
-        }
-        return PeriodicWorkRequestBuilder<RAResultRetrievalWorker>(
-            repeatInterval,
-            TimeUnit.MINUTES
-        )
-            .addTag(RAT_RESULT_WORKER_TAG)
-            .setConstraints(BackgroundWorkHelper.getConstraintsForDiagnosisKeyOneTimeBackgroundWork())
-            .setInitialDelay(
-                DIAGNOSIS_TEST_RESULT_PERIODIC_INITIAL_DELAY,
-                TimeUnit.SECONDS
-            ).setBackoffCriteria(
-                BackoffPolicy.LINEAR,
-                BackgroundConstants.KIND_DELAY,
-                TimeUnit.MINUTES
-            )
-            .build()
-    }
-
-    companion object {
-        /**
-         * Kind initial delay in minutes for periodic work for accessibility reason
-         *
-         * @see TimeUnit.SECONDS
-         */
-        private const val DIAGNOSIS_TEST_RESULT_PERIODIC_INITIAL_DELAY = 10L
-        private const val RAT_RESULT_WORKER_TAG = "RAT_RESULT_PERIODIC_WORKER"
-        private const val RAT_RESULT_WORKER_UNIQUEUNAME = "RatResultRetrievalWorker"
-
-        private const val TAG = "RatResultScheduler"
-
-        private const val ratResultRetrievalPeriodicWorkPhase1IntervalInMinutes = 15L
-
-        private const val ratResultRetrievalPeriodicWorkPhase2IntervalInMinutes = 90L
-    }
-}
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 4c273c3bf87907bf9a2779923cade024be725462..9c4f706575da4b7a73e9e4814eb96c505c6d184a 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
@@ -173,7 +173,7 @@ class Analytics @Inject constructor(
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     fun stopDueToTimeSinceOnboarding(): Boolean {
-        val onboarding = onboardingSettings.onboardingCompletedTimestamp ?: return true
+        val onboarding = onboardingSettings.onboardingCompletedTimestamp.value ?: return true
         return onboarding.plus(Hours.hours(ONBOARDING_DELAY_HOURS).toStandardDuration()).isAfter(timeStamper.nowUTC)
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deniability/BackgroundNoisePeriodicWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deniability/BackgroundNoisePeriodicWorker.kt
index fc0852a0d8c8979e1aba380d233f9a549628f560..d67951dd6abdac42d420dc79b1a3056b1c9b385e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deniability/BackgroundNoisePeriodicWorker.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deniability/BackgroundNoisePeriodicWorker.kt
@@ -10,7 +10,6 @@ import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.worker.InjectedWorkerFactory
 import de.rki.coronawarnapp.worker.BackgroundConstants
-import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 import kotlinx.coroutines.flow.first
 import org.joda.time.Duration
 import org.joda.time.Instant
@@ -18,8 +17,6 @@ import timber.log.Timber
 
 /**
  * Periodic background noise worker
- *
- * @see BackgroundWorkScheduler
  */
 class BackgroundNoisePeriodicWorker @AssistedInject constructor(
     @Assisted val context: Context,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deniability/NoiseScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deniability/NoiseScheduler.kt
index c7d8db4da0a6b70aae134a341db3b3d2cd8fdfba..c414351531a4ad5651eb5b9c689c22cba5c777b1 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deniability/NoiseScheduler.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deniability/NoiseScheduler.kt
@@ -1,17 +1,19 @@
 package de.rki.coronawarnapp.deniability
 
 import androidx.work.BackoffPolicy
+import androidx.work.Constraints
 import androidx.work.ExistingPeriodicWorkPolicy
 import androidx.work.ExistingWorkPolicy
+import androidx.work.NetworkType
 import androidx.work.OneTimeWorkRequestBuilder
 import androidx.work.PeriodicWorkRequestBuilder
 import androidx.work.WorkManager
 import dagger.Reusable
 import de.rki.coronawarnapp.worker.BackgroundConstants
-import de.rki.coronawarnapp.worker.BackgroundWorkHelper
 import timber.log.Timber
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
+import kotlin.random.Random
 
 @Reusable
 class NoiseScheduler @Inject constructor(
@@ -44,9 +46,13 @@ class NoiseScheduler @Inject constructor(
     private fun buildBackgroundNoiseOneTimeWork() =
         OneTimeWorkRequestBuilder<BackgroundNoiseOneTimeWorker>()
             .addTag(BACKGROUND_NOISE_ONE_TIME_WORKER_TAG)
-            .setConstraints(BackgroundWorkHelper.getConstraintsForDiagnosisKeyOneTimeBackgroundWork())
+            .setConstraints(
+                Constraints.Builder().apply {
+                    setRequiredNetworkType(NetworkType.CONNECTED)
+                }.build()
+            )
             .setInitialDelay(
-                BackgroundWorkHelper.getBackgroundNoiseOneTimeWorkDelay(),
+                getBackgroundNoiseOneTimeWorkDelay(),
                 TimeUnit.HOURS
             ).setBackoffCriteria(
                 BackoffPolicy.LINEAR,
@@ -101,5 +107,21 @@ class NoiseScheduler @Inject constructor(
         const val BACKGROUND_NOISE_ONE_TIME_WORK_NAME = "BackgroundNoiseOneTimeWork"
 
         private const val TAG = "NoiseScheduler"
+
+        /**
+         * Get background noise one time work delay
+         * The periodic job is already delayed by MIN_HOURS_TO_NEXT_BACKGROUND_NOISE_EXECUTION
+         * so we only need to delay further by the difference between min and max.
+         *
+         * @return Long
+         *
+         * @see BackgroundConstants.MAX_HOURS_TO_NEXT_BACKGROUND_NOISE_EXECUTION
+         * @see BackgroundConstants.MIN_HOURS_TO_NEXT_BACKGROUND_NOISE_EXECUTION
+         */
+        fun getBackgroundNoiseOneTimeWorkDelay() = Random.nextLong(
+            0,
+            BackgroundConstants.MAX_HOURS_TO_NEXT_BACKGROUND_NOISE_EXECUTION -
+                BackgroundConstants.MIN_HOURS_TO_NEXT_BACKGROUND_NOISE_EXECUTION
+        )
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/PCRTestResultAvailableNotificationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/PCRTestResultAvailableNotificationService.kt
deleted file mode 100644
index 15eb8d656cc17073b7ed87bc969b192878fe3c0a..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/PCRTestResultAvailableNotificationService.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package de.rki.coronawarnapp.notification
-
-import android.content.Context
-import androidx.navigation.NavDeepLinkBuilder
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.main.CWASettings
-import de.rki.coronawarnapp.util.device.ForegroundState
-import de.rki.coronawarnapp.util.di.AppContext
-import javax.inject.Inject
-import javax.inject.Provider
-
-class PCRTestResultAvailableNotificationService @Inject constructor(
-    @AppContext context: Context,
-    foregroundState: ForegroundState,
-    navDeepLinkBuilderProvider: Provider<NavDeepLinkBuilder>,
-    notificationHelper: GeneralNotifications,
-    cwaSettings: CWASettings
-) : TestResultAvailableNotificationService(
-    context,
-    foregroundState,
-    navDeepLinkBuilderProvider,
-    notificationHelper,
-    cwaSettings,
-    NotificationConstants.PCR_TEST_RESULT_AVAILABLE_NOTIFICATION_ID,
-    R.id.submissionTestResultPendingFragment
-)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/RATTestResultAvailableNotificationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/RATTestResultAvailableNotificationService.kt
deleted file mode 100644
index 2d85badd449cee0bd2c4968fb89e110fec6f82f5..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/RATTestResultAvailableNotificationService.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package de.rki.coronawarnapp.notification
-
-import android.content.Context
-import androidx.navigation.NavDeepLinkBuilder
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.main.CWASettings
-import de.rki.coronawarnapp.util.device.ForegroundState
-import de.rki.coronawarnapp.util.di.AppContext
-import javax.inject.Inject
-import javax.inject.Provider
-
-class RATTestResultAvailableNotificationService @Inject constructor(
-    @AppContext context: Context,
-    foregroundState: ForegroundState,
-    navDeepLinkBuilderProvider: Provider<NavDeepLinkBuilder>,
-    notificationHelper: GeneralNotifications,
-    cwaSettings: CWASettings
-) : TestResultAvailableNotificationService(
-    context,
-    foregroundState,
-    navDeepLinkBuilderProvider,
-    notificationHelper,
-    cwaSettings,
-    NotificationConstants.RAT_TEST_RESULT_AVAILABLE_NOTIFICATION_ID,
-    R.id.submissionTestResultPendingFragment // TODO check nav args, after other PRs are merged
-)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/TraceLocationSettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/TraceLocationSettings.kt
index 11b0c580fb3ffa147e5a0e882e56dfdb903bc382..ecd7764c78f988345c2cea77332e179d556e0d60 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/TraceLocationSettings.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/TraceLocationSettings.kt
@@ -2,7 +2,11 @@ package de.rki.coronawarnapp.presencetracing
 
 import android.content.Context
 import de.rki.coronawarnapp.util.di.AppContext
+import de.rki.coronawarnapp.util.preferences.FlowPreference
 import de.rki.coronawarnapp.util.preferences.clearAndNotify
+import de.rki.coronawarnapp.util.preferences.createFlowPreference
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
 import javax.inject.Inject
 import javax.inject.Singleton
 
@@ -15,14 +19,22 @@ class TraceLocationSettings @Inject constructor(
         context.getSharedPreferences(name, Context.MODE_PRIVATE)
     }
 
-    var onboardingStatus: OnboardingStatus
-        get() {
-            val order = preferences.getInt(key_status, OnboardingStatus.NOT_ONBOARDED.order)
-            return OnboardingStatus.values().find { it.order == order } ?: OnboardingStatus.NOT_ONBOARDED
+    val onboardingStatus: FlowPreference<OnboardingStatus> = preferences.createFlowPreference(
+        key = PKEY_ONBOARDING_STATUS,
+        reader = { key ->
+            val order = getInt(key, OnboardingStatus.NOT_ONBOARDED.order)
+            OnboardingStatus.values().find { it.order == order } ?: OnboardingStatus.NOT_ONBOARDED
+        },
+        writer = { key, value ->
+            putInt(key, value.order)
         }
-        set(value) = preferences.edit().putInt(key_status, value.order).apply()
+    )
 
-    inline val isOnboardingDone get() = onboardingStatus == OnboardingStatus.ONBOARDED_2_0
+    inline val isOnboardingDoneFlow: Flow<Boolean>
+        get() = onboardingStatus.flow.map { it == OnboardingStatus.ONBOARDED_2_0 }
+
+    inline val isOnboardingDone: Boolean
+        get() = onboardingStatus.value == OnboardingStatus.ONBOARDED_2_0
 
     fun clear() {
         preferences.clearAndNotify()
@@ -34,7 +46,7 @@ class TraceLocationSettings @Inject constructor(
     }
 
     companion object {
-        private const val key_status = "trace_location_onboardingstatus"
+        private const val PKEY_ONBOARDING_STATUS = "trace_location_onboardingstatus"
         private const val name = "trace_location_localdata"
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt
index bc9bb66393317c88172eb6889ec8021d322aaab3..4cf28e6ec08a4ebb5d01ef6643ad34a6699d02ef 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt
@@ -21,12 +21,16 @@ data class PtRiskLevelResult(
         riskState != RiskState.CALCULATION_FAILED
     }
 
-    val numberOfDaysWithHighRisk: Int by lazy {
-        presenceTracingDayRisk?.count { it.riskState == RiskState.INCREASED_RISK } ?: 0
+    val daysWithHighRisk: List<LocalDate> by lazy {
+        presenceTracingDayRisk?.filter {
+            it.riskState == RiskState.INCREASED_RISK
+        }?.map { it.localDateUtc } ?: emptyList()
     }
 
-    val numberOfDaysWithLowRisk: Int by lazy {
-        presenceTracingDayRisk?.count { it.riskState == RiskState.LOW_RISK } ?: 0
+    val daysWithLowRisk: List<LocalDate> by lazy {
+        presenceTracingDayRisk?.filter {
+            it.riskState == RiskState.LOW_RISK
+        }?.map { it.localDateUtc } ?: emptyList()
     }
 
     val mostRecentDateWithHighRisk: LocalDate? by lazy {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingRiskWorkScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingRiskWorkScheduler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9392134354f174525613b4742322febccfb725ad
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingRiskWorkScheduler.kt
@@ -0,0 +1,85 @@
+package de.rki.coronawarnapp.presencetracing.risk.execution
+
+import android.annotation.SuppressLint
+import androidx.work.WorkManager
+import dagger.Reusable
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.isRiskCalculationNecessary
+import de.rki.coronawarnapp.presencetracing.TraceLocationSettings
+import de.rki.coronawarnapp.risk.execution.RiskWorkScheduler
+import de.rki.coronawarnapp.task.TaskController
+import de.rki.coronawarnapp.task.common.DefaultTaskRequest
+import de.rki.coronawarnapp.util.coroutine.AppScope
+import de.rki.coronawarnapp.util.coroutine.await
+import de.rki.coronawarnapp.util.device.BackgroundModeStatus
+import de.rki.coronawarnapp.util.flow.combine
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import timber.log.Timber
+import javax.inject.Inject
+
+@Reusable
+class PresenceTracingRiskWorkScheduler @Inject constructor(
+    @AppScope private val appScope: CoroutineScope,
+    private val workManager: WorkManager,
+    private val taskController: TaskController,
+    private val presenceWorkBuilder: PresenceTracingWarningWorkBuilder,
+    private val backgroundModeStatus: BackgroundModeStatus,
+    private val presenceTracingSettings: TraceLocationSettings,
+    private val coronaTestRepository: CoronaTestRepository,
+) : RiskWorkScheduler(
+    workManager = workManager,
+    logTag = TAG,
+) {
+
+    @SuppressLint("BinaryOperationInTimber")
+    fun setup() {
+        Timber.tag(TAG).i("setup() PresenceTracingRiskWorkScheduler")
+        combine(
+            backgroundModeStatus.isAutoModeEnabled,
+            presenceTracingSettings.isOnboardingDoneFlow,
+            coronaTestRepository.isRiskCalculationNecessary,
+        ) { isAutoMode, isPresenceTracingOnboarded, isRiskCalculationNecessesary ->
+            Timber.tag(TAG).d(
+                "isAutoMode=$isAutoMode, " +
+                    "isPresenceTracingOnboarded=$isPresenceTracingOnboarded, " +
+                    "isRiskCalculationNecessesary=$isRiskCalculationNecessesary"
+            )
+            isAutoMode && isPresenceTracingOnboarded && isRiskCalculationNecessesary
+        }
+            .onEach { runPeriodicWorker ->
+                Timber.tag(TAG).v("runPeriodicWorker=$runPeriodicWorker")
+                setPeriodicRiskCalculation(enabled = runPeriodicWorker)
+            }
+            .launchIn(appScope)
+    }
+
+    fun runRiskTaskNow(sourceTag: String) = taskController.submit(
+        DefaultTaskRequest(
+            PresenceTracingWarningTask::class,
+            originTag = "PresenceTracingRiskWorkScheduler-$sourceTag"
+        )
+    )
+
+    override suspend fun isScheduled(): Boolean = workManager
+        .getWorkInfosForUniqueWork(WORKER_ID_PRESENCE_TRACING)
+        .await()
+        .any { it.isScheduled }
+
+    override fun setPeriodicRiskCalculation(enabled: Boolean) {
+        Timber.tag(TAG).i("setPeriodicRiskCalculation(enabled=$enabled)")
+
+        if (enabled) {
+            val warningRequest = presenceWorkBuilder.createPeriodicWorkRequest()
+            queueWorker(WORKER_ID_PRESENCE_TRACING, warningRequest)
+        } else {
+            cancelWorker(WORKER_ID_PRESENCE_TRACING)
+        }
+    }
+
+    companion object {
+        private const val WORKER_ID_PRESENCE_TRACING = "PresenceTracingWarningWorker"
+        private const val TAG = "PTRiskWorkScheduler"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt
index 304aa75d3599ce225c70b2eaddd3ed199d84e596..cd5d3699d94a1b0e95360c62733c4d504f17edd4 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt
@@ -31,12 +31,14 @@ data class CombinedEwPtRiskLevelResult(
     val daysWithEncounters: Int by lazy {
         when (riskState) {
             RiskState.INCREASED_RISK -> {
-                (ewRiskLevelResult.ewAggregatedRiskResult?.numberOfDaysWithHighRisk ?: 0) +
-                    ptRiskLevelResult.numberOfDaysWithHighRisk
+                ewRiskLevelResult.daysWithHighRisk
+                    .plus(ptRiskLevelResult.daysWithHighRisk)
+                    .distinct().count()
             }
             RiskState.LOW_RISK -> {
-                (ewRiskLevelResult.ewAggregatedRiskResult?.numberOfDaysWithLowRisk ?: 0) +
-                    ptRiskLevelResult.numberOfDaysWithLowRisk
+                ewRiskLevelResult.daysWithLowRisk
+                    .plus(ptRiskLevelResult.daysWithLowRisk)
+                    .distinct().count()
             }
             else -> 0
         }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/EwRiskLevelResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/EwRiskLevelResult.kt
index 952b994c4ca78dfc7cb904d7282392e9abd789e0..daa440e5a5d375f5c0b1ded9a8885c07f8a74aee 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/EwRiskLevelResult.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/EwRiskLevelResult.kt
@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.risk
 import com.google.android.gms.nearby.exposurenotification.ExposureWindow
 import de.rki.coronawarnapp.risk.result.EwAggregatedRiskResult
 import org.joda.time.Instant
+import org.joda.time.LocalDate
 
 interface EwRiskLevelResult {
     val calculatedAt: Instant
@@ -35,13 +36,6 @@ interface EwRiskLevelResult {
             ewAggregatedRiskResult?.totalMinimumDistinctEncountersWithLowRisk ?: 0
         }
 
-    val daysWithEncounters: Int
-        get() = if (isIncreasedRisk) {
-            ewAggregatedRiskResult?.numberOfDaysWithHighRisk ?: 0
-        } else {
-            ewAggregatedRiskResult?.numberOfDaysWithLowRisk ?: 0
-        }
-
     val lastRiskEncounterAt: Instant?
         get() = if (isIncreasedRisk) {
             ewAggregatedRiskResult?.mostRecentDateWithHighRisk
@@ -49,6 +43,16 @@ interface EwRiskLevelResult {
             ewAggregatedRiskResult?.mostRecentDateWithLowRisk
         }
 
+    val daysWithHighRisk: List<LocalDate>
+        get() = ewAggregatedRiskResult?.exposureWindowDayRisks?.filter {
+            it.riskLevel.mapToRiskState() == RiskState.INCREASED_RISK
+        }?.map { it.localDateUtc } ?: emptyList()
+
+    val daysWithLowRisk: List<LocalDate>
+        get() = ewAggregatedRiskResult?.exposureWindowDayRisks?.filter {
+            it.riskLevel.mapToRiskState() == RiskState.LOW_RISK
+        }?.map { it.localDateUtc } ?: emptyList()
+
     enum class FailureReason(val failureCode: String) {
         UNKNOWN("unknown"),
         TRACING_OFF("tracingOff"),
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelResultExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelResultExtensions.kt
index 1d0ea0988e7b013f220062d5ffd009ccf30f65c7..73bafdb64da0d85c1b17419a9ef31ebc7a1d9c11 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelResultExtensions.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelResultExtensions.kt
@@ -30,7 +30,6 @@ private object EwInitialLowRiskLevelResult : EwRiskLevelResult {
     override val ewAggregatedRiskResult: EwAggregatedRiskResult? = null
     override val exposureWindows: List<ExposureWindow>? = null
     override val matchedKeyCount: Int = 0
-    override val daysWithEncounters: Int = 0
 }
 
 private object EwUndeterminedRiskLevelResult : EwRiskLevelResult {
@@ -40,5 +39,4 @@ private object EwUndeterminedRiskLevelResult : EwRiskLevelResult {
     override val ewAggregatedRiskResult: EwAggregatedRiskResult? = null
     override val exposureWindows: List<ExposureWindow>? = null
     override val matchedKeyCount: Int = 0
-    override val daysWithEncounters: Int = 0
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/execution/ExposureWindowRiskWorkScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/execution/ExposureWindowRiskWorkScheduler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e65fa414d61fc79310d6885e22c07a7d32935c41
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/execution/ExposureWindowRiskWorkScheduler.kt
@@ -0,0 +1,102 @@
+package de.rki.coronawarnapp.risk.execution
+
+import android.annotation.SuppressLint
+import androidx.work.WorkManager
+import dagger.Reusable
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.isRiskCalculationNecessary
+import de.rki.coronawarnapp.diagnosiskeys.download.DownloadDiagnosisKeysTask
+import de.rki.coronawarnapp.diagnosiskeys.execution.DiagnosisKeyRetrievalWorkBuilder
+import de.rki.coronawarnapp.nearby.ENFClient
+import de.rki.coronawarnapp.risk.RiskLevelTask
+import de.rki.coronawarnapp.storage.OnboardingSettings
+import de.rki.coronawarnapp.task.TaskController
+import de.rki.coronawarnapp.task.common.DefaultTaskRequest
+import de.rki.coronawarnapp.task.submitBlocking
+import de.rki.coronawarnapp.util.coroutine.AppScope
+import de.rki.coronawarnapp.util.coroutine.await
+import de.rki.coronawarnapp.util.device.BackgroundModeStatus
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import timber.log.Timber
+import javax.inject.Inject
+
+@Reusable
+class ExposureWindowRiskWorkScheduler @Inject constructor(
+    @AppScope private val appScope: CoroutineScope,
+    private val workManager: WorkManager,
+    private val taskController: TaskController,
+    private val diagnosisWorkBuilder: DiagnosisKeyRetrievalWorkBuilder,
+    private val backgroundModeStatus: BackgroundModeStatus,
+    private val onboardingSettings: OnboardingSettings,
+    private val enfClient: ENFClient,
+    private val coronaTestRepository: CoronaTestRepository,
+) : RiskWorkScheduler(
+    workManager = workManager,
+    logTag = TAG,
+) {
+
+    @SuppressLint("BinaryOperationInTimber")
+    fun setup() {
+        Timber.tag(TAG).i("setup() ExposureWindowRiskWorkScheduler")
+        combine(
+            backgroundModeStatus.isAutoModeEnabled,
+            onboardingSettings.isOnboardedFlow,
+            enfClient.isTracingEnabled,
+            coronaTestRepository.isRiskCalculationNecessary,
+        ) { isAutoMode, isOnboarded, isTracing, isRiskCalculationNecessesary ->
+            Timber.tag(TAG).d(
+                "isAutoMode=$isAutoMode, " +
+                    "isOnBoarded=$isOnboarded, " +
+                    "isTracing=$isTracing, " +
+                    "isRiskCalculationNecessesary=$isRiskCalculationNecessesary"
+            )
+            isAutoMode && isOnboarded && isTracing && isRiskCalculationNecessesary
+        }
+            .onEach { runPeriodicWorker ->
+                Timber.tag(TAG).v("runPeriodicWorker=$runPeriodicWorker")
+                setPeriodicRiskCalculation(enabled = runPeriodicWorker)
+            }
+            .launchIn(appScope)
+    }
+
+    suspend fun runRiskTasksNow(sourceTag: String) = appScope.launch {
+        taskController.submitBlocking(
+            DefaultTaskRequest(
+                DownloadDiagnosisKeysTask::class,
+                DownloadDiagnosisKeysTask.Arguments(),
+                originTag = "ExposureWindowRiskWorkScheduler-$sourceTag"
+            )
+        )
+        taskController.submit(
+            DefaultTaskRequest(
+                RiskLevelTask::class,
+                originTag = "ExposureWindowRiskWorkScheduler-$sourceTag"
+            )
+        )
+    }
+
+    override suspend fun isScheduled(): Boolean = workManager
+        .getWorkInfosForUniqueWork(WORKER_ID_DIAGNOSIS_KEY_DOWNLOAD)
+        .await()
+        .any { it.isScheduled }
+
+    override fun setPeriodicRiskCalculation(enabled: Boolean) {
+        Timber.tag(TAG).i("setPeriodicRiskCalculation(enabled=$enabled)")
+
+        if (enabled) {
+            val diagnosisRequest = diagnosisWorkBuilder.createPeriodicWorkRequest()
+            queueWorker(WORKER_ID_DIAGNOSIS_KEY_DOWNLOAD, diagnosisRequest)
+        } else {
+            cancelWorker(WORKER_ID_DIAGNOSIS_KEY_DOWNLOAD)
+        }
+    }
+
+    companion object {
+        private const val WORKER_ID_DIAGNOSIS_KEY_DOWNLOAD = "DiagnosisKeyRetrievalWorker"
+        private const val TAG = "EWRiskWorkScheduler"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/execution/RiskWorkScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/execution/RiskWorkScheduler.kt
index ba05ce2a89622ce6cb12e207ae02095270fd799a..37e1eb4a839cbe55132a205837424bab32f9b285 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/execution/RiskWorkScheduler.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/execution/RiskWorkScheduler.kt
@@ -4,88 +4,19 @@ import androidx.work.ExistingPeriodicWorkPolicy
 import androidx.work.PeriodicWorkRequest
 import androidx.work.WorkInfo
 import androidx.work.WorkManager
-import de.rki.coronawarnapp.diagnosiskeys.download.DownloadDiagnosisKeysTask
-import de.rki.coronawarnapp.diagnosiskeys.execution.DiagnosisKeyRetrievalWorkBuilder
-import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingWarningTask
-import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingWarningWorkBuilder
-import de.rki.coronawarnapp.task.TaskController
-import de.rki.coronawarnapp.task.TaskState
-import de.rki.coronawarnapp.task.common.DefaultTaskRequest
-import de.rki.coronawarnapp.task.submitBlocking
-import de.rki.coronawarnapp.util.coroutine.AppScope
-import de.rki.coronawarnapp.util.coroutine.await
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
 import timber.log.Timber
-import javax.inject.Inject
-import javax.inject.Singleton
 
-@Singleton
-class RiskWorkScheduler @Inject constructor(
-    @AppScope private val appScope: CoroutineScope,
+abstract class RiskWorkScheduler(
     private val workManager: WorkManager,
-    private val taskController: TaskController,
-    private val presenceWorkBuilder: PresenceTracingWarningWorkBuilder,
-    private val diagnosisWorkBuilder: DiagnosisKeyRetrievalWorkBuilder,
+    private val logTag: String
 ) {
 
-    suspend fun runRiskTasksNow(): List<TaskState> {
-        val diagnosisKeysState = appScope.async {
-            Timber.tag(TAG).d("Running DownloadDiagnosisKeysTask")
-            val result = taskController.submitBlocking(
-                DefaultTaskRequest(
-                    DownloadDiagnosisKeysTask::class,
-                    DownloadDiagnosisKeysTask.Arguments(),
-                    originTag = "RiskWorkScheduler-runRiskTasksNow"
-                )
-            )
-            Timber.tag(TAG).d("DownloadDiagnosisKeysTask finished with %s", result)
-            result
-        }
-        val presenceWarningState = appScope.async {
-            Timber.tag(TAG).d("Running PresenceTracingWarningTask")
-            val result = taskController.submitBlocking(
-                DefaultTaskRequest(
-                    PresenceTracingWarningTask::class,
-                    originTag = "RiskWorkScheduler-runRiskTasksNow"
-                )
-            )
-            Timber.tag(TAG).d("PresenceTracingWarningTask finished with %s", result)
-            result
-        }
-        return listOf(diagnosisKeysState, presenceWarningState).awaitAll()
-    }
-
-    suspend fun isScheduled(): Boolean {
-        val diagnosisWorkerInfos = appScope.async {
-            workManager.getWorkInfosForUniqueWork(WORKER_ID_PRESENCE_TRACING).await()
-        }
-        val warningWorkerInfos = appScope.async {
-            workManager.getWorkInfosForUniqueWork(WORKER_ID_DIAGNOSIS_KEY_DOWNLOAD).await()
-        }
-        return listOf(diagnosisWorkerInfos, warningWorkerInfos).awaitAll().all { perWorkerInfos ->
-            perWorkerInfos.any { it.isScheduled }
-        }
-    }
-
-    fun setPeriodicRiskCalculation(enabled: Boolean) {
-        Timber.tag(TAG).i("setPeriodicRiskCalculation(enabled=$enabled)")
+    abstract suspend fun isScheduled(): Boolean
 
-        if (enabled) {
-            val diagnosisRequest = diagnosisWorkBuilder.createPeriodicWorkRequest()
-            queueWorker(WORKER_ID_DIAGNOSIS_KEY_DOWNLOAD, diagnosisRequest)
+    internal abstract fun setPeriodicRiskCalculation(enabled: Boolean)
 
-            val warningRequest = presenceWorkBuilder.createPeriodicWorkRequest()
-            queueWorker(WORKER_ID_PRESENCE_TRACING, warningRequest)
-        } else {
-            cancelWorker(WORKER_ID_DIAGNOSIS_KEY_DOWNLOAD)
-            cancelWorker(WORKER_ID_PRESENCE_TRACING)
-        }
-    }
-
-    private fun queueWorker(workerId: String, request: PeriodicWorkRequest) {
-        Timber.tag(TAG).d("queueWorker(workerId=%s, request=%s)", workerId, request)
+    internal fun queueWorker(workerId: String, request: PeriodicWorkRequest) {
+        Timber.tag(logTag).d("queueWorker(workerId=%s, request=%s)", workerId, request)
         workManager.enqueueUniquePeriodicWork(
             workerId,
             ExistingPeriodicWorkPolicy.KEEP,
@@ -93,17 +24,11 @@ class RiskWorkScheduler @Inject constructor(
         )
     }
 
-    private fun cancelWorker(workerId: String) {
-        Timber.tag(TAG).d("cancelWorker(workerId=$workerId")
+    internal fun cancelWorker(workerId: String) {
+        Timber.tag(logTag).d("cancelWorker(workerId=$workerId")
         workManager.cancelUniqueWork(workerId)
     }
 
-    private val WorkInfo.isScheduled: Boolean
+    internal val WorkInfo.isScheduled: Boolean
         get() = state == WorkInfo.State.RUNNING || state == WorkInfo.State.ENQUEUED
-
-    companion object {
-        private const val WORKER_ID_DIAGNOSIS_KEY_DOWNLOAD = "DiagnosisKeyRetrievalWorker"
-        private const val WORKER_ID_PRESENCE_TRACING = "PresenceTracingWarningWorker"
-        private const val TAG = "RiskWorkScheduler"
-    }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt
index 800757c75b5c3e32104b6d769e6d1901d8ec6dbe..e7891623cc31e9c57bb4b7368d0dc529185655d8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt
@@ -190,7 +190,8 @@ abstract class BaseRiskLevelStorage constructor(
             presenceTracingRiskRepository.allEntries()
         ) { ewRiskLevelResults, ptRiskLevelResults ->
 
-            val combinedResults = riskCombinator.combineEwPtRiskLevelResults(ptRiskLevelResults, ewRiskLevelResults)
+            val combinedResults = riskCombinator
+                .combineEwPtRiskLevelResults(ptRiskLevelResults, ewRiskLevelResults)
                 .sortedByDescending { it.calculatedAt }
 
             LastCombinedRiskResults(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/internal/RiskCombinator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/internal/RiskCombinator.kt
index 13aa62d91979693e113b43d430cfd340c44aa13b..4e33b2a24dcfc65766999d1b67f09ab77e1f00f3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/internal/RiskCombinator.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/internal/RiskCombinator.kt
@@ -27,7 +27,6 @@ class RiskCombinator @Inject constructor(
         override val ewAggregatedRiskResult: EwAggregatedRiskResult? = null
         override val exposureWindows: List<ExposureWindow>? = null
         override val matchedKeyCount: Int = 0
-        override val daysWithEncounters: Int = 0
     }
 
     private val initialPTRiskLevelResult: PtRiskLevelResult = PtRiskLevelResult(
@@ -48,7 +47,6 @@ class RiskCombinator @Inject constructor(
             override val ewAggregatedRiskResult: EwAggregatedRiskResult? = null
             override val exposureWindows: List<ExposureWindow>? = null
             override val matchedKeyCount: Int = 0
-            override val daysWithEncounters: Int = 0
         }
 
     private val ptCurrentLowRiskLevelResult: PtRiskLevelResult
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/OnboardingSettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/OnboardingSettings.kt
index 1f22c31b71311e5ad2a7b7e08a053151da93f8ae..bd7ee3276ccb6396080420a2853b7377ee7ad8f6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/OnboardingSettings.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/OnboardingSettings.kt
@@ -3,7 +3,11 @@ package de.rki.coronawarnapp.storage
 import android.content.Context
 import androidx.core.content.edit
 import de.rki.coronawarnapp.util.di.AppContext
+import de.rki.coronawarnapp.util.preferences.FlowPreference
 import de.rki.coronawarnapp.util.preferences.clearAndNotify
+import de.rki.coronawarnapp.util.preferences.createFlowPreference
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
 import org.joda.time.Instant
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -16,16 +20,24 @@ class OnboardingSettings @Inject constructor(
         context.getSharedPreferences("onboarding_localdata", Context.MODE_PRIVATE)
     }
 
-    var onboardingCompletedTimestamp: Instant?
-        get() = prefs.getLong(ONBOARDING_COMPLETED_TIMESTAMP, 0L).let {
-            if (it != 0L) {
-                Instant.ofEpochMilli(it)
+    val onboardingCompletedTimestamp: FlowPreference<Instant?> = prefs.createFlowPreference(
+        key = ONBOARDING_COMPLETED_TIMESTAMP,
+        reader = {
+            val raw = getLong(it, 0L)
+            if (raw != 0L) {
+                Instant.ofEpochMilli(raw)
             } else null
+        },
+        writer = { key, value ->
+            putLong(key, value?.millis ?: 0L)
         }
-        set(value) = prefs.edit { putLong(ONBOARDING_COMPLETED_TIMESTAMP, value?.millis ?: 0L) }
+    )
 
     val isOnboarded: Boolean
-        get() = onboardingCompletedTimestamp != null
+        get() = onboardingCompletedTimestamp.value != null
+
+    val isOnboardedFlow: Flow<Boolean>
+        get() = onboardingCompletedTimestamp.flow.map { it != null }
 
     var isBackgroundCheckDone: Boolean
         get() = prefs.getBoolean(BACKGROUND_CHECK_DONE, false)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
index b69db70bb6c049c1119e8f3313ca2157039a49c2..bd5aaa78ba6d9a48ab2e26661e818512ff025734 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
@@ -7,10 +7,11 @@ import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.lastSubmission
+import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingRiskWorkScheduler
 import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingWarningTask
 import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingWarningTaskProgress
 import de.rki.coronawarnapp.risk.RiskLevelTask
-import de.rki.coronawarnapp.risk.execution.RiskWorkScheduler
+import de.rki.coronawarnapp.risk.execution.ExposureWindowRiskWorkScheduler
 import de.rki.coronawarnapp.task.TaskController
 import de.rki.coronawarnapp.task.TaskInfo
 import de.rki.coronawarnapp.task.common.DefaultTaskRequest
@@ -47,7 +48,8 @@ class TracingRepository @Inject constructor(
     private val timeStamper: TimeStamper,
     private val exposureDetectionTracker: ExposureDetectionTracker,
     private val backgroundModeStatus: BackgroundModeStatus,
-    private val riskWorkScheduler: RiskWorkScheduler,
+    private val exposureWindowRiskWorkScheduler: ExposureWindowRiskWorkScheduler,
+    private val presenceTracingRiskWorkScheduler: PresenceTracingRiskWorkScheduler,
 ) {
 
     @SuppressLint("BinaryOperationInTimber")
@@ -96,14 +98,8 @@ class TracingRepository @Inject constructor(
     fun refreshRiskResult() = scope.launch {
         Timber.tag(TAG).d("refreshRiskResults()")
 
-        riskWorkScheduler.runRiskTasksNow()
-
-        taskController.submit(
-            DefaultTaskRequest(
-                RiskLevelTask::class,
-                originTag = "TracingRepository.refreshRiskResult()"
-            )
-        )
+        exposureWindowRiskWorkScheduler.runRiskTasksNow(sourceTag = TAG)
+        presenceTracingRiskWorkScheduler.runRiskTaskNow(sourceTag = TAG)
     }
 
     /**
@@ -164,6 +160,6 @@ class TracingRepository @Inject constructor(
     }
 
     companion object {
-        private val TAG: String? = TracingRepository::class.simpleName
+        private const val TAG: String = "TracingRepository"
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt
index 82dfa27637e6d3e7cf99272366987f3e5fb93554..7e621ecff18388ef2a5f100003def572229cb6eb 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt
@@ -75,7 +75,7 @@ class SubmissionRepository @Inject constructor(
         }
     }
 
-    fun refreshTest(type: CoronaTest.Type) {
+    fun refreshTest(type: CoronaTest.Type? = null) {
         Timber.tag(TAG).v("refreshTest(type=%s)", type)
 
         scope.launch {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/task/SubmissionTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/task/SubmissionTask.kt
index d95c9e4ad988c3f3c98bca38667d247a194a8c9d..8e0551005b4c26f57eebcd962e47aee5ab00883e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/task/SubmissionTask.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/task/SubmissionTask.kt
@@ -6,8 +6,9 @@ import de.rki.coronawarnapp.bugreporting.reportProblem
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.coronatest.notification.ShareTestResultNotificationService
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.playbook.Playbook
 import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository
 import de.rki.coronawarnapp.presencetracing.checkins.CheckInsTransformer
@@ -22,7 +23,6 @@ import de.rki.coronawarnapp.task.TaskCancellationException
 import de.rki.coronawarnapp.task.TaskFactory
 import de.rki.coronawarnapp.task.common.DefaultProgress
 import de.rki.coronawarnapp.util.TimeStamper
-import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 import kotlinx.coroutines.channels.ConflatedBroadcastChannel
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.asFlow
@@ -46,7 +46,6 @@ class SubmissionTask @Inject constructor(
     private val checkInsRepository: CheckInRepository,
     private val checkInsTransformer: CheckInsTransformer,
     private val analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector,
-    private val backgroundWorkScheduler: BackgroundWorkScheduler,
     private val coronaTestRepository: CoronaTestRepository,
 ) : Task<DefaultProgress, SubmissionTask.Result> {
 
@@ -138,7 +137,7 @@ class SubmissionTask @Inject constructor(
         val keys: List<TemporaryExposureKey> = try {
             tekHistoryStorage.tekData.first().flatMap { it.keys }
         } catch (e: NoSuchElementException) {
-            Timber.tag(TAG).e(e, "No TEKs available, aborting.")
+            Timber.tag(TAG).e(e, "tekHistoryStorage access failed, aborting.")
             autoSubmission.updateMode(AutoSubmission.Mode.DISABLED)
             throw e
         }
@@ -172,8 +171,11 @@ class SubmissionTask @Inject constructor(
         Timber.tag(TAG).d("Submitting %s", submissionData)
         playbook.submit(submissionData)
 
-        analyticsKeySubmissionCollector.reportSubmitted()
-        if (inBackground) analyticsKeySubmissionCollector.reportSubmittedInBackground()
+        // PPA will only be used for PCR tests for now
+        if (coronaTest.type == PCR) {
+            analyticsKeySubmissionCollector.reportSubmitted()
+            if (inBackground) analyticsKeySubmissionCollector.reportSubmittedInBackground()
+        }
 
         Timber.tag(TAG).d("Submission successful, deleting submission data.")
         tekHistoryStorage.clear()
@@ -197,9 +199,7 @@ class SubmissionTask @Inject constructor(
 
     private suspend fun setSubmissionFinished(coronaTest: CoronaTest) {
         Timber.tag(TAG).d("setSubmissionFinished()")
-        backgroundWorkScheduler.stopWorkScheduler()
         coronaTestRepository.markAsSubmitted(coronaTest.identifier)
-        backgroundWorkScheduler.startWorkScheduler()
 
         testResultAvailableNotificationService.cancelTestResultAvailableNotification()
     }
@@ -264,6 +264,6 @@ class SubmissionTask @Inject constructor(
 }
 
 private fun CoronaTest.Type.toSubmissionType() = when (this) {
-    CoronaTest.Type.PCR -> SubmissionType.SUBMISSION_TYPE_PCR_TEST
+    PCR -> SubmissionType.SUBMISSION_TYPE_PCR_TEST
     CoronaTest.Type.RAPID_ANTIGEN -> SubmissionType.SUBMISSION_TYPE_RAPID_TEST
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/homecards/PcrTestSubmissionDoneCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/homecards/PcrTestSubmissionDoneCard.kt
index 9cb260b99330b0006922b70d69f3d6ec14cd3960..d4ed6af6b785854ccaa27f593a538961a89bc8bb 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/homecards/PcrTestSubmissionDoneCard.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/homecards/PcrTestSubmissionDoneCard.kt
@@ -30,6 +30,7 @@ class PcrTestSubmissionDoneCard(
     }
 
     data class Item(
-        val state: SubmissionStatePCR.SubmissionDone
+        val state: SubmissionStatePCR.SubmissionDone,
+        val onClickAction: (Item) -> Unit,
     ) : TestResultItem.PCR
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/homecards/RapidTestSubmissionDoneCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/homecards/RapidTestSubmissionDoneCard.kt
index c6e3866a09b30c10f864d7b732150a7f7c16c0fe..c41df314763cbfb4c4262019318a6b22232249b0 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/homecards/RapidTestSubmissionDoneCard.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/homecards/RapidTestSubmissionDoneCard.kt
@@ -30,6 +30,7 @@ class RapidTestSubmissionDoneCard(
     }
 
     data class Item(
-        val state: SubmissionStateRAT.SubmissionDone
+        val state: SubmissionStateRAT.SubmissionDone,
+        val onClickAction: (Item) -> Unit,
     ) : TestResultItem.RA
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragmentViewModel.kt
index 571ae77c03533982ee966b7edbd1709094b7a9fe..420e2179b7763130d0c82a0386d2c31fb0ea7be6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragmentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragmentViewModel.kt
@@ -13,6 +13,7 @@ import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.installTime.InstallTimeProvider
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.nearby.TracingPermissionHelper
+import de.rki.coronawarnapp.risk.execution.ExposureWindowRiskWorkScheduler
 import de.rki.coronawarnapp.tracing.GeneralTracingStatus
 import de.rki.coronawarnapp.tracing.ui.details.items.periodlogged.PeriodLoggedBox
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
@@ -21,7 +22,6 @@ import de.rki.coronawarnapp.util.flow.shareLatest
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.map
@@ -35,7 +35,7 @@ class SettingsTracingFragmentViewModel @AssistedInject constructor(
     installTimeProvider: InstallTimeProvider,
     private val backgroundStatus: BackgroundModeStatus,
     tracingPermissionHelperFactory: TracingPermissionHelper.Factory,
-    private val backgroundWorkScheduler: BackgroundWorkScheduler
+    private val exposureWindowRiskWorkScheduler: ExposureWindowRiskWorkScheduler
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
     val loggingPeriod: LiveData<PeriodLoggedBox.Item> =
@@ -76,7 +76,7 @@ class SettingsTracingFragmentViewModel @AssistedInject constructor(
                             if (!backgroundStatus.isIgnoringBatteryOptimizations.first()) {
                                 events.postValue(Event.ManualCheckingDialog)
                             }
-                            backgroundWorkScheduler.startWorkScheduler()
+                            exposureWindowRiskWorkScheduler.setPeriodicRiskCalculation(enabled = true)
                         }
                         isTracingSwitchChecked.postValue(isTracingEnabled)
                     }
@@ -110,7 +110,7 @@ class SettingsTracingFragmentViewModel @AssistedInject constructor(
                 launch {
                     if (InternalExposureNotificationClient.asyncIsEnabled()) {
                         InternalExposureNotificationClient.asyncStop()
-                        backgroundWorkScheduler.stopWorkScheduler()
+                        exposureWindowRiskWorkScheduler.setPeriodicRiskCalculation(enabled = false)
                     }
                 }
             }
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 9a6eda1d20b0681c79b202305fae10693d27c4f5..1b669bb181d70987acf682fa200fcc0a62a2d311 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
@@ -37,7 +37,6 @@ import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper.Companion.getShort
 import de.rki.coronawarnapp.util.ui.findNavController
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
-import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 import org.joda.time.LocalDate
 import timber.log.Timber
 import javax.inject.Inject
@@ -47,7 +46,6 @@ import javax.inject.Inject
  * connectivity and bluetooth to update the ui.
  *
  * @see ConnectivityHelper
- * @see BackgroundWorkScheduler
  */
 class MainActivity : AppCompatActivity(), HasAndroidInjector {
     companion object {
@@ -79,7 +77,6 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector {
     @Inject lateinit var powerManagement: PowerManagement
     @Inject lateinit var contactDiaryWorkScheduler: ContactDiaryWorkScheduler
     @Inject lateinit var dataDonationAnalyticsScheduler: DataDonationAnalyticsScheduler
-    @Inject lateinit var backgroundWorkScheduler: BackgroundWorkScheduler
 
     override fun onCreate(savedInstanceState: Bundle?) {
         AppInjector.setup(this)
@@ -195,7 +192,6 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector {
      */
     override fun onResume() {
         super.onResume()
-        backgroundWorkScheduler.startWorkScheduler()
         vm.doBackgroundNoiseCheck()
         contactDiaryWorkScheduler.schedulePeriodic()
         dataDonationAnalyticsScheduler.schedulePeriodic()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt
index be2720d7a0caf7f755e0370eec37e59e439ab549..07aafffdeae0827824974016fab9076d192d76c2 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt
@@ -29,7 +29,6 @@ import de.rki.coronawarnapp.tracing.ui.homecards.TracingProgressCard
 import de.rki.coronawarnapp.ui.main.home.items.CreateTraceLocationCard
 import de.rki.coronawarnapp.ui.main.home.items.FAQCard
 import de.rki.coronawarnapp.ui.main.home.items.HomeItem
-import de.rki.coronawarnapp.ui.main.home.items.ReenableRiskCard
 import de.rki.coronawarnapp.util.lists.BindableVH
 import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffUtilAdapter
 import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffer
@@ -52,7 +51,6 @@ class HomeAdapter :
                 DataBinderMod<HomeItem, HomeItemVH<HomeItem, ViewBinding>>(data),
                 TypedVHCreatorMod({ data[it] is FAQCard.Item }) { FAQCard(it) },
                 TypedVHCreatorMod({ data[it] is CreateTraceLocationCard.Item }) { CreateTraceLocationCard(it) },
-                TypedVHCreatorMod({ data[it] is ReenableRiskCard.Item }) { ReenableRiskCard(it) },
                 TypedVHCreatorMod({ data[it] is IncreasedRiskCard.Item }) { IncreasedRiskCard(it) },
                 TypedVHCreatorMod({ data[it] is LowRiskCard.Item }) { LowRiskCard(it) },
                 TypedVHCreatorMod({ data[it] is TracingFailedCard.Item }) { TracingFailedCard(it) },
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt
index ad760fe105b7e6761951322bf58af0442cdbf7da..dfbad3ce5fc64c9f911afcb2b89421f40b7c8250 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt
@@ -101,9 +101,6 @@ class HomeFragment : Fragment(R.layout.home_fragment_layout), AutoInject {
                 HomeFragmentEvents.GoToStatisticsExplanation -> doNavigate(
                     HomeFragmentDirections.actionMainFragmentToStatisticsExplanationFragment()
                 )
-                HomeFragmentEvents.ShowReactivateRiskCheckDialog -> {
-                    showReactivateRiskCheckDialog()
-                }
                 HomeFragmentEvents.ShowTracingExplanation -> {
                     tracingExplanationDialog.show {
                         viewModel.tracingExplanationWasShown()
@@ -147,23 +144,6 @@ class HomeFragment : Fragment(R.layout.home_fragment_layout), AutoInject {
         }
     }
 
-    private fun showReactivateRiskCheckDialog() {
-        val removeTestDialog = DialogHelper.DialogInstance(
-            requireActivity(),
-            R.string.dialog_reactivate_risk_calculation_title,
-            R.string.dialog_reactivate_risk_calculation_message,
-            R.string.dialog_reactivate_risk_calculation_button_positive,
-            R.string.dialog_reactivate_risk_calculation_button_negative,
-            positiveButtonFunction = {
-                viewModel.reenableRiskCalculation()
-            }
-        )
-        DialogHelper.showDialog(removeTestDialog).apply {
-            getButton(AlertDialog.BUTTON_POSITIVE)
-                .setTextColor(context.getColorCompat(R.color.colorTextSemanticRed))
-        }
-    }
-
     private fun showRiskLevelLoweredDialog() {
         val riskLevelLoweredDialog = DialogHelper.DialogInstance(
             context = requireActivity(),
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt
index 45f581002f78709b070aa97ea686d628b72f9188..b219536e6ad616d1f0e99d5e9b10584a2336c35c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentEvents.kt
@@ -8,7 +8,5 @@ sealed class HomeFragmentEvents {
 
     object ShowDeleteTestDialog : HomeFragmentEvents()
 
-    object ShowReactivateRiskCheckDialog : HomeFragmentEvents()
-
     object GoToStatisticsExplanation : HomeFragmentEvents()
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
index 0c5b76df726c81881920476a80750d497162e4bb..73fc1c4d40237b9bb81b043a5d6fc82cf0e100d1 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
@@ -10,7 +10,6 @@ import de.rki.coronawarnapp.appconfig.CoronaTestConfig
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.coronatest.latestPCRT
 import de.rki.coronawarnapp.coronatest.latestRAT
-import de.rki.coronawarnapp.coronatest.type.CommonSubmissionStates
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
 import de.rki.coronawarnapp.coronatest.type.pcr.SubmissionStatePCR
@@ -61,7 +60,6 @@ import de.rki.coronawarnapp.ui.main.home.HomeFragmentEvents.ShowTracingExplanati
 import de.rki.coronawarnapp.ui.main.home.items.CreateTraceLocationCard
 import de.rki.coronawarnapp.ui.main.home.items.FAQCard
 import de.rki.coronawarnapp.ui.main.home.items.HomeItem
-import de.rki.coronawarnapp.ui.main.home.items.ReenableRiskCard
 import de.rki.coronawarnapp.ui.presencetracing.organizer.TraceLocationOrganizerSettings
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
@@ -209,7 +207,9 @@ class HomeFragmentViewModel @AssistedInject constructor(
                     .actionMainFragmentToSubmissionTestResultPendingFragment(testType = CoronaTest.Type.PCR)
             )
         }
-        is SubmissionStatePCR.SubmissionDone -> PcrTestSubmissionDoneCard.Item(state)
+        is SubmissionStatePCR.SubmissionDone -> PcrTestSubmissionDoneCard.Item(state) {
+            // TODO
+        }
     }
 
     private fun RACoronaTest?.toTestCardItem(coronaTestConfig: CoronaTestConfig) =
@@ -260,7 +260,9 @@ class HomeFragmentViewModel @AssistedInject constructor(
             is SubmissionStateRAT.TestOutdated -> RapidTestOutdatedCard.Item(state) {
                 submissionRepository.removeTestFromDevice(type = CoronaTest.Type.RAPID_ANTIGEN)
             }
-            is SubmissionStateRAT.SubmissionDone -> RapidTestSubmissionDoneCard.Item(state)
+            is SubmissionStateRAT.SubmissionDone -> RapidTestSubmissionDoneCard.Item(state) {
+                // TODO
+            }
         }
 
     val homeItems: LiveData<List<HomeItem>> = combine(
@@ -309,16 +311,6 @@ class HomeFragmentViewModel @AssistedInject constructor(
                 }
             }
 
-            bothTestStates.firstOrNull { it is CommonSubmissionStates.SubmissionDone }?.let {
-                it as CommonSubmissionStates.SubmissionDone
-                add(
-                    ReenableRiskCard.Item(
-                        data = it,
-                        onClickAction = { popupEvents.postValue(HomeFragmentEvents.ShowReactivateRiskCheckDialog) }
-                    )
-                )
-            }
-
             if (statsData.isDataAvailable) {
                 add(
                     StatisticsHomeCard.Item(
@@ -338,12 +330,6 @@ class HomeFragmentViewModel @AssistedInject constructor(
         .distinctUntilChanged()
         .asLiveData(dispatcherProvider.Default)
 
-    fun reenableRiskCalculation() {
-        deregisterWarningAccepted()
-        deadmanNotificationScheduler.schedulePeriodic()
-        refreshRiskResult()
-    }
-
     private var isLoweredRiskLevelDialogBeingShown = false
 
     // TODO only lazy to keep tests going which would break because of LocalData access
@@ -367,7 +353,7 @@ class HomeFragmentViewModel @AssistedInject constructor(
 
     fun refreshRequiredData() {
         launch {
-            submissionRepository.refreshTest(type = CoronaTest.Type.PCR)
+            submissionRepository.refreshTest()
             tracingRepository.refreshRiskLevel()
         }
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/items/ReenableRiskCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/items/ReenableRiskCard.kt
deleted file mode 100644
index 5c9df231a7c6a9106169323c436d11b1766f96b2..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/items/ReenableRiskCard.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package de.rki.coronawarnapp.ui.main.home.items
-
-import android.view.ViewGroup
-import android.widget.Button
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.coronatest.type.CommonSubmissionStates
-import de.rki.coronawarnapp.databinding.HomeReenableRiskCardLayoutBinding
-import de.rki.coronawarnapp.ui.main.home.HomeAdapter
-import de.rki.coronawarnapp.ui.main.home.items.ReenableRiskCard.Item
-import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUIFormat
-import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer
-
-class ReenableRiskCard(parent: ViewGroup) : HomeAdapter.HomeItemVH<Item, HomeReenableRiskCardLayoutBinding>(
-    R.layout.home_card_container_layout,
-    parent
-) {
-
-    override val viewBinding = lazy {
-        HomeReenableRiskCardLayoutBinding.inflate(layoutInflater, itemView.findViewById(R.id.card_container), true)
-    }
-
-    override val onBindData: HomeReenableRiskCardLayoutBinding.(Item, List<Any>) -> Unit = { item, payloads ->
-        reenableRiskCardTestRegistrationDate.text =
-            context.getString(R.string.reenable_risk_card_test_registration_string)
-                .format(item.data.testRegisteredAt.toDate().toUIFormat(context))
-
-        itemView.findViewById<Button>(R.id.reenable_risk_card_button).setOnClickListener {
-            val curItem = payloads.filterIsInstance<Item>().singleOrNull() ?: item
-            curItem.onClickAction(item)
-        }
-    }
-
-    data class Item(
-        val data: CommonSubmissionStates.SubmissionDone,
-        val onClickAction: (Item) -> Unit
-    ) : HomeItem,
-        HasPayloadDiffer {
-        override val stableId: Long = Item::class.java.name.hashCode().toLong()
-
-        override fun diffPayload(old: Any, new: Any): Any? = if (old::class == new::class) new else null
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt
index 6ad6c7e9f31491ff41abe4408601302642f6975d..6723bf329c2fdd33c73289db6e258faa087e3b5a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt
@@ -68,7 +68,9 @@ class OnboardingActivity : AppCompatActivity(), LifecycleObserver, HasAndroidInj
     }
 
     fun completeOnboarding() {
-        onboardingSettings.onboardingCompletedTimestamp = timeStamper.nowUTC
+        onboardingSettings.onboardingCompletedTimestamp.update {
+            timeStamper.nowUTC
+        }
         settings.lastChangelogVersion.update { BuildConfigWrap.VERSION_CODE }
         settings.lastChangelogVersion.update { BuildConfigWrap.VERSION_CODE }
         MainActivity.start(this, intent)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt
index c11dbe490f54cff9590b1355064a5553f09787d2..8b014f565b08ae7e37cf3b95f3fd656701dde8c9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt
@@ -69,7 +69,9 @@ class CheckInsConsentFragment : Fragment(R.layout.check_ins_consent_fragment), A
                     CheckInsConsentFragmentDirections.actionCheckInsConsentFragmentToMainFragment()
                 )
                 CheckInsConsentNavigation.ToSubmissionResultReadyFragment -> doNavigate(
-                    CheckInsConsentFragmentDirections.actionCheckInsConsentFragmentToSubmissionResultReadyFragment()
+                    CheckInsConsentFragmentDirections.actionCheckInsConsentFragmentToSubmissionResultReadyFragment(
+                        navArgs.testType
+                    )
                 )
                 CheckInsConsentNavigation.ToSubmissionTestResultConsentGivenFragment -> doNavigate(
                     CheckInsConsentFragmentDirections
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/onboarding/CheckInOnboardingViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/onboarding/CheckInOnboardingViewModel.kt
index afbffab4c3d2a4f1abdb5c56ed078adbe699ab48..f364d30e9ffc79fc9588f584095ba4df244dc6b4 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/onboarding/CheckInOnboardingViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/onboarding/CheckInOnboardingViewModel.kt
@@ -13,7 +13,9 @@ class CheckInOnboardingViewModel @AssistedInject constructor(
     val events = SingleLiveEvent<CheckInOnboardingNavigation>()
 
     fun onAcknowledged() {
-        settings.onboardingStatus = TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
+        settings.onboardingStatus.update {
+            TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
+        }
         events.value = CheckInOnboardingNavigation.AcknowledgedNavigation
     }
 
@@ -25,7 +27,7 @@ class CheckInOnboardingViewModel @AssistedInject constructor(
         events.value = CheckInOnboardingNavigation.AcknowledgedNavigation
     }
 
-    val isOnboardingComplete = settings.onboardingStatus == TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
+    val isOnboardingComplete = settings.onboardingStatus.value == TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0
 
     @AssistedFactory
     interface Factory : SimpleCWAViewModelFactory<CheckInOnboardingViewModel>
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetViewModel.kt
index aac4f54a8698348da4a06949c581e571c607289f..9260aefa17d5e884a7986acd9ee4ea6a2b77bd13 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetViewModel.kt
@@ -12,13 +12,11 @@ import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 
 class SettingsResetViewModel @AssistedInject constructor(
     dispatcherProvider: DispatcherProvider,
     private val dataReset: DataReset,
     private val shortcutsHelper: AppShortcutsHelper,
-    private val backgroundWorkScheduler: BackgroundWorkScheduler,
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
     val clickEvent: SingleLiveEvent<SettingsEvents> = SingleLiveEvent()
@@ -34,11 +32,11 @@ class SettingsResetViewModel @AssistedInject constructor(
     fun deleteAllAppContent() {
         launch {
             try {
+                // TODO Remove static access
                 val isTracingEnabled = InternalExposureNotificationClient.asyncIsEnabled()
                 // only stop tracing if it is currently enabled
                 if (isTracingEnabled) {
                     InternalExposureNotificationClient.asyncStop()
-                    backgroundWorkScheduler.stopWorkScheduler()
                 }
             } catch (apiException: ApiException) {
                 apiException.report(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt
index d07af3d2dd2aa8ae4f3f65f23b5d15a4d2e00fce..b49dad70291cd84b7433f48fac0d66a8bcc99720 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt
@@ -6,6 +6,8 @@ import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.bugreporting.censors.QRCodeCensor
 import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQrCodeValidator
 import de.rki.coronawarnapp.coronatest.qrcode.InvalidQRCodeException
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.ui.submission.qrcode.QrCodeRegistrationStateProcessor
 import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents
@@ -23,7 +25,8 @@ class SubmissionQRCodeScanViewModel @AssistedInject constructor(
     private val qrCodeRegistrationStateProcessor: QrCodeRegistrationStateProcessor,
     @Assisted private val isConsentGiven: Boolean,
     private val submissionRepository: SubmissionRepository,
-    private val qrCodeValidator: CoronaTestQrCodeValidator
+    private val qrCodeValidator: CoronaTestQrCodeValidator,
+    private val analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
     val routeToScreen = SingleLiveEvent<SubmissionNavigationEvents>()
     val showRedeemedTokenWarning = qrCodeRegistrationStateProcessor.showRedeemedTokenWarning
@@ -53,6 +56,9 @@ class SubmissionQRCodeScanViewModel @AssistedInject constructor(
                     )
                 )
             } else {
+                if (isConsentGiven && coronaTestQRCode.type == CoronaTest.Type.PCR) {
+                    analyticsKeySubmissionCollector.reportAdvancedConsentGiven()
+                }
                 qrCodeRegistrationStateProcessor.startQrCodeRegistration(coronaTestQRCode, isConsentGiven)
             }
         } catch (err: InvalidQRCodeException) {
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 e5bc9c33455c323b41aba5ba967aae1050eb2a5d..dadb6672622aee60d7d16d7732f0da963f30bba4 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
@@ -9,6 +9,7 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.reporting.report
@@ -98,7 +99,7 @@ class SubmissionTestResultAvailableViewModel @AssistedInject constructor(
     )
 
     init {
-        submissionRepository.refreshTest(type = CoronaTest.Type.PCR)
+        submissionRepository.refreshTest(type = testType)
     }
 
     fun goBack() {
@@ -130,7 +131,9 @@ class SubmissionTestResultAvailableViewModel @AssistedInject constructor(
                 tekHistoryUpdater.updateTEKHistoryOrRequestPermission()
             } else {
                 Timber.tag(TAG).d("routeToScreen:SubmissionTestResultNoConsentFragment")
-                analyticsKeySubmissionCollector.reportConsentWithdrawn()
+                if (testType == PCR) {
+                    analyticsKeySubmissionCollector.reportConsentWithdrawn()
+                }
                 showKeysRetrievalProgress.postValue(false)
                 routeToScreen.postValue(
                     SubmissionTestResultAvailableFragmentDirections
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt
index 92f10cc9a535593ceac5c95e78c3467cad058724..a97360430793e8efc5c53c244cd9b7f3d9fdb888 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt
@@ -5,8 +5,10 @@ import android.view.View
 import android.view.accessibility.AccessibilityEvent
 import androidx.activity.OnBackPressedCallback
 import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.navArgs
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentSubmissionResultReadyBinding
+import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.consent.CheckInsConsentFragmentArgs
 import de.rki.coronawarnapp.ui.submission.SubmissionBlockingDialog
 import de.rki.coronawarnapp.ui.submission.SubmissionCancelDialog
 import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents
@@ -27,6 +29,8 @@ class SubmissionResultReadyFragment : Fragment(R.layout.fragment_submission_resu
     private val viewModel: SubmissionResultReadyViewModel by cwaViewModels { viewModelFactory }
     private val binding: FragmentSubmissionResultReadyBinding by viewBindingLazy()
 
+    private val navArgs by navArgs<CheckInsConsentFragmentArgs>()
+
     private lateinit var uploadDialog: SubmissionBlockingDialog
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -50,7 +54,7 @@ class SubmissionResultReadyFragment : Fragment(R.layout.fragment_submission_resu
 
                 is SubmissionNavigationEvents.NavigateToSymptomIntroduction -> doNavigate(
                     SubmissionResultReadyFragmentDirections
-                        .actionSubmissionResultReadyFragmentToSubmissionSymptomIntroductionFragment()
+                        .actionSubmissionResultReadyFragmentToSubmissionSymptomIntroductionFragment(navArgs.testType)
                 )
             }
         }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4c6ddaa7d8b92a557c33ca491eb82a26e68be719
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneFragment.kt
@@ -0,0 +1,70 @@
+package de.rki.coronawarnapp.ui.submission.submissiondone
+
+import android.os.Bundle
+import android.view.View
+import android.view.accessibility.AccessibilityEvent
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.navArgs
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.databinding.FragmentSubmissionDoneBinding
+import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents
+import de.rki.coronawarnapp.util.ContextExtensions.getDrawableCompat
+import de.rki.coronawarnapp.util.di.AutoInject
+import de.rki.coronawarnapp.util.ui.doNavigate
+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.cwaViewModelsAssisted
+import javax.inject.Inject
+
+class SubmissionDoneFragment : Fragment(R.layout.fragment_submission_done), AutoInject {
+
+    private val args by navArgs<SubmissionDoneFragmentArgs>()
+
+    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
+    private val viewModel: SubmissionDoneViewModel by cwaViewModelsAssisted(
+        factoryProducer = { viewModelFactory },
+        constructorCall = { factory, _ ->
+            factory as SubmissionDoneViewModel.Factory
+            factory.create(args.testType)
+        }
+    )
+
+    private val binding: FragmentSubmissionDoneBinding by viewBindingLazy()
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        binding.apply {
+
+            toolbar.apply {
+                navigationIcon = context.getDrawableCompat(R.drawable.ic_close)
+                navigationContentDescription = getString(R.string.accessibility_close)
+                setNavigationOnClickListener { viewModel.onFinishButtonClick() }
+            }
+
+            submissionDoneButtonDone.setOnClickListener {
+                viewModel.onFinishButtonClick()
+            }
+
+            submissionDoneContent.submissionDoneContent.submissionDonePcrValidation.root.isVisible =
+                (viewModel.testType == CoronaTest.Type.RAPID_ANTIGEN)
+        }
+
+        viewModel.routeToScreen.observe2(this) {
+            when (it) {
+                SubmissionNavigationEvents.NavigateToMainActivity -> {
+                    doNavigate(
+                        SubmissionDoneFragmentDirections.actionSubmissionDoneFragmentToMainFragment()
+                    )
+                }
+            }
+        }
+    }
+
+    override fun onResume() {
+        super.onResume()
+        binding.submissionDoneContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT)
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ab24c4f9b677414eac42da432ec194c4e230a9d1
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneModule.kt
@@ -0,0 +1,18 @@
+package de.rki.coronawarnapp.ui.submission.submissiondone
+
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoMap
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
+
+@Module
+abstract class SubmissionDoneModule {
+    @Binds
+    @IntoMap
+    @CWAViewModelKey(SubmissionDoneViewModel::class)
+    abstract fun submissionDoneFragmentVM(
+        factory: SubmissionDoneViewModel.Factory
+    ): CWAViewModelFactory<out CWAViewModel>
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0f72b0df369c5c45fb88c7abe005905b7aa8d77e
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneViewModel.kt
@@ -0,0 +1,26 @@
+package de.rki.coronawarnapp.ui.submission.submissiondone
+
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents
+import de.rki.coronawarnapp.util.ui.SingleLiveEvent
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
+
+class SubmissionDoneViewModel @AssistedInject constructor(
+    @Assisted val testType: CoronaTest.Type
+
+) : CWAViewModel() {
+    val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent()
+
+    fun onFinishButtonClick() {
+        routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity)
+    }
+
+    @AssistedFactory
+    interface Factory : CWAViewModelFactory<SubmissionDoneViewModel> {
+        fun create(testType: CoronaTest.Type): SubmissionDoneViewModel
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt
index 44e574a02b8d267c89e83d1887beac6e74f62ed2..5c2bac13584fa622a1306fa03cb0592c920e4e51 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt
@@ -32,7 +32,7 @@ class SubmissionSymptomCalendarFragment :
         factoryProducer = { viewModelFactory },
         constructorCall = { factory, _ ->
             factory as SubmissionSymptomCalendarViewModel.Factory
-            factory.create(navArgs.symptomIndication)
+            factory.create(navArgs.symptomIndication, navArgs.testType)
         }
     )
 
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 249f7e24e09d257c549b102d63de380f2d2e014f..9d7816702666e20a29c0cfcbdeca2d60a9f62a88 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
@@ -8,6 +8,8 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.bugreporting.reportProblem
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.Screen
 import de.rki.coronawarnapp.submission.SubmissionRepository
@@ -23,6 +25,7 @@ import timber.log.Timber
 
 class SubmissionSymptomCalendarViewModel @AssistedInject constructor(
     @Assisted val symptomIndication: Symptoms.Indication,
+    @Assisted val testType: Type,
     dispatcherProvider: DispatcherProvider,
     private val submissionRepository: SubmissionRepository,
     private val autoSubmission: AutoSubmission,
@@ -87,12 +90,20 @@ class SubmissionSymptomCalendarViewModel @AssistedInject constructor(
                 startOfSymptoms = symptomStartInternal.value
             ).also { Timber.tag(TAG).v("Symptoms updated to %s", it) }
         }
-        performSubmission { analyticsKeySubmissionCollector.reportSubmittedAfterSymptomFlow() }
+        performSubmission {
+            if (testType == PCR) {
+                analyticsKeySubmissionCollector.reportSubmittedAfterSymptomFlow()
+            }
+        }
     }
 
     fun onCancelConfirmed() {
         Timber.d("onCancelConfirmed() clicked on calendar screen.")
-        performSubmission { analyticsKeySubmissionCollector.reportSubmittedAfterCancel() }
+        performSubmission {
+            if (testType == PCR) {
+                analyticsKeySubmissionCollector.reportSubmittedAfterCancel()
+            }
+        }
     }
 
     private fun performSubmission(onSubmitted: () -> Unit) {
@@ -106,7 +117,8 @@ class SubmissionSymptomCalendarViewModel @AssistedInject constructor(
                 Timber.i("Hide uploading progress and navigate to HomeFragment")
                 mediatorShowUploadDialog.postValue(false)
                 routeToScreen.postValue(
-                    SubmissionSymptomCalendarFragmentDirections.actionSubmissionSymptomCalendarFragmentToMainFragment()
+                    SubmissionSymptomCalendarFragmentDirections
+                        .actionSubmissionSymptomCalendarFragmentToSubmissionDoneFragment(testType)
                 )
             }
         }
@@ -114,14 +126,16 @@ class SubmissionSymptomCalendarViewModel @AssistedInject constructor(
 
     fun onNewUserActivity() {
         Timber.d("onNewUserActivity()")
-        analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.SYMPTOM_ONSET)
+        if (testType == PCR) {
+            analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.SYMPTOM_ONSET)
+        }
         autoSubmission.updateLastSubmissionUserActivity()
     }
 
     @AssistedFactory
     interface Factory : CWAViewModelFactory<SubmissionSymptomCalendarViewModel> {
 
-        fun create(symptomIndication: Symptoms.Indication): SubmissionSymptomCalendarViewModel
+        fun create(symptomIndication: Symptoms.Indication, testType: Type): SubmissionSymptomCalendarViewModel
     }
 
     companion object {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt
index 40d9e4ebabc21d506dc6b74284ea83f5c202ff6c..0a60e95c23b109d379d6031f0094186c53885056 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt
@@ -5,9 +5,11 @@ import android.os.Bundle
 import android.view.View
 import android.widget.Button
 import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.navArgs
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentSubmissionSymptomIntroBinding
 import de.rki.coronawarnapp.submission.Symptoms
+import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.consent.CheckInsConsentFragmentArgs
 import de.rki.coronawarnapp.ui.submission.SubmissionBlockingDialog
 import de.rki.coronawarnapp.ui.submission.SubmissionCancelDialog
 import de.rki.coronawarnapp.util.di.AutoInject
@@ -17,7 +19,7 @@ import de.rki.coronawarnapp.util.ui.doNavigate
 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 de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted
 import javax.inject.Inject
 
 /**
@@ -28,10 +30,18 @@ class SubmissionSymptomIntroductionFragment :
     Fragment(R.layout.fragment_submission_symptom_intro),
     AutoInject {
 
-    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
-    private val viewModel: SubmissionSymptomIntroductionViewModel by cwaViewModels { viewModelFactory }
+    private val navArgs by navArgs<CheckInsConsentFragmentArgs>()
 
+    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
+    private val viewModel: SubmissionSymptomIntroductionViewModel by cwaViewModelsAssisted(
+        factoryProducer = { viewModelFactory },
+        constructorCall = { factory, _ ->
+            factory as SubmissionSymptomIntroductionViewModel.Factory
+            factory.create(navArgs.testType)
+        }
+    )
     private val binding: FragmentSubmissionSymptomIntroBinding by viewBindingLazy()
+
     private lateinit var uploadDialog: SubmissionBlockingDialog
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt
index 6628ddc879fa20a4f736fb7d9b74f4c8bd683273..4bacd588ac13a17b0e50c46c20a14feed475dda0 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt
@@ -4,8 +4,11 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.MediatorLiveData
 import androidx.lifecycle.asLiveData
 import androidx.navigation.NavDirections
+import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.Screen
 import de.rki.coronawarnapp.submission.SubmissionRepository
@@ -14,7 +17,7 @@ import de.rki.coronawarnapp.submission.auto.AutoSubmission
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
-import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
 import kotlinx.coroutines.flow.MutableStateFlow
 import timber.log.Timber
 
@@ -22,7 +25,8 @@ class SubmissionSymptomIntroductionViewModel @AssistedInject constructor(
     dispatcherProvider: DispatcherProvider,
     private val submissionRepository: SubmissionRepository,
     private val autoSubmission: AutoSubmission,
-    private val analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector
+    private val analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector,
+    @Assisted private val testType: Type
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
     private val symptomIndicationInternal = MutableStateFlow<Symptoms.Indication?>(null)
@@ -50,7 +54,8 @@ class SubmissionSymptomIntroductionViewModel @AssistedInject constructor(
                     navigation.postValue(
                         SubmissionSymptomIntroductionFragmentDirections
                             .actionSubmissionSymptomIntroductionFragmentToSubmissionSymptomCalendarFragment(
-                                symptomIndication = Symptoms.Indication.POSITIVE
+                                symptomIndication = Symptoms.Indication.POSITIVE,
+                                testType = testType
                             )
                     )
                 }
@@ -62,6 +67,11 @@ class SubmissionSymptomIntroductionViewModel @AssistedInject constructor(
                         )
                     }
                     doSubmit()
+
+                    navigation.postValue(
+                        SubmissionSymptomIntroductionFragmentDirections
+                            .actionSubmissionSymptomIntroductionFragmentToSubmissionDoneFragment(testType)
+                    )
                 }
                 Symptoms.Indication.NO_INFORMATION -> {
                     submissionRepository.currentSymptoms.update {
@@ -71,6 +81,11 @@ class SubmissionSymptomIntroductionViewModel @AssistedInject constructor(
                         )
                     }
                     doSubmit()
+
+                    navigation.postValue(
+                        SubmissionSymptomIntroductionFragmentDirections
+                            .actionSubmissionSymptomIntroductionFragmentToSubmissionDoneFragment(testType)
+                    )
                 }
             }
         }
@@ -121,10 +136,14 @@ class SubmissionSymptomIntroductionViewModel @AssistedInject constructor(
 
     fun onNewUserActivity() {
         Timber.d("onNewUserActivity()")
-        analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.SYMPTOMS)
+        if (testType == PCR) {
+            analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.SYMPTOMS)
+        }
         autoSubmission.updateLastSubmissionUserActivity()
     }
 
     @AssistedFactory
-    interface Factory : SimpleCWAViewModelFactory<SubmissionSymptomIntroductionViewModel>
+    interface Factory : CWAViewModelFactory<SubmissionSymptomIntroductionViewModel> {
+        fun create(testType: Type): SubmissionSymptomIntroductionViewModel
+    }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/invalid/SubmissionTestResultInvalidViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/invalid/SubmissionTestResultInvalidViewModel.kt
index 163264bb67137733718622557b47349967f9ada0..913da481b9b1e88904c178ebadfbdd0d9914c680 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/invalid/SubmissionTestResultInvalidViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/invalid/SubmissionTestResultInvalidViewModel.kt
@@ -7,7 +7,7 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeViewModel.kt
index d4b683833c8999b3cce67f313f797461414e7ef7..98ed23aeeba648f2888d14b4eddd749a73c2f73e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeViewModel.kt
@@ -7,7 +7,7 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenFragment.kt
index 07b6e9f665052b7bc797a496b4923f0377550df5..30208766ca81b736c6e570df2e1a6f630d3577b3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenFragment.kt
@@ -69,7 +69,9 @@ class SubmissionTestResultConsentGivenFragment :
                 is SubmissionNavigationEvents.NavigateToSymptomIntroduction ->
                     doNavigate(
                         SubmissionTestResultConsentGivenFragmentDirections
-                            .actionSubmissionTestResultConsentGivenFragmentToSubmissionSymptomIntroductionFragment()
+                            .actionSubmissionTestResultConsentGivenFragmentToSubmissionSymptomIntroductionFragment(
+                                navArgs.testType
+                            )
                     )
                 is SubmissionNavigationEvents.NavigateToMainActivity ->
                     doNavigate(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenViewModel.kt
index c2c4f6b45b70d5e3b4e9e3d4b4a202fe2fb26df9..022d9310fde7be687fe9f6e4db31e39be7bd75ff 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenViewModel.kt
@@ -5,10 +5,10 @@ import androidx.lifecycle.asLiveData
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
-import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.Screen
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.submission.auto.AutoSubmission
 import de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState
@@ -27,7 +27,7 @@ class SubmissionTestResultConsentGivenViewModel @AssistedInject constructor(
     private val autoSubmission: AutoSubmission,
     private val testResultAvailableNotificationService: PCRTestResultAvailableNotificationService,
     private val analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector,
-    @Assisted private val testType: CoronaTest.Type,
+    @Assisted private val testType: Type,
     dispatcherProvider: DispatcherProvider
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
@@ -77,12 +77,14 @@ class SubmissionTestResultConsentGivenViewModel @AssistedInject constructor(
 
     fun onNewUserActivity() {
         Timber.d("onNewUserActivity()")
-        analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.TEST_RESULT)
+        if (testType == Type.PCR) {
+            analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.TEST_RESULT)
+        }
         autoSubmission.updateLastSubmissionUserActivity()
     }
 
     @AssistedFactory
     interface Factory : CWAViewModelFactory<SubmissionTestResultConsentGivenViewModel> {
-        fun create(testType: CoronaTest.Type): SubmissionTestResultConsentGivenViewModel
+        fun create(testType: Type): SubmissionTestResultConsentGivenViewModel
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentViewModel.kt
index 9868f82dfbe3bd56e2c53218a47096e82175497c..3c21410fa9787dbdac4c8bd81cf3dbf53e9b582c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentViewModel.kt
@@ -6,9 +6,10 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.Screen
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
@@ -36,7 +37,9 @@ class SubmissionTestResultNoConsentViewModel @AssistedInject constructor(
 
     fun onTestOpened() = launch {
         Timber.v("onTestOpened()")
-        analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.TEST_RESULT)
+        if (testType == PCR) {
+            analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.TEST_RESULT)
+        }
         submissionRepository.setViewedTestResult(type = testType)
         testResultAvailableNotificationService.cancelTestResultAvailableNotification()
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt
index 93186ab86ac5b3655f3b99668d21d719adbaa0d8..40b436ea56a0bf12eb637bcd3797854b2aa9d07e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt
@@ -16,6 +16,8 @@ import de.rki.coronawarnapp.ui.submission.resultavailable.SubmissionTestResultAv
 import de.rki.coronawarnapp.ui.submission.resultavailable.SubmissionTestResultAvailableModule
 import de.rki.coronawarnapp.ui.submission.resultready.SubmissionResultReadyFragment
 import de.rki.coronawarnapp.ui.submission.resultready.SubmissionResultReadyModule
+import de.rki.coronawarnapp.ui.submission.submissiondone.SubmissionDoneFragment
+import de.rki.coronawarnapp.ui.submission.submissiondone.SubmissionDoneModule
 import de.rki.coronawarnapp.ui.submission.symptoms.calendar.SubmissionSymptomCalendarFragment
 import de.rki.coronawarnapp.ui.submission.symptoms.calendar.SubmissionSymptomCalendarModule
 import de.rki.coronawarnapp.ui.submission.symptoms.introduction.SubmissionSymptomIntroductionFragment
@@ -86,6 +88,9 @@ internal abstract class SubmissionFragmentModule {
     @ContributesAndroidInjector(modules = [SubmissionTestResultAvailableModule::class])
     abstract fun submissionTestResultAvailableScreen(): SubmissionTestResultAvailableFragment
 
+    @ContributesAndroidInjector(modules = [SubmissionDoneModule::class])
+    abstract fun submissionDoneScreen(): SubmissionDoneFragment
+
     @ContributesAndroidInjector(modules = [SubmissionTestResultConsentGivenModule::class])
     abstract fun submissionTestResultConsentGivenScreen(): SubmissionTestResultConsentGivenFragment
 
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 28f1e8a8c2e3f18fe1579f0c26247f59caff5716..14ac3802e44d3c17a221821e099d3454342ecfff 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
@@ -9,6 +9,7 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.Screen
 import de.rki.coronawarnapp.exception.ExceptionCategory
@@ -70,7 +71,9 @@ class SubmissionResultPositiveOtherWarningNoConsentViewModel @AssistedInject con
                     autoSubmission.updateMode(AutoSubmission.Mode.MONITOR)
                     Timber.tag(TAG).d("Navigate to SubmissionResultReadyFragment")
                     SubmissionResultPositiveOtherWarningNoConsentFragmentDirections
-                        .actionSubmissionResultPositiveOtherWarningNoConsentFragmentToSubmissionResultReadyFragment()
+                        .actionSubmissionResultPositiveOtherWarningNoConsentFragmentToSubmissionResultReadyFragment(
+                            testType
+                        )
                 }
                 routeToScreen.postValue(navDirections)
             }
@@ -138,7 +141,9 @@ class SubmissionResultPositiveOtherWarningNoConsentViewModel @AssistedInject con
     }
 
     fun onResume() {
-        analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.WARN_OTHERS)
+        if (testType == PCR) {
+            analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.WARN_OTHERS)
+        }
     }
 
     @AssistedFactory
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt
index 442df0780ea00459160a7c9471bfec09a44293eb..e657ddd7d3e6d550ade9159761bc57d7c86b63a2 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt
@@ -5,13 +5,11 @@ import android.net.wifi.WifiManager
 import android.os.PowerManager
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.lifecycleScope
-import de.rki.coronawarnapp.risk.execution.RiskWorkScheduler
-import de.rki.coronawarnapp.storage.OnboardingSettings
-import de.rki.coronawarnapp.task.TaskController
+import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingRiskWorkScheduler
+import de.rki.coronawarnapp.risk.execution.ExposureWindowRiskWorkScheduler
 import de.rki.coronawarnapp.util.device.BackgroundModeStatus
 import de.rki.coronawarnapp.util.di.AppContext
 import de.rki.coronawarnapp.util.di.ProcessLifecycle
-import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
@@ -23,12 +21,10 @@ import javax.inject.Singleton
 @Singleton
 class WatchdogService @Inject constructor(
     @AppContext private val context: Context,
-    private val taskController: TaskController,
     private val backgroundModeStatus: BackgroundModeStatus,
     @ProcessLifecycle private val processLifecycleOwner: LifecycleOwner,
-    private val onboardingSettings: OnboardingSettings,
-    private val backgroundWorkScheduler: BackgroundWorkScheduler,
-    private val riskWorkScheduler: RiskWorkScheduler,
+    private val exposureWindowRiskWorkScheduler: ExposureWindowRiskWorkScheduler,
+    private val presenceTracingRiskRepository: PresenceTracingRiskWorkScheduler,
 ) {
 
     private val powerManager by lazy {
@@ -46,6 +42,10 @@ class WatchdogService @Inject constructor(
             return
         }
 
+        // TODO it's unclear whether this really has any effect
+        // If we are being bound by Google Play Services (which is only a few seconds)
+        // and don't have a worker or foreground service, the system may still kill us and the tasks
+        // before they have finished executing.
         Timber.tag(TAG).v("Acquiring wakelocks for watchdog routine.")
         processLifecycleOwner.lifecycleScope.launch {
             // A wakelock as the OS does not handle this for us like in the background job execution
@@ -55,18 +55,15 @@ class WatchdogService @Inject constructor(
 
             Timber.tag(TAG).d("Automatic mode is on, check if we have downloaded keys already today")
 
-            val results = riskWorkScheduler.runRiskTasksNow()
-            Timber.tag(TAG).d("runRiskTasksNow() results: %s", results)
+            Timber.tag(TAG).d("Running EW risk tasks now.")
+            exposureWindowRiskWorkScheduler.runRiskTasksNow(TAG)
+
+            Timber.tag(TAG).d("Rnuning PT risk tasks now.")
+            presenceTracingRiskRepository.runRiskTaskNow(TAG)
 
             if (wifiLock.isHeld) wifiLock.release()
             if (wakeLock.isHeld) wakeLock.release()
         }
-
-        // if the user is onboarded we will schedule period background jobs
-        // in case the app was force stopped and woken up again by the Google WakeUpService
-        if (onboardingSettings.isOnboarded) {
-            backgroundWorkScheduler.startWorkScheduler()
-        }
     }
 
     private fun createWakeLock(): PowerManager.WakeLock = powerManager
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
index fafb7e29de202995224714daf4bbcfe5178112b8..574ed5dbcdd248c658dc375b0b2b0539adfd76f3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
@@ -18,12 +18,12 @@ import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule
 import de.rki.coronawarnapp.diagnosiskeys.DownloadDiagnosisKeysTaskModule
 import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository
 import de.rki.coronawarnapp.environment.EnvironmentModule
-import de.rki.coronawarnapp.presencetracing.PresenceTracingModule
 import de.rki.coronawarnapp.http.HttpModule
 import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.nearby.ENFModule
 import de.rki.coronawarnapp.playbook.Playbook
 import de.rki.coronawarnapp.playbook.PlaybookModule
+import de.rki.coronawarnapp.presencetracing.PresenceTracingModule
 import de.rki.coronawarnapp.receiver.ReceiverBinder
 import de.rki.coronawarnapp.risk.RiskModule
 import de.rki.coronawarnapp.service.ServiceBinder
@@ -44,7 +44,6 @@ import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
 import de.rki.coronawarnapp.util.security.SecurityModule
 import de.rki.coronawarnapp.util.serialization.SerializationModule
 import de.rki.coronawarnapp.util.worker.WorkerBinder
-import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 import javax.inject.Singleton
 
 @Singleton
@@ -103,8 +102,6 @@ interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> {
 
     fun inject(logger: DebugLogger)
 
-    fun inject(backgroundWorkScheduler: BackgroundWorkScheduler)
-
     val encryptedMigration: EncryptedPreferencesMigration
 
     @Component.Factory
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigration.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigration.kt
index b2eea5c60ce439ad2bb43140aabacaf9e1a4a151..9479266cd2b464059f98a58a8afd340ee37e902b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigration.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigration.kt
@@ -59,8 +59,8 @@ class EncryptedPreferencesMigration @Inject constructor(
         }
 
         OnboardingLocalData(encryptedSharedPreferences).apply {
-            onboardingSettings.onboardingCompletedTimestamp = onboardingCompletedTimestamp()?.let {
-                Instant.ofEpochMilli(it)
+            onboardingSettings.onboardingCompletedTimestamp.update {
+                onboardingCompletedTimestamp()?.let { Instant.ofEpochMilli(it) }
             }
             onboardingSettings.isBackgroundCheckDone = isBackgroundCheckDone()
         }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/flow/FlowExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/flow/FlowExtensions.kt
index 1abf9aded1592a32d94f65f06fcf70033f153fe5..09fc597d5549e782671b3a9c47029060f3c50a6b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/flow/FlowExtensions.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/flow/FlowExtensions.kt
@@ -57,6 +57,24 @@ inline fun <T1, T2, R> combine(
     )
 }
 
+@Suppress("UNCHECKED_CAST", "LongParameterList")
+inline fun <T1, T2, T3, R> combine(
+    flow: Flow<T1>,
+    flow2: Flow<T2>,
+    flow3: Flow<T3>,
+    crossinline transform: suspend (T1, T2, T3) -> R
+): Flow<R> = combine(
+    flow,
+    flow2,
+    flow3,
+) { args: Array<*> ->
+    transform(
+        args[0] as T1,
+        args[1] as T2,
+        args[2] as T3,
+    )
+}
+
 @Suppress("UNCHECKED_CAST", "LongParameterList")
 inline fun <T1, T2, T3, T4, T5, R> combine(
     flow: Flow<T1>,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/worker/WorkerBinder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/worker/WorkerBinder.kt
index 7f1d39bc4282decace282912e2ab110e65cb9dd9..3b07716c52847508970e5b09bb781858ca55e9d9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/worker/WorkerBinder.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/worker/WorkerBinder.kt
@@ -5,8 +5,8 @@ import dagger.Binds
 import dagger.Module
 import dagger.multibindings.IntoMap
 import de.rki.coronawarnapp.contactdiary.retention.ContactDiaryRetentionWorker
-import de.rki.coronawarnapp.coronatest.worker.PCRResultRetrievalWorker
-import de.rki.coronawarnapp.coronatest.worker.RAResultRetrievalWorker
+import de.rki.coronawarnapp.coronatest.type.pcr.execution.PCRResultRetrievalWorker
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultRetrievalWorker
 import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsPeriodicWorker
 import de.rki.coronawarnapp.deadman.DeadmanNotificationOneTimeWorker
 import de.rki.coronawarnapp.deadman.DeadmanNotificationPeriodicWorker
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundConstants.kt
index b250c13b7b41292d63406c65e60ded636630426d..32bec142a340b955e949c5b6b58fd1b7e79fe838 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundConstants.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundConstants.kt
@@ -4,22 +4,9 @@ import java.util.concurrent.TimeUnit
 
 /**
  * The background work constants are used inside the BackgroundWorkScheduler
- *
- * @see BackgroundWorkScheduler
  */
 object BackgroundConstants {
 
-    /**
-     * Total minutes in one day
-     */
-    const val MINUTES_IN_DAY = 1440
-
-    /**
-     * Total tries count for diagnosis key retrieval per day
-     * Internal requirement
-     */
-    const val DIAGNOSIS_TEST_RESULT_RETRIEVAL_TRIES_PER_DAY = 12
-
     /**
      * Kind initial delay in minutes for periodic work for accessibility reason
      *
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundWorkHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundWorkHelper.kt
deleted file mode 100644
index 67a621d61fb61b58f75fc4689b2185b940ce99be..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundWorkHelper.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-package de.rki.coronawarnapp.worker
-
-import androidx.work.Constraints
-import androidx.work.NetworkType
-import kotlin.random.Random
-
-/**
- * Singleton class for background work helper functions
- * The helper uses externalised constants for readability.
- *
- * @see BackgroundConstants
- * @see BackgroundWorkScheduler
- */
-object BackgroundWorkHelper {
-
-    /**
-     * Get background noise one time work delay
-     * The periodic job is already delayed by MIN_HOURS_TO_NEXT_BACKGROUND_NOISE_EXECUTION
-     * so we only need to delay further by the difference between min and max.
-     *
-     * @return Long
-     *
-     * @see BackgroundConstants.MAX_HOURS_TO_NEXT_BACKGROUND_NOISE_EXECUTION
-     * @see BackgroundConstants.MIN_HOURS_TO_NEXT_BACKGROUND_NOISE_EXECUTION
-     */
-    fun getBackgroundNoiseOneTimeWorkDelay() = Random.nextLong(
-        0,
-        BackgroundConstants.MAX_HOURS_TO_NEXT_BACKGROUND_NOISE_EXECUTION -
-            BackgroundConstants.MIN_HOURS_TO_NEXT_BACKGROUND_NOISE_EXECUTION
-    )
-
-    /**
-     * Constraints for diagnosis key one time work
-     * Requires battery not low and any network connection
-     * Mobile data usage is handled on OS level in application settings
-     *
-     * @return Constraints
-     *
-     * @see NetworkType.CONNECTED
-     */
-    fun getConstraintsForDiagnosisKeyOneTimeBackgroundWork() =
-        Constraints
-            .Builder()
-            .setRequiredNetworkType(NetworkType.CONNECTED)
-            .build()
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundWorkScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundWorkScheduler.kt
deleted file mode 100644
index cad840478e28eb59f3308be97be47c082f0621ce..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundWorkScheduler.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-package de.rki.coronawarnapp.worker
-
-import de.rki.coronawarnapp.coronatest.CoronaTestRepository
-import de.rki.coronawarnapp.coronatest.worker.execution.PCRResultScheduler
-import de.rki.coronawarnapp.deniability.NoiseScheduler
-import de.rki.coronawarnapp.risk.execution.RiskWorkScheduler
-import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.runBlocking
-import timber.log.Timber
-import javax.inject.Inject
-import javax.inject.Singleton
-
-/**
- * Singleton class for background work handling
- * The helper uses externalised constants and helper for readability.
- *
- * @see BackgroundConstants
- * @see BackgroundWorkHelper
- */
-@Singleton
-class BackgroundWorkScheduler @Inject constructor(
-    private val riskWorkScheduler: RiskWorkScheduler,
-    private val coronaTestRepository: CoronaTestRepository,
-    private val testResultScheduler: PCRResultScheduler,
-    private val noiseScheduler: NoiseScheduler,
-) {
-
-    fun startWorkScheduler() {
-        Timber.d("startWorkScheduler()")
-        riskWorkScheduler.setPeriodicRiskCalculation(enabled = true)
-
-        // TODO Blocking isn't very nice here...
-        val coronatests = runBlocking { coronaTestRepository.coronaTests.first() }
-
-        val isSubmissionSuccessful = coronatests.any { it.isSubmitted }
-        val hasPendingTests = coronatests.any { !it.isResultAvailableNotificationSent }
-
-        if (!isSubmissionSuccessful && hasPendingTests) {
-            testResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = true)
-        }
-    }
-
-    fun stopWorkScheduler() {
-        noiseScheduler.setPeriodicNoise(enabled = false)
-        riskWorkScheduler.setPeriodicRiskCalculation(enabled = false)
-        testResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = false)
-        Timber.d("All Background Jobs Stopped")
-    }
-}
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_done.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_done.xml
index 5265e288aeb2b577b1f2910f5733633e77e5079a..25844017a9edf419fd46c3b30e697558c7e78cab 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_submission_done.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_done.xml
@@ -11,15 +11,14 @@
         android:fillViewport="true"
         tools:context=".ui.submission.fragment.SubmissionDoneFragment">
 
-        <include
-            android:id="@+id/submission_done_header"
-            layout="@layout/include_header"
+        <androidx.appcompat.widget.Toolbar
+            android:id="@+id/toolbar"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
-            app:icon="@{@drawable/ic_close}"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="parent" />
+            app:layout_constraintTop_toTopOf="parent"
+            app:title="@string/submission_done_title" />
 
         <include
             android:id="@+id/submission_done_content"
@@ -29,7 +28,7 @@
             app:layout_constraintBottom_toBottomOf="@id/guideline_action"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/submission_done_header" />
+            app:layout_constraintTop_toBottomOf="@id/toolbar"/>
 
         <Button
             android:id="@+id/submission_done_button_done"
@@ -41,7 +40,7 @@
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="@id/guideline_end"
             app:layout_constraintStart_toStartOf="@id/guideline_start"
-            app:layout_constraintTop_toBottomOf="@+id/guideline_action" />
+            app:layout_constraintTop_toBottomOf="@id/guideline_action" />
 
         <androidx.constraintlayout.widget.Guideline
             android:id="@+id/guideline_action"
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_consent_given.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_consent_given.xml
index d000dfd81b3f6a4e4c2f52382680e89d979fcf8d..ec8026435bfdd6dcd1480f0b5e06bad91682af00 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_consent_given.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_consent_given.xml
@@ -13,10 +13,10 @@
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/submission_test_result_container"
-        android:contentDescription="@string/submission_test_result_headline"
-        android:accessibilityLiveRegion="assertive"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="match_parent"
+        android:accessibilityLiveRegion="assertive"
+        android:contentDescription="@string/submission_test_result_headline">
 
         <include
             android:id="@+id/submission_test_result_consent_given_header"
@@ -30,14 +30,15 @@
             app:title="@{@string/submission_test_result_consent_given_heading}" />
 
         <ScrollView
+            android:id="@+id/scroll_view"
             android:layout_width="0dp"
             android:layout_height="0dp"
-            app:layout_constraintEnd_toEndOf="@+id/guideline_end"
-            app:layout_constraintStart_toStartOf="@+id/guideline_start"
+            android:layout_marginBottom="12dp"
             android:fillViewport="true"
-            app:layout_constraintTop_toBottomOf="@+id/submission_test_result_consent_given_header"
-            app:layout_constraintBottom_toTopOf="@+id/include_submission_test_result_consent_given_buttons"
-            app:layout_constraintVertical_bias="1.0">
+            app:layout_constraintBottom_toTopOf="@id/submission_test_result_button_consent_given_continue"
+            app:layout_constraintEnd_toEndOf="@id/guideline_end"
+            app:layout_constraintStart_toStartOf="@id/guideline_start"
+            app:layout_constraintTop_toBottomOf="@id/submission_test_result_consent_given_header">
 
             <androidx.constraintlayout.widget.ConstraintLayout
                 android:layout_width="match_parent"
@@ -65,7 +66,7 @@
                     android:text="@string/submission_test_result_consent_given_subtitle"
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toBottomOf="@+id/submission_test_result_section" />
+                    app:layout_constraintTop_toBottomOf="@id/submission_test_result_section" />
 
                 <TextView
                     android:id="@+id/submission_test_result_consent_given_body"
@@ -77,39 +78,32 @@
                     android:text="@string/submission_test_result_consent_given_body"
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toBottomOf="@+id/submission_test_result_consent_given_subtitle" />
+                    app:layout_constraintTop_toBottomOf="@id/submission_test_result_consent_given_subtitle" />
             </androidx.constraintlayout.widget.ConstraintLayout>
         </ScrollView>
 
-        <androidx.constraintlayout.widget.Barrier
-            android:id="@+id/include_submission_test_result_consent_given_buttons"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            app:barrierAllowsGoneWidgets="false"
-            app:barrierDirection="top"
-            app:constraint_referenced_ids="submission_test_result_button_consent_given_continue" />
-
         <Button
             android:id="@+id/submission_test_result_button_consent_given_continue"
             style="@style/buttonPrimary"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
+            android:layout_marginTop="24dp"
+            android:layout_marginBottom="18dp"
             android:text="@string/submission_test_result_positive_continue_button_with_symptoms"
-            app:layout_constraintBottom_toTopOf="@+id/submission_test_result_button__consent_given_continue_without_symptoms"
-            app:layout_constraintEnd_toStartOf="@+id/guideline_end"
-            app:layout_constraintStart_toStartOf="@id/guideline_start"
-            app:layout_constraintTop_toBottomOf="@+id/guideline_action_large" />
+            app:layout_constraintBottom_toTopOf="@id/submission_test_result_button_consent_given_continue_without_symptoms"
+            app:layout_constraintEnd_toStartOf="@id/guideline_end"
+            app:layout_constraintStart_toStartOf="@id/guideline_start" />
 
         <Button
             android:id="@+id/submission_test_result_button_consent_given_continue_without_symptoms"
             style="@style/buttonPrimary"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
+            android:layout_marginBottom="18dp"
             android:text="@string/submission_test_result_consent_given_breakup_button"
             app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toStartOf="@+id/guideline_end"
-            app:layout_constraintStart_toStartOf="@id/guideline_start"
-            app:layout_constraintTop_toBottomOf="@+id/submission_test_result_button_consent_given_continue" />
+            app:layout_constraintEnd_toStartOf="@id/guideline_end"
+            app:layout_constraintStart_toStartOf="@id/guideline_start" />
 
         <include layout="@layout/merge_guidelines_side" />
 
diff --git a/Corona-Warn-App/src/main/res/layout/home_reenable_risk_card_layout.xml b/Corona-Warn-App/src/main/res/layout/home_reenable_risk_card_layout.xml
deleted file mode 100644
index 34fcc456137c95fbce1b2a6d5a5b3a242f5fb89f..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/res/layout/home_reenable_risk_card_layout.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<layout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools">
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:padding="@dimen/card_padding"
-        tools:showIn="@layout/home_card_container_layout">
-
-        <TextView
-            android:id="@+id/reenable_risk_card_title"
-            style="@style/headline5"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="@dimen/spacing_small"
-            android:accessibilityHeading="true"
-            android:text="@string/reenable_risk_card_title"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="parent" />
-
-        <TextView
-            android:id="@+id/reenable_risk_card_positive_title"
-            style="@style/headline6"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/spacing_normal"
-            android:layout_marginEnd="@dimen/spacing_small"
-            android:accessibilityHeading="true"
-            android:text="@string/submission_test_result_card_positive_title"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/reenable_risk_card_title" />
-
-        <ImageView
-            android:id="@+id/reenable_risk_card_positive_icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:background="@drawable/ic_test_result_illustration_positive_card"
-            android:importantForAccessibility="no"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintTop_toTopOf="@id/reenable_risk_card_positive_title"
-            tools:src="@drawable/ic_test_result_illustration_positive" />
-
-        <TextView
-            android:id="@+id/reenable_risk_card_positive_body"
-            style="@style/body2"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/spacing_normal"
-            android:layout_marginEnd="@dimen/spacing_small"
-            android:text="@string/submission_test_result_card_positive_body"
-            app:layout_constraintEnd_toStartOf="@id/reenable_risk_card_positive_icon"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@id/reenable_risk_card_positive_title" />
-
-        <TextView
-            android:id="@+id/reenable_risk_card_test_registration_date"
-            style="@style/body2"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="@dimen/spacing_small"
-            tools:text="@string/reenable_risk_card_test_registration_string"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@id/reenable_risk_card_positive_body" />
-
-        <View
-            android:id="@+id/reenable_risk_card_divider"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/card_divider"
-            android:layout_marginTop="@dimen/spacing_normal"
-            android:background="@color/colorHairline"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/reenable_risk_card_test_registration_date" />
-
-        <TextView
-            android:id="@+id/reenable_risk_card_description"
-            style="@style/body1"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/spacing_medium"
-            android:layout_marginEnd="@dimen/spacing_small"
-            android:text="@string/reenable_risk_card_description_text"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@id/reenable_risk_card_divider" />
-
-        <Button
-            android:id="@+id/reenable_risk_card_button"
-            style="@style/buttonPrimary"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/spacing_normal"
-            android:text="@string/reenable_risk_card_button_text"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@id/reenable_risk_card_description" />
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-</layout>
diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_done_content.xml b/Corona-Warn-App/src/main/res/layout/include_submission_done_content.xml
index e37bf7a9566126cd425bf08e256483529d9f45fa..62d33f58f92e99de14b143adfd3eddace2f9a8ce 100644
--- a/Corona-Warn-App/src/main/res/layout/include_submission_done_content.xml
+++ b/Corona-Warn-App/src/main/res/layout/include_submission_done_content.xml
@@ -68,8 +68,8 @@
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_marginTop="@dimen/spacing_normal"
-            app:body="@{@string/submission_done_share_keys}"
-            app:icon="@{@drawable/ic_share_keys}"
+            app:body="@{@string/submission_done_isolate}"
+            app:icon="@{@drawable/ic_risk_details_home}"
             app:layout_constraintEnd_toEndOf="@id/guideline_end"
             app:layout_constraintStart_toStartOf="@id/guideline_start"
             app:layout_constraintTop_toBottomOf="@id/submission_done_contagious" />
diff --git a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml
index 44c7f71310aaba1f7be87d768f2694d07f010719..bfa756731ac7755907337488500703bb9deb018a 100644
--- a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml
+++ b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml
@@ -401,6 +401,9 @@
         android:name="de.rki.coronawarnapp.ui.submission.resultready.SubmissionResultReadyFragment"
         android:label="SubmissionResultReadyFragment"
         tools:layout="@layout/fragment_submission_result_ready">
+        <argument
+            android:name="testType"
+            app:argType="de.rki.coronawarnapp.coronatest.type.CoronaTest$Type" />
         <action
             android:id="@+id/action_submissionResultReadyFragment_to_mainFragment"
             app:destination="@id/mainFragment"
@@ -422,6 +425,9 @@
         android:id="@+id/submissionSymptomIntroductionFragment"
         android:name="de.rki.coronawarnapp.ui.submission.symptoms.introduction.SubmissionSymptomIntroductionFragment"
         android:label="SubmissionSymptomIntroductionFragment">
+        <argument
+            android:name="testType"
+            app:argType="de.rki.coronawarnapp.coronatest.type.CoronaTest$Type" />
         <action
             android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionSymptomCalendarFragment"
             app:destination="@id/submissionSymptomCalendarFragment" />
@@ -430,6 +436,11 @@
             app:destination="@id/mainFragment"
             app:popUpTo="@id/nav_graph"
             app:popUpToInclusive="true" />
+        <action
+            android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionDoneFragment"
+            app:destination="@id/submissionDoneFragment"
+            app:popUpTo="@id/mainFragment"
+            app:popUpToInclusive="false"/>
     </fragment>
     <fragment
         android:id="@+id/submissionSymptomCalendarFragment"
@@ -438,6 +449,9 @@
         <argument
             android:name="symptomIndication"
             app:argType="de.rki.coronawarnapp.submission.Symptoms$Indication" />
+        <argument
+            android:name="testType"
+            app:argType="de.rki.coronawarnapp.coronatest.type.CoronaTest$Type" />
         <action
             android:id="@+id/action_submissionCalendarFragment_to_submissionSymptomIntroductionFragment"
             app:destination="@id/submissionSymptomIntroductionFragment" />
@@ -449,6 +463,11 @@
             app:destination="@id/mainFragment"
             app:popUpTo="@id/nav_graph"
             app:popUpToInclusive="true" />
+        <action
+            android:id="@+id/action_submissionSymptomCalendarFragment_to_submissionDoneFragment"
+            app:destination="@id/submissionDoneFragment"
+            app:popUpTo="@id/mainFragment"
+            app:popUpToInclusive="false"/>
     </fragment>
     <fragment
         android:id="@+id/submissionConsentFragment"
@@ -755,4 +774,18 @@
             android:name="testType"
             app:argType="de.rki.coronawarnapp.coronatest.type.CoronaTest$Type" />
     </fragment>
+    <fragment
+        android:id="@+id/submissionDoneFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.submissiondone.SubmissionDoneFragment"
+        android:label="SubmissionDoneFragment"
+        tools:layout="@layout/fragment_submission_done">
+        <action
+            android:id="@+id/action_submissionDoneFragment_to_mainFragment"
+            app:destination="@id/mainFragment"
+            app:popUpTo="@id/nav_graph"
+            app:popUpToInclusive="true"/>
+        <argument
+            android:name="testType"
+            app:argType="de.rki.coronawarnapp.coronatest.type.CoronaTest$Type"/>
+    </fragment>
 </navigation>
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 43d5ccde843d7ab2ea8b7b5aa112b1ba021f66ff..c45a642f087a824de2e3ba8d106090c4fc677387 100644
--- a/Corona-Warn-App/src/main/res/values-bg/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/strings.xml
@@ -249,7 +249,7 @@
     <!-- XACT: main (overview) - illustraction description, explanation image -->
     <string name="main_overview_illustration_description">"Смартфон, показващ различни блокове съдържание с номера от 1 до 3."</string>
     <!-- XACT: App main page title -->
-    <string name="main_title">"Главна страница на приложението Corona-Warn-App"</string>
+    <string name="main_title">"Главен екран на приложението Corona-Warn-App"</string>
 
     <!-- ####################################
                Risk Details
@@ -787,7 +787,10 @@
     <string name="information_contact_subtitle_phone">"Технически въпроси:"</string>
     <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page -->
     <string name="information_contact_button_phone">"0800 7540001"</string>
+    <!-- XLNK: Button / hyperlink to international phone call for technical contact and hotline information page -->
     <string name="information_contact_button_international_phone">"+49 30 498 75401"</string>
+    <!-- XLNK: Button / hyperlink to international phone call for technical contact and hotline TAN info page -->
+    <string name="submission_contact_button_international_phone">"+49 30 498 75402"</string>
     <!-- XLNK: Description for national technical contact and hotline information page -->
     <string name="information_contact_button_phone_description">"За обаждания на територията на Германия.\nОбаждането е безплатно."</string>
     <!-- XLNK: Description for international technical contact and hotline information page -->
@@ -1134,19 +1137,19 @@
     <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN  -->
     <string name="submission_dispatcher_needs_testing_subheadline">"Правили ли сте си тест?"</string>
     <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN  -->
-    <string name="submission_dispatcher_already_positive_subheadline">"Положителен ли е Вашият резултат от теста за коронавирус?"</string>
+    <string name="submission_dispatcher_already_positive_subheadline">"Положителен ли е Вашият резултат от PCR теста?"</string>
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"Тест с QR код"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
     <string name="submission_dispatcher_qr_card_text">"Регистрирайте теста си, като сканирате QR кода на документа."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
-    <string name="submission_dispatcher_card_tan_code">"Въведете ТАН код"</string>
+    <string name="submission_dispatcher_card_tan_code">"Въведете ТАН код за PCR тест"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
-    <string name="submission_dispatcher_tan_code_card_text">"Имате TAN код? Въведете го тук, за да предупредите останалите."</string>
+    <string name="submission_dispatcher_tan_code_card_text">"Имате TAN код за вашия PCR тест? Въведете го тук, за да предупредите останалите."</string>
     <!-- YTXT: Dispatcher text for TELE-TAN option -->
-    <string name="submission_dispatcher_card_tan_tele">"Все още нямате TAN код?"</string>
+    <string name="submission_dispatcher_card_tan_tele">"Заявете ТАН код за PCR тест"</string>
     <!-- YTXT: Body text for TELE_TAN dispatcher option -->
-    <string name="submission_dispatcher_tan_tele_card_text">"Позвънете ни, за да получите TAN код."</string>
+    <string name="submission_dispatcher_tan_tele_card_text">"Позвънете ни, за да получите TAN код за PCR тест."</string>
     <!-- XACT: Dispatcher Tan page title -->
     <string name="submission_dispatcher_accessibility_title">"С каква информация разполагате?"</string>
 
@@ -1204,10 +1207,15 @@
     <string name="submission_done_body">"Благодарение на Вашата подкрепа други хора ще бъдат предупредени и ще могат да реагират адекватно."</string>
     <!-- XHED: Page subtitle for completed submission page -->
     <string name="submission_done_subtitle">"Моля, не забравяйте:"</string>
+    <!-- YTXT: text after submission: pcr validation -->
+    <string name="submission_done_pcr_validation">"Направете PCR тест, за да потвърдите този резултат от тест."</string>
+    <!-- YTXT: text after submission: pcr validation -->
+    <string name="submission_done_share_keys">"Споделете своите случайни ИД кодове, за да предупредите останалите потребители."</string>
     <!-- YTXT: text after submission: contagious -->
     <string name="submission_done_contagious">"От службата за обществено здравеопазване (Gesundheitsamt) ще се свържат с Вас в следващите няколко дни."</string>
     <!-- YTXT: text after submission: isolate -->
     <string name="submission_done_isolate">"Вие сте носител на заразата. Необходимо е да се самоизолирате."</string>
+
     <!-- XHED: Title for further info -->
     <string name="submission_done_further_info_title">"Още информация:"</string>
     <!-- YTXT: submission done further info bullet points -->
@@ -1268,7 +1276,7 @@
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
-    <string name="submission_contact_title">"Заявка за ТАН код"</string>
+    <string name="submission_contact_title">"Заявете ТАН код за PCR тест"</string>
     <!-- XHED: Page headline for contact page in submission flow -->
     <string name="submission_contact_headline">"Как работи:"</string>
     <!-- YTXT: Body text for contact page in submission flow-->
@@ -1284,7 +1292,7 @@
     <!-- XLNK: Technical number which is called when the user clicks on the display number -->
     <string name="submission_contact_number_dial">"0800 7540002"</string>
     <!-- YTXT: Body text for step 2 of contact page-->
-    <string name="submission_contact_step_2_body">"Регистрирайте теста си, като въведете ТАН кода в приложението."</string>
+    <string name="submission_contact_step_2_body">"Регистрирайте PCR теста си, като въведете ТАН кода в приложението."</string>
     <!-- YTXT: Body text for operating hours in contact page-->
     <string name="submission_contact_operating_hours_body">"Нашият екип за обслужване на клиенти е готов да Ви помогне на следните езици: \nанглийски, немски, турски\n\nРаботно време:\n24/7"</string>
     <!-- YTXT: Body text for technical contact and hotline information page -->
@@ -1369,23 +1377,6 @@
     <!-- YTXT: text for share result card-->
     <string name="submission_status_card_positive_result_share">"Споделете своите случайни ИД кодове, за да предупредите останалите потребители."</string>
 
-
-    <!-- XBUT: submission deletion warning button continue -->
-    <string name="submission_deletion_warning_continue_button">"Напред"</string>
-    <!-- XBUT: submission deletion warning button cancel -->
-    <string name="submission_deletion_warning_cancel_button">"Отказ"</string>
-    <!-- XHED: submission deletion warning title -->
-    <string name="submission_deletion_warning_title">"Бележка"</string>
-    <!-- YTXT: Headline for rapid test submission deletion warning -->
-    <string name="submission_deletion_warning_headline_antigen_test">"Вече сте регистрирали бърз тест."</string>
-    <!-- YTXT: Body for rapid test submission deletion warning -->
-    <string name="submission_deletion_warning_body_antigen_test">"Вече сте регистрирали бърз тест. Приложението може да обработва едновременно само един бърз тест и един PCR тест. Ако регистрирате друг бърз тест, предходният бърз тест ще бъде изтрит."</string>
-    <!-- YTXT: Headline for PCR test submission deletion warning -->
-    <string name="submission_deletion_warning_headline_pcr_test">"Вече сте регистрирали PCR тест."</string>
-    <!-- YTXT: Body for PCR test submission deletion warning -->
-    <string name="submission_deletion_warning_body_pcr_test">"Вече сте регистрирали PCR тест. Приложението може да обработва едновременно само един бърз тест и един PCR тест. Ако регистрирате друг PCR тест, предходният PCR тест ще бъде изтрит."</string>
-
-
     <!-- Reenable risk card -->
     <!-- XHED: Card title for re-enable risk card -->
     <string name="reenable_risk_card_title">"Проверката за излагане на риск е спряна"</string>
@@ -1405,11 +1396,11 @@
     <string name="dialog_reactivate_risk_calculation_button_negative">"Отказ"</string>
 
     <!-- Test Result Card -->
-    <string name="test_result_card_headline">"Вашата диагноза:"</string>
+    <string name="test_result_card_headline">"Вашата диагноза %s:"</string>
     <!-- YTXT: virus name text -->
     <string name="test_result_card_virus_name_text">"SARS-CoV-2"</string>
     <!-- YTXT: registered at text -->
-    <string name="test_result_card_registered_at_text">"Регистрирано на %s"</string>
+    <string name="test_result_card_registered_at_text">"Тестът е добавен на %s"</string>
     <!-- YTXT: negative status text -->
     <string name="test_result_card_status_negative">"Отрицателен"</string>
     <!-- YTXT: positive status text -->
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 707f0e5913aa59fc7bc7a475794604b724890733..c262665e2bac9319a4d9cafc676251776d4ea1aa 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
@@ -130,7 +130,7 @@
     <!-- XTXT: Third bulletpoint text for privacy card -->
     <string name="trace_location_privacy_card_third_bulletpoint_text">"Bitte stellen Sie den QR-Code so zur Verfügung, dass alle Ihre Gäste ihn unter Einhaltung der Abstands- und Hygieneregeln (mindestens 1,5 Meter) scannen können."</string>
     <!-- XTXT: Fourth bulletpoint text for privacy card -->
-    <string name="trace_location_privacy_card_fourth_bulletpoint_text">"Wir empfehlen die QR-Codes für Orte in einmal täglich außerhalb der Öffnungszeiten neu zu erstellen, um dauerhaft zuverlässige Warnungen zu ermöglichen und Missbrauch der QR-Codes zu verhindern."</string>
+    <string name="trace_location_privacy_card_fourth_bulletpoint_text">"Wir empfehlen die QR-Codes für Orte in regelmäßigen Abständen neu zu erstellen, um dauerhaft zuverlässige Warnungen zu ermöglichen und Missbrauch der QR-Codes zu verhindern."</string>
 
     <!-- Trace Location Onboarding Strings -->
     <!-- XHED: Title for the trace location onboarding consent card -->
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 2fb1a2f98bc5413edf28da0fcf3fb650b9bd4a91..83c2f1da8b7ffcc3f86ea7a9540085b6b4edb161 100644
--- a/Corona-Warn-App/src/main/res/values-de/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/strings.xml
@@ -1379,24 +1379,6 @@
     <!-- YTXT: text for share result card-->
     <string name="submission_status_card_positive_result_share">"Teilen Sie Ihre Zufalls-IDs, damit andere gewarnt werden können."</string>
 
-    <!-- Reenable risk card -->
-    <!-- XHED: Card title for re-enable risk card -->
-    <string name="reenable_risk_card_title">"Risiko-Überprüfung beendet"</string>
-    <!-- YTXT: Body text for test registration date -->
-    <string name="reenable_risk_card_test_registration_string">"Test registriert am %s"</string>
-    <!-- YTXT: Description text for re-enable risk card -->
-    <string name="reenable_risk_card_description_text">"Die automatische Risiko-Überprüfung wurde beendet, weil Sie sich aufgrund Ihres positiven Tests aktuell in Isolation befinden. Sie können die Risiko-Überprüfung jederzeit wieder einschalten. Ihr registrierter Test wird dann automatisch gelöscht."</string>
-    <!-- XBUT: Button for re-enabling risk calculation -->
-    <string name="reenable_risk_card_button_text">"Risiko-Überprüfung Einschalten "</string>
-    <!-- XHED: Dialog title for reactivate risk calculation  -->
-    <string name="dialog_reactivate_risk_calculation_title">"Risiko-Überprüfung aktivieren."</string>
-    <!-- YTXT: Dialog text for reactivate risk calculation -->
-    <string name="dialog_reactivate_risk_calculation_message">"Ihr aktueller Test wird aus der App gelöscht, damit Sie bei Bedarf einen neuen Test registrieren können."</string>
-    <!-- XBUT: Positive button for reactivate risk calculation -->
-    <string name="dialog_reactivate_risk_calculation_button_positive">"Aktivieren"</string>
-    <!-- XBUT: Negative button for reactivate risk calculation -->
-    <string name="dialog_reactivate_risk_calculation_button_negative">"Abbrechen"</string>
-
     <!-- Test Result Card -->
     <string name="test_result_card_headline">"Ihr %s-Befund:"</string>
     <!-- YTXT: virus name text -->
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 964b1624d965c649d145fbb95e86e49470dd2e1b..0d164ebd5a791e4ca0c76a4f6c4469b5eaf2b1a4 100644
--- a/Corona-Warn-App/src/main/res/values-en/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/strings.xml
@@ -249,7 +249,7 @@
     <!-- XACT: main (overview) - illustraction description, explanation image -->
     <string name="main_overview_illustration_description">"A smartphone displays various content, numbered 1 to 3."</string>
     <!-- XACT: App main page title -->
-    <string name="main_title">"Main page of the Corona-Warn-App"</string>
+    <string name="main_title">"Main screen of the Corona-Warn-App"</string>
 
     <!-- ####################################
                Risk Details
@@ -787,7 +787,10 @@
     <string name="information_contact_subtitle_phone">"Technical hotline:"</string>
     <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page -->
     <string name="information_contact_button_phone">"0800 7540001"</string>
+    <!-- XLNK: Button / hyperlink to international phone call for technical contact and hotline information page -->
     <string name="information_contact_button_international_phone">"+49 30 498 75401"</string>
+    <!-- XLNK: Button / hyperlink to international phone call for technical contact and hotline TAN info page -->
+    <string name="submission_contact_button_international_phone">"+49 30 498 75402"</string>
     <!-- XLNK: Description for national technical contact and hotline information page -->
     <string name="information_contact_button_phone_description">"For calls from within Germany. The call is free of charge."</string>
     <!-- XLNK: Description for international technical contact and hotline information page -->
@@ -1134,19 +1137,19 @@
     <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN  -->
     <string name="submission_dispatcher_needs_testing_subheadline">"Have you been tested?"</string>
     <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN  -->
-    <string name="submission_dispatcher_already_positive_subheadline">"Did you test positive for coronavirus?"</string>
+    <string name="submission_dispatcher_already_positive_subheadline">"Was your PCR test positive?"</string>
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"Test with QR Code"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
     <string name="submission_dispatcher_qr_card_text">"Register your test by scanning the QR code of your test document."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
-    <string name="submission_dispatcher_card_tan_code">"Enter TAN"</string>
+    <string name="submission_dispatcher_card_tan_code">"Enter TAN for PCR Test"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
-    <string name="submission_dispatcher_tan_code_card_text">"Do you have a TAN? Tap here to enter your TAN so you can warn others. "</string>
+    <string name="submission_dispatcher_tan_code_card_text">"Do you have a TAN for your PCR test? Tap here to enter your TAN so you can warn others."</string>
     <!-- YTXT: Dispatcher text for TELE-TAN option -->
-    <string name="submission_dispatcher_card_tan_tele">"No TAN yet?"</string>
+    <string name="submission_dispatcher_card_tan_tele">"Request TAN for PCR Test?"</string>
     <!-- YTXT: Body text for TELE_TAN dispatcher option -->
-    <string name="submission_dispatcher_tan_tele_card_text">"Call us and get a TAN."</string>
+    <string name="submission_dispatcher_tan_tele_card_text">"Call us and get a TAN for your PCR test."</string>
     <!-- XACT: Dispatcher Tan page title -->
     <string name="submission_dispatcher_accessibility_title">"What information do you have?"</string>
 
@@ -1204,10 +1207,15 @@
     <string name="submission_done_body">"Thanks to your support, other people can now be warned and respond appropriately."</string>
     <!-- XHED: Page subtitle for completed submission page -->
     <string name="submission_done_subtitle">"Please note:"</string>
+    <!-- YTXT: text after submission: pcr validation -->
+    <string name="submission_done_pcr_validation">"Take a PCR test to verify this test result."</string>
+    <!-- YTXT: text after submission: pcr validation -->
+    <string name="submission_done_share_keys">"Share your random IDs so that others can be warned."</string>
     <!-- YTXT: text after submission: contagious -->
     <string name="submission_done_contagious">"The public health authority will contact you within the next few days."</string>
     <!-- YTXT: text after submission: isolate -->
     <string name="submission_done_isolate">"You are infectious. Isolate yourself from other people."</string>
+
     <!-- XHED: Title for further info -->
     <string name="submission_done_further_info_title">"Other information:"</string>
     <!-- YTXT: submission done further info bullet points -->
@@ -1268,7 +1276,7 @@
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
-    <string name="submission_contact_title">"Request TAN"</string>
+    <string name="submission_contact_title">"Request TAN for PCR Test"</string>
     <!-- XHED: Page headline for contact page in submission flow -->
     <string name="submission_contact_headline">"How this works:"</string>
     <!-- YTXT: Body text for contact page in submission flow-->
@@ -1284,7 +1292,7 @@
     <!-- XLNK: Technical number which is called when the user clicks on the display number -->
     <string name="submission_contact_number_dial">"0800 7540002"</string>
     <!-- YTXT: Body text for step 2 of contact page-->
-    <string name="submission_contact_step_2_body">"Register your test by entering the TAN in the app."</string>
+    <string name="submission_contact_step_2_body">"Register your PCR test by entering the TAN in the app."</string>
     <!-- YTXT: Body text for operating hours in contact page-->
     <string name="submission_contact_operating_hours_body">"Our customer service is available in the following languages: \nEnglish, German, Turkish\n\nBusiness hours:\n24/7"</string>
     <!-- YTXT: Body text for technical contact and hotline information page -->
@@ -1369,23 +1377,6 @@
     <!-- YTXT: text for share result card-->
     <string name="submission_status_card_positive_result_share">"Share your random IDs so that others can be warned."</string>
 
-
-    <!-- XBUT: submission deletion warning button continue -->
-    <string name="submission_deletion_warning_continue_button">"Next"</string>
-    <!-- XBUT: submission deletion warning button cancel -->
-    <string name="submission_deletion_warning_cancel_button">"Cancel"</string>
-    <!-- XHED: submission deletion warning title -->
-    <string name="submission_deletion_warning_title">"Note"</string>
-    <!-- YTXT: Headline for rapid test submission deletion warning -->
-    <string name="submission_deletion_warning_headline_antigen_test">"You have already registered a rapid test."</string>
-    <!-- YTXT: Body for rapid test submission deletion warning -->
-    <string name="submission_deletion_warning_body_antigen_test">"You have already registered a rapid test. The app can manage a maximum of one rapid test and one PCR test at the same time. If you register another rapid test, the first rapid test will be deleted from the app."</string>
-    <!-- YTXT: Headline for PCR test submission deletion warning -->
-    <string name="submission_deletion_warning_headline_pcr_test">"You have already registered a PCR test."</string>
-    <!-- YTXT: Body for PCR test submission deletion warning -->
-    <string name="submission_deletion_warning_body_pcr_test">"You have already registered a PCR test. The app can manage a maximum of one rapid test and one PCR test at the same time. If you register another PCR test, the first PCR test will be deleted from the app."</string>
-
-
     <!-- Reenable risk card -->
     <!-- XHED: Card title for re-enable risk card -->
     <string name="reenable_risk_card_title">"Exposure Check Ended"</string>
@@ -1405,11 +1396,11 @@
     <string name="dialog_reactivate_risk_calculation_button_negative">"Cancel"</string>
 
     <!-- Test Result Card -->
-    <string name="test_result_card_headline">"Your diagnosis:"</string>
+    <string name="test_result_card_headline">"Your %s diagnosis:"</string>
     <!-- YTXT: virus name text -->
     <string name="test_result_card_virus_name_text">"SARS-CoV-2"</string>
     <!-- YTXT: registered at text -->
-    <string name="test_result_card_registered_at_text">"Registered on %s"</string>
+    <string name="test_result_card_registered_at_text">"Test added on %s"</string>
     <!-- YTXT: negative status text -->
     <string name="test_result_card_status_negative">"Negative"</string>
     <!-- YTXT: positive status text -->
@@ -1994,7 +1985,7 @@
     <!-- XHED: Trace location poster title -->
     <string name="trace_location_organiser_poster_title">"Print Version"</string>
     <!-- XHED: Trace location check-ins consent screen title -->
-    <string name="trace_location_attendee_consent_title">"Share Your Location Check-Ins?"</string>
+    <string name="trace_location_attendee_consent_title">"Share Location Check-Ins?"</string>
     <!-- XTXT: Trace location check-ins consent screen header description -->
     <string name="trace_location_attendee_consent_header_description">"Warn others who checked in near you. Your personal data will not be shared."</string>
     <!-- XBUT: Trace location check-ins consent screen header button -->
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 33bb35d74f8e4379cff533931ed2198ea27bd4ff..5787cb0fbd4b8e97f54944aed4ce0a45f24288bd 100644
--- a/Corona-Warn-App/src/main/res/values-pl/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/strings.xml
@@ -249,7 +249,7 @@
     <!-- XACT: main (overview) - illustraction description, explanation image -->
     <string name="main_overview_illustration_description">"Smartfon wyświetla różne treści oznaczone numerami od 1 do 3."</string>
     <!-- XACT: App main page title -->
-    <string name="main_title">"Strona główna Corona-Warn-App"</string>
+    <string name="main_title">"Ekran główny Corona-Warn-App"</string>
 
     <!-- ####################################
                Risk Details
@@ -787,7 +787,10 @@
     <string name="information_contact_subtitle_phone">"Infolinia techniczna:"</string>
     <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page -->
     <string name="information_contact_button_phone">"0800 7540001"</string>
+    <!-- XLNK: Button / hyperlink to international phone call for technical contact and hotline information page -->
     <string name="information_contact_button_international_phone">"+49 30 498 75401"</string>
+    <!-- XLNK: Button / hyperlink to international phone call for technical contact and hotline TAN info page -->
+    <string name="submission_contact_button_international_phone">"+49 30 498 75402"</string>
     <!-- XLNK: Description for national technical contact and hotline information page -->
     <string name="information_contact_button_phone_description">"Dla połączeń z terytorium Niemiec. Połączenie jest bezpłatne."</string>
     <!-- XLNK: Description for international technical contact and hotline information page -->
@@ -1134,19 +1137,19 @@
     <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN  -->
     <string name="submission_dispatcher_needs_testing_subheadline">"Czy wykonano Ci test?"</string>
     <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN  -->
-    <string name="submission_dispatcher_already_positive_subheadline">"Czy Twój wynik testu na obecność koronawirusa był pozytywny?"</string>
+    <string name="submission_dispatcher_already_positive_subheadline">"Czy wynik Twojego testu PCR był pozytywny?"</string>
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"Test z kodem QR"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
     <string name="submission_dispatcher_qr_card_text">"Zarejestruj test poprzez zeskanowanie kodu QR dokumentu testu."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
-    <string name="submission_dispatcher_card_tan_code">"Wpisz TAN"</string>
+    <string name="submission_dispatcher_card_tan_code">"Wpisz TAN do testu PCR"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
-    <string name="submission_dispatcher_tan_code_card_text">"Czy masz numer TAN? Naciśnij tutaj, aby go wprowadzić i dzięki temu ostrzegać innych."</string>
+    <string name="submission_dispatcher_tan_code_card_text">"Czy masz numer TAN do swojego testu PCR? Naciśnij tutaj, aby go wprowadzić i dzięki temu ostrzegać innych."</string>
     <!-- YTXT: Dispatcher text for TELE-TAN option -->
-    <string name="submission_dispatcher_card_tan_tele">"Nie masz jeszcze numeru TAN?"</string>
+    <string name="submission_dispatcher_card_tan_tele">"PoproÅ› o TAN do testu PCR"</string>
     <!-- YTXT: Body text for TELE_TAN dispatcher option -->
-    <string name="submission_dispatcher_tan_tele_card_text">"Zadzwoń i odbierz numer TAN."</string>
+    <string name="submission_dispatcher_tan_tele_card_text">"Zadzwoń i odbierz numer TAN do testu PCR."</string>
     <!-- XACT: Dispatcher Tan page title -->
     <string name="submission_dispatcher_accessibility_title">"Jakie informacje posiadasz?"</string>
 
@@ -1204,10 +1207,15 @@
     <string name="submission_done_body">"Twoje wsparcie pozwala na ostrzeganie innych osób i daje im możliwość odpowiedniego zareagowania."</string>
     <!-- XHED: Page subtitle for completed submission page -->
     <string name="submission_done_subtitle">"Uwaga:"</string>
+    <!-- YTXT: text after submission: pcr validation -->
+    <string name="submission_done_pcr_validation">"Wykonaj test PCR, aby zweryfikować wynik tego testu."</string>
+    <!-- YTXT: text after submission: pcr validation -->
+    <string name="submission_done_share_keys">"Udostępnij swoje losowe identyfikatory, aby umożliwić ostrzeganie innych osób."</string>
     <!-- YTXT: text after submission: contagious -->
     <string name="submission_done_contagious">"Organ ds. zdrowia publicznego skontaktuje się z Tobą w ciągu kilku najbliższych dni."</string>
     <!-- YTXT: text after submission: isolate -->
     <string name="submission_done_isolate">"Możesz zarażać. Izoluj się od innych osób."</string>
+
     <!-- XHED: Title for further info -->
     <string name="submission_done_further_info_title">"Inne informacje:"</string>
     <!-- YTXT: submission done further info bullet points -->
@@ -1268,7 +1276,7 @@
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
-    <string name="submission_contact_title">"PoproÅ› o TAN"</string>
+    <string name="submission_contact_title">"PoproÅ› o TAN do testu PCR"</string>
     <!-- XHED: Page headline for contact page in submission flow -->
     <string name="submission_contact_headline">"Jak to działa:"</string>
     <!-- YTXT: Body text for contact page in submission flow-->
@@ -1284,7 +1292,7 @@
     <!-- XLNK: Technical number which is called when the user clicks on the display number -->
     <string name="submission_contact_number_dial">"0800 7540002"</string>
     <!-- YTXT: Body text for step 2 of contact page-->
-    <string name="submission_contact_step_2_body">"Zarejestruj swój test poprzez wpisanie numeru TAN w aplikacji."</string>
+    <string name="submission_contact_step_2_body">"Zarejestruj swój test PCR poprzez wpisanie numeru TAN w aplikacji."</string>
     <!-- YTXT: Body text for operating hours in contact page-->
     <string name="submission_contact_operating_hours_body">"Zapewniamy obsługę klienta w następujących językach: \nangielskim, niemieckim, tureckim\n\nGodziny pracy:\n24/7"</string>
     <!-- YTXT: Body text for technical contact and hotline information page -->
@@ -1369,23 +1377,6 @@
     <!-- YTXT: text for share result card-->
     <string name="submission_status_card_positive_result_share">"Udostępnij swoje losowe identyfikatory, aby umożliwić ostrzeganie innych osób."</string>
 
-
-    <!-- XBUT: submission deletion warning button continue -->
-    <string name="submission_deletion_warning_continue_button">"Dalej"</string>
-    <!-- XBUT: submission deletion warning button cancel -->
-    <string name="submission_deletion_warning_cancel_button">"Anuluj"</string>
-    <!-- XHED: submission deletion warning title -->
-    <string name="submission_deletion_warning_title">"Uwaga"</string>
-    <!-- YTXT: Headline for rapid test submission deletion warning -->
-    <string name="submission_deletion_warning_headline_antigen_test">"Zarejestrowano już szybki test."</string>
-    <!-- YTXT: Body for rapid test submission deletion warning -->
-    <string name="submission_deletion_warning_body_antigen_test">"Zarejestrowano już szybki test. Aplikacja może zarządzać maksymalnie jednym szybkim testem i jednym testem PCR jednocześnie. Jeśli zarejestrujesz kolejny szybki test, pierwszy szybki test zostanie usunięty z aplikacji."</string>
-    <!-- YTXT: Headline for PCR test submission deletion warning -->
-    <string name="submission_deletion_warning_headline_pcr_test">"Zarejestrowano już test PCR."</string>
-    <!-- YTXT: Body for PCR test submission deletion warning -->
-    <string name="submission_deletion_warning_body_pcr_test">"Zarejestrowano już test PCR. Aplikacja może zarządzać maksymalnie jednym szybkim testem i jednym testem PCR jednocześnie. Jeśli zarejestrujesz kolejny test PCR, pierwszy test PCR zostanie usunięty z aplikacji."</string>
-
-
     <!-- Reenable risk card -->
     <!-- XHED: Card title for re-enable risk card -->
     <string name="reenable_risk_card_title">"Zakończono sprawdzanie narażeń"</string>
@@ -1405,11 +1396,11 @@
     <string name="dialog_reactivate_risk_calculation_button_negative">"Anuluj"</string>
 
     <!-- Test Result Card -->
-    <string name="test_result_card_headline">"Twoja diagnoza:"</string>
+    <string name="test_result_card_headline">"Twoja %s diagnoza:"</string>
     <!-- YTXT: virus name text -->
     <string name="test_result_card_virus_name_text">"SARS-CoV-2"</string>
     <!-- YTXT: registered at text -->
-    <string name="test_result_card_registered_at_text">"Zarejestrowano dnia %s"</string>
+    <string name="test_result_card_registered_at_text">"Test dodany dnia %s"</string>
     <!-- YTXT: negative status text -->
     <string name="test_result_card_status_negative">"Brak zakażenia"</string>
     <!-- YTXT: positive status text -->
@@ -1994,7 +1985,7 @@
     <!-- XHED: Trace location poster title -->
     <string name="trace_location_organiser_poster_title">"Wersja do druku"</string>
     <!-- XHED: Trace location check-ins consent screen title -->
-    <string name="trace_location_attendee_consent_title">"Udostępnić Twoje zameldowania w lokalizacji?"</string>
+    <string name="trace_location_attendee_consent_title">"Udostępnić zameldowania w lokalizacji?"</string>
     <!-- XTXT: Trace location check-ins consent screen header description -->
     <string name="trace_location_attendee_consent_header_description">"Ostrzegaj inne osoby, które się zameldowały w pobliżu. Twoje dane osobowe nie będą udostępniane."</string>
     <!-- XBUT: Trace location check-ins consent screen header button -->
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 1c8fc8c719b2ad4abac5c58e7b866f5b96f46896..3e92702f112ff5ae91283f499a070d7d5b7eeeb6 100644
--- a/Corona-Warn-App/src/main/res/values-ro/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/strings.xml
@@ -249,7 +249,7 @@
     <!-- XACT: main (overview) - illustraction description, explanation image -->
     <string name="main_overview_illustration_description">"Un smartphone afișează conținut variat, numerotat de la 1 la 3."</string>
     <!-- XACT: App main page title -->
-    <string name="main_title">"Pagina principală a aplicației Corona-Warn"</string>
+    <string name="main_title">"Ecranul principal al aplicației Corona-Warn"</string>
 
     <!-- ####################################
                Risk Details
@@ -294,7 +294,7 @@
     <!-- XMSG: risk details - panel doctor on-call service, bullet point -->
     <string name="risk_details_behavior_increased_body_2">"Serviciul general de urgență la numărul de telefon 116117"</string>
     <!-- XMSG: risk details - public health department, bullet point -->
-    <string name="risk_details_behavior_increased_body_3">"Direcția de sănătate publică relevantă"</string>
+    <string name="risk_details_behavior_increased_body_3">"Autoritatea de sănătate publică relevantă"</string>
     <!-- XHED: risk details - infection risk headline, below behaviors -->
     <string name="risk_details_headline_infection_risk">"Risc de infectare"</string>
     <!-- XHED: risk details - infection period logged headling, below behaviors -->
@@ -787,7 +787,10 @@
     <string name="information_contact_subtitle_phone">"Hotline tehnic:"</string>
     <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page -->
     <string name="information_contact_button_phone">"0800 7540001"</string>
+    <!-- XLNK: Button / hyperlink to international phone call for technical contact and hotline information page -->
     <string name="information_contact_button_international_phone">"+49 30 498 75401"</string>
+    <!-- XLNK: Button / hyperlink to international phone call for technical contact and hotline TAN info page -->
+    <string name="submission_contact_button_international_phone">"+49 30 498 75402"</string>
     <!-- XLNK: Description for national technical contact and hotline information page -->
     <string name="information_contact_button_phone_description">"Pentru apeluri din Germania. Apelul este gratuit."</string>
     <!-- XLNK: Description for international technical contact and hotline information page -->
@@ -995,7 +998,7 @@
     <!-- XHED: Dialog headline for invalid QR code  -->
     <string name="submission_qr_code_scan_invalid_dialog_headline">"Codul QR este nevalabil"</string>
     <!-- YTXT: Dialog Body text for invalid QR code -->
-    <string name="submission_qr_code_scan_invalid_dialog_body">"Codul QR este nevalabil sau a fost deja înregistrat pe un alt smartphone. Veți primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteți diagnosticat cu coronavirus, direcția de sănătate publică va fi notificată prin canalul de comunicare prevăzut în mod legal și vă va contacta."</string>
+    <string name="submission_qr_code_scan_invalid_dialog_body">"Codul QR este nevalabil sau a fost deja înregistrat pe un alt smartphone. Veți primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteți diagnosticat cu coronavirus, autoritatea de sănătate publică va fi notificată prin canalul de comunicare prevăzut în mod legal și vă va contacta."</string>
     <!-- XBUT: Dialog(Invalid QR code) - positive button (right) -->
     <string name="submission_qr_code_scan_invalid_dialog_button_positive">"Reîncercați."</string>
     <!-- XBUT: Dialog(Invalid QR code) - negative button (left) -->
@@ -1086,7 +1089,7 @@
     <!-- XHED: Dialog title for test removal  -->
     <string name="submission_test_result_dialog_remove_test_title">"Testul poate fi scanat o singură dată."</string>
     <!-- YTXT: Dialog text for test removal -->
-    <string name="submission_test_result_dialog_remove_test_message">"Dacă eliminați testul, nu veți mai putea afla rezultatul testului. Veți primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteți diagnosticat cu coronavirus, direcția de sănătate publică va fi notificată prin canalul de comunicare prevăzut în mod legal și vă va contacta."</string>
+    <string name="submission_test_result_dialog_remove_test_message">"Dacă eliminați testul, nu veți mai putea afla rezultatul testului. Veți primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteți diagnosticat cu coronavirus, autoritatea de sănătate publică va fi notificată prin canalul de comunicare prevăzut în mod legal și vă va contacta."</string>
     <!-- XBUT: Positive button for test removal -->
     <string name="submission_test_result_dialog_remove_test_button_positive">"Eliminare"</string>
     <!-- XBUT: Negative button for test removal -->
@@ -1134,19 +1137,19 @@
     <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN  -->
     <string name="submission_dispatcher_needs_testing_subheadline">"Ați fost testat?"</string>
     <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN  -->
-    <string name="submission_dispatcher_already_positive_subheadline">"Ați fost testat pozitiv la coronavirus?"</string>
+    <string name="submission_dispatcher_already_positive_subheadline">"Testul dvs. PCR a fost pozitiv?"</string>
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"Testarea cu cod QR"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
     <string name="submission_dispatcher_qr_card_text">"Înregistrați-vă testul scanând codul QR al documentului de testare."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
-    <string name="submission_dispatcher_card_tan_code">"Introduceți TAN"</string>
+    <string name="submission_dispatcher_card_tan_code">"Introduceți codul TAN pentru testul PCR"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
-    <string name="submission_dispatcher_tan_code_card_text">"Aveți un cod TAN? Atingeți aici pentru a introduce codul dvs. TAN pentru a-i putea avertiza pe ceilalți."</string>
+    <string name="submission_dispatcher_tan_code_card_text">"Aveți un cod TAN pentru testul dvs. PCR? Atingeți aici pentru a introduce codul dvs. TAN pentru a-i putea avertiza pe ceilalți."</string>
     <!-- YTXT: Dispatcher text for TELE-TAN option -->
-    <string name="submission_dispatcher_card_tan_tele">"Nu aveți un cod TAN încă?"</string>
+    <string name="submission_dispatcher_card_tan_tele">"Solicitați un cod TAN pentru testul PCR?"</string>
     <!-- YTXT: Body text for TELE_TAN dispatcher option -->
-    <string name="submission_dispatcher_tan_tele_card_text">"Sunați-ne și obțineți un cod TAN."</string>
+    <string name="submission_dispatcher_tan_tele_card_text">"Sunați-ne și obțineți un cod TAN pentru testul dvs. PCR."</string>
     <!-- XACT: Dispatcher Tan page title -->
     <string name="submission_dispatcher_accessibility_title">"Ce informații aveți?"</string>
 
@@ -1179,7 +1182,7 @@
     <!-- XTXT: Second bullet point when test result is positive and consent is requested for key sharing-->
     <string name="submission_test_result_positive_no_consent_text_2">"Identitatea dvs. va rămâne secretă. Alți utilizatori nu vor afla cine a partajat rezultatul testului."</string>
     <!-- XTXT: Third bullet point when test result is positive and consent is requested for key sharing-->
-    <string name="submission_test_result_positive_no_consent_text_3">"Asigurați-vă că urmați instrucțiunile direcției dvs. de sănătate publică și că stați acasă, pentru a nu-i infecta pe ceilalți."</string>
+    <string name="submission_test_result_positive_no_consent_text_3">"Asigurați-vă că urmați instrucțiunile autorității dvs. de sănătate publică și că stați acasă, pentru a nu-i infecta pe ceilalți."</string>
     <!-- XBUT: Button for giving consent for key sharing -->
     <string name="submission_test_result_positive_no_consent_button_warn_others">"Avertizați-i pe ceilalți"</string>
 
@@ -1204,10 +1207,15 @@
     <string name="submission_done_body">"Datorită sprijinului dvs., alte persoane pot fi acum avertizate și pot reacționa adecvat."</string>
     <!-- XHED: Page subtitle for completed submission page -->
     <string name="submission_done_subtitle">"Rețineți:"</string>
+    <!-- YTXT: text after submission: pcr validation -->
+    <string name="submission_done_pcr_validation">"Efectuați un test PCR pentru a verifica rezultatul acestui test."</string>
+    <!-- YTXT: text after submission: pcr validation -->
+    <string name="submission_done_share_keys">"Trimiteți ID-ul dvs. aleatoriu pentru a-i avertiza și pe alții."</string>
     <!-- YTXT: text after submission: contagious -->
     <string name="submission_done_contagious">"Autoritatea de sănătate publică vă va contacta în următoarele zile."</string>
     <!-- YTXT: text after submission: isolate -->
     <string name="submission_done_isolate">"Sunteți infectat. Izolați-vă de alte persoane."</string>
+
     <!-- XHED: Title for further info -->
     <string name="submission_done_further_info_title">"Alte informații:"</string>
     <!-- YTXT: submission done further info bullet points -->
@@ -1224,7 +1232,7 @@
 
     <!-- Submission Done No Consent-->
     <!-- XHED: Page title for completed submission page -->
-    <string name="submission_done_no_consent_title">"Vă mulţumim"</string>
+    <string name="submission_done_no_consent_title">"Vă mulțumim"</string>
     <!-- YTXT: Page subtitle for completed submission page -->
     <string name="submission_done_no_consent_subtitle">"Vă mulțumim pentru ajutorul dat la oprirea răspândirii coronavirusului."</string>
     <!-- YTXT: Page body for submission no consent page -->
@@ -1268,7 +1276,7 @@
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
-    <string name="submission_contact_title">"Solicitare TAN"</string>
+    <string name="submission_contact_title">"Solicitare cod TAN pentru testul PCR"</string>
     <!-- XHED: Page headline for contact page in submission flow -->
     <string name="submission_contact_headline">"Cum funcționează:"</string>
     <!-- YTXT: Body text for contact page in submission flow-->
@@ -1284,7 +1292,7 @@
     <!-- XLNK: Technical number which is called when the user clicks on the display number -->
     <string name="submission_contact_number_dial">"0800 7540002"</string>
     <!-- YTXT: Body text for step 2 of contact page-->
-    <string name="submission_contact_step_2_body">"Înregistrați testul dvs. introducând codul TAN în aplicație."</string>
+    <string name="submission_contact_step_2_body">"Înregistrați testul dvs. PCR introducând codul TAN în aplicație."</string>
     <!-- YTXT: Body text for operating hours in contact page-->
     <string name="submission_contact_operating_hours_body">"Serviciul clienți vă stă la dispoziție în următoarele limbi: \nengleză, germană, turcă\n\nProgram de lucru:\n24/7"</string>
     <!-- YTXT: Body text for technical contact and hotline information page -->
@@ -1369,23 +1377,6 @@
     <!-- YTXT: text for share result card-->
     <string name="submission_status_card_positive_result_share">"Trimiteți ID-ul dvs. aleatoriu pentru a-i avertiza și pe alții."</string>
 
-
-    <!-- XBUT: submission deletion warning button continue -->
-    <string name="submission_deletion_warning_continue_button">"ÃŽnainte"</string>
-    <!-- XBUT: submission deletion warning button cancel -->
-    <string name="submission_deletion_warning_cancel_button">"Anulare"</string>
-    <!-- XHED: submission deletion warning title -->
-    <string name="submission_deletion_warning_title">"Notă"</string>
-    <!-- YTXT: Headline for rapid test submission deletion warning -->
-    <string name="submission_deletion_warning_headline_antigen_test">"Ați înregistrat deja un test rapid."</string>
-    <!-- YTXT: Body for rapid test submission deletion warning -->
-    <string name="submission_deletion_warning_body_antigen_test">"Ați înregistrat deja un test rapid. Aplicația poate gestiona cel mult un test rapid și un test PCR în același timp. Dacă înregistrați un alt test rapid, primul test rapid va fi șters din aplicație."</string>
-    <!-- YTXT: Headline for PCR test submission deletion warning -->
-    <string name="submission_deletion_warning_headline_pcr_test">"Ați înregistrat deja un test PCR."</string>
-    <!-- YTXT: Body for PCR test submission deletion warning -->
-    <string name="submission_deletion_warning_body_pcr_test">"Ați înregistrat deja un test PCR. Aplicația poate gestiona cel mult un test rapid și un test PCR în același timp. Dacă înregistrați un alt test PCR, primul test PCR va fi șters din aplicație."</string>
-
-
     <!-- Reenable risk card -->
     <!-- XHED: Card title for re-enable risk card -->
     <string name="reenable_risk_card_title">"Verificarea expunerii s-a încheiat"</string>
@@ -1405,11 +1396,11 @@
     <string name="dialog_reactivate_risk_calculation_button_negative">"Anulare"</string>
 
     <!-- Test Result Card -->
-    <string name="test_result_card_headline">"Diagnosticul dvs.:"</string>
+    <string name="test_result_card_headline">"Diagnosticul dvs. pentru %s:"</string>
     <!-- YTXT: virus name text -->
     <string name="test_result_card_virus_name_text">"SARS-CoV-2"</string>
     <!-- YTXT: registered at text -->
-    <string name="test_result_card_registered_at_text">"ÃŽnregistrat la %s"</string>
+    <string name="test_result_card_registered_at_text">"Test adăugat pe %s"</string>
     <!-- YTXT: negative status text -->
     <string name="test_result_card_status_negative">"Negativ"</string>
     <!-- YTXT: positive status text -->
@@ -1994,7 +1985,7 @@
     <!-- XHED: Trace location poster title -->
     <string name="trace_location_organiser_poster_title">"Versiune de tipărire"</string>
     <!-- XHED: Trace location check-ins consent screen title -->
-    <string name="trace_location_attendee_consent_title">"Partajați check-inurile locației dvs.?"</string>
+    <string name="trace_location_attendee_consent_title">"Partajați check-inurile locației?"</string>
     <!-- XTXT: Trace location check-ins consent screen header description -->
     <string name="trace_location_attendee_consent_header_description">"Avertizați-i pe ceilalți care au făcut check-in în aproprierea dvs. Datele dvs. personale nu vor fi partajate."</string>
     <!-- XBUT: Trace location check-ins consent screen header button -->
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 c2a1fffe58eb094b9cff16fbb4d14e1a0ee74119..f283c8543139f0c1598b4c385fb32069a98ce4be 100644
--- a/Corona-Warn-App/src/main/res/values-tr/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/strings.xml
@@ -249,7 +249,7 @@
     <!-- XACT: main (overview) - illustraction description, explanation image -->
     <string name="main_overview_illustration_description">"Bir akıllı telefon, 1 ila 3 olarak numaralandırılmış farklı içerikleri gösterir."</string>
     <!-- XACT: App main page title -->
-    <string name="main_title">"Corona-Warn-App Ana sayfası"</string>
+    <string name="main_title">"Corona-Warn-App Ana ekranı"</string>
 
     <!-- ####################################
                Risk Details
@@ -787,7 +787,10 @@
     <string name="information_contact_subtitle_phone">"Teknik yardım hattı:"</string>
     <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page -->
     <string name="information_contact_button_phone">"0800 7540001"</string>
+    <!-- XLNK: Button / hyperlink to international phone call for technical contact and hotline information page -->
     <string name="information_contact_button_international_phone">"+49 30 498 75401"</string>
+    <!-- XLNK: Button / hyperlink to international phone call for technical contact and hotline TAN info page -->
+    <string name="submission_contact_button_international_phone">"+49 30 498 75402"</string>
     <!-- XLNK: Description for national technical contact and hotline information page -->
     <string name="information_contact_button_phone_description">"Almanya’dan yapılan aramalar içindir. Arama ücretsizdir."</string>
     <!-- XLNK: Description for international technical contact and hotline information page -->
@@ -1134,19 +1137,19 @@
     <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN  -->
     <string name="submission_dispatcher_needs_testing_subheadline">"Test yaptırdınız mı?"</string>
     <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN  -->
-    <string name="submission_dispatcher_already_positive_subheadline">"Koronavirüs testinizin sonucu pozitif mi?"</string>
+    <string name="submission_dispatcher_already_positive_subheadline">"PCR testinizin sonucu pozitif miydi?"</string>
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"QR Kodlu Test"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
     <string name="submission_dispatcher_qr_card_text">"Test belgenizin QR kodunu tarayarak testinizi kaydedin."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
-    <string name="submission_dispatcher_card_tan_code">"TAN gir"</string>
+    <string name="submission_dispatcher_card_tan_code">"PCR Testi için TAN girin"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
-    <string name="submission_dispatcher_tan_code_card_text">"TAN\'niz var mı? Diğer kullanıcıları uyarabilmek için TAN\'nizi girmek üzere buraya dokunun."</string>
+    <string name="submission_dispatcher_tan_code_card_text">"PCR testiniz için bir TAN\'niz var mı? Diğer kullanıcıları uyarabilmek için TAN\'nizi girmek üzere buraya dokunun."</string>
     <!-- YTXT: Dispatcher text for TELE-TAN option -->
-    <string name="submission_dispatcher_card_tan_tele">"TAN yok mu?"</string>
+    <string name="submission_dispatcher_card_tan_tele">"PCR Testi için TAN talebinde bulunulsun mu?"</string>
     <!-- YTXT: Body text for TELE_TAN dispatcher option -->
-    <string name="submission_dispatcher_tan_tele_card_text">"Bizi arayın ve TAN alın."</string>
+    <string name="submission_dispatcher_tan_tele_card_text">"Bizi arayın ve PCR testiniz için bir TAN alın."</string>
     <!-- XACT: Dispatcher Tan page title -->
     <string name="submission_dispatcher_accessibility_title">"Hangi bilgilere sahipsiniz?"</string>
 
@@ -1204,10 +1207,15 @@
     <string name="submission_done_body">"Desteğiniz sayesinde artık diğer kullanıcılar uyarılabilir ve buna uygun şekilde hareket edebilir."</string>
     <!-- XHED: Page subtitle for completed submission page -->
     <string name="submission_done_subtitle">"Lütfen unutmayın:"</string>
+    <!-- YTXT: text after submission: pcr validation -->
+    <string name="submission_done_pcr_validation">"Bu test sonucunu doğrulamak için PCR testi yapın."</string>
+    <!-- YTXT: text after submission: pcr validation -->
+    <string name="submission_done_share_keys">"Diğer kullanıcıların uyarılabilmesi için rastgele kimliklerinizi paylaşın."</string>
     <!-- YTXT: text after submission: contagious -->
     <string name="submission_done_contagious">"Kamu sağlığı yetkiliniz önümüzdeki birkaç gün içinde size ulaşacaktır."</string>
     <!-- YTXT: text after submission: isolate -->
     <string name="submission_done_isolate">"Bulaşıcı bir hastalık taşıyorsunuz. Kendinizi diğer insanlardan izole edin."</string>
+
     <!-- XHED: Title for further info -->
     <string name="submission_done_further_info_title">"DiÄŸer bilgiler:"</string>
     <!-- YTXT: submission done further info bullet points -->
@@ -1268,7 +1276,7 @@
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
-    <string name="submission_contact_title">"TAN Talebi"</string>
+    <string name="submission_contact_title">"PCR Testi için TAN talebinde bulunun"</string>
     <!-- XHED: Page headline for contact page in submission flow -->
     <string name="submission_contact_headline">"Nasıl çalışır?"</string>
     <!-- YTXT: Body text for contact page in submission flow-->
@@ -1284,7 +1292,7 @@
     <!-- XLNK: Technical number which is called when the user clicks on the display number -->
     <string name="submission_contact_number_dial">"0800 7540002"</string>
     <!-- YTXT: Body text for step 2 of contact page-->
-    <string name="submission_contact_step_2_body">"Uygulamaya TAN girerek testinizi kaydedin."</string>
+    <string name="submission_contact_step_2_body">"Uygulamaya TAN girerek PCR testinizi kaydedin."</string>
     <!-- YTXT: Body text for operating hours in contact page-->
     <string name="submission_contact_operating_hours_body">"Müşteri hizmetlerimiz şu dillerde size yardımcı olmaya hazır:\nİngilizce, Almanca, Türkçe\n\nMesai saatleri:\n7 gün 24 saat"</string>
     <!-- YTXT: Body text for technical contact and hotline information page -->
@@ -1369,23 +1377,6 @@
     <!-- YTXT: text for share result card-->
     <string name="submission_status_card_positive_result_share">"Diğer kullanıcıların uyarılabilmesi için rastgele kimliklerinizi paylaşın."</string>
 
-
-    <!-- XBUT: submission deletion warning button continue -->
-    <string name="submission_deletion_warning_continue_button">"Sonraki"</string>
-    <!-- XBUT: submission deletion warning button cancel -->
-    <string name="submission_deletion_warning_cancel_button">"Ä°ptal Et"</string>
-    <!-- XHED: submission deletion warning title -->
-    <string name="submission_deletion_warning_title">"Not"</string>
-    <!-- YTXT: Headline for rapid test submission deletion warning -->
-    <string name="submission_deletion_warning_headline_antigen_test">"Zaten bir hızlı test kaydı oluşturdunuz."</string>
-    <!-- YTXT: Body for rapid test submission deletion warning -->
-    <string name="submission_deletion_warning_body_antigen_test">"Zaten bir hızlı test kaydı oluşturdunuz. Uygulama tek seferde en fazla bir hızlı testi ve bir PCR testini yönetebilir. Başka bir hızlı test kaydı oluşturursanız ilk hızlı test uygulamadan silinir."</string>
-    <!-- YTXT: Headline for PCR test submission deletion warning -->
-    <string name="submission_deletion_warning_headline_pcr_test">"Zaten bir PCR testi kaydı oluşturdunuz."</string>
-    <!-- YTXT: Body for PCR test submission deletion warning -->
-    <string name="submission_deletion_warning_body_pcr_test">"Zaten bir PCR testi kaydı oluşturdunuz. Uygulama tek seferde en fazla bir hızlı testi ve bir PCR testini yönetebilir. Başka bir PCR testi kaydı oluşturursanız ilk PCR testi uygulamadan silinir."</string>
-
-
     <!-- Reenable risk card -->
     <!-- XHED: Card title for re-enable risk card -->
     <string name="reenable_risk_card_title">"Maruz Kalma Denetimi Sona Erdi"</string>
@@ -1405,11 +1396,11 @@
     <string name="dialog_reactivate_risk_calculation_button_negative">"Ä°ptal"</string>
 
     <!-- Test Result Card -->
-    <string name="test_result_card_headline">"Tanı sonucunuz:"</string>
+    <string name="test_result_card_headline">"%s tanınız:"</string>
     <!-- YTXT: virus name text -->
     <string name="test_result_card_virus_name_text">"SARS-CoV-2"</string>
     <!-- YTXT: registered at text -->
-    <string name="test_result_card_registered_at_text">"Kayıt tarihi: %s"</string>
+    <string name="test_result_card_registered_at_text">"Testin eklenme tarihi: %s"</string>
     <!-- YTXT: negative status text -->
     <string name="test_result_card_status_negative">"Negatif"</string>
     <!-- YTXT: positive status text -->
@@ -1994,7 +1985,7 @@
     <!-- XHED: Trace location poster title -->
     <string name="trace_location_organiser_poster_title">"Yazdırma Sürümü"</string>
     <!-- XHED: Trace location check-ins consent screen title -->
-    <string name="trace_location_attendee_consent_title">"Konum Check-In’leriniz Paylaşılsın Mı?"</string>
+    <string name="trace_location_attendee_consent_title">"Konum Check-In’leri Paylaşılsın Mı?"</string>
     <!-- XTXT: Trace location check-ins consent screen header description -->
     <string name="trace_location_attendee_consent_header_description">"Sizin yakınınızda check in yapmış olan diğer kullanıcıları uyarın. Kişisel verileriniz paylaşılmayacaktır."</string>
     <!-- XBUT: Trace location check-ins consent screen header button -->
diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml
index 81d4778548c5e21205f1cfa64b20dcfedfd802ba..aea8af6971ea6615af6026b250614aab580cae5a 100644
--- a/Corona-Warn-App/src/main/res/values/strings.xml
+++ b/Corona-Warn-App/src/main/res/values/strings.xml
@@ -258,7 +258,7 @@
     <!-- XACT: main (overview) - illustraction description, explanation image -->
     <string name="main_overview_illustration_description">"A smartphone displays various content, numbered 1 to 3."</string>
     <!-- XACT: App main page title -->
-    <string name="main_title">"Main page of the Corona-Warn-App"</string>
+    <string name="main_title">"Main screen of the Corona-Warn-App"</string>
 
     <!-- ####################################
                Risk Details
@@ -1146,19 +1146,19 @@
     <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN  -->
     <string name="submission_dispatcher_needs_testing_subheadline">"Have you been tested?"</string>
     <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN  -->
-    <string name="submission_dispatcher_already_positive_subheadline">"Did you test positive for coronavirus?"</string>
+    <string name="submission_dispatcher_already_positive_subheadline">"Was your PCR test positive?"</string>
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"Test with QR Code"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
     <string name="submission_dispatcher_qr_card_text">"Register your test by scanning the QR code of your test document."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
-    <string name="submission_dispatcher_card_tan_code">"Enter TAN"</string>
+    <string name="submission_dispatcher_card_tan_code">"Enter TAN for PCR Test"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
-    <string name="submission_dispatcher_tan_code_card_text">"Do you have a TAN? Tap here to enter your TAN so you can warn others. "</string>
+    <string name="submission_dispatcher_tan_code_card_text">"Do you have a TAN for your PCR test? Tap here to enter your TAN so you can warn others."</string>
     <!-- YTXT: Dispatcher text for TELE-TAN option -->
-    <string name="submission_dispatcher_card_tan_tele">"No TAN yet?"</string>
+    <string name="submission_dispatcher_card_tan_tele">"Request TAN for PCR Test?"</string>
     <!-- YTXT: Body text for TELE_TAN dispatcher option -->
-    <string name="submission_dispatcher_tan_tele_card_text">"Call us and get a TAN."</string>
+    <string name="submission_dispatcher_tan_tele_card_text">"Call us and get a TAN for your PCR test."</string>
     <!-- XACT: Dispatcher Tan page title -->
     <string name="submission_dispatcher_accessibility_title">"What information do you have?"</string>
 
@@ -1217,13 +1217,14 @@
     <!-- XHED: Page subtitle for completed submission page -->
     <string name="submission_done_subtitle">"Please note:"</string>
     <!-- YTXT: text after submission: pcr validation -->
-    <string name="submission_done_pcr_validation">"Machen Sie einen PCR-Test, um dieses Test-Ergebnis zu verifizieren."</string>
+    <string name="submission_done_pcr_validation">"Take a PCR test to verify this test result."</string>
     <!-- YTXT: text after submission: pcr validation -->
-    <string name="submission_done_share_keys">"Teilen Sie Ihre Zufalls-IDs, damit andere gewarnt werden können."</string>
+    <string name="submission_done_share_keys">"Share your random IDs so that others can be warned."</string>
     <!-- YTXT: text after submission: contagious -->
     <string name="submission_done_contagious">"The public health authority will contact you within the next few days."</string>
     <!-- YTXT: text after submission: isolate -->
     <string name="submission_done_isolate">"You are infectious. Isolate yourself from other people."</string>
+
     <!-- XHED: Title for further info -->
     <string name="submission_done_further_info_title">"Other information:"</string>
     <!-- YTXT: submission done further info bullet points -->
@@ -1284,7 +1285,7 @@
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
-    <string name="submission_contact_title">"Request TAN"</string>
+    <string name="submission_contact_title">"Request TAN for PCR Test"</string>
     <!-- XHED: Page headline for contact page in submission flow -->
     <string name="submission_contact_headline">"How this works:"</string>
     <!-- YTXT: Body text for contact page in submission flow-->
@@ -1300,7 +1301,7 @@
     <!-- XLNK: Technical number which is called when the user clicks on the display number -->
     <string name="submission_contact_number_dial">"0800 7540002"</string>
     <!-- YTXT: Body text for step 2 of contact page-->
-    <string name="submission_contact_step_2_body">"Register your test by entering the TAN in the app."</string>
+    <string name="submission_contact_step_2_body">"Register your PCR test by entering the TAN in the app."</string>
     <!-- YTXT: Body text for operating hours in contact page-->
     <string name="submission_contact_operating_hours_body">"Our customer service is available in the following languages: \nEnglish, German, Turkish\n\nBusiness hours:\n24/7"</string>
     <!-- YTXT: Body text for technical contact and hotline information page -->
@@ -1385,7 +1386,6 @@
     <!-- YTXT: text for share result card-->
     <string name="submission_status_card_positive_result_share">"Share your random IDs so that others can be warned."</string>
 
-
     <!-- Reenable risk card -->
     <!-- XHED: Card title for re-enable risk card -->
     <string name="reenable_risk_card_title">"Exposure Check Ended"</string>
@@ -1405,11 +1405,11 @@
     <string name="dialog_reactivate_risk_calculation_button_negative">"Cancel"</string>
 
     <!-- Test Result Card -->
-    <string name="test_result_card_headline">"Your diagnosis:"</string>
+    <string name="test_result_card_headline">"Your %s diagnosis:"</string>
     <!-- YTXT: virus name text -->
     <string name="test_result_card_virus_name_text">"SARS-CoV-2"</string>
     <!-- YTXT: registered at text -->
-    <string name="test_result_card_registered_at_text">"Registered on %s"</string>
+    <string name="test_result_card_registered_at_text">"Test added on %s"</string>
     <!-- YTXT: negative status text -->
     <string name="test_result_card_status_negative">"Negative"</string>
     <!-- YTXT: positive status text -->
@@ -1994,7 +1994,7 @@
     <!-- XHED: Trace location poster title -->
     <string name="trace_location_organiser_poster_title">"Print Version"</string>
     <!-- XHED: Trace location check-ins consent screen title -->
-    <string name="trace_location_attendee_consent_title">"Share Your Location Check-Ins?"</string>
+    <string name="trace_location_attendee_consent_title">"Share Location Check-Ins?"</string>
     <!-- XTXT: Trace location check-ins consent screen header description -->
     <string name="trace_location_attendee_consent_header_description">"Warn others who checked in near you. Your personal data will not be shared."</string>
     <!-- XBUT: Trace location check-ins consent screen header button -->
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/storage/CoronaTestStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/storage/CoronaTestStorageTest.kt
index 4f026681cd45b9b91c5b1359b3d18228f29ea08f..c3e2537a4207039949ab89142f4933d22d92c01e 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/storage/CoronaTestStorageTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/storage/CoronaTestStorageTest.kt
@@ -50,7 +50,8 @@ class CoronaTestStorageTest : BaseTest() {
         isJournalEntryCreated = false,
         isResultAvailableNotificationSent = false,
         testResult = CoronaTestResult.PCR_POSITIVE,
-        testResultReceivedAt = Instant.ofEpochMilli(2000)
+        testResultReceivedAt = Instant.ofEpochMilli(2000),
+        lastUpdatedAt = Instant.ofEpochMilli(2001),
     )
     private val raTest = RACoronaTest(
         identifier = "identifier-ra",
@@ -66,7 +67,8 @@ class CoronaTestStorageTest : BaseTest() {
         firstName = "firstname",
         lastName = "lastname",
         dateOfBirth = LocalDate.parse("2021-12-24"),
-        testedAt = Instant.ofEpochMilli(3000)
+        testedAt = Instant.ofEpochMilli(3000),
+        lastUpdatedAt = Instant.ofEpochMilli(2001),
     )
 
     @Test
@@ -110,7 +112,8 @@ class CoronaTestStorageTest : BaseTest() {
                     "isJournalEntryCreated": false,
                     "isResultAvailableNotificationSent": false,
                     "testResultReceivedAt": 2000,
-                    "testResult": 2
+                    "testResult": 2,
+                    "lastUpdatedAt": 2001
                 }
             ]
         """.toComparableJsonPretty()
@@ -148,6 +151,7 @@ class CoronaTestStorageTest : BaseTest() {
                     "isJournalEntryCreated": false,
                     "isResultAvailableNotificationSent": false,
                     "testResultReceivedAt": 2000,
+                    "lastUpdatedAt": 2001,
                     "testResult": 7,
                     "testedAt": 3000,
                     "firstName": "firstname",
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt
index 39ee2b0fd03be3ed556a2059de6e0cc706a42e6b..4692cc48ae93f8f0c5ee647c20eb905ded541760 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt
@@ -1,12 +1,75 @@
 package de.rki.coronawarnapp.coronatest.type.pcr
 
+import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
+import de.rki.coronawarnapp.coronatest.type.CoronaTestService
+import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
+import de.rki.coronawarnapp.datadonation.analytics.modules.registeredtest.TestResultDataCollector
+import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler
+import de.rki.coronawarnapp.util.TimeStamper
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.Runs
+import io.mockk.coEvery
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.just
+import kotlinx.coroutines.test.runBlockingTest
+import org.joda.time.Duration
+import org.joda.time.Instant
+import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 
 class PCRProcessorTest : BaseTest() {
+    @MockK lateinit var timeStamper: TimeStamper
+    @MockK lateinit var submissionService: CoronaTestService
+    @MockK lateinit var analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector
+    @MockK lateinit var testResultDataCollector: TestResultDataCollector
+    @MockK lateinit var deadmanNotificationScheduler: DeadmanNotificationScheduler
+
+    private val nowUTC = Instant.parse("2021-03-15T05:45:00.000Z")
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        every { timeStamper.nowUTC } returns nowUTC
+
+        submissionService.apply {
+            coEvery { asyncRequestTestResult(any()) } answers { CoronaTestResult.PCR_OR_RAT_PENDING }
+        }
+
+        testResultDataCollector.apply {
+            coEvery { updatePendingTestResultReceivedTime(any()) } just Runs
+        }
+    }
+
+    fun createInstance() = PCRProcessor(
+        timeStamper = timeStamper,
+        submissionService = submissionService,
+        analyticsKeySubmissionCollector = analyticsKeySubmissionCollector,
+        testResultDataCollector = testResultDataCollector,
+        deadmanNotificationScheduler = deadmanNotificationScheduler,
+    )
 
     @Test
-    fun todo() {
-        // TODO
+    fun `if we receive a pending result 60 days after registration, we map to REDEEMED`() = runBlockingTest {
+        val instance = createInstance()
+
+        val pcrTest = PCRCoronaTest(
+            identifier = "identifier",
+            lastUpdatedAt = Instant.EPOCH,
+            registeredAt = nowUTC,
+            registrationToken = "regtoken",
+            testResult = CoronaTestResult.PCR_POSITIVE
+        )
+
+        instance.pollServer(pcrTest).testResult shouldBe CoronaTestResult.PCR_OR_RAT_PENDING
+
+        val past60DaysTest = pcrTest.copy(
+            registeredAt = nowUTC.minus(Duration.standardDays(21))
+        )
+
+        instance.pollServer(past60DaysTest).testResult shouldBe CoronaTestResult.PCR_REDEEMED
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/execution/PCRResultSchedulerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/execution/PCRResultSchedulerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3034188cc69784f1f70c5bb7a798c4787d960294
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/execution/PCRResultSchedulerTest.kt
@@ -0,0 +1,78 @@
+package de.rki.coronawarnapp.coronatest.type.pcr.execution
+
+import androidx.work.WorkManager
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.mockk
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.TestCoroutineScope
+import kotlinx.coroutines.test.runBlockingTest
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class PCRResultSchedulerTest : BaseTest() {
+
+    @MockK lateinit var workManager: WorkManager
+    @MockK lateinit var coronaTestRepository: CoronaTestRepository
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        every { workManager.enqueueUniquePeriodicWork(any(), any(), any()) } returns mockk()
+    }
+
+    private fun createInstance() = PCRResultScheduler(
+        appScope = TestCoroutineScope(),
+        coronaTestRepository = coronaTestRepository,
+        workManager = workManager
+    )
+
+    @Test
+    fun `final worker doesn't need to be scheduled`() {
+        every { coronaTestRepository.coronaTests } returns flowOf(
+            setOf(
+                mockk<PCRCoronaTest>().apply {
+                    every { isFinal } returns true
+                    every { type } returns CoronaTest.Type.PCR
+                }
+            )
+        )
+
+        runBlockingTest {
+            createInstance().shouldBePolling.first() shouldBe false
+        }
+    }
+
+    @Test
+    fun `not final worker needs to be scheduled`() {
+        every { coronaTestRepository.coronaTests } returns flowOf(
+            setOf(
+                mockk<PCRCoronaTest>().apply {
+                    every { isFinal } returns false
+                    every { type } returns CoronaTest.Type.PCR
+                }
+            )
+        )
+
+        runBlockingTest {
+            createInstance().shouldBePolling.first() shouldBe true
+        }
+    }
+
+    @Test
+    fun `no worker needed without test`() {
+        every { coronaTestRepository.coronaTests } returns flowOf(emptySet())
+
+        runBlockingTest {
+            createInstance().shouldBePolling.first() shouldBe false
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/notification/TestResultAvailableNotificationServiceTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/notification/PCRTestResultAvailableNotificationServiceTest.kt
similarity index 78%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/notification/TestResultAvailableNotificationServiceTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/notification/PCRTestResultAvailableNotificationServiceTest.kt
index e81162622143b53c91be6f9663985f1e6f020f13..0a44ab4c02bb52b9acb64243b3ee42891e9c5318 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/notification/TestResultAvailableNotificationServiceTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/notification/PCRTestResultAvailableNotificationServiceTest.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.notification
+package de.rki.coronawarnapp.coronatest.type.pcr.notification
 
 import android.app.NotificationManager
 import android.app.PendingIntent
@@ -6,8 +6,10 @@ import android.content.Context
 import androidx.navigation.NavDeepLinkBuilder
 import de.rki.coronawarnapp.CoronaWarnApplication
 import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.main.CWASettings
+import de.rki.coronawarnapp.notification.GeneralNotifications
 import de.rki.coronawarnapp.util.device.ForegroundState
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
@@ -19,14 +21,16 @@ import io.mockk.mockk
 import io.mockk.mockkObject
 import io.mockk.verify
 import io.mockk.verifyOrder
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.test.TestCoroutineScope
 import kotlinx.coroutines.test.runBlockingTest
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 import javax.inject.Provider
 
-class TestResultAvailableNotificationServiceTest : BaseTest() {
+class PCRTestResultAvailableNotificationServiceTest : BaseTest() {
 
     @MockK(relaxed = true) lateinit var context: Context
     @MockK lateinit var foregroundState: ForegroundState
@@ -36,6 +40,7 @@ class TestResultAvailableNotificationServiceTest : BaseTest() {
     @MockK lateinit var notificationManager: NotificationManager
     @MockK lateinit var notificationHelper: GeneralNotifications
     @MockK lateinit var cwaSettings: CWASettings
+    @MockK lateinit var coronaTestRepository: CoronaTestRepository
 
     @BeforeEach
     fun setUp() {
@@ -52,19 +57,21 @@ class TestResultAvailableNotificationServiceTest : BaseTest() {
         every { notificationHelper.newBaseBuilder() } returns mockk(relaxed = true)
     }
 
-    fun createInstance() = PCRTestResultAvailableNotificationService(
+    fun createInstance(scope: CoroutineScope = TestCoroutineScope()) = PCRTestResultAvailableNotificationService(
         context = context,
         foregroundState = foregroundState,
         navDeepLinkBuilderProvider = navDeepLinkBuilderProvider,
         notificationHelper = notificationHelper,
-        cwaSettings = cwaSettings
+        cwaSettings = cwaSettings,
+        coronaTestRepository = coronaTestRepository,
+        appScope = scope,
     )
 
     @Test
     fun `test notification in foreground`() = runBlockingTest {
         coEvery { foregroundState.isInForeground } returns flow { emit(true) }
 
-        createInstance().showTestResultAvailableNotification(CoronaTestResult.PCR_POSITIVE)
+        createInstance().showTestResultAvailableNotification(mockk())
 
         verify(exactly = 0) { navDeepLinkBuilderProvider.get() }
     }
@@ -80,8 +87,10 @@ class TestResultAvailableNotificationServiceTest : BaseTest() {
         } just Runs
 
         val instance = createInstance()
-
-        instance.showTestResultAvailableNotification(CoronaTestResult.PCR_POSITIVE)
+        val coronaTest = mockk<CoronaTest>().apply {
+            every { type } returns CoronaTest.Type.PCR
+        }
+        instance.showTestResultAvailableNotification(coronaTest)
 
         verifyOrder {
             navDeepLinkBuilderProvider.get()
@@ -100,7 +109,7 @@ class TestResultAvailableNotificationServiceTest : BaseTest() {
         every { cwaSettings.isNotificationsTestEnabled.value } returns false
 
         createInstance().apply {
-            showTestResultAvailableNotification(CoronaTestResult.PCR_POSITIVE)
+            showTestResultAvailableNotification(mockk())
 
             verify(exactly = 0) {
                 notificationHelper.sendNotification(
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensionsTest.kt
index ed1be6eb11aa6fa1b747bb51267f0a19f80c3a67..3998d73348ed29e81a1ed8c900b39d10529c7ea2 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensionsTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensionsTest.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.coronatest.type.rapidantigen
 
 import de.rki.coronawarnapp.appconfig.CoronaTestConfig
+import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
 import de.rki.coronawarnapp.util.TimeStamper
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
@@ -29,4 +30,23 @@ class RapidAntigenCoronaTestExtensionsTest : BaseTest() {
         val test: RACoronaTest? = null
         test.toSubmissionState(timeStamper.nowUTC, coronaTestConfig) shouldBe SubmissionStateRAT.NoTest
     }
+
+    @Test
+    fun `submission done mapping`() = runBlockingTest {
+        val test = RACoronaTest(
+            identifier = "identifier",
+            registeredAt = Instant.ofEpochMilli(123),
+            registrationToken = "regtoken",
+            testResult = CoronaTestResult.RAT_POSITIVE,
+            testedAt = Instant.EPOCH,
+            isSubmitted = true, // <---
+            dateOfBirth = null,
+            firstName = null,
+            lastName = null,
+            lastUpdatedAt = Instant.EPOCH,
+        )
+        test.toSubmissionState(timeStamper.nowUTC, coronaTestConfig) shouldBe SubmissionStateRAT.SubmissionDone(
+            testRegisteredAt = Instant.ofEpochMilli(123)
+        )
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessorTest.kt
index 2396194a96a5bc2fe009c291304880aad27afc56..b2b3693be4be5f6d4bca10a5c0ed201df0116d87 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessorTest.kt
@@ -1,12 +1,62 @@
 package de.rki.coronawarnapp.coronatest.type.rapidantigen
 
+import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
+import de.rki.coronawarnapp.coronatest.type.CoronaTestService
+import de.rki.coronawarnapp.util.TimeStamper
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.coEvery
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import kotlinx.coroutines.test.runBlockingTest
+import org.joda.time.Duration
+import org.joda.time.Instant
+import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 
 class RapidAntigenProcessorTest : BaseTest() {
 
+    @MockK lateinit var timeStamper: TimeStamper
+    @MockK lateinit var submissionService: CoronaTestService
+
+    private val nowUTC = Instant.parse("2021-03-15T05:45:00.000Z")
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        every { timeStamper.nowUTC } returns nowUTC
+
+        submissionService.apply {
+            coEvery { asyncRequestTestResult(any()) } answers { CoronaTestResult.PCR_OR_RAT_PENDING }
+        }
+    }
+
+    fun createInstance() = RapidAntigenProcessor(
+        timeStamper = timeStamper,
+        submissionService = submissionService,
+    )
+
     @Test
-    fun todo() {
-        // TODO
+    fun `if we receive a pending result 60 days after registration, we map to REDEEMED`() = runBlockingTest {
+        val instance = createInstance()
+
+        val pcrTest = RACoronaTest(
+            identifier = "identifier",
+            lastUpdatedAt = Instant.EPOCH,
+            registeredAt = nowUTC,
+            registrationToken = "regtoken",
+            testResult = CoronaTestResult.RAT_POSITIVE,
+            testedAt = Instant.EPOCH,
+        )
+
+        instance.pollServer(pcrTest).testResult shouldBe CoronaTestResult.PCR_OR_RAT_PENDING
+
+        val past60DaysTest = pcrTest.copy(
+            registeredAt = nowUTC.minus(Duration.standardDays(21))
+        )
+
+        instance.pollServer(past60DaysTest).testResult shouldBe CoronaTestResult.RAT_REDEEMED
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/notification/RATestResultAvailableNotificationServiceTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/notification/RATestResultAvailableNotificationServiceTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3878e2e2efba25125d19e543823fdcbf2f79f177
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/notification/RATestResultAvailableNotificationServiceTest.kt
@@ -0,0 +1,122 @@
+package de.rki.coronawarnapp.coronatest.type.rapidantigen.notification
+
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.Context
+import androidx.navigation.NavDeepLinkBuilder
+import de.rki.coronawarnapp.CoronaWarnApplication
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.main.CWASettings
+import de.rki.coronawarnapp.notification.GeneralNotifications
+import de.rki.coronawarnapp.util.device.ForegroundState
+import io.mockk.MockKAnnotations
+import io.mockk.Runs
+import io.mockk.coEvery
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.mockkObject
+import io.mockk.verify
+import io.mockk.verifyOrder
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.test.TestCoroutineScope
+import kotlinx.coroutines.test.runBlockingTest
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import javax.inject.Provider
+
+class RATestResultAvailableNotificationServiceTest : BaseTest() {
+
+    @MockK(relaxed = true) lateinit var context: Context
+    @MockK lateinit var foregroundState: ForegroundState
+    @MockK(relaxed = true) lateinit var navDeepLinkBuilder: NavDeepLinkBuilder
+    @MockK lateinit var pendingIntent: PendingIntent
+    @MockK lateinit var navDeepLinkBuilderProvider: Provider<NavDeepLinkBuilder>
+    @MockK lateinit var notificationManager: NotificationManager
+    @MockK lateinit var notificationHelper: GeneralNotifications
+    @MockK lateinit var cwaSettings: CWASettings
+    @MockK lateinit var coronaTestRepository: CoronaTestRepository
+
+    @BeforeEach
+    fun setUp() {
+        MockKAnnotations.init(this)
+
+        mockkObject(CoronaWarnApplication)
+
+        every { CoronaWarnApplication.getAppContext() } returns context
+        every { context.getSystemService(Context.NOTIFICATION_SERVICE) } returns notificationManager
+        every { navDeepLinkBuilderProvider.get() } returns navDeepLinkBuilder
+        every { navDeepLinkBuilder.createPendingIntent() } returns pendingIntent
+        every { cwaSettings.isNotificationsTestEnabled.value } returns true
+
+        every { notificationHelper.newBaseBuilder() } returns mockk(relaxed = true)
+    }
+
+    fun createInstance(scope: CoroutineScope = TestCoroutineScope()) = RATTestResultAvailableNotificationService(
+        context = context,
+        foregroundState = foregroundState,
+        navDeepLinkBuilderProvider = navDeepLinkBuilderProvider,
+        notificationHelper = notificationHelper,
+        cwaSettings = cwaSettings,
+        coronaTestRepository = coronaTestRepository,
+        appScope = scope,
+    )
+
+    @Test
+    fun `test notification in foreground`() = runBlockingTest {
+        coEvery { foregroundState.isInForeground } returns flow { emit(true) }
+
+        createInstance().showTestResultAvailableNotification(mockk())
+
+        verify(exactly = 0) { navDeepLinkBuilderProvider.get() }
+    }
+
+    @Test
+    fun `test notification in background`() = runBlockingTest {
+        coEvery { foregroundState.isInForeground } returns flow { emit(false) }
+        every {
+            notificationHelper.sendNotification(
+                notificationId = any(),
+                notification = any()
+            )
+        } just Runs
+
+        val instance = createInstance()
+        val coronaTest = mockk<CoronaTest>().apply {
+            every { type } returns CoronaTest.Type.RAPID_ANTIGEN
+        }
+        instance.showTestResultAvailableNotification(coronaTest)
+
+        verifyOrder {
+            navDeepLinkBuilderProvider.get()
+            context.getString(R.string.notification_headline_test_result_ready)
+            context.getString(R.string.notification_body_test_result_ready)
+            notificationHelper.sendNotification(
+                notificationId = any(),
+                notification = any()
+            )
+        }
+    }
+
+    @Test
+    fun `test notification in background disabled`() = runBlockingTest {
+        coEvery { foregroundState.isInForeground } returns flow { emit(false) }
+        every { cwaSettings.isNotificationsTestEnabled.value } returns false
+
+        createInstance().apply {
+            showTestResultAvailableNotification(mockk())
+
+            verify(exactly = 0) {
+                notificationHelper.sendNotification(
+                    notificationId = any(),
+                    notification = any()
+                )
+            }
+        }
+    }
+}
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 6cc0f482d8e03e279efd2d5565a51fc560f6477f..c15f04bc3558c7a31b690546682a03395f81a435 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
@@ -71,7 +71,7 @@ class AnalyticsTest : BaseTest() {
 
         val twoDaysAgo = baseTime.minus(Days.TWO.toStandardDuration())
         every { settings.lastSubmittedTimestamp } returns mockFlowPreference(twoDaysAgo)
-        every { onboardingSettings.onboardingCompletedTimestamp } returns twoDaysAgo
+        every { onboardingSettings.onboardingCompletedTimestamp } returns mockFlowPreference(twoDaysAgo)
 
         every { analyticsConfig.safetyNetRequirements } returns SafetyNetRequirementsContainer()
 
@@ -195,7 +195,7 @@ class AnalyticsTest : BaseTest() {
 
     @Test
     fun `abort due to time since onboarding`() {
-        every { onboardingSettings.onboardingCompletedTimestamp } returns baseTime
+        every { onboardingSettings.onboardingCompletedTimestamp } returns mockFlowPreference(baseTime)
 
         val analytics = createInstance()
 
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 6451d5f74de1e7f538722940f47c557b8f444fe8..22d97cc86b1bcea6cf247f4e221271bf2ed598a1 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
@@ -50,7 +50,6 @@ class ExposureRiskMetadataDonorTest : BaseTest() {
         override val failureReason: EwRiskLevelResult.FailureReason? = failureReason
         override val exposureWindows: List<ExposureWindow>? = null
         override val matchedKeyCount: Int = 0
-        override val daysWithEncounters: Int = 0
     }
 
     private fun createInstance() = ExposureRiskMetadataDonor(
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt
index fa2a64983a5bdfba1a7fa9d4d8ed9197dcaa646c..ea587edecb10533f5f69eb9b50fe6633166172bd 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt
@@ -24,6 +24,7 @@ import testhelpers.BaseTest
 import testhelpers.TestDispatcherProvider
 import testhelpers.extensions.CoroutinesTestExtension
 import testhelpers.extensions.InstantExecutorExtension
+import testhelpers.preferences.mockFlowPreference
 
 @ExtendWith(InstantExecutorExtension::class, CoroutinesTestExtension::class)
 class MainActivityViewModelTest : BaseTest() {
@@ -46,7 +47,9 @@ class MainActivityViewModelTest : BaseTest() {
 
         every { onboardingSettings.isOnboarded } returns true
         every { environmentSetup.currentEnvironment } returns EnvironmentSetup.Type.WRU
-        every { traceLocationSettings.onboardingStatus } returns TraceLocationSettings.OnboardingStatus.NOT_ONBOARDED
+        every { traceLocationSettings.onboardingStatus } returns mockFlowPreference(
+            TraceLocationSettings.OnboardingStatus.NOT_ONBOARDED
+        )
         every { onboardingSettings.isBackgroundCheckDone } returns true
         every { checkInRepository.checkInsWithinRetention } returns MutableStateFlow(listOf())
     }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/CombinedEwPtRiskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/CombinedEwPtRiskTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..18ec9e4c29a3c2051546b6fd2c4b2b7118660159
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/CombinedEwPtRiskTest.kt
@@ -0,0 +1,143 @@
+package de.rki.coronawarnapp.risk
+
+import com.google.android.gms.nearby.exposurenotification.ExposureWindow
+import de.rki.coronawarnapp.presencetracing.risk.PtRiskLevelResult
+import de.rki.coronawarnapp.presencetracing.risk.calculation.PresenceTracingDayRisk
+import de.rki.coronawarnapp.risk.result.EwAggregatedRiskResult
+import de.rki.coronawarnapp.risk.result.ExposureWindowDayRisk
+import de.rki.coronawarnapp.server.protocols.internal.v2.RiskCalculationParametersOuterClass
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import org.joda.time.Instant
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class CombinedEwPtRiskTest : BaseTest() {
+
+    @MockK lateinit var ewAggregatedRiskResult: EwAggregatedRiskResult
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+    }
+
+    @Test
+    fun `counts high risk days correctly`() {
+        val ewDayRisk = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = 1000,
+            riskLevel = RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel.HIGH,
+            minimumDistinctEncountersWithLowRisk = 0,
+            minimumDistinctEncountersWithHighRisk = 1
+        )
+        val ewDayRisk2 = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = 1000 + MILLIS_DAY,
+            riskLevel = RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel.LOW,
+            minimumDistinctEncountersWithLowRisk = 1,
+            minimumDistinctEncountersWithHighRisk = 0
+        )
+        val ewDayRisk3 = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = 1000 + 2 * MILLIS_DAY,
+            riskLevel = RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel.HIGH,
+            minimumDistinctEncountersWithLowRisk = 1,
+            minimumDistinctEncountersWithHighRisk = 2
+        )
+        every { ewAggregatedRiskResult.exposureWindowDayRisks } returns listOf(ewDayRisk, ewDayRisk2, ewDayRisk3)
+
+        val ptDayRisk = PresenceTracingDayRisk(
+            riskState = RiskState.INCREASED_RISK,
+            localDateUtc = Instant.ofEpochMilli(1000).toLocalDateUtc()
+        )
+        val ptDayRisk2 = PresenceTracingDayRisk(
+            riskState = RiskState.LOW_RISK,
+            localDateUtc = Instant.ofEpochMilli(1000 + MILLIS_DAY).toLocalDateUtc()
+        )
+        val ptDayRisk3 = PresenceTracingDayRisk(
+            riskState = RiskState.INCREASED_RISK,
+            localDateUtc = Instant.ofEpochMilli(1000 + 2 * MILLIS_DAY).toLocalDateUtc()
+        )
+
+        every { ewAggregatedRiskResult.isIncreasedRisk() } returns true
+
+        CombinedEwPtRiskLevelResult(
+            ptRiskLevelResult = createPtRiskLevelResult(
+                calculatedAt = Instant.ofEpochMilli(1000 + 2 * MILLIS_DAY),
+                riskState = RiskState.LOW_RISK,
+                presenceTracingDayRisk = listOf(ptDayRisk, ptDayRisk2, ptDayRisk3)
+            ),
+            ewRiskLevelResult = createEwRiskLevel(
+                calculatedAt = Instant.ofEpochMilli(1000 + 2 * MILLIS_DAY),
+                ewAggregatedRiskResult
+            )
+        ).daysWithEncounters shouldBe 2
+    }
+
+    @Test
+    fun `counts low risk days correctly`() {
+        val ewDayRisk = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = 1000,
+            riskLevel = RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel.LOW,
+            minimumDistinctEncountersWithLowRisk = 0,
+            minimumDistinctEncountersWithHighRisk = 1
+        )
+        val ewDayRisk2 = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = 1000 + MILLIS_DAY,
+            riskLevel = RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel.LOW,
+            minimumDistinctEncountersWithLowRisk = 1,
+            minimumDistinctEncountersWithHighRisk = 0
+        )
+
+        every { ewAggregatedRiskResult.exposureWindowDayRisks } returns listOf(ewDayRisk, ewDayRisk2)
+
+        val ptDayRisk = PresenceTracingDayRisk(
+            riskState = RiskState.LOW_RISK,
+            localDateUtc = Instant.ofEpochMilli(1000).toLocalDateUtc()
+        )
+
+        val ptDayRisk3 = PresenceTracingDayRisk(
+            riskState = RiskState.LOW_RISK,
+            localDateUtc = Instant.ofEpochMilli(1000 + 2 * MILLIS_DAY).toLocalDateUtc()
+        )
+
+        every { ewAggregatedRiskResult.isLowRisk() } returns true
+        every { ewAggregatedRiskResult.isIncreasedRisk() } returns false
+
+        CombinedEwPtRiskLevelResult(
+            ptRiskLevelResult = createPtRiskLevelResult(
+                calculatedAt = Instant.ofEpochMilli(1000 + 2 * MILLIS_DAY),
+                riskState = RiskState.LOW_RISK,
+                presenceTracingDayRisk = listOf(ptDayRisk, ptDayRisk3)
+            ),
+            ewRiskLevelResult = createEwRiskLevel(
+                calculatedAt = Instant.ofEpochMilli(1000 + 2 * MILLIS_DAY),
+                ewAggregatedRiskResult
+            )
+        ).daysWithEncounters shouldBe 3
+    }
+
+    private fun createPtRiskLevelResult(
+        calculatedAt: Instant,
+        riskState: RiskState,
+        presenceTracingDayRisk: List<PresenceTracingDayRisk>
+    ): PtRiskLevelResult = PtRiskLevelResult(
+        calculatedAt = calculatedAt,
+        riskState = riskState,
+        presenceTracingDayRisk = presenceTracingDayRisk
+    )
+
+    private fun createEwRiskLevel(
+        calculatedAt: Instant,
+        ewAggregatedRiskResult: EwAggregatedRiskResult?
+    ): EwRiskLevelResult = object : EwRiskLevelResult {
+        override val calculatedAt = calculatedAt
+        override val ewAggregatedRiskResult: EwAggregatedRiskResult? = ewAggregatedRiskResult
+        override val failureReason: EwRiskLevelResult.FailureReason? = null
+        override val exposureWindows: List<ExposureWindow>? = null
+        override val matchedKeyCount: Int = 0
+    }
+}
+
+private const val MILLIS_DAY = (1000 * 60 * 60 * 24).toLong()
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultExtensionsTest.kt
index 18acf7c6352c7cb688064d5e52989cf29d984c2c..24e88df609daba5e4c564c06f43d398b96e8cee2 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultExtensionsTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultExtensionsTest.kt
@@ -21,7 +21,6 @@ class EwRiskLevelResultExtensionsTest : BaseTest() {
             get() = if (!hasResult) EwRiskLevelResult.FailureReason.UNKNOWN else null
         override val exposureWindows: List<ExposureWindow>? = null
         override val matchedKeyCount: Int = 0
-        override val daysWithEncounters: Int = 0
     }
 
     @Test
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultTest.kt
index c5b8c6c55f0dfa11297e982e6880bdae16abba57..c2bb7d54632201dc77070fac12757dd674cdf4c5 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultTest.kt
@@ -2,28 +2,29 @@ package de.rki.coronawarnapp.risk
 
 import com.google.android.gms.nearby.exposurenotification.ExposureWindow
 import de.rki.coronawarnapp.risk.result.EwAggregatedRiskResult
+import de.rki.coronawarnapp.risk.result.ExposureWindowDayRisk
+import de.rki.coronawarnapp.server.protocols.internal.v2.RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel
 import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
 import io.mockk.mockk
 import org.joda.time.Instant
-import org.junit.Test
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 
 class EwRiskLevelResultTest : BaseTest() {
 
-    private fun createRiskLevel(
-        ewAggregatedRiskResult: EwAggregatedRiskResult?,
-        failureReason: EwRiskLevelResult.FailureReason?
-    ): EwRiskLevelResult = object : EwRiskLevelResult {
-        override val calculatedAt: Instant = Instant.EPOCH
-        override val ewAggregatedRiskResult: EwAggregatedRiskResult? = ewAggregatedRiskResult
-        override val failureReason: EwRiskLevelResult.FailureReason? = failureReason
-        override val exposureWindows: List<ExposureWindow>? = null
-        override val matchedKeyCount: Int = 0
-        override val daysWithEncounters: Int = 0
+    @MockK lateinit var ewAggregatedRiskResult1: EwAggregatedRiskResult
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
     }
 
     @Test
-    fun testUnsuccessfulRistLevels() {
+    fun testUnsuccessfulRiskLevels() {
         createRiskLevel(
             ewAggregatedRiskResult = null,
             failureReason = EwRiskLevelResult.FailureReason.UNKNOWN
@@ -34,4 +35,46 @@ class EwRiskLevelResultTest : BaseTest() {
             failureReason = null
         ).wasSuccessfullyCalculated shouldBe true
     }
+
+    @Test
+    fun `counts days correctly`() {
+        val dayRisk = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = 1000,
+            riskLevel = RiskLevel.HIGH,
+            minimumDistinctEncountersWithLowRisk = 0,
+            minimumDistinctEncountersWithHighRisk = 1
+        )
+        val dayRisk2 = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = 1000 + MILLIS_DAY,
+            riskLevel = RiskLevel.LOW,
+            minimumDistinctEncountersWithLowRisk = 1,
+            minimumDistinctEncountersWithHighRisk = 0
+        )
+        val dayRisk3 = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = 1000 + 2 * MILLIS_DAY,
+            riskLevel = RiskLevel.HIGH,
+            minimumDistinctEncountersWithLowRisk = 1,
+            minimumDistinctEncountersWithHighRisk = 2
+        )
+        every { ewAggregatedRiskResult1.exposureWindowDayRisks } returns listOf(dayRisk, dayRisk2, dayRisk3)
+        val riskLevel = createRiskLevel(
+            ewAggregatedRiskResult = ewAggregatedRiskResult1,
+            failureReason = null
+        )
+        riskLevel.daysWithHighRisk.size shouldBe 2
+        riskLevel.daysWithLowRisk.size shouldBe 1
+    }
+
+    private fun createRiskLevel(
+        ewAggregatedRiskResult: EwAggregatedRiskResult?,
+        failureReason: EwRiskLevelResult.FailureReason?
+    ): EwRiskLevelResult = object : EwRiskLevelResult {
+        override val calculatedAt: Instant = Instant.EPOCH
+        override val ewAggregatedRiskResult: EwAggregatedRiskResult? = ewAggregatedRiskResult
+        override val failureReason: EwRiskLevelResult.FailureReason? = failureReason
+        override val exposureWindows: List<ExposureWindow>? = null
+        override val matchedKeyCount: Int = 0
+    }
 }
+
+private const val MILLIS_DAY = (1000 * 60 * 60 * 24).toLong()
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt
index a88a3a777beda43d72e3800e7bbf588471b4a511..da0c655bef71f41f57272680b601e743c54eba06 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt
@@ -105,7 +105,6 @@ class RiskLevelChangeDetectorTest : BaseTest() {
         override val failureReason: EwRiskLevelResult.FailureReason? = null
         override val exposureWindows: List<ExposureWindow>? = null
         override val matchedKeyCount: Int = 0
-        override val daysWithEncounters: Int = 0
     }
 
     private fun createPtRiskLevel(
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/internal/RiskCombinatorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/internal/RiskCombinatorTest.kt
index 3d23b8d37e02bafdd04f5ae0f76d094417f07845..13a44475916138802e65932eb1d76c441953e759 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/internal/RiskCombinatorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/internal/RiskCombinatorTest.kt
@@ -210,7 +210,7 @@ class RiskCombinatorTest : BaseTest() {
     }
 
     @Test
-    fun `max RiskState works`() {
+    fun `combine RiskState works`() {
         RiskCombinator.combine(INCREASED_RISK, INCREASED_RISK) shouldBe INCREASED_RISK
         RiskCombinator.combine(INCREASED_RISK, LOW_RISK) shouldBe INCREASED_RISK
         RiskCombinator.combine(INCREASED_RISK, CALCULATION_FAILED) shouldBe CALCULATION_FAILED
@@ -232,5 +232,4 @@ private fun createEwRiskLevelResult(
     override val ewAggregatedRiskResult: EwAggregatedRiskResult? = null
     override val exposureWindows: List<ExposureWindow>? = null
     override val matchedKeyCount: Int = 0
-    override val daysWithEncounters: Int = 0
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/task/SubmissionTaskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/task/SubmissionTaskTest.kt
index 81300aaa5438d57928007af973011618fa347232..de0bc5cb26df3bdcdd47b355d3c875cdc2386c93 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/task/SubmissionTaskTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/task/SubmissionTaskTest.kt
@@ -6,8 +6,10 @@ import de.rki.coronawarnapp.appconfig.ConfigData
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.coronatest.notification.ShareTestResultNotificationService
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.RAPID_ANTIGEN
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.playbook.Playbook
 import de.rki.coronawarnapp.presencetracing.checkins.CheckIn
 import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository
@@ -20,7 +22,6 @@ import de.rki.coronawarnapp.submission.auto.AutoSubmission
 import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryStorage
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.preferences.FlowPreference
-import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 import io.kotest.assertions.throwables.shouldThrow
 import io.kotest.assertions.throwables.shouldThrowMessage
 import io.kotest.matchers.shouldBe
@@ -66,7 +67,6 @@ class SubmissionTaskTest : BaseTest() {
     @MockK lateinit var analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector
     @MockK lateinit var checkInsTransformer: CheckInsTransformer
     @MockK lateinit var checkInRepository: CheckInRepository
-    @MockK lateinit var backgroundWorkScheduler: BackgroundWorkScheduler
     @MockK lateinit var coronaTestRepository: CoronaTestRepository
 
     private lateinit var settingSymptomsPreference: FlowPreference<Symptoms?>
@@ -122,9 +122,6 @@ class SubmissionTaskTest : BaseTest() {
             coEvery { markAsSubmitted("coronatest-identifier") } just Runs
         }
 
-        every { backgroundWorkScheduler.stopWorkScheduler() } just Runs
-        every { backgroundWorkScheduler.startWorkScheduler() } just Runs
-
         every { tekBatch.keys } returns listOf(tek)
         every { tekHistoryStorage.tekData } returns flowOf(listOf(tekBatch))
         coEvery { tekHistoryStorage.clear() } just Runs
@@ -181,7 +178,6 @@ class SubmissionTaskTest : BaseTest() {
         analyticsKeySubmissionCollector = analyticsKeySubmissionCollector,
         checkInsRepository = checkInRepository,
         checkInsTransformer = checkInsTransformer,
-        backgroundWorkScheduler = backgroundWorkScheduler,
         coronaTestRepository = coronaTestRepository,
     )
 
@@ -223,9 +219,6 @@ class SubmissionTaskTest : BaseTest() {
                 )
             )
 
-            analyticsKeySubmissionCollector.reportSubmitted()
-            analyticsKeySubmissionCollector.reportSubmittedInBackground()
-
             tekHistoryStorage.clear()
             submissionSettings.symptoms
             settingSymptomsPreference.update(match { it.invoke(mockk()) == null })
@@ -234,9 +227,7 @@ class SubmissionTaskTest : BaseTest() {
 
             autoSubmission.updateMode(AutoSubmission.Mode.DISABLED)
 
-            backgroundWorkScheduler.stopWorkScheduler()
             coronaTestRepository.markAsSubmitted(any())
-            backgroundWorkScheduler.startWorkScheduler()
 
             testResultAvailableNotificationService.cancelTestResultAvailableNotification()
         }
@@ -393,4 +384,42 @@ class SubmissionTaskTest : BaseTest() {
         }
         verify { autoSubmission.updateMode(AutoSubmission.Mode.DISABLED) }
     }
+
+    @Test
+    fun `PPA is collected for PCR tests`() = runBlockingTest {
+        coronaTestsFlow.value = setOf(
+            mockk<CoronaTest>().apply {
+                every { type } returns PCR
+                every { isAdvancedConsentGiven } returns true
+                every { isSubmissionAllowed } returns true
+                every { isSubmitted } returns false
+                every { registrationToken } returns "regtoken"
+                every { identifier } returns "coronatest-identifier"
+            }
+        )
+
+        createTask().run(SubmissionTask.Arguments(checkUserActivity = true))
+
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportSubmitted() }
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportSubmittedInBackground() }
+    }
+
+    @Test
+    fun `PPA is NOT collected for RAT tests`() = runBlockingTest {
+        coronaTestsFlow.value = setOf(
+            mockk<CoronaTest>().apply {
+                every { type } returns RAPID_ANTIGEN
+                every { isAdvancedConsentGiven } returns true
+                every { isSubmissionAllowed } returns true
+                every { isSubmitted } returns false
+                every { registrationToken } returns "regtoken"
+                every { identifier } returns "coronatest-identifier"
+            }
+        )
+
+        createTask().run(SubmissionTask.Arguments(checkUserActivity = true))
+
+        verify(exactly = 0) { analyticsKeySubmissionCollector.reportSubmitted() }
+        verify(exactly = 0) { analyticsKeySubmissionCollector.reportSubmittedInBackground() }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModelTest.kt
index 0f81834e2c3a901acb07b36f8b5e892520c407d0..bd8f052d20fbc544f19b3ef378a2567a6c378c9e 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModelTest.kt
@@ -6,6 +6,7 @@ import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQRCode
 import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQrCodeValidator
 import de.rki.coronawarnapp.coronatest.qrcode.InvalidQRCodeException
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.ui.submission.ApiRequestState
 import de.rki.coronawarnapp.ui.submission.qrcode.QrCodeRegistrationStateProcessor
@@ -14,11 +15,14 @@ import de.rki.coronawarnapp.util.permission.CameraSettings
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
+import io.mockk.Runs
 import io.mockk.coEvery
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
+import io.mockk.just
 import io.mockk.verify
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.runBlockingTest
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
@@ -34,6 +38,7 @@ class SubmissionQRCodeScanViewModelTest : BaseTest() {
     @MockK lateinit var cameraSettings: CameraSettings
     @MockK lateinit var qrCodeValidator: CoronaTestQrCodeValidator
     @MockK lateinit var qrCodeRegistrationStateProcessor: QrCodeRegistrationStateProcessor
+    @MockK lateinit var analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector
 
     private val coronaTestFlow = MutableStateFlow<CoronaTest?>(
         null
@@ -57,7 +62,8 @@ class SubmissionQRCodeScanViewModelTest : BaseTest() {
         qrCodeRegistrationStateProcessor,
         isConsentGiven = true,
         submissionRepository,
-        qrCodeValidator
+        qrCodeValidator,
+        analyticsKeySubmissionCollector
     )
 
     @Test
@@ -100,4 +106,30 @@ class SubmissionQRCodeScanViewModelTest : BaseTest() {
 
         verify { cameraSettings.isCameraDeniedPermanently }
     }
+
+    @Test
+    fun `startQrCodeRegistration() should call analyticsKeySubmissionCollector for PCR tests`() = runBlockingTest {
+        val coronaTestQRCode = CoronaTestQRCode.PCR(qrCodeGUID = "123456-12345678-1234-4DA7-B166-B86D85475064")
+
+        every { qrCodeValidator.validate(any()) } returns coronaTestQRCode
+        every { analyticsKeySubmissionCollector.reportAdvancedConsentGiven() } just Runs
+        coEvery { qrCodeRegistrationStateProcessor.startQrCodeRegistration(any(), any()) } just Runs
+
+        createViewModel().startQrCodeRegistration(rawResult = "", isConsentGiven = true)
+
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportAdvancedConsentGiven() }
+    }
+
+    @Test
+    fun `startQrCodeRegistration() should NOT call analyticsKeySubmissionCollector for RAT tests`() = runBlockingTest {
+        val coronaTestQRCode = CoronaTestQRCode.PCR(qrCodeGUID = "123456-12345678-1234-4DA7-B166-B86D85475064")
+
+        every { qrCodeValidator.validate(any()) } returns coronaTestQRCode
+        every { analyticsKeySubmissionCollector.reportAdvancedConsentGiven() } just Runs
+        coEvery { qrCodeRegistrationStateProcessor.startQrCodeRegistration(any(), any()) } just Runs
+
+        createViewModel().startQrCodeRegistration(rawResult = "", isConsentGiven = true)
+
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportAdvancedConsentGiven() }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModelTest.kt
index 835ce668dbbfcd9ec40525b1576bbdb0f722fd56..c50aaff09c73e897079d6e9b6d6fa9be21a03002 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarViewModelTest.kt
@@ -1,6 +1,10 @@
 package de.rki.coronawarnapp.ui.submission.symptoms.calendar
 
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.RAPID_ANTIGEN
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
+import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.Screen
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.submission.Symptoms
 import de.rki.coronawarnapp.submission.auto.AutoSubmission
@@ -16,6 +20,7 @@ import io.mockk.just
 import io.mockk.verify
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runBlockingTest
 import org.joda.time.LocalDate
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
@@ -31,6 +36,7 @@ class SubmissionSymptomCalendarViewModelTest : BaseTest() {
     @MockK lateinit var submissionRepository: SubmissionRepository
     @MockK lateinit var autoSubmission: AutoSubmission
     @MockK lateinit var analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector
+    @MockK lateinit var testType: CoronaTest.Type
     private lateinit var currentSymptoms: FlowPreference<Symptoms?>
 
     @BeforeEach
@@ -51,7 +57,8 @@ class SubmissionSymptomCalendarViewModelTest : BaseTest() {
             dispatcherProvider = TestDispatcherProvider(),
             submissionRepository = submissionRepository,
             autoSubmission = autoSubmission,
-            analyticsKeySubmissionCollector = analyticsKeySubmissionCollector
+            analyticsKeySubmissionCollector = analyticsKeySubmissionCollector,
+            testType = testType
         )
 
     @Test
@@ -111,4 +118,64 @@ class SubmissionSymptomCalendarViewModelTest : BaseTest() {
             showUploadDialog.value shouldBe false
         }
     }
+
+    @Test
+    fun `onNewUserActivity() should call analyticsKeySubmissionCollector for PCR tests`() {
+        testType = PCR
+
+        createViewModel().onNewUserActivity()
+
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.SYMPTOM_ONSET) }
+    }
+
+    @Test
+    fun `onNewUserActivity() should NOT call analyticsKeySubmissionCollector for RAT tests`() {
+        testType = RAPID_ANTIGEN
+
+        createViewModel().onNewUserActivity()
+
+        verify(exactly = 0) { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.SYMPTOM_ONSET) }
+    }
+
+    @Test
+    fun `onCancelConfirmed() should call analyticsKeySubmissionCollector for PCR tests`() {
+        testType = PCR
+
+        createViewModel().onCancelConfirmed()
+
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportSubmittedAfterCancel() }
+    }
+
+    @Test
+    fun `onCancelConfirmed() should NOT call analyticsKeySubmissionCollector for RAT tests`() {
+        testType = RAPID_ANTIGEN
+
+        createViewModel().onCancelConfirmed()
+
+        verify(exactly = 0) { analyticsKeySubmissionCollector.reportSubmittedAfterCancel() }
+    }
+
+    @Test
+    fun `onDone() should call analyticsKeySubmissionCollector for PCR tests`() = runBlockingTest {
+        testType = PCR
+
+        createViewModel().apply {
+            onLastSevenDaysStart()
+            onDone()
+        }
+
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportSubmittedAfterSymptomFlow() }
+    }
+
+    @Test
+    fun `onDone() should NOT call analyticsKeySubmissionCollector for RAT tests`() {
+        testType = RAPID_ANTIGEN
+
+        createViewModel().apply {
+            onLastSevenDaysStart()
+            onDone()
+        }
+
+        verify(exactly = 0) { analyticsKeySubmissionCollector.reportSubmittedAfterSymptomFlow() }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModelTest.kt
index 250cb3f5c117bd403c560b54938e46396fd053fa..9416e012362aef6182d443d7e1c12ed834456cdd 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModelTest.kt
@@ -1,6 +1,10 @@
 package de.rki.coronawarnapp.ui.submission.symptoms.introduction
 
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.RAPID_ANTIGEN
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
+import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.Screen
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.submission.Symptoms
 import de.rki.coronawarnapp.submission.auto.AutoSubmission
@@ -30,6 +34,7 @@ class SubmissionSymptomIntroductionViewModelTest : BaseTest() {
     @MockK lateinit var submissionRepository: SubmissionRepository
     @MockK lateinit var autoSubmission: AutoSubmission
     @MockK lateinit var analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector
+    @MockK lateinit var testType: CoronaTest.Type
     private val currentSymptoms = mockFlowPreference<Symptoms?>(null)
 
     @BeforeEach
@@ -45,7 +50,8 @@ class SubmissionSymptomIntroductionViewModelTest : BaseTest() {
         dispatcherProvider = TestDispatcherProvider(),
         submissionRepository = submissionRepository,
         autoSubmission = autoSubmission,
-        analyticsKeySubmissionCollector = analyticsKeySubmissionCollector
+        analyticsKeySubmissionCollector = analyticsKeySubmissionCollector,
+        testType = testType
     )
 
     @Test
@@ -55,7 +61,8 @@ class SubmissionSymptomIntroductionViewModelTest : BaseTest() {
             onNextClicked()
             navigation.value shouldBe SubmissionSymptomIntroductionFragmentDirections
                 .actionSubmissionSymptomIntroductionFragmentToSubmissionSymptomCalendarFragment(
-                    symptomIndication = Symptoms.Indication.POSITIVE
+                    symptomIndication = Symptoms.Indication.POSITIVE,
+                    testType = testType
                 )
         }
 
@@ -121,4 +128,22 @@ class SubmissionSymptomIntroductionViewModelTest : BaseTest() {
             showUploadDialog.value shouldBe false
         }
     }
+
+    @Test
+    fun `onNewUserActivity() should call analyticsKeySubmissionCollector for PCR tests`() {
+        testType = PCR
+
+        createViewModel().onNewUserActivity()
+
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.SYMPTOMS) }
+    }
+
+    @Test
+    fun `onNewUserActivity() should NOT call analyticsKeySubmissionCollector for RAT tests`() {
+        testType = RAPID_ANTIGEN
+
+        createViewModel().onNewUserActivity()
+
+        verify(exactly = 0) { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.SYMPTOMS) }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testavailable/SubmissionTestResultAvailableViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testavailable/SubmissionTestResultAvailableViewModelTest.kt
index 00fae3d0b58f412a9bbc0dc3cab9f2b780b5b75a..fad77e25164561a6928eb11a15575266f5f2804b 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testavailable/SubmissionTestResultAvailableViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testavailable/SubmissionTestResultAvailableViewModelTest.kt
@@ -2,6 +2,8 @@ package de.rki.coronawarnapp.ui.submission.testavailable
 
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.RAPID_ANTIGEN
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository
 import de.rki.coronawarnapp.submission.SubmissionRepository
@@ -129,4 +131,28 @@ class SubmissionTestResultAvailableViewModelTest : BaseTest() {
         viewModel.routeToScreen.value shouldBe SubmissionTestResultAvailableFragmentDirections
             .actionSubmissionTestResultAvailableFragmentToSubmissionTestResultNoConsentFragment(testType)
     }
+
+    @Test
+    fun `proceed() should call analyticsKeySubmissionCollector for PCR tests`() {
+        testType = PCR
+        coronaTestFlow.value = mockk<CoronaTest>().apply {
+            every { isAdvancedConsentGiven } returns false
+        }
+
+        createViewModel().proceed()
+
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportConsentWithdrawn() }
+    }
+
+    @Test
+    fun `proceed() should NOT call analyticsKeySubmissionCollector for RAT tests`() {
+        testType = RAPID_ANTIGEN
+        coronaTestFlow.value = mockk<CoronaTest>().apply {
+            every { isAdvancedConsentGiven } returns false
+        }
+
+        createViewModel().proceed()
+
+        verify(exactly = 0) { analyticsKeySubmissionCollector.reportConsentWithdrawn() }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModelTest.kt
index 31e401a51b154f9487de4c8b4f94ee6210aee253..9c717c0817c14d21ee0ef6e2628c00b8c69e415d 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultConsentGivenViewModelTest.kt
@@ -1,8 +1,9 @@
 package de.rki.coronawarnapp.ui.submission.testresult
 
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
+import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.Screen
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.submission.auto.AutoSubmission
 import de.rki.coronawarnapp.ui.submission.testresult.positive.SubmissionTestResultConsentGivenViewModel
@@ -10,6 +11,7 @@ import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.impl.annotations.MockK
+import io.mockk.verify
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
@@ -53,4 +55,18 @@ class SubmissionTestResultConsentGivenViewModelTest : BaseTest() {
         viewModel.onCancelConfirmed()
         viewModel.routeToScreen.value shouldBe SubmissionNavigationEvents.NavigateToMainActivity
     }
+
+    @Test
+    fun `onNewUserActivity should call analyticsSubmissionCollector for PCR tests`() {
+        testType = CoronaTest.Type.PCR
+        createViewModel().onNewUserActivity()
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.TEST_RESULT) }
+    }
+
+    @Test
+    fun `onNewUserActivity should NOT call analyticsSubmissionCollector for RAT tests`() {
+        testType = CoronaTest.Type.RAPID_ANTIGEN
+        createViewModel().onNewUserActivity()
+        verify(exactly = 0) { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.TEST_RESULT) }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentViewModelTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e47dff84d152db22ddc2028f65cc75d6f2e8c8af
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentViewModelTest.kt
@@ -0,0 +1,46 @@
+package de.rki.coronawarnapp.ui.submission.testresult.positive
+
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.RAPID_ANTIGEN
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
+import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
+import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.Screen
+import de.rki.coronawarnapp.submission.SubmissionRepository
+import io.mockk.MockKAnnotations
+import io.mockk.impl.annotations.MockK
+import io.mockk.verify
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+internal class SubmissionTestResultNoConsentViewModelTest : BaseTest() {
+
+    @MockK lateinit var submissionRepository: SubmissionRepository
+    @MockK lateinit var testResultAvailableNotificationService: PCRTestResultAvailableNotificationService
+    @MockK lateinit var analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector
+
+    @BeforeEach
+    fun setUp() {
+        MockKAnnotations.init(this, relaxed = true)
+    }
+
+    private fun createInstance(testType: Type) = SubmissionTestResultNoConsentViewModel(
+        submissionRepository,
+        testResultAvailableNotificationService,
+        analyticsKeySubmissionCollector,
+        testType
+    )
+
+    @Test
+    fun `onTestOpened() should call analyticsKeySubmissionCollector for PCR tests`() {
+        createInstance(PCR).onTestOpened()
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.TEST_RESULT) }
+    }
+
+    @Test
+    fun `onTestOpened() should NOT call analyticsKeySubmissionCollector for RAT tests`() {
+        createInstance(RAPID_ANTIGEN).onTestOpened()
+        verify(exactly = 0) { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.TEST_RESULT) }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModelTest.kt
index a189fc59576067c2b46f9d644792a5509daaf66e..3e16e938556fca6f03e13e043987cc0dffff9dcc 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModelTest.kt
@@ -1,7 +1,10 @@
 package de.rki.coronawarnapp.ui.submission.warnothers
 
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.PCR
+import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.RAPID_ANTIGEN
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
+import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.Screen
 import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository
 import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository
@@ -59,6 +62,7 @@ class SubmissionResultPositiveOtherWarningNoConsentViewModelTest : BaseTest() {
         }
 
         every { enfClient.isTracingEnabled } returns flowOf(true)
+        every { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.WARN_OTHERS) } just Runs
     }
 
     private fun createViewModel() = SubmissionResultPositiveOtherWarningNoConsentViewModel(
@@ -86,4 +90,18 @@ class SubmissionResultPositiveOtherWarningNoConsentViewModelTest : BaseTest() {
         verify { submissionRepository.giveConsentToSubmission(any()) }
         verify { tekHistoryUpdater.updateTEKHistoryOrRequestPermission() }
     }
+
+    @Test
+    fun `onResume() should call analyticsKeySubmissionCollector for PCR tests`() {
+        testType = PCR
+        createViewModel().onResume()
+        verify(exactly = 1) { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.WARN_OTHERS) }
+    }
+
+    @Test
+    fun `onResume() should NOT call analyticsKeySubmissionCollector for RAT tests`() {
+        testType = RAPID_ANTIGEN
+        createViewModel().onResume()
+        verify(exactly = 0) { analyticsKeySubmissionCollector.reportLastSubmissionFlowScreen(Screen.WARN_OTHERS) }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigrationTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigrationTest.kt
index f3585f5d8fe1a1cab0d9a359b7d6b780daf782dc..f10be3cd849ecac441f0fedf6bb05f5b9f70e353 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigrationTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/encryptionmigration/EncryptedPreferencesMigrationTest.kt
@@ -109,7 +109,8 @@ class EncryptedPreferencesMigrationTest : BaseIOTest() {
         every { cwaSettings.numberOfRemainingSharePositiveTestResultReminders = Int.MAX_VALUE } just Runs
 
         // OnboardingLocalData
-        every { onboardingSettings.onboardingCompletedTimestamp = Instant.ofEpochMilli(10101010L) } just Runs
+        val mockOnboardingCompletedTimestamp = mockFlowPreference(Instant.ofEpochMilli(10101010L))
+        every { onboardingSettings.onboardingCompletedTimestamp } returns mockOnboardingCompletedTimestamp
         every { onboardingSettings.isBackgroundCheckDone = true } just Runs
 
         // TracingLocalData
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/worker/WorkerBinderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/worker/WorkerBinderTest.kt
index 34e53717fc997045cee9cac4f50b97c0ee6e0bf0..812d53b027a0a988bf3eff783e52b8ba787a3f5b 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/worker/WorkerBinderTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/worker/WorkerBinderTest.kt
@@ -7,8 +7,9 @@ import dagger.Component
 import dagger.Module
 import dagger.Provides
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
-import de.rki.coronawarnapp.coronatest.worker.execution.PCRResultScheduler
-import de.rki.coronawarnapp.coronatest.worker.execution.RAResultScheduler
+import de.rki.coronawarnapp.coronatest.type.pcr.execution.PCRResultScheduler
+import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultScheduler
 import de.rki.coronawarnapp.datadonation.analytics.Analytics
 import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsScheduler
 import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler
@@ -16,7 +17,6 @@ import de.rki.coronawarnapp.deadman.DeadmanNotificationSender
 import de.rki.coronawarnapp.deniability.NoiseScheduler
 import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.notification.GeneralNotifications
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.playbook.Playbook
 import de.rki.coronawarnapp.presencetracing.checkins.checkout.CheckOutNotification
 import de.rki.coronawarnapp.presencetracing.checkins.checkout.auto.AutoCheckOut
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/BackgroundConstantsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/BackgroundConstantsTest.kt
index 899fc46235d9c8adbb16c326d5238e873c61211e..c932ef5a240341b9ec60177bdaa0b1c46bcc7499 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/BackgroundConstantsTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/BackgroundConstantsTest.kt
@@ -7,8 +7,6 @@ class BackgroundConstantsTest {
 
     @Test
     fun allBackgroundConstants() {
-        Assert.assertEquals(BackgroundConstants.MINUTES_IN_DAY, 1440)
-        Assert.assertEquals(BackgroundConstants.DIAGNOSIS_TEST_RESULT_RETRIEVAL_TRIES_PER_DAY, 12)
         Assert.assertEquals(BackgroundConstants.KIND_DELAY, 1L)
         Assert.assertEquals(BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD, 2)
         Assert.assertEquals(BackgroundConstants.POLLING_VALIDITY_MAX_DAYS, 21)
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/BackgroundWorkHelperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/BackgroundWorkHelperTest.kt
index d2251ee4826ebb672a4baf84b57ca2712457e885..411335d1708f8b45b183fe9438bbb48d49ab27e5 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/BackgroundWorkHelperTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/BackgroundWorkHelperTest.kt
@@ -1,7 +1,6 @@
 package de.rki.coronawarnapp.worker
 
-import androidx.work.NetworkType
-import de.rki.coronawarnapp.coronatest.worker.execution.PCRResultScheduler
+import de.rki.coronawarnapp.coronatest.type.pcr.execution.PCRResultScheduler
 import org.junit.Assert
 import org.junit.Test
 
@@ -14,10 +13,4 @@ class BackgroundWorkHelperTest {
             120
         )
     }
-
-    @Test
-    fun getConstraintsForDiagnosisKeyOneTimeBackgroundWork() {
-        val constraints = BackgroundWorkHelper.getConstraintsForDiagnosisKeyOneTimeBackgroundWork()
-        Assert.assertEquals(constraints.requiredNetworkType, NetworkType.CONNECTED)
-    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/DiagnosisTestResultRetrievalPeriodicWorkerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/DiagnosisTestResultRetrievalPeriodicWorkerTest.kt
deleted file mode 100644
index 33ec41f79e37ef37e46225fb3a7a0056464a3283..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/DiagnosisTestResultRetrievalPeriodicWorkerTest.kt
+++ /dev/null
@@ -1,257 +0,0 @@
-package de.rki.coronawarnapp.worker
-
-import android.content.Context
-import androidx.work.ListenableWorker
-import androidx.work.WorkRequest
-import androidx.work.WorkerParameters
-import de.rki.coronawarnapp.coronatest.CoronaTestRepository
-import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
-import de.rki.coronawarnapp.coronatest.type.CoronaTest
-import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
-import de.rki.coronawarnapp.coronatest.worker.PCRResultRetrievalWorker
-import de.rki.coronawarnapp.coronatest.worker.execution.PCRResultScheduler
-import de.rki.coronawarnapp.notification.GeneralNotifications
-import de.rki.coronawarnapp.notification.NotificationConstants
-import de.rki.coronawarnapp.notification.PCRTestResultAvailableNotificationService
-import de.rki.coronawarnapp.util.TimeAndDateExtensions.daysToMilliseconds
-import de.rki.coronawarnapp.util.TimeStamper
-import de.rki.coronawarnapp.util.di.AppInjector
-import de.rki.coronawarnapp.util.di.ApplicationComponent
-import de.rki.coronawarnapp.util.encryptionmigration.EncryptedPreferencesFactory
-import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
-import io.kotest.matchers.shouldBe
-import io.mockk.MockKAnnotations
-import io.mockk.Runs
-import io.mockk.coEvery
-import io.mockk.coVerify
-import io.mockk.every
-import io.mockk.impl.annotations.MockK
-import io.mockk.impl.annotations.RelaxedMockK
-import io.mockk.just
-import io.mockk.mockk
-import io.mockk.mockkObject
-import io.mockk.verify
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.test.runBlockingTest
-import org.joda.time.Instant
-import org.junit.Before
-import org.junit.Test
-import testhelpers.BaseTest
-
-class DiagnosisTestResultRetrievalPeriodicWorkerTest : BaseTest() {
-    @MockK lateinit var context: Context
-    @MockK lateinit var request: WorkRequest
-    @MockK lateinit var testResultAvailableNotificationService: PCRTestResultAvailableNotificationService
-    @MockK lateinit var notificationHelper: GeneralNotifications
-    @MockK lateinit var appComponent: ApplicationComponent
-    @MockK lateinit var encryptedPreferencesFactory: EncryptedPreferencesFactory
-    @MockK lateinit var encryptionErrorResetTool: EncryptionErrorResetTool
-    @MockK lateinit var timeStamper: TimeStamper
-    @MockK lateinit var coronaTestRepository: CoronaTestRepository
-    @MockK lateinit var testResultScheduler: PCRResultScheduler
-
-    @RelaxedMockK lateinit var workerParams: WorkerParameters
-    private val currentInstant = Instant.ofEpochSecond(1611764225)
-    private val testToken = "test token"
-
-    private val coronaTestFlow = MutableStateFlow(emptySet<CoronaTest>())
-
-    @Before
-    fun setUp() {
-        MockKAnnotations.init(this)
-        every { timeStamper.nowUTC } returns currentInstant
-
-        mockkObject(AppInjector)
-        every { AppInjector.component } returns appComponent
-        every { appComponent.encryptedPreferencesFactory } returns encryptedPreferencesFactory
-        every { appComponent.errorResetTool } returns encryptionErrorResetTool
-
-        every { testResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = any()) } just Runs
-
-        every { notificationHelper.cancelCurrentNotification(any()) } just Runs
-
-        coronaTestRepository.apply {
-            every { coronaTests } answers { coronaTestFlow }
-            coEvery { refresh(any()) } coAnswers { coronaTestFlow.first() }
-            coEvery { updateResultNotification(identifier = any(), sent = any()) } just Runs
-        }
-    }
-
-    private fun newCoronaTest(
-        registered: Instant = currentInstant,
-        viewed: Boolean = false,
-        result: CoronaTestResult = CoronaTestResult.PCR_POSITIVE,
-        isNotificationSent: Boolean = false,
-    ): CoronaTest {
-        return mockk<PCRCoronaTest>().apply {
-            every { identifier } returns ""
-            every { type } returns CoronaTest.Type.PCR
-            every { registeredAt } returns registered
-            every { isViewed } returns viewed
-            every { testResult } returns result
-            every { registrationToken } returns testToken
-            every { isResultAvailableNotificationSent } returns isNotificationSent
-        }
-    }
-
-    private fun createWorker() = PCRResultRetrievalWorker(
-        context = context,
-        workerParams = workerParams,
-        testResultAvailableNotificationService = testResultAvailableNotificationService,
-        notificationHelper = notificationHelper,
-        coronaTestRepository = coronaTestRepository,
-        testResultScheduler = testResultScheduler,
-        timeStamper = timeStamper,
-    )
-
-    @Test
-    fun testStopWorkerWhenResultHasBeenViewed() = runBlockingTest {
-        coronaTestFlow.value = setOf(newCoronaTest(viewed = true))
-
-        val result = createWorker().doWork()
-
-        coVerify(exactly = 0) { coronaTestRepository.refresh(type = CoronaTest.Type.PCR) }
-        verify(exactly = 1) { testResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = false) }
-        result shouldBe ListenableWorker.Result.success()
-    }
-
-    @Test
-    fun testStopWorkerWhenNotificationSent() = runBlockingTest {
-        coronaTestFlow.value = setOf(newCoronaTest(isNotificationSent = true))
-
-        val result = createWorker().doWork()
-
-        coVerify(exactly = 0) { coronaTestRepository.refresh(type = CoronaTest.Type.PCR) }
-        verify(exactly = 1) { testResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = false) }
-        result shouldBe ListenableWorker.Result.success()
-    }
-
-    @Test
-    fun testStopWorkerWhenMaxDaysExceeded() = runBlockingTest {
-        val past =
-            currentInstant - (BackgroundConstants.POLLING_VALIDITY_MAX_DAYS.toLong() + 1).daysToMilliseconds()
-        coronaTestFlow.value = setOf(newCoronaTest(registered = past))
-
-        val result = createWorker().doWork()
-
-        coVerify(exactly = 0) { coronaTestRepository.refresh(type = CoronaTest.Type.PCR) }
-        verify(exactly = 1) { testResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = false) }
-        result shouldBe ListenableWorker.Result.success()
-    }
-
-    @Test
-    fun testSendNotificationWhenPositive() = runBlockingTest {
-        val testResult = CoronaTestResult.PCR_POSITIVE
-        coronaTestFlow.value = setOf(newCoronaTest(result = testResult))
-
-        coEvery { testResultAvailableNotificationService.showTestResultAvailableNotification(testResult) } just Runs
-        coEvery {
-            notificationHelper.cancelCurrentNotification(
-                NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
-            )
-        } just Runs
-
-        val result = createWorker().doWork()
-
-        coVerify {
-            coronaTestRepository.refresh(type = CoronaTest.Type.PCR)
-            testResultAvailableNotificationService.showTestResultAvailableNotification(testResult)
-            notificationHelper.cancelCurrentNotification(
-                NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
-            )
-            coronaTestRepository.updateResultNotification(any(), sent = true)
-        }
-
-        result shouldBe ListenableWorker.Result.success()
-    }
-
-    @Test
-    fun testSendNotificationWhenNegative() = runBlockingTest {
-        val testResult = CoronaTestResult.PCR_NEGATIVE
-        coronaTestFlow.value = setOf(newCoronaTest(result = testResult))
-        coEvery { testResultAvailableNotificationService.showTestResultAvailableNotification(testResult) } just Runs
-        coEvery {
-            notificationHelper.cancelCurrentNotification(
-                NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
-            )
-        } just Runs
-
-        val result = createWorker().doWork()
-
-        coVerify {
-            coronaTestRepository.refresh(type = CoronaTest.Type.PCR)
-            testResultAvailableNotificationService.showTestResultAvailableNotification(testResult)
-            notificationHelper.cancelCurrentNotification(
-                NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
-            )
-            coronaTestRepository.updateResultNotification(any(), sent = true)
-        }
-
-        result shouldBe ListenableWorker.Result.success()
-    }
-
-    @Test
-    fun testSendNotificationWhenInvalid() = runBlockingTest {
-        val testResult = CoronaTestResult.PCR_INVALID
-        coronaTestFlow.value = setOf(newCoronaTest(result = testResult))
-        coEvery { testResultAvailableNotificationService.showTestResultAvailableNotification(testResult) } just Runs
-        coEvery {
-            notificationHelper.cancelCurrentNotification(
-                NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
-            )
-        } just Runs
-
-        val result = createWorker().doWork()
-
-        coVerify {
-            coronaTestRepository.refresh(type = CoronaTest.Type.PCR)
-            testResultAvailableNotificationService.showTestResultAvailableNotification(testResult)
-            notificationHelper.cancelCurrentNotification(
-                NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
-            )
-            coronaTestRepository.updateResultNotification(any(), sent = true)
-        }
-
-        result shouldBe ListenableWorker.Result.success()
-    }
-
-    @Test
-    fun testSendNoNotificationWhenPending() = runBlockingTest {
-        val testResult = CoronaTestResult.PCR_OR_RAT_PENDING
-        coronaTestFlow.value = setOf(newCoronaTest(result = testResult))
-        coEvery { testResultAvailableNotificationService.showTestResultAvailableNotification(testResult) } just Runs
-        coEvery {
-            notificationHelper.cancelCurrentNotification(
-                NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
-            )
-        } just Runs
-
-        val result = createWorker().doWork()
-
-        coVerify { coronaTestRepository.refresh(type = CoronaTest.Type.PCR) }
-        coVerify(exactly = 0) {
-            testResultAvailableNotificationService.showTestResultAvailableNotification(
-                testResult
-            )
-            notificationHelper.cancelCurrentNotification(
-                NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
-            )
-            testResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = false)
-        }
-
-        result shouldBe ListenableWorker.Result.success()
-    }
-
-    @Test
-    fun testRetryWhenExceptionIsThrown() = runBlockingTest {
-        coronaTestFlow.value = setOf(newCoronaTest())
-        coEvery { coronaTestRepository.refresh(any()) } throws Exception()
-
-        val result = createWorker().doWork()
-
-        coVerify(exactly = 1) { coronaTestRepository.refresh(type = CoronaTest.Type.PCR) }
-        coVerify(exactly = 0) { testResultScheduler.setPcrPeriodicTestPollingEnabled(any()) }
-        result shouldBe ListenableWorker.Result.retry()
-    }
-}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/PCRResultRetrievalWorkerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/PCRResultRetrievalWorkerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..605a6d9206f0ce5843b39ae809cc748da4d7b4c7
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/worker/PCRResultRetrievalWorkerTest.kt
@@ -0,0 +1,119 @@
+package de.rki.coronawarnapp.worker
+
+import android.content.Context
+import androidx.work.ListenableWorker
+import androidx.work.WorkRequest
+import androidx.work.WorkerParameters
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
+import de.rki.coronawarnapp.coronatest.type.pcr.execution.PCRResultRetrievalWorker
+import de.rki.coronawarnapp.coronatest.type.pcr.execution.PCRResultScheduler
+import de.rki.coronawarnapp.notification.GeneralNotifications
+import de.rki.coronawarnapp.util.TimeStamper
+import de.rki.coronawarnapp.util.di.AppInjector
+import de.rki.coronawarnapp.util.di.ApplicationComponent
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptedPreferencesFactory
+import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.Runs
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.impl.annotations.RelaxedMockK
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.mockkObject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.test.runBlockingTest
+import org.joda.time.Instant
+import org.junit.Before
+import org.junit.Test
+import testhelpers.BaseTest
+
+class PCRResultRetrievalWorkerTest : BaseTest() {
+    @MockK lateinit var context: Context
+    @MockK lateinit var request: WorkRequest
+    @MockK lateinit var notificationHelper: GeneralNotifications
+    @MockK lateinit var appComponent: ApplicationComponent
+    @MockK lateinit var encryptedPreferencesFactory: EncryptedPreferencesFactory
+    @MockK lateinit var encryptionErrorResetTool: EncryptionErrorResetTool
+    @MockK lateinit var timeStamper: TimeStamper
+    @MockK lateinit var coronaTestRepository: CoronaTestRepository
+    @MockK lateinit var testResultScheduler: PCRResultScheduler
+
+    @RelaxedMockK lateinit var workerParams: WorkerParameters
+    private val currentInstant = Instant.ofEpochSecond(1611764225)
+    private val testToken = "test token"
+
+    private val coronaTestFlow = MutableStateFlow(emptySet<CoronaTest>())
+
+    @Before
+    fun setUp() {
+        MockKAnnotations.init(this)
+        every { timeStamper.nowUTC } returns currentInstant
+
+        mockkObject(AppInjector)
+        every { AppInjector.component } returns appComponent
+        every { appComponent.encryptedPreferencesFactory } returns encryptedPreferencesFactory
+        every { appComponent.errorResetTool } returns encryptionErrorResetTool
+
+        coEvery { testResultScheduler.setPcrPeriodicTestPollingEnabled(enabled = any()) } just Runs
+
+        every { notificationHelper.cancelCurrentNotification(any()) } just Runs
+
+        coronaTestRepository.apply {
+            every { coronaTests } answers { coronaTestFlow }
+            coEvery { refresh(any()) } coAnswers { coronaTestFlow.first() }
+            coEvery { updateResultNotification(identifier = any(), sent = any()) } just Runs
+        }
+    }
+
+    private fun newCoronaTest(
+        registered: Instant = currentInstant,
+        viewed: Boolean = false,
+        result: CoronaTestResult = CoronaTestResult.PCR_POSITIVE,
+        isNotificationSent: Boolean = false,
+    ): CoronaTest {
+        return mockk<PCRCoronaTest>().apply {
+            every { identifier } returns ""
+            every { type } returns CoronaTest.Type.PCR
+            every { registeredAt } returns registered
+            every { isViewed } returns viewed
+            every { testResult } returns result
+            every { registrationToken } returns testToken
+            every { isResultAvailableNotificationSent } returns isNotificationSent
+        }
+    }
+
+    private fun createWorker() = PCRResultRetrievalWorker(
+        context = context,
+        workerParams = workerParams,
+        coronaTestRepository = coronaTestRepository,
+    )
+
+    @Test
+    fun testSuccess() = runBlockingTest {
+        coronaTestFlow.value = setOf(newCoronaTest())
+
+        val result = createWorker().doWork()
+
+        coVerify(exactly = 1) { coronaTestRepository.refresh(type = CoronaTest.Type.PCR) }
+        result shouldBe ListenableWorker.Result.success()
+    }
+
+    @Test
+    fun testRetryWhenExceptionIsThrown() = runBlockingTest {
+        coronaTestFlow.value = setOf(newCoronaTest())
+        coEvery { coronaTestRepository.refresh(any()) } throws Exception()
+
+        val result = createWorker().doWork()
+
+        coVerify(exactly = 1) { coronaTestRepository.refresh(type = CoronaTest.Type.PCR) }
+        result shouldBe ListenableWorker.Result.retry()
+    }
+}