diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt
index 34f8be0bb2a6df2029de72f0de6a2888206da592..4cf07f10e528732e5e7c71c6fc973c3cfb792983 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt
@@ -3,13 +3,10 @@ package de.rki.coronawarnapp.datadonation.analytics.modules.registeredtest
 import de.rki.coronawarnapp.datadonation.analytics.common.calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration
 import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule
 import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings
-import de.rki.coronawarnapp.risk.RiskLevelSettings
-import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
 import de.rki.coronawarnapp.submission.SubmissionSettings
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.formatter.TestResult
-import kotlinx.coroutines.flow.first
 import org.joda.time.Duration
 import org.joda.time.Instant
 import timber.log.Timber
@@ -19,8 +16,6 @@ import javax.inject.Singleton
 @Singleton
 class TestResultDonor @Inject constructor(
     private val testResultDonorSettings: TestResultDonorSettings,
-    private val riskLevelSettings: RiskLevelSettings,
-    private val riskLevelStorage: RiskLevelStorage,
     private val timeStamper: TimeStamper,
     private val submissionSettings: SubmissionSettings
 ) : DonorModule {
@@ -28,42 +23,66 @@ class TestResultDonor @Inject constructor(
     override suspend fun beginDonation(request: DonorModule.Request): DonorModule.Contribution {
         val scannedAfterConsent = testResultDonorSettings.testScannedAfterConsent.value
         if (!scannedAfterConsent) {
-            Timber.d("Skipping TestResultMetadata donation (testScannedAfterConsent=%s)", scannedAfterConsent)
+            Timber.d("Skipping TestResultMetadata donation (scannedAfterConsent=%s)", scannedAfterConsent)
             return TestResultMetadataNoContribution
         }
 
         val timestampAtRegistration = submissionSettings.initialTestResultReceivedAt
-
         if (timestampAtRegistration == null) {
-            Timber.d("Skipping TestResultMetadata donation timestampAtRegistration isn't found")
+            Timber.d("Skipping TestResultMetadata donation (timestampAtRegistration is missing)")
             return TestResultMetadataNoContribution
         }
 
-        val configHours = request
-            .currentConfig
-            .analytics
-            .hoursSinceTestRegistrationToSubmitTestResultMetadata
-
-        val hoursSinceTestRegistrationTime = Duration(timestampAtRegistration, timeStamper.nowUTC).standardHours.toInt()
-        val isDiffHoursMoreThanConfigHoursForPendingTest = hoursSinceTestRegistrationTime >= configHours
+        val testResultAtRegistration = testResultDonorSettings.testResultAtRegistration.value
+        if (testResultAtRegistration == null) {
+            Timber.d("Skipping TestResultMetadata donation (testResultAtRegistration is missing)")
+            return TestResultMetadataNoContribution
+        }
 
-        val testResultAtRegistration =
-            testResultDonorSettings.testResultAtRegistration.value ?: return TestResultMetadataNoContribution
+        val lastChangeCheckedRiskLevelTimestamp = testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel.value
+        if (lastChangeCheckedRiskLevelTimestamp == null) {
+            Timber.d("Skipping TestResultMetadata donation (lastChangeCheckedRiskLevelTimestamp is missing)")
+            return TestResultMetadataNoContribution
+        }
 
         val daysSinceMostRecentDateAtRiskLevelAtTestRegistration =
             calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
-                riskLevelSettings.lastChangeCheckedRiskLevelTimestamp,
+                lastChangeCheckedRiskLevelTimestamp,
                 timestampAtRegistration
             )
 
+        Timber.i(
+            "daysSinceMostRecentDateAtRiskLevelAtTestRegistration: %s",
+            daysSinceMostRecentDateAtRiskLevelAtTestRegistration
+        )
+
         val riskLevelAtRegistration = testResultDonorSettings.riskLevelAtTestRegistration.value
+        val highRiskResultCalculatedAt = testResultDonorSettings.riskLevelTurnedRedTime.value
 
         val hoursSinceHighRiskWarningAtTestRegistration =
             if (riskLevelAtRegistration == PpaData.PPARiskLevel.RISK_LEVEL_LOW) {
                 DEFAULT_HOURS_SINCE_HIGH_RISK_WARNING
             } else {
-                calculatedHoursSinceHighRiskWarning(timestampAtRegistration)
+                if (highRiskResultCalculatedAt == null) {
+                    Timber.d("Skipping TestResultMetadata donation (highRiskResultCalculatedAt is missing)")
+                    return TestResultMetadataNoContribution
+                }
+
+                Timber.i(
+                    "highRiskResultCalculatedAt: %s, timestampAtRegistration: %s",
+                    highRiskResultCalculatedAt,
+                    timestampAtRegistration
+                )
+                calculatedHoursSinceHighRiskWarning(highRiskResultCalculatedAt, timestampAtRegistration)
             }
+        Timber.i(
+            "hoursSinceHighRiskWarningAtTestRegistration: %s",
+            hoursSinceHighRiskWarningAtTestRegistration
+        )
+
+        val configHours = request.currentConfig.analytics.hoursSinceTestRegistrationToSubmitTestResultMetadata
+        val hoursSinceTestRegistrationTime = Duration(timestampAtRegistration, timeStamper.nowUTC).standardHours.toInt()
+        val isDiffHoursMoreThanConfigHoursForPendingTest = hoursSinceTestRegistrationTime >= configHours
 
         return when {
             /**
@@ -134,8 +153,13 @@ class TestResultDonor @Inject constructor(
     ): DonorModule.Contribution {
         val finalTestResultReceivedAt = testResultDonorSettings.finalTestResultReceivedAt.value
         val hoursSinceTestRegistrationTime = if (finalTestResultReceivedAt != null) {
-            Duration(registrationTime, finalTestResultReceivedAt).standardHours.toInt()
+            Timber.i("finalTestResultReceivedAt: %s", finalTestResultReceivedAt)
+            Timber.i("registrationTime: %s", registrationTime)
+            Duration(registrationTime, finalTestResultReceivedAt).standardHours.toInt().also {
+                Timber.i("Calculated hoursSinceTestRegistrationTime: %s", it)
+            }
         } else {
+            Timber.i("Default hoursSinceTestRegistrationTime")
             DEFAULT_HOURS_SINCE_TEST_REGISTRATION_TIME
         }
 
@@ -153,14 +177,10 @@ class TestResultDonor @Inject constructor(
         return TestResultMetadataContribution(testResultMetaData, ::cleanUp)
     }
 
-    private suspend fun calculatedHoursSinceHighRiskWarning(registrationTime: Instant): Int {
-        val highRiskResultCalculatedAt = riskLevelStorage
-            .latestAndLastSuccessful
-            .first()
-            .filter { it.isIncreasedRisk }
-            .minByOrNull { it.calculatedAt }
-            ?.calculatedAt ?: return DEFAULT_HOURS_SINCE_HIGH_RISK_WARNING
-
+    private fun calculatedHoursSinceHighRiskWarning(
+        highRiskResultCalculatedAt: Instant,
+        registrationTime: Instant
+    ): Int {
         return Duration(
             highRiskResultCalculatedAt,
             registrationTime
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/TestResultDonorSettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/TestResultDonorSettings.kt
index 11b76710c64c003c3c22715ce996e2afaee6d2f3..ccc15cb891da84070ffc49410ffcb03cc6acafff 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/TestResultDonorSettings.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/storage/TestResultDonorSettings.kt
@@ -65,6 +65,34 @@ class TestResultDonorSettings @Inject constructor(
         }
     )
 
+    val mostRecentDateWithHighOrLowRiskLevel = prefs.createFlowPreference(
+        key = PREFS_KEY_MOST_RECENT_WITH_HIGH_OR_LOW_RISK_LEVEL,
+        reader = { key ->
+            getLong(key, 0L).let {
+                if (it != 0L) {
+                    Instant.ofEpochMilli(it)
+                } else null
+            }
+        },
+        writer = { key, value ->
+            putLong(key, value?.millis ?: 0L)
+        }
+    )
+
+    val riskLevelTurnedRedTime = prefs.createFlowPreference(
+        key = PREFS_KEY_RISK_LEVEL_TURNED_RED_TIME,
+        reader = { key ->
+            getLong(key, 0L).let {
+                if (it != 0L) {
+                    Instant.ofEpochMilli(it)
+                } else null
+            }
+        },
+        writer = { key, value ->
+            putLong(key, value?.millis ?: 0L)
+        }
+    )
+
     fun saveTestResultDonorDataAtRegistration(testResult: TestResult, lastRiskResult: RiskLevelResult) {
         testScannedAfterConsent.update { true }
         testResultAtRegistration.update { testResult }
@@ -82,5 +110,8 @@ class TestResultDonorSettings @Inject constructor(
         private const val PREFS_KEY_TEST_RESULT_AT_REGISTRATION = "testResultDonor.testResultAtRegistration"
         private const val PREFS_KEY_RISK_LEVEL_AT_REGISTRATION = "testResultDonor.riskLevelAtRegistration"
         private const val PREFS_KEY_FINAL_TEST_RESULT_RECEIVED_AT = "testResultDonor.finalTestResultReceivedAt"
+        private const val PREFS_KEY_RISK_LEVEL_TURNED_RED_TIME = "testResultDonor.riskLevelTurnedRedTime"
+        private const val PREFS_KEY_MOST_RECENT_WITH_HIGH_OR_LOW_RISK_LEVEL =
+            "testResultDonor.mostRecentWithHighOrLowRiskLevel"
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetector.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetector.kt
index 8a6fe31799602ee50ff2aabe8522054b497c6d00..fbee2b6d4a04294dee741b7565c18047c0cb5631 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetector.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetector.kt
@@ -4,6 +4,7 @@ import android.content.Context
 import androidx.annotation.VisibleForTesting
 import androidx.core.app.NotificationManagerCompat
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings
 import de.rki.coronawarnapp.datadonation.survey.Surveys
 import de.rki.coronawarnapp.notification.NotificationConstants.NEW_MESSAGE_RISK_LEVEL_SCORE_NOTIFICATION_ID
 import de.rki.coronawarnapp.notification.NotificationHelper
@@ -34,7 +35,8 @@ class RiskLevelChangeDetector @Inject constructor(
     private val notificationHelper: NotificationHelper,
     private val surveys: Surveys,
     private val submissionSettings: SubmissionSettings,
-    private val tracingSettings: TracingSettings
+    private val tracingSettings: TracingSettings,
+    private val testResultDonorSettings: TestResultDonorSettings
 ) {
 
     fun launch() {
@@ -65,9 +67,54 @@ class RiskLevelChangeDetector @Inject constructor(
 
         val oldRiskState = oldResult.riskState
         val newRiskState = newResult.riskState
-
         Timber.d("Last state was $oldRiskState and current state is $newRiskState")
 
+        // Check sending a notification when risk level changes
+        checkSendingNotification(oldRiskState, newRiskState)
+
+        // Save Survey related data based on the risk state
+        saveSurveyRiskState(oldRiskState, newRiskState, newResult)
+
+        // Save TestDonor risk level timestamps
+        saveTestDonorRiskLevelAnalytics(newResult)
+    }
+
+    private fun saveTestDonorRiskLevelAnalytics(
+        newRiskState: RiskLevelResult
+    ) {
+        // Save riskLevelTurnedRedTime if not already set before for high risk detection
+        Timber.i("riskLevelTurnedRedTime=%s", testResultDonorSettings.riskLevelTurnedRedTime.value)
+        if (testResultDonorSettings.riskLevelTurnedRedTime.value == null) {
+            if (newRiskState.isIncreasedRisk) {
+                testResultDonorSettings.riskLevelTurnedRedTime.update {
+                    newRiskState.calculatedAt
+                }
+                Timber.i(
+                    "riskLevelTurnedRedTime: newRiskState=%s, riskLevelTurnedRedTime=%s",
+                    newRiskState.riskState,
+                    newRiskState.calculatedAt
+                )
+            }
+        }
+
+        // Save most recent date of high or low risks
+        if (newRiskState.riskState in listOf(RiskState.INCREASED_RISK, RiskState.LOW_RISK)) {
+            Timber.i(
+                "mostRecentDateWithHighOrLowRiskLevel: newRiskState=%s, lastRiskEncounterAt=%s",
+                newRiskState.riskState,
+                newRiskState.lastRiskEncounterAt
+            )
+
+            testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel.update {
+                newRiskState.lastRiskEncounterAt
+            }
+        }
+    }
+
+    private suspend fun checkSendingNotification(
+        oldRiskState: RiskState,
+        newRiskState: RiskState
+    ) {
         if (hasHighLowLevelChanged(oldRiskState, newRiskState) && !submissionSettings.isSubmissionSuccessful) {
             Timber.d("Notification Permission = ${notificationManagerCompat.areNotificationsEnabled()}")
 
@@ -82,7 +129,13 @@ class RiskLevelChangeDetector @Inject constructor(
 
             Timber.d("Risk level changed and notification sent. Current Risk level is $newRiskState")
         }
+    }
 
+    private fun saveSurveyRiskState(
+        oldRiskState: RiskState,
+        newRiskState: RiskState,
+        newResult: RiskLevelResult
+    ) {
         if (oldRiskState == RiskState.INCREASED_RISK && newRiskState == RiskState.LOW_RISK) {
             tracingSettings.isUserToBeNotifiedOfLoweredRiskLevel.update { true }
             Timber.d("Risk level changed LocalData is updated. Current Risk level is $newRiskState")
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonorTest.kt
index f128a602166778abbbcae049ec4a8e24a0fefd15..ac97cc321836a06795df3bb79985366634134468 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonorTest.kt
@@ -4,8 +4,6 @@ import de.rki.coronawarnapp.appconfig.AnalyticsConfig
 import de.rki.coronawarnapp.appconfig.ConfigData
 import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule
 import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings
-import de.rki.coronawarnapp.risk.RiskLevelSettings
-import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
 import de.rki.coronawarnapp.submission.SubmissionSettings
 import de.rki.coronawarnapp.util.TimeStamper
@@ -31,8 +29,6 @@ import testhelpers.preferences.mockFlowPreference
 
 class TestResultDonorTest : BaseTest() {
     @MockK lateinit var testResultDonorSettings: TestResultDonorSettings
-    @MockK lateinit var riskLevelSettings: RiskLevelSettings
-    @MockK lateinit var riskLevelStorage: RiskLevelStorage
     @MockK lateinit var timeStamper: TimeStamper
     @MockK lateinit var submissionSettings: SubmissionSettings
 
@@ -43,16 +39,16 @@ class TestResultDonorTest : BaseTest() {
     @BeforeEach
     fun setUp() {
         MockKAnnotations.init(this, true)
+        with(testResultDonorSettings) {
+            every { mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(baseTime)
+            every { riskLevelTurnedRedTime } returns mockFlowPreference(baseTime)
+            every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_LOW)
+        }
         every { timeStamper.nowUTC } returns baseTime
-        every { riskLevelSettings.lastChangeCheckedRiskLevelTimestamp } returns baseTime
-        every { testResultDonorSettings.riskLevelAtTestRegistration } returns
-            mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_LOW)
         every { submissionSettings.initialTestResultReceivedAt } returns baseTime
 
         testResultDonor = TestResultDonor(
             testResultDonorSettings,
-            riskLevelSettings,
-            riskLevelStorage,
             timeStamper,
             submissionSettings
         )
@@ -108,7 +104,9 @@ class TestResultDonorTest : BaseTest() {
 
             val timeDayBefore = baseTime.minus(Duration.standardDays(1))
             every { submissionSettings.initialTestResultReceivedAt } returns timeDayBefore
-            every { riskLevelSettings.lastChangeCheckedRiskLevelTimestamp } returns timeDayBefore
+            every { testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(
+                timeDayBefore
+            )
 
             val donation = testResultDonor.beginDonation(TestRequest)
             donation.shouldBeInstanceOf<TestResultDonor.TestResultMetadataContribution>()
@@ -141,6 +139,86 @@ class TestResultDonorTest : BaseTest() {
         }
     }
 
+    @Test
+    fun `No donation when test is  POSITIVE and HighRisk but riskLevelTurnedRedTime is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.POSITIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(null)
+                every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
+    @Test
+    fun `No donation when test is NEGATIVE and HighRisk but riskLevelTurnedRedTime is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.NEGATIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(null)
+                every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
+    @Test
+    fun `No donation when test is  POSITIVE and HighRisk but mostRecentDateWithHighOrLowRiskLevel is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.POSITIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(baseTime)
+                every { mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(null)
+                every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
+    @Test
+    fun `No donation when test is NEGATIVE and HighRisk but mostRecentDateWithHighOrLowRiskLevel is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.NEGATIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(baseTime)
+                every { mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(null)
+                every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
+    @Test
+    fun `No donation when test is  POSITIVE and LowRisk but mostRecentDateWithHighOrLowRiskLevel is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.POSITIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(null)
+                every { mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(null)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
+    @Test
+    fun `No donation when test is NEGATIVE and LowRisk but mostRecentDateWithHighOrLowRiskLevel is missing`() =
+        runBlockingTest {
+            with(testResultDonorSettings) {
+                every { testScannedAfterConsent } returns mockFlowPreference(true)
+                every { testResultAtRegistration } returns mockFlowPreference(TestResult.NEGATIVE)
+                every { finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
+                every { riskLevelTurnedRedTime } returns mockFlowPreference(null)
+                every { mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(null)
+            }
+            testResultDonor.beginDonation(TestRequest) shouldBe TestResultDonor.TestResultMetadataNoContribution
+        }
+
     @Test
     fun `Donation is collected when test result is NEGATIVE`() {
         runBlockingTest {
@@ -160,6 +238,61 @@ class TestResultDonorTest : BaseTest() {
         }
     }
 
+    @Test
+    fun `Scenario 1 LowRisk`() = runBlockingTest {
+        with(testResultDonorSettings) {
+            every { testScannedAfterConsent } returns mockFlowPreference(true)
+            every { testResultAtRegistration } returns mockFlowPreference(TestResult.NEGATIVE)
+            every { finalTestResultReceivedAt } returns mockFlowPreference(
+                Instant.parse("2021-03-20T20:00:00Z")
+            )
+            every { riskLevelTurnedRedTime } returns mockFlowPreference(null) // No High risk
+            every { mostRecentDateWithHighOrLowRiskLevel } returns
+                mockFlowPreference(Instant.parse("2021-03-18T00:00:00Z"))
+            every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_LOW)
+        }
+        every { timeStamper.nowUTC } returns Instant.parse("2021-03-20T00:00:00Z")
+        every { submissionSettings.initialTestResultReceivedAt } returns Instant.parse("2021-03-20T00:00:00Z")
+
+        val donation = testResultDonor.beginDonation(TestRequest)
+        donation.shouldBeInstanceOf<TestResultDonor.TestResultMetadataContribution>()
+        with(donation.testResultMetadata) {
+            testResult shouldBe PpaData.PPATestResult.TEST_RESULT_NEGATIVE
+            hoursSinceTestRegistration shouldBe 20 // hours
+            riskLevelAtTestRegistration shouldBe PpaData.PPARiskLevel.RISK_LEVEL_LOW
+            hoursSinceHighRiskWarningAtTestRegistration shouldBe -1 // expected for low risk
+            daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 2 // days
+        }
+    }
+
+    @Test
+    fun `Scenario 2 HighRisk`() = runBlockingTest {
+        with(testResultDonorSettings) {
+            every { testScannedAfterConsent } returns mockFlowPreference(true)
+            every { testResultAtRegistration } returns mockFlowPreference(TestResult.POSITIVE)
+            every { finalTestResultReceivedAt } returns mockFlowPreference(
+                Instant.parse("2021-03-20T20:00:00Z")
+            )
+            every { riskLevelTurnedRedTime } returns mockFlowPreference(Instant.parse("2021-03-01T00:00:00Z"))
+            every { mostRecentDateWithHighOrLowRiskLevel } returns
+                mockFlowPreference(Instant.parse("2021-03-18T00:00:00Z"))
+            every { riskLevelAtTestRegistration } returns mockFlowPreference(PpaData.PPARiskLevel.RISK_LEVEL_HIGH)
+        }
+
+        every { timeStamper.nowUTC } returns Instant.parse("2021-03-20T00:00:00Z")
+        every { submissionSettings.initialTestResultReceivedAt } returns Instant.parse("2021-03-20T00:00:00Z")
+
+        val donation = testResultDonor.beginDonation(TestRequest)
+        donation.shouldBeInstanceOf<TestResultDonor.TestResultMetadataContribution>()
+        with(donation.testResultMetadata) {
+            testResult shouldBe PpaData.PPATestResult.TEST_RESULT_POSITIVE
+            hoursSinceTestRegistration shouldBe 20 // hours
+            riskLevelAtTestRegistration shouldBe PpaData.PPARiskLevel.RISK_LEVEL_HIGH
+            hoursSinceHighRiskWarningAtTestRegistration shouldBe 456 // 19 days in hours
+            daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 2 // days
+        }
+    }
+
     @Test
     fun deleteData() = runBlockingTest {
         every { testResultDonorSettings.clear() } just Runs
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt
index 13fea4bb9f7b0a2bb24c3848256cfe2431e2ba14..29f1c11c468e47c8e721dd77bb079f5eea69ff7e 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelChangeDetectorTest.kt
@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.risk
 import android.content.Context
 import androidx.core.app.NotificationManagerCompat
 import com.google.android.gms.nearby.exposurenotification.ExposureWindow
+import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings
 import de.rki.coronawarnapp.datadonation.survey.Surveys
 import de.rki.coronawarnapp.notification.NotificationHelper
 import de.rki.coronawarnapp.risk.RiskState.CALCULATION_FAILED
@@ -23,6 +24,7 @@ import io.mockk.coVerifySequence
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
 import io.mockk.just
+import io.mockk.mockk
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runBlockingTest
@@ -43,6 +45,7 @@ class RiskLevelChangeDetectorTest : BaseTest() {
     @MockK lateinit var surveys: Surveys
     @MockK lateinit var submissionSettings: SubmissionSettings
     @MockK lateinit var tracingSettings: TracingSettings
+    @MockK lateinit var testResultDonorSettings: TestResultDonorSettings
 
     @BeforeEach
     fun setup() {
@@ -52,18 +55,27 @@ class RiskLevelChangeDetectorTest : BaseTest() {
         every { submissionSettings.isSubmissionSuccessful } returns false
         every { foregroundState.isInForeground } returns flowOf(true)
         every { notificationManagerCompat.areNotificationsEnabled() } returns true
+
         every { riskLevelSettings.lastChangeCheckedRiskLevelTimestamp = any() } just Runs
         every { riskLevelSettings.lastChangeCheckedRiskLevelTimestamp } returns null
+
+        every { riskLevelSettings.lastChangeToHighRiskLevelTimestamp = any() } just Runs
+        every { riskLevelSettings.lastChangeToHighRiskLevelTimestamp } returns null
+
         coEvery { surveys.resetSurvey(Surveys.Type.HIGH_RISK_ENCOUNTER) } just Runs
+
+        every { testResultDonorSettings.riskLevelTurnedRedTime } returns mockFlowPreference(null)
+        every { testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel } returns mockFlowPreference(null)
     }
 
     private fun createRiskLevel(
         riskState: RiskState,
-        calculatedAt: Instant = Instant.EPOCH
+        calculatedAt: Instant = Instant.EPOCH,
+        aggregatedRiskResult: AggregatedRiskResult? = null
     ): RiskLevelResult = object : RiskLevelResult {
         override val riskState: RiskState = riskState
         override val calculatedAt: Instant = calculatedAt
-        override val aggregatedRiskResult: AggregatedRiskResult? = null
+        override val aggregatedRiskResult: AggregatedRiskResult? = aggregatedRiskResult
         override val failureReason: RiskLevelResult.FailureReason? = null
         override val exposureWindows: List<ExposureWindow>? = null
         override val matchedKeyCount: Int = 0
@@ -80,7 +92,8 @@ class RiskLevelChangeDetectorTest : BaseTest() {
         notificationHelper = notificationHelper,
         surveys = surveys,
         submissionSettings = submissionSettings,
-        tracingSettings = tracingSettings
+        tracingSettings = tracingSettings,
+        testResultDonorSettings = testResultDonorSettings
     )
 
     @Test
@@ -191,6 +204,89 @@ class RiskLevelChangeDetectorTest : BaseTest() {
         }
     }
 
+    @Test
+    fun `riskLevelTurnedRedTime is only set once`() {
+        testResultDonorSettings.riskLevelTurnedRedTime.update { Instant.EPOCH.plus(1) }
+
+        every { riskLevelStorage.latestRiskLevelResults } returns flowOf(
+            listOf(
+                createRiskLevel(
+                    INCREASED_RISK,
+                    calculatedAt = Instant.EPOCH.plus(2),
+                    aggregatedRiskResult = mockk<AggregatedRiskResult>().apply {
+                        every { isIncreasedRisk() } returns true
+                    }
+                ),
+                createRiskLevel(LOW_RISK, calculatedAt = Instant.EPOCH)
+            )
+        )
+
+        runBlockingTest {
+            val instance = createInstance(scope = this)
+            instance.launch()
+            advanceUntilIdle()
+        }
+
+        testResultDonorSettings.riskLevelTurnedRedTime.value shouldBe Instant.EPOCH.plus(1)
+
+        testResultDonorSettings.riskLevelTurnedRedTime.update { null }
+
+        runBlockingTest {
+            val instance = createInstance(scope = this)
+            instance.launch()
+            advanceUntilIdle()
+        }
+
+        testResultDonorSettings.riskLevelTurnedRedTime.value shouldBe Instant.EPOCH.plus(2)
+    }
+
+    @Test
+    fun `mostRecentDateWithHighOrLowRiskLevel is updated every time`() {
+        every { riskLevelStorage.latestRiskLevelResults } returns flowOf(
+            listOf(
+                createRiskLevel(
+                    INCREASED_RISK,
+                    calculatedAt = Instant.EPOCH.plus(1),
+                    aggregatedRiskResult = mockk<AggregatedRiskResult>().apply {
+                        every { mostRecentDateWithHighRisk } returns Instant.EPOCH.plus(10)
+                        every { isIncreasedRisk() } returns true
+                    }
+                ),
+                createRiskLevel(LOW_RISK, calculatedAt = Instant.EPOCH)
+            )
+        )
+
+        runBlockingTest {
+            val instance = createInstance(scope = this)
+            instance.launch()
+            advanceUntilIdle()
+        }
+
+        testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel.value shouldBe Instant.EPOCH.plus(10)
+
+        every { riskLevelStorage.latestRiskLevelResults } returns flowOf(
+            listOf(
+                createRiskLevel(
+                    INCREASED_RISK,
+                    calculatedAt = Instant.EPOCH.plus(1),
+                    aggregatedRiskResult = mockk<AggregatedRiskResult>().apply {
+                        every { mostRecentDateWithLowRisk } returns Instant.EPOCH.plus(20)
+                        every { isIncreasedRisk() } returns false
+                    }
+                ),
+                createRiskLevel(LOW_RISK, calculatedAt = Instant.EPOCH)
+            )
+        )
+
+        runBlockingTest {
+            val instance = createInstance(scope = this)
+            instance.launch()
+            advanceUntilIdle()
+        }
+
+        testResultDonorSettings.mostRecentDateWithHighOrLowRiskLevel.value shouldBe Instant.EPOCH.plus(20)
+    }
+
     @Test
     fun `evaluate risk level change detection function`() {
         RiskLevelChangeDetector.hasHighLowLevelChanged(CALCULATION_FAILED, CALCULATION_FAILED) shouldBe false