diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 334cbf113bc1c42348ed76a582f1ddacf28ddb5e..098fe846891336dbe9c4465f59ebbba03506e4f1 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -1,6 +1,6 @@
 <component name="ProjectCodeStyleConfiguration">
   <code_scheme name="Project" version="173">
-     <JetCodeStyleSettings>
+    <JetCodeStyleSettings>
       <option name="PACKAGES_TO_USE_STAR_IMPORTS">
         <value>
           <package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
diff --git a/CODEOWNERS b/CODEOWNERS
index 8111becb3ac79ded1372847d6f8367bbe784c836..889237e4267d9de3958cc27f4e0801d0fad009cc 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -8,4 +8,4 @@
 * @corona-warn-app/cwa-app-android-maintainers
 
 # Code Onwer of all german texts
-/Corona-Warn-App/src/main/res/values-de/ @janetback
+/Corona-Warn-App/src/main/res/values-de/ @janetback @SabineLoss
diff --git a/Corona-Warn-App/build.gradle b/Corona-Warn-App/build.gradle
index 63c99edc3af68ee60b7955e94f4c8376e34b8a96..ddaef139c82a02a59c2aa5b32912f9259dacab1a 100644
--- a/Corona-Warn-App/build.gradle
+++ b/Corona-Warn-App/build.gradle
@@ -248,6 +248,8 @@ dependencies {
     implementation 'android.arch.lifecycle:extensions:2.2.0'
     implementation 'androidx.lifecycle:lifecycle-common-java8:2.2.0'
     implementation 'androidx.annotation:annotation:1.1.0'
+    implementation "androidx.recyclerview:recyclerview:1.1.0"
+    implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc02"
 
     implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
 
diff --git a/Corona-Warn-App/config/detekt.yml b/Corona-Warn-App/config/detekt.yml
index 2555aa687375ea096032184e62adfedd4ce03604..5a483363dc80a7702453dac0b684dd37b27b49ec 100644
--- a/Corona-Warn-App/config/detekt.yml
+++ b/Corona-Warn-App/config/detekt.yml
@@ -100,7 +100,7 @@ complexity:
     ignoreStringsRegex: '$^'
   TooManyFunctions:
     active: true
-    excludes: ['**/test/**', '**/androidTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt', '**/LocalData.kt', '**/formatter/*Helper.kt']
+    excludes: ['**/test/**', '**/androidTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt', '**/LocalData.kt', '**/formatter/*Helper.kt', '**/*ViewModel.kt']
     thresholdInFiles: 20
     thresholdInClasses: 20
     thresholdInInterfaces: 20
diff --git a/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/ui/main/MainFragment.kt b/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/ui/main/MainFragment.kt
index a6a339419ee9e366314f67cad85d81345bf607a4..171a19992a864283016e7b49c24059c66701dc29 100644
--- a/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/ui/main/MainFragment.kt
+++ b/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/ui/main/MainFragment.kt
@@ -133,7 +133,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {
     private fun toSubmissionIntro() {
         findNavController().doNavigate(
             MainFragmentDirections.actionMainFragmentToSubmissionIntroFragment()
-        )
+            )
     }
 
     private fun showPopup(view: View) {
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt
index f7094337bcd777cb4f52ec1e89e2fface92cbe1c..35fda975f43568685d84bbb8c441212b1c08aeb6 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt
@@ -32,6 +32,7 @@ import com.google.zxing.BarcodeFormat
 import com.google.zxing.integration.android.IntentIntegrator
 import com.google.zxing.integration.android.IntentResult
 import com.google.zxing.qrcode.QRCodeWriter
+import de.rki.coronawarnapp.CoronaWarnApplication
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.RiskLevelAndKeyRetrievalBenchmark
 import de.rki.coronawarnapp.databinding.FragmentTestForAPIBinding
@@ -62,6 +63,7 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
 import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.*
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import org.joda.time.DateTime
@@ -92,6 +94,10 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i),
         }
     }
 
+    private val enfClient by lazy {
+        AppInjector.component.enfClient
+    }
+
     private var myExposureKeysJSON: String? = null
     private var myExposureKeys: List<TemporaryExposureKey>? = mutableListOf()
     private var otherExposureKey: AppleLegacyKeyExchange.Key? = null
@@ -278,6 +284,51 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i),
             }
             false
         }
+
+        binding.testLogfileToggle.isChecked = CoronaWarnApplication.fileLogger?.isLogging ?: false
+        binding.testLogfileToggle.setOnClickListener { buttonView ->
+            CoronaWarnApplication.fileLogger?.let {
+                if (binding.testLogfileToggle.isChecked) {
+                    it.start()
+                } else {
+                    it.stop()
+                }
+            }
+        }
+
+        binding.testLogfileShare.setOnClickListener {
+            CoronaWarnApplication.fileLogger?.let {
+                lifecycleScope.launch {
+                    val targetPath = withContext(Dispatchers.IO) {
+                        async {
+                            if (!it.logFile.exists()) return@async null
+
+                            val externalPath = File(
+                                requireContext().getExternalFilesDir(null),
+                                "LogFile-${System.currentTimeMillis()}.log"
+                            )
+
+                            it.logFile.copyTo(externalPath)
+
+                            return@async externalPath
+                        }
+                    }.await()
+                    if (targetPath != null) {
+                        Toast.makeText(
+                            requireActivity(),
+                            "Logfile copied to $targetPath",
+                            Toast.LENGTH_SHORT
+                        ).show()
+                    } else {
+                        Toast.makeText(
+                            requireActivity(),
+                            "No log file available",
+                            Toast.LENGTH_SHORT
+                        ).show()
+                    }
+                }
+            }
+        }
     }
 
     override fun onResume() {
@@ -434,7 +485,7 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i),
                 Timber.i("Provide ${googleFileList.count()} files with ${appleKeyList.size} keys with token $token")
                 try {
                     // only testing implementation: this is used to wait for the broadcastreceiver of the OS / EN API
-                    InternalExposureNotificationClient.asyncProvideDiagnosisKeys(
+                    enfClient.provideDiagnosisKeys(
                         googleFileList,
                         ApplicationConfigurationService.asyncRetrieveExposureConfiguration(),
                         token!!
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 5628d6c968e6d6870818ee6cca169335f89d306f..7ba08ef6d67382d462fb1beca3af4f1519a90491 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
@@ -5,13 +5,12 @@ import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.SavedStateHandle
 import androidx.lifecycle.viewModelScope
 import com.google.android.gms.nearby.exposurenotification.ExposureInformation
-import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
 import com.squareup.inject.assisted.Assisted
 import com.squareup.inject.assisted.AssistedInject
 import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository
 import de.rki.coronawarnapp.exception.ExceptionCategory
-import de.rki.coronawarnapp.exception.TransactionException
 import de.rki.coronawarnapp.exception.reporting.report
+import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.risk.DefaultRiskLevelCalculation
 import de.rki.coronawarnapp.risk.RiskLevel
@@ -43,7 +42,7 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
     @Assisted private val handle: SavedStateHandle,
     @Assisted private val exampleArg: String?,
     private val context: Context, // App context
-    private val exposureNotificationClient: ExposureNotificationClient,
+    private val enfClient: ENFClient,
     private val keyCacheRepository: KeyCacheRepository
 ) : CWAViewModel() {
 
@@ -63,7 +62,7 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
             try {
                 RetrieveDiagnosisKeysTransaction.start()
                 calculateRiskLevel()
-            } catch (e: TransactionException) {
+            } catch (e: Exception) {
                 e.report(ExceptionCategory.INTERNAL)
             }
         }
@@ -73,7 +72,7 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
         viewModelScope.launch {
             try {
                 RiskLevelTransaction.start()
-            } catch (e: TransactionException) {
+            } catch (e: Exception) {
                 e.report(ExceptionCategory.INTERNAL)
             }
         }
@@ -218,7 +217,7 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
 
     private suspend fun asyncGetExposureInformation(token: String): List<ExposureInformation> =
         suspendCoroutine { cont ->
-            exposureNotificationClient.getExposureInformation(token)
+            enfClient.internalClient.getExposureInformation(token)
                 .addOnSuccessListener {
                     cont.resume(it)
                 }.addOnFailureListener {
@@ -261,7 +260,7 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
             Timber.i("Provide ${googleFileList.count()} files with ${appleKeyList.size} keys with token $token")
             try {
                 // only testing implementation: this is used to wait for the broadcastreceiver of the OS / EN API
-                InternalExposureNotificationClient.asyncProvideDiagnosisKeys(
+                enfClient.provideDiagnosisKeys(
                     googleFileList,
                     ApplicationConfigurationService.asyncRetrieveExposureConfiguration(),
                     token
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_for_a_p_i.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_for_a_p_i.xml
index 09ac74915257e9d58fbf690dc376ebd8e419ac2a..8c7d43bdaec80f9a104bd018f5a2145f27ce01ec 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_for_a_p_i.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_for_a_p_i.xml
@@ -22,11 +22,17 @@
             android:layout_margin="@dimen/spacing_normal"
             android:orientation="vertical">
 
+            <de.rki.coronawarnapp.ui.calendar.CalendarView
+                android:id="@+id/calendar_container"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+
             <TextView
                 android:id="@+id/label_googlePlayServices_version"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content" />
 
+
             <Switch
                 android:id="@+id/test_api_switch_last_three_hours_from_server"
                 style="@style/body1"
@@ -43,6 +49,27 @@
                 android:text="@string/test_api_switch_background_notifications"
                 android:theme="@style/switchBase" />
 
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:orientation="horizontal"
+                android:layout_height="wrap_content">
+
+                <Switch
+                    android:id="@+id/test_logfile_toggle"
+                    style="@style/body1"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Logfile enabled"
+                    android:theme="@style/switchBase" />
+
+                <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/test_logfile_share"
+                    android:text="Share log" />
+
+            </LinearLayout>
+
             <TextView
                 android:id="@+id/label_exposure_summary"
                 style="@style/headline6"
diff --git a/Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml b/Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml
index 43fb6ab2caa3ce823f5a146236074240695ab3f8..89a9fb400b43b7b803e8ae9433043f7984eb8f8b 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml
@@ -234,8 +234,8 @@
             app:popUpTo="@id/mainFragment"
             app:popUpToInclusive="true" />
         <action
-            android:id="@+id/action_submissionResultFragment_to_submissionResultPositiveOtherWarningFragment"
-            app:destination="@id/submissionResultPositiveOtherWarningFragment" />
+            android:id="@+id/action_submissionResultFragment_to_submissionSymptomIntroductionFragment"
+            app:destination="@id/submissionSymptomIntroductionFragment" />
     </fragment>
 
     <fragment
@@ -323,4 +323,29 @@
             app:argType="string"
             app:nullable="true" />
     </fragment>
+    <fragment
+        android:id="@+id/submissionSymptomIntroductionFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionSymptomIntroductionFragment"
+        android:label="SubmissionSymptomIntroductionFragment" >
+        <action
+            android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionSymptomCalendarFragment"
+            app:destination="@id/submissionSymptomCalendarFragment" />
+        <action
+            android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionResultFragment"
+            app:destination="@id/submissionResultFragment" />
+        <action
+            android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionResultPositiveOtherWarningFragment"
+            app:destination="@id/submissionResultPositiveOtherWarningFragment" />
+    </fragment>
+    <fragment
+        android:id="@+id/submissionSymptomCalendarFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionSymptomCalendarFragment"
+        android:label="SubmissionSymptomCalendarFragment" >
+        <action
+            android:id="@+id/action_submissionCalendarFragment_to_submissionSymptomIntroductionFragment"
+            app:destination="@id/submissionSymptomIntroductionFragment" />
+        <action
+            android:id="@+id/action_submissionSymptomCalendarFragment_to_submissionResultPositiveOtherWarningFragment"
+            app:destination="@id/submissionResultPositiveOtherWarningFragment" />
+    </fragment>
 </navigation>
diff --git a/Corona-Warn-App/src/main/assets/privacy_de.html b/Corona-Warn-App/src/main/assets/privacy_de.html
index d259720849b8dbd04ca0a9f6ebf0258853ed4d54..43a28a5ea27729b881fb63d5e9112899523b98a3 100644
--- a/Corona-Warn-App/src/main/assets/privacy_de.html
+++ b/Corona-Warn-App/src/main/assets/privacy_de.html
@@ -13,77 +13,77 @@
     Damit diese Datenschutzerklärung für alle Nutzer verständlich ist, bemühen
     wir uns um eine einfache und möglichst untechnische Darstellung.
 </p>
-<h2>
+<h1>
     1. Wer stellt Ihnen diese App zur Verfügung?
-</h2>
+</h1>
 <p>
     Der Anbieter der Corona-Warn-App (im Folgenden die „<strong>App</strong>“)
     ist das Robert Koch-Institut, Nordufer 20, 13353 Berlin (im Folgenden „<strong>RKI</strong>“).
-</p>
-<p>
-    Das RKI ist auch der datenschutzrechtlich Verantwortliche für die
-    Verarbeitung von personenbezogenen Daten der App-Nutzer.
+    Das RKI ist auch der datenschutzrechtlich
+    Verantwortliche für die Verarbeitung von personenbezogenen Daten der
+    App-Nutzer.
 </p>
 <p>
     Den Datenschutzbeauftragten des RKI erreichen Sie unter der oben genannten
     Anschrift (zu Händen „Behördlicher Datenschutzbeauftragter“) und per E-Mail
-    an: datenschutz@rki.de).
+    an: datenschutz@rki.de.
 </p>
-<h2>
+<h1>
     2. Ist die Nutzung der App freiwillig?
-</h2>
-<p>
-    Die Benutzung der App basiert ausschließlich auf Freiwilligkeit. Es ist
-    daher allein Ihre Entscheidung, ob und wie Sie die App nutzen.
-</p>
+</h1>
 <p>
-    Auch wenn die Installation und die Benutzung der App freiwillig sind,
-    müssen Sie nach dem erstmaligen Aufruf der App gegenüber dem RKI durch
-    Antippen des Buttons „Risiko-Ermittlung aktivieren“ zustimmen, dass die App
-    im Rahmen der Risiko-Ermittlung Ihre personenbezogenen Daten verarbeiten
-    darf. Falls die App dabei ein Infektionsrisiko für Sie ermittelt, stellen
-    Ihre Daten auch Gesundheitsdaten dar. Ihre Zustimmung ist erforderlich, da
-    andernfalls die App nicht auf die Kontaktaufzeichnungs-Funktion Ihres
-    Smartphones zugreifen kann. Sie können die Risiko-Ermittlung jedoch
-    jederzeit über den Schieberegler innerhalb der App deaktivieren. In diesem
-    Fall stehen Ihnen nicht alle Funktionen der App zur Verfügung. Gesonderte
-    Einwilligungen sind darüber hinaus für die Datenverarbeitung der folgenden
-    Funktionen erforderlich:
+    Die Nutzung der App ist freiwillig. Es ist daher allein Ihre Entscheidung,
+    ob Sie die App installieren und welche Funktionen Sie nutzen. Ihre Daten
+    (zum Beispiel zu Ihren Begegnungen und Ihrem Infektionsrisiko) werden
+    ausschließlich auf Ihrem eigenen Smartphone erzeugt und gespeichert. Eine
+    Weitergabe Ihrer Daten an das RKI, das Betriebssystem Ihres Smartphones
+    oder andere Nutzer findet nur statt, wenn Sie eine der folgenden
+    App-Funktion nutzen und in die jeweils erforderliche Datenweitergabe
+    eingewilligt haben:
 </p>
 <ul>
+    <li>
+        Risiko-Ermittlung (siehe Ziffer 6 a.)
+    </li>
     <li>
         Test registrieren (siehe Ziffer 6 b.)
     </li>
     <li>
-        Testergebnis teilen (siehe Ziffer 6 c.)
+        Andere warnen (siehe Ziffer 6 c.)
     </li>
 </ul>
+<p>
+    Sie sind nicht verpflichtet, diese Funktionen zu nutzen. Wenn Sie sich
+    entscheiden, eine von diesen Funktionen erbetene Einwilligung nicht zu
+    erteilen oder nachträglich zurückzuziehen, entstehen Ihnen keine Nachteile.
+    Sie können dann lediglich die einwilligungsbasierten App-Funktion nicht
+    bzw. nicht mehr nutzen.
+</p>
 <p>
     Die Datenverarbeitung im Rahmen dieser Funktionen wird in den folgenden
     Abschnitten näher beschrieben.
 </p>
-<h2>
+<h1>
     3. Auf welcher Rechtsgrundlage werden Ihre Daten verarbeitet?
-</h2>
+</h1>
 <p>
-    Das RKI verarbeitet Ihre personenbezogenen Daten grundsätzlich nur auf
-    Grundlage einer von Ihnen erteilten Einwilligung nach Artikel 6 Absatz 1
-    Satz 1 Buchstabe a und Artikel 9 Absatz 2 Buchstabe a der
-    Datenschutzgrundverordnung (DSGVO). Sie können eine von Ihnen erteilte
-    Einwilligung jederzeit widerrufen. Weitere Informationen zu Ihrem
-    Widerrufsrecht und Hinweise, wie Sie dieses ausüben können, finden Sie
-    unter Ziffer 11.
+    Das RKI verarbeitet Ihre Daten grundsätzlich nur auf Grundlage einer von
+    Ihnen erteilten Einwilligung nach Artikel 6 Absatz 1 Satz 1 Buchstabe a und
+    Artikel 9 Absatz 2 Buchstabe a der Datenschutzgrundverordnung (DSGVO). Sie
+    können eine erteilte Einwilligung jederzeit widerrufen. Weitere
+    Informationen zu Ihrem Widerrufsrecht und Hinweise, wie Sie dieses ausüben
+    können, finden Sie unter Ziffer 11.
 </p>
-<h2>
+<h1>
     4. An wen richtet sich die App?
-</h2>
+</h1>
 <p>
     Die App richtet sich an Personen, die sich in Deutschland aufhalten und
     mindestens 16 Jahre alt sind.
 </p>
-<h2>
+<h1>
     5. Welche personenbezogenen Daten werden verarbeitet?
-</h2>
+</h1>
 <p>
     Die App ist so konzipiert, dass so wenig personenbezogene Daten wie möglich
     verarbeitet werden. Das bedeutet zum Beispiel, dass die App keine Daten
@@ -96,41 +96,45 @@
     Die von der App verarbeiteten Daten lassen sich den folgenden Kategorien
     zuordnen:
 </p>
+<h2>
+    a. Zugriffsdaten
+</h2>
 <p>
-    <strong>a. Zugriffsdaten</strong>
-</p>
-<p>
-    Zugriffsdaten fallen an, wenn Sie die folgenden Funktionen nutzen bzw.
-    aktivieren:
+    Bei jedem Datenaustausch über das Internet zwischen der App und dem
+    Serversystem der App werden vom Serversystem sogenannte Zugriffsdaten
+    verarbeitet. Dies ist erforderlich, damit die App aktuelle Daten vom
+    Serversystem abrufen oder bestimmte auf dem Smartphone gespeicherte Daten
+    an das Serversystem übermitteln kann. Folgende App-Funktionen erfordern
+    einen solchen Datenaustausch mit dem Serversystem der App:
 </p>
 <ul>
     <li>
-        Risiko-Ermittlung
+        Risiko-Ermittlung (Abruf der Liste mit den Zufalls-IDs von positiv
+        getesteten Nutzern)
     </li>
     <li>
-        Test registrieren
+        Test registrieren (Ãœbermitteln der Test-Kennzahl und Abruf des
+        Testergebnisses)
     </li>
     <li>
-        Testergebnis teilen
+        Andere warnen (Ãœbermitteln Ihrer Zufalls-IDs)
     </li>
 </ul>
 <p>
-    Bei jedem Abruf von Daten vom Serversystem der App wird Ihre IP-Adresse
-    (auf dem vorgelagerten Load Balancer) maskiert und im Weiteren nicht mehr
-    innerhalb des Serversystems der App verarbeitet.
-</p>
-<p>
-    Zusätzlich werden folgende Daten verarbeitet:
+    Die Zugriffsdaten umfassen folgende Daten:
 </p>
 <ul>
+    <li>
+        IP-Adresse
+    </li>
     <li>
         Datum und Uhrzeit des Abrufs (Zeitstempel)
     </li>
     <li>
-        übertragene Datenmenge (bzw. Paketlänge)
+        übertragene Datenmenge (bzw. Paketlänge)
     </li>
     <li>
-        Meldung über erfolgreichen Abruf
+        Meldung über erfolgreichen Abruf
     </li>
 </ul>
 <p>
@@ -141,73 +145,81 @@
     hinaus erfolgt nicht.
 </p>
 <p>
-    <strong>b. Begegnungsdaten</strong>
+    Um eine unbefugte Zuordnung Ihrer Daten anhand Ihrer IP-Adresse schon
+    während eines Nutzungsvorgangs zu erschweren, greift die App über einen
+    speziellen Eingangsserver auf das Serversystem zu. Dieser Eingangsserver
+    leitet die von der App angeforderten oder übermittelten Daten dann ohne
+    Ihre IP-Adresse an den jeweils zuständigen Server weiter, so dass sie im
+    Weiteren nicht mehr innerhalb des Serversystems verarbeitet wird.
 </p>
+<h2>
+    b. Begegnungsdaten
+</h2>
 <p>
     Wenn Sie auf Ihrem Smartphone die betriebssystemseitige Funktion zur
-    Aufzeichnung von Kontakten zu anderen Nutzern aktivieren, versendet Ihr
-    Smartphone per Bluetooth Low Energy kontinuierlich zufallsgenerierte
-    Kennnummern, auch als Zufallscodes bezeichnet (im Folgenden: „<strong>Zufalls-IDs“</strong>),
-    die von anderen Smartphones in Ihrer Nähe
-    mit ebenfalls aktivierter Kontaktaufzeichnung empfangen werden können.
-    Umgekehrt empfängt Ihr Smartphone auch die Zufalls-IDs der anderen
-    Smartphones. Zu den von anderen Smartphones empfangenen Zufalls-IDs werden
-    von der Kontaktaufzeichnungs-Funktion Ihres Smartphones zusätzlich folgende
-    Begegnungsdaten aufgezeichnet und gespeichert:
+    Begegnungs-Aufzeichnung aktivieren, versendet Ihr Smartphone per Bluetooth
+    Low Energy kontinuierlich zufallsgenerierte Kennnummern, auch als
+    Zufallscodes zu bezeichnet (im Folgenden: „<strong>Zufalls-IDs“</strong>),
+    die von anderen Smartphones in Ihrer Nähe mit ebenfalls aktivierter
+    Kontaktaufzeichnung empfangen werden können. Umgekehrt empfängt Ihr
+    Smartphone auch die Zufalls-IDs der anderen Smartphones. Zu den von anderen
+    Smartphones empfangenen Zufalls-IDs werden von der
+    Begegnungsaufzeichnung-Funktion Ihres Smartphones zusätzlich folgende
+    Begegnungsdaten aufgezeichnet:
 </p>
 <ul>
-    <li>
-        Datum und Zeitpunkt des Kontakts
-    </li>
-    <li>
-        Dauer des Kontakts
-    </li>
-    <li>
-        Bluetooth-Signalstärke des Kontakts
-    </li>
-    <li>
-        Verschlüsselte Metadaten (Protokollversion und Sendestärke).
-    </li>
+    <li>Datum und Zeitpunkt des Kontakts</li>
+    <li>Dauer des Kontakts</li>
+    <li>Bluetooth-Signalstärke des Kontakts</li>
+    <li>Verschlüsselte Metadaten (Protokollversion und Sendestärke)</li>
 </ul>
 <p>
     Die eigenen und von anderen Smartphones empfangenen Zufalls-IDs und die
     weiteren Begegnungsdaten (Datum und Zeitpunkt des Kontakts, Dauer des
-    Kontakts, Signalstärke des Kontakts und verschlüsselte Metadaten) werden
-    von Ihrem Smartphone in einem Kontaktprotokoll der
-    Kontaktaufzeichnungs-Funktion erfasst und dort zurzeit für 14 Tage
-    gespeichert.
+    Kontakts, Signalstärke des Kontakts und verschlüsselte Metadaten) werden
+    von der Begegnungsaufzeichnungs-Funktion Ihres Smartphones erfasst und dort
+    zurzeit für 14 Tage gespeichert.
 </p>
 <p>
-    Die Kontaktaufzeichnungs-Funktion heißt bei Android-Smartphones
-    "Benachrichtigungen zu möglicher Begegnung mit Infizierten" und bei iPhones
-    „COVID-19-Kontaktprotokoll“. Wir weisen Sie darauf hin, dass diese
-    Kontaktaufzeichnungs-Funktionen kein Bestandteil der App, sondern ein
-    integraler Bestandteil des Betriebssystems Ihres Smartphones sind. Die
-    Kontaktaufzeichnungs-Funktion wird Ihnen daher von Apple (iPhones) bzw.
-    Google (Android-Smartphones) bereitgestellt und unterliegt dementsprechend
-    den Datenschutzbestimmungen dieser Unternehmen. Die betriebssystemseitige
-    Datenverarbeitung im Rahmen der Kontaktaufzeichnungs-Funktion liegt
-    außerhalb des Einflussbereichs des RKI.
+    Die Begegnungsaufzeichnungs-Funktion heißt bei Android-Smartphones
+    "COVID-19-Benachrichtungen" und bei iPhones „Begegnungsmittelungen“. Wir
+    weisen Sie darauf hin, dass diese Funktionen kein Bestandteil der App,
+    sondern ein integraler Bestandteil Ihres Betriebssystems sind. Anbieter der
+    Begegnungsaufzeichnungs-Funktionen sind daher Apple (iPhones) bzw. Google
+    (Android-Smartphones). Dementsprechend unterliegt die betriebssystemseitige
+    Datenverarbeitung durch die Begegnungsaufzeichnungs-Funktionen den
+    jeweiligen Datenschutzbestimmungen dieser Unternehmen und liegt außerhalb
+    des Verantwortungs- und Einflussbereichs des RKI.
 </p>
 <p>
-    Weitere Informationen zu der Kontaktaufzeichnungs-Funktion von
-    Android-Smartphones finden Sie unter:
-    https://support.google.com/android/answer/9888358?hl=de.
+    Weitere Informationen stellen Ihnen die Anbieter der
+    Begegnungsaufzeichnungs-Funktion zur Verfügung:
 </p>
+<ul>
+    <li>
+        Informationen von Google für Android-Smartphones:
+        https://support.google.com/android/answer/9888358?hl=de
+    </li>
+    <li>
+        Informationen von Apple für iPhones finden Sie auf Ihrem Gerät unter
+        „Einstellungen“ &gt; "Begegnungsmitteilungen“ unter dem Link „So
+        funktionieren Begegnungsmitteilungen …“.
+    </li>
+</ul>
 <p>
-    Weitere Informationen zu der Kontaktaufzeichnungs-Funktion von Apple finden
-    Sie in den Einstellungen Ihres iPhones unter "Datenschutz“ &gt; „Health"
-    &gt; „COVID-19-Kontaktprotokoll“. Bitte beachten Sie: Die
-    Kontaktaufzeichnungs-Funktion steht Ihnen nur zur Verfügung, wenn auf Ihrem
-    iPhone das Betriebssystem iOS ab Version 13.5 installiert ist.
+    Bitte beachten Sie, dass die tatsächlichen Bezeichnungen, Bedienschritte
+    und Einstellmöglichkeiten der Kontaktaufzeichnungs-Funktion je nach Version
+    und Konfiguration Ihres Betriebssystems von der der Darstellung in dieser
+    Datenschutzerklärung abweichen kann.
 </p>
 <p>
-    Die vom Smartphone erzeugten und gespeicherten Begegnungsdaten werden von
-    der App nur verarbeitet, wenn die Risiko-Ermittlung aktiviert ist.
+    Die von der Begegnungsaufzeichnungs-Funktion Ihres Betriebssystems
+    erzeugten und gespeicherten Begegnungsdaten werden von der App nur
+    verarbeitet, wenn die Risiko-Ermittlung aktiviert ist.
 </p>
-<h3>
-    a. Gesundheitsdaten
-</h3>
+<h2>
+    c. Gesundheitsdaten
+</h2>
 <p>
     Gesundheitsdaten sind alle Daten, die Informationen zum Gesundheitszustand
     einer bestimmten Person enthalten. Dazu gehören nicht nur Angaben zu
@@ -216,74 +228,88 @@
     infiziert hat).
 </p>
 <p>
-    In den folgenden Fällen handelt es sich um eine Verarbeitung von
+    Bei der Nutzung folgender Funktionen verarbeitet die App Ihre
     Gesundheitsdaten:
 </p>
 <ul>
-    <li>
-        Wenn die Risiko-Ermittlung erkennt, dass Sie möglicherweise Kontakt zu
-        einer Person hatten, die sich mit dem Corona-Virus infiziert hat.
+    <li>Risiko-Ermittlung, sobald eine Risiko-Begegnung festgestellt wird (d. h.
+        Sie hatten möglicherweise Kontakt zu einer Person, die sich mit dem
+        Corona-Virus infiziert hat).
     </li>
-    <li>
-        Wenn Sie einen Test registrieren.
-    </li>
-    <li>
-        Wenn Sie ein positives Testergebnis teilen.
+    <li>Andere warnen (Testergebnis, eventuelle Angaben zu Symptomen und
+        Symptombeginn)
     </li>
+    <li>Test registrieren (Teststatus und Testergebnis)</li>
 </ul>
-<h2>
+<h1>
     6. Funktionen der App
-</h2>
-<h3>
+</h1>
+<h2>
     a. Risiko-Ermittlung
-</h3>
+</h2>
 <p>
     Die Risiko-Ermittlung ist die Kernfunktion der App. Sie dient dazu,
-    mögliche Kontakte zu mit dem Corona-Virus infizierten anderen Nutzern der
-    App nachzuverfolgen, das infolge für Sie bestehende Infektionsrisiko zu
-    bewerten und Ihnen, basierend auf dem für Sie ermittelten Risikowert,
-    Verhaltens- und Gesundheitshinweise bereitzustellen.
+    mögliche Kontakte zu mit dem Corona-Virus infizierten anderen Nutzern
+    (Risiko-Begegnungen) nachzuverfolgen, das infolge für Sie bestehende
+    Infektionsrisiko zu bewerten und Ihnen entsprechende Verhaltens- und
+    Gesundheitshinweise bereitzustellen.
 </p>
 <p>
     Wenn Sie die Risiko-Ermittlung aktivieren, ruft die App von den
     Serversystemen der App im Hintergrundbetrieb mehrmals täglich (oder wenn
-    Sie auf „Aktualisieren“ tippen) eine Liste mit Zufalls-IDs von Nutzern ab,
-    die positiv getestet wurden und Ihre eigenen Zufalls-IDs geteilt haben. Die
-    App gibt die Zufalls-IDs an die Kontaktaufzeichnungs-Funktion Ihres
-    Smartphones weiter, welche diese dann mit den im Kontaktprotokoll Ihres
-    Smartphones gespeicherten Zufalls-IDs abgleicht. Wenn die
-    Kontaktaufzeichnungs-Funktion Ihres Smartphones eine Ãœbereinstimmung
+    Sie auf „Aktualisieren“ tippen) eine Liste mit Zufalls-IDs mit jeweils
+    einem Ãœbertragungsrisiko-Wert (als Zahlenwert von 1-8) von Nutzern ab, die
+    positiv getestet wurden und Ihre eigenen Zufalls-IDs über die App mit der
+    Funktion „Andere warnen“ bereitgestellt haben. Der Übertragungsrisiko-Wert
+    ist ein Schätzwert zur Höhe der Ansteckungswahrscheinlichkeit am Tag der
+    jeweiligen Risiko-Begegnung. Da die Infektiosität (also die Höhe des
+    Ansteckungsrisikos für die Kontakte einer positiv getesteten Person) nach
+    derzeitigem Wissensstand von der Dauer und dem Verlauf der Infektion
+    abhängt, kann somit beispielsweise berücksichtigt werden, dass die Gefahr
+    einer Ansteckung am Tag einer Risiko-Begegnung geringer ist, je mehr Zeit
+    seit Symptombeginn verstrichen ist.
+</p>
+<p>
+    Die App gibt die Zufalls-IDs an die Begegnungsaufzeichnungs-Funktion Ihres
+    Smartphones weiter, welche diese dann mit den im von der
+    Begegnungsaufzeichnung protokollierten Zufalls-IDs abgleicht. Wenn die
+    Begegnungsaufzeichnungs-Funktion Ihres Smartphones eine Ãœbereinstimmung
     feststellt, übergibt sie der App die Begegnungsdaten (Datum, Dauer,
     Signalstärke), nicht jedoch die Zufalls-ID des betreffenden Kontakts.
 </p>
 <p>
-    Im Fall eines Kontakts werden die von der Kontaktaufzeichnungs-Funktion
-    übergebenen Begegnungsdaten von der App analysiert, um Ihr individuelles
-    Infektionsrisiko zu ermitteln. Der Bewertungsalgorithmus, der festlegt, wie
-    die Begegnungsdaten interpretiert werden (z. B. welchen Einfluss die Dauer
-    eines Kontakts auf das Infektionsrisiko hat) basiert auf den aktuellen
-    wissenschaftlichen Erkenntnissen. Bei neuen Erkenntnissen kann der
-    Bewertungsalgorithmus daher durch das RKI aktualisiert werden, indem die
-    Einstellungen für den Bewertungsalgorithmus neu gesetzt werden. Die
+    Im Fall einer Risiko-Begegnung werden die von der
+    Begegnungsaufzeichnungs-Funktion übergebenen Begegnungsdaten sowie der
+    Ãœbertragungsrisiko-Wert von der App analysiert, um Ihr individuelles
+    Infektionsrisiko zu ermitteln.
+</p>
+<p>
+    Der Bewertungsalgorithmus, der festlegt, wie die Begegnungsdaten und der
+    Ãœbertragungsrisiko-Wert interpretiert werden (z. B. welchen Einfluss die
+    Dauer eines Kontakts auf das Infektionsrisiko hat) basiert auf den
+    aktuellen wissenschaftlichen Erkenntnissen. Bei neuen Erkenntnissen kann
+    der Bewertungsalgorithmus daher durch das RKI aktualisiert werden, indem
+    die Einstellungen für den Bewertungsalgorithmus neu gesetzt werden. Die
     Einstellungen für den Bewertungsalgorithmus werden dann zusammen mit der
-    Liste der Zufalls-IDs infizierter Personen an die App übermittelt.
+    Liste der Zufalls-IDs infizierter Nutzer an die App übermittelt.
 </p>
 <p>
     Die Ermittlung des Infektionsrisikos findet ausschließlich lokal auf Ihrem
-    Smartphone statt, das heißt die Daten werden offline verarbeitet. Das
-    ermittelte Infektionsrisiko wird ebenfalls ausschließlich in der App
-    gespeichert und an keine anderen Empfänger (auch nicht an das RKI, Apple,
-    Google und sonstige Dritte) weitergegeben.
+    Smartphone statt, das heißt die Daten werden offline ohne Zugriffe auf das
+    Serversystem der App verarbeitet. Das ermittelte Infektionsrisiko wird
+    ebenfalls ausschließlich in der App berechnet und an keine anderen
+    Empfänger (auch nicht an das RKI, Apple, Google und sonstige Dritte)
+    weitergegeben.
 </p>
 <p>
     Rechtsgrundlage der oben beschriebenen Verarbeitung Ihrer Zugriffsdaten,
-    Begegnungsdaten und ggf. Gesundheitsdaten (sofern für Sie ein
-    Infektionsrisiko ermittelt wird) ist Ihre Einwilligung, die Sie bei der
-    Aktivierung der Risiko-Ermittlung erteilt haben.
+    Begegnungsdaten und ggf. Gesundheitsdaten (sofern eine Risiko-Begegnung
+    erkannt wird) ist Ihre Einwilligung, die Sie bei der Aktivierung der
+    Risiko-Ermittlung erteilt haben.
 </p>
-<h3>
+<h2>
     b. Test registrieren
-</h3>
+</h2>
 <p>
     Wenn Sie auf eine Infektion mit dem Corona-Virus getestet wurden, können
     Sie den Test in der App registrieren, indem Sie den QR-Code, den Sie von
@@ -338,7 +364,7 @@
     speziellen Server innerhalb des Serversystems der App betrieben. Das
     Testlabor erzeugt die gehashte Kennzahl ebenfalls auf Basis der an Sie im
     ausgegebenen QR-Code enthaltenen Kennzahl unter Verwendung des gleichen
-    mathematischen Verfahrens, das auch die App einsetzt.<u></u>
+    mathematischen Verfahrens, das auch die App einsetzt.
 </p>
 <p>
     <u>Abruf des Testergebnisses</u>
@@ -359,28 +385,36 @@
     Kennzahl ein positives Testergebnis vorliegt. Sofern die
     Testergebnis-Datenbank dies bestätigt, erzeugt das Serversystem die TAN und
     übermittelt sie an die App. Eine Kopie der TAN verbleibt auf dem
-    Serversystem.
+    Serversystem. Die TAN wird benötigt, um im Fall einer Übermittlung des
+    positiven Testergebnisses sicherzustellen, dass keine falschen
+    Informationen an andere Nutzer verteilt werden. Rechtsgrundlage der oben
+    beschriebenen Verarbeitung der zuvor genannten Daten ist Ihre Einwilligung
+    für die Funktion „Test registrieren“.
 </p>
+<h2>
+    c. Andere warnen
+</h2>
 <p>
-    Die TAN wird benötigt, um im Fall einer Übermittlung des positiven
-    Testergebnisses sicherzustellen, dass keine falschen Informationen an
-    andere Nutzer verteilt werden.
+    Wenn Sie die Funktion „Andere warnen“ nutzen überträgt die App die von
+    Ihrem Smartphone gespeicherten eigenen Zufalls-IDs (einschließlich der
+    jeweiligen Ãœbertragungsrisiko-Werte) der letzten 14 Tage und die TAN an das
+    Serversystem der App. Dieses prüft zunächst, ob die TAN gültig ist und
+    trägt Ihre Zufalls-IDs sodann in die Liste der Zufalls-IDs von Nutzern, die
+    ihr positives Testergebnis bereitgestellt haben, ein. Ihre Zufalls-IDs
+    können nun von anderen Nutzern im Rahmen der Risiko-Ermittlung
+    heruntergeladen werden.
 </p>
 <p>
-    Rechtsgrundlage der oben beschriebenen Verarbeitung der zuvor genannten
-    Daten ist Ihre Einwilligung für die Funktion „Test registrieren“.
-</p>
-<h3>
-    c. Testergebnis teilen
-</h3>
-<p>
-    Wenn Sie die Funktion „Testergebnis teilen“ nutzen um andere Nutzer zu
-    warnen, überträgt die App die von Ihrem Smartphone gespeicherten eigenen
-    Zufalls-IDs der letzten 14 Tage und die TAN an das Serversystem der App.
-    Dieses prüft zunächst, ob die TAN gültig ist und trägt Ihre Zufalls-IDs
-    sodann in die Liste der Zufalls-IDs von Nutzern, die ihr positives
-    Testergebnis geteilt haben, ein. Ihre Zufalls-IDs können nun von anderen
-    Nutzern im Rahmen der Risiko-Ermittlung heruntergeladen werden.
+    Die von der Funktion „Andere warnen“ abgefragten Angaben zu Symptomen und
+    Symptombeginn sind optional und nicht erforderlich, um andere Nutzer zu
+    warnen. Diese Angaben können jedoch helfen, das Infektionsrisiko der
+    anderen Nutzer, denen Sie begegnet sind, genauer zu berechnen. Soweit Sie
+    keine oder nicht alle Fragen beantworten können oder wollen, wählen Sie
+    einfach „keine Angabe“. In diesem Fall werden die Übertragungsrisiko-Werte
+    Ihrer Zufalls-IDs von der App anhand des Zeitablaufs seit Abruf des
+    Testergebnisses unter Zugrundelegung eines durchschnittlichen
+    Infektionsverlaufs festgelegt, d. h. je mehr Zeit seit Verwendung einer
+    Zufalls-ID vergangen ist, desto kleiner ist ihr Ãœbertragungsrisiko-Wert.
 </p>
 <p>
     <u>Wenn Sie Ihr Testergebnis nicht in der App abgerufen haben:</u>
@@ -419,22 +453,22 @@
     Gesundheitsdaten (Zufalls-IDs, Testergebnis, TAN und ggf. TeleTAN) ist Ihre
     Einwilligung für die Funktion „Testergebnis teilen“.
 </p>
-<p>
-    <strong>d. Informatorische Nutzung der App</strong>
-</p>
+<h3>
+    d. Informatorische Nutzung der App
+</h3>
 <p>
     Soweit Sie die App nur informatorisch nutzen, also keine der oben genannten
     Funktionen der App verwenden und keine Daten eingeben, findet die
     Verarbeitung ausschließlich lokal auf Ihrem Smartphone statt und es fallen
-    keine personenbezogenen Daten an. In der App verlinkte Webseiten z.B.:
-    www.bundesregierung.de werden im Standard-Browser Ihres Smartphones
-    geöffnet und angezeigt. Welche Daten dabei verarbeitet werden hängt von dem
-    genutzten Browser, dessen Konfiguration sowie der Datenverarbeitungspraxis
-    der aufgerufenen Webseite ab.
+    keine personenbezogenen Daten an. In der App verlinkte Webseiten z.B.: www.bundesregierung.de
+    werden je nach Betriebssystem
+    im Standard-Browser Ihres Smartphones (Android-Smartphones) oder innerhalb
+    der App (iPhone) geöffnet und angezeigt. Welche Daten dabei verarbeitet
+    werden hängt von der Datenverarbeitungspraxis der aufgerufenen Webseite ab.
 </p>
-<h2>
+<h1>
     7. Welche Berechtigungen und Funktionen benötigt die App?
-</h2>
+</h1>
 <p>
     Die App benötigt Zugriff auf verschiedene Funktionen und Schnittstellen
     Ihres Smartphones. Dazu ist es erforderlich, dass Sie der App bestimmte
@@ -445,9 +479,9 @@
     beachten Sie, dass Sie im Falle der Ablehnung eines Zugriffs durch die App
     keine oder nur wenige Funktionen der App nutzen können.
 </p>
-<h3>
+<h2>
     a. Technische Voraussetzungen (alle Smartphones)
-</h3>
+</h2>
 <ul>
     <li>
         Internet
@@ -489,9 +523,9 @@
     Betriebssystem Ihres Smartphones deaktivieren, müssen Sie alle Aktionen in
     der App selbst starten.
 </p>
-<h3>
+<h2>
     b. Android-Smartphones
-</h3>
+</h2>
 <p>
     Wenn Sie ein Android-Gerät verwenden, müssen außerdem folgende
     Systemfunktionen aktiviert sein:
@@ -539,16 +573,16 @@
     Die App benötigt Zugriff auf die Kamera, um bei der Testregistrierung den
     QR-Code auslesen zu können.
 </p>
-<h3>
+<h2>
     c. iPhones (Apple iOS)
-</h3>
+</h2>
 <p>
     Wenn Sie ein iPhone verwenden, müssen folgende Systemfunktionen aktiviert
     sein:
 </p>
 <ul>
     <li>
-        COVID-19-Kontaktprotokoll
+        Begegnungsmitteilungen
     </li>
 </ul>
 <p>
@@ -578,16 +612,16 @@
     Die App benötigt Zugriff auf die Kamera, um bei der Testregistrierung den
     QR-Code auslesen zu können.
 </p>
-<h2>
+<h1>
     8. Wann werden die Daten gelöscht?
-</h2>
+</h1>
 <p>
     Alle in der App gespeicherten Daten werden gelöscht, sobald sie für die
     Funktionen der App nicht mehr benötigt werden:
 </p>
-<h3>
+<h2>
     a. Risiko-Ermittlung
-</h3>
+</h2>
 <ul>
     <li>
         Die Liste der Zufalls-IDs von Nutzern, die ein positives Testergebnis
@@ -595,26 +629,26 @@
         Kontaktprotokoll Ihres Smartphones nach 14 Tagen automatisch gelöscht.
     </li>
     <li>
-        Auf die Löschung der Begegnungsdaten im Kontaktprotokoll Ihres
-        Smartphones (einschließlich Ihrer eigenen Zufalls-IDs) und die
-        Begegnungsdaten auf anderen Smartphones hat das RKI keinen Einfluss, da
-        diese Funktion von Apple bzw. Google bereitgestellt werden. Die
-        Löschung richtet sich nach den Festlegungen von Apple bzw. Google.
-        Zurzeit werden die Daten nach 14 Tagen automatisch gelöscht. Zudem
-        können Sie im Rahmen der von Apple und Google bereitgestellten
-        Funktionalitäten in den Systemeinstellungen Ihres Geräts gegebenenfalls
-        eine manuelle Löschung anstoßen.
+        Auf die Löschung der Begegnungsdaten im Kontaktprotokoll der
+        Begegnungsaufzeichnung Ihres Smartphones (einschließlich Ihrer eigenen
+        Zufalls-IDs) und die Begegnungsdaten auf anderen Smartphones hat das
+        RKI keinen Einfluss, da diese Funktionen von Apple bzw. Google
+        bereitgestellt werden. Die Löschung richtet sich nach den Festlegungen
+        von Apple bzw. Google. Zurzeit werden die Daten nach 14 Tagen
+        automatisch gelöscht. Zudem können Sie im Rahmen der von Apple und
+        Google bereitgestellten Funktionalitäten in den Systemeinstellungen
+        Ihres Geräts gegebenenfalls eine manuelle Löschung anstoßen.
     </li>
     <li>
-        Der in der App angezeigte Risikowert wird gelöscht, sobald ein neuer
-        Risikowert ermittelt worden ist. Ein neuer Risikowert wird in der Regel
-        ermittelt, nachdem die App eine neue Liste mit Zufalls-IDs erhalten
-        hat.
+        Das in der App angezeigte Infektionsrisiko wird gelöscht, sobald ein
+        neuer Risikowert ermittelt worden ist. Ein neuer Risikowert wird in der
+        Regel ermittelt, nachdem die App eine neue Liste mit Zufalls-IDs
+        erhalten hat.
     </li>
 </ul>
-<h3>
+<h2>
     b. Test registrieren
-</h3>
+</h2>
 <ul>
     <li>
         Die gehashte Kennzahl wird auf dem Serversystem der App nach 21 Tagen
@@ -633,29 +667,35 @@
     </li>
     <li>
         Das Token, das in der App gespeichert ist, wird nach Löschung der App
-        vom Smartphone oder nach Ausführung der Funktion „Testergebnis teilen“
+        vom Smartphone oder nach Ausführung der Funktion „Andere warnen“
         gelöscht.
     </li>
 </ul>
-<h3>
-    c. Testergebnis teilen
-</h3>
+<h2>
+    c. Andere warnen
+</h2>
 <ul>
     <li>
-        Die in der App geteilten eigenen Zufalls-IDs werden nach 14 Tagen vom
-        Serversystem gelöscht.
+        Die über die App bereitgestellten eigenen Zufalls-IDs und
+        Risikoübertragungs-Werte werden nach 14 Tagen vom Serversystem
+        gelöscht.
+    </li>
+    <li>
+        Ihre Angaben zu Symptomen und zum Symptombeginn werden direkt nach dem
+        Bereitstellen der Zufalls-IDs und Ãœbertragungsrisiko-Werte von der App
+        gelöscht.
     </li>
     <li>
         Die Kopie der TAN, die auf dem Serversystem gespeichert ist, wird nach
         21 Tagen gelöscht.
     </li>
     <li>
-        Die TAN, die in der App gespeichert ist, wird nach Teilen des
+        Die TAN, die in der App gespeichert ist, wird nach Bereitstellen des
         Testergebnisses gelöscht.
     </li>
     <li>
-        Die TeleTAN, die in der App gespeichert ist, wird nach Teilen des
-        Testergebnisses gelöscht.
+        Die TeleTAN, die in der App gespeichert ist, wird nach Bereitstellen
+        des Testergebnisses gelöscht.
     </li>
     <li>
         Die TeleTAN, die auf dem Serversystem gespeichert ist, wird nach 21
@@ -670,16 +710,17 @@
         gelöscht.
     </li>
     <li>
-        Das Token, das in der App gespeichert ist, wird nach Teilen des
+        Das Token, das in der App gespeichert ist, wird nach Bereitstellen des
         Testergebnisses gelöscht.
     </li>
 </ul>
-<h2>
+<h1>
     9. An wen werden Ihre Daten weitergegeben?
-</h2>
+</h1>
 <p>
-    Wenn Sie ein Testergebnis teilen, um andere Nutzer zu warnen, werden Ihre
-    Zufalls-IDs der letzten 14 Tage an die Apps der anderen Nutzer
+    Wenn Sie ein Testergebnis über die Funktion „Andere warnen“ bereitstellen,
+    um andere Nutzer zu warnen, werden Ihre Zufalls-IDs und deren
+    Ãœbertragungsrisiko-Werte der letzten 14 Tage an die Apps der anderen Nutzer
     weitergegeben.
 </p>
 <p>
@@ -696,17 +737,17 @@
     erforderlich ist. Eine Weitergabe in anderen Fällen erfolgt grundsätzlich
     nicht.
 </p>
-<h2>
+<h1>
     10. Werden Daten in ein Drittland übermittelt?
-</h2>
+</h1>
 <p>
     Die bei der Nutzung der App anfallenden Daten werden ausschließlich auf
     Servern in Deutschland oder in einem anderem EU- oder EWR-Mitgliedsstaat
     verarbeitet.
 </p>
-<h2>
+<h1>
     11. Widerruf von Einwilligungen
-</h2>
+</h1>
 <p>
     Ihnen steht das Recht zu, die in der App erteilten Einwilligungen gegenüber
     dem RKI jederzeit mit Wirkung für die Zukunft zu widerrufen. Die
@@ -728,20 +769,21 @@
     werden Sie um eine neue Einwilligung gebeten.
 </p>
 <p>
-    Zum Widerruf Ihrer Einwilligung für die Funktion „Testergebnis teilen“
-    müssen Sie die App löschen. Sämtliche Ihrer in der App gespeicherten
-    Zufalls-IDs werden dann entfernt und können Ihrem Smartphone nicht mehr
-    zugeordnet werden. Wenn Sie erneut ein Testergebnis melden möchten, können
-    Sie in der App erneut installieren und eine neue Einwilligung erteilen.
-    Alternativ können Sie Ihre eigenen Zufalls-IDs gegebenenfalls im Rahmen der
-    Kontaktaufzeichnungs-Funktion in den Systemeinstellungen Ihres Smartphones
-    löschen. Bitte beachten Sie, dass das RKI keine Möglichkeit hat, um Ihre
-    bereits übermittelten Zufalls-IDs unmittelbar aus den bereitgestellten
-    Listen und von Smartphones anderer Nutzer zu löschen.
+    Zum Widerruf Ihrer Einwilligung für die Funktion „Andere warnen“ müssen
+    Sie die App löschen. Sämtliche Ihrer in der App gespeicherten Zufalls-IDs
+    werden dann entfernt und können Ihrem Smartphone nicht mehr zugeordnet
+    werden. Wenn Sie erneut ein Testergebnis melden möchten, können Sie in der
+    App erneut installieren und eine neue Einwilligung erteilen. Alternativ
+    können Sie Ihre eigenen Zufalls-IDs gegebenenfalls im Rahmen der
+    Begegnungsaufzeichnungs-Funktion in den Systemeinstellungen Ihres
+    Smartphones löschen. Bitte beachten Sie, dass das RKI keine Möglichkeit
+    hat, um Ihre bereits übermittelten Zufalls-IDs und Übertragungsrisiko-Werte
+    unmittelbar aus den bereitgestellten Listen und von Smartphones anderer
+    Nutzer zu löschen.
 </p>
-<h2>
+<h1>
     12. Ihre weiteren Datenschutzrechte
-</h2>
+</h1>
 <p>
     Soweit das RKI personenbezogene Daten von Ihnen verarbeitet, stehen Ihnen
     außerdem folgende Datenschutzrechte zu:
@@ -751,19 +793,24 @@
         die Rechte aus den Artikeln 15, 16, 17, 18, 20 und 21 DSGVO,
     </li>
     <li>
-        das Recht, den behördlichen Datenschutzbeauftragten des RKI zu
-        kontaktieren und Ihr Anliegen vorzubringen (Artikel 38 Abs. 4 DSGVO)
+        das Recht, den behördlichen
+        Datenschutzbeauftragten des RKI
+        (https://www.rki.de/DE/Content/Institut/OrgEinheiten/Datenschutz/Datenschutz_node.html)
+        zu kontaktieren und Ihr Anliegen vorzubringen (Artikel 38 Abs. 4 DSGVO)
         und
     </li>
     <li>
         das Recht, sich bei einer zuständigen Aufsichtsbehörde für den
         Datenschutz zu beschweren. Dazu können Sie sich entweder an die
-        zuständige Aufsichtsbehörde an Ihrem Wohnort oder an die am Sitz des
-        RKI zuständige Behörde wenden. Die zuständige Aufsichtsbehörde für das
-        RKI ist der Bundesbeauftragte für den Datenschutz und die
-        Informationsfreiheit, Graurheindorfer Str. 153, 53117 Bonn.
+        zuständige
     </li>
 </ul>
+<p>
+    Aufsichtsbehörde an Ihrem Wohnort oder an die am Sitz des RKI zuständige
+    Behörde wenden. Die zuständige Aufsichtsbehörde für das RKI ist der
+    Bundesbeauftragte für den Datenschutz und die Informationsfreiheit,
+    Graurheindorfer Str. 153, 53117 Bonn.
+</p>
 <p>
     Es wird darauf hingewiesen, dass die vorgenannten Rechte vom RKI nur
     erfüllt werden können, wenn die Daten, auf die sich die geltend gemachten
@@ -781,5 +828,5 @@
     können.
 </p>
 <p>
-    Stand: 12.06.2020
-</p>
+    Stand: 05.10.2020
+</p>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/assets/privacy_en.html b/Corona-Warn-App/src/main/assets/privacy_en.html
index 44edf5a86ba02563c67c8c807de87a5534b86902..b9f7a0f9feeec8d72c569ad83b20cf186fb1c038 100644
--- a/Corona-Warn-App/src/main/assets/privacy_en.html
+++ b/Corona-Warn-App/src/main/assets/privacy_en.html
@@ -32,30 +32,31 @@
     2. Is using the App voluntary?
 </h2>
 <p>
-    Using the App is entirely voluntary. It is your decision alone whether and
-    how you use the App.
-</p>
-<p>
-    Although installing and using the App is voluntary, if you wish to use the
-    exposure logging feature you still have to grant the RKI your consent to
-    let the App process your personal data. You do this by tapping on the
-    “Enable Exposure Logging” button the first time you open the App. If the
-    App identifies a potential risk of infection for you, then your data also
-    includes health data. Your consent is necessary because otherwise the App
-    will not be able to access your smartphone’s exposure logging feature. You
-    can, however, use the toggle switch in the App to disable the exposure
-    logging feature at any time. Doing this will mean that you are unable to
-    use the full functionality of the App. Separate consent is also required
-    for the data processing performed for the following features:
+    Using the App is voluntary. It is therefore your decision alone whether you
+    install the App and which features you use. Your data (such as information
+    about your exposures and your risk of infection) will only be generated and
+    stored on your own smartphone. Your data will only be shared with the RKI,
+    your smartphone’s operating system or other users if you use one of the
+    following App features and have consented to the necessary data transfer in
+    the individual case:
 </p>
 <ul>
+    <li>
+        Risk identification (see 6 a.)
+    </li>
     <li>
         Registering a test (see 6 b.)
     </li>
     <li>
-        Sharing your test result (see 6 c.).
+        Warning others (see 6 c.).
     </li>
 </ul>
+<p>
+    You are not obliged to use these features. If you decide not to grant the
+    consent requested by one of these features, or if you subsequently withdraw
+    your consent, you will not suffer any disadvantages. This will only mean
+    that you cannot or can no longer use that consent-based feature of the App.
+</p>
 <p>
     The data processing performed in connection with these features is
     described in more detail in the following sections.
@@ -64,12 +65,12 @@
     3. On what legal basis is your data processed?
 </h2>
 <p>
-    In principle, the RKI will process your personal data only on the basis of
-    your consent granted pursuant to Article 6(1) Sentence 1(a) and Article
-    9(2)(a) of the General Data Protection Regulation (GDPR). If you have
-    granted your consent, you can withdraw it at any time. Further information
-    on your right of withdrawal and instructions on how to exercise this right
-    can be found under 11.
+    In principle, the RKI will process your data only on the basis of your
+    consent granted pursuant to Article 6(1) Sentence 1(a) and Article 9(2)(a)
+    of the General Data Protection Regulation (GDPR). If you have granted your
+    consent, you can withdraw it at any time. Further information on your right
+    of withdrawal and instructions on how to exercise this right can be found
+    under 11.
 </p>
 <h2>
     4. Who is the App aimed at?
@@ -95,28 +96,33 @@
     a. Access data
 </h3>
 <p>
-    Access data is generated when you use or enable the following features:
+    Every time data is exchanged over the internet between the App and the
+    App’s server system, the server system processes so-called access data.
+    This is necessary for the App to retrieve current data from the server
+    system or to transmit certain data stored on the smartphone to the server
+    system. The following App features require this type of data exchange with
+    the App’s server system:
 </p>
 <ul>
     <li>
-        Exposure Logging
+        Risk identification (retrieving the list of random IDs from users who
+        have tested positive)
     </li>
     <li>
-        Registering a test
+        Registering a test (transmitting the test code and retrieving the test
+        result)
     </li>
     <li>
-        Sharing your test result.
+        Warning others (transmitting your random IDs).
     </li>
 </ul>
 <p>
-    Each time data is retrieved from the App’s server system, your IP address
-    (on the upstream load balancer) is masked and no longer used within the
-    App’s server system.
-</p>
-<p>
-    The following data is also processed:
+    This access data comprises the following information:
 </p>
 <ul>
+    <li>
+        IP address
+    </li>
     <li>
         Date and time of retrieval (time stamp)
     </li>
@@ -133,19 +139,26 @@
     it is not possible to create a user profile. The IP address will not be
     saved beyond the end of the period of use.
 </p>
+<p>
+    In order to prevent unauthorised identification of your data by means of
+    your IP address when you use the App, the App accesses the server system
+    via a special access server. This access server then forwards the data
+    requested or transmitted by the App to the appropriate server, but without
+    your IP address, so that your IP address is no longer processed within the
+    server system.
+</p>
 <h3>
-    b. Contact data
+    b. Exposure data
 </h3>
 <p>
-    If you enable exposure logging in your smartphone’s operating system, which
-    serves to record encounters (contacts) with other users, then your
-    smartphone will continuously send out randomly generated identification
-    numbers (“<strong>random IDs</strong>”) via Bluetooth Low Energy, which
-    other smartphones in your vicinity can receive if exposure logging is also
-    enabled on them. Your smartphone, in turn, also receives the random IDs of
-    the other smartphones. In addition to the random IDs received from other
-    smartphones, your smartphone’s exposure logging functionality records and
-    stores the following contact data:
+    If you enable exposure logging in your smartphone’s operating system, then
+    your smartphone will continuously send out randomly generated
+    identification numbers (“<strong>random IDs</strong>”) via Bluetooth Low
+    Energy, which other smartphones in your vicinity can receive if exposure
+    logging is also enabled on them. Your smartphone, in turn, also receives
+    the random IDs of the other smartphones. In addition to the random IDs
+    received from other smartphones, your smartphone’s exposure logging
+    functionality records the following exposure data:
 </p>
 <ul>
     <li>
@@ -163,36 +176,47 @@
 </ul>
 <p>
     Your own random IDs and those received from other smartphones as well as
-    the other contact data (date and time of the contact, duration of the
+    the other exposure data (date and time of the contact, duration of the
     contact, signal strength of the contact and encrypted metadata) are
-    recorded by your smartphone in an exposure log and currently stored there
-    for 14 days.
+    recorded by your smartphone’s exposure logging functionality and currently
+    stored there for 14 days.
 </p>
 <p>
-    The functionality used to record encounters with other users is called
-    “COVID-19 Exposure Notifications” on Android smartphones and “COVID-19
-    Exposure Logging” on iPhones. Please note that this exposure logging
-    functionality is not part of the App, but an integral part of your
-    smartphone's operating system. This means that the exposure logging
-    functionality is provided to you by Apple (iPhones) or Google (Android
-    smartphones) and is subject to these companies’ respective privacy
-    policies. The RKI has no influence on data processing performed by the
-    operating system in connection with exposure logging.
+    The exposure logging functionality is called “COVID-19 Exposure
+    Notifications” on Android smartphones and “Exposure Notification” on
+    iPhones. Please note that this functionality is not part of the App, but an
+    integral part of your operating system. The exposure logging functionality
+    is therefore provided to you by Apple (iPhones) or Google (Android
+    smartphones). Accordingly, any data processing performed by the operating
+    system using this exposure logging functionality is subject to these
+    companies’ respective privacy policies. The RKI is not responsible for this
+    and has no influence on it.
 </p>
 <p>
-    More information about the exposure logging functionality on Android
-    smartphones is available at:
-    https://support.google.com/android/answer/9888358?hl=en.
+    More information about the exposure logging functionality is available from
+    the providers:
 </p>
+<ul>
+    <li>
+        Information from Google for Android smartphones:
+        https://support.google.com/android/answer/9888358?hl=en
+    </li>
+    <li>
+        Information from Apple for iPhones can be found on your device under “Settings”
+        &gt; "Exposure Notification“ and the link “How Exposure Notification
+        works…”.
+    </li>
+</ul>
 <p>
-    More information about Apple’s exposure logging functionality can be found
-    in your iPhone’s settings under “Privacy” &gt; “Health” &gt; "COVID-19
-    Exposure Logging”. Please note that the exposure logging functionality is
-    only available if iOS version 13.5 or higher is installed on your iPhone.
+    Please note that the actual named us, operating steps, and settings options
+    for the exposure logging functionality on your smartphone may differ from
+    those described in this privacy notice depending on the version and
+    configuration of your operating system.
 </p>
 <p>
-    The App will only process the contact data generated and stored by your
-    smartphone if the App’s exposure logging feature is enabled.
+    The App will only process the exposure data generated and stored by your
+    operating system’s exposure logging functionality if the App’s risk
+    identification feature is enabled.
 </p>
 <h3>
     c. Health data
@@ -204,67 +228,84 @@
     risk that the person has been infected with the coronavirus).
 </p>
 <p>
-    The following cases involve processing health data:
+    The App will process your health data if you use the following features:
 </p>
 <ul>
     <li>
-        If the exposure logging feature detects that you may have been in
-        contact with a person who has been infected with the coronavirus.
+        Risk identification, as soon as a potential exposure is detected (i.e.
+        you may have been in contact with a person who has been infected with
+        the coronavirus)
     </li>
     <li>
-        If you register your test.
+        Registering a test (test status and test result)
     </li>
     <li>
-        If you share a positive test result.
+        Warning others (test result, and possibly information about symptoms
+        and their onset).
     </li>
 </ul>
 <h2>
     6. App features
 </h2>
 <h3>
-    a. Exposure Logging
+    a. Risk identification
 </h3>
 <p>
-    The App’s core functionality is exposure logging. This serves to track
+    The App’s core functionality is risk identification. This serves to track
     possible contacts with other users of the App who are infected with the
-    coronavirus, to evaluate the risk that you yourself have been infected, and
-    – based on the risk identified – to provide you with health advice and
+    coronavirus (possible exposures), to evaluate the risk that you yourself
+    have been infected, and to provide you with health advice and
     recommendations for what to do next.
 </p>
 <p>
-    If you enable the exposure logging feature, then several times a day while
-    the App runs in the background (or when you tap on “Update”), the App will
-    retrieve a list from the App’s server system of random IDs from users who
-    have tested positive and shared their own random IDs. The App shares these
-    random IDs with your smartphone’s exposure logging functionality, which
-    then compares them with the random IDs stored in your smartphone’s exposure
-    log. If your smartphone’s exposure logging functionality detects a match,
-    it transfers the contact data (date, duration, signal strength) to the App,
-    but not the random ID of the contact in question.
+    If you enable the risk identification feature, then several times a day
+    while the App runs in the background (or when you tap on “Update”), the App
+    will retrieve a list from the App’s server system of random IDs, each with
+    a transmission risk value (a numerical value from 1–8) from users who have
+    tested positive and provided their own random IDs via the App using the
+    feature for warning others. The transmission risk value is an estimate of
+    the likelihood of infection on the day of the possible exposure in
+    question. Since infectiousness (i.e. the risk of infection for those who
+    come into contact with a person who has tested positive) is currently
+    believed to depend on the duration and course of the infection, it can be
+    taken into account, for example, that the more time has passed since the
+    onset of symptoms, the lower the risk of infection on the day of a possible
+    exposure.
+</p>
+<p>
+    The App shares these random IDs with your smartphone’s exposure logging
+    functionality, which then compares them with the random
+    IDs logged by the exposure logging functionality. If your smartphone’s
+    exposure logging functionality detects a match, it transfers the exposure
+    data (date, duration, signal strength) to the App, but not the random ID of
+    the contact in question.
+</p>
+<p>
+    In the event of a potential exposure, the App analyses the exposure data
+    provided by the exposure logging functionality as well as the transmission
+    risk value in order to determine your individual risk of infection.
 </p>
 <p>
-    In the event of a contact, the App analyses the contact data provided by
-    the exposure logging functionality in order to determine your individual
-    risk of infection. The evaluation algorithm which determines how the
-    contact data is interpreted (for example, how the duration of a contact
-    influences the risk of infection) is based on current scientific findings.
-    To account for new findings as and when they arise, the RKI can update the
-    evaluation algorithm by adjusting its settings. The settings for the
-    evaluation algorithm are sent to the App together with the list of random
-    IDs of infected users.
+    The evaluation algorithm which determines how the exposure data and the
+    transmission risk value are interpreted (for example, how the duration of a
+    contact influences the risk of infection) is based on current scientific
+    findings. To account for new findings as and when they arise, the RKI can
+    update the evaluation algorithm by adjusting its settings. The settings for
+    the evaluation algorithm are sent to the App together with the list of
+    random IDs of infected users.
 </p>
 <p>
     The identification of your risk of infection is only carried out locally on
-    your smartphone, meaning that the data is processed offline. Once
-    identified, the risk of infection is also only stored in the App and is not
-    passed on to any other recipients (including the RKI, Apple, Google and
-    other third parties).
+    your smartphone, meaning that the data is processed offline without
+    accessing the App’s server system. Once identified, the risk of infection
+    is also only calculated in the App and is not passed on to any other
+    recipients (including the RKI, Apple, Google and other third parties).
 </p>
 <p>
-    The legal basis for the processing of your access data, contact data and,
-    if applicable, health data (if the App determines that you may have been
-    infected) described above is your consent which you gave when enabling the
-    exposure logging feature.
+    The legal basis for the processing of your access data, exposure data and,
+    if applicable, health data (if the App determines a possible exposure)
+    described above is your consent which you gave when enabling the risk
+    identification feature.
 </p>
 <h3>
     b. Registering a test
@@ -320,7 +361,7 @@
     number. The test result database is operated by the RKI on a special server
     within the App’s server system. Based on the code number contained in the
     QR code issued to you, the testing laboratory also generates the hashed
-    code number using the same mathematical procedure as the App.
+    code number using the same mathematical procedure as the App.<u></u>
 </p>
 <p>
     <u>Retrieval of the test result</u>
@@ -351,22 +392,34 @@
     above is your consent to using the test registration feature.
 </p>
 <h3>
-    c. Sharing your test result
+    c. Warning others
 </h3>
 <p>
-    If you use the feature for sharing your test result in order to warn other
-    users, the App will transfer the random IDs generated and stored by your
-    smartphone from the last 14 days and the TAN to the App’s server system.
-    The server system first checks whether the TAN is valid and then adds your
-    random IDs to the list of random IDs of users who have shared a positive
-    test result. Your random IDs can now be downloaded by other users as part
-    of the exposure logging process.
+    If you use the feature for warning others, the App will transfer the random
+    IDs (including the respective transmission risk values) generated and
+    stored by your smartphone from the last 14 days and the TAN to the App’s
+    server system. The server system first checks whether the TAN is valid and
+    then adds your random IDs to the list of random IDs of users who have
+    provided a positive test result. Your random IDs can now be downloaded by
+    other users as part of the risk identification process.
+</p>
+<p>
+    The information about symptoms and symptom onset requested by the feature
+    for warning others is optional and not required to warn other users.
+    However, this information can help to calculate more accurately the risk of
+    infection to other users you have encountered. If you can’t or don’t want
+    to answer some or all of the questions, just select “no answer”. In this
+    case, the transmission risk values determined by the App and assigned to
+    your random IDs will be based on the time that has passed since your test
+    result was retrieved, assuming an average infection – meaning that the more
+    time has passed since using a random ID, the lower its transmission risk
+    value will be.
 </p>
 <p>
     <u>If you have not retrieved your test result in the App:</u>
 </p>
 <p>
-    Even if you have not retrieved a positive test result in the app, you can
+    Even if you have not retrieved a positive test result in the App, you can
     share the test result via the App to warn other users. In this case, the
     App prompts you to enter a so-called TeleTAN, which acts as a TAN.
 </p>
@@ -375,7 +428,7 @@
     7540002. The operator will first ask you some questions over the phone to
     check the plausibility of your call. These questions serve to prevent
     fraudulent reports of infections and any resulting incorrect warnings and
-    risk status. Once you have answered these questions sufficiently, you will
+    risk levels. Once you have answered these questions sufficiently, you will
     be asked for your mobile/telephone number. This is so that you can be
     called back later and given a TeleTAN to enter in the App. Your
     mobile/telephone number will only be temporarily stored for this purpose
@@ -393,7 +446,7 @@
 <p>
     The legal basis for this processing of your access data and health data
     (random IDs, test result, TAN and, if applicable, TeleTAN) is your consent
-    to using the feature for sharing your test result.
+    to using the feature for warning others.
 </p>
 <h3>
     d. Using the App for information purposes only
@@ -402,9 +455,10 @@
     As long as you use the App for information purposes only, i.e. do not use
     any of the App features mentioned above and do not enter any data, then
     processing only takes place locally on your smartphone and no personal data
-    is generated. Websites linked in the app, such as www.bundesregierung.de,
-    will open in your smartphone’s standard browser. The data processed here
-    depends on the browser used, your browser settings, and the data processing
+    is generated. Depending on your operating system, websites linked in the
+    App, such as www.bundesregierung.de, will
+    open in your smartphone’s standard browser (Android smartphones) or within
+    the App (iPhone). The data processed here depends on the data processing
     practices of the website you are visiting.
 </p>
 <h2>
@@ -428,9 +482,9 @@
     </li>
 </ul>
 <p>
-    The App requires an internet connection for the exposure logging feature,
-    and so that it can receive and transmit test results, so that it can
-    communicate with the App’s server system.
+    The App requires an internet connection for the risk identification
+    feature, and so that it can receive and transmit test results, so that it
+    can communicate with the App’s server system.
 </p>
 <ul>
     <li>
@@ -476,10 +530,10 @@
     </li>
 </ul>
 <p>
-    The App’s exposure logging feature requires this functionality. Otherwise,
-    no exposure log with the random IDs of your contacts will be available. The
-    functionality must be enabled within the App to allow the App to access the
-    exposure log.
+    The App’s risk identification feature requires this functionality.
+    Otherwise, no exposure log with the random IDs of your contacts will be
+    available. The functionality must be enabled within the App to allow the
+    App to access the exposure log.
 </p>
 <ul>
     <li>
@@ -521,14 +575,14 @@
 </p>
 <ul>
     <li>
-        COVID-19 Exposure Logging
+        Exposure Notification
     </li>
 </ul>
 <p>
-    The App’s exposure logging feature requires this functionality, otherwise
-    no exposure log with the random IDs of your contacts will be available. The
-    functionality must be enabled within the App to allow the App to access the
-    exposure log.
+    The App’s risk identification feature requires this functionality,
+    otherwise no exposure log with the random IDs of your contacts will be
+    available. The functionality must be enabled within the App to allow the
+    App to access the exposure log.
 </p>
 <ul>
     <li>
@@ -559,7 +613,7 @@
     the App features:
 </p>
 <h3>
-    a. Exposure Logging
+    a. Risk identification
 </h3>
 <ul>
     <li>
@@ -568,18 +622,18 @@
         deleted from your smartphone’s exposure log after 14 days.
     </li>
     <li>
-        The RKI has no way of influencing the deletion of contact data in your
-        smartphone’s exposure log (including your own random IDs) and contact
-        data on other smartphones, as this functionality is provided by Apple
-        or Google. In this case, the deletion depends on what Apple or Google
-        has determined. Currently, the data is automatically deleted after 14
-        days. It may also be possible, using the functionality provided by
-        Apple and Google, to manually delete data in your device’s system
-        settings.
+        The RKI has no way of influencing the deletion of exposure data in the
+        exposure log of your smartphone’s exposure logging functionality
+        (including your own random IDs) and exposure data on other smartphones,
+        as this functionality is provided by Apple or Google. In this case, the
+        deletion depends on what Apple or Google has determined. Currently, the
+        data is automatically deleted after 14 days. It may also be possible,
+        using the functionality provided by Apple and Google, to manually
+        delete data in your device’s system settings.
     </li>
     <li>
-        The risk status displayed in the App will be deleted as soon as a new
-        risk status has been determined. A new risk status is usually
+        The risk of infection displayed in the App will be deleted as soon as a
+        new risk level has been determined. A new risk level is usually
         determined after the App has received a new list of random IDs.
     </li>
 </ul>
@@ -602,18 +656,23 @@
         The token stored on the server system will be deleted after 21 days.
     </li>
     <li>
-        The token stored in the app will be deleted from the smartphone after
-        the App is deleted or after using the feature for sharing the test
-        result.
+        The token stored in the App will be deleted from the smartphone after
+        the App is deleted or after using the feature for warning others.
     </li>
 </ul>
 <h3>
-    c. Sharing your test result
+    c. Warning others
 </h3>
 <ul>
     <li>
-        Your smartphone’s own random IDs which are shared in the App will be
-        deleted from the server system after 14 days.
+        Your smartphone’s own random IDs and transmission risk values which
+        are provided via the App will be deleted from the server system after
+        14 days.
+    </li>
+    <li>
+        Your information about symptoms and the onset of symptoms will be
+        deleted from the App immediately after the random IDs and transmission
+        risk values have been provided.
     </li>
     <li>
         The copy of the TAN stored on the server system will be deleted after
@@ -621,11 +680,11 @@
     </li>
     <li>
         The TAN stored in the App will be deleted after the test result has
-        been shared.
+        been provided.
     </li>
     <li>
         The TeleTAN stored in the App will be deleted after the test result has
-        been shared.
+        been provided.
     </li>
     <li>
         The TeleTAN stored on the server system will be deleted after 21 days.
@@ -639,22 +698,23 @@
     </li>
     <li>
         The token stored in the App will be deleted after the test result has
-        been shared.
+        been provided.
     </li>
 </ul>
 <h2>
     9. Who will receive your data?
 </h2>
 <p>
-    If you share a test result to warn other users, your random IDs from the
-    last 14 days will be passed on to the App on other users’ smartphones.
+    If you provide a test result by using the feature for warning other users,
+    your random IDs and their transmission risk values from the last 14 days
+    will be passed on to the App on other users’ smartphones.
 </p>
 <p>
-    The RKI has commissioned T-Systems International GmbH and SAP Deutschland
-    SE &amp; Co. KG to operate and maintain part of the technical
-    infrastructure of the App (e.g. server system, hotline), meaning that these
-    two companies are processors under data protection law and acting on the
-    RKI’s behalf (Article 28 GDPR).
+    The RKI has commissioned Deutsche Telekom AG and SAP Deutschland SE &amp;
+    Co. KG to operate and maintain part of the technical infrastructure of the
+    App (e.g. server system, hotline), meaning that these two companies are
+    processors under data protection law and acting on the RKI’s behalf
+    (Article 28 GDPR).
 </p>
 <p>
     Otherwise, the RKI will only pass on personal data collected in connection
@@ -679,10 +739,10 @@
     affect the lawfulness of the processing before the withdrawal.
 </p>
 <p>
-    To withdraw your consent to the exposure logging feature, you can disable
-    the feature using the toggle switch in the App or delete the App. If you
-    decide to use the exposure logging feature again, you can toggle the
-    feature back on or reinstall the App.
+    To withdraw your consent to the risk identification feature, you can
+    disable the feature using the toggle switch in the App or delete the App.
+    If you decide to use the risk identification feature again, you can toggle
+    the feature back on or reinstall the App.
 </p>
 <p>
     To withdraw your consent to the test registration feature, you can delete
@@ -693,14 +753,15 @@
     consent again.
 </p>
 <p>
-    To withdraw your consent to the sharing of your test result, you must
-    delete the App. All of your random IDs stored in the App will then be
-    removed and can no longer be assigned to your smartphone. If you wish to
-    report another test result, you can reinstall the App and grant your
-    consent again. Alternatively, you may be able to delete your own random IDs
-    in the exposure log in your smartphone’s system settings. Please note that,
-    once transmitted, the RKI has no way of deleting your random IDs from the
-    lists and from other users’ smartphones.
+    To withdraw your consent to the feature for warning others, you must delete
+    the App. All of your random IDs stored in the App will then be removed and
+    can no longer be assigned to your smartphone. If you wish to report another
+    test result, you can reinstall the App and grant your consent again.
+    Alternatively, you may be able to delete your own random IDs in the
+    exposure logging functionality in your smartphone’s system settings. Please
+    note that, once transmitted, the RKI has no way of deleting your random IDs
+    and transmission risk values from the lists provided and from other users’
+    smartphones.
 </p>
 <h2>
     12. Your other rights under data protection law
@@ -714,8 +775,9 @@
         the rights under Articles 15, 16, 17, 18, 20 and 21 GDPR,
     </li>
     <li>
-        the right to contact the official RKI data protection officer and raise
-        your concerns (Article 38(4) GDPR) and
+        the right to contact the official RKI data protection officer
+        (https://www.rki.de/DE/Content/Institut/OrgEinheiten/Datenschutz/Datenschutz_node.html)
+        and raise your concerns (Article 38(4) GDPR) and
     </li>
     <li>
         the right to lodge a complaint with a competent data protection
@@ -741,5 +803,5 @@
     you which is not available to the RKI.
 </p>
 <p>
-    Last amended: 12 June 2020
+    Last amended: 05 October 2020
 </p>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/assets/privacy_tr.html b/Corona-Warn-App/src/main/assets/privacy_tr.html
index c92bb2077e79d129f06a306a75f3b0e8b298dc32..b421d7df2c895672d1aadedaab6d117d5dca8f05 100644
--- a/Corona-Warn-App/src/main/assets/privacy_tr.html
+++ b/Corona-Warn-App/src/main/assets/privacy_tr.html
@@ -10,126 +10,128 @@
     koruma haklarına sahip olduğunuzu öğrenirsiniz.
 </p>
 <p>
-    Tüm kullanıcıların anlayabilmesi için bu veri gizliliği beyanını mümkün
-    olduğu kadar teknik olmayan ve basit şekilde açıklamaya çalıştık.
+    Bu veri gizliliği beyanının tüm kullanıcılar tarafından anlaşılabilmesi
+    için basit ve mümkün oldukça teknik olmayan şekilde anlatmaya çalıştık.
 </p>
-<h2>
+<h1>
     1. Bu uygulamayı size kim sunuyor?
-</h2>
+</h1>
 <p>
     Corona-Warn-App (bundan böyle "<strong>UYGULAMA</strong>") Nordufer 20,
     13353 Berlin adresinde bulunan Robert Koch-Institut (bundan böyle "<strong>RKI</strong>")
-    sunuyor.
-</p>
-<p>
-    RKI, veri koruma hukuku açısından da UYGULAMA kullanıcılarının kişisel
-    verilerinin iÅŸlenmesinden sorumludur.
+    sunuyor. RKI, veri koruma hukuku açısından da
+    UYGULAMA kullanıcılarının kişisel verilerinin işlenmesinden sorumludur.
 </p>
 <p>
-    Yukarıda anılan adres (zu Händen „Behördlicher Datenschutzbeauftragter“
-    – "Resmi Veri Koruma Görevlisi" dikkatine) ve datenschutz@rki.de
-    e-posta adresi aracılığıyla RKI'nin veri koruma görevlisine
-    ulaÅŸabilirsiniz.
+    Yukarıda anılan adres (zu Händen "Behördlicher Datenschutzbeauftragter" –
+    "Resmi Veri Koruma Görevlisi" dikkatine) ve datenschutz@rki.de e-posta
+    adresi aracılığıyla RKI'nin veri koruma görevlisine ulaşabilirsiniz.
 </p>
-<h2>
+<h1>
     2. UYGULAMA'nın kullanımı isteğe mi bağlı?
-</h2>
-<p>
-    UYGULAMA'nın kullanımı tamamen isteğe bağlıdır. Bu sebeple, UYGULAMA'yı
-    kullanıp kullanmamaya ve nasıl kullanacağınıza bizzat kendiniz karar
-    verirsiniz.
-</p>
+</h1>
 <p>
-    UYGULAMA'nın yüklenmesi ve kullanımı tamamen isteğe bağlı olsa da,
-    UYGULAMA'yı ilk açtığınızda, UYGULAMA'nın maruz kalma günlüğü için kişisel
-    verilerinizi işleyebilmesi için "Maruz kalma günlüğünü etkinleştir"
-    düğmesine tıklayarak RKI'ye onayınızı beyan etmelisiniz. UYGULAMA sizin
-    için bir enfeksiyon riski tespit ederse, verileriniz, sağlık verilerini de
-    oluşturur. Aksi takdirde UYGULAMA akıllı telefonunuzun temas kayıt işlevine
-    erişemeyeceği için, Kabul etmeniz gereklidir. Maruz kalma günlüğünü
-    dilediğinizde UYGULAMA içerisindeki butondan devre dışı bırakabilirsiniz.
-    Bu durumda UYGULAMA'nın tüm işlevlerini kullanamazsınız. Aşağıdaki
-    işlevlerin veri işlemesi için özel onayınız ayrıca gereklidir:
+    UYGULAMA'nın kullanımı, isteğe bağlıdır. Bu yüzden, Uygulamayı yükleyip
+    yüklememe ve kullanacağınız işlevleri seçme kararı size aittir. Verileriniz
+    (örneğin, temas ve enfeksiyon riskleriniz) sadece kendi akıllı
+    telefonunuzda oluşturulur ve saklanır. Verileriniz RKI, akıllı
+    telefonunuzun işletim sistemi ya da diğer kullanıcılara sadece aşağıdaki
+    uygulama işlevlerinden birini kullanmanız ve gerekli veri aktarımına izin
+    vermeniz halinde aktarılır:
 </p>
 <ul>
+    <li>
+        Maruz kalma (6 a numaralı başlığa bakınız)
+    </li>
     <li>
         Test kaydetme (6 b numaralı başlığa bakınız)
     </li>
     <li>
-        Test sonucunuzu paylaşma (6 c numaralı başlığa bakınız)
+        Diğerlerini uyar (6 c numaralı başlığa bakınız)
     </li>
 </ul>
+<p>
+    Bu iÅŸlevleri kullanmak zorunda deÄŸilsiniz. Bu iÅŸlevlerin gerektirdiÄŸi
+    onayları vermek istemez ya da bunları sonradan geri almayı isterseniz, bu
+    durum sizin açınızdan dezavantaj oluşturmaz. Onaya tabi uygulama
+    iÅŸlevlerini dilerseniz kullanmayabilirsiniz.
+</p>
 <p>
     Bu işlevler çerçevesinde yapılan veri işleme aşağıdaki bölümlerde ayrıntılı
     şekilde açıklanmıştır.
 </p>
-<h2>
+<h1>
     3. Verileriniz hangi hukuki dayanakla iÅŸlenir?
-</h2>
+</h1>
 <p>
     RKI, esas itibariyle Avrupa Birliği Genel Veri Koruma Tüzüğü (GDPR) madde 6
     paragraf 1 cümle 1 bent a ve madde 9 paragraf 2 bent a uyarınca kişisel
-    verilerinizi sadece verdiğiniz onaya dayanarak işler. Verdiğiniz onayı,
-    dilediğinizde geri alabilirsiniz. Cayma hakkınız hakkındaki diğer bilgileri
-    ve bu hakkı nasıl kullanacağınız hakkındaki talimatları madde 11'de
-    bulabilirsiniz.
+    verilerinizi sadece verdiğiniz onaya dayanarak işler. Verdiğiniz onayı
+    dilediğinizde geri alabilirsiniz. Geri alma hakkı ve bu hakkı nasıl
+    kullanacağınıza ilişkin açıklamalar hakkında diğer bilgileri 11 numaralı
+    başlıkta bulabilirsiniz.
 </p>
-<h2>
+<h1>
     4. UYGULAMA kimlere yöneliktir?
-</h2>
+</h1>
 <p>
     UYGULAMA, Almanya'da ikamet eden ve en az 16 yaşında olan kişilere
     yöneliktir.
 </p>
-<h2>
+<h1>
     5. Hangi kiÅŸisel veriler iÅŸlenir?
-</h2>
+</h1>
 <p>
     UYGULAMA, mümkün olduğu kadar az sayıda kişisel veri işlenecek şekilde
-    tasarlanmıştır. Bununla kastedilen, örneğin UYGULAMA RKI ya da diğer
+    tasarlanmıştır. Bununla kastedilen, UYGULAMA’nın, RKI ya da diğer
     kullanıcıların kimliğinizi, sağlık durumunuzu ya da konumunuzu öğrenmesine
-    imkan verecek bilgileri toplamadığıdır. UYGULAMA ayrıca, kullanım
+    imkan verecek bilgileri toplamamasıdır. UYGULAMA ayrıca, kullanım
     davranışınızın izleme araçları (Tracking Tool) tarafından tespit ya da
     analiz edilmesine imkan tanımaz.
 </p>
 <p>
     UYGULAMA tarafından işlenen veriler aşağıdaki kategorilere ayrılır:
 </p>
+<h2>
+    a. EriÅŸim verileri
+</h2>
 <p>
-    <strong>a. EriÅŸim verileri</strong>
-</p>
-<p>
-    Aşağıdaki işlevleri kullanıyorsanız veya etkinleştiriyorsanız, erişim
-    verileri oluÅŸur:
+    UYGULAMA ile UYGULAMA'nın sunucu sistemi arasında internet aracılığıyla
+    yapılan her veri alışverişinde, sunucu sistemi tarafından erişim verileri
+    işlenir. Bu durum, UYGULAMA'nın sunucu sisteminden güncel verileri
+    çağırabilmesi ya da akıllı telefonda saklanan belirli verileri sunucu
+    sistemine aktarabilmesi için gereklidir. Aşağıdaki UYGULAMA işlevleri,
+    UYGULAMA'nın sunucu sistemi ile bu tür bir veri alışverişi yapmasını
+    gerektirir:
 </p>
 <ul>
     <li>
-        Maruz kalma günlüğü
+        Maruz kalma (test sonucu pozitif kullanıcıların rastgele kimliklerinden
+        oluşan listenin çağrılması)
     </li>
     <li>
-        Test kaydetme
+        Test kaydetme (test tanıtma sayısının iletilmesi ve test sonucunun
+        çağrılması)
     </li>
     <li>
-        Test sonucunuzu paylaÅŸma
+        DiÄŸerlerini uyar (rastgele kimliÄŸinizin iletilmesi)
     </li>
 </ul>
 <p>
-    UYGULAMA'nın sunucu sisteminden her veri çağırdığınızda, IP adresiniz
-    (sunucular arası yükü dengeleyen Load Balancer'da) gizlenir ve sonraki
-    işlemlerde UYGULAMA'nın sunucu sistemleri dahilinde işlenmez.
-</p>
-<p>
-    Ek olarak, aşağıdaki veriler işlenir:
+    Erişim verileri, aşağıdaki verileri kapsar:
 </p>
 <ul>
+    <li>
+        IP adresi
+    </li>
     <li>
         Çağırmanın tarih ve saati (zaman kaydı)
     </li>
     <li>
-        taşınan veri miktarı (örn., paket uzunluğu)
+        iletilen veri miktarı (örn., paket uzunluğu)
     </li>
     <li>
-        Başarılı çağırmalar hakkında bildirim
+        Başarılı çağırma hakkında bildirim
     </li>
 </ul>
 <p>
@@ -139,143 +141,156 @@
     saklanmaz.
 </p>
 <p>
-    <strong>b. Maruz kalma verileri</strong>
+    Kullanım esnasında IP adresiniz aracılığıyla verilerinizin yetkisiz şekilde
+    sınıflandırılmasını engellemek için UYGULAMA, sunucu sistemine özel bir
+    başlangıç sunucusu aracılığıyla erişir. Bu başlangıç sunucusu, UYGULAMA
+    tarafından istenen ya da iletilen verileri, IP adresiniz olmadan söz konusu
+    yetkili sunucuya ilettiği için bu veriler artık sunucu sisteminde
+    iÅŸlenemez.
 </p>
+<h2>
+    b. Temas verileri
+</h2>
 <p>
-    Akıllı telefonunuzda, işletim sistemindeki diğer kullanıcılar için temas
-    kaydı işlevini etkinleştirirseniz, akıllı telefonunuz yakın çevrenizdeki
-    temas kaydı etkinleştirilmiş akıllı telefonlardan alınan rastgele
-    kimlikleri (bundan böyle: "<strong>Rastgele Kimlikler"</strong>) olarak da
-    anılan, sürekli rastgele oluşturulan tanıtıcı numaraları Bluetooth Low
-    Energy aracılığıyla gönderir. Aynı şekilde, akıllı telefonunuz da diğer
-    akıllı telefonların rastgele kimliklerini alır. Diğer akıllı telefonlardan
-    alınan rastgele kimliklere, akıllı telefonunuzun temas kayıt işlevi ve
-    ayrıca aşağıdaki maruz kalma verileri kaydedilir ve saklanır:
+    Akıllı telefonunuzda, işletim sistemindeki maruz kalma günlüğünü
+    etkinleştirirseniz, akıllı telefonunuz temas kaydı etkin olan yakınınızdaki
+    diğer akıllı telefonlardan alınan, rastgele kodlar olarak da tanımlanan,
+    sürekli ve rastgele oluşturulan tanıtma sayılarını (bundan sonra: "<strong>Rastgele
+    Kimlikler"</strong>) Bluetooth Low Energy aracılığıyla
+    gönderir. Aynı şekilde, akıllı telefonunuz da diğer akıllı telefonların
+    rastgele kimliklerini alır. Diğer akıllı telefonlardan alınan rastgele
+    kimliklere, akıllı telefonunuzun temas kayıt işlevinden ek olarak aşağıdaki
+    temas verileri tanımlanır:
 </p>
 <ul>
-    <li>
-        Temasın tarihi ve saati
-    </li>
-    <li>
-        Temasın süresi
-    </li>
-    <li>
-        Temasın Bluetooth sinyal gücü
-    </li>
-    <li>
-        Şifrelenmiş meta veriler (protokol sürümü ve verici gücü).
-    </li>
+    <li>Temasın tarihi ve saati</li>
+    <li>Temasın süresi</li>
+    <li>Temasın Bluetooth sinyal gücü</li>
+    <li>Şifreli meta veriler (protokol sürümü ve gönderme gücü)</li>
 </ul>
 <p>
-    Akıllı telefonunuzun kendi rastgele kimliği ve diğer akıllı telefonlardan
-    alınan rastgele kimlikler ve diğer maruz kalma verileri (temasın tarihi ve
-    saati, temasın süresi, temasın sinyal gücü ve şifrelenmiş meta veriler)
-    akıllı telefonunuz tarafından temas kayıt işlevinin temas protokolünde
-    kaydedilir ve halihazırda 14 gün boyunca saklanır.
+    Akıllı telefonun kendi ve diğer akıllı telefonlardan aldığı rastgele
+    kimlikler ve diğer temas verileri (temasın tarihi ve saati, temasın süresi,
+    temasın sinyal gücü ve şifreli meta veriler) akıllı telefonunuzun temas
+    kayıt işlevi tarafından toplanır ve orada 14 gün boyunca saklanır.
 </p>
 <p>
-    Android akıllı telefonlarda bu temas kayıt işlevinin adı "COVID-19 Temas
-    Bildirimleri Sistemi" ve iPhone'larda "COVID-19'a Maruz Kalma Günlüğü"dür.
-    Bu temas kayıt işlevlerinin UYGULAMA'nın parçası olmadığını, aksine akıllı
-    telefonunuzun işletim sisteminin ayrılmaz bir parçası olduğunu
-    hatırlatırız. Temas kayıt işlevi bu yüzden size Apple (iPhone) ve Google
-    (Android akıllı telefonlar) tarafından hazırlanır ve bu yüzden bu
-    işletmelerin veri koruma kurallarına tabidir. Temas kayıt işlevi
-    çerçevesindeki işletim sistemindeki veri işleme, RKI'nin etki alanının
-    dışında kalır.
+    Temas kayıt işlevi, Android akıllı telefonlarda "COVID 19 bildirimleri" ve
+    iPhone akıllı telefonlarda "temas bildirimleri" olarak anılır. Bu
+    işlevlerin, UYGULAMA'nın parçası olmadığını, aksine işletim sisteminizin
+    ayrılmaz bir parçası olduğunu hatırlatırız. Bu yüzden, temas kayıt
+    işlevlerinin sağlayıcısı Apple (iPhone) ve Google (Android akıllı
+    telefonlar)'dır. Temas kayıt işlevleri aracılığıyla işletim sistemi
+    tarafından veri işleme, bu şirketlerin ilgili veri koruma kurallarına
+    tabidir ve RKI'nin sorumluluk ve etki alanının haricindedir.
 </p>
 <p>
-    Android akıllı telefonların temas kayıt işlevine ilişkin diğer bilgilere şu
-    adresten eriÅŸebilirsiniz:
-    https://support.google.com/android/answer/9888358?hl=de.
+    Bu konuya ilişkin diğer bilgileri, temas kayıt işlevinin sağlayıcıları
+    sunar:
 </p>
+<ul>
+    <li>
+        Android akıllı telefonlar için Google bilgileri:
+        https://support.google.com/android/answer/9888358?hl=de
+    </li>
+    <li>
+        iPhone için Apple bilgilerini aygıtınızda "Ayarlar" &gt; "Temas
+        bildirimleri" kısmında "Temas bildirimleri bu şekilde çalışır …"
+        bağlantısında bulabilirsiniz.
+    </li>
+</ul>
 <p>
-    Apple'ın temas kayıt işlevi ile ilgili diğer bilgilere, iPhone'unuzun
-    ayarlar kısmındaki "Gizlilik" &gt; "Sağlık" &gt; "COVID-19'a Maruz Kalma
-    Günlüğü" kısmından erişebilirsiniz. Lütfen dikkat ediniz: Temas kayıt
-    işlevini, iPhone'unuzda Sürüm 13.5 ve üstü iOS işletim sistemleri yüklüyse,
-    kullanabilirsiniz.
+    Tanımlamalar, işletim adımları ve temas kayıt işlevi ayar olanaklarının,
+    işletim sisteminizin sürüm ve yapılandırmasına göre bu veri gizliliği
+    beyanındaki şeklinden farklı olabileceğini dikkate alın.
 </p>
 <p>
-    Akıllı telefonun oluşturduğu ve sakladığı maruz kalma verileri UYGULAMA
-    tarafından, sadece maruz kalma günlüğü etkinleştirildiyse işlenir.
+    İşletim sisteminizin oluşturduğu ve sakladığı temas verileri, maruz kalma
+    günlüğünün etkinleştirilmiş olması halinde UYGULAMA tarafından işlenir.
 </p>
-<h3>
-    a. Sağlık verileri
-</h3>
+<h2>
+    c. Sağlık verileri
+</h2>
 <p>
     Sağlık verileri, belirli bir kişinin sağlık durumuna ilişkin bilgiler
     içeren tüm verilerdir. Bunlara sadece eski ve güncel hastalıklara ilişkin
     bilgiler değil, ayrıca bir kişinin hastalık risklerine ilişkin bilgiler de
-    dahildir (örn. kişiye koronavirüsün bulaşma riski).
+    dahildir (örn. kişiye koronavirüsün bulaş riski).
 </p>
 <p>
-    Aşağıdaki durumlarda sağlık verilerinin işlenmesi söz konusudur:
+    Aşağıdaki işlevler kullanılırken UYGULAMA, sağlık verilerinizi işler:
 </p>
 <ul>
-    <li>
-        Maruz kalma günlüğü, koronavirüs ile enfekte olan kişi ile olası
-        temasını olduğunu tespit ettiğinde.
+    <li>Maruz kalma tespit edilir edilmez (örn. koronavirüs bulaşmış bir kişi ile
+        olası temasınız olduysa) maruz kalma günlüğü.
     </li>
-    <li>
-        Bir testi kaydettiÄŸinizde.
-    </li>
-    <li>
-        Pozitif test sonucu paylaştığınızda.
+    <li>Test kaydetme (test durumu ve test sonucu)</li>
+    <li>Diğerlerini uyar (test sonucu, bulgu ve bulgu başlangıcına ilişkin güncel
+        bilgiler)
     </li>
 </ul>
-<h2>
+<h1>
     6. UYGULAMA'nın işlevleri
-</h2>
-<h3>
+</h1>
+<h2>
     a. Maruz kalma günlüğü
-</h3>
+</h2>
 <p>
-    Maruz kalma günlüğü, UYGULAMA'nın çekirdek işlevidir. UYGULAMA'nın amacı
-    koronavirüs ile enfekte olmuş diğer kullanıcılara olası bir teması takip
-    etmek, bu yüzden sizin için oluşan enfeksiyon riskini değerlendirmek ve
-    sizin için tespit edilen toplam risk puanına göre davranış ve sağlık
-    talimatları hazırlamaktır.
+    Maruz kalma günlüğü, UYGULAMA'nın temel işlevidir. Koronavirüs bulaşmış
+    diğer kullanıcılar ile olası temasları (maruz kalmalar) takip etmeye,
+    enfeksiyon riskini değerlendirmeye ve sizin için davranış ve sağlık
+    tavsiyeleri vermeye yarar.
 </p>
 <p>
-    Maruz kalma günlüğünü etkinleştirdiğinizde, UYGULAMA arka plan işletimdeki
-    sunucu sistemlerinden test sonuçları pozitif çıkmış ve kendi rastgele
-    kimliklerini paylaşmış olan diğer kullanıcıların rastgele kimliklerinden
-    oluşan listeyi günde bir kaç defa (ya da "Güncelleme" düğmesini
-    tıklattığınızda) çağırır. UYGULAMA, akıllı telefonunuzun temas protokolünde
-    saklanan rastgele kimlikleri ile karşılaştıracağı rastgele kimlikleri,
-    akıllı telefonunuzun temas kayıt işlevine iletir. Akıllı telefonunuzun
-    temas kayıt işlevi bir eşleştirme belirlerse, UYGULAMA'ya maruz kalma
-    verilerini (tarih, süre, sinyal gücü) verir, ancak ilgili temasın rastgele
-    kimliÄŸini vermez.
+    Maruz kalma günlüğünü etkinleştirirseniz, UYGULAMA, UYGULAMA'nın arka
+    plandaki sunucu sistemlerinden günde birden fazla defa (ya da "Güncelle"
+    seçeneğine tıklarsanız) taşıma riski değerleri (1 ile 8 arasında sayısal
+    deÄŸerler) ve rastgele kimlikleri ile test sonucu pozitif olan ve kendi
+    rastgele kimliklerini "Diğerlerini uyar" işlevi ile UYGULAMA üzerinden
+    sunan kullanıcıların listesini çağırır. Taşıma riski değeri, ilgili maruz
+    kalmanın bulaşma olasılığının seviyesinin değeridir. Bulaşıcılık (test
+    sonuçları pozitif kişilerin temaslarının bulaş riski seviyesi), o andaki
+    bilgi seviyesine göre bulaşıcı hastalığın seyir ve süresine bağlı
+    olduğundan, bulgu başlangıcından itibaren geçen zamana göre maruz kalmanın
+    bulaş riski azaldığı dikkate alınır.
 </p>
 <p>
-    Temas halinde, bireysel enfeksiyon riskinizi tespit etmek amacıyla temas
-    kayıt işlevi tarafından iletilen maruz kalma verileri UYGULAMA tarafından
-    analiz edilir. Maruz kalma verilerinin nasıl yorumlanması gerektiğini
+    UYGULAMA, rastgele kimlikleri akıllı telefonunuzun temas kayıt işlevine
+    iletir ve bunlar da temas kayıt tarafından düzenlenen rastgele kimlikler
+    ile birleştirilir. Akıllı telefonunuzun temas kayıt işlevi bir eşleşme
+    tespit ederse, UYGULAMA'ya temas verilerini (tarih, süre, sinyal gücü)
+    iletir, ilgili temasın rastgele kimliklerini iletmez.
+</p>
+<p>
+    Maruz kalma halinde, temas kayıt işlevinin verdiği temas verileri ve de
+    taşıma risk değeri, bireysel bulaşıcı hastalık riskinizin tespit
+    edilebilmesi için UYGULAMA tarafından analiz edilir.
+</p>
+<p>
+    Temas verileri ve taşıma risk değerinin nasıl yorumlanması gerektiğini
     belirleyen (örn. temas süresinin, enfeksiyon riski üzerinde ne tür bir
     etkisinin olduğu) değerlendirme algoritması, sahip olunan güncel bilimsel
     bilgilere dayanır. Bu yüzden yeni bilgiler edinildiğinde değerlendirme
     algoritmasının ayarları RKI tarafından yeniden yapılır ve değerlendirme
     algoritması bu şekilde güncellenebilir. Değerlendirme algoritmasının
-    ayarları, enfekte olan kişilerin rastgele kimliklerinden oluşan liste ile
-    birlikte UYGULAMA'ya iletilir.
+    ayarları, enfekte olan kullanıcıların rastgele kimlikleri ile birlikte
+    UYGULAMA'ya iletilir.
 </p>
 <p>
-    Enfeksiyon riskinin tespiti sadece akıllı telefonunuzda lokal olarak
-    gerçekleşir, yani veriler çevrimdışı işlenir. Tespit edilen enfeksiyon
-    riski de aynı şekilde sadece UYGULAMA'da saklanır ve başka alıcılara (RKI,
-    Apple, Google ve diğer üçüncü taraflara) verilmez.
+    Bulaş riski tespiti sadece lokal olarak akıllı telefonunuzda yapılır;
+    bununla kastedilen, verilerin UYGULAMA'nın sunucu sistemine erişimler
+    olmaksızın çevrimdışı işleneceğidir. Tespit edilen enfeksiyon riski de
+    sadece UYGULAMA tarafından hesaplanır ve diğer alıcılara (RKI, Apple,
+    Google ve üçüncü taraflara da iletilmez) iletilmez.
 </p>
 <p>
-    Erişim verilerinizin, maruz kalma verilerinizin ve gerekirse sağlık
-    verilerinizin (sizin için bir enfeksiyon riski tespit edilmişse) yukarıda
-    anıldığı gibi işlenmesinin hukuki dayanağı, maruz kalma günlüğü
-    etkinleştirme esnasında verdiğiniz onaydır.
+    Erişim verileriniz, temas verileriniz ve varsa, sağlık verilerinize (maruz
+    kalma algılanırsa) ilişkin yukarıda anılan veri işlemenin hukuki dayanağı,
+    maruz kalma günlüğünü etkinleştirme esnasında vermiş olduğunuz onayınızdır.
 </p>
-<h3>
+<h2>
     b. Test kaydetme
-</h3>
+</h2>
 <p>
     Koronavirüs enfeksiyonu için test olduysanız, bu testi doktorunuz ya da
     test kuruluşundan aldığınız QR kodunu UYGULAMA'da tarayarak, UYGULAMA'ya
@@ -346,29 +361,35 @@
     tabanından, karma kod numarasının pozitif bir test sonucu bulunduğuna dair
     bir onay ister. Test sonucu veri tabanı bunu onaylarsa, sunucu sistemi
     TAN'ı oluşturur ve UYGULAMA'ya iletir. TAN'ın bir kopyası sunucu sisteminde
-    kalır.
-</p>
-<p>
-    Pozitif bir test sonucunun iletilmesi halinde yanlış bilgilerin diğer
-    kullanıcılar ile paylaşılmamasını sağlamak için TAN gereklidir.
-</p>
-<p>
+    kalır. Pozitif bir test sonucunun iletilmesi halinde yanlış bilgilerin
+    diğer kullanıcılar ile paylaşılmamasını sağlamak için TAN gereklidir.
     Anılan verilerin yukarıda açıklandığı şekilde işlenmesinin hukuki dayanağı,
     "Test kaydetme" işlevine verdiğiniz onaydır.
 </p>
-<h3>
-    c. Test sonucunuzu paylaÅŸma
-</h3>
+<h2>
+    c. DiÄŸerlerini uyar
+</h2>
 <p>
-    Diğer kullanıcıları uyarmak için "Test sonucunuzu paylaşma" işlevini
-    kullanırsanız, UYGULAMA akıllı telefonunuzda kayıtlı olan son 14 güne ait
-    rastgele kimliklerinizi ve TAN'ı UYGULAMA'nın sunucu sistemine iletir.
-    Sunucu sistemi öncelikle TAN'ın geçerli olup olmadığını kontrol eder ve
-    rastgele kimliklerinizi, pozitif test sonucu paylaşan kullanıcıların
-    rastgele kimliklerinden oluşan listeye taşır. Bundan böyle rastgele
+    "Diğerlerini uyar" işlevini kullanıyorsanız, UYGULAMA, akıllı telefonunuzda
+    saklanan, son 14 güne ait rastgele kimlikleri (ilgili taşıma risk değerleri
+    dahil) ve TAN'ı UYGULAMA'nın sunucu sistemine iletir. Burada ilk olarak
+    TAN'ın geçerli olup olmadığı denetlenir ve rastgele kimliklerinizi, pozitif
+    test sonucunu sunan kullanıcı listesine kaydeder. Bundan böyle rastgele
     kimlikleriniz, maruz kalma günlüğü çerçevesinde diğer kullanıcılar
     tarafından indirilebilir.
 </p>
+<p>
+    "Diğerlerini uyar" işlevinin sorguladığı, bulgu ve bulgu başlangıcına
+    ilişkin bilgiler, tercihe bağlıdır ve diğer kullanıcıları uyarmak için
+    gerekli değildir. Ancak, bu bilgiler, karşılaştığınız diğer kullanıcıların
+    enfeksiyon riskini daha iyi hesaplamaya yardım eder. Başka ya da hiçbir
+    soruyu yanıtlamak istemiyorsanız, "bilgi yok" seçeneğini seçebilirsiniz. Bu
+    durumda, rastgele kimliğinizin taşıma risk değerleri, test sonucunun
+    çağrılmasından itibaren geçen zaman aracılığıyla UYGULAMA tarafından
+    ortalama bir enfeksiyon sürecinin esas alınması ile belirlenir, daha
+    doğrusu bir rastgele kimliğin kullanılmasından uzun süre geçtiyse, taşıma
+    risk değeriniz daha düşüktür.
+</p>
 <p>
     <u>Test sonucunuzu UYGULAMA'da çağırmadıysanız:</u>
 </p>
@@ -403,35 +424,36 @@
     sonucu, TAN ve TeleTAN) işlenmesinin hukuki dayanağı, "Test sonucunuzu
     paylaşma" işlevine verdiğiniz onaydır.
 </p>
-<p>
-    <strong>d. UYGULAMA'nın bilgi amaçlı kullanımı</strong>
-</p>
+<h3>
+    d. UYGULAMA'nın bilgi amaçlı kullanımı
+</h3>
 <p>
     UYGULAMA'yı sadece bilgi amaçlı kullanıyorsanız, daha doğrusu UYGULAMA'nın
     yukarıda anılan hiçbir işlevini kullanmıyorsanız ve hiçbir veri
     girmiyorsanız, veri işleme sadece akıllı telefonunuzda yapılır ve hiçbir
-    kişisel veri meydana gelmez. UYGULAMA'da bağlantı kurulan:
-    www.bundesregierung.de gibi web sayfaları akıllı telefonunuzun standart
-    tarayıcısında açılır ve gösterilir. Hangi verilerin işleneceği, kullanılan
-    tarayıcıya, yapılandırmasına ve de çağrılan web sayfasının veri işleme
+    kişisel veri meydana gelmez. UYGULAMA'da bağlantı kurulan: www.bundesregierung.de gibi web
+    siteleri iÅŸletim
+    sistemine bağlı olarak akıllı telefonunuzun (Android akıllı telefonlar)
+    standart tarayıcısında ya da Uygulamada (iPhone) açılır ve görüntülenir. Bu
+    esnada hangi verilerin işleneceği, çağrılan web sitesinin veri işleme
     uygulamasına bağlıdır.
 </p>
-<h2>
+<h1>
     7. UYGULAMA hangi yetkilendirme ve iÅŸlevleri gerektirir?
-</h2>
+</h1>
 <p>
     UYGULAMA, akıllı telefonunuzun çeşitli işlevlerine ve ara yüzlerine erişim
     gerektirir. Bunun için, UYGULAMA'nın belirli yetkilendirmeleri istemesi
     gereklidir. Yetkilendirmeler, çeşitli üreticiler tarafından farklı
     programlanır. Bu sayede, yetkilendirme kategorisini topluca kabul
-    edebileceğiniz şekilde örn., yetkilendirme kategorilerine ilişkin tekil
+    edebileceğiniz şekilde örneğin, yetkilendirme kategorilerine ilişkin tekil
     yetkilendirmeler toplanabilir. UYGULAMA aracılığıyla bir erişimin reddi
     halinde UYGULAMA'nın hiçbir işlevini kullanamayacağınızı ya da çok az
     işlevini kullanabileceğinizi lütfen dikkate alın.
 </p>
-<h3>
+<h2>
     a. Teknik şartlar (tüm akıllı telefonlar)
-</h3>
+</h2>
 <ul>
     <li>
         Ä°nternet
@@ -473,22 +495,22 @@
     işletimini devre dışı bırakırsanız, tüm eylemleri UYGULAMA'da bizzat
     başlatmalısınız.
 </p>
-<h3>
+<h2>
     b. Android akıllı telefonlar
-</h3>
+</h2>
 <p>
     Android cihaz kullanıyorsanız, aşağıdaki sistem işlevleri ayrıca
     etkinleÅŸtirilmelidir:
 </p>
 <ul>
     <li>
-        COVID-19 Temas Bildirimleri Sistemi
+        COVID-19 Bildirimleri
     </li>
 </ul>
 <p>
-    Temaslarınızın rastgele kimlikleri ile aksi takdirde hiçbir temas protokolü
-    sunulmadığından, maruz kalma günlüğü bu işlevi gerektirir. İşlev,
-    UYGULAMA'nın temas protokolüne erişebilmesi için UYGULAMA dahilinde
+    Maruz kalma günlüğü temaslarınızın rastgele kimlikleri ile başka hiçbir
+    temas protokolü sunulmadığından bu işlevi gerektirir. İşlev, UYGULAMA'nın
+    temas protokolüne erişebilmesi için UYGULAMA dahilinde
     etkinleÅŸtirilmelidir.
 </p>
 <ul>
@@ -523,15 +545,15 @@
     UYGULAMA, test kaydı esnasında QR kodunu okuyabilmek için kameraya
     eriÅŸebilmelidir.
 </p>
-<h3>
+<h2>
     c. iPhone (Apple iOS)
-</h3>
+</h2>
 <p>
     iPhone kullanıyorsanız, aşağıdaki sistem işlevleri etkinleştirilmelidir:
 </p>
 <ul>
     <li>
-        COVID-19'a Maruz Kalma Günlüğü
+        Temas bildirimleri
     </li>
 </ul>
 <p>
@@ -561,16 +583,16 @@
     UYGULAMA, test kaydı esnasında QR kodunu okuyabilmek için kameraya
     eriÅŸebilmelidir.
 </p>
-<h2>
+<h1>
     8. Veriler ne zaman silinir?
-</h2>
+</h1>
 <p>
     UYGULAMA'da saklanan tüm veriler, UYGULAMA'nın işlevleri için ihtiyaç
     kalmadığında silinir:
 </p>
-<h3>
+<h2>
     a. Maruz kalma günlüğü
-</h3>
+</h2>
 <ul>
     <li>
         Pozitif test sonucu paylaşan kullanıcılara ilişkin liste, UYGULAMA'da
@@ -578,25 +600,25 @@
         sonra otomatik silinir.
     </li>
     <li>
-        Akıllı telefonunuzun temas protokolünde maruz kalma verileri (kendi
-        rastgele kimlikleriniz dahil) ve diğer akıllı telefonlardaki maruz
-        kalma verilerinin silinmesine iliÅŸkin olarak RKI'nin, bu iÅŸlev Apple
-        veya Google tarafından hazırlandığı için hiçbir etkisi yoktur. Silme
-        işlemi Apple veya Google'ın kararlarına göre gerçekleşir. Veriler şu
-        anda 14 gün sonra otomatik silinir. Ayrıca cihazınızın sistem
-        ayarlarında Apple ve Google tarafından sunulan fonksiyonları kullanarak
-        bunları manuel olarak silebilirsiniz.
+        Bu işlevler Apple ya da Google tarafından sunulduğu için akıllı
+        telefonunuzun temas kayıt iletişim protokolündeki temas verilerinin
+        (kendi rastgele kimlikleriniz dahil) ve diğer akıllı telefonlardaki
+        temas verilerinin silinmesine ilişkin olarak RKI'nin hiçbir etkisi
+        yoktur. Silme işlemi Apple veya Google'ın kararlarına göre gerçekleşir.
+        Veriler şu anda 14 gün sonra otomatik silinir. Ayrıca cihazınızın
+        sistem ayarlarında Apple ve Google tarafından sunulan fonksiyonları
+        kullanarak bunları manuel olarak silebilirsiniz.
     </li>
     <li>
-        Yeni toplam risk puanı tespit edildiğinde UYGULAMA'da görüntülenen
-        toplam risk puanı silinir. Yeni toplam risk puanı kural olarak
+        Yeni toplam risk puanı tespit edilir edilmez UYGULAMA'da görüntülenen
+        enfeksiyon risk değeri silinir. Yeni toplam risk puanı kural olarak
         UYGULAMA, rastgele kimliklerinden oluşan listeyi aldıktan sonra tespit
         edilir.
     </li>
 </ul>
-<h3>
+<h2>
     b. Test kaydetme
-</h3>
+</h2>
 <ul>
     <li>
         Karma kod numarası, 21 gün sonra UYGULAMA'nın sunucu sisteminden
@@ -612,28 +634,33 @@
         Sunucu sisteminde saklanan belirteç, 21 gün sonra silinir.
     </li>
     <li>
-        UYGULAMA'da saklanan belirteç, UYGULAMA akıllı telefondan silindikten
-        sonra ya da "Test sonucunuzu paylaşma" işlevi gerçekleştirildikten
-        sonra silinir.
+        UYGULAMA'da saklanan belirteç, UYGULAMA, akıllı telefondan silindikten
+        sonra ya da "Diğerlerini uyar" işlevi gerçekleştirildikten sonra
+        silinir.
     </li>
 </ul>
-<h3>
-    c. Test sonucunuzu paylaÅŸma
-</h3>
+<h2>
+    c. DiÄŸerlerini uyar
+</h2>
 <ul>
     <li>
-        UYGULAMA'da paylaşılan rastgele kimlikler, 14 gün sonra sunucu
-        sisteminden silinir.
+        UYGULAMA aracılığıyla sunulan rastgele kimlikler ve risk bulaş
+        değerleri, 14 gün sonra sunucu sistemi tarafından silinir.
+    </li>
+    <li>
+        Bulgu ve bulgu başlangıcına ilişkin bilgileriniz, rastgele kimlik ve
+        taşıma risk değerlerinin hazırlanmasından hemen sonra UYGULAMA
+        tarafından silinir.
     </li>
     <li>
         Sunucu sisteminde saklanan TAN kopyası, 21 gün sonra silinir.
     </li>
     <li>
-        UYGULAMA'da saklanan TAN, test sonucunun paylaşılmasından sonra
+        UYGULAMA'da saklanan TAN, test sonucunun hazırlanmasından sonra
         silinir.
     </li>
     <li>
-        UYGULAMA'da saklanan TeleTAN, test sonucunun paylaşılmasından sonra
+        UYGULAMA'da saklanan TeleTAN, test sonucunun hazırlanmasından sonra
         silinir.
     </li>
     <li>
@@ -647,23 +674,24 @@
         Sunucu sisteminde saklanan belirteç, 21 gün sonra silinir.
     </li>
     <li>
-        UYGULAMA'da saklanan belirteç, test sonucunun paylaşılmasından sonra
+        UYGULAMA'da saklanan belirteç, test sonucunun hazırlanmasından sonra
         silinir.
     </li>
 </ul>
-<h2>
+<h1>
     9. Verileriniz kimlere iletilir?
-</h2>
+</h1>
 <p>
-    Diğer kullanıcıları uyarmak için test sonucu paylaştığınızda, son 14 güne
-    ait rastgele kimlikleriniz diğer kullanıcıların UYGULAMA'larına iletilir.
+    Diğer kullanıcıları uyarmak için "Diğerlerini uyar" işlevi aracılığıyla bir
+    test sonucu hazırlarsanız, son 14 güne ilişkin rastgele kimlikleriniz ve
+    bunlara ilişkin taşıma risk değerleri diğer kullanıcıların UYGULAMALARINA
+    iletilir.
 </p>
 <p>
     RKI, UYGULAMA'nın teknik alt yapısının bir bölümünün işletimi ve bakımı
-    (örn., sunucu sistemleri, yardım hattı) için Deutsche Telekom AG ve SAP
-    Deutschland SE &amp; Co. KG'yi görevlendirmiştir (AB Genel Veri Koruma
-    Tüzüğü madde 28) ve bu firmalar bununla ilgili olarak RKI'nin veri
-    işlemcisi sıfatıyla faaliyet gösterecektir.
+    (örn., sunucu sistemleri, yardım hattı) için RKI'nin veri işlemcisi olarak
+    faaliyet gösteren Deutsche Telekom AG ve SAP Deutschland SE &amp; Co. KG'yi
+    görevlendirmiştir (AB Genel Veri Koruma Tüzüğü madde 28).
 </p>
 <p>
     Bundan başka, RKI, UYGULAMA'nın kullanımı ile bağlantılı olarak toplanan
@@ -672,18 +700,18 @@
     gerekli olursa üçüncü kişilere iletebilir. Bundan başka durumlarda veriler
     esas itibariyle başkalarına iletilmez.
 </p>
-<h2>
+<h1>
     10. Veriler üçüncü ülkelere aktarılır mı?
-</h2>
+</h1>
 <p>
     UYGULAMA'nın kullanımında toplanan veriler, sadece Almanya'daki sunucularda
     ya da başka bir AB ya da Avrupa Ekonomik Alanı üye devletinde işlenir.
 </p>
-<h2>
+<h1>
     11. Onayı geri alma
-</h2>
+</h1>
 <p>
-    UYGULAMA'da RKI'ya yönelik verdiğiniz onayları dilediğinizde ve gelecekte
+    UYGULAMA'da RKI'ye yönelik verdiğiniz onayları dilediğinizde ve gelecekte
     etki etmek şartıyla geri alabilirsiniz. Ancak, geri alma anına kadarki veri
     iÅŸlemenin hukuka uygunluÄŸu, bu geri almadan etkilenmez.
 </p>
@@ -697,24 +725,24 @@
 <p>
     "Test kaydetme" işlevine verdiğiniz onayı geri almak için UYGULAMA'daki
     test kaydını silebilirsiniz. Test sonucunun çağrılması için alınan
-    belirteç, bundan sonra cihazınızdan silinir. RKI ve test laboravutarı,
-    iletilen verileri UYGULAMA'nıza ya da cihazınıza ekleyemez. Başka bir testi
-    kaydettirmek isterseniz sizden yeni bir onay vermeniz istenir.
-</p>
-<p>
-    "Test sonucunuzu paylaşma" işlevine verdiğiniz onayı geri almak için
-    UYGULAMA'yı silmelisiniz. UYGULAMA'da saklanan tüm rastgele kimlikleriniz
-    silinir ve akıllı telefonunuzla artık ilişkilendirilemez. Yeniden bir test
-    sonucu bildirmek isterseniz, UYGULAMA'yı yeniden yükleyebilir ve yeni bir
-    onay verebilirsiniz. Alternatif olarak, şayet varsa, akıllı telefonunuzun
-    sistem ayarlarından temas bildirim işlevi çerçevesinde rastgele
-    kimliklerinizi silebilirsiniz. Lütfen RKI'nin iletmiş olduğunuz rastgele
-    kimlikleri diğer kullanıcıların akıllı telefonlarından ve hazırlanan
-    listelerden doğrudan silme imkanının olmadığını dikkate alın.
-</p>
-<h2>
+    belirteç, bundan sonra cihazınızdan silinir. RKI ve test laboratuvarı,
+    iletilen verileri UYGULAMA'nıza ya da akıllı telefonunuza ekleyemez. Başka
+    bir testi kaydettirmek isterseniz sizden yeni bir onay vermeniz istenir.
+</p>
+<p>
+    "Diğerlerini uyar" işlevine verdiğiniz onayı geri almak için UYGULAMA'yı
+    silmelisiniz. UYGULAMA'da saklanan tüm rastgele kimlikleriniz silinir ve
+    akıllı telefonunuzla artık ilişkilendirilemez. Yeniden bir test sonucu
+    bildirmek isterseniz, UYGULAMA'yı yeniden yükleyebilir ve yeni bir onay
+    verebilirsiniz. Alternatif olarak, rastgele kimliklerinizi gerekirse temas
+    kayıt işlevi çerçevesinde akıllı telefonunuzun sistem ayarlarından
+    silebilirsiniz. Lütfen RKI'nin iletilmiş rastgele kimlikleriniz ve taşıma
+    risk değerlerini, diğer kullanıcıların akıllı telefonlarından ve
+    hazırlanmış listelerden doğrudan silemeyeceğini dikkate alın.
+</p>
+<h1>
     12. Diğer veri koruma haklarınız
-</h2>
+</h1>
 <p>
     Kişisel verileriniz, RKI tarafından işlendiği sürece aşağıdaki veri koruma
     haklarına da sahipsiniz:
@@ -725,33 +753,37 @@
         kaynaklanan haklar,
     </li>
     <li>
-        RKI resmi veri koruma görevlisi ile iletişime geçme ve talebinizi sunma
-        hakkı (AB Genel Veri Koruma Tüzüğü madde 38 paragraf 4) ve
+        RKI resmi veri koruma görevlisi
+        (https://www.rki.de/DE/Content/Institut/OrgEinheiten/Datenschutz/Datenschutz_node.html)
+        ile iletişime geçme ve talebinizi sunma hakkı (AB Genel Veri Koruma
+        Tüzüğü madde 38 paragraf 4) ve
     </li>
     <li>
         yetkili denetim kurumu huzurunda veri korumaya iliÅŸkin ÅŸikayette
-        bulunma hakkı. Bunun için, ikamet ettiğiniz ya da RKI'nin şirket
-        merkezinin bulunduÄŸu yerdeki yetkili denetim kurumuna
-        başvurabilirsiniz. RKI için yetkili denetim kurumu, Graurheindorfer
-        Str. 153, 53117 Bonn adresinde bulunan Veri Koruma ve Bilgi Özgürlüğü
-        federal görevlisidir.
+        bulunma hakkı. Bunun için, oturduğunuz yerdeki yetkili denetim kurumu
     </li>
 </ul>
+<p>
+    ya da RKI'nin ÅŸirket merkezinin olduÄŸu yerdeki yetkili kuruma
+    başvurabilirsiniz. RKI için yetkili denetim kurumu, Graurheindorfer Str.
+    153, 53117 Bonn adresinde bulunan Veri Koruma ve Bilgi Özgürlüğü federal
+    görevlisidir.
+</p>
 <p>
     RKI'nin yukarıda anılan haklarının sadece, ileri sürülen taleplerin
     dayanağı verilerin açıkça şahsınıza bağlanması halinde ifa edilebileceğine
-    dikkat çekeriz. Bu da, yukarıda anılan verilerin şahsınıza ya da cihazınıza
-    eklenmesine izin verilen diğer kişisel verilerin RKI tarafından toplanması
-    halinde mümkündür. Bu husus da UYGULAMA'nın amaçları için gerekli
-    olmadığından – ve ayrıca istenmediğinden – RKI bu tür bir ek veri toplama
-    ile sorumlu değildir (AB Genel Veri Koruma Tüzüğü madde 11 paragraf. 2).
-    Ayrıca, bu husus UYGULAMA çerçevesindeki veri işlemenin mümkün olduğu kadar
-    veri koruma tasarrufu yaparak gerçekleştirilmesi olan amaca ve de açıklanan
-    amaca aykırıdır. Bu yüzden, yukarıda anılan AB Genel Veri Koruma Tüzüğü
-    maddeler 15, 16, 17, 18, 20 ve 21'den kaynaklanan veri koruma hakları,
-    kural olarak derhal uygulanmaz ve RKI'ye sunulmayan, şahsınızla ilgili ek
-    bilgiler ile uygulanır.
-</p>
-<p>
-    Versiyon: 09.06.2020
+    dikkat çekeriz. Bu da, yukarıda anılan verilerin şahsınıza ya da akıllı
+    telefonunuza eklenmesine izin verilen diÄŸer kiÅŸisel verilerin RKI
+    tarafından toplanması halinde mümkündür. Bu husus da UYGULAMA'nın amaçları
+    için gerekli olmadığından – ve ayrıca istenmediğinden – RKI bu tür bir ek
+    veri toplama ile sorumlu değildir (AB Genel Veri Koruma Tüzüğü madde 11
+    paragraf. 2). Ayrıca, bu husus UYGULAMA çerçevesindeki veri işlemenin
+    mümkün olduğu kadar veri koruma tasarrufu yaparak gerçekleştirilmesi olan
+    amaca ve de açıklanan amaca aykırıdır. Bu yüzden, yukarıda anılan AB Genel
+    Veri Koruma Tüzüğü maddeler 15, 16, 17, 18, 20 ve 21'den kaynaklanan veri
+    koruma hakları, kural olarak derhal uygulanmaz ve RKI'ye sunulmayan,
+    şahsınızla ilgili ek bilgiler ile uygulanır.
+</p>
+<p>
+    Versiyon: 05.10.2020
 </p>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/assets/terms_de.html b/Corona-Warn-App/src/main/assets/terms_de.html
index abecebc46f1160e3457dc5ffb11a929448541ab0..d129ee47173b2c6fe1109a1761848197e41324b6 100644
--- a/Corona-Warn-App/src/main/assets/terms_de.html
+++ b/Corona-Warn-App/src/main/assets/terms_de.html
@@ -91,7 +91,7 @@
 </p>
 <p>
     Sie sind für die Einhaltung dieser Nutzungsbedingungen auch dann
-    verantwortlich, wenn Sie das Endgerät, auf dem Sie die App installiert
+    verantwortlich, wenn Sie das Smartphone, auf dem Sie die App installiert
     haben, Dritten überlassen und diese die App verwenden.
 </p>
 <p>
@@ -119,9 +119,9 @@
     Hintergrund
 </h4>
 <p>
-    Die App läuft auf dem Endgerät im Hintergrund und speichert automatisiert
+    Die App läuft auf dem Smartphone im Hintergrund und speichert automatisiert
     und verschlüsselt die Zufallscodes (<em>rolling proximity identifier</em>)
-    anderer in der Nähe befindlicher Endgeräte. In regelmäßigen Abständen holt
+    anderer in der Nähe befindlicher Smartphones. In regelmäßigen Abständen holt
     sich die App über die CWADienste eine Liste der Zufallscodes (<em>temporary exposure keys</em>)
     der Personen, die sich freiwillig
     infiziert gemeldet haben, und vergleicht diese mit den gespeicherten
@@ -129,7 +129,7 @@
 </p>
 <p>
     Die App kann nur Begegnungen mit Personen registrieren, die ihrerseits ein
-    Endgerät mit installierter App bei sich führen und alle Voraussetzungen für
+    Smartphone mit installierter App bei sich führen und alle Voraussetzungen für
     die Nutzung der App erfüllen (siehe unten Ziffer 7). Begegnungen mit
     anderen Personen kann die App nicht registrieren.
 </p>
@@ -161,7 +161,7 @@
     Im Fall eines positiven SARS-CoV-2-Befunds können Sie freiwillig die in der
     App gespeicherten eigenen Zufallscodes der letzten 14 Tage als
     Positivkennungen (<em>diagnosis keys</em>) veröffentlichen, damit andere
-    Personen, die die App nutzen, auf ihrem eigenen Endgerät abgleichen können,
+    Personen, die die App nutzen, auf ihrem eigenen Smartphone abgleichen können,
     ob sie mit Ihnen eine Risiko-Begegnung hatten.
 </p>
 <h4>
@@ -260,9 +260,9 @@
     <strong>
         Die Benachrichtigung über eine Risiko-Begegnung kann unzutreffend sein.
     </strong>
-    Die Risiko-Begegnung kann von Ihrem Endgerät beispielsweise zu einem
+    Die Risiko-Begegnung kann von Ihrem Smartphone beispielsweise zu einem
     Zeitpunkt registriert worden sein, zu dem Sie sich nicht in der Nähe Ihres
-    Endgeräts aufgehalten haben oder während eine andere Person Ihr Endgerät
+    Smartphones aufgehalten haben oder während eine andere Person Ihr Smartphone
     verwendet hat. Die Risiko-Begegnung kann auch aufgrund bestehender Grenzen
     bei der Kontaktmessung fälschlicherweise registriert worden sein (siehe
     unten Ziffer 8).
@@ -292,7 +292,7 @@
 </p>
 <p>
     o Die App registriert nicht alle Ihre Begegnungen mit anderen Personen,
-    z.B. weil andere Personen die App nicht verwenden, Sie Ihr Endgerät nicht
+    z.B. weil andere Personen die App nicht verwenden, Sie Ihr Smartphone nicht
     immer bei sich tragen oder die App nicht immer in Betrieb haben oder weil
     die Kontaktmessung gewissen Grenzen unterliegt (siehe unten Ziffer 8).
 </p>
@@ -411,35 +411,35 @@
 <p>
     Bestimmte Funktionen der App setzen auf zentrale Dienste und Systeme auf,
     die über die CWA-Dienste zur Verfügung gestellt werden. Diese Funktionen
-    stehen daher nur zur Verfügung, wenn Ihr Endgerät über eine Datenverbindung
+    stehen daher nur zur Verfügung, wenn Ihr Smartphone über eine Datenverbindung
     mit dem Internet verfügt, z.B. über UMTS, LTE oder WLAN, um hierüber auf
     die CWA-Dienste zugreifen zu können. Ohne Datenverbindung stehen einige
     oder alle Funktionen der App nicht zur Verfügung. Dies gilt auch, wenn Sie
-    Ihr Endgerät in den Flugmodus versetzen oder ausschalten.
+    Ihr Smartphone in den Flugmodus versetzen oder ausschalten.
 </p>
 <h4>
-    Die App muss auf dem Endgerät laufen und eingeschaltet sein
+    Die App muss auf dem Smartphone laufen und eingeschaltet sein
 </h4>
 <p>
-    Die App muss auf Ihrem Endgerät im Vorder- oder Hintergrund laufen und
+    Die App muss auf Ihrem Smartphone im Vorder- oder Hintergrund laufen und
     eingeschaltet sein. Hierzu müssen Sie die App starten. Wenn Sie die App
     nicht starten, ausschalten oder beenden, speichert die App keine
     Begegnungen mit anderen Personen und erzeugt keine Zufallscodes zur
-    Speicherung durch andere Personen. Wenn Sie das Endgerät neu starten (z.B.
+    Speicherung durch andere Personen. Wenn Sie das Smartphone neu starten (z.B.
     nach dem Ausschalten, nachdem die Batterie leer war oder nach einem Update
     des Betriebssystems), müssen Sie auch die App neu starten.
 </p>
 <h4>
-    Einstellungen im Endgerät
+    Einstellungen im Smartphone
 </h4>
 <p>
     Für die Nutzung der App müssen Sie ferner die Bluetooth (BLE)-Funktionen
-    auf Ihrem Endgerät aktivieren und ggf. zur Verwendung durch die App
+    auf Ihrem Smartphone aktivieren und ggf. zur Verwendung durch die App
     freigegeben.
 </p>
 <p>
     Für die Nutzung der App empfiehlt das RKI ferner folgende Funktionen auf
-    Ihrem Endgerät zu aktivieren und ggf. zur Verwendung durch die App
+    Ihrem Smartphone zu aktivieren und ggf. zur Verwendung durch die App
     freizugegeben, auch wenn diese nicht Voraussetzung für die Nutzung der
     grundlegenden Funktionen der App sind:
 </p>
@@ -450,7 +450,7 @@
     • Kamerafunktion
 </p>
 <p>
-    Bitte prüfen Sie in den Einstellungen ihres Endgeräts, ob diese Funktionen
+    Bitte prüfen Sie in den Einstellungen ihres Smartphones, ob diese Funktionen
     aktiviert und für die Verwendung der App freigegeben sind.
 </p>
 <p>
@@ -497,11 +497,11 @@
 <p>
     Für die Entfernungsmessung wird die Dämpfung des Bluetooth-Signals
     verwendet. Eine geringere Dämpfung bedeutet dabei grundsätzlich, dass das
-    andere Endgerät näher ist. Eine höhere Dämpfung kann entweder bedeuten,
-    dass das andere Endgerät weiter entfernt ist (also eine Entfernung von mehr
-    als zwei Metern) oder dass sich zwischen den beiden Endgeräten etwas
+    andere Smartphone näher ist. Eine höhere Dämpfung kann entweder bedeuten,
+    dass das andere Smartphone weiter entfernt ist (also eine Entfernung von mehr
+    als zwei Metern) oder dass sich zwischen den beiden Smartphones etwas
     befindet, was das Signal blockiert. Das können Objekte wie eine Wand oder
-    eine Tasche, in der sich das Endgerät befindet, sein, aber genauso Personen
+    eine Tasche, in der sich das Smartphone befindet, sein, aber genauso Personen
     oder Tiere.
 </p>
 <h1>
@@ -567,7 +567,7 @@
     Sie dürfen die App und die Schnittstellen zu den CWA-Diensten nicht
     missbräuchlich verwenden. Sie dürfen die CWA-Dienste nicht für andere
     Zwecke nutzen als den bestimmungsgemäßen Betrieb der App auf Ihrem
-    Endgerät. Sie dürfen auf die CWADienste ausschließlich über die App
+    Smartphone. Sie dürfen auf die CWADienste ausschließlich über die App
     zugreifen.
 </p>
 <h1>
@@ -613,7 +613,7 @@
     Fall werden Sie beim Start der App aufgefordert, den geänderten
     Nutzungsbedingungen zuzustimmen. Wenn Sie den geänderten
     Nutzungsbedingungen nicht zustimmen, können Sie die App und die CWA-
-    Dienste nicht mehr nutzen und müssen die App von Ihrem Endgerät löschen.
+    Dienste nicht mehr nutzen und müssen die App von Ihrem Smartphone löschen.
 </p>
 <h4>
     Risk Score
@@ -654,9 +654,9 @@
     sein werden.
 </p>
 <p>
-    Für die Datensicherung Ihres Endgeräts sowie ggf. damit verbundener Systeme
+    Für die Datensicherung Ihres Smartphones sowie ggf. damit verbundener Systeme
     sind Sie verantwortlich, inklusive der Datensicherung sämtlicher anderer
-    Apps, welche auf Ihrem Endgerät gespeichert sind.
+    Apps, welche auf Ihrem Smartphone gespeichert sind.
 </p>
 <h1>
     12. BESONDERE BEDINGUNGEN FÃœR DIE IOSVERSION DER APP
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 cd26d162082c879c4b44e3a4beba10c9c18403e8..184ec476975eeee93a524b35091a2208054fc6ad 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
@@ -27,6 +27,7 @@ import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction
 import de.rki.coronawarnapp.util.CWADebug
 import de.rki.coronawarnapp.util.ConnectivityHelper
+import de.rki.coronawarnapp.util.debug.FileLogger
 import de.rki.coronawarnapp.util.di.AppInjector
 import de.rki.coronawarnapp.util.di.ApplicationComponent
 import de.rki.coronawarnapp.worker.BackgroundWorkHelper
@@ -56,6 +57,7 @@ class CoronaWarnApplication : Application(), LifecycleObserver,
             instance.applicationContext
 
         const val TEN_MINUTE_TIMEOUT_IN_MS = 10 * 60 * 1000L
+        var fileLogger: FileLogger? = null
     }
 
     private lateinit var errorReceiver: ErrorReportReceiver
@@ -88,6 +90,9 @@ class CoronaWarnApplication : Application(), LifecycleObserver,
         if (BuildConfig.DEBUG) {
             Timber.plant(Timber.DebugTree())
         }
+        if ((BuildConfig.FLAVOR == "deviceForTesters" || BuildConfig.DEBUG)) {
+            fileLogger = FileLogger(this)
+        }
 
         // notification to test the WakeUpService from Google when the app
         // was force stopped
@@ -99,27 +104,9 @@ class CoronaWarnApplication : Application(), LifecycleObserver,
             ProcessLifecycleOwner.get().lifecycleScope.launch {
                 // we want a wakelock as the OS does not handle this for us like in the background
                 // job execution
-                val wakeLock: PowerManager.WakeLock =
-                    (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
-                        newWakeLock(
-                            PowerManager.PARTIAL_WAKE_LOCK,
-                            TAG + "-WAKE-" + UUID.randomUUID().toString()
-                        ).apply {
-                            acquire(TEN_MINUTE_TIMEOUT_IN_MS)
-                        }
-                    }
-
+                val wakeLock = createWakeLock()
                 // we keep a wifi lock to wake up the wifi connection in case the device is dozing
-                val wifiLock: WifiManager.WifiLock =
-                    (getSystemService(Context.WIFI_SERVICE) as WifiManager).run {
-                        createWifiLock(
-                            WifiManager.WIFI_MODE_FULL_HIGH_PERF,
-                            TAG + "-WIFI-" + UUID.randomUUID().toString()
-                        ).apply {
-                            acquire()
-                        }
-                    }
-
+                val wifiLock = createWifiLock()
                 try {
                     BackgroundWorkHelper.sendDebugNotification(
                         "Automatic mode is on", "Check if we have downloaded keys already today"
@@ -146,6 +133,28 @@ class CoronaWarnApplication : Application(), LifecycleObserver,
         }
     }
 
+    private fun createWakeLock(): PowerManager.WakeLock =
+        (getSystemService(Context.POWER_SERVICE) as PowerManager)
+            .run {
+                newWakeLock(
+                    PowerManager.PARTIAL_WAKE_LOCK,
+                    TAG + "-WAKE-" + UUID.randomUUID().toString()
+                ).apply {
+                    acquire(TEN_MINUTE_TIMEOUT_IN_MS)
+                }
+            }
+
+    private fun createWifiLock(): WifiManager.WifiLock =
+        (getSystemService(Context.WIFI_SERVICE) as WifiManager)
+            .run {
+                createWifiLock(
+                    WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                    TAG + "-WIFI-" + UUID.randomUUID().toString()
+                ).apply {
+                    acquire()
+                }
+            }
+
     /**
      * Callback when the app is open but backgrounded
      */
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt
new file mode 100644
index 0000000000000000000000000000000000000000..526b5e05270bad8de02da844dbda29a1292a1ff1
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt
@@ -0,0 +1,35 @@
+@file:Suppress("DEPRECATION")
+
+package de.rki.coronawarnapp.nearby
+
+import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider
+import timber.log.Timber
+import java.io.File
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ENFClient @Inject constructor(
+    private val googleENFClient: ExposureNotificationClient,
+    private val diagnosisKeyProvider: DiagnosisKeyProvider
+) : DiagnosisKeyProvider {
+
+    // TODO Remove this once we no longer need direct access to the ENF Client,
+    // i.e. in **[InternalExposureNotificationClient]**
+    internal val internalClient: ExposureNotificationClient
+        get() = googleENFClient
+
+    override suspend fun provideDiagnosisKeys(
+        keyFiles: Collection<File>,
+        configuration: ExposureConfiguration?,
+        token: String
+    ): Boolean {
+        Timber.d(
+            "asyncProvideDiagnosisKeys(keyFiles=%s, configuration=%s, token=%s)",
+            keyFiles, configuration, token
+        )
+        return diagnosisKeyProvider.provideDiagnosisKeys(keyFiles, configuration, token)
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClientLocalData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClientLocalData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..26564ab4af748c81731269262f78141e6b43c7de
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClientLocalData.kt
@@ -0,0 +1,34 @@
+package de.rki.coronawarnapp.nearby
+
+import android.content.Context
+import androidx.core.content.edit
+import org.joda.time.Instant
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ENFClientLocalData @Inject constructor(
+    private val context: Context
+) {
+
+    private val prefs by lazy {
+        context.getSharedPreferences("enfclient_localdata", Context.MODE_PRIVATE)
+    }
+
+    var lastQuotaResetAt: Instant
+        get() = Instant.ofEpochMilli(prefs.getLong(PKEY_QUOTA_LAST_RESET, 0L))
+        set(value) = prefs.edit(true) {
+            putLong(PKEY_QUOTA_LAST_RESET, value.millis)
+        }
+
+    var currentQuota: Int
+        get() = prefs.getInt(PKEY_QUOTA_CURRENT, 0)
+        set(value) = prefs.edit(true) {
+            putInt(PKEY_QUOTA_CURRENT, value)
+        }
+
+    companion object {
+        private const val PKEY_QUOTA_LAST_RESET = "enfclient.quota.lastreset"
+        private const val PKEY_QUOTA_CURRENT = "enfclient.quota.current"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4b7094c8f709b45f7765061d8078771d5a0ec118
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt
@@ -0,0 +1,24 @@
+package de.rki.coronawarnapp.nearby
+
+import android.content.Context
+import com.google.android.gms.nearby.Nearby
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import dagger.Module
+import dagger.Provides
+import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DefaultDiagnosisKeyProvider
+import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider
+import javax.inject.Singleton
+
+@Module
+class ENFModule {
+
+    @Singleton
+    @Provides
+    fun exposureNotificationClient(context: Context): ExposureNotificationClient =
+        Nearby.getExposureNotificationClient(context)
+
+    @Singleton
+    @Provides
+    fun diagnosisKeySubmitter(submitter: DefaultDiagnosisKeyProvider): DiagnosisKeyProvider =
+        submitter
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt
index 020dd1d4065eaa2df04500b4a2c7561a38ba4f2c..06b33b5503e44f33c4c7127f993fece9d6df485d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt
@@ -1,8 +1,5 @@
 package de.rki.coronawarnapp.nearby
 
-import com.google.android.gms.nearby.Nearby
-import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
-import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration.ExposureConfigurationBuilder
 import com.google.android.gms.nearby.exposurenotification.ExposureSummary
 import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
 import de.rki.coronawarnapp.CoronaWarnApplication
@@ -10,7 +7,7 @@ import de.rki.coronawarnapp.risk.TimeVariables
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.storage.tracing.TracingIntervalRepository
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.millisecondsToSeconds
-import java.io.File
+import de.rki.coronawarnapp.util.di.AppInjector
 import java.util.Date
 import kotlin.coroutines.resume
 import kotlin.coroutines.resumeWithException
@@ -24,7 +21,7 @@ object InternalExposureNotificationClient {
 
     // reference to the client from the Google framework with the given application context
     private val exposureNotificationClient by lazy {
-        Nearby.getExposureNotificationClient(CoronaWarnApplication.getAppContext())
+        AppInjector.component.enfClient.internalClient
     }
 
     /****************************************************
@@ -101,36 +98,6 @@ object InternalExposureNotificationClient {
             }
     }
 
-    /**
-     * Takes an ExposureConfiguration object. Inserts a list of files that contain key
-     * information into the on-device database. Provide the keys of confirmed cases retrieved
-     * from your internet-accessible server to the Google Play service once requested from the
-     * API. Information about the file format is in the Exposure Key Export File Format and
-     * Verification document that is linked from google.com/covid19/exposurenotifications.
-     *
-     * @param keyFiles
-     * @param configuration
-     * @param token
-     * @return
-     */
-    suspend fun asyncProvideDiagnosisKeys(
-        keyFiles: Collection<File>,
-        configuration: ExposureConfiguration?,
-        token: String
-    ): Void = suspendCoroutine { cont ->
-        val exposureConfiguration = configuration ?: ExposureConfigurationBuilder().build()
-        exposureNotificationClient.provideDiagnosisKeys(
-            keyFiles.toList(),
-            exposureConfiguration,
-            token
-        )
-            .addOnSuccessListener {
-                cont.resume(it)
-            }.addOnFailureListener {
-                cont.resumeWithException(it)
-            }
-    }
-
     /**
      * Retrieves key history from the data store on the device for uploading to your
      * internet-accessible server. Calling this method prompts Google Play services to display
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bca8dfdd48723b685774623dfcd72733203aec66
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt
@@ -0,0 +1,106 @@
+@file:Suppress("DEPRECATION")
+
+package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
+
+import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import de.rki.coronawarnapp.util.GoogleAPIVersion
+import timber.log.Timber
+import java.io.File
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlin.coroutines.suspendCoroutine
+
+@Singleton
+class DefaultDiagnosisKeyProvider @Inject constructor(
+    private val googleAPIVersion: GoogleAPIVersion,
+    private val submissionQuota: SubmissionQuota,
+    private val enfClient: ExposureNotificationClient
+) : DiagnosisKeyProvider {
+
+    override suspend fun provideDiagnosisKeys(
+        keyFiles: Collection<File>,
+        configuration: ExposureConfiguration?,
+        token: String
+    ): Boolean {
+        return try {
+            if (keyFiles.isEmpty()) {
+                Timber.d("No key files submitted, returning early.")
+                return true
+            }
+
+            val usedConfiguration = if (configuration == null) {
+                Timber.w("Passed configuration was NULL, creating fallback.")
+                ExposureConfiguration.ExposureConfigurationBuilder().build()
+            } else {
+                configuration
+            }
+
+            if (googleAPIVersion.isAtLeast(GoogleAPIVersion.V16)) {
+                provideKeys(keyFiles, usedConfiguration, token)
+            } else {
+                provideKeysLegacy(keyFiles, usedConfiguration, token)
+            }
+        } catch (e: Exception) {
+            Timber.e(
+                e, "Error during provideDiagnosisKeys(keyFiles=%s, configuration=%s, token=%s)",
+                keyFiles, configuration, token
+            )
+            throw e
+        }
+    }
+
+    private suspend fun provideKeys(
+        files: Collection<File>,
+        configuration: ExposureConfiguration,
+        token: String
+    ): Boolean {
+        Timber.d("Using non-legacy key provision.")
+
+        if (!submissionQuota.consumeQuota(1)) {
+            Timber.w("Not enough quota available.")
+            // TODO Currently only logging, we'll be more strict in a future release
+            // return false
+        }
+
+        performSubmission(files, configuration, token)
+        return true
+    }
+
+    /**
+     * We use Batch Size 1 and thus submit multiple times to the API.
+     * This means that instead of directly submitting all files at once, we have to split up
+     * our file list as this equals a different batch for Google every time.
+     */
+    private suspend fun provideKeysLegacy(
+        keyFiles: Collection<File>,
+        configuration: ExposureConfiguration,
+        token: String
+    ): Boolean {
+        Timber.d("Using LEGACY key provision.")
+
+        if (!submissionQuota.consumeQuota(keyFiles.size)) {
+            Timber.w("Not enough quota available.")
+            // TODO What about proceeding with partial submission?
+            // TODO Currently only logging, we'll be more strict in a future release
+            // return false
+        }
+
+        keyFiles.forEach { performSubmission(listOf(it), configuration, token) }
+        return true
+    }
+
+    private suspend fun performSubmission(
+        keyFiles: Collection<File>,
+        configuration: ExposureConfiguration,
+        token: String
+    ): Void = suspendCoroutine { cont ->
+        Timber.d("Performing key submission.")
+        enfClient
+            .provideDiagnosisKeys(keyFiles.toList(), configuration, token)
+            .addOnSuccessListener { cont.resume(it) }
+            .addOnFailureListener { cont.resumeWithException(it) }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt
new file mode 100644
index 0000000000000000000000000000000000000000..accedeed05ba0a7be5e2259326da4960db3ab3b7
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt
@@ -0,0 +1,25 @@
+package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
+
+import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
+import java.io.File
+
+interface DiagnosisKeyProvider {
+
+    /**
+     * Takes an ExposureConfiguration object. Inserts a list of files that contain key
+     * information into the on-device database. Provide the keys of confirmed cases retrieved
+     * from your internet-accessible server to the Google Play service once requested from the
+     * API. Information about the file format is in the Exposure Key Export File Format and
+     * Verification document that is linked from google.com/covid19/exposurenotifications.
+     *
+     * @param keyFiles
+     * @param configuration
+     * @param token
+     * @return
+     */
+    suspend fun provideDiagnosisKeys(
+        keyFiles: Collection<File>,
+        configuration: ExposureConfiguration?,
+        token: String
+    ): Boolean
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuota.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuota.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d9bd53506983a3d65e700bd694c21e6ca8d2a618
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuota.kt
@@ -0,0 +1,91 @@
+package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
+
+import androidx.annotation.VisibleForTesting
+import de.rki.coronawarnapp.nearby.ENFClientLocalData
+import de.rki.coronawarnapp.util.TimeStamper
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import org.joda.time.DateTimeZone
+import org.joda.time.Duration
+import org.joda.time.Instant
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class SubmissionQuota @Inject constructor(
+    private val enfData: ENFClientLocalData,
+    private val timeStamper: TimeStamper
+) {
+
+    private var currentQuota: Int
+        get() = enfData.currentQuota
+        set(value) {
+            enfData.currentQuota = value
+        }
+
+    private var lastQuotaReset: Instant
+        get() = enfData.lastQuotaResetAt
+        set(value) {
+            enfData.lastQuotaResetAt = value
+        }
+
+    private val mutex = Mutex()
+
+    /**
+     * Attempts to consume quota, and returns true if enough quota was available.
+     */
+    suspend fun consumeQuota(wanted: Int): Boolean = mutex.withLock {
+        attemptQuotaReset()
+
+        if (currentQuota < wanted) {
+            Timber.d("Not enough quota: want=%d, have=%d", wanted, currentQuota)
+            return false
+        }
+
+        run {
+            val oldQuota = currentQuota
+            val newQuota = currentQuota - wanted
+            Timber.d("Consuming quota: old=%d, new=%d", oldQuota, newQuota)
+            currentQuota = newQuota
+        }
+        return true
+    }
+
+    /**
+     * Attempts to reset the quota
+     * On initial launch, the lastQuotaReset is set to Instant.EPOCH,
+     * thus the quota will be immediately set to 20.
+     */
+    private fun attemptQuotaReset() {
+        val oldQuota = currentQuota
+        val oldQuotaReset = lastQuotaReset
+
+        val now = timeStamper.nowUTC
+
+        val nextQuotaReset = lastQuotaReset
+            .toDateTime(DateTimeZone.UTC)
+            .withTimeAtStartOfDay()
+            .plus(Duration.standardDays(1))
+
+        if (now.isAfter(nextQuotaReset)) {
+            currentQuota = DEFAULT_QUOTA
+            lastQuotaReset = now
+
+            Timber.i(
+                "Quota reset: oldQuota=%d, lastReset=%s -> newQuota=%d, thisReset=%s",
+                oldQuota, oldQuotaReset, currentQuota, now
+            )
+        } else {
+            Timber.d(
+                "No new quota available (now=%s, availableAt=%s)",
+                now, nextQuotaReset
+            )
+        }
+    }
+
+    companion object {
+        @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+        internal const val DEFAULT_QUOTA = 20
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt
index e33668fa5ddabfdda14f8a7564555a5fff992786..8695e37cfa9bee099f71465faf9fd4ab52f2160b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt
@@ -8,6 +8,7 @@ import de.rki.coronawarnapp.http.playbook.BackgroundNoise
 import de.rki.coronawarnapp.http.playbook.PlaybookImpl
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.storage.SubmissionRepository
+import de.rki.coronawarnapp.submission.Symptoms
 import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction
 import de.rki.coronawarnapp.util.formatter.TestResult
 import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
@@ -51,10 +52,10 @@ object SubmissionService {
         SubmissionRepository.updateTestResult(testResult)
     }
 
-    suspend fun asyncSubmitExposureKeys(keys: List<TemporaryExposureKey>) {
+    suspend fun asyncSubmitExposureKeys(keys: List<TemporaryExposureKey>, symptoms: Symptoms) {
         val registrationToken =
             LocalData.registrationToken() ?: throw NoRegistrationTokenSetException()
-        SubmitDiagnosisKeysTransaction.start(registrationToken, keys)
+        SubmitDiagnosisKeysTransaction.start(registrationToken, keys, symptoms)
     }
 
     suspend fun asyncRequestTestResult(): TestResult {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt
index 48bc37e409fea1553cc046a816338afa94529ee2..889ab566942df188a9780255f3301afafc45daa3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt
@@ -6,7 +6,6 @@ import de.rki.coronawarnapp.CoronaWarnApplication
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.risk.RiskLevel
 import de.rki.coronawarnapp.util.security.SecurityHelper.globalEncryptedSharedPreferencesInstance
-import org.joda.time.Instant
 import java.util.Date
 
 /**
@@ -19,11 +18,6 @@ object LocalData {
 
     private val TAG: String? = LocalData::class.simpleName
 
-    private const val PREFERENCE_NEXT_TIME_RATE_LIMITING_UNLOCKS =
-        "preference_next_time_rate_limiting_unlocks"
-    private const val PREFERENCE_GOOGLE_API_PROVIDE_DIAGNOSIS_KEYS_CALL_COUNT =
-        "preference_google_api_provide_diagnosis_keys_call_count"
-
     /****************************************************
      * ONBOARDING DATA
      ****************************************************/
@@ -396,40 +390,6 @@ object LocalData {
         }
     }
 
-    var nextTimeRateLimitingUnlocks: Instant
-        get() {
-            return Instant.ofEpochMilli(
-                getSharedPreferenceInstance().getLong(
-                    PREFERENCE_NEXT_TIME_RATE_LIMITING_UNLOCKS,
-                    0L
-                )
-            )
-        }
-        set(value) {
-            getSharedPreferenceInstance().edit(true) {
-                putLong(
-                    PREFERENCE_NEXT_TIME_RATE_LIMITING_UNLOCKS,
-                    value.millis
-                )
-            }
-        }
-
-    var googleAPIProvideDiagnosisKeysCallCount: Int
-        get() {
-            return getSharedPreferenceInstance().getInt(
-                PREFERENCE_GOOGLE_API_PROVIDE_DIAGNOSIS_KEYS_CALL_COUNT,
-                0
-            )
-        }
-        set(value) {
-            getSharedPreferenceInstance().edit(true) {
-                putInt(
-                    PREFERENCE_GOOGLE_API_PROVIDE_DIAGNOSIS_KEYS_CALL_COUNT,
-                    value
-                )
-            }
-        }
-
     /**
      * Gets the last time of successful risk level calculation as long
      * from the EncryptedSharedPrefs
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DefaultKeyConverter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DefaultKeyConverter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e467c0f033231f096dd3710771f18586ab402298
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DefaultKeyConverter.kt
@@ -0,0 +1,21 @@
+package de.rki.coronawarnapp.submission
+
+import KeyExportFormat
+import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
+import com.google.protobuf.ByteString
+
+class DefaultKeyConverter : KeyConverter {
+
+    override fun toExternalFormat(key: TemporaryExposureKey, riskValue: Int) =
+        KeyExportFormat.TemporaryExposureKey.newBuilder()
+            .setKeyData(ByteString.readFrom(key.keyData.inputStream()))
+            .setRollingStartIntervalNumber(key.rollingStartIntervalNumber)
+            .setRollingPeriod(ROLLING_PERIOD)
+            .setTransmissionRiskLevel(riskValue)
+            .build()
+
+    companion object {
+
+        private const val ROLLING_PERIOD = 144
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculations.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculations.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5a57de881eaa95ac5c9c865eec4aa5ee4da76f8f
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculations.kt
@@ -0,0 +1,39 @@
+package de.rki.coronawarnapp.submission
+
+import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
+
+class ExposureKeyHistoryCalculations(
+    private val transmissionRiskVectorDeterminator: TransmissionRiskVectorDeterminator,
+    private val keyConverter: KeyConverter
+) {
+
+    fun transformToKeyHistoryInExternalFormat(
+        keys: List<TemporaryExposureKey>,
+        symptoms: Symptoms
+    ) =
+        toExternalFormat(
+            toSortedHistory(limitKeyCount(keys)),
+            transmissionRiskVectorDeterminator.determine(symptoms)
+        )
+
+    fun <T> limitKeyCount(keys: List<T>): List<T> =
+        keys.take(MAXIMUM_KEYS)
+
+    fun toExternalFormat(
+        keys: List<TemporaryExposureKey>,
+        transmissionRiskVector: TransmissionRiskVector
+    ) =
+        keys.mapIndexed { index, key ->
+            // The latest key we receive is from yesterday (i.e. 1 day ago),
+            // thus we need use index+1
+            keyConverter.toExternalFormat(key, transmissionRiskVector.getRiskValue(index + 1))
+        }
+
+    fun toSortedHistory(keys: List<TemporaryExposureKey>) =
+        keys.sortedWith(compareByDescending { it.rollingStartIntervalNumber })
+
+    companion object {
+
+        private const val MAXIMUM_KEYS = 14
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/KeyConverter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/KeyConverter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f50795ca52f4bdb3a31d6edb8b82aacb064ce721
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/KeyConverter.kt
@@ -0,0 +1,12 @@
+package de.rki.coronawarnapp.submission
+
+import KeyExportFormat
+import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
+
+interface KeyConverter {
+
+    fun toExternalFormat(
+        key: TemporaryExposureKey,
+        riskValue: Int
+    ): KeyExportFormat.TemporaryExposureKey
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/Symptoms.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/Symptoms.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2e36a7d32b7cc173977a8a8a157d35efd0110a45
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/Symptoms.kt
@@ -0,0 +1,21 @@
+package de.rki.coronawarnapp.submission
+
+data class Symptoms(
+    val startOfSymptoms: StartOf?,
+    val symptomIndication: Indication
+) {
+    sealed class StartOf {
+
+        data class Date(val millis: Long) : StartOf()
+        object LastSevenDays : StartOf()
+        object OneToTwoWeeksAgo : StartOf()
+        object MoreThanTwoWeeks : StartOf()
+        object NoInformation : StartOf()
+    }
+
+    enum class Indication {
+        POSITIVE,
+        NEGATIVE,
+        NO_INFORMATION
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVector.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVector.kt
new file mode 100644
index 0000000000000000000000000000000000000000..92fea5e3a939b15be08558ea1d5bb876a315dce3
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVector.kt
@@ -0,0 +1,15 @@
+package de.rki.coronawarnapp.submission
+
+class TransmissionRiskVector(private val values: IntArray) {
+
+    val raw: IntArray
+        get() = values
+
+    fun getRiskValue(index: Int) =
+        if (index < values.size) values[index] else DEFAULT_TRANSMISSION_RISK_LEVEL
+
+    companion object {
+
+        private const val DEFAULT_TRANSMISSION_RISK_LEVEL = 1
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminator.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2908a339197fe986eb4142cef51e875c0a229749
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminator.kt
@@ -0,0 +1,52 @@
+package de.rki.coronawarnapp.submission
+
+import org.joda.time.Duration
+import org.joda.time.Instant
+
+class TransmissionRiskVectorDeterminator {
+
+    @Suppress("MagicNumber")
+    fun determine(symptoms: Symptoms): TransmissionRiskVector = TransmissionRiskVector(
+        when (symptoms.symptomIndication) {
+            Symptoms.Indication.POSITIVE -> when (symptoms.startOfSymptoms) {
+                is Symptoms.StartOf.Date -> when (
+                    numberOfDays(symptoms.startOfSymptoms.millis)) {
+                    0 -> intArrayOf(8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1)
+                    1 -> intArrayOf(8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1)
+                    2 -> intArrayOf(6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1, 1, 1)
+                    3 -> intArrayOf(5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1, 1)
+                    4 -> intArrayOf(3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1)
+                    5 -> intArrayOf(2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1)
+                    6 -> intArrayOf(2, 2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1)
+                    7 -> intArrayOf(1, 2, 2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1)
+                    8 -> intArrayOf(1, 1, 2, 2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1)
+                    9 -> intArrayOf(1, 1, 1, 2, 2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2)
+                    10 -> intArrayOf(1, 1, 1, 1, 2, 2, 3, 5, 6, 8, 8, 8, 7, 6, 4)
+                    11 -> intArrayOf(1, 1, 1, 1, 1, 2, 2, 3, 5, 6, 8, 8, 8, 7, 6)
+                    12 -> intArrayOf(1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 6, 8, 8, 8, 7)
+                    13 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 6, 8, 8, 8)
+                    14 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 6, 8, 8)
+                    15 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 6, 8)
+                    16 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 6)
+                    17 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5)
+                    18 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3)
+                    19 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2)
+                    20 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2)
+                    else -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
+                }
+                is Symptoms.StartOf.LastSevenDays -> intArrayOf(4, 5, 6, 7, 7, 7, 6, 5, 4, 3, 2, 1, 1, 1, 1)
+                is Symptoms.StartOf.MoreThanTwoWeeks -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5)
+                is Symptoms.StartOf.NoInformation -> intArrayOf(5, 6, 8, 8, 8, 7, 5, 3, 2, 1, 1, 1, 1, 1, 1)
+                is Symptoms.StartOf.OneToTwoWeeksAgo -> intArrayOf(1, 1, 1, 1, 2, 3, 4, 5, 6, 6, 7, 7, 6, 6, 4)
+                else -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
+            }
+            Symptoms.Indication.NEGATIVE -> intArrayOf(4, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
+            Symptoms.Indication.NO_INFORMATION -> intArrayOf(5, 6, 7, 7, 7, 6, 4, 3, 2, 1, 1, 1, 1, 1, 1)
+        }
+    )
+
+    companion object {
+        fun numberOfDays(t0: Long, t1: Long = System.currentTimeMillis()) =
+            Duration(Instant.ofEpochMilli(t0), Instant.ofEpochMilli(t1)).standardDays.toInt()
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisInjectionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisInjectionHelper.kt
index 69598eedc3bdd08e445d4f317330285a3d009b84..38ff9dc344166b971806756daadcfe0c2bf5363a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisInjectionHelper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisInjectionHelper.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.transaction
 
+import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.util.GoogleAPIVersion
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -8,5 +9,6 @@ import javax.inject.Singleton
 @Singleton
 data class RetrieveDiagnosisInjectionHelper @Inject constructor(
     val transactionScope: TransactionCoroutineScope,
-    val googleAPIVersion: GoogleAPIVersion
+    val googleAPIVersion: GoogleAPIVersion,
+    val cwaEnfClient: ENFClient
 )
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransaction.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransaction.kt
index ff77253438bce970b14a08837aadc11fcf1f5460..f2c0eb1499cf3fd69e225e44d910f1340c0fe0e5 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransaction.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransaction.kt
@@ -23,6 +23,7 @@ import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
 import de.rki.coronawarnapp.diagnosiskeys.download.KeyFileDownloader
 import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode
 import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository
+import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService
 import de.rki.coronawarnapp.storage.LocalData
@@ -30,23 +31,17 @@ import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.Retriev
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.RetrieveDiagnosisKeysTransactionState.CLOSE
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.RetrieveDiagnosisKeysTransactionState.FETCH_DATE_UPDATE
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.RetrieveDiagnosisKeysTransactionState.FILES_FROM_WEB_REQUESTS
-import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.RetrieveDiagnosisKeysTransactionState.QUOTA_CALCULATION
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.RetrieveDiagnosisKeysTransactionState.RETRIEVE_RISK_SCORE_PARAMS
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.RetrieveDiagnosisKeysTransactionState.SETUP
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.RetrieveDiagnosisKeysTransactionState.TOKEN
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.rollback
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.start
 import de.rki.coronawarnapp.util.CWADebug
-import de.rki.coronawarnapp.util.GoogleAPIVersion
-import de.rki.coronawarnapp.util.GoogleQuotaCalculator
-import de.rki.coronawarnapp.util.QuotaCalculator
 import de.rki.coronawarnapp.util.di.AppInjector
 import de.rki.coronawarnapp.worker.BackgroundWorkHelper
 import org.joda.time.DateTime
 import org.joda.time.DateTimeZone
-import org.joda.time.Duration
 import org.joda.time.Instant
-import org.joda.time.chrono.GJChronology
 import timber.log.Timber
 import java.io.File
 import java.util.Date
@@ -97,9 +92,6 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
         /** Initial Setup of the Transaction and Transaction ID Generation and Date Lock */
         SETUP,
 
-        /** calculates the Quota so that the rate limiting is caught gracefully*/
-        QUOTA_CALCULATION,
-
         /** Initialisation of the identifying token used during the entire transaction */
         TOKEN,
 
@@ -128,8 +120,6 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
     /** atomic reference for the rollback value for created files during the transaction */
     private val exportFilesForRollback = AtomicReference<List<File>>()
 
-    private val progressTowardsQuotaForRollback = AtomicReference<Int>()
-
     private val transactionScope: TransactionCoroutineScope by lazy {
         AppInjector.component.transRetrieveKeysInjection.transactionScope
     }
@@ -146,19 +136,8 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
     var onKeyFilesDownloadStarted: (() -> Unit)? = null
     var onKeyFilesDownloadFinished: ((keyCount: Int, fileSize: Long) -> Unit)? = null
 
-    private const val QUOTA_RESET_PERIOD_IN_HOURS = 24
-
-    private val quotaCalculator: QuotaCalculator<Int> = GoogleQuotaCalculator(
-        incrementByAmount = 14,
-        quotaLimit = 20,
-        quotaResetPeriod = Duration.standardHours(QUOTA_RESET_PERIOD_IN_HOURS.toLong()),
-        quotaTimeZone = DateTimeZone.UTC,
-        quotaChronology = GJChronology.getInstanceUTC()
-    )
-
-    private val googleAPIVersion: GoogleAPIVersion by lazy {
-        AppInjector.component.transRetrieveKeysInjection.googleAPIVersion
-    }
+    private val enfClient: ENFClient
+        get() = AppInjector.component.transRetrieveKeysInjection.cwaEnfClient
 
     suspend fun startWithConstraints() {
         val currentDate = DateTime(Instant.now(), DateTimeZone.UTC)
@@ -166,7 +145,6 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
             LocalData.lastTimeDiagnosisKeysFromServerFetch(),
             DateTimeZone.UTC
         )
-
         if (LocalData.lastTimeDiagnosisKeysFromServerFetch() == null ||
             currentDate.withTimeAtStartOfDay() != lastFetch.withTimeAtStartOfDay()
         ) {
@@ -201,31 +179,14 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
          ****************************************************/
         val currentDate = executeSetup()
 
-        /****************************************************
-         * CALCULATE QUOTA FOR PROVIDE DIAGNOSIS KEYS
-         ****************************************************/
-        val hasExceededQuota = executeQuotaCalculation()
-
-        // When we are above the Quote, cancel the execution entirely
-        if (hasExceededQuota) {
-            Timber.tag(TAG).w("above quota, skipping RetrieveDiagnosisKeys")
-            executeClose()
-            return@lockAndExecute
-        }
-
         /****************************************************
          * RETRIEVE TOKEN
          ****************************************************/
         val token = executeToken()
 
-        /****************************************************
-         * RETRIEVE RISK SCORE PARAMETERS
-         ****************************************************/
+        // RETRIEVE RISK SCORE PARAMETERS
         val exposureConfiguration = executeRetrieveRiskScoreParams()
 
-        /****************************************************
-         * FILES FROM WEB REQUESTS
-         ****************************************************/
         val countries = requestedCountries ?: ApplicationConfigurationService
             .asyncRetrieveApplicationConfiguration()
             .supportedCountriesList
@@ -235,14 +196,18 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
             onKeyFilesDownloadStarted = null
         }
 
-        val keyFiles = executeFetchKeyFilesFromServer(countries)
+        val availableKeyFiles = executeFetchKeyFilesFromServer(countries)
+
+        if (availableKeyFiles.isEmpty()) {
+            Timber.tag(TAG).w("No keyfiles were available!")
+        }
 
         if (CWADebug.isDebugBuildOrMode) {
-            val totalFileSize = keyFiles.fold(0L, { acc, file ->
+            val totalFileSize = availableKeyFiles.fold(0L, { acc, file ->
                 file.length() + acc
             })
 
-            onKeyFilesDownloadFinished?.invoke(keyFiles.size, totalFileSize)
+            onKeyFilesDownloadFinished?.invoke(availableKeyFiles.size, totalFileSize)
             onKeyFilesDownloadFinished = null
         }
 
@@ -251,28 +216,19 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
             onApiSubmissionStarted = null
         }
 
-        if (keyFiles.isNotEmpty()) {
-            /****************************************************
-             * SUBMIT FILES TO API
-             ****************************************************/
-            executeAPISubmission(token, keyFiles, exposureConfiguration)
-        } else {
-            Timber.tag(TAG).w("no key files, skipping submission to internal API.")
-        }
+        val isSubmissionSuccessful = executeAPISubmission(
+            exportFiles = availableKeyFiles,
+            exposureConfiguration = exposureConfiguration,
+            token = token
+        )
 
         if (CWADebug.isDebugBuildOrMode) {
             onApiSubmissionFinished?.invoke()
             onApiSubmissionFinished = null
         }
 
-        /****************************************************
-         * Fetch Date Update
-         ****************************************************/
-        executeFetchDateUpdate(currentDate)
+        if (isSubmissionSuccessful) executeFetchDateUpdate(currentDate)
 
-        /****************************************************
-         * CLOSE TRANSACTION
-         ****************************************************/
         executeClose()
     }
 
@@ -285,10 +241,6 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
             if (TOKEN.isInStateStack()) {
                 rollbackToken()
             }
-            // we reset the quota only if the submission has not happened yet
-            if (QUOTA_CALCULATION.isInStateStack() && !API_SUBMISSION.isInStateStack()) {
-                rollbackProgressTowardsQuota()
-            }
         } catch (e: Exception) {
             // We handle every exception through a RollbackException to make sure that a single EntryPoint
             // is available for the caller.
@@ -306,11 +258,6 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
         LocalData.googleApiToken(googleAPITokenForRollback.get())
     }
 
-    private fun rollbackProgressTowardsQuota() {
-        Timber.tag(TAG).v("rollback $QUOTA_CALCULATION")
-        quotaCalculator.resetProgressTowardsQuota(progressTowardsQuotaForRollback.get())
-    }
-
     /**
      * Executes the INIT Transaction State
      */
@@ -321,16 +268,6 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
         currentDate
     }
 
-    /**
-     * Executes the QUOTA_CALCULATION Transaction State
-     */
-    private suspend fun executeQuotaCalculation() = executeState(
-        QUOTA_CALCULATION
-    ) {
-        progressTowardsQuotaForRollback.set(quotaCalculator.getProgressTowardsQuota())
-        quotaCalculator.calculateQuota()
-    }
-
     /**
      * Executes the TOKEN Transaction State
      */
@@ -359,34 +296,19 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
         keyFileDownloader.asyncFetchKeyFiles(locationCodes)
     }
 
-    /**
-     * Executes the API_SUBMISSION Transaction State
-     *
-     * We currently use Batch Size 1 and thus submit multiple times to the API.
-     * This means that instead of directly submitting all files at once, we have to split up
-     * our file list as this equals a different batch for Google every time.
-     */
     private suspend fun executeAPISubmission(
         token: String,
         exportFiles: Collection<File>,
         exposureConfiguration: ExposureConfiguration?
-    ) = executeState(API_SUBMISSION) {
-        if (googleAPIVersion.isAtLeast(GoogleAPIVersion.V16)) {
-            InternalExposureNotificationClient.asyncProvideDiagnosisKeys(
-                exportFiles,
-                exposureConfiguration,
-                token
-            )
-        } else {
-            exportFiles.forEach { batch ->
-                InternalExposureNotificationClient.asyncProvideDiagnosisKeys(
-                    listOf(batch),
-                    exposureConfiguration,
-                    token
-                )
-            }
-        }
-        Timber.tag(TAG).d("Diagnosis Keys provided successfully, Token: $token")
+    ): Boolean = executeState(API_SUBMISSION) {
+        Timber.tag(TAG).d("Attempting submission to ENF")
+        val success = enfClient.provideDiagnosisKeys(
+            keyFiles = exportFiles,
+            configuration = exposureConfiguration,
+            token = token
+        )
+        Timber.tag(TAG).d("Diagnosis Keys provided (success=%s, token=%s)", success, token)
+        return@executeState success
     }
 
     /**
@@ -395,6 +317,7 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
     private suspend fun executeFetchDateUpdate(
         currentDate: Date
     ) = executeState(FETCH_DATE_UPDATE) {
+        Timber.tag(TAG).d("executeFetchDateUpdate(currentDate=%s)", currentDate)
         LocalData.lastTimeDiagnosisKeysFromServerFetch(currentDate)
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransaction.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransaction.kt
index dddc3798253c03cee64fc09869c52d359c1e5ad0..ea6a4720f187cba0d66d1ea9916ce5152015838a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransaction.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransaction.kt
@@ -4,12 +4,14 @@ import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
 import de.rki.coronawarnapp.http.WebRequestBuilder
 import de.rki.coronawarnapp.http.playbook.PlaybookImpl
 import de.rki.coronawarnapp.service.submission.SubmissionService
+import de.rki.coronawarnapp.submission.ExposureKeyHistoryCalculations
+import de.rki.coronawarnapp.submission.DefaultKeyConverter
+import de.rki.coronawarnapp.submission.Symptoms
+import de.rki.coronawarnapp.submission.TransmissionRiskVectorDeterminator
 import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction.SubmitDiagnosisKeysTransactionState.CLOSE
 import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction.SubmitDiagnosisKeysTransactionState.RETRIEVE_TAN_AND_SUBMIT_KEYS
 import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction.SubmitDiagnosisKeysTransactionState.RETRIEVE_TEMPORARY_EXPOSURE_KEY_HISTORY
 import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction.SubmitDiagnosisKeysTransactionState.STORE_SUCCESS
-import de.rki.coronawarnapp.util.ProtoFormatConverterExtensions.limitKeyCount
-import de.rki.coronawarnapp.util.ProtoFormatConverterExtensions.transformKeyHistoryToExternalFormat
 import de.rki.coronawarnapp.util.di.AppInjector
 
 /**
@@ -55,14 +57,17 @@ object SubmitDiagnosisKeysTransaction : Transaction() {
     /** initiates the transaction. This suspend function guarantees a successful transaction once completed. */
     suspend fun start(
         registrationToken: String,
-        keys: List<TemporaryExposureKey>
+        keys: List<TemporaryExposureKey>,
+        symptoms: Symptoms
     ) = lockAndExecute(unique = true, scope = transactionScope) {
         /****************************************************
          * RETRIEVE TEMPORARY EXPOSURE KEY HISTORY
          ****************************************************/
         val temporaryExposureKeyList = executeState(RETRIEVE_TEMPORARY_EXPOSURE_KEY_HISTORY) {
-            keys.limitKeyCount()
-                .transformKeyHistoryToExternalFormat()
+            ExposureKeyHistoryCalculations(
+                TransmissionRiskVectorDeterminator(),
+                DefaultKeyConverter()
+            ).transformToKeyHistoryInExternalFormat(keys, symptoms)
         }
         /****************************************************
          * RETRIEVE TAN & SUBMIT KEYS
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/SingleLiveEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/SingleLiveEvent.kt
new file mode 100644
index 0000000000000000000000000000000000000000..03fff86ccbc7ad804151e68875e07b093837d956
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/SingleLiveEvent.kt
@@ -0,0 +1,67 @@
+
+package de.rki.coronawarnapp.ui
+
+/*
+ *  Copyright 2017 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+import androidx.annotation.MainThread
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Observer
+import timber.log.Timber
+import java.util.concurrent.atomic.AtomicBoolean
+
+/**
+ * A lifecycle-aware observable that sends only new updates after subscription, used for events like
+ * navigation and Snackbar messages.
+ *
+ *
+ * This avoids a common problem with events: on configuration change (like rotation) an update
+ * can be emitted if the observer is active. This LiveData only calls the observable if there's an
+ * explicit call to setValue() or call().
+ *
+ *
+ * Note that only one observer is going to be notified of changes.
+ */
+class SingleLiveEvent<T> : MutableLiveData<T>() {
+    private val pending = AtomicBoolean(false)
+    @MainThread
+    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
+        if (hasActiveObservers()) {
+            Timber
+                .w("Multiple observers registered but only one will be notified of changes.")
+        }
+        // Observe the internal MutableLiveData
+        super.observe(owner, Observer { t ->
+            if (pending.compareAndSet(true, false)) {
+                observer.onChanged(t)
+            }
+        })
+    }
+
+    @MainThread
+    override fun setValue(t: T?) {
+        pending.set(true)
+        super.setValue(t)
+    }
+    /**
+     * Used for cases where T is Void, to make calls cleaner.
+     */
+    @MainThread
+    fun call() {
+        value = null
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarAdapter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f9346c71339d9a40efa65926622fb2b837bca970
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarAdapter.kt
@@ -0,0 +1,78 @@
+package de.rki.coronawarnapp.ui.calendar
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import de.rki.coronawarnapp.R
+import org.joda.time.LocalDate
+
+/**
+ * Calendar adapter for recycler view
+ *
+ * @param clickListener (Day) -> Unit - on item click event listener
+ */
+class CalendarAdapter(private val clickListener: (Day) -> Unit) :
+    RecyclerView.Adapter<CalendarDayViewHolder>() {
+
+    /**
+     * Mutable list of days
+     *
+     * @see Day
+     */
+    private val data = mutableListOf<Day>()
+
+    init {
+        setHasStableIds(true)
+    }
+
+    /**
+     * Create new calendar day view holders
+     *
+     * @see CalendarDayViewHolder
+     */
+    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): CalendarDayViewHolder {
+        // Create a new view.
+        val v = LayoutInflater.from(viewGroup.context)
+            .inflate(R.layout.fragment_calendar_day, viewGroup, false)
+
+        return CalendarDayViewHolder(v)
+    }
+
+    /**
+     * Update calendar day view holders
+     *
+     * @see CalendarDayViewHolder.bind
+     */
+    override fun onBindViewHolder(viewHolder: CalendarDayViewHolder, position: Int) {
+        viewHolder.bind(data[position], clickListener)
+    }
+
+    /**
+     * Update days list and notify that data set was changed
+     *
+     * @see CalendarDayViewHolder.bind
+     */
+    fun update(days: List<Day>) {
+        data.clear()
+        data.addAll(days)
+        notifyDataSetChanged()
+    }
+
+    override fun getItemId(position: Int): Long {
+        return position.toLong()
+    }
+
+    override fun getItemCount(): Int {
+        return data.size
+    }
+
+    /**
+     * Data class for calendar day
+     *
+     * @param date LocalDate
+     * @param isSelected Boolean
+     *
+     * @see LocalDate
+     */
+    data class Day(val date: LocalDate, val isSelected: Boolean = false)
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculation.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a78f20525bdfb4c195b4115250264cbb3c27e248
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculation.kt
@@ -0,0 +1,121 @@
+package de.rki.coronawarnapp.ui.calendar
+
+import dagger.Reusable
+import org.joda.time.DateTime
+import org.joda.time.DateTimeZone
+import org.joda.time.Instant
+import org.joda.time.LocalDate
+import java.util.Locale
+import javax.inject.Inject
+
+@Reusable
+class CalendarCalculation @Inject constructor() {
+
+    /**
+     * Get month text view text
+     *
+     * Algorithm:
+     * Case 1:
+     * first date month != last date month
+     * first date year == last date year
+     * Result: September - October 2020
+     *
+     * Case 2:
+     * first date month != last date month
+     * first date year != last date year
+     * Result: December 2020 - January 2021
+     *
+     * Case 3:
+     * first date month == last date month
+     * Result: September 2020
+     *
+     * NOTE: This algorithm does not cover same month, but different year - calendar has
+     * strict constant of 28 days to display, so this case would never happen.
+     *
+     * @param firstDate LocalDate - first displayed date
+     * @param lastDate LocalDate - last displayed date
+     *
+     * @return String
+     *
+     * @see StringBuilder
+     */
+    fun getMonthText(firstDate: LocalDate, lastDate: LocalDate): String {
+        val monthText = StringBuilder()
+        // Append first date month as it would always be displayed
+        monthText.append(firstDate.monthOfYear().getAsText(Locale.getDefault()))
+        if (firstDate.monthOfYear() != lastDate.monthOfYear()) {
+            // Different month
+            if (firstDate.year() == lastDate.year()) {
+                // Same year (Case 1)
+                monthText.append(" - ")
+                    .append(lastDate.monthOfYear().getAsText(Locale.getDefault()))
+            } else {
+                // Different year (Case 2)
+                monthText.append(" ")
+                    .append(firstDate.year().get())
+                    .append(" - ")
+                    .append(lastDate.monthOfYear().getAsText(Locale.getDefault()))
+            }
+            // Append last date year
+            monthText.append(" ")
+                .append(lastDate.year().get())
+        } else {
+            // Same month
+            monthText.append(" ")
+                .append(firstDate.year().get())
+        }
+        return monthText.toString()
+    }
+
+    /**
+     * Calculate dates for calendar
+     * Input constants:
+     * - 4 Weeks (TotalWeeks)
+     * - 7 Days (DaysInWeekCount)
+     * - Current week - last row
+     * - Week starts from Monday
+     *
+     * Algorithm:
+     * Goal: calculate days to add with JodaTime lib to current date
+     *
+     * Input: Today = 9 September (Wednesday)
+     *
+     * Step 1: Define day shift in the week
+     * |_M_|_T_|_W_|_T_|_F_|_S_|_S_|
+     * | -2| -1| 9 | +1| +2| +3| +4| <- Current Week (4th row)
+     * Code: (CurrentDayOfTheWeek * -1) + dayId
+     *
+     * Step 2: Apply week shift
+     * |_M_|_T_|_W_|_T_|_F_|_S_|_S_|
+     * | -9| -8| -7| -6| -5| -4| -3| <- Previous Week (3d row)
+     * | -2| -1| 9 | +1| +2| +3| +4| <- Current Week (4th row)
+     * Code: (DaysInWeekCount * (TotalWeeks - weekId)) * -1
+     */
+    fun getDates(currentDate: DateTime = DateTime(Instant.now(), DateTimeZone.UTC)): List<CalendarAdapter.Day> {
+        // Create mutable list of DateTime as a result
+        val result = mutableListOf<CalendarAdapter.Day>()
+        // Get current day of the week (where 1 = Monday, 7 = Sunday)
+        val currentDayOfTheWeek = currentDate.dayOfWeek().get()
+        // Week count
+        val weeksCount = WEEKS_COUNT - 1
+        for (weekId in 0..weeksCount) {
+            for (dayId in 1..DAYS_IN_WEEK) {
+                val daysDiff = (currentDayOfTheWeek * -1) + dayId - (DAYS_IN_WEEK * (weeksCount - weekId))
+                result.add(CalendarAdapter.Day(currentDate.plusDays(daysDiff).toLocalDate()))
+            }
+        }
+        return result
+    }
+
+    companion object {
+        /**
+         * Total days in week
+         */
+        const val DAYS_IN_WEEK = 7
+
+        /**
+         * Weeks count
+         */
+        private const val WEEKS_COUNT = 4
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarDayViewHolder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarDayViewHolder.kt
new file mode 100644
index 0000000000000000000000000000000000000000..393f585c04f71bb7fabbd91de19db2fbf6fd05bb
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarDayViewHolder.kt
@@ -0,0 +1,70 @@
+package de.rki.coronawarnapp.ui.calendar
+
+import android.view.View
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import androidx.recyclerview.widget.RecyclerView
+import de.rki.coronawarnapp.R
+import org.joda.time.LocalDate
+import org.joda.time.format.DateTimeFormat
+
+/**
+ * Calendar day view holder
+ *
+ * @param v View - view for holder
+ */
+class CalendarDayViewHolder(v: View) : RecyclerView.ViewHolder(v) {
+
+    /**
+     * Day text view
+     */
+    private val textView: TextView = v.findViewById(R.id.dayText)
+
+    /**
+     * Accessibility talk back date format
+     */
+    private val talkBackDateFormat = DateTimeFormat.forPattern("EEEE d MMMMM")
+
+    /**
+     * Bind data to view
+     */
+    fun bind(day: CalendarAdapter.Day, clickListener: (CalendarAdapter.Day) -> Unit) {
+        val context = textView.context
+        val today = LocalDate.now()
+
+        // Set day text
+        textView.text = day.date.dayOfMonth.toString()
+
+        // Set day content description for talk back
+        textView.contentDescription = day.date.toString(talkBackDateFormat)
+
+        // If date is after today - then disable click listener
+        if (!day.date.isAfter(today)) {
+            textView.setOnClickListener { clickListener(day) }
+        }
+
+        // Update visuals
+        when {
+            // Selected
+            day.isSelected -> {
+                textView.setBackgroundResource(R.drawable.calendar_selected_day_back)
+                textView.setTextColor(ContextCompat.getColor(context, R.color.colorTextEmphasizedButton))
+            }
+            // Today
+            day.date.isEqual(today) -> {
+                textView.setBackgroundResource(R.drawable.calendar_today_back)
+                textView.setTextColor(ContextCompat.getColor(context, R.color.colorCalendarTodayText))
+            }
+            // Future
+            day.date.isAfter(today) -> {
+                textView.setBackgroundResource(0)
+                textView.setTextColor(ContextCompat.getColor(context, R.color.colorTextPrimary3))
+            }
+            // Past
+            day.date.isBefore(today) -> {
+                textView.setBackgroundResource(0)
+                textView.setTextColor(ContextCompat.getColor(context, R.color.colorTextPrimary1))
+            }
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarView.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarView.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c5045db27e35fb1f32c8b9f943644bd4d81863ea
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarView.kt
@@ -0,0 +1,199 @@
+package de.rki.coronawarnapp.ui.calendar
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import de.rki.coronawarnapp.R
+import org.joda.time.DateTime
+import org.joda.time.Instant
+import org.joda.time.LocalDate
+import java.util.Locale
+
+/**
+ * Custom calendar view with rules:
+ * - 4 Weeks
+ * - 7 Days
+ * - Current week - last row
+ * - Week starts from Monday
+ */
+class CalendarView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr) {
+
+    /**
+     * Calendar layout
+     */
+    private var calendarLayout: LinearLayout
+
+    /**
+     * Calendar header
+     */
+    private var headerTextView: TextView
+
+    /**
+     * Recycler view for dates
+     *
+     * @see RecyclerView
+     */
+    private var recyclerView: RecyclerView
+
+    /**
+     * Layout manager for recycler view
+     *
+     * @see RecyclerView.LayoutManager
+     */
+    private var layoutManager: RecyclerView.LayoutManager
+
+    /**
+     * Mutable list of Day
+     *
+     * @see CalendarAdapter.Day
+     */
+    private val days = mutableListOf<CalendarAdapter.Day>()
+
+    /**
+     * Recycler view adapter
+     *
+     * @see CalendarAdapter
+     */
+    private lateinit var adapter: CalendarAdapter
+
+    /**
+     * Fragment click listener
+     */
+    private var listener: ((LocalDate?) -> Unit)? = null
+
+    /**
+     * On item click event listener
+     *
+     * @see CalendarAdapter.update
+     * @see updateSelection
+     */
+    private val onItemClickListener: (CalendarAdapter.Day) -> Unit = { selectedDay ->
+        // Update data set
+        val updateData = days.map { oldDay -> oldDay.copy(isSelected = selectedDay == oldDay) }
+        // Update selection
+        updateSelection(updateData.any { it.isSelected })
+
+        adapter.update(updateData)
+
+        // Invoke fragment on click
+        listener?.invoke(updateData.find { it.isSelected }?.date)
+    }
+
+    /**
+     * Unset selection of each date shown
+     *
+     * @see CalendarAdapter.update
+     */
+    fun unsetSelection() {
+        val updateData = days.map { oldDay -> oldDay.copy(isSelected = false) }
+        updateSelection(false)
+        adapter.update(updateData)
+    }
+
+    init {
+        LayoutInflater.from(context)
+            .inflate(R.layout.fragment_calendar, this, true)
+
+        // Get linear layout
+        calendarLayout = findViewById<LinearLayout>(R.id.calendar_layout)
+
+        // Get header view
+        headerTextView = findViewById<TextView>(R.id.calendar_header)
+
+        // Get recycler view
+        recyclerView = findViewById<RecyclerView>(R.id.calendar_recycler_view)
+
+        // Create layout manager
+        layoutManager = LinearLayoutManager(context)
+        // Set to grid layout
+        layoutManager = GridLayoutManager(context, CalendarCalculation.DAYS_IN_WEEK)
+
+        with(recyclerView) {
+            layoutManager = this@CalendarView.layoutManager
+            scrollToPosition(0)
+        }
+
+        // Calculate dates to display
+        days.addAll(CalendarCalculation().getDates())
+
+        // Set calendar adapter as adapter for recycler view
+        adapter = CalendarAdapter(onItemClickListener)
+        adapter.update(days)
+
+        recyclerView.adapter = adapter
+
+        // Setup day legend
+        setUpDayLegend(this)
+
+        // Setup month
+        setUpMonthTextView(this)
+    }
+
+    /**
+     * Set fragment click listener
+     *
+     * @see listener
+     */
+    fun setDateSelectedListener(listener: (LocalDate?) -> Unit) {
+        this.listener = listener
+    }
+
+    /**
+     * Update header and top level layout background
+     */
+    private fun updateSelection(isSelected: Boolean) {
+        calendarLayout.isSelected = isSelected
+        headerTextView.isSelected = isSelected
+    }
+
+    /**
+     * SetUp day legend (week day)
+     *
+     * NOTE: DaysOfWeek is impossible to use due to API 23
+     *
+     * @param view View - CalendarView
+     */
+    private fun setUpDayLegend(view: View) {
+        // Get day legend layout
+        val dayLegendLayout = findViewById<LinearLayout>(R.id.calendar_day_legend)
+        // Get current week day
+        val date = LocalDate()
+        val currentWeekDay = DateTime(Instant.now()).dayOfWeek().get()
+        for (dayId in 1..CalendarCalculation.DAYS_IN_WEEK) {
+            val dayOfWeek = CalendarWeekDayView(context)
+            val weekDay = date.withDayOfWeek(dayId).dayOfWeek()
+            // weekDay.getAsText returns in either "Fri" or "Friday" format, substring first latter
+            dayOfWeek.setUp(weekDay.getAsText(Locale.getDefault()).take(1),
+                weekDay.get() == currentWeekDay)
+            dayLegendLayout.addView(dayOfWeek)
+        }
+    }
+
+    /**
+     * SetUp month text view
+     *
+     * @param view View - CalendarView
+     *
+     * @see CalendarCalculation.getMonthText
+     */
+    private fun setUpMonthTextView(view: View) {
+        // Get month text view
+        val monthTextView = findViewById<TextView>(R.id.calendar_month)
+
+        // Get first and last days
+        val firstDate = days.first().date
+        val lastDate = days.last().date
+
+        monthTextView.text = CalendarCalculation().getMonthText(firstDate, lastDate)
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarWeekDayView.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarWeekDayView.kt
new file mode 100644
index 0000000000000000000000000000000000000000..52ff504e3d219e5fee43e5c51e86c5dea38a4afe
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarWeekDayView.kt
@@ -0,0 +1,51 @@
+package de.rki.coronawarnapp.ui.calendar
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.LinearLayout
+import android.widget.TextView
+import de.rki.coronawarnapp.R
+
+/**
+ * Week day custom view
+ */
+class CalendarWeekDayView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr) {
+
+    private val textView: TextView
+
+    /**
+     * Initialize the view
+     *
+     * Get TextView for day setup
+     * SetUp layout params
+     */
+    init {
+        LayoutInflater.from(context)
+            .inflate(R.layout.fragment_calendar_day, this, true)
+        textView = findViewById(R.id.dayText)
+
+        layoutParams = LayoutParams(
+            0,
+            LayoutParams.WRAP_CONTENT,
+            1.0f
+        )
+    }
+
+    /**
+     * SetUp the view from CalendarFragment
+     */
+    fun setUp(text: String, isSelected: Boolean = false) {
+        textView.text = text
+
+        if (isSelected) {
+            textView.setTextAppearance(R.style.calendarWeekDaySelected)
+        } else {
+            textView.setTextAppearance(R.style.calendarWeekDayNormal)
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..cc4cc4b727fe926c05916149d053dcaa33a93e5b
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragment.kt
@@ -0,0 +1,154 @@
+package de.rki.coronawarnapp.ui.submission
+
+import android.content.res.ColorStateList
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Observer
+import androidx.navigation.fragment.findNavController
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.databinding.FragmentSubmissionSymptomCalendarBinding
+import de.rki.coronawarnapp.submission.Symptoms
+import de.rki.coronawarnapp.ui.doNavigate
+import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
+import de.rki.coronawarnapp.util.formatter.formatCalendarBackgroundButtonStyleByState
+import de.rki.coronawarnapp.util.formatter.formatCalendarButtonStyleByState
+import de.rki.coronawarnapp.util.formatter.isEnableSymptomCalendarButtonByState
+
+class SubmissionSymptomCalendarFragment : Fragment() {
+
+    private var _binding: FragmentSubmissionSymptomCalendarBinding? = null
+    private val binding: FragmentSubmissionSymptomCalendarBinding get() = _binding!!
+    private val submissionViewModel: SubmissionViewModel by activityViewModels()
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        _binding = FragmentSubmissionSymptomCalendarBinding.inflate(inflater)
+        binding.submissionViewModel = submissionViewModel
+        binding.lifecycleOwner = this
+        return binding.root
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        setButtonOnClickListener()
+
+        binding.symptomCalendarContainer.setDateSelectedListener(submissionViewModel::onDateSelected)
+
+        submissionViewModel.symptomCalendarEvent.observe(viewLifecycleOwner, Observer {
+            when (it) {
+                is SymptomCalendarEvent.NavigateToNext -> navigateToSymptomFinish()
+                is SymptomCalendarEvent.NavigateToPrevious -> navigateToPreviousScreen()
+            }
+        })
+
+        submissionViewModel.symptomStart.observe(viewLifecycleOwner, Observer {
+            updateButtons(it)
+            if (it !is Symptoms.StartOf.Date) {
+                binding.symptomCalendarContainer.unsetSelection()
+            }
+        })
+
+        submissionViewModel.initSymptomStart()
+    }
+
+    private fun updateButtons(symptomStart: Symptoms.StartOf?) {
+        binding.symptomCalendarChoiceSelection.calendarButtonSevenDays
+            .findViewById<Button>(R.id.calendar_button_seven_days)
+            .setTextColor(formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.LastSevenDays))
+        binding.symptomCalendarChoiceSelection.targetLayout
+            .findViewById<Button>(R.id.calendar_button_seven_days).backgroundTintList =
+            ColorStateList.valueOf(
+                formatCalendarBackgroundButtonStyleByState(
+                    symptomStart, Symptoms.StartOf.LastSevenDays
+                )
+            )
+
+        binding.symptomCalendarChoiceSelection.targetLayout
+            .findViewById<Button>(R.id.calendar_button_one_two_weeks)
+            .setTextColor(formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.OneToTwoWeeksAgo))
+        binding.symptomCalendarChoiceSelection.targetLayout
+            .findViewById<Button>(R.id.calendar_button_one_two_weeks).backgroundTintList =
+            ColorStateList.valueOf(
+                formatCalendarBackgroundButtonStyleByState(
+                    symptomStart, Symptoms.StartOf.OneToTwoWeeksAgo
+                )
+            )
+
+        binding.symptomCalendarChoiceSelection.targetLayout
+            .findViewById<Button>(R.id.calendar_button_more_than_two_weeks)
+            .setTextColor(formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.MoreThanTwoWeeks))
+        binding.symptomCalendarChoiceSelection.targetLayout
+            .findViewById<Button>(R.id.calendar_button_more_than_two_weeks).backgroundTintList =
+            ColorStateList.valueOf(
+                formatCalendarBackgroundButtonStyleByState(
+                    symptomStart, Symptoms.StartOf.MoreThanTwoWeeks
+                )
+            )
+
+        binding.symptomCalendarChoiceSelection.targetLayout
+            .findViewById<Button>(R.id.target_button_verify)
+            .setTextColor(formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.NoInformation))
+        binding.symptomCalendarChoiceSelection.targetLayout
+            .findViewById<Button>(R.id.target_button_verify).backgroundTintList =
+            ColorStateList.valueOf(
+                formatCalendarBackgroundButtonStyleByState(
+                    symptomStart, Symptoms.StartOf.NoInformation
+                )
+            )
+
+        binding
+            .symptomButtonNext.findViewById<Button>(R.id.symptom_button_next).isEnabled =
+            isEnableSymptomCalendarButtonByState(
+                symptomStart
+            )
+    }
+
+    private fun navigateToSymptomFinish() {
+        findNavController().doNavigate(SubmissionSymptomCalendarFragmentDirections
+            .actionSubmissionSymptomCalendarFragmentToSubmissionResultPositiveOtherWarningFragment())
+    }
+
+    private fun navigateToPreviousScreen() {
+        findNavController().doNavigate(SubmissionSymptomCalendarFragmentDirections
+            .actionSubmissionCalendarFragmentToSubmissionSymptomIntroductionFragment())
+    }
+
+    private fun setButtonOnClickListener() {
+        binding
+            .submissionSymptomCalendarHeader.headerButtonBack.buttonIcon
+            .setOnClickListener { submissionViewModel.onCalendarPreviousClicked() }
+
+        binding
+            .symptomButtonNext
+            .setOnClickListener { submissionViewModel.onCalendarNextClicked() }
+
+        binding.symptomCalendarChoiceSelection
+            .calendarButtonSevenDays
+            .setOnClickListener { submissionViewModel.onLastSevenDaysStart() }
+
+        binding.symptomCalendarChoiceSelection
+            .calendarButtonOneTwoWeeks
+            .setOnClickListener { submissionViewModel.onOneToTwoWeeksAgoStart() }
+
+        binding.symptomCalendarChoiceSelection
+            .calendarButtonMoreThanTwoWeeks
+            .setOnClickListener { submissionViewModel.onMoreThanTwoWeeksStart() }
+
+        binding.symptomCalendarChoiceSelection
+            .targetButtonVerify
+            .setOnClickListener { submissionViewModel.onNoInformationStart() }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomIntroductionFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomIntroductionFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..dd6042ec6663217dd340b46833e6fa59d4b844aa
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomIntroductionFragment.kt
@@ -0,0 +1,145 @@
+package de.rki.coronawarnapp.ui.submission
+
+import android.content.res.ColorStateList
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Observer
+import androidx.navigation.fragment.findNavController
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.databinding.FragmentSubmissionSymptomIntroBinding
+import de.rki.coronawarnapp.submission.Symptoms
+import de.rki.coronawarnapp.ui.doNavigate
+import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
+import de.rki.coronawarnapp.util.formatter.formatBackgroundButtonStyleByState
+import de.rki.coronawarnapp.util.formatter.formatButtonStyleByState
+import de.rki.coronawarnapp.util.formatter.isEnableSymptomIntroButtonByState
+
+class SubmissionSymptomIntroductionFragment : Fragment() {
+
+    private var _binding: FragmentSubmissionSymptomIntroBinding? = null
+    private val binding: FragmentSubmissionSymptomIntroBinding get() = _binding!!
+    private val submissionViewModel: SubmissionViewModel by activityViewModels()
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        _binding = FragmentSubmissionSymptomIntroBinding.inflate(inflater)
+        binding.submissionViewModel = submissionViewModel
+        binding.lifecycleOwner = this
+        return binding.root
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        setButtonOnClickListener()
+
+        submissionViewModel.symptomIntroductionEvent.observe(viewLifecycleOwner, Observer {
+            when (it) {
+                is SymptomIntroductionEvent.NavigateToSymptomCalendar -> navigateToNext()
+                is SymptomIntroductionEvent.NavigateToPreviousScreen -> navigateToPreviousScreen()
+            }
+        })
+
+        submissionViewModel.symptomIndication.observe(viewLifecycleOwner, Observer {
+            updateButtons(it)
+        })
+
+        submissionViewModel.initSymptoms()
+    }
+
+    private fun updateButtons(symptomIndication: Symptoms.Indication?) {
+        binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_apply)
+            .setTextColor(formatButtonStyleByState(symptomIndication, Symptoms.Indication.POSITIVE))
+        binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_apply).backgroundTintList =
+            ColorStateList.valueOf(
+                formatBackgroundButtonStyleByState(
+                    symptomIndication,
+                    Symptoms.Indication.POSITIVE
+                )
+            )
+        binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_reject)
+            .setTextColor(formatButtonStyleByState(symptomIndication, Symptoms.Indication.NEGATIVE))
+        binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_reject).backgroundTintList =
+            ColorStateList.valueOf(
+                formatBackgroundButtonStyleByState(
+                    symptomIndication,
+                    Symptoms.Indication.NEGATIVE
+                )
+            )
+        binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_verify)
+            .setTextColor(
+                formatButtonStyleByState(
+                    symptomIndication,
+                    Symptoms.Indication.NO_INFORMATION
+                )
+            )
+        binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_verify).backgroundTintList =
+            ColorStateList.valueOf(
+                formatBackgroundButtonStyleByState(
+                    symptomIndication,
+                    Symptoms.Indication.NO_INFORMATION
+                )
+            )
+        binding
+            .symptomButtonNext.findViewById<Button>(R.id.symptom_button_next).isEnabled =
+            isEnableSymptomIntroButtonByState(
+                symptomIndication
+            )
+    }
+
+    private fun navigateToNext() {
+
+        if (submissionViewModel.symptomIndication.value!! == Symptoms.Indication.POSITIVE) {
+            findNavController().doNavigate(
+                SubmissionSymptomIntroductionFragmentDirections
+                    .actionSubmissionSymptomIntroductionFragmentToSubmissionSymptomCalendarFragment()
+            )
+        } else {
+            findNavController().doNavigate(
+                SubmissionSymptomIntroductionFragmentDirections
+                    .actionSubmissionSymptomIntroductionFragmentToSubmissionResultPositiveOtherWarningFragment()
+            )
+        }
+    }
+
+    private fun navigateToPreviousScreen() {
+        findNavController().doNavigate(
+            SubmissionSymptomIntroductionFragmentDirections
+                .actionSubmissionSymptomIntroductionFragmentToSubmissionResultFragment()
+        )
+    }
+
+    private fun setButtonOnClickListener() {
+        binding
+            .submissionSymptomHeader.headerButtonBack.buttonIcon
+            .setOnClickListener { submissionViewModel.onPreviousClicked() }
+
+        binding
+            .symptomButtonNext
+            .setOnClickListener { submissionViewModel.onNextClicked() }
+
+        binding
+            .symptomChoiceSelection.targetButtonApply
+            .setOnClickListener { submissionViewModel.onPositiveSymptomIndication() }
+
+        binding
+            .symptomChoiceSelection.targetButtonReject
+            .setOnClickListener { submissionViewModel.onNegativeSymptomIndication() }
+
+        binding
+            .symptomChoiceSelection.targetButtonVerify
+            .setOnClickListener { submissionViewModel.onNoInformationSymptomIndication() }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomCalendarEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomCalendarEvent.kt
new file mode 100644
index 0000000000000000000000000000000000000000..922d0ff4c44846e25266eb7093fa67b3f843422d
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomCalendarEvent.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.ui.submission
+
+sealed class SymptomCalendarEvent {
+    object NavigateToNext : SymptomCalendarEvent()
+    object NavigateToPrevious : SymptomCalendarEvent()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomIntroductionEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomIntroductionEvent.kt
new file mode 100644
index 0000000000000000000000000000000000000000..96eb49ef2e3e6ba19beee220f6276b51c5ad7a73
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomIntroductionEvent.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.ui.submission
+
+sealed class SymptomIntroductionEvent {
+    object NavigateToSymptomCalendar : SymptomIntroductionEvent()
+    object NavigateToPreviousScreen : SymptomIntroductionEvent()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionTestResultFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionTestResultFragment.kt
index cc109856925f49d24993b308bafea5a2bbe672a8..f1491771d7a10538e5ddb3b6709b24f5acae2b3a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionTestResultFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionTestResultFragment.kt
@@ -173,7 +173,7 @@ class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_
 
         findNavController().doNavigate(
             SubmissionTestResultFragmentDirections
-                .actionSubmissionResultFragmentToSubmissionResultPositiveOtherWarningFragment()
+                .actionSubmissionResultFragmentToSubmissionSymptomIntroductionFragment()
         )
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
index c5f670cb06796888458824bdbeb98cc15d6bee50..c40ebc853875ddd53c2b390da228f5a4a7240ec7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
@@ -13,11 +13,17 @@ import de.rki.coronawarnapp.service.submission.QRScanResult
 import de.rki.coronawarnapp.service.submission.SubmissionService
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.storage.SubmissionRepository
+import de.rki.coronawarnapp.submission.Symptoms
+import de.rki.coronawarnapp.ui.SingleLiveEvent
 import de.rki.coronawarnapp.ui.submission.ApiRequestState
 import de.rki.coronawarnapp.ui.submission.ScanStatus
+import de.rki.coronawarnapp.ui.submission.SymptomCalendarEvent
+import de.rki.coronawarnapp.ui.submission.SymptomIntroductionEvent
 import de.rki.coronawarnapp.util.DeviceUIState
 import de.rki.coronawarnapp.util.Event
 import kotlinx.coroutines.launch
+import org.joda.time.LocalDate
+import timber.log.Timber
 import java.util.Date
 
 class SubmissionViewModel : ViewModel() {
@@ -34,6 +40,9 @@ class SubmissionViewModel : ViewModel() {
 
     val scanStatus: LiveData<Event<ScanStatus>> = _scanStatus
 
+    val symptomIntroductionEvent: SingleLiveEvent<SymptomIntroductionEvent> = SingleLiveEvent()
+    val symptomCalendarEvent: SingleLiveEvent<SymptomCalendarEvent> = SingleLiveEvent()
+
     val registrationState: LiveData<Event<ApiRequestState>> = _registrationState
     val registrationError: LiveData<Event<CwaWebException>> = _registrationError
 
@@ -50,24 +59,44 @@ class SubmissionViewModel : ViewModel() {
     val deviceUiState: LiveData<DeviceUIState> =
         SubmissionRepository.deviceUIState
 
-    fun submitDiagnosisKeys(keys: List<TemporaryExposureKey>) = viewModelScope.launch {
-        try {
-            _submissionState.value = ApiRequestState.STARTED
-            SubmissionService.asyncSubmitExposureKeys(keys)
-            _submissionState.value = ApiRequestState.SUCCESS
-        } catch (err: CwaWebException) {
-            _submissionError.value = Event(err)
-            _submissionState.value = ApiRequestState.FAILED
-        } catch (err: TransactionException) {
-            if (err.cause is CwaWebException) {
-                _submissionError.value = Event(err.cause)
-            } else {
-                err.report(ExceptionCategory.INTERNAL)
+    val symptomIndication = MutableLiveData<Symptoms.Indication?>()
+    val symptomStart = MutableLiveData<Symptoms.StartOf?>()
+
+    fun initSymptoms() {
+        symptomIndication.postValue(null)
+    }
+
+    fun initSymptomStart() {
+        symptomStart.postValue(null)
+    }
+
+    fun submitDiagnosisKeys(keys: List<TemporaryExposureKey>) {
+        val indication = symptomIndication.value
+        if (indication == null) {
+            Timber.w("symptoms indicator is null")
+            return
+        }
+        Symptoms(symptomStart.value, indication).also {
+            viewModelScope.launch {
+                try {
+                    _submissionState.value = ApiRequestState.STARTED
+                    SubmissionService.asyncSubmitExposureKeys(keys, it)
+                    _submissionState.value = ApiRequestState.SUCCESS
+                } catch (err: CwaWebException) {
+                    _submissionError.value = Event(err)
+                    _submissionState.value = ApiRequestState.FAILED
+                } catch (err: TransactionException) {
+                    if (err.cause is CwaWebException) {
+                        _submissionError.value = Event(err.cause)
+                    } else {
+                        err.report(ExceptionCategory.INTERNAL)
+                    }
+                    _submissionState.value = ApiRequestState.FAILED
+                } catch (err: Exception) {
+                    _submissionState.value = ApiRequestState.FAILED
+                    err.report(ExceptionCategory.INTERNAL)
+                }
             }
-            _submissionState.value = ApiRequestState.FAILED
-        } catch (err: Exception) {
-            _submissionState.value = ApiRequestState.FAILED
-            err.report(ExceptionCategory.INTERNAL)
         }
     }
 
@@ -142,4 +171,52 @@ class SubmissionViewModel : ViewModel() {
             }
         }
     }
+
+    fun onNextClicked() {
+        symptomIntroductionEvent.postValue(SymptomIntroductionEvent.NavigateToSymptomCalendar)
+    }
+
+    fun onPreviousClicked() {
+        symptomIntroductionEvent.postValue(SymptomIntroductionEvent.NavigateToPreviousScreen)
+    }
+
+    fun onCalendarNextClicked() {
+        symptomCalendarEvent.postValue(SymptomCalendarEvent.NavigateToNext)
+    }
+
+    fun onCalendarPreviousClicked() {
+        symptomCalendarEvent.postValue(SymptomCalendarEvent.NavigateToPrevious)
+    }
+
+    fun onPositiveSymptomIndication() {
+        symptomIndication.postValue(Symptoms.Indication.POSITIVE)
+    }
+
+    fun onNegativeSymptomIndication() {
+        symptomIndication.postValue(Symptoms.Indication.NEGATIVE)
+    }
+
+    fun onNoInformationSymptomIndication() {
+        symptomIndication.postValue(Symptoms.Indication.NO_INFORMATION)
+    }
+
+    fun onLastSevenDaysStart() {
+        symptomStart.postValue(Symptoms.StartOf.LastSevenDays)
+    }
+
+    fun onOneToTwoWeeksAgoStart() {
+        symptomStart.postValue(Symptoms.StartOf.OneToTwoWeeksAgo)
+    }
+
+    fun onMoreThanTwoWeeksStart() {
+        symptomStart.postValue(Symptoms.StartOf.MoreThanTwoWeeks)
+    }
+
+    fun onNoInformationStart() {
+        symptomStart.postValue(Symptoms.StartOf.NoInformation)
+    }
+
+    fun onDateSelected(localDate: LocalDate?) {
+        symptomStart.postValue(if (localDate == null) null else Symptoms.StartOf.Date(localDate.toDate().time))
+    }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/GoogleQuotaCalculator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/GoogleQuotaCalculator.kt
deleted file mode 100644
index e7aace190ed9a6217487d3f76b6356c07c6aa267..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/GoogleQuotaCalculator.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-package de.rki.coronawarnapp.util
-
-import de.rki.coronawarnapp.storage.LocalData
-import org.joda.time.Chronology
-import org.joda.time.DateTime
-import org.joda.time.DateTimeZone
-import org.joda.time.Duration
-import org.joda.time.Instant
-
-/**
- * This Calculator class takes multiple parameters to check if the Google API
- * can be called or the Rate Limit has been reached. The Quota is expected to reset at
- * the start of the day in the given timeZone and Chronology
- *
- * @property incrementByAmount The amount of Quota Calls to increment per Call
- * @property quotaLimit The maximum amount of Quota Calls allowed before Rate Limiting
- * @property quotaResetPeriod The Period after which the Quota Resets
- * @property quotaTimeZone The Timezone to work in
- * @property quotaChronology The Chronology to work in
- */
-class GoogleQuotaCalculator(
-    val incrementByAmount: Int,
-    val quotaLimit: Int,
-    val quotaResetPeriod: Duration,
-    val quotaTimeZone: DateTimeZone,
-    val quotaChronology: Chronology
-) : QuotaCalculator<Int> {
-    override var hasExceededQuota: Boolean = false
-
-    override fun calculateQuota(): Boolean {
-        if (Instant.now().isAfter(LocalData.nextTimeRateLimitingUnlocks)) {
-            LocalData.nextTimeRateLimitingUnlocks = DateTime
-                .now(quotaTimeZone)
-                .withChronology(quotaChronology)
-                .plus(quotaResetPeriod)
-                .withTimeAtStartOfDay()
-                .toInstant()
-            LocalData.googleAPIProvideDiagnosisKeysCallCount = 0
-        }
-
-        if (LocalData.googleAPIProvideDiagnosisKeysCallCount <= quotaLimit) {
-            LocalData.googleAPIProvideDiagnosisKeysCallCount += incrementByAmount
-        }
-
-        hasExceededQuota = LocalData.googleAPIProvideDiagnosisKeysCallCount > quotaLimit
-
-        return hasExceededQuota
-    }
-
-    override fun resetProgressTowardsQuota(newProgress: Int) {
-        if (newProgress > quotaLimit) {
-            throw IllegalArgumentException("cannot reset progress to a value higher than the quota limit")
-        }
-        if (newProgress % incrementByAmount != 0) {
-            throw IllegalArgumentException("supplied progress is no multiple of $incrementByAmount")
-        }
-        LocalData.googleAPIProvideDiagnosisKeysCallCount = newProgress
-        hasExceededQuota = false
-    }
-
-    override fun getProgressTowardsQuota(): Int = LocalData.googleAPIProvideDiagnosisKeysCallCount
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensions.kt
index b7597b2cafa3faa737ac5786c8aed84aaf0deedb..6f3db1758c31fec40607709d11f494f9bd006f25 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensions.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensions.kt
@@ -1,55 +1,10 @@
 package de.rki.coronawarnapp.util
 
 import KeyExportFormat
-import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
-import com.google.protobuf.ByteString
 import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange
 
 object ProtoFormatConverterExtensions {
 
-    private const val ROLLING_PERIOD = 144
-    private const val DEFAULT_TRANSMISSION_RISK_LEVEL = 1
-    private const val TRANSMISSION_RISK_DAY_0 = 5
-    private const val TRANSMISSION_RISK_DAY_1 = 6
-    private const val TRANSMISSION_RISK_DAY_2 = 8
-    private const val TRANSMISSION_RISK_DAY_3 = 8
-    private const val TRANSMISSION_RISK_DAY_4 = 8
-    private const val TRANSMISSION_RISK_DAY_5 = 5
-    private const val TRANSMISSION_RISK_DAY_6 = 3
-    private const val TRANSMISSION_RISK_DAY_7 = 1
-    private val DEFAULT_TRANSMISSION_RISK_VECTOR = intArrayOf(
-        TRANSMISSION_RISK_DAY_0,
-        TRANSMISSION_RISK_DAY_1,
-        TRANSMISSION_RISK_DAY_2,
-        TRANSMISSION_RISK_DAY_3,
-        TRANSMISSION_RISK_DAY_4,
-        TRANSMISSION_RISK_DAY_5,
-        TRANSMISSION_RISK_DAY_6,
-        TRANSMISSION_RISK_DAY_7
-    )
-    private const val MAXIMUM_KEYS = 14
-
-    fun List<TemporaryExposureKey>.limitKeyCount() =
-        this.sortedWith(compareByDescending { it.rollingStartIntervalNumber }).take(MAXIMUM_KEYS)
-
-    fun List<TemporaryExposureKey>.transformKeyHistoryToExternalFormat() =
-        this.sortedWith(compareByDescending { it.rollingStartIntervalNumber })
-            .mapIndexed { index, it ->
-                // The latest key we receive is from yesterday (i.e. 1 day ago),
-                // thus we need use index+1
-                val riskValue =
-                    if (index + 1 <= DEFAULT_TRANSMISSION_RISK_VECTOR.lastIndex)
-                        DEFAULT_TRANSMISSION_RISK_VECTOR[index + 1]
-                    else
-                        DEFAULT_TRANSMISSION_RISK_LEVEL
-                KeyExportFormat.TemporaryExposureKey.newBuilder()
-                    .setKeyData(ByteString.readFrom(it.keyData.inputStream()))
-                    .setRollingStartIntervalNumber(it.rollingStartIntervalNumber)
-                    .setRollingPeriod(ROLLING_PERIOD)
-                    .setTransmissionRiskLevel(riskValue)
-                    .build()
-            }
-
     fun AppleLegacyKeyExchange.Key.convertToGoogleKey(): KeyExportFormat.TemporaryExposureKey =
         KeyExportFormat.TemporaryExposureKey.newBuilder()
             .setKeyData(this.keyData)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/QuotaCalculator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/QuotaCalculator.kt
deleted file mode 100644
index 682f4a6002b06ef548e04da1c68012372f3c6743..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/QuotaCalculator.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package de.rki.coronawarnapp.util
-
-/**
- * Class to check if a Quota has been reached based on the calculation done inside
- * the Calculator
- *
- */
-interface QuotaCalculator<T> {
-    val hasExceededQuota: Boolean
-
-    /**
-     * This function is called to recalculate an old quota score
-     */
-    fun calculateQuota(): Boolean
-
-    /**
-     * Reset the quota progress
-     *
-     * @param newProgress new progress towards the quota
-     */
-    fun resetProgressTowardsQuota(newProgress: T)
-
-    /**
-     * Retrieve the current progress towards the quota
-     *
-     * @return current progress count
-     */
-    fun getProgressTowardsQuota(): T
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLogger.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLogger.kt
new file mode 100644
index 0000000000000000000000000000000000000000..eb3b29093e4a6c772d65dd7167ecbeda941588e0
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLogger.kt
@@ -0,0 +1,40 @@
+package de.rki.coronawarnapp.util.debug
+
+import android.content.Context
+import timber.log.Timber
+import java.io.File
+
+class FileLogger constructor(private val context: Context) {
+
+    val logFile = File(context.cacheDir, "FileLoggerTree.log")
+    val triggerFile = File(context.filesDir, "FileLoggerTree.trigger")
+    private var loggerTree: FileLoggerTree? = null
+
+    val isLogging: Boolean
+        get() = loggerTree != null
+
+    init {
+        if (triggerFile.exists()) {
+            start()
+        }
+    }
+
+    fun start() {
+        if (loggerTree != null) return
+
+        loggerTree = FileLoggerTree(logFile).also {
+            Timber.plant(it)
+            it.start()
+            triggerFile.createNewFile()
+        }
+    }
+
+    fun stop() {
+        loggerTree?.let {
+            it.stop()
+            logFile.delete()
+            triggerFile.delete()
+            loggerTree = null
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLoggerTree.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLoggerTree.kt
new file mode 100644
index 0000000000000000000000000000000000000000..84bd21ad68562197d35c5e136283ccd22ef73f7f
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/FileLoggerTree.kt
@@ -0,0 +1,86 @@
+package de.rki.coronawarnapp.util.debug
+
+import android.annotation.SuppressLint
+import android.util.Log
+import timber.log.Timber
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.OutputStreamWriter
+
+@SuppressLint("LogNotTimber")
+class FileLoggerTree(private val logFile: File) : Timber.DebugTree() {
+    private var logWriter: OutputStreamWriter? = null
+
+    @SuppressLint("SetWorldReadable")
+    @Synchronized
+    fun start() {
+        if (logWriter != null) return
+
+        logFile.parentFile.mkdirs()
+        if (logFile.createNewFile()) {
+            Log.i(TAG, "File logger writing to " + logFile.path)
+        }
+        if (logFile.setReadable(true, false)) {
+            Log.i(TAG, "Debug run log read permission set")
+        }
+
+        try {
+            logWriter = OutputStreamWriter(FileOutputStream(logFile, true))
+            logWriter!!.write("=== BEGIN ===\n")
+            logWriter!!.write("Logfile: $logFile\n")
+            logWriter!!.flush()
+            Log.i(TAG, "File logger started.")
+        } catch (e: IOException) {
+            e.printStackTrace()
+
+            logFile.delete()
+            if (logWriter != null) logWriter!!.close()
+        }
+    }
+
+    @Synchronized
+    fun stop() {
+        logWriter?.let {
+            logWriter = null
+            try {
+                it.write("=== END ===\n")
+                it.close()
+            } catch (ignore: IOException) {
+            }
+            Log.i(TAG, "File logger stopped.")
+        }
+    }
+
+    override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
+        logWriter?.let {
+            try {
+                it.write("${System.currentTimeMillis()}  ${priorityToString(priority)}/$tag: $message\n")
+                it.flush()
+            } catch (e: IOException) {
+                Timber.tag(TAG).e(e)
+                try {
+                    it.close()
+                } catch (ignore: Exception) {
+                }
+                logWriter = null
+            }
+        }
+    }
+
+    override fun toString(): String {
+        return "FileLoggerTree(file=$logFile)"
+    }
+
+    companion object {
+        private const val TAG = "FileLoggerTree"
+        private fun priorityToString(priority: Int): String = when (priority) {
+            Log.ERROR -> "E"
+            Log.WARN -> "W"
+            Log.INFO -> "I"
+            Log.DEBUG -> "D"
+            Log.VERBOSE -> "V"
+            else -> priority.toString()
+        }
+    }
+}
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 03340dbfbb1ba4e43a4da4ed8f984fde8755b4c5..01f3dca1df3cf004af06d63b402e42f585e1e8d2 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
@@ -5,13 +5,14 @@ import dagger.Component
 import dagger.android.AndroidInjector
 import dagger.android.support.AndroidSupportInjectionModule
 import de.rki.coronawarnapp.CoronaWarnApplication
-import de.rki.coronawarnapp.nearby.NearbyModule
 import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule
 import de.rki.coronawarnapp.diagnosiskeys.download.KeyFileDownloader
 import de.rki.coronawarnapp.diagnosiskeys.server.AppConfigServer
 import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository
 import de.rki.coronawarnapp.http.HttpModule
 import de.rki.coronawarnapp.http.ServiceFactory
+import de.rki.coronawarnapp.nearby.ENFClient
+import de.rki.coronawarnapp.nearby.ENFModule
 import de.rki.coronawarnapp.receiver.ReceiverBinder
 import de.rki.coronawarnapp.risk.RiskModule
 import de.rki.coronawarnapp.service.ServiceBinder
@@ -37,9 +38,9 @@ import javax.inject.Singleton
         RiskModule::class,
         UtilModule::class,
         DeviceModule::class,
+        ENFModule::class,
         HttpModule::class,
-        DiagnosisKeysModule::class,
-        NearbyModule::class
+        DiagnosisKeysModule::class
     ]
 )
 interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> {
@@ -59,6 +60,8 @@ interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> {
 
     val appConfigServer: AppConfigServer
 
+    val enfClient: ENFClient
+
     @Component.Factory
     interface Factory {
         fun create(@BindsInstance app: CoronaWarnApplication): ApplicationComponent
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt
index 59965289788a0a3ffe127833ea18dcfec897d450..ea0ea81e282531d04ad27e41a0d6bf0288c40854 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt
@@ -11,12 +11,45 @@ import android.text.style.ForegroundColorSpan
 import android.view.View
 import de.rki.coronawarnapp.CoronaWarnApplication
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.submission.Symptoms
 import de.rki.coronawarnapp.ui.submission.ApiRequestState
 import de.rki.coronawarnapp.util.DeviceUIState
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUIFormat
 import java.util.Date
 import java.util.Locale
 
+fun formatButtonStyleByState(
+    currentState: Symptoms.Indication?,
+    state: Symptoms.Indication?
+): Int =
+    formatColor(currentState == state, R.color.colorTextSixteenWhite, R.color.colorTextPrimary1)
+
+fun formatBackgroundButtonStyleByState(
+    currentState: Symptoms.Indication?,
+    state: Symptoms.Indication?
+): Int =
+    formatColor(currentState == state, R.color.colorTextSemanticNeutral, R.color.colorSurface2)
+
+fun formatCalendarButtonStyleByState(
+    currentState: Symptoms.StartOf?,
+    state: Symptoms.StartOf?
+): Int =
+    formatColor(currentState == state, R.color.colorTextSixteenWhite, R.color.colorTextPrimary1)
+
+fun formatCalendarBackgroundButtonStyleByState(
+    currentState: Symptoms.StartOf?,
+    state: Symptoms.StartOf?
+): Int =
+    formatColor(currentState == state, R.color.colorTextSemanticNeutral, R.color.colorSurface2)
+
+fun isEnableSymptomIntroButtonByState(currentState: Symptoms.Indication?): Boolean {
+    return currentState != null
+}
+
+fun isEnableSymptomCalendarButtonByState(currentState: Symptoms.StartOf?): Boolean {
+    return currentState != null
+}
+
 fun formatTestResultSpinnerVisible(uiStateState: ApiRequestState?): Int =
     formatVisibility(uiStateState != ApiRequestState.SUCCESS)
 
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
index c7e797fa3a075a6cfb7cded9f63f8058533aa00c..9e9fb0a702ba1f8268bd0e1c231776fccb7f55fe 100644
--- 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
@@ -5,6 +5,7 @@ import androidx.work.Constraints
 import androidx.work.NetworkType
 import de.rki.coronawarnapp.notification.NotificationHelper
 import de.rki.coronawarnapp.storage.LocalData
+import timber.log.Timber
 import kotlin.random.Random
 
 /**
@@ -90,6 +91,7 @@ object BackgroundWorkHelper {
      * @see LocalData.backgroundNotification()
      */
     fun sendDebugNotification(title: String, content: String) {
+        Timber.d("sendDebugNotification(title=%s, content=%s)", title, content)
         if (!LocalData.backgroundNotification()) return
         NotificationHelper.sendNotification(title, content, NotificationCompat.PRIORITY_HIGH, true)
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt
index e45eb28baae14e26ea910330763c46ccf2a766b1..95cf66a25bc91be467412f2b161929af7e1d7594 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt
@@ -15,10 +15,6 @@ import timber.log.Timber
 class DiagnosisKeyRetrievalOneTimeWorker(val context: Context, workerParams: WorkerParameters) :
     CoroutineWorker(context, workerParams) {
 
-    companion object {
-        private val TAG: String? = DiagnosisKeyRetrievalOneTimeWorker::class.simpleName
-    }
-
     /**
      * Work execution
      *
@@ -27,28 +23,40 @@ class DiagnosisKeyRetrievalOneTimeWorker(val context: Context, workerParams: Wor
      * @see RetrieveDiagnosisKeysTransaction
      */
     override suspend fun doWork(): Result {
-        Timber.d("Background job started. Run attempt: $runAttemptCount ")
+        Timber.d("$id: doWork() started. Run attempt: $runAttemptCount")
+
         BackgroundWorkHelper.sendDebugNotification(
-            "KeyOneTime Executing: Start", "KeyOneTime started. Run attempt: $runAttemptCount ")
+            "KeyOneTime Executing: Start", "KeyOneTime started. Run attempt: $runAttemptCount "
+        )
 
         var result = Result.success()
         try {
             RetrieveDiagnosisKeysTransaction.startWithConstraints()
         } catch (e: Exception) {
+            Timber.w(
+                e, "$id: Error during RetrieveDiagnosisKeysTransaction.startWithConstraints()."
+            )
+
             if (runAttemptCount > BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD) {
+                Timber.w(e, "$id: Retry attempts exceeded.")
 
                 BackgroundWorkHelper.sendDebugNotification(
-                    "KeyOneTime Executing: Failure", "KeyOneTime failed with $runAttemptCount attempts")
+                    "KeyOneTime Executing: Failure",
+                    "KeyOneTime failed with $runAttemptCount attempts"
+                )
 
                 return Result.failure()
             } else {
+                Timber.d(e, "$id: Retrying.")
                 result = Result.retry()
             }
         }
 
         BackgroundWorkHelper.sendDebugNotification(
-            "KeyOneTime Executing: End", "KeyOneTime result: $result ")
+            "KeyOneTime Executing: End", "KeyOneTime result: $result "
+        )
 
+        Timber.d("$id: doWork() finished with %s", result)
         return result
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalPeriodicWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalPeriodicWorker.kt
index 79f091610676c9184dfef85882a5dfa83e972eb2..f7baa0f0855e09a3fef92a67d03b125b25452a42 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalPeriodicWorker.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalPeriodicWorker.kt
@@ -15,10 +15,6 @@ import timber.log.Timber
 class DiagnosisKeyRetrievalPeriodicWorker(val context: Context, workerParams: WorkerParameters) :
     CoroutineWorker(context, workerParams) {
 
-    companion object {
-        private val TAG: String? = DiagnosisKeyRetrievalPeriodicWorker::class.simpleName
-    }
-
     /**
      * Work execution
      *
@@ -28,28 +24,40 @@ class DiagnosisKeyRetrievalPeriodicWorker(val context: Context, workerParams: Wo
      * @see BackgroundWorkScheduler.scheduleDiagnosisKeyOneTimeWork()
      */
     override suspend fun doWork(): Result {
-        Timber.d("Background job started. Run attempt: $runAttemptCount")
+        Timber.d("$id: doWork() started. Run attempt: $runAttemptCount")
+
         BackgroundWorkHelper.sendDebugNotification(
-            "KeyPeriodic Executing: Start", "KeyPeriodic started. Run attempt: $runAttemptCount ")
+            "KeyPeriodic Executing: Start", "KeyPeriodic started. Run attempt: $runAttemptCount"
+        )
 
         var result = Result.success()
         try {
             BackgroundWorkScheduler.scheduleDiagnosisKeyOneTimeWork()
         } catch (e: Exception) {
+            Timber.w(
+                e, "$id: Error during BackgroundWorkScheduler.scheduleDiagnosisKeyOneTimeWork()."
+            )
+
             if (runAttemptCount > BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD) {
+                Timber.w(e, "$id: Retry attempts exceeded.")
 
                 BackgroundWorkHelper.sendDebugNotification(
-                    "KeyPeriodic Executing: Failure", "KeyPeriodic failed with $runAttemptCount attempts")
+                    "KeyPeriodic Executing: Failure",
+                    "KeyPeriodic failed with $runAttemptCount attempts"
+                )
 
                 return Result.failure()
             } else {
+                Timber.d(e, "$id: Retrying.")
                 result = Result.retry()
             }
         }
 
         BackgroundWorkHelper.sendDebugNotification(
-            "KeyPeriodic Executing: End", "KeyPeriodic result: $result ")
+            "KeyPeriodic Executing: End", "KeyPeriodic result: $result "
+        )
 
+        Timber.d("$id: doWork() finished with %s", result)
         return result
     }
 }
diff --git a/Corona-Warn-App/src/main/res/color/calendar_header.xml b/Corona-Warn-App/src/main/res/color/calendar_header.xml
new file mode 100644
index 0000000000000000000000000000000000000000..727593c505031885cbff514ce8ff43b1c55a430a
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/color/calendar_header.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true" android:color="@color/colorTextEmphasizedButton"/>
+    <item android:color="@color/colorTextPrimary1"/>
+</selector>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_header_background.xml b/Corona-Warn-App/src/main/res/drawable/calendar_header_background.xml
new file mode 100644
index 0000000000000000000000000000000000000000..50e670c9803c7983d2edb9f1a72d94970c76ad7d
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/calendar_header_background.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/calendar_header_background_focus_on" android:state_selected="true" />
+    <item android:drawable="@drawable/calendar_header_background_focus_off" />
+</selector>
diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_off.xml b/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_off.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c147a5441c7c653875066a2975624234f89f59c1
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_off.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners
+        android:radius="@dimen/calendar_header_initial_radius"
+        android:bottomLeftRadius="@dimen/calendar_header_bottom_radius"
+        android:bottomRightRadius="@dimen/calendar_header_bottom_radius"
+        android:topLeftRadius="@dimen/calendar_header_top_radius"
+        android:topRightRadius="@dimen/calendar_header_top_radius" />
+    <solid android:color="@color/colorSurface2" />
+</shape>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_on.xml b/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_on.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9eebae7774300955c275ad819b2f61d40c548160
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_on.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners
+        android:radius="@dimen/calendar_header_initial_radius"
+        android:bottomLeftRadius="@dimen/calendar_header_bottom_radius"
+        android:bottomRightRadius="@dimen/calendar_header_bottom_radius"
+        android:topLeftRadius="@dimen/calendar_header_top_radius"
+        android:topRightRadius="@dimen/calendar_header_top_radius" />
+    <solid android:color="@color/colorCalendarLayoutFocusOn" />
+</shape>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_layout_background.xml b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background.xml
new file mode 100644
index 0000000000000000000000000000000000000000..806443454d9218c4a8b8634703edd42d45767652
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/calendar_layout_background_focus_on" android:state_selected="true" />
+    <item android:drawable="@drawable/calendar_layout_background_focus_off" />
+</selector>
diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_off.xml b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_off.xml
new file mode 100644
index 0000000000000000000000000000000000000000..10c1626fc85807bc3080af27a816cfbf9424fb67
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_off.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners android:radius="@dimen/radius_card" />
+    <stroke
+        android:width="@dimen/calendar_layout_stroke"
+        android:color="@color/colorSurface2" />
+</shape>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_on.xml b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_on.xml
new file mode 100644
index 0000000000000000000000000000000000000000..39ecfa7c0532579cd21e7f158b1693e377ef0c57
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_on.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners android:radius="@dimen/radius_card" />
+    <stroke
+        android:width="@dimen/calendar_layout_stroke"
+        android:color="@color/colorCalendarLayoutFocusOn" />
+</shape>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_selected_day_back.xml b/Corona-Warn-App/src/main/res/drawable/calendar_selected_day_back.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a76b8d017908dd7a02e2c7fcb3dce47f87d76ec7
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/calendar_selected_day_back.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="@color/colorCalendarSelectedDayBackground" />
+</shape>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_today_back.xml b/Corona-Warn-App/src/main/res/drawable/calendar_today_back.xml
new file mode 100644
index 0000000000000000000000000000000000000000..874c81cd881e26340720b8352be966257dbda8f8
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/calendar_today_back.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="@android:color/transparent" />
+    <stroke
+        android:width="1dp"
+        android:color="@color/colorCalendarTodayBorder" />
+</shape>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_calendar.xml b/Corona-Warn-App/src/main/res/layout/fragment_calendar.xml
new file mode 100644
index 0000000000000000000000000000000000000000..73c16a8413200ca445513e7feb48b8b30d9c48e8
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/layout/fragment_calendar.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/calendar_layout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/calendar_layout_background"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/calendar_header"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/calendar_header_height"
+        android:padding="@dimen/spacing_normal"
+        android:textSize="@dimen/font_title"
+        android:textColor="@color/calendar_header"
+        android:text="@string/symptoms_calendar_exact_date_button"
+        android:background="@drawable/calendar_header_background"
+        android:focusable="true"
+        android:focusableInTouchMode="true" />
+
+    <TextView
+        android:id="@+id/calendar_month"
+        style="@style/calendarMonthText"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_small"
+        android:layout_marginBottom="@dimen/spacing_small"
+        android:focusable="true"
+        android:focusableInTouchMode="true" />
+
+    <LinearLayout
+        android:id="@+id/calendar_day_legend"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/spacing_small"
+        android:layout_marginEnd="@dimen/spacing_small"
+        android:gravity="center"
+        android:orientation="horizontal" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/calendar_recycler_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginStart="@dimen/spacing_small"
+        android:layout_marginEnd="@dimen/spacing_small"
+        android:layout_marginBottom="@dimen/spacing_small"
+        android:importantForAccessibility="no"
+        android:scrollbars="vertical" />
+
+</LinearLayout>
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_calendar_day.xml b/Corona-Warn-App/src/main/res/layout/fragment_calendar_day.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8daa8976ed087640d62f8eba9277ae3b3f084feb
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/layout/fragment_calendar_day.xml
@@ -0,0 +1,15 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/calendar_day_size"
+    android:layout_height="@dimen/calendar_day_size"
+    android:layout_marginTop="@dimen/calendar_day_spacing"
+    android:layout_marginBottom="@dimen/calendar_day_spacing" >
+
+    <TextView
+        android:id="@+id/dayText"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:textColor="@color/colorTextPrimary1"
+        android:textSize="@dimen/font_button" />
+
+</LinearLayout>
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_calendar.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_calendar.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eb19ee84f777439eb95616fd29cd758dfc369bc5
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_calendar.xml
@@ -0,0 +1,116 @@
+<?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">
+
+    <data>
+
+        <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" />
+
+        <import type="de.rki.coronawarnapp.submission.Symptoms.StartOf" />
+
+        <variable
+            name="submissionViewModel"
+            type="de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel" />
+
+    </data>
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:fillViewport="true"
+            android:focusable="true"
+            tools:context=".ui.submission.fragment.SubmissionSymptomCalendarFragment">
+
+            <include
+                android:id="@+id/submission_symptom_calendar_header"
+                layout="@layout/include_header"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                app:icon="@{@drawable/ic_back}"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                app:title="@{@string/submission_symptom_calendar_title}" />
+
+            <TextView
+                android:id="@+id/submission_symptom_calendar_headline"
+                style="@style/headline5"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_normal"
+                android:accessibilityHeading="true"
+                android:text="@string/submission_symptom_calendar_headline"
+                app:layout_constraintEnd_toEndOf="@id/guideline_end"
+                app:layout_constraintStart_toStartOf="@id/guideline_start"
+                app:layout_constraintTop_toBottomOf="@+id/submission_symptom_calendar_header" />
+
+            <TextView
+                android:id="@+id/submission_symptom_calendar_body"
+                style="@style/body1"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_normal"
+                android:accessibilityHeading="true"
+                android:text="@string/submission_symptom_calendar_body"
+                app:layout_constraintEnd_toEndOf="@id/guideline_end"
+                app:layout_constraintStart_toStartOf="@id/guideline_start"
+                app:layout_constraintTop_toBottomOf="@+id/submission_symptom_calendar_headline" />
+
+            <de.rki.coronawarnapp.ui.calendar.CalendarView
+                android:id="@+id/symptom_calendar_container"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_normal"
+                app:layout_constraintEnd_toEndOf="@id/guideline_end"
+                app:layout_constraintStart_toStartOf="@id/guideline_start"
+                app:layout_constraintTop_toBottomOf="@+id/submission_symptom_calendar_body"/>
+
+            <include
+                android:id="@+id/symptom_calendar_choice_selection"
+                layout="@layout/include_submission_symptom_length_selection"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:focusable="true"
+                app:layout_constraintEnd_toEndOf="@id/guideline_end"
+                app:layout_constraintStart_toStartOf="@id/guideline_start"
+                app:layout_constraintTop_toBottomOf="@+id/symptom_calendar_container" />
+
+            <Button
+                android:id="@+id/symptom_button_next"
+                style="@style/buttonPrimary"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="@dimen/spacing_small"
+                android:layout_marginTop="@dimen/spacing_small"
+                android:text="@string/submission_symptom_further_button"
+                app:layout_constraintBottom_toTopOf="@id/guideline_bottom"
+                app:layout_constraintEnd_toEndOf="@id/guideline_end"
+                app:layout_constraintStart_toStartOf="@id/guideline_start"
+                app:layout_constraintTop_toBottomOf="@+id/symptom_calendar_choice_selection"/>
+
+            <include layout="@layout/merge_guidelines_side" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/guideline_top"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                app:layout_constraintGuide_begin="@dimen/guideline_top" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/guideline_bottom"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                app:layout_constraintGuide_end="@dimen/spacing_small" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+    </ScrollView>
+
+</layout>
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_intro.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_intro.xml
new file mode 100644
index 0000000000000000000000000000000000000000..09df7481b0c54f8241fadfaabc7bd95ccbb3e865
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_intro.xml
@@ -0,0 +1,105 @@
+<?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">
+
+    <data>
+
+        <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" />
+
+        <variable
+            name="submissionViewModel"
+            type="de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel" />
+
+    </data>
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/submission_symptom_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:fillViewport="true"
+            android:focusable="true"
+            tools:context=".ui.submission.fragment.SubmissionIntroFragment">
+
+            <include
+                android:id="@+id/submission_symptom_header"
+                layout="@layout/include_header"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                app:icon="@{@drawable/ic_back}"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                app:title="@{@string/submission_symptom_title}" />
+
+            <TextView
+                android:id="@+id/submission_symptom_initial_headline"
+                style="@style/headline5"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_normal"
+                android:accessibilityHeading="true"
+                android:text="@string/submission_symptom_initial_headline"
+                app:layout_constraintEnd_toEndOf="@id/guideline_end"
+                app:layout_constraintStart_toStartOf="@id/guideline_start"
+                app:layout_constraintTop_toBottomOf="@+id/submission_symptom_header" />
+
+            <de.rki.coronawarnapp.ui.view.BulletPointList
+                android:id="@+id/further_info_text"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:focusable="true"
+                android:layout_marginTop="@dimen/spacing_normal"
+                app:entries="@array/submission_symptom_symptom_bullets"
+                app:layout_constraintEnd_toEndOf="@id/guideline_end"
+                app:layout_constraintStart_toStartOf="@id/guideline_start"
+                app:layout_constraintTop_toBottomOf="@+id/submission_symptom_initial_headline" />
+
+            <include
+                android:id="@+id/symptom_choice_selection"
+                layout="@layout/include_submission_target_selection"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:focusable="true"
+                app:layout_constraintEnd_toEndOf="@id/guideline_end"
+                app:layout_constraintStart_toStartOf="@id/guideline_start"
+                app:layout_constraintTop_toBottomOf="@+id/further_info_text" />
+
+            <Button
+                android:id="@+id/symptom_button_next"
+                style="@style/buttonPrimary"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="@dimen/spacing_small"
+                android:layout_marginTop="@dimen/spacing_small"
+                android:text="@string/submission_symptom_further_button"
+                app:layout_constraintBottom_toTopOf="@id/guideline_bottom"
+                app:layout_constraintEnd_toEndOf="@id/guideline_end"
+                app:layout_constraintStart_toStartOf="@id/guideline_start"
+                app:layout_constraintTop_toBottomOf="@+id/symptom_choice_selection"/>
+
+            <include layout="@layout/merge_guidelines_side" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/guideline_top"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                app:layout_constraintGuide_begin="@dimen/guideline_top" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/guideline_bottom"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                app:layout_constraintGuide_end="@dimen/spacing_small" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+    </ScrollView>
+
+</layout>
diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_symptom_length_selection.xml b/Corona-Warn-App/src/main/res/layout/include_submission_symptom_length_selection.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d95f4ed9f6f4201980e57caa01ec1e06c2d1ff6e
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/layout/include_submission_symptom_length_selection.xml
@@ -0,0 +1,73 @@
+<?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">
+
+    <data>
+
+        <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" />
+
+        <import type="de.rki.coronawarnapp.submission.Symptoms.StartOf" />
+
+        <variable
+            name="submissionViewModel"
+            type="de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel" />
+
+    </data>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/target_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:focusable="true">
+
+        <Button
+            android:id="@+id/calendar_button_seven_days"
+            style="@style/selectionButton"
+            android:enabled="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/spacing_small"
+            android:text="@{@string/submission_symptom_less_seven}"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            />
+
+        <Button
+            android:id="@+id/calendar_button_one_two_weeks"
+            style="@style/selectionButton"
+            android:enabled="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/spacing_small"
+            android:text="@{@string/submission_symptom_one_two_weeks}"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/calendar_button_seven_days" />
+
+        <Button
+            android:id="@+id/calendar_button_more_than_two_weeks"
+            style="@style/selectionButton"
+            android:enabled="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/spacing_small"
+            android:text="@{@string/submission_symptom_more_two_weeks}"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/calendar_button_one_two_weeks" />
+
+        <Button
+            android:id="@+id/target_button_verify"
+            style="@style/selectionButton"
+            android:enabled="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/spacing_small"
+            android:text="@{@string/submission_symptom_verify}"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/calendar_button_more_than_two_weeks" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_tan.xml b/Corona-Warn-App/src/main/res/layout/include_submission_tan.xml
index aeb76381c1855966593e8a09f145aeb2aaef3e82..795e2414432a623b48ec39c9887c2a07db4e690d 100644
--- a/Corona-Warn-App/src/main/res/layout/include_submission_tan.xml
+++ b/Corona-Warn-App/src/main/res/layout/include_submission_tan.xml
@@ -46,13 +46,13 @@
                 app:layout_constraintTop_toBottomOf="@+id/submission_tan_body" />
 
             <TextView
-                android:id="@+id/submission_tan_character_error"
+                android:id="@+id/submission_tan_error"
                 style="@style/subtitle"
                 android:layout_width="@dimen/match_constraint"
                 android:layout_height="wrap_content"
                 android:layout_marginTop="@dimen/spacing_small"
                 android:accessibilityLiveRegion="assertive"
-                android:text="@string/submission_tan_character_error"
+                android:text="@string/submission_tan_error"
                 android:textColor="@color/colorTextSemanticRed"
                 android:visibility="gone"
                 app:layout_constraintEnd_toStartOf="@+id/guideline_end"
@@ -61,18 +61,18 @@
                 tools:visibility="visible" />
 
             <TextView
-                android:id="@+id/submission_tan_error"
+                android:id="@+id/submission_tan_character_error"
                 style="@style/subtitle"
                 android:layout_width="@dimen/match_constraint"
                 android:layout_height="wrap_content"
                 android:layout_marginTop="@dimen/spacing_small"
                 android:accessibilityLiveRegion="assertive"
-                android:text="@string/submission_tan_error"
+                android:text="@string/submission_tan_character_error"
                 android:textColor="@color/colorTextSemanticRed"
                 android:visibility="gone"
                 app:layout_constraintEnd_toStartOf="@+id/guideline_end"
                 app:layout_constraintStart_toStartOf="@+id/guideline_start"
-                app:layout_constraintTop_toBottomOf="@id/submission_tan_character_error"
+                app:layout_constraintTop_toBottomOf="@id/submission_tan_error"
                 tools:visibility="visible" />
 
             <include layout="@layout/merge_guidelines_side" />
diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_target_selection.xml b/Corona-Warn-App/src/main/res/layout/include_submission_target_selection.xml
new file mode 100644
index 0000000000000000000000000000000000000000..885289e1986f84037042802f1800f3aa632997b4
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/layout/include_submission_target_selection.xml
@@ -0,0 +1,48 @@
+<?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">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/target_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:focusable="true">
+
+        <Button
+            android:id="@+id/target_button_apply"
+            style="@style/selectionButton"
+            android:enabled="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/spacing_small"
+            android:text="@{@string/submission_symptom_positive_button}"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"  />
+
+        <Button
+            android:id="@+id/target_button_reject"
+            style="@style/selectionButton"
+            android:enabled="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/spacing_small"
+            android:text="@{@string/submission_symptom_negative_button}"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/target_button_apply" />
+
+        <Button
+            android:id="@+id/target_button_verify"
+            style="@style/selectionButton"
+            android:enabled="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/spacing_small"
+            android:text="@{@string/submission_symptom_no_information_button}"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/target_button_reject" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>
\ No newline at end of file
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 61b00b60017520df908020800160fe9c24967683..07332d9b90e4451e047f039e29d0dad243c77db2 100644
--- a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml
+++ b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml
@@ -26,9 +26,6 @@
         <action
             android:id="@+id/action_mainFragment_to_mainSharingFragment"
             app:destination="@id/mainSharingFragment" />
-        <action
-            android:id="@+id/action_mainFragment_to_submissionIntroFragment"
-            app:destination="@id/submissionIntroFragment" />
         <action
             android:id="@+id/action_mainFragment_to_submissionResultFragment"
             app:destination="@id/submissionResultFragment" />
@@ -38,6 +35,9 @@
         <action
             android:id="@+id/action_mainFragment_to_mainOverviewFragment"
             app:destination="@id/mainOverviewFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_submissionIntroFragment"
+            app:destination="@id/submissionIntroFragment" />
     </fragment>
 
     <fragment
@@ -205,6 +205,12 @@
             app:destination="@id/submissionDoneFragment"
             app:popUpTo="@id/submissionDoneFragment"
             app:popUpToInclusive="true" />
+        <action
+            android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionSymptomCalendarFragment"
+            app:destination="@id/submissionSymptomCalendarFragment" />
+        <action
+            android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionSymptomIntroductionFragment"
+            app:destination="@id/submissionSymptomIntroductionFragment" />
     </fragment>
     <fragment
         android:id="@+id/submissionResultFragment"
@@ -221,8 +227,8 @@
             app:popUpTo="@id/mainFragment"
             app:popUpToInclusive="true" />
         <action
-            android:id="@+id/action_submissionResultFragment_to_submissionResultPositiveOtherWarningFragment"
-            app:destination="@id/submissionResultPositiveOtherWarningFragment" />
+            android:id="@+id/action_submissionResultFragment_to_submissionSymptomIntroductionFragment"
+            app:destination="@id/submissionSymptomIntroductionFragment" />
     </fragment>
 
     <fragment
@@ -230,6 +236,11 @@
         android:name="de.rki.coronawarnapp.ui.submission.fragment.SubmissionTanFragment"
         android:label="fragment_submission_tan"
         tools:layout="@layout/fragment_submission_tan">
+        <action
+            android:id="@+id/action_submissionTanFragment_to_submissionDispatcherFragment"
+            app:destination="@id/submissionDispatcherFragment"
+            app:popUpTo="@id/submissionDispatcherFragment"
+            app:popUpToInclusive="true" />
         <action
             android:id="@+id/action_submissionTanFragment_to_submissionResultFragment"
             app:destination="@id/submissionResultFragment"
@@ -300,4 +311,29 @@
             android:id="@+id/action_submissionContactFragment_to_submissionTanFragment"
             app:destination="@id/submissionTanFragment" />
     </fragment>
+    <fragment
+        android:id="@+id/submissionSymptomIntroductionFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionSymptomIntroductionFragment"
+        android:label="SubmissionSymptomIntroductionFragment" >
+        <action
+            android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionSymptomCalendarFragment"
+            app:destination="@id/submissionSymptomCalendarFragment" />
+        <action
+            android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionResultFragment"
+            app:destination="@id/submissionResultFragment" />
+        <action
+            android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionResultPositiveOtherWarningFragment"
+            app:destination="@id/submissionResultPositiveOtherWarningFragment" />
+    </fragment>
+    <fragment
+        android:id="@+id/submissionSymptomCalendarFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionSymptomCalendarFragment"
+        android:label="SubmissionSymptomCalendarFragment" >
+        <action
+            android:id="@+id/action_submissionCalendarFragment_to_submissionSymptomIntroductionFragment"
+            app:destination="@id/submissionSymptomIntroductionFragment" />
+        <action
+            android:id="@+id/action_submissionSymptomCalendarFragment_to_submissionResultPositiveOtherWarningFragment"
+            app:destination="@id/submissionResultPositiveOtherWarningFragment" />
+    </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 0e77b972ba7c4a35b683dead150fcc14cab0443b..b34a979f3b9cde949f588bc8b5e3a23f6232b326 100644
--- a/Corona-Warn-App/src/main/res/values-bg/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/strings.xml
@@ -425,7 +425,7 @@
     <!-- XHED: onboarding(tracing) - headline for consent information -->
     <string name="onboarding_tracing_headline_consent">"Поверителност"</string>
     <!-- YTXT: onboarding(tracing) - body for consent information -->
-    <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping the “Enable” button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the COVID-19 Exposure Logging functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyzes this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Information”."</string>
+    <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping the “Enable” button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the \"Exposure Notifications\" functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyzes this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Information”."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_button_next">"Активиране на регистрирането на излагания на риск"</string>
     <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined -->
@@ -495,7 +495,7 @@
     <string name="sixteen_title_text">"Минимална възраст: 16 год."</string>
 
     <!-- XACT: onboarding(sixteen) title -->
-    <string name="sixteen_description_text">"Това приложение е предназначено за лица с постоянно пребиваване в Германия, които имат навършени 16 години."</string>
+    <string name="sixteen_description_text">"Употребата на това приложение е предназначено за лица, навършили 16 години, с постоянно пребиваване в Германия."</string>
 
 
     <!-- ####################################
@@ -541,7 +541,9 @@
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
     <string name="settings_tracing_status_location_headline">"Разрешаване на достъп до данните за местоположение"</string>
     <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled -->
-    <string name="settings_tracing_status_location_body">"Не може да бъде осъществен достъп до Вашето местоположение. За да използвате Bluetooth, Google и/или Android изискват от Вас да предоставите достъп до местоположението на устройството си."</string>
+    <string name="settings_tracing_status_location_body">"Активирайте услугите за споделяне на местоположение. Bluetooth с нисък разход на енергия изисква активирани услуги за споделяне на местоположението, за да може да изчисли физическото разстояние, но в момента няма достъп до Вашето местоположение. Повече информация може да намерите на страницата “Често задавани въпроси”."</string>
+    <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL -->
+    <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string>
     <!-- XBUT: settings(tracing) - go to operating system settings button on card - location -->
     <string name="settings_tracing_status_location_button">"Към настройките за устройството"</string>
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
@@ -720,7 +722,7 @@
     <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German -->
     <string name="information_legal_subtitle_contact_form_non_en_de">"Contact Form in "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"English"</a>" or "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"German"</a></string>
     <!-- XHED: Headline for legal information page, tax section -->
-    <string name="information_legal_headline_taxid">"Идентификационен номер за ДДС"</string>
+    <string name="information_legal_headline_taxid">"Идентификационен номер \nза ДДС"</string>
     <!-- YTXT: subtitle for legal information page, tax section -->
     <string name="information_legal_subtitle_taxid">"DE 165 893 430"</string>
     <!-- XACT: describes illustration -->
@@ -740,10 +742,14 @@
     <!-- XBUT: Positive button for generic web request error -->
     <string name="submission_error_dialog_web_generic_error_button_positive">"Назад"</string>
 
-    <!-- XHED: Dialog title for already paired test error -->
+    <!-- XHED: Dialog title for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_title">"Невалиден QR код"</string>
-    <!-- XMSG: Dialog body for already paired test error -->
+    <!-- XMSG: Dialog body for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_body">"QR кодът е невалиден или вече е регистриран на друг смартфон. Ще получите резултата си от център за тестване или лаборатория, независимо от валидността на QR кода. Ако Ви бъде поставена диагноза COVID-19, службата за обществено осигуряване ще Ви уведоми за това."</string>
+    <!-- XHED: Dialog title for already paired test error: tan -->
+    <string name="submission_error_dialog_web_test_paired_title_tan">"ТАН кодът е невалиден"</string>
+    <!-- XMSG: Dialog body for already paired test via tan - error: tan -->
+    <string name="submission_error_dialog_web_test_paired_body_tan">"ТАН кодът е невалиден или вече е използван. За повече информация се обадете на номера, посочен под “Заявяване на ТАН код”."</string>
     <!-- XBUT: Positive button for already paired test error -->
     <string name="submission_error_dialog_web_test_paired_button_positive">"Назад"</string>
 
@@ -768,6 +774,15 @@
     <!-- XBUT: Positive button for submission tan redeemed -->
     <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string>
 
+    <!-- XHED: Dialog title for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_title">"Желаете ли отмяна?"</string>
+    <!-- XMSG: Dialog body for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_body">"Въведените от Вас данни няма да бъдат запазени."</string>
+    <!-- XBUT: Positive button for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_button_positive">"Да"</string>
+    <!-- XBUT: Negative button for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_button_negative">"Не"</string>
+
     <!-- Permission Rationale Dialog -->
     <!-- XHED: Dialog headline QR Scan permission rationale  -->
     <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Изисква се разрешение за използване на камерата"</string>
@@ -869,9 +884,9 @@
     <!-- XACT: Submission Tan page title -->
     <string name="submission_tan_accessibility_title">"Въвеждане на ТАН код"</string>
     <!-- YTXT: Error text for the tan submission page -->
-    <string name="submission_tan_error">"Невалиден ТАН код. Проверете въведените данни."</string>
+    <string name="submission_tan_error">"Невалиден ТАН код. Моля, проверете въведените данни!"</string>
     <!-- YTXT: Error text for the tan submission page (wrong characters) -->
-    <string name="submission_tan_character_error">"Въведете данни са невалидни. Моля, проверете."</string>
+    <string name="submission_tan_character_error">"Въвели сте невалидни символи. Моля, проверете данните!"</string>
 
     <!-- Submission Intro -->
     <!-- XHED: Page title for menu at the start of the submission process  -->
@@ -931,9 +946,9 @@
     <!-- XHED: Title for the privacy card-->
     <string name="submission_positive_other_warning_privacy_title">"Поверителност"</string>
     <!-- YTXT: Body text for the privacy card-->
-    <string name="submission_positive_other_warning_privacy_body">"By tapping on “Accept”, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy Information”."</string>
+    <string name="submission_positive_other_warning_privacy_body">"By tapping “Accept”, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy”."</string>
     <!-- XBUT: other warning continue button -->
-    <string name="submission_positive_other_warning_button">"Напред"</string>
+    <string name="submission_positive_other_warning_button">"Приемам"</string>
     <!-- XACT: other warning - illustration description, explanation image -->
     <string name="submission_positive_other_illustration_description">"Устройство предава на системата информация за положителен резултат от тест."</string>
 
@@ -961,7 +976,33 @@
     <!-- XBUT: submission finished button -->
     <string name="submission_done_button_done">"Готово"</string>
     <!-- XACT: submission finished - illustration description, explanation image -->
-    <string name="submission_done_illustration_description">"Всички в групата аплодират, защото някой е споделил резултата от своя тест."</string>
+    <string name="submission_done_illustration_description">"Имали ли сте един или повече от следните симптоми през последните няколко дни?"</string>
+
+    <!-- Submission Symptoms -->
+    <!-- XHED: Page title for symptom screens -->
+    <string name="submission_symptom_title">"Симптоми"</string>
+    <!-- YTXT: headline text for initial symptom screen -->
+    <string name="submission_symptom_initial_headline">"Имали ли сте един или повече от следните симптоми през последните няколко дни?"</string>
+    <!-- YTXT: Bullet points for symptoms -->
+    <string-array name="submission_symptom_symptom_bullets">
+        <item>"Повишена температура или треска"</item>
+        <item>"Затруднено дишане"</item>
+        <item>"Загуба на обоняние/вкус"</item>
+        <item>"Кашлица"</item>
+        <item>"Хрема"</item>
+        <item>"Болки в гърлото"</item>
+        <item>"Главоболие и болки в крайниците"</item>
+        <item>"Обща слабост и умора"</item>
+    </string-array>
+    <!-- XBUT: symptom initial screen yes button -->
+    <string name="submission_symptom_positive_button">"Да"</string>
+    <!-- XBUT:  symptom initial screen no button -->
+    <string name="submission_symptom_negative_button">"Не"</string>
+    <!-- XBUT:  symptom initial screen no information button -->
+    <string name="submission_symptom_no_information_button">"Без коментар"</string>
+    <!-- XBUT:  symptom initial screen continue button -->
+    <string name="submission_symptom_further_button">"Напред"</string>
+
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
@@ -992,6 +1033,22 @@
     <!-- XACT: Content Description for submission contact step 2 -->
     <string name="submission_contact_step_2_content">"Във втората стъпка регистрирате теста си, като въвеждате ТАН кода в приложението."</string>
 
+    <!-- Submission Symptom Calendar -->
+    <!-- XHED: Page title for calendar page in submission symptom flow -->
+    <string name="submission_symptom_calendar_title">"Начало на симптомите"</string>
+    <!-- XHED: Page headline for calendar page in symptom submission flow -->
+    <string name="submission_symptom_calendar_headline">"Кога се появиха за първи път тези симптоми? "</string>
+    <!-- YTXT: Body text for calendar page in symptom submission flow-->
+    <string name="submission_symptom_calendar_body">"Изберете точната дата от календара или, ако не можете да си я спомните, някоя от другите опции."</string>
+    <!-- XBUT: symptom calendar screen less than 7 days button -->
+    <string name="submission_symptom_less_seven">"През последните 7 дни"</string>
+    <!-- XBUT: symptom calendar screen 1-2 weeks button -->
+    <string name="submission_symptom_one_two_weeks">"Преди 1-2 седмици"</string>
+    <!-- XBUT: symptom calendar screen more than 2 weeks button -->
+    <string name="submission_symptom_more_two_weeks">"Преди повече от 2 седмици"</string>
+    <!-- XBUT: symptom calendar screen verify button -->
+    <string name="submission_symptom_verify">"Без коментар"</string>
+
     <!-- Submission Status Card -->
     <!-- XHED: Page title for the various submission status: fetching -->
     <string name="submission_status_card_title_fetching">"Извършва се извличане на данни"</string>
@@ -1055,6 +1112,9 @@
         <item>"Не ходете на работа, ако не се чувствате добре, за да не излагате други хора на риск. Ако симптомите Ви се влошат, може да се наложи да направите нов тест за SARS-CoV-2."</item>
     </string-array>
 
+    <!-- XBUT Symptoms exact date button -->
+    <string name="symptoms_calendar_exact_date_button">"Точна дата"</string>
+
     <!-- ####################################
           Button Tooltips for Accessibility
     ###################################### -->
@@ -1083,7 +1143,7 @@
     <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action -->
     <string name="errors_external_action">"На може да извършите това действие. Моля, обадете се на горещата линия."</string>
     <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update -->
-    <string name="errors_google_update_needed">"Вашето Corona-Warn-App приложение е инсталирано правилно, но услугата “известия за излагания на риск от заразяване с COVID-19” не се предлага за операционната система на Вашия смартфон. Това означава, че не можете да използвате приложението Corona-Warn-App. Повече информация може да намерите в страницата „ЧЗВ“ на адрес: https://www.coronawarn.app/en/faq/"</string>
+    <string name="errors_google_update_needed">"Вашето приложение Corona-Warn-App е инсталирано правилно, но „Системата за известяване при излагания на риск от заразяване с COVID-19” не се предлага за операционната система на Вашия смартфон. Това означава, че не можете да използвате приложението Corona-Warn-App. Повече информация може да намерите в страницата „ЧЗВ“ на адрес: https://www.coronawarn.app/en/faq/"</string>
     <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day -->
     <string name="errors_google_api_error">"Приложението Corona-Warn-App работи правилно, но не можем да актуализираме Вашия статус на риск. Регистрирането на излагания на риск все още е активно и функционира правилно. За повече информация посетете страницата „ЧЗВ“ на адрес: https://www.coronawarn.app/en/faq/"</string>
 
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 025aae05313214dc9e21d1be6f25c8ad75feb407..a2457e0b1def1e0499fa0260762f0aea10c30c75 100644
--- a/Corona-Warn-App/src/main/res/values-de/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/strings.xml
@@ -345,7 +345,7 @@
     <!-- YTXT: risk details - low risk explanation text -->
     <string name="risk_details_information_body_low_risk">"Sie haben ein niedriges Infektionsrisiko, da keine Begegnung mit nachweislich Corona-positiv getesteten Personen aufgezeichnet wurde oder sich Ihre Begegnung auf kurze Zeit und einen größeren Abstand beschränkt hat."</string>
     <!-- YTXT: risk details - low risk explanation text with encounter with low risk -->
-    <string name="risk_details_information_body_low_risk_with_encounter">"Das Infektionsrisiko wird anhand der Daten der Risiko-Ermittlung unter Berücksichtigung des Abstands und der Dauer von Begegnungen mit nachweislich Corona-positiv getesteten Personen sowie deren vermutlicher Infektiosität lokal auf Ihrem Endgerät berechnet. Ihr Infektionsrisiko ist für niemanden einsehbar und wird nicht weitergegeben."</string>
+    <string name="risk_details_information_body_low_risk_with_encounter">"Das Infektionsrisiko wird anhand der Daten der Risiko-Ermittlung unter Berücksichtigung des Abstands und der Dauer von Begegnungen mit nachweislich Corona-positiv getesteten Personen sowie deren vermutlicher Infektiosität lokal auf Ihrem Smartphone berechnet. Ihr Infektionsrisiko ist für niemanden einsehbar und wird nicht weitergegeben."</string>
     <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact -->
     <plurals name="risk_details_information_body_increased_risk">
         <item quantity="one">"Sie haben ein erhöhtes Infektionsrisiko, da Sie zuletzt vor %1$s Tag mindestens einer nachweislich Corona-positiv getesteten Person über einen längeren Zeitraum und mit einem geringen Abstand begegnet sind."</item>
@@ -407,7 +407,7 @@
     <string name="onboarding_privacy_headline">"Datenschutz"</string>
 
     <!-- XACT: onboarding(privacy) - illustraction description, header image -->
-    <string name="onboarding_privacy_illustration_description">"Eine Frau mit einem Handy benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten."</string>
+    <string name="onboarding_privacy_illustration_description">"Eine Frau mit einem Smartphone benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten."</string>
     <!-- XACT: Onboarding (tracing) page title -->
     <string name="onboarding_tracing_accessibility_title">"Einführung Seite 3 von 5: Wie Sie die Risiko Ermittlung ermöglichen"</string>
     <!-- XHED: onboarding(tracing) - how to enable tracing -->
@@ -415,7 +415,7 @@
     <!-- XHED: onboarding(tracing) - two/three line headline under an illustration -->
     <string name="onboarding_tracing_subtitle">"Um zu erkennen, ob für Sie ein Infektionsrisiko vorliegt, müssen Sie die Risiko-Ermittlung aktivieren."</string>
     <!-- YTXT: onboarding(tracing) - explain tracing -->
-    <string name="onboarding_tracing_body">"Die Risiko-Ermittlung funktioniert, indem Ihr Handy per Bluetooth verschlüsselte Zufallscodes anderer Nutzerinnen und Nutzer empfängt und Ihren eigenen Zufallscode an deren Smartphones weitergibt. Die Funktion lässt sich jederzeit wieder deaktivieren."</string>
+    <string name="onboarding_tracing_body">"Die Risiko-Ermittlung funktioniert, indem Ihr Smartphone per Bluetooth verschlüsselte Zufallscodes anderer Nutzerinnen und Nutzer empfängt und Ihren eigenen Zufallscode an deren Smartphones weitergibt. Die Funktion lässt sich jederzeit wieder deaktivieren."</string>
     <!-- YTXT: onboarding(tracing) - explain tracing -->
     <string name="onboarding_tracing_body_emphasized">"Die verschlüsselten Zufallscodes geben nur Auskunft über das Datum, die Dauer und die anhand der Signalstärke berechnete Entfernung zu Ihren Mitmenschen. Persönliche Daten wie Name, Adresse oder Aufenthaltsort werden zu keiner Zeit erfasst. Konkrete Rückschlüsse auf Personen sind nicht möglich."</string>
     <!-- YTXT: onboarding(tracing) - easy language explain tracing link-->
@@ -521,7 +521,7 @@
     <!-- XTXT: settings(tracing) - shows status under header in home, inactive location -->
     <string name="settings_tracing_body_inactive_location">"Standortdienste deaktiviert"</string>
     <!-- YTXT: settings(tracing) - explains tracings -->
-    <string name="settings_tracing_body_text">"Um zu erkennen, ob für Sie ein Infektionsrisiko vorliegt, müssen Sie die Risiko-Ermittlung aktivieren. Die Risiko-Ermittlung funktioniert, indem Ihr Handy per Bluetooth verschlüsselte Zufallscodes anderer Nutzerinnen und Nutzer empfängt und Ihren eigenen Zufallscode an deren Smartphones weitergibt. Die Funktion lässt sich jederzeit wieder deaktivieren."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Die verschlüsselten Zufallscodes geben nur Auskunft über das Datum, die Dauer und die anhand der Signalstärke berechnete Entfernung zu Ihren Mitmenschen. Persönliche Daten wie Name, Adresse oder Aufenthaltsort werden zu keiner Zeit erfasst. Konkrete Rückschlüsse auf Personen sind nicht möglich."</string>
+    <string name="settings_tracing_body_text">"Um zu erkennen, ob für Sie ein Infektionsrisiko vorliegt, müssen Sie die Risiko-Ermittlung aktivieren. Die Risiko-Ermittlung funktioniert, indem Ihr Smartphone per Bluetooth verschlüsselte Zufallscodes anderer Nutzerinnen und Nutzer empfängt und Ihren eigenen Zufallscode an deren Smartphones weitergibt. Die Funktion lässt sich jederzeit wieder deaktivieren."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Die verschlüsselten Zufallscodes geben nur Auskunft über das Datum, die Dauer und die anhand der Signalstärke berechnete Entfernung zu Ihren Mitmenschen. Persönliche Daten wie Name, Adresse oder Aufenthaltsort werden zu keiner Zeit erfasst. Konkrete Rückschlüsse auf Personen sind nicht möglich."</string>
     <!-- XTXT: settings(tracing) - status next to switch under title -->
     <string name="settings_tracing_status_active">"Aktiv"</string>
     <!-- XTXT: settings(tracing) - status next to switch under title -->
@@ -662,7 +662,7 @@
     <!-- XHED: Page title for privacy information page, also menu item / button text -->
     <string name="information_privacy_title">"Datenschutz"</string>
     <!-- XACT: describes illustration -->
-    <string name="information_privacy_illustration_description">"Eine Frau mit einem Handy benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten."</string>
+    <string name="information_privacy_illustration_description">"Eine Frau mit einem Smartphone benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten."</string>
     <!-- XTXT: Path to the full blown privacy html, to translate it exchange "_de" to "_en" and provide the corresponding html file -->
     <string name="information_privacy_html_path">"privacy_de.html"</string>
     <!-- XHED: Page title for terms of use information page, also menu item / button text -->
@@ -749,7 +749,7 @@
     <!-- XHED: Dialog title for already paired test error: tan -->
     <string name="submission_error_dialog_web_test_paired_title_tan">"TAN ist ungültig"</string>
     <!-- XMSG: Dialog body for already paired test via tan - error: tan -->
-    <string name="submission_error_dialog_web_test_paired_body_tan">"Die TAN ist ungültig oder wurde bereits verwendet. Bitte rufen Sie die unter „TAN anfragen" angegebene Nummer an, um weitere Informationen zu erhalten."</string>
+    <string name="submission_error_dialog_web_test_paired_body_tan">"Die TAN ist ungültig oder wurde bereits verwendet. Bitte rufen Sie die unter „TAN anfragen“ angegebene Nummer an, um weitere Informationen zu erhalten."</string>
     <!-- XBUT: Positive button for already paired test error -->
     <string name="submission_error_dialog_web_test_paired_button_positive">"Zurück"</string>
 
@@ -884,9 +884,9 @@
     <!-- XACT: Submission Tan page title -->
     <string name="submission_tan_accessibility_title">"TAN-Eingabe"</string>
     <!-- YTXT: Error text for the tan submission page -->
-    <string name="submission_tan_error">"Ungültige TAN, bitte überprüfen Sie Ihre Eingabe."</string>
+    <string name="submission_tan_error">"Ungültige TAN. Bitte überprüfen Sie Ihre Eingabe."</string>
     <!-- YTXT: Error text for the tan submission page (wrong characters) -->
-    <string name="submission_tan_character_error">"Ungültige Eingabe, bitte überprüfen Sie das Zeichen."</string>
+    <string name="submission_tan_character_error">"Ihre Eingabe enthält ein ungültiges Zeichen. Bitte überprüfen Sie Ihre Eingabe."</string>
 
     <!-- Submission Intro -->
     <!-- XHED: Page title for menu at the start of the submission process  -->
@@ -942,13 +942,13 @@
     <!-- XHED: Page headline for the positive result additional warning page-->
     <string name="submission_positive_other_warning_headline">"Helfen Sie mit!"</string>
     <!-- YTXT: Body text for the positive result additional warning page-->
-    <string name="submission_positive_other_warning_body">"Als Nächstes können Sie dafür sorgen, dass das Corona-Warn-System Ihre lokal gespeicherten Zufallscodes der letzten 14 Tage an andere verteilt. So können Sie Ihre Mitmenschen warnen und helfen, die Infektionskette zu unterbrechen.\n\nDa nur unpersönliche Zufallscodes übertragen werden, bleibt Ihre Identität unbekannt."</string>
+    <string name="submission_positive_other_warning_body">"Als Nächstes können Sie dafür sorgen, dass das Corona-Warn-System Ihre lokal gespeicherten Zufallscodes der letzten 14 Tage an andere verteilt. So können Sie Ihre Mitmenschen warnen und helfen, die Infektionskette zu unterbrechen.\n\nDa ein Ansteckungsrisiko schon vor dem Erkrankungsbeginn bestehen und im Zeitverlauf variieren kann, bitten wir Sie auch anzugeben, wann eventuelle Corona-Symptome (z. B. Fieber oder Husten) zum ersten Mal bei Ihnen aufgetreten sind. Dadurch kann das Infektionsrisiko von anderen App-Nutzern, die Ihnen begegnet sind, genauer berechnet werden. Die Angabe des Symptombeginns ist optional. Wenn Sie keine Symptome haben oder keine Angaben machen möchten, können Sie „keine Angabe“ auswählen."</string>
     <!-- XHED: Title for the privacy card-->
     <string name="submission_positive_other_warning_privacy_title">"Datenschutz"</string>
     <!-- YTXT: Body text for the privacy card-->
-    <string name="submission_positive_other_warning_privacy_body">"Durch Antippen von „Weiter“ willigen Sie ein, dass die App Ihr positives Testergebnis zusammen mit Ihren Zufalls-IDs der letzten 14 Tage an das Serversystem der App übermittelt, damit andere App-Nutzer mit aktivierter Risiko-Ermittlung automatisch informiert werden können, dass sie möglicherweise einem Infektionsrisiko ausgesetzt waren. Die übermittelten Zufalls-IDs enthalten keine Angaben, die Rückschlüsse auf Ihre Identität oder Ihre Person zulassen.\n\nDie Übermittlung Ihres Testergebnisses per App ist freiwillig. Wenn Sie Ihr Testergebnis nicht übermitteln, entstehen Ihnen keine Nachteile. Da weder nachvollzogen noch kontrolliert werden kann, ob und wie Sie die App verwenden, erfährt außer Ihnen niemand, ob Sie eine Infektion übermittelt haben.\n\nSie können Ihre Einwilligung jederzeit widerrufen, indem Sie die App löschen. Durch den Widerruf der Einwilligung wird die Rechtmäßigkeit der aufgrund der Einwilligung bis zum Widerruf erfolgten Verarbeitung nicht berührt. Weitere Informationen finden Sie unter dem Menüpunkt „Datenschutzinformation“."</string>
+    <string name="submission_positive_other_warning_privacy_body">"Durch Antippen von „Einverstanden“ willigen Sie ein, dass die App Ihr positives Testergebnis zusammen mit Ihren Zufalls-IDs der letzten 14 Tage an das Serversystem der App übermittelt, damit andere App-Nutzer mit aktivierter Risiko-Ermittlung automatisch informiert werden können, dass sie möglicherweise einem Infektionsrisiko ausgesetzt waren. Wenn Sie optionale Angaben zum Symptombeginn machen, enthalten die übermittelten Zufalls-IDs auch einen aus Ihren Angaben abgeleiteten Risikowert, der Ihr Ansteckungsrisiko am Gültigkeitstag der jeweiligen Zufalls-ID angibt. Die übermittelten Zufalls-IDs enthalten keine Angaben, die Rückschlüsse auf Ihre Identität oder Ihre Person zulassen.\n\nDie Übermittlung Ihres Testergebnisses per App ist freiwillig. Wenn Sie Ihr Testergebnis nicht übermitteln, entstehen Ihnen keine Nachteile. Da weder nachvollzogen noch kontrolliert werden kann, ob und wie Sie die App verwenden, erfährt außer Ihnen niemand, ob Sie eine Infektion übermittelt haben.\n\nSie können Ihre Einwilligung jederzeit widerrufen, indem Sie die App löschen. Durch den Widerruf der Einwilligung wird die Rechtmäßigkeit der aufgrund der Einwilligung bis zum Widerruf erfolgten Verarbeitung nicht berührt. Weitere Informationen finden Sie unter dem Menüpunkt „App-Informationen“ > „Datenschutz“."</string>
     <!-- XBUT: other warning continue button -->
-    <string name="submission_positive_other_warning_button">"Weiter"</string>
+    <string name="submission_positive_other_warning_button">"Einverstanden"</string>
     <!-- XACT: other warning - illustration description, explanation image -->
     <string name="submission_positive_other_illustration_description">"Ein Smartphone übermittelt einen positiven Testbefund verschlüsselt ins System."</string>
 
@@ -989,7 +989,33 @@
     <!-- XBUT: submission finished button -->
     <string name="submission_done_button_done">"Fertig"</string>
     <!-- XACT: submission finished - illustration description, explanation image -->
-    <string name="submission_done_illustration_description">"Eine vielfältige Gruppe begrüßt durch Jubel, dass jemand sein Testergebnis mit anderen geteilt hat."</string>
+    <string name="submission_done_illustration_description">"Sind eines oder mehrere der folgenden Symptome in den letzten Tagen bei Ihnen neu aufgetreten?"</string>
+
+    <!-- Submission Symptoms -->
+    <!-- XHED: Page title for symptom screens -->
+    <string name="submission_symptom_title">"Symptome"</string>
+    <!-- YTXT: headline text for initial symptom screen -->
+    <string name="submission_symptom_initial_headline">"Sind eines oder mehrere der folgenden Symptome in den letzten Tagen bei Ihnen neu aufgetreten?"</string>
+    <!-- YTXT: Bullet points for symptoms -->
+    <string-array name="submission_symptom_symptom_bullets">
+        <item>"Erhöhte Temperatur oder Fieber"</item>
+        <item>"Kurzatmigkeit"</item>
+        <item>"Verlust des Geruchs-/Geschmackssinns"</item>
+        <item>"Husten"</item>
+        <item>"Schnupfen"</item>
+        <item>"Halsschmerzen"</item>
+        <item>"Kopf- und Gliederschmerzen"</item>
+        <item>"Allgemeine Schwäche und Abgeschlagenheit"</item>
+    </string-array>
+    <!-- XBUT: symptom initial screen yes button -->
+    <string name="submission_symptom_positive_button">"Ja"</string>
+    <!-- XBUT:  symptom initial screen no button -->
+    <string name="submission_symptom_negative_button">"Nein"</string>
+    <!-- XBUT:  symptom initial screen no information button -->
+    <string name="submission_symptom_no_information_button">"Keine Angabe"</string>
+    <!-- XBUT:  symptom initial screen continue button -->
+    <string name="submission_symptom_further_button">"Weiter"</string>
+
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
@@ -1020,6 +1046,22 @@
     <!-- XACT: Content Description for submission contact step 2 -->
     <string name="submission_contact_step_2_content">"Im zweiten Schritt registrieren Sie den Test per TAN-Eingabe in der App."</string>
 
+    <!-- Submission Symptom Calendar -->
+    <!-- XHED: Page title for calendar page in submission symptom flow -->
+    <string name="submission_symptom_calendar_title">"Symptom-Beginn"</string>
+    <!-- XHED: Page headline for calendar page in symptom submission flow -->
+    <string name="submission_symptom_calendar_headline">"Wann sind die Symptome bei Ihnen aufgetreten? "</string>
+    <!-- YTXT: Body text for calendar page in symptom submission flow-->
+    <string name="submission_symptom_calendar_body">"Selektieren Sie entweder das genaue Datum in dem Kalender oder wenn Sie sich nicht genau erinnern, eine der anderen Optionen."</string>
+    <!-- XBUT: symptom calendar screen less than 7 days button -->
+    <string name="submission_symptom_less_seven">"In den letzten 7 Tagen"</string>
+    <!-- XBUT: symptom calendar screen 1-2 weeks button -->
+    <string name="submission_symptom_one_two_weeks">"Vor 1-2 Wochen"</string>
+    <!-- XBUT: symptom calendar screen more than 2 weeks button -->
+    <string name="submission_symptom_more_two_weeks">"Vor mehr als 2 Wochen"</string>
+    <!-- XBUT: symptom calendar screen verify button -->
+    <string name="submission_symptom_verify">"Keine Angabe"</string>
+
     <!-- Submission Status Card -->
     <!-- XHED: Page title for the various submission status: fetching -->
     <string name="submission_status_card_title_fetching">"Datenabruf…"</string>
@@ -1083,6 +1125,9 @@
         <item>"Gehen Sie nicht krank zur Arbeit, um andere Personen nicht zu gefährden. Falls sich Ihre Symptome verschlechtern, kann die Notwendigkeit eines weiteren SARS-CoV-2-Tests bestehen."</item>
     </string-array>
 
+    <!-- XBUT Symptoms exact date button -->
+    <string name="symptoms_calendar_exact_date_button">"Genaues Datum"</string>
+
     <!-- ####################################
           Button Tooltips for Accessibility
     ###################################### -->
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 1cea318c8050ccf66aef881f190c159ee1ba8cca..3f9469b81bf7f494dadacc2bd68721cf22c60466 100644
--- a/Corona-Warn-App/src/main/res/values-en/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/strings.xml
@@ -425,7 +425,7 @@
     <!-- XHED: onboarding(tracing) - headline for consent information -->
     <string name="onboarding_tracing_headline_consent">"Declaration of Consent"</string>
     <!-- YTXT: onboarding(tracing) - body for consent information -->
-    <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping the “Enable” button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the COVID-19 Exposure Logging functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyzes this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Information”."</string>
+    <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping the “Enable” button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the \"Exposure Notifications\" functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyzes this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Information”."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_button_next">"Activate Exposure Logging"</string>
     <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined -->
@@ -495,7 +495,7 @@
     <string name="sixteen_title_text">"Age Limit: 16 and Up"</string>
 
     <!-- XACT: onboarding(sixteen) title -->
-    <string name="sixteen_description_text">"This app is intended for people who reside in Germany and who are at least 16 years of age."</string>
+    <string name="sixteen_description_text">"The use of this app is intended for persons who are at least 16 years of age and who reside in Germany."</string>
 
 
     <!-- ####################################
@@ -541,7 +541,9 @@
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
     <string name="settings_tracing_status_location_headline">"Allow location access"</string>
     <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled -->
-    <string name="settings_tracing_status_location_body">"Your location cannot be accessed. Google and/or Android requires access to your device\'s location to use Bluetooth."</string>
+    <string name="settings_tracing_status_location_body">"Activate your location services. Bluetooth Low Energy requires activated location services to calculate physical distances, but does not access your location. For further information, please see our FAQ page."</string>
+    <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL -->
+    <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string>
     <!-- XBUT: settings(tracing) - go to operating system settings button on card - location -->
     <string name="settings_tracing_status_location_button">"Open Device Settings"</string>
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
@@ -720,7 +722,7 @@
     <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German -->
     <string name="information_legal_subtitle_contact_form_non_en_de">"Contact Form in "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"English"</a>" or "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"German"</a></string>
     <!-- XHED: Headline for legal information page, tax section -->
-    <string name="information_legal_headline_taxid">"VAT identification number"</string>
+    <string name="information_legal_headline_taxid">"VAT identification\nnumber"</string>
     <!-- YTXT: subtitle for legal information page, tax section -->
     <string name="information_legal_subtitle_taxid">"DE 165 893 430"</string>
     <!-- XACT: describes illustration -->
@@ -740,10 +742,14 @@
     <!-- XBUT: Positive button for generic web request error -->
     <string name="submission_error_dialog_web_generic_error_button_positive">"Back"</string>
 
-    <!-- XHED: Dialog title for already paired test error -->
+    <!-- XHED: Dialog title for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_title">"QR code is invalid"</string>
-    <!-- XMSG: Dialog body for already paired test error -->
+    <!-- XMSG: Dialog body for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_body">"The QR code is invalid or has been registered on another smartphone already. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with COVID-19, you will be notified by the public health authority."</string>
+    <!-- XHED: Dialog title for already paired test error: tan -->
+    <string name="submission_error_dialog_web_test_paired_title_tan">"TAN is invalid"</string>
+    <!-- XMSG: Dialog body for already paired test via tan - error: tan -->
+    <string name="submission_error_dialog_web_test_paired_body_tan">"The TAN is invalid or has already been used. For further information, call the number listed under \"Request TAN\"."</string>
     <!-- XBUT: Positive button for already paired test error -->
     <string name="submission_error_dialog_web_test_paired_button_positive">"Back"</string>
 
@@ -768,6 +774,15 @@
     <!-- XBUT: Positive button for submission tan redeemed -->
     <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string>
 
+    <!-- XHED: Dialog title for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_title">"Do you want to cancel?"</string>
+    <!-- XMSG: Dialog body for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_body">"Your entries will not be saved."</string>
+    <!-- XBUT: Positive button for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_button_positive">"Yes"</string>
+    <!-- XBUT: Negative button for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_button_negative">"No"</string>
+
     <!-- Permission Rationale Dialog -->
     <!-- XHED: Dialog headline QR Scan permission rationale  -->
     <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Camera authorization required"</string>
@@ -869,9 +884,9 @@
     <!-- XACT: Submission Tan page title -->
     <string name="submission_tan_accessibility_title">"TAN entry"</string>
     <!-- YTXT: Error text for the tan submission page -->
-    <string name="submission_tan_error">"Invalid TAN, please check your entry."</string>
+    <string name="submission_tan_error">"Invalid TAN. Please check your entry."</string>
     <!-- YTXT: Error text for the tan submission page (wrong characters) -->
-    <string name="submission_tan_character_error">"Invalid entry. Please check your entry."</string>
+    <string name="submission_tan_character_error">"Your entry contains invalid characters. Please check your entry."</string>
 
     <!-- Submission Intro -->
     <!-- XHED: Page title for menu at the start of the submission process  -->
@@ -931,9 +946,9 @@
     <!-- XHED: Title for the privacy card-->
     <string name="submission_positive_other_warning_privacy_title">"Data Privacy"</string>
     <!-- YTXT: Body text for the privacy card-->
-    <string name="submission_positive_other_warning_privacy_body">"By tapping on “Accept”, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy Information”."</string>
+    <string name="submission_positive_other_warning_privacy_body">"By tapping “Accept”, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy”."</string>
     <!-- XBUT: other warning continue button -->
-    <string name="submission_positive_other_warning_button">"Next"</string>
+    <string name="submission_positive_other_warning_button">"Accept"</string>
     <!-- XACT: other warning - illustration description, explanation image -->
     <string name="submission_positive_other_illustration_description">"A device transmits an encrypted positive test diagnosis to the system."</string>
 
@@ -961,7 +976,33 @@
     <!-- XBUT: submission finished button -->
     <string name="submission_done_button_done">"Done"</string>
     <!-- XACT: submission finished - illustration description, explanation image -->
-    <string name="submission_done_illustration_description">"Everyone in the group is cheering because someone has shared the test result."</string>
+    <string name="submission_done_illustration_description">"Have you experienced one or more of the following symptoms in the past few days?"</string>
+
+    <!-- Submission Symptoms -->
+    <!-- XHED: Page title for symptom screens -->
+    <string name="submission_symptom_title">"Symptoms"</string>
+    <!-- YTXT: headline text for initial symptom screen -->
+    <string name="submission_symptom_initial_headline">"Have you experienced one or more of the following symptoms in the past few days?"</string>
+    <!-- YTXT: Bullet points for symptoms -->
+    <string-array name="submission_symptom_symptom_bullets">
+        <item>"Increased temperature or fever"</item>
+        <item>"Shortness of breath"</item>
+        <item>"Loss of sense of smell/taste"</item>
+        <item>"Cough"</item>
+        <item>"Runny nose"</item>
+        <item>"Sore throat"</item>
+        <item>"Headache and aching limbs"</item>
+        <item>"General weakness and exhaustion"</item>
+    </string-array>
+    <!-- XBUT: symptom initial screen yes button -->
+    <string name="submission_symptom_positive_button">"Yes"</string>
+    <!-- XBUT:  symptom initial screen no button -->
+    <string name="submission_symptom_negative_button">"No"</string>
+    <!-- XBUT:  symptom initial screen no information button -->
+    <string name="submission_symptom_no_information_button">"No comment"</string>
+    <!-- XBUT:  symptom initial screen continue button -->
+    <string name="submission_symptom_further_button">"Next"</string>
+
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
@@ -992,6 +1033,22 @@
     <!-- XACT: Content Description for submission contact step 2 -->
     <string name="submission_contact_step_2_content">"In the second step, you register your test with your TAN in the app."</string>
 
+    <!-- Submission Symptom Calendar -->
+    <!-- XHED: Page title for calendar page in submission symptom flow -->
+    <string name="submission_symptom_calendar_title">"Start of Symptoms"</string>
+    <!-- XHED: Page headline for calendar page in symptom submission flow -->
+    <string name="submission_symptom_calendar_headline">"When did you first start to experience these symptoms? "</string>
+    <!-- YTXT: Body text for calendar page in symptom submission flow-->
+    <string name="submission_symptom_calendar_body">"Select the exact date in the calendar or, if you cannot remember the exact date, choose one of the other options."</string>
+    <!-- XBUT: symptom calendar screen less than 7 days button -->
+    <string name="submission_symptom_less_seven">"In the last 7 days"</string>
+    <!-- XBUT: symptom calendar screen 1-2 weeks button -->
+    <string name="submission_symptom_one_two_weeks">"1-2 weeks ago"</string>
+    <!-- XBUT: symptom calendar screen more than 2 weeks button -->
+    <string name="submission_symptom_more_two_weeks">"More than 2 weeks ago"</string>
+    <!-- XBUT: symptom calendar screen verify button -->
+    <string name="submission_symptom_verify">"No comment"</string>
+
     <!-- Submission Status Card -->
     <!-- XHED: Page title for the various submission status: fetching -->
     <string name="submission_status_card_title_fetching">"Data being retrieved...."</string>
@@ -1055,6 +1112,9 @@
         <item>"Do not go to work if you feel unwell to ensure you do not put other people at risk. If your symptoms worsen, you might need a further SARS-CoV-2 test."</item>
     </string-array>
 
+    <!-- XBUT Symptoms exact date button -->
+    <string name="symptoms_calendar_exact_date_button">"Exact date"</string>
+
     <!-- ####################################
           Button Tooltips for Accessibility
     ###################################### -->
@@ -1083,7 +1143,7 @@
     <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action -->
     <string name="errors_external_action">"You cannot perform this action. Please contact the hotline."</string>
     <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update -->
-    <string name="errors_google_update_needed">"Your Corona-Warn-App is correctly installed, but the \"COVID-19 exposure notifications\" service is not available on your smartphone\'s operating system. This means that you cannot use the Corona-Warn-App. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string>
+    <string name="errors_google_update_needed">"Your Corona-Warn-App is correctly installed, but the \"COVID-19 Exposure Notifications System\" is not available on your smartphone\'s operating system. This means that you cannot use the Corona-Warn-App. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string>
     <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day -->
     <string name="errors_google_api_error">"The Corona-Warn-App is running correctly, but we cannot update your current risk status. Exposure logging remains active and is working correctly. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string>
 
diff --git a/Corona-Warn-App/src/main/res/values-night/colors.xml b/Corona-Warn-App/src/main/res/values-night/colors.xml
index b2fda3b41a4aabd5763535f0ca7ffd85fe4ff600..0481128c930d6fa77df913daa7402f94e00b4a51 100644
--- a/Corona-Warn-App/src/main/res/values-night/colors.xml
+++ b/Corona-Warn-App/src/main/res/values-night/colors.xml
@@ -53,4 +53,6 @@
     <color name="colorStableHairlineLight">#33FFFFFF</color>
     <color name="colorStableHairlineDark">#3317191A</color>
 
+    <!-- Calendar -->
+    <color name="colorCalendarMonthText">#DEFFFFFF</color>
 </resources>
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 ee8a348dc7fbb995706322514d4fb96a18dacab1..2b43331da8bd5a3ba585f59fc0436457664d7671 100644
--- a/Corona-Warn-App/src/main/res/values-pl/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/strings.xml
@@ -425,7 +425,7 @@
     <!-- XHED: onboarding(tracing) - headline for consent information -->
     <string name="onboarding_tracing_headline_consent">"Oświadczenie o wyrażeniu zgody"</string>
     <!-- YTXT: onboarding(tracing) - body for consent information -->
-    <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping the “Enable” button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the COVID-19 Exposure Logging functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyzes this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Information”."</string>
+    <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping the “Enable” button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the \"Exposure Notifications\" functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyzes this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Information”."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_button_next">"Aktywuj rejestrowanie narażenia"</string>
     <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined -->
@@ -495,7 +495,7 @@
     <string name="sixteen_title_text">"Limit wieku: 16 i więcej"</string>
 
     <!-- XACT: onboarding(sixteen) title -->
-    <string name="sixteen_description_text">"Ta aplikacja jest przeznaczona dla osób mieszkających w Niemczech, które ukończyły 16 lat."</string>
+    <string name="sixteen_description_text">"Ta aplikacja jest przeznaczona dla osób, które ukończyły 16 lat i mieszkają w Niemczech."</string>
 
 
     <!-- ####################################
@@ -541,7 +541,9 @@
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
     <string name="settings_tracing_status_location_headline">"Zezwól na dostęp do lokalizacji"</string>
     <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled -->
-    <string name="settings_tracing_status_location_body">"Nie można uzyskać dostępu do Twojej lokalizacji. Google i/lub Android wymaga dostępu do lokalizacji Twojego urządzenia w celu użycia Bluetooth."</string>
+    <string name="settings_tracing_status_location_body">"Aktywuj swoje usługi lokalizacji. Bluetooth Low Energy wymaga aktywowanych usług lokalizacji do obliczenia fizycznego dystansu, ale nie uzyskuje dostępu do Twojej lokalizacji. Więcej informacji znajduje się na stronie Często zadawane pytania."</string>
+    <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL -->
+    <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string>
     <!-- XBUT: settings(tracing) - go to operating system settings button on card - location -->
     <string name="settings_tracing_status_location_button">"Otwórz ustawienia urządzenia"</string>
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
@@ -740,10 +742,14 @@
     <!-- XBUT: Positive button for generic web request error -->
     <string name="submission_error_dialog_web_generic_error_button_positive">"Wstecz"</string>
 
-    <!-- XHED: Dialog title for already paired test error -->
+    <!-- XHED: Dialog title for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_title">"Niepoprawny kod QR"</string>
-    <!-- XMSG: Dialog body for already paired test error -->
+    <!-- XMSG: Dialog body for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_body">"Kod QR jest niepoprawny lub został już zarejestrowany na innym smartfonie. Otrzymasz swój wynik testu z ośrodka wykonującego testy lub laboratorium niezależnie od ważności kodu QR. W przypadku zdiagnozowania u Ciebie COVID-19 otrzymasz powiadomienie z organu ds. zdrowia publicznego."</string>
+    <!-- XHED: Dialog title for already paired test error: tan -->
+    <string name="submission_error_dialog_web_test_paired_title_tan">"TAN jest nieprawidłowy."</string>
+    <!-- XMSG: Dialog body for already paired test via tan - error: tan -->
+    <string name="submission_error_dialog_web_test_paired_body_tan">"TAN jest nieprawidłowy lub został już użyty. Więcej informacji można uzyskać dzwoniąc na numer wymieniony w sekcji „Poproś o TAN”."</string>
     <!-- XBUT: Positive button for already paired test error -->
     <string name="submission_error_dialog_web_test_paired_button_positive">"Wstecz"</string>
 
@@ -768,6 +774,15 @@
     <!-- XBUT: Positive button for submission tan redeemed -->
     <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string>
 
+    <!-- XHED: Dialog title for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_title">"Czy chcesz anulować?"</string>
+    <!-- XMSG: Dialog body for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_body">"Twoje wpisy nie zostanÄ… zapisane."</string>
+    <!-- XBUT: Positive button for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_button_positive">"Tak"</string>
+    <!-- XBUT: Negative button for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_button_negative">"Nie"</string>
+
     <!-- Permission Rationale Dialog -->
     <!-- XHED: Dialog headline QR Scan permission rationale  -->
     <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Wymagana autoryzacja aparatu"</string>
@@ -871,7 +886,7 @@
     <!-- YTXT: Error text for the tan submission page -->
     <string name="submission_tan_error">"Nieprawidłowy TAN, sprawdź swój wpis."</string>
     <!-- YTXT: Error text for the tan submission page (wrong characters) -->
-    <string name="submission_tan_character_error">"Nieprawidłowy wpis, sprawdź go."</string>
+    <string name="submission_tan_character_error">"Twój wpis zawiera nieprawidłowe znaki, Sprawdź swój wpis."</string>
 
     <!-- Submission Intro -->
     <!-- XHED: Page title for menu at the start of the submission process  -->
@@ -931,9 +946,9 @@
     <!-- XHED: Title for the privacy card-->
     <string name="submission_positive_other_warning_privacy_title">"Prywatność danych"</string>
     <!-- YTXT: Body text for the privacy card-->
-    <string name="submission_positive_other_warning_privacy_body">"By tapping on “Accept”, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy Information”."</string>
+    <string name="submission_positive_other_warning_privacy_body">"By tapping “Accept”, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy”."</string>
     <!-- XBUT: other warning continue button -->
-    <string name="submission_positive_other_warning_button">"Dalej"</string>
+    <string name="submission_positive_other_warning_button">"Akceptuj"</string>
     <!-- XACT: other warning - illustration description, explanation image -->
     <string name="submission_positive_other_illustration_description">"Zaszyfrowana diagnoza zakażenia jest przesyłana do systemu."</string>
 
@@ -961,7 +976,33 @@
     <!-- XBUT: submission finished button -->
     <string name="submission_done_button_done">"Gotowe"</string>
     <!-- XACT: submission finished - illustration description, explanation image -->
-    <string name="submission_done_illustration_description">"Wszyscy w grupie się cieszą, ponieważ ktoś podzielił się wynikiem testu."</string>
+    <string name="submission_done_illustration_description">"Czy w ciągu ostatnich kilku dni wystąpił u Ciebie jeden lub kilka z wymienionych poniżej symptomów?"</string>
+
+    <!-- Submission Symptoms -->
+    <!-- XHED: Page title for symptom screens -->
+    <string name="submission_symptom_title">"Symptomy"</string>
+    <!-- YTXT: headline text for initial symptom screen -->
+    <string name="submission_symptom_initial_headline">"Czy w ciągu ostatnich kilku dni wystąpił u Ciebie jeden lub kilka z wymienionych poniżej symptomów?"</string>
+    <!-- YTXT: Bullet points for symptoms -->
+    <string-array name="submission_symptom_symptom_bullets">
+        <item>"Podwyższona temperatura lub gorączka"</item>
+        <item>"Duszności"</item>
+        <item>"Utrata węchu/smaku"</item>
+        <item>"Kaszel"</item>
+        <item>"Katar"</item>
+        <item>"Ból gardła"</item>
+        <item>"Ból głowy i kończyn"</item>
+        <item>"Ogólne osłabienie i wyczerpanie"</item>
+    </string-array>
+    <!-- XBUT: symptom initial screen yes button -->
+    <string name="submission_symptom_positive_button">"Tak"</string>
+    <!-- XBUT:  symptom initial screen no button -->
+    <string name="submission_symptom_negative_button">"Nie"</string>
+    <!-- XBUT:  symptom initial screen no information button -->
+    <string name="submission_symptom_no_information_button">"Bez komentarza"</string>
+    <!-- XBUT:  symptom initial screen continue button -->
+    <string name="submission_symptom_further_button">"Dalej"</string>
+
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
@@ -992,6 +1033,22 @@
     <!-- XACT: Content Description for submission contact step 2 -->
     <string name="submission_contact_step_2_content">"Następnie zarejestruj test przy użyciu numeru TAN w aplikacji."</string>
 
+    <!-- Submission Symptom Calendar -->
+    <!-- XHED: Page title for calendar page in submission symptom flow -->
+    <string name="submission_symptom_calendar_title">"Początek wystąpienia symptomów"</string>
+    <!-- XHED: Page headline for calendar page in symptom submission flow -->
+    <string name="submission_symptom_calendar_headline">"Kiedy zacząłeś(-łaś) odczutwać te symptomy? "</string>
+    <!-- YTXT: Body text for calendar page in symptom submission flow-->
+    <string name="submission_symptom_calendar_body">"Wybierz dokładną datę w kalendarzu lub, jeśli nie pamiętasz dokładnej daty, wybierz jedną z innych opcji."</string>
+    <!-- XBUT: symptom calendar screen less than 7 days button -->
+    <string name="submission_symptom_less_seven">"W ciÄ…gu ostatnich 7 dni"</string>
+    <!-- XBUT: symptom calendar screen 1-2 weeks button -->
+    <string name="submission_symptom_one_two_weeks">"1-2 tygodnie temu"</string>
+    <!-- XBUT: symptom calendar screen more than 2 weeks button -->
+    <string name="submission_symptom_more_two_weeks">"Ponad 2 tygodnie temu"</string>
+    <!-- XBUT: symptom calendar screen verify button -->
+    <string name="submission_symptom_verify">"Bez komentarza"</string>
+
     <!-- Submission Status Card -->
     <!-- XHED: Page title for the various submission status: fetching -->
     <string name="submission_status_card_title_fetching">"Pobieranie danych..."</string>
@@ -1055,6 +1112,9 @@
         <item>"Nie idź do pracy, jeśli nie czujesz się dobrze, aby nie stwarzać zagrożenia dla innych osób. Jeśli objawy nasilą się, może być konieczne wykonanie kolejnego testu SARS-CoV-2."</item>
     </string-array>
 
+    <!-- XBUT Symptoms exact date button -->
+    <string name="symptoms_calendar_exact_date_button">"Dokładna data"</string>
+
     <!-- ####################################
           Button Tooltips for Accessibility
     ###################################### -->
@@ -1083,7 +1143,7 @@
     <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action -->
     <string name="errors_external_action">"Nie możesz wykonać tej czynności. Skontaktuj się z infolinią."</string>
     <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update -->
-    <string name="errors_google_update_needed">"Twoja aplikacja Corona-Warn-App jest poprawnie zainstalowana, ale usługa „Powiadomienia o narażeniu na COVID-19” nie jest dostępna w systemie operacyjnym Twojego smartfona. Oznacza to, że nie możesz korzystać z aplikacji Corona-Warn-App. Więcej informacji znajduje się na naszej stronie „Często zadawane pytania”: https://www.coronawarn.app/en/faq/."</string>
+    <string name="errors_google_update_needed">"Twoja aplikacja Corona-Warn-App jest poprawnie zainstalowana, ale system „Powiadomienia o narażeniu na COVID-19” nie jest dostępny w systemie operacyjnym Twojego smartfona. Oznacza to, że nie możesz korzystać z aplikacji Corona-Warn-App. Więcej informacji znajduje się na naszej stronie „Często zadawane pytania”: https://www.coronawarn.app/en/faq/."</string>
     <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day -->
     <string name="errors_google_api_error">"Aplikacja Corona-Warn-App działa prawidłowo, ale nie możemy zaaktualizować Twojego aktualnego statusu ryzyka. Rejestrowanie narażenia pozostaje aktywne i działa prawidłowo. Więcej informacji można znaleźć na naszej stronie „Często zadawane pytania”: https://www.coronawarn.app/en/faq/"</string>
 
diff --git a/Corona-Warn-App/src/main/res/values-ro/strings.xml b/Corona-Warn-App/src/main/res/values-ro/strings.xml
index a38d1fc6e6e39a509c0ffce0a13855905460cd66..cbcc88284abfc41b988d42d536e00801301a16c7 100644
--- a/Corona-Warn-App/src/main/res/values-ro/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/strings.xml
@@ -425,7 +425,7 @@
     <!-- XHED: onboarding(tracing) - headline for consent information -->
     <string name="onboarding_tracing_headline_consent">"Declarație de consimțământ"</string>
     <!-- YTXT: onboarding(tracing) - body for consent information -->
-    <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping the “Enable” button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the COVID-19 Exposure Logging functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyzes this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Information”."</string>
+    <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping the “Enable” button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the \"Exposure Notifications\" functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyzes this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Information”."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_button_next">"Activați înregistrarea în jurnal a expunerilor"</string>
     <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined -->
@@ -495,7 +495,7 @@
     <string name="sixteen_title_text">"Limita de vârstă: începând cu 16 ani"</string>
 
     <!-- XACT: onboarding(sixteen) title -->
-    <string name="sixteen_description_text">"Această aplicație este destinată persoanelor care locuiesc în Germania și care au vârsta de cel puțin 16 ani."</string>
+    <string name="sixteen_description_text">"Utilizarea acestei aplicații este destinată persoanelor care au vârsta de cel puțin 16 ani și care locuiesc în Germania."</string>
 
 
     <!-- ####################################
@@ -541,7 +541,9 @@
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
     <string name="settings_tracing_status_location_headline">"Permiteți accesul la locație"</string>
     <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled -->
-    <string name="settings_tracing_status_location_body">"Locația dvs. nu poate fi accesată. Google și/sau Android necesită acces la locația dispozitivului dvs. pentru a utiliza Bluetooth-ul."</string>
+    <string name="settings_tracing_status_location_body">"Activați serviciile de localizare. Bluetooth Low Energy necesită ca serviciile de localizare să fie activate pentru a calcula distanțele fizice, dar nu vă accesează locația. Pentru informații suplimentare, consultați pagina noastră de întrebări frecvente."</string>
+    <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL -->
+    <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string>
     <!-- XBUT: settings(tracing) - go to operating system settings button on card - location -->
     <string name="settings_tracing_status_location_button">"Deschideți setările dispozitivului"</string>
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
@@ -720,7 +722,7 @@
     <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German -->
     <string name="information_legal_subtitle_contact_form_non_en_de">"Contact Form in "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"English"</a>" or "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"German"</a></string>
     <!-- XHED: Headline for legal information page, tax section -->
-    <string name="information_legal_headline_taxid">"Număr de înregistrare în scop de TVA"</string>
+    <string name="information_legal_headline_taxid">"Număr de înregistrare\nîn scop de TVA"</string>
     <!-- YTXT: subtitle for legal information page, tax section -->
     <string name="information_legal_subtitle_taxid">"DE 165 893 430"</string>
     <!-- XACT: describes illustration -->
@@ -740,10 +742,14 @@
     <!-- XBUT: Positive button for generic web request error -->
     <string name="submission_error_dialog_web_generic_error_button_positive">"ÃŽnapoi"</string>
 
-    <!-- XHED: Dialog title for already paired test error -->
+    <!-- XHED: Dialog title for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_title">"Codul QR este nevalabil"</string>
-    <!-- XMSG: Dialog body for already paired test error -->
+    <!-- XMSG: Dialog body for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_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 COVID-19, veți fi notificat de autoritatea de sănătate publică."</string>
+    <!-- XHED: Dialog title for already paired test error: tan -->
+    <string name="submission_error_dialog_web_test_paired_title_tan">"TAN-ul este nevalabil"</string>
+    <!-- XMSG: Dialog body for already paired test via tan - error: tan -->
+    <string name="submission_error_dialog_web_test_paired_body_tan">"TAN-ul este nevalabil sau a fost deja utilizat. Pentru informații suplimentare, apelați numărul afișat la „Solicitare TAN”."</string>
     <!-- XBUT: Positive button for already paired test error -->
     <string name="submission_error_dialog_web_test_paired_button_positive">"ÃŽnapoi"</string>
 
@@ -768,6 +774,15 @@
     <!-- XBUT: Positive button for submission tan redeemed -->
     <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string>
 
+    <!-- XHED: Dialog title for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_title">"Doriți să anulați?"</string>
+    <!-- XMSG: Dialog body for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_body">"Intrările dvs. nu vor fi salvate."</string>
+    <!-- XBUT: Positive button for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_button_positive">"Da"</string>
+    <!-- XBUT: Negative button for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_button_negative">"Nu"</string>
+
     <!-- Permission Rationale Dialog -->
     <!-- XHED: Dialog headline QR Scan permission rationale  -->
     <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Este necesară autorizația pentru camera foto"</string>
@@ -869,9 +884,9 @@
     <!-- XACT: Submission Tan page title -->
     <string name="submission_tan_accessibility_title">"Intrare TAN"</string>
     <!-- YTXT: Error text for the tan submission page -->
-    <string name="submission_tan_error">"TAN nevalabil. Verificați intrarea."</string>
+    <string name="submission_tan_error">"TAN nevalabil. Verificați intrarea dvs."</string>
     <!-- YTXT: Error text for the tan submission page (wrong characters) -->
-    <string name="submission_tan_character_error">"Intrare nevalabilă. Verificați intrarea."</string>
+    <string name="submission_tan_character_error">"Intrarea dvs. conține caractere nevalabile. Vă rugăm să o verificați."</string>
 
     <!-- Submission Intro -->
     <!-- XHED: Page title for menu at the start of the submission process  -->
@@ -931,9 +946,9 @@
     <!-- XHED: Title for the privacy card-->
     <string name="submission_positive_other_warning_privacy_title">"Confidențialitatea datelor"</string>
     <!-- YTXT: Body text for the privacy card-->
-    <string name="submission_positive_other_warning_privacy_body">"By tapping on “Accept”, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy Information”."</string>
+    <string name="submission_positive_other_warning_privacy_body">"Apăsând pe „Accept”, consimțiți ca aplicația să trimită rezultatul pozitiv al testului dvs. către sistemul de servere al aplicației, împreună cu ID-urile dvs. aleatorii din ultimele 14 zile, pentru ca ceilalți utilizatori ai aplicației care au activat caracteristica de înregistrare în jurnal a expunerilor să poată fi notificați automat că se poate să fi fost expuși la riscul de infectare. ID-urile aleatorii transmise în acest scop nu conțin informații care să poată permite tragerea unor concluzii privind identitatea dvs. sau persoana dvs. \n\nTransmiterea rezultatului testului prin intermediul aplicației este voluntară. Nu veți fi penalizat dacă nu transmiteți rezultatul testului. Din moment ce nu este posibilă urmărirea sau verificarea modului în care utilizați aplicația sau dacă o utilizați sau nu, doar dvs. veți ști dacă ați transmis informațiile că sunteți infectat.\n\nPuteți oricând să vă retrageți consimțământul prin ștergerea acestei aplicații. Retragerea consimțământului nu va afecta legalitatea procesării efectuate în baza consimțământului acordat înainte de retragerea acestuia. Pentru informații suplimentare, consultați meniul din „Confidențialitatea datelor”."</string>
     <!-- XBUT: other warning continue button -->
-    <string name="submission_positive_other_warning_button">"ÃŽnainte"</string>
+    <string name="submission_positive_other_warning_button">"Accept"</string>
     <!-- XACT: other warning - illustration description, explanation image -->
     <string name="submission_positive_other_illustration_description">"Un dispozitiv transmite un diagnostic de test pozitiv criptat către sistem."</string>
 
@@ -961,7 +976,33 @@
     <!-- XBUT: submission finished button -->
     <string name="submission_done_button_done">"Gata"</string>
     <!-- XACT: submission finished - illustration description, explanation image -->
-    <string name="submission_done_illustration_description">"Toată lumea din grup aclamă deoarece o persoană și-a împărtășit rezultatul testului."</string>
+    <string name="submission_done_illustration_description">"Ați resimțit unul sau mai multe dintre următoarele simptome în ultimele zile?"</string>
+
+    <!-- Submission Symptoms -->
+    <!-- XHED: Page title for symptom screens -->
+    <string name="submission_symptom_title">"Simptome"</string>
+    <!-- YTXT: headline text for initial symptom screen -->
+    <string name="submission_symptom_initial_headline">"Ați resimțit unul sau mai multe dintre următoarele simptome în ultimele zile?"</string>
+    <!-- YTXT: Bullet points for symptoms -->
+    <string-array name="submission_symptom_symptom_bullets">
+        <item>"Temperatură crescută sau febră"</item>
+        <item>"Scurtarea respirației"</item>
+        <item>"Pierderea mirosului/gustului"</item>
+        <item>"Tuse"</item>
+        <item>"Curgerea nasului"</item>
+        <item>"Durere în gât"</item>
+        <item>"Durere de cap și dureri de membre"</item>
+        <item>"Slăbiciune generală și epuizare"</item>
+    </string-array>
+    <!-- XBUT: symptom initial screen yes button -->
+    <string name="submission_symptom_positive_button">"Da"</string>
+    <!-- XBUT:  symptom initial screen no button -->
+    <string name="submission_symptom_negative_button">"Nu"</string>
+    <!-- XBUT:  symptom initial screen no information button -->
+    <string name="submission_symptom_no_information_button">"Nu comentez"</string>
+    <!-- XBUT:  symptom initial screen continue button -->
+    <string name="submission_symptom_further_button">"ÃŽnainte"</string>
+
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
@@ -992,6 +1033,22 @@
     <!-- XACT: Content Description for submission contact step 2 -->
     <string name="submission_contact_step_2_content">"Al doilea pas: înregistrați-vă testul cu codul dvs. TAN în aplicație."</string>
 
+    <!-- Submission Symptom Calendar -->
+    <!-- XHED: Page title for calendar page in submission symptom flow -->
+    <string name="submission_symptom_calendar_title">"ÃŽnceputul simptomelor"</string>
+    <!-- XHED: Page headline for calendar page in symptom submission flow -->
+    <string name="submission_symptom_calendar_headline">"Când ați început să resimțiți aceste simptome? "</string>
+    <!-- YTXT: Body text for calendar page in symptom submission flow-->
+    <string name="submission_symptom_calendar_body">"Selectați data exactă din calendar sau, în cazul în care nu țineți minte data exactă, alegeți una dintre celelalte opțiuni:"</string>
+    <!-- XBUT: symptom calendar screen less than 7 days button -->
+    <string name="submission_symptom_less_seven">"ÃŽn ultimele 7 zile"</string>
+    <!-- XBUT: symptom calendar screen 1-2 weeks button -->
+    <string name="submission_symptom_one_two_weeks">"Acum 1-2 săptămâni"</string>
+    <!-- XBUT: symptom calendar screen more than 2 weeks button -->
+    <string name="submission_symptom_more_two_weeks">"Cu peste 2 săptămâni în urmă"</string>
+    <!-- XBUT: symptom calendar screen verify button -->
+    <string name="submission_symptom_verify">"Nu comentez"</string>
+
     <!-- Submission Status Card -->
     <!-- XHED: Page title for the various submission status: fetching -->
     <string name="submission_status_card_title_fetching">"Datele sunt citite...."</string>
@@ -1055,6 +1112,9 @@
         <item>"Nu mergeți la serviciu dacă nu vă simțiți bine pentru a nu expune la risc alte persoane. Dacă simptomele dvs. se agravează, se poate să aveți nevoie de un test SARS-CoV-2 suplimentar."</item>
     </string-array>
 
+    <!-- XBUT Symptoms exact date button -->
+    <string name="symptoms_calendar_exact_date_button">"Data exactă"</string>
+
     <!-- ####################################
           Button Tooltips for Accessibility
     ###################################### -->
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 0b5195ad18370c52bcfc538eebe18a445c0743c9..37da8aabb8cba5c6415109d67a207c791a12169d 100644
--- a/Corona-Warn-App/src/main/res/values-tr/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/strings.xml
@@ -425,7 +425,7 @@
     <!-- XHED: onboarding(tracing) - headline for consent information -->
     <string name="onboarding_tracing_headline_consent">"Kabul Beyanı"</string>
     <!-- YTXT: onboarding(tracing) - body for consent information -->
-    <string name="onboarding_tracing_body_consent">"Enfekte olan biriyle temas halinde olup olmadığınızı ve sizin de enfeksiyon riski altında olup olmadığınızı öğrenmek için Uygulamanın maruz kalma günlüğü özelliğini etkinleştirmeniz gerekir. \"Etkinleştir\" düğmesine dokunarak Uygulamanın maruz kalma günlüğü özelliğini etkinleştirmeyi ve ilişkili verilerin işlenmesini kabul edersiniz."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Uygulamanın maruz kalma günlüğü özelliğini kullanmak için akıllı telefonunuzda Google tarafından sunulan COVID-19\'a Maruz Kalma Günlüğü işlevini etkinleştirmeniz ve Corona-Warn-App\'e bu işlevi kullanma izni vermeniz gerekecektir."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Maruz kalma günlüğü etkinleştirildiğinde akıllı telefonunuz sürekli olarak rastgele kimlikler oluşturur ve bu rastgele kimlikleri maruz kalma günlüğü etkinleştirilmiş olan yakınınızdaki diğer Android veya Apple akıllı telefonlara Bluetooth üzerinden aktarır. Bunun karşılığında akıllı telefonunuz diğer akıllı telefonların rastgele kimliklerini alır. Size ait olan ve diğer akıllı telefonlardan alınan rastgele kimlikler, maruz kalma günlüğüne kaydedilir ve 14 gün süreyle burada saklanır."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Uygulama, enfeksiyon riskinizi belirlemek için koronavirüs enfeksiyonu olduğunu Uygulamada belirten tüm kullanıcıların rastgele kimliklerinin listesini (günde birkaç kez veya talep üzerine) yükler. Ardından bu liste maruz kalma günlüğünde tutulan rastgele kimliklerle karşılaştırılır. Uygulama enfekte olan bir kullanıcı ile temas halinde olabileceğinizi saptadığında bu konuda bilgilendirilirsiniz ve sizin de enfeksiyon riski taşıdığınız belirtilir. Bu durumda Uygulama akıllı telefonunuzun maruz kalma günlüğünde tutulan diğer verilere (tarih, süre ve temas sırasındaki Bluetooth sinyalinin gücü) erişir."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Bluetooth sinyal gücü, fiziksel mesafenin belirlenmesi için kullanılır (sinyal ne kadar güçlü olursa mesafe o kadar kısa olur). Ardından Uygulama, koronavirüs enfeksiyonu olasılığınızı değerlendirmek ve sonraki adımlara yönelik öneriler sunmak üzere bu bilgileri analiz eder. Bu analiz akıllı telefonunuzda yalnızca yerel olarak gerçekleştirilir. Sizin dışınızda hiç kimse (RKI bile) enfekte olan biriyle temas ettiğinizi ve sizin için belirlenen riski bilmez."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Maruz kalma günlüğüne verdiğiniz onayı geri çekmek için Uygulamadaki düğmeyi kullanarak veya Uygulamayı silerek özelliği devre dışı bırakabilirsiniz. Maruz kalma günlüğü özelliğini yeniden kullanmaya karar verirseniz özelliği geri açabilir veya Uygulamayı yeniden yükleyebilirsiniz. Maruz kalma günlüğü özelliğini devre dışı bırakırsanız Uygulama artık enfekte olan bir kullanıcı ile temas halinde olup olmadığınızı kontrol etmez. Cihazınızın rastgele kimlik göndermesini ve almasını durdurmak isterseniz de akıllı telefonunuzun ayarlarında COVID-19\'a Maruz Kalma Günlüğü özelliğini devre dışı bırakmanız gerekir. Size ait olan ve diğer akıllı telefonlardan alınan maruz kalma günlüğündeki rastgele kimliklerin Uygulamada silinmeyeceğini unutmayın. Akıllı telefonunuzun ayarlarında yalnızca maruz kalma günlüğünde tutulan verileri kalıcı olarak silebilirsiniz."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Uygulamanın gizlilik bildirimini (maruz kalma günlüğü özelliği için gerçekleştirilen veri işlemeye ilişkin açıklama dahil) menüde \"Veri Gizliliği Bilgileri\" başlığında bulabilirsiniz."</string>
+    <string name="onboarding_tracing_body_consent">"Enfekte olan biriyle temas halinde olup olmadığınızı ve sizin de enfeksiyon riski altında olup olmadığınızı öğrenmek için Uygulamanın maruz kalma günlüğü özelliğini etkinleştirmeniz gerekir. \"Etkinleştir\" düğmesine dokunarak Uygulamanın maruz kalma günlüğü özelliğini etkinleştirmeyi ve ilişkili verilerin işlenmesini kabul edersiniz."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Uygulamanın maruz kalma günlüğü özelliğini kullanmak için akıllı telefonunuzda Google tarafından sunulan \"Maruz Kalma Bildirimleri\" işlevini etkinleştirmeniz ve Corona-Warn-App\'e bu işlevi kullanma izni vermeniz gerekecektir."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Maruz kalma günlüğü etkinleştirildiğinde akıllı telefonunuz sürekli olarak rastgele kimlikler oluşturur ve bu rastgele kimlikleri maruz kalma günlüğü etkinleştirilmiş olan yakınınızdaki diğer Android veya Apple akıllı telefonlara Bluetooth üzerinden aktarır. Bunun karşılığında akıllı telefonunuz diğer akıllı telefonların rastgele kimliklerini alır. Size ait olan ve diğer akıllı telefonlardan alınan rastgele kimlikler, maruz kalma günlüğüne kaydedilir ve 14 gün süreyle burada saklanır."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Uygulama, enfeksiyon riskinizi belirlemek için koronavirüs enfeksiyonu olduğunu Uygulamada belirten tüm kullanıcıların rastgele kimliklerinin listesini (günde birkaç kez veya talep üzerine) yükler. Ardından bu liste maruz kalma günlüğünde tutulan rastgele kimliklerle karşılaştırılır. Uygulama enfekte olan bir kullanıcı ile temas halinde olabileceğinizi saptadığında bu konuda bilgilendirilirsiniz ve sizin de enfeksiyon riski taşıdığınız belirtilir. Bu durumda Uygulama akıllı telefonunuzun maruz kalma günlüğünde tutulan diğer verilere (tarih, süre ve temas sırasındaki Bluetooth sinyalinin gücü) erişir."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Bluetooth sinyal gücü, fiziksel mesafenin belirlenmesi için kullanılır (sinyal ne kadar güçlü olursa mesafe o kadar kısa olur). Ardından Uygulama, koronavirüs enfeksiyonu olasılığınızı değerlendirmek ve sonraki adımlara yönelik öneriler sunmak üzere bu bilgileri analiz eder. Bu analiz akıllı telefonunuzda yalnızca yerel olarak gerçekleştirilir. Sizin dışınızda hiç kimse (RKI bile) enfekte olan biriyle temas ettiğinizi ve sizin için belirlenen riski bilmez."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Maruz kalma günlüğüne verdiğiniz onayı geri çekmek için Uygulamadaki düğmeyi kullanarak veya Uygulamayı silerek özelliği devre dışı bırakabilirsiniz. Maruz kalma günlüğü özelliğini yeniden kullanmaya karar verirseniz özelliği geri açabilir veya Uygulamayı yeniden yükleyebilirsiniz. Maruz kalma günlüğü özelliğini devre dışı bırakırsanız Uygulama artık enfekte olan bir kullanıcı ile temas halinde olup olmadığınızı kontrol etmez. Cihazınızın rastgele kimlik göndermesini ve almasını durdurmak isterseniz de akıllı telefonunuzun ayarlarında COVID-19\'a Maruz Kalma Günlüğü özelliğini devre dışı bırakmanız gerekir. Size ait olan ve diğer akıllı telefonlardan alınan maruz kalma günlüğündeki rastgele kimliklerin Uygulamada silinmeyeceğini unutmayın. Akıllı telefonunuzun ayarlarında yalnızca maruz kalma günlüğünde tutulan verileri kalıcı olarak silebilirsiniz."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Uygulamanın gizlilik bildirimini (maruz kalma günlüğü özelliği için gerçekleştirilen veri işlemeye ilişkin açıklama dahil) menüde \"Veri Gizliliği Bilgileri\" başlığında bulabilirsiniz."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_button_next">"Maruz Kalma Günlüğünü Etkinleştir"</string>
     <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined -->
@@ -495,7 +495,7 @@
     <string name="sixteen_title_text">"Yaş Sınırı: 16 ve Üzeri"</string>
 
     <!-- XACT: onboarding(sixteen) title -->
-    <string name="sixteen_description_text">"Uygulama, Almanya\'da yaşayan ve 16 yaş ve üzerindeki kişiler için hazırlanmıştır."</string>
+    <string name="sixteen_description_text">"Bu uygulama, 16 yaş ve üzerinde olan ve Almanya\'da yaşayan kişilerin kullanması için hazırlanmıştır."</string>
 
 
     <!-- ####################################
@@ -541,7 +541,9 @@
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
     <string name="settings_tracing_status_location_headline">"Konum eriÅŸimine izin ver"</string>
     <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled -->
-    <string name="settings_tracing_status_location_body">"Konumunuza erişilemiyor. Bluetooth\'u kullanmak için Google ve/veya Android\'in cihazınızın konumuna erişmesi gerekiyor."</string>
+    <string name="settings_tracing_status_location_body">"Konum hizmetlerinizi etkinleştirin. Bluetooth Düşük Enerji işlevi ile fiziksel mesafeleri hesaplamak için konum hizmetlerinin etkinleştirilmesi gerekir ancak konumunuza erişmez. Daha fazla bilgi için lütfen SSS sayfamıza bakın."</string>
+    <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL -->
+    <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string>
     <!-- XBUT: settings(tracing) - go to operating system settings button on card - location -->
     <string name="settings_tracing_status_location_button">"Cihaz Ayarlarını Aç"</string>
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
@@ -740,10 +742,14 @@
     <!-- XBUT: Positive button for generic web request error -->
     <string name="submission_error_dialog_web_generic_error_button_positive">"Geri"</string>
 
-    <!-- XHED: Dialog title for already paired test error -->
+    <!-- XHED: Dialog title for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_title">"QR kod geçersiz"</string>
-    <!-- XMSG: Dialog body for already paired test error -->
+    <!-- XMSG: Dialog body for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_body">"QR kod geçersiz veya başka bir akıllı telefona zaten kaydedilmiş. QR kod geçerli olsun veya olmasın test sonucunuzu test merkezinden veya laboratuvardan alacaksınız. COVID-19 tanısı alırsanız kamu sağlığı yetkilisi tarafından bilgilendirileceksiniz."</string>
+    <!-- XHED: Dialog title for already paired test error: tan -->
+    <string name="submission_error_dialog_web_test_paired_title_tan">"TAN geçersiz"</string>
+    <!-- XMSG: Dialog body for already paired test via tan - error: tan -->
+    <string name="submission_error_dialog_web_test_paired_body_tan">"TAN geçersiz veya zaten kullanılmış. Daha fazla bilgi için \"TAN Talebi\" bölümünün altında listelenen numarayı arayın."</string>
     <!-- XBUT: Positive button for already paired test error -->
     <string name="submission_error_dialog_web_test_paired_button_positive">"Geri"</string>
 
@@ -768,6 +774,15 @@
     <!-- XBUT: Positive button for submission tan redeemed -->
     <string name="submission_error_dialog_web_tan_redeemed_button_positive">"Tamam"</string>
 
+    <!-- XHED: Dialog title for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_title">"Ä°ptal etmek istiyor musunuz?"</string>
+    <!-- XMSG: Dialog body for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_body">"GiriÅŸleriniz kaydedilmeyecektir."</string>
+    <!-- XBUT: Positive button for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_button_positive">"Evet"</string>
+    <!-- XBUT: Negative button for keys submission process cancellation -->
+    <string name="submission_error_dialog_confirm_cancellation_button_negative">"Hayır"</string>
+
     <!-- Permission Rationale Dialog -->
     <!-- XHED: Dialog headline QR Scan permission rationale  -->
     <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Kamera yetkisi gereklidir"</string>
@@ -869,9 +884,9 @@
     <!-- XACT: Submission Tan page title -->
     <string name="submission_tan_accessibility_title">"TAN giriÅŸi"</string>
     <!-- YTXT: Error text for the tan submission page -->
-    <string name="submission_tan_error">"TAN geçersiz, lütfen girişinizi kontrol edin."</string>
+    <string name="submission_tan_error">"TAN geçersiz. Lütfen girişinizi kontrol edin."</string>
     <!-- YTXT: Error text for the tan submission page (wrong characters) -->
-    <string name="submission_tan_character_error">"Giriş geçersiz. Lütfen girişinizi kontrol edin."</string>
+    <string name="submission_tan_character_error">"Girişiniz geçersiz karakterler içeriyor. Lütfen girişinizi kontrol edin."</string>
 
     <!-- Submission Intro -->
     <!-- XHED: Page title for menu at the start of the submission process  -->
@@ -931,9 +946,9 @@
     <!-- XHED: Title for the privacy card-->
     <string name="submission_positive_other_warning_privacy_title">"Veri GizliliÄŸi"</string>
     <!-- YTXT: Body text for the privacy card-->
-    <string name="submission_positive_other_warning_privacy_body">"\"Kabul et\" seçeneğine dokunduğunuzda, Uygulamanın pozitif test sonucunuzu son 14 güne ait rastgele kimliklerinizle birlikte uygulamanın sunucu sistemine göndermesine izin vermiş olursunuz, bu sayede maruz kalma günlüğünü etkinleştirmiş olan diğer Uygulama kullanıcıları otomatik şekilde bilgilendirilebilir. İletilen rastgele kimlikler, kimliğiniz ya da kişiliğinize ilişkin sonuç çıkartacak hiçbir bilgi içermez. \n\nTest sonucunuzun Uygulama aracılığıyla iletilmesi, isteğe bağlıdır. Test sonucunuzu iletmezseniz size hiçbir dezavantajı olmaz. Uygulamayı kullanıp kullanmadığınızı ve nasıl kullandığınızı anlayamadığımız ve kontrol edemediğimiz için enfeksiyonu bulaştırıp bulaştırmadığınızı sizden başka kimse öğrenemez.\n\nUygulamayı silerek, onayınızı dilediğinizde geri alabilirsiniz. Onayın geri alınmasıyla, geri almaya kadar yapılmış veri işlemelerin hukuka uygunlukları bu durumdan etkilenmez. \"Veri Gizliliği Bilgileri\" menüsünden diğer bilgilere ulaşabilirsiniz."</string>
+    <string name="submission_positive_other_warning_privacy_body">"\"Kabul Et\" seçeneğine dokunduğunuzda, Uygulamanın pozitif test sonucunuzu son 14 güne ait rastgele kimliklerinizle birlikte uygulamanın sunucu sistemine göndermesine izin vermiş olursunuz, bu sayede maruz kalma günlüğünü etkinleştirmiş olan diğer Uygulama kullanıcıları otomatik şekilde bilgilendirilebilir. İletilen rastgele kimlikler, kimliğiniz ya da kişiliğinize ilişkin sonuç çıkartacak hiçbir bilgi içermez. \n\nTest sonucunuzun Uygulama aracılığıyla iletilmesi, isteğe bağlıdır. Test sonucunuzu iletmezseniz size hiçbir dezavantajı olmaz. Uygulamayı kullanıp kullanmadığınızı ve nasıl kullandığınızı anlayamadığımız ve kontrol edemediğimiz için enfeksiyonu bulaştırıp bulaştırmadığınızı sizden başka kimse öğrenemez.\n\nUygulamayı silerek, onayınızı dilediğinizde geri alabilirsiniz. Onayın geri alınmasıyla, geri almaya kadar yapılmış veri işlemelerin hukuka uygunlukları bu durumdan etkilenmez. \"Veri Gizliliği\" menüsünden diğer bilgilere ulaşabilirsiniz."</string>
     <!-- XBUT: other warning continue button -->
-    <string name="submission_positive_other_warning_button">"Sonraki"</string>
+    <string name="submission_positive_other_warning_button">"Kabul Et"</string>
     <!-- XACT: other warning - illustration description, explanation image -->
     <string name="submission_positive_other_illustration_description">"Bir cihaz şifrelenmiş pozitif test tanısını sisteme aktarır."</string>
 
@@ -961,7 +976,33 @@
     <!-- XBUT: submission finished button -->
     <string name="submission_done_button_done">"Tamamlandı"</string>
     <!-- XACT: submission finished - illustration description, explanation image -->
-    <string name="submission_done_illustration_description">"Bir kişi test sonucunu paylaştığı için gruptaki herkes gülüyor."</string>
+    <string name="submission_done_illustration_description">"Son birkaç günde aşağıdaki belirtilerden birini veya daha fazlasını yaşadınız mı?"</string>
+
+    <!-- Submission Symptoms -->
+    <!-- XHED: Page title for symptom screens -->
+    <string name="submission_symptom_title">"Belirtiler"</string>
+    <!-- YTXT: headline text for initial symptom screen -->
+    <string name="submission_symptom_initial_headline">"Son birkaç günde aşağıdaki belirtilerden birini veya daha fazlasını yaşadınız mı?"</string>
+    <!-- YTXT: Bullet points for symptoms -->
+    <string-array name="submission_symptom_symptom_bullets">
+        <item>"Artan vücut sıcaklığı veya ateş"</item>
+        <item>"Nefes darlığı"</item>
+        <item>"Koku/tat kaybı"</item>
+        <item>"Öksürük"</item>
+        <item>"Burun akıntısı"</item>
+        <item>"Boğaz ağrısı"</item>
+        <item>"Baş ağrısı ve kol/bacak ağrısı"</item>
+        <item>"Genel zayıflık ve bitkinlik"</item>
+    </string-array>
+    <!-- XBUT: symptom initial screen yes button -->
+    <string name="submission_symptom_positive_button">"Evet"</string>
+    <!-- XBUT:  symptom initial screen no button -->
+    <string name="submission_symptom_negative_button">"Hayır"</string>
+    <!-- XBUT:  symptom initial screen no information button -->
+    <string name="submission_symptom_no_information_button">"Yorum yok"</string>
+    <!-- XBUT:  symptom initial screen continue button -->
+    <string name="submission_symptom_further_button">"Sonraki"</string>
+
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
@@ -992,6 +1033,22 @@
     <!-- XACT: Content Description for submission contact step 2 -->
     <string name="submission_contact_step_2_content">"İkinci adımda, TAN\'nizi kullanarak testinizi uygulamaya kaydedersiniz."</string>
 
+    <!-- Submission Symptom Calendar -->
+    <!-- XHED: Page title for calendar page in submission symptom flow -->
+    <string name="submission_symptom_calendar_title">"Belirtilerin başlangıcı"</string>
+    <!-- XHED: Page headline for calendar page in symptom submission flow -->
+    <string name="submission_symptom_calendar_headline">"Bu belirtileri ilk kez ne zaman yaşamaya başladınız? "</string>
+    <!-- YTXT: Body text for calendar page in symptom submission flow-->
+    <string name="submission_symptom_calendar_body">"Takvimde tam tarihi seçin veya tam tarihi hatırlayamıyorsanız diğer seçeneklerden birini seçin."</string>
+    <!-- XBUT: symptom calendar screen less than 7 days button -->
+    <string name="submission_symptom_less_seven">"Son 7 gün içinde"</string>
+    <!-- XBUT: symptom calendar screen 1-2 weeks button -->
+    <string name="submission_symptom_one_two_weeks">"1-2 hafta önce"</string>
+    <!-- XBUT: symptom calendar screen more than 2 weeks button -->
+    <string name="submission_symptom_more_two_weeks">"2 haftadan uzun süre önce"</string>
+    <!-- XBUT: symptom calendar screen verify button -->
+    <string name="submission_symptom_verify">"Yorum yok"</string>
+
     <!-- Submission Status Card -->
     <!-- XHED: Page title for the various submission status: fetching -->
     <string name="submission_status_card_title_fetching">"Veriler alınıyor...."</string>
@@ -1055,6 +1112,9 @@
         <item>"Kendinizi iyi hissetmiyorsanız diğer insanları riske atmamak için işe gitmeyin. Belirtileriniz kötüleşirse ilave SARS-CoV-2 testi yapılması gerekebilir."</item>
     </string-array>
 
+    <!-- XBUT Symptoms exact date button -->
+    <string name="symptoms_calendar_exact_date_button">"Tam tarih"</string>
+
     <!-- ####################################
           Button Tooltips for Accessibility
     ###################################### -->
@@ -1083,7 +1143,7 @@
     <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action -->
     <string name="errors_external_action">"Bu işlemi gerçekleştiremezsiniz. Lütfen yardım hattı ile iletişime geçin."</string>
     <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update -->
-    <string name="errors_google_update_needed">"Corona-Warn-App uygulamanız doğru şekilde yüklendi ancak akıllı telefonunuzun işletim sisteminde \"COVID-19 maruz kalma bildirimleri\" hizmeti yok. Bu, Corona-Warn-App\'i kullanamayacağınız anlamına geliyor. Daha fazla bilgi için lütfen SSS sayfamıza bakın: https://www.coronawarn.app/en/faq/"</string>
+    <string name="errors_google_update_needed">"Corona-Warn-App uygulamanız doğru şekilde yüklendi ancak akıllı telefonunuzun işletim sisteminde \"COVID-19 Maruz Kalma Bildirimleri Sistemi\" yok. Bu, Corona-Warn-App\'i kullanamayacağınız anlamına geliyor. Daha fazla bilgi için lütfen SSS sayfamıza bakın: https://www.coronawarn.app/en/faq/"</string>
     <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day -->
     <string name="errors_google_api_error">"Corona-Warn-App doğru şekilde çalışıyor ancak mevcut risk durumunuzu güncelleyemiyoruz. Maruz kalma günlüğü aktif ve doğru şekilde çalışıyor. Daha fazla bilgi için lütfen SSS sayfamıza bakın: https://www.coronawarn.app/en/faq/"</string>
 
diff --git a/Corona-Warn-App/src/main/res/values/colors.xml b/Corona-Warn-App/src/main/res/values/colors.xml
index ec54cc383d4eb0c5cbbb2e6f494338133c8ce141..b0246b90d5372420f43b7d242d32815a7ef2cc14 100644
--- a/Corona-Warn-App/src/main/res/values/colors.xml
+++ b/Corona-Warn-App/src/main/res/values/colors.xml
@@ -53,4 +53,11 @@
     <color name="colorStableHairlineLight">#33FFFFFF</color>
     <color name="colorStableHairlineDark">#3317191A</color>
 
+    <!-- Calendar -->
+    <color name="colorCalendarSelectedDayBackground">#5D6F80</color>
+    <color name="colorCalendarTodayBorder">#007FAD</color>
+    <color name="colorCalendarTodayText">#007FAD</color>
+    <color name="colorCalendarMonthText">#DE000000</color>
+    <color name="colorCalendarLayoutFocusOn">#FF5D6F80</color>
+    <color name="colorCalendarLayoutFocusOff">#F5F5F5</color>
 </resources>
diff --git a/Corona-Warn-App/src/main/res/values/dimens.xml b/Corona-Warn-App/src/main/res/values/dimens.xml
index fb5edbf545e15f2e88acb152e7ad9c9c0967d61c..a411731f9aa6b3d473a92cb90143b7858f813c4e 100644
--- a/Corona-Warn-App/src/main/res/values/dimens.xml
+++ b/Corona-Warn-App/src/main/res/values/dimens.xml
@@ -123,4 +123,13 @@
 
     <dimen name="match_constraint">0dp</dimen>
     <dimen name="no_padding">0dp</dimen>
+
+    <!-- Calendar -->
+    <dimen name="calendar_header_height">72dp</dimen>
+    <dimen name="calendar_header_initial_radius">1dp</dimen>
+    <dimen name="calendar_header_top_radius">4dp</dimen>
+    <dimen name="calendar_header_bottom_radius">4dp</dimen>
+    <dimen name="calendar_layout_stroke">2dp</dimen>
+    <dimen name="calendar_day_size">40dp</dimen>
+    <dimen name="calendar_day_spacing">4dp</dimen>
 </resources>
diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml
index 8ac46316b8176e0b3bbb9f6fc6d5c097cbc7bf9f..968491faafa62ac00cc81854fc2aeb1128bfed66 100644
--- a/Corona-Warn-App/src/main/res/values/strings.xml
+++ b/Corona-Warn-App/src/main/res/values/strings.xml
@@ -427,7 +427,7 @@
     <!-- XHED: onboarding(tracing) - headline for consent information -->
     <string name="onboarding_tracing_headline_consent">"Declaration of Consent"</string>
     <!-- YTXT: onboarding(tracing) - body for consent information -->
-    <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping the “Enable” button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the COVID-19 Exposure Logging functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyzes this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Information”."</string>
+    <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping the “Enable” button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the \"Exposure Notifications\" functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyzes this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Information”."</string>
     <!-- XBUT: onboarding(tracing) - button enable tracing -->
     <string name="onboarding_tracing_button_next">"Activate Exposure Logging"</string>
     <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined -->
@@ -497,7 +497,7 @@
     <string name="sixteen_title_text">"Age Limit: 16 and Up"</string>
 
     <!-- XACT: onboarding(sixteen) title -->
-    <string name="sixteen_description_text">"This app is intended for people who reside in Germany and who are at least 16 years of age."</string>
+    <string name="sixteen_description_text">"The use of this app is intended for persons who are at least 16 years of age and who reside in Germany."</string>
 
 
     <!-- ####################################
@@ -543,9 +543,9 @@
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
     <string name="settings_tracing_status_location_headline">"Allow location access"</string>
     <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled -->
-    <string name="settings_tracing_status_location_body">"Your location cannot be accessed. Google and/or Android requires access to your device\'s location to use Bluetooth."</string>
+    <string name="settings_tracing_status_location_body">"Activate your location services. Bluetooth Low Energy requires activated location services to calculate physical distances, but does not access your location. For further information, please see our FAQ page."</string>
     <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL -->
-    <string name="settings_tracing_status_location_body_url"/>
+    <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string>
     <!-- XBUT: settings(tracing) - go to operating system settings button on card - location -->
     <string name="settings_tracing_status_location_button">"Open Device Settings"</string>
     <!--XHED : settings(tracing) - headline on card about the current status and what to do -->
@@ -724,7 +724,7 @@
     <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German -->
     <string name="information_legal_subtitle_contact_form_non_en_de">"Contact Form in "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"English"</a>" or "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"German"</a></string>
     <!-- XHED: Headline for legal information page, tax section -->
-    <string name="information_legal_headline_taxid">"VAT identification number"</string>
+    <string name="information_legal_headline_taxid">"VAT identification\nnumber"</string>
     <!-- YTXT: subtitle for legal information page, tax section -->
     <string name="information_legal_subtitle_taxid">"DE 165 893 430"</string>
     <!-- XACT: describes illustration -->
@@ -744,14 +744,14 @@
     <!-- XBUT: Positive button for generic web request error -->
     <string name="submission_error_dialog_web_generic_error_button_positive">"Back"</string>
 
-    <!-- XHED: Dialog title for already paired test error -->
+    <!-- XHED: Dialog title for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_title">"QR code is invalid"</string>
-    <!-- XMSG: Dialog body for already paired test error -->
+    <!-- XMSG: Dialog body for already paired test error: qr -->
     <string name="submission_error_dialog_web_test_paired_body">"The QR code is invalid or has been registered on another smartphone already. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with COVID-19, you will be notified by the public health authority."</string>
     <!-- XHED: Dialog title for already paired test error: tan -->
-    <string name="submission_error_dialog_web_test_paired_title_tan" />
+    <string name="submission_error_dialog_web_test_paired_title_tan">"TAN is invalid"</string>
     <!-- XMSG: Dialog body for already paired test via tan - error: tan -->
-    <string name="submission_error_dialog_web_test_paired_body_tan" />
+    <string name="submission_error_dialog_web_test_paired_body_tan">"The TAN is invalid or has already been used. For further information, call the number listed under \"Request TAN\"."</string>
     <!-- XBUT: Positive button for already paired test error -->
     <string name="submission_error_dialog_web_test_paired_button_positive">"Back"</string>
 
@@ -777,13 +777,13 @@
     <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string>
 
     <!-- XHED: Dialog title for keys submission process cancellation -->
-    <string name="submission_error_dialog_confirm_cancellation_title">"Wollen Sie wirklich abbrechen?"</string>
+    <string name="submission_error_dialog_confirm_cancellation_title">"Do you want to cancel?"</string>
     <!-- XMSG: Dialog body for keys submission process cancellation -->
-    <string name="submission_error_dialog_confirm_cancellation_body">"Ihre bisherigen Angaben werden nicht gespeichert."</string>
+    <string name="submission_error_dialog_confirm_cancellation_body">"Your entries will not be saved."</string>
     <!-- XBUT: Positive button for keys submission process cancellation -->
-    <string name="submission_error_dialog_confirm_cancellation_button_positive">"Ja"</string>
+    <string name="submission_error_dialog_confirm_cancellation_button_positive">"Yes"</string>
     <!-- XBUT: Negative button for keys submission process cancellation -->
-    <string name="submission_error_dialog_confirm_cancellation_button_negative">"Nein"</string>
+    <string name="submission_error_dialog_confirm_cancellation_button_negative">"No"</string>
 
     <!-- Permission Rationale Dialog -->
     <!-- XHED: Dialog headline QR Scan permission rationale  -->
@@ -886,9 +886,9 @@
     <!-- XACT: Submission Tan page title -->
     <string name="submission_tan_accessibility_title">"TAN entry"</string>
     <!-- YTXT: Error text for the tan submission page -->
-    <string name="submission_tan_error">"Invalid TAN, please check your entry."</string>
+    <string name="submission_tan_error">"Invalid TAN. Please check your entry."</string>
     <!-- YTXT: Error text for the tan submission page (wrong characters) -->
-    <string name="submission_tan_character_error">"Invalid entry. Please check your entry."</string>
+    <string name="submission_tan_character_error">"Your entry contains invalid characters. Please check your entry."</string>
 
     <!-- Submission Intro -->
     <!-- XHED: Page title for menu at the start of the submission process  -->
@@ -948,9 +948,9 @@
     <!-- XHED: Title for the privacy card-->
     <string name="submission_positive_other_warning_privacy_title">"Data Privacy"</string>
     <!-- YTXT: Body text for the privacy card-->
-    <string name="submission_positive_other_warning_privacy_body">"By tapping on “Accept”, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy Information”."</string>
+    <string name="submission_positive_other_warning_privacy_body">"By tapping “Accept”, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy”."</string>
     <!-- XBUT: other warning continue button -->
-    <string name="submission_positive_other_warning_button">"Next"</string>
+    <string name="submission_positive_other_warning_button">"Accept"</string>
     <!-- XACT: other warning - illustration description, explanation image -->
     <string name="submission_positive_other_illustration_description">"A device transmits an encrypted positive test diagnosis to the system."</string>
 
@@ -991,7 +991,33 @@
     <!-- XBUT: submission finished button -->
     <string name="submission_done_button_done">"Done"</string>
     <!-- XACT: submission finished - illustration description, explanation image -->
-    <string name="submission_done_illustration_description">"Everyone in the group is cheering because someone has shared the test result."</string>
+    <string name="submission_done_illustration_description">"Have you experienced one or more of the following symptoms in the past few days?"</string>
+
+    <!-- Submission Symptoms -->
+    <!-- XHED: Page title for symptom screens -->
+    <string name="submission_symptom_title">"Symptoms"</string>
+    <!-- YTXT: headline text for initial symptom screen -->
+    <string name="submission_symptom_initial_headline">"Have you experienced one or more of the following symptoms in the past few days?"</string>
+    <!-- YTXT: Bullet points for symptoms -->
+    <string-array name="submission_symptom_symptom_bullets">
+        <item>"Increased temperature or fever"</item>
+        <item>"Shortness of breath"</item>
+        <item>"Loss of sense of smell/taste"</item>
+        <item>"Cough"</item>
+        <item>"Runny nose"</item>
+        <item>"Sore throat"</item>
+        <item>"Headache and aching limbs"</item>
+        <item>"General weakness and exhaustion"</item>
+    </string-array>
+    <!-- XBUT: symptom initial screen yes button -->
+    <string name="submission_symptom_positive_button">"Yes"</string>
+    <!-- XBUT:  symptom initial screen no button -->
+    <string name="submission_symptom_negative_button">"No"</string>
+    <!-- XBUT:  symptom initial screen no information button -->
+    <string name="submission_symptom_no_information_button">"No comment"</string>
+    <!-- XBUT:  symptom initial screen continue button -->
+    <string name="submission_symptom_further_button">"Next"</string>
+
 
     <!-- Submission Contact -->
     <!-- XHED: Page title for contact page in submission flow -->
@@ -1022,6 +1048,22 @@
     <!-- XACT: Content Description for submission contact step 2 -->
     <string name="submission_contact_step_2_content">"In the second step, you register your test with your TAN in the app."</string>
 
+    <!-- Submission Symptom Calendar -->
+    <!-- XHED: Page title for calendar page in submission symptom flow -->
+    <string name="submission_symptom_calendar_title">"Start of Symptoms"</string>
+    <!-- XHED: Page headline for calendar page in symptom submission flow -->
+    <string name="submission_symptom_calendar_headline">"When did you first start to experience these symptoms? "</string>
+    <!-- YTXT: Body text for calendar page in symptom submission flow-->
+    <string name="submission_symptom_calendar_body">"Select the exact date in the calendar or, if you cannot remember the exact date, choose one of the other options."</string>
+    <!-- XBUT: symptom calendar screen less than 7 days button -->
+    <string name="submission_symptom_less_seven">"In the last 7 days"</string>
+    <!-- XBUT: symptom calendar screen 1-2 weeks button -->
+    <string name="submission_symptom_one_two_weeks">"1-2 weeks ago"</string>
+    <!-- XBUT: symptom calendar screen more than 2 weeks button -->
+    <string name="submission_symptom_more_two_weeks">"More than 2 weeks ago"</string>
+    <!-- XBUT: symptom calendar screen verify button -->
+    <string name="submission_symptom_verify">"No comment"</string>
+
     <!-- Submission Status Card -->
     <!-- XHED: Page title for the various submission status: fetching -->
     <string name="submission_status_card_title_fetching">"Data being retrieved...."</string>
@@ -1085,6 +1127,9 @@
         <item>"Do not go to work if you feel unwell to ensure you do not put other people at risk. If your symptoms worsen, you might need a further SARS-CoV-2 test."</item>
     </string-array>
 
+    <!-- XBUT Symptoms exact date button -->
+    <string name="symptoms_calendar_exact_date_button">"Exact date"</string>
+
     <!-- ####################################
           Button Tooltips for Accessibility
     ###################################### -->
@@ -1113,7 +1158,7 @@
     <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action -->
     <string name="errors_external_action">"You cannot perform this action. Please contact the hotline."</string>
     <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update -->
-    <string name="errors_google_update_needed">"Your Corona-Warn-App is correctly installed, but the \"COVID-19 exposure notifications\" service is not available on your smartphone\'s operating system. This means that you cannot use the Corona-Warn-App. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string>
+    <string name="errors_google_update_needed">"Your Corona-Warn-App is correctly installed, but the \"COVID-19 Exposure Notifications System\" is not available on your smartphone\'s operating system. This means that you cannot use the Corona-Warn-App. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string>
     <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day -->
     <string name="errors_google_api_error">"The Corona-Warn-App is running correctly, but we cannot update your current risk status. Exposure logging remains active and is working correctly. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string>
 
diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml
index 106040033080d838608ef110e1ee9bb4e17dac4b..51dd9c9e93f2e565424502e1e487754f4d5dd475 100644
--- a/Corona-Warn-App/src/main/res/values/styles.xml
+++ b/Corona-Warn-App/src/main/res/values/styles.xml
@@ -140,11 +140,27 @@
         <item name="android:textColor">@color/colorStableLight</item>
     </style>
 
+    <style name="selectionButton" parent="@style/Widget.AppCompat.Button.Borderless">
+        <item name="android:padding">@dimen/card_padding</item>
+        <item name="android:gravity">left</item>
+        <item name="android:background">@drawable/card</item>
+        <item name="fontFamily">sans-serif-medium</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textAllCaps">false</item>
+        <item name="android:textSize">20sp</item>
+        <item name="android:letterSpacing">0.0125</item>
+    </style>
+
+    <style name="targetLayout">
+        <item name="android:padding">@dimen/card_padding</item>
+        <item name="android:background">@drawable/card</item>
+    </style>
+
     <style name="cardGrey">
         <item name="android:background">@drawable/card_dark</item>
     </style>
 
-
     <!-- ####################################
             Grey Body Background
     ###################################### -->
@@ -285,4 +301,28 @@
         <item name="android:textColor">@color/colorStableLight</item>
         <item name="android:textSize">14sp</item>
     </style>
+
+    <!-- ####################################
+            Calendar
+    ###################################### -->
+    <style name="calendarMonthText">
+        <item name="android:textColor">@color/colorCalendarMonthText</item>
+        <item name="android:textSize">@dimen/font_normal</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:letterSpacing">0.1</item>
+    </style>
+
+    <style name="calendarWeekDayNormal">
+        <item name="android:textColor">@color/colorTextPrimary2</item>
+        <item name="android:textSize">@dimen/font_small</item>
+        <item name="android:fontFamily">sans-serif</item>
+        <item name="android:letterSpacing">0.4</item>
+    </style>
+
+    <style name="calendarWeekDaySelected">
+        <item name="android:textColor">@color/colorCalendarTodayText</item>
+        <item name="android:textSize">@dimen/font_small</item>
+        <item name="android:fontFamily">sans-serif-black</item>
+        <item name="android:letterSpacing">2</item>
+    </style>
 </resources>
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5a91e9b4eed50fdb33c859eef3bebe22b406e2dc
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt
@@ -0,0 +1,76 @@
+package de.rki.coronawarnapp.nearby
+
+import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.clearAllMocks
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.impl.annotations.MockK
+import io.mockk.mockk
+import kotlinx.coroutines.runBlocking
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import java.io.File
+
+@Suppress("DEPRECATION")
+class ENFClientTest : BaseTest() {
+
+    @MockK
+    lateinit var googleENFClient: ExposureNotificationClient
+
+    @MockK
+    lateinit var diagnosisKeyProvider: DiagnosisKeyProvider
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any(), any()) } returns true
+    }
+
+    @AfterEach
+    fun teardown() {
+        clearAllMocks()
+    }
+
+    private fun createClient() = ENFClient(
+        googleENFClient = googleENFClient,
+        diagnosisKeyProvider = diagnosisKeyProvider
+    )
+
+    @Test
+    fun `internal enf client is available as workaround`() {
+        val client = createClient()
+        client.internalClient shouldBe googleENFClient
+    }
+
+    @Test
+    fun `provide diagnosis key call is forwarded to the right module`() {
+        val client = createClient()
+        val keyFiles = listOf(File("test"))
+        val configuration = mockk<ExposureConfiguration>()
+        val token = "123"
+
+        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any(), any()) } returns true
+        runBlocking {
+            client.provideDiagnosisKeys(keyFiles, configuration, token) shouldBe true
+        }
+
+        coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any(), any()) } returns false
+        runBlocking {
+            client.provideDiagnosisKeys(keyFiles, configuration, token) shouldBe false
+        }
+
+        coVerify(exactly = 2) {
+            diagnosisKeyProvider.provideDiagnosisKeys(
+                keyFiles,
+                configuration,
+                token
+            )
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2141680366571b7216d7d003b3874eb570a60160
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt
@@ -0,0 +1,200 @@
+@file:Suppress("DEPRECATION")
+
+package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
+
+import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import com.google.android.gms.tasks.OnSuccessListener
+import com.google.android.gms.tasks.Task
+import de.rki.coronawarnapp.util.GoogleAPIVersion
+import io.mockk.MockKAnnotations
+import io.mockk.clearAllMocks
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.mockk
+import kotlinx.coroutines.runBlocking
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import java.io.File
+
+class DefaultDiagnosisKeyProviderTest : BaseTest() {
+    @MockK
+    lateinit var googleENFClient: ExposureNotificationClient
+
+    @MockK
+    lateinit var googleAPIVersion: GoogleAPIVersion
+
+    @MockK
+    lateinit var submissionQuota: SubmissionQuota
+
+    @MockK
+    lateinit var exampleConfiguration: ExposureConfiguration
+    private val exampleKeyFiles = listOf(File("file1"), File("file2"))
+    private val exampleToken = "123e4567-e89b-12d3-a456-426655440000"
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        coEvery { submissionQuota.consumeQuota(any()) } returns true
+
+        val taskResult = mockk<Task<Void>>()
+        every { taskResult.addOnSuccessListener(any()) } answers {
+            val listener = arg<OnSuccessListener<Nothing>>(0)
+            listener.onSuccess(null)
+            taskResult
+        }
+        every { taskResult.addOnFailureListener(any()) } returns taskResult
+        coEvery { googleENFClient.provideDiagnosisKeys(any(), any(), any()) } returns taskResult
+
+        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns true
+    }
+
+    @AfterEach
+    fun teardown() {
+        clearAllMocks()
+    }
+
+    private fun createProvider() = DefaultDiagnosisKeyProvider(
+        googleAPIVersion = googleAPIVersion,
+        submissionQuota = submissionQuota,
+        enfClient = googleENFClient
+    )
+
+    @Test
+    fun `legacy key provision is used on older ENF versions`() {
+        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns false
+
+        val provider = createProvider()
+
+        runBlocking {
+            provider.provideDiagnosisKeys(exampleKeyFiles, exampleConfiguration, exampleToken)
+        }
+
+        coVerify(exactly = 0) {
+            googleENFClient.provideDiagnosisKeys(
+                exampleKeyFiles, exampleConfiguration, exampleToken
+            )
+        }
+
+        coVerify(exactly = 1) {
+            googleENFClient.provideDiagnosisKeys(
+                listOf(exampleKeyFiles[0]), exampleConfiguration, exampleToken
+            )
+            googleENFClient.provideDiagnosisKeys(
+                listOf(exampleKeyFiles[1]), exampleConfiguration, exampleToken
+            )
+            submissionQuota.consumeQuota(2)
+        }
+    }
+
+    @Test
+    fun `normal key provision is used on newer ENF versions`() {
+        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns true
+
+        val provider = createProvider()
+
+        runBlocking {
+            provider.provideDiagnosisKeys(exampleKeyFiles, exampleConfiguration, exampleToken)
+        }
+
+        coVerify(exactly = 1) {
+            googleENFClient.provideDiagnosisKeys(any(), any(), any())
+            googleENFClient.provideDiagnosisKeys(
+                exampleKeyFiles, exampleConfiguration, exampleToken
+            )
+            submissionQuota.consumeQuota(1)
+        }
+    }
+
+    @Test
+    fun `passing an a null configuration leads to constructing a fallback from defaults`() {
+        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns true
+
+        val provider = createProvider()
+        val fallback = ExposureConfiguration.ExposureConfigurationBuilder().build()
+
+        runBlocking {
+            provider.provideDiagnosisKeys(exampleKeyFiles, null, exampleToken)
+        }
+
+        coVerify(exactly = 1) {
+            googleENFClient.provideDiagnosisKeys(any(), any(), any())
+            googleENFClient.provideDiagnosisKeys(exampleKeyFiles, fallback, exampleToken)
+        }
+    }
+
+    @Test
+    fun `passing an a null configuration leads to constructing a fallback from defaults, legacy`() {
+        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns false
+
+        val provider = createProvider()
+        val fallback = ExposureConfiguration.ExposureConfigurationBuilder().build()
+
+        runBlocking {
+            provider.provideDiagnosisKeys(exampleKeyFiles, null, exampleToken)
+        }
+
+        coVerify(exactly = 1) {
+            googleENFClient.provideDiagnosisKeys(
+                listOf(exampleKeyFiles[0]), fallback, exampleToken
+            )
+            googleENFClient.provideDiagnosisKeys(
+                listOf(exampleKeyFiles[1]), fallback, exampleToken
+            )
+            submissionQuota.consumeQuota(2)
+        }
+    }
+
+    @Test
+    fun `quota is consumed silenently`() {
+        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns true
+        coEvery { submissionQuota.consumeQuota(any()) } returns false
+
+        val provider = createProvider()
+
+        runBlocking {
+            provider.provideDiagnosisKeys(exampleKeyFiles, exampleConfiguration, exampleToken)
+        }
+
+        coVerify(exactly = 1) {
+            googleENFClient.provideDiagnosisKeys(any(), any(), any())
+            googleENFClient.provideDiagnosisKeys(
+                exampleKeyFiles, exampleConfiguration, exampleToken
+            )
+            submissionQuota.consumeQuota(1)
+        }
+    }
+
+    @Test
+    fun `quota is consumed silently, legacy`() {
+        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns false
+        coEvery { submissionQuota.consumeQuota(any()) } returns false
+
+        val provider = createProvider()
+
+        runBlocking {
+            provider.provideDiagnosisKeys(exampleKeyFiles, exampleConfiguration, exampleToken)
+        }
+
+        coVerify(exactly = 0) {
+            googleENFClient.provideDiagnosisKeys(
+                exampleKeyFiles, exampleConfiguration, exampleToken
+            )
+        }
+
+        coVerify(exactly = 1) {
+            googleENFClient.provideDiagnosisKeys(
+                listOf(exampleKeyFiles[0]), exampleConfiguration, exampleToken
+            )
+            googleENFClient.provideDiagnosisKeys(
+                listOf(exampleKeyFiles[1]), exampleConfiguration, exampleToken
+            )
+            submissionQuota.consumeQuota(2)
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuotaTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuotaTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c5d7238a84bd7dea1318173e73841f09ee74bbdc
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuotaTest.kt
@@ -0,0 +1,228 @@
+package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
+
+import de.rki.coronawarnapp.nearby.ENFClientLocalData
+import de.rki.coronawarnapp.util.TimeStamper
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.clearAllMocks
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.verify
+import kotlinx.coroutines.runBlocking
+import org.joda.time.Duration
+import org.joda.time.Instant
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class SubmissionQuotaTest : BaseTest() {
+    @MockK
+    lateinit var enfData: ENFClientLocalData
+
+    @MockK
+    lateinit var timeStamper: TimeStamper
+
+    private var testStorageCurrentQuota = SubmissionQuota.DEFAULT_QUOTA
+    private var testStorageLastQuotaReset = Instant.parse("2020-08-01T01:00:00.000Z")
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        every { enfData.currentQuota = any() } answers {
+            testStorageCurrentQuota = arg(0)
+            Unit
+        }
+        every { enfData.currentQuota } answers {
+            testStorageCurrentQuota
+        }
+        every { enfData.lastQuotaResetAt } answers {
+            testStorageLastQuotaReset
+        }
+        every { enfData.lastQuotaResetAt = any() } answers {
+            testStorageLastQuotaReset = arg(0)
+            Unit
+        }
+        every { timeStamper.nowUTC } returns Instant.parse("2020-08-01T23:00:00.000Z")
+    }
+
+    @AfterEach
+    fun teardown() {
+        clearAllMocks()
+    }
+
+    private fun createQuota() = SubmissionQuota(
+        enfData = enfData,
+        timeStamper = timeStamper
+    )
+
+    @Test
+    fun `first init sets a sane default quota`() {
+        // The default lastQuotaReset is at 0L EPOCH Millis
+        testStorageLastQuotaReset = Instant.EPOCH
+
+        val quota = createQuota()
+
+        runBlocking {
+            quota.consumeQuota(5) shouldBe true
+        }
+
+        coVerify { enfData.currentQuota = 20 }
+
+        // Reset to 20, then consumed 5
+        testStorageCurrentQuota shouldBe 15
+    }
+
+    @Test
+    fun `quota consumption return true if quota was available`() {
+        testStorageCurrentQuota shouldBe 20
+
+        val quota = createQuota()
+
+        runBlocking {
+            quota.consumeQuota(10) shouldBe true
+            quota.consumeQuota(10) shouldBe true
+            quota.consumeQuota(10) shouldBe false
+            quota.consumeQuota(1) shouldBe false
+        }
+
+        verify(exactly = 4) { timeStamper.nowUTC }
+    }
+
+    @Test
+    fun `consumption of 0 quota is handled`() {
+        val quota = createQuota()
+
+        runBlocking {
+            quota.consumeQuota(0) shouldBe true
+            quota.consumeQuota(20) shouldBe true
+            quota.consumeQuota(0) shouldBe true
+            quota.consumeQuota(1) shouldBe false
+        }
+    }
+
+    @Test
+    fun `partial consumption is not possible`() {
+        testStorageCurrentQuota shouldBe 20
+
+        val quota = createQuota()
+
+        runBlocking {
+            quota.consumeQuota(18) shouldBe true
+            quota.consumeQuota(1) shouldBe true
+            quota.consumeQuota(2) shouldBe false
+        }
+    }
+
+    @Test
+    fun `quota consumption automatically fills up quota if possible`() {
+        val quota = createQuota()
+
+        // Reset is at 00:00:00UTC, we trigger at 1 milisecond after midnight
+        val timeTravelTarget = Instant.parse("2020-12-24T00:00:00.001Z")
+
+        runBlocking {
+            quota.consumeQuota(20) shouldBe true
+            quota.consumeQuota(20) shouldBe false
+
+            every { timeStamper.nowUTC } returns timeTravelTarget
+
+            quota.consumeQuota(20) shouldBe true
+            quota.consumeQuota(1) shouldBe false
+        }
+
+        coVerify(exactly = 1) { enfData.currentQuota = 20 }
+        verify(exactly = 4) { timeStamper.nowUTC }
+        verify(exactly = 1) { enfData.lastQuotaResetAt = timeTravelTarget }
+    }
+
+    @Test
+    fun `quota fill up is at midnight`() {
+        testStorageCurrentQuota = 20
+        testStorageLastQuotaReset = Instant.parse("2020-12-24T23:00:00.000Z")
+        val startTime = Instant.parse("2020-12-24T23:59:59.998Z")
+        every { timeStamper.nowUTC } returns startTime
+
+        val quota = createQuota()
+
+        runBlocking {
+            quota.consumeQuota(20) shouldBe true
+            quota.consumeQuota(1) shouldBe false
+
+            every { timeStamper.nowUTC } returns startTime.plus(1)
+            quota.consumeQuota(1) shouldBe false
+
+            every { timeStamper.nowUTC } returns startTime.plus(2)
+            quota.consumeQuota(1) shouldBe false
+
+            every { timeStamper.nowUTC } returns startTime.plus(3)
+            quota.consumeQuota(1) shouldBe true
+
+            every { timeStamper.nowUTC } returns startTime.plus(4)
+            quota.consumeQuota(20) shouldBe false
+
+            every { timeStamper.nowUTC } returns startTime.plus(3).plus(Duration.standardDays(1))
+            quota.consumeQuota(20) shouldBe true
+        }
+    }
+
+    @Test
+    fun `large time gaps are no issue`() {
+        val startTime = Instant.parse("2020-12-24T20:00:00.000Z")
+
+        runBlocking {
+            every { timeStamper.nowUTC } returns startTime
+            val quota = createQuota()
+            quota.consumeQuota(17) shouldBe true
+        }
+
+        runBlocking {
+            every { timeStamper.nowUTC } returns startTime.plus(Duration.standardDays(365))
+            val quota = createQuota()
+            quota.consumeQuota(20) shouldBe true
+            quota.consumeQuota(1) shouldBe false
+        }
+
+        runBlocking {
+            every { timeStamper.nowUTC } returns startTime.plus(Duration.standardDays(365 * 2))
+            val quota = createQuota()
+            quota.consumeQuota(17) shouldBe true
+        }
+        runBlocking {
+            every { timeStamper.nowUTC } returns startTime.plus(Duration.standardDays(365 * 3))
+            val quota = createQuota()
+            quota.consumeQuota(3) shouldBe true
+            quota.consumeQuota(17) shouldBe true
+            quota.consumeQuota(1) shouldBe false
+        }
+    }
+
+    @Test
+    fun `reverse timetravel is handled `() {
+        testStorageLastQuotaReset = Instant.parse("2020-12-24T23:00:00.000Z")
+        val startTime = Instant.parse("2020-12-24T23:59:59.999Z")
+        every { timeStamper.nowUTC } returns startTime
+
+        val quota = createQuota()
+
+        runBlocking {
+            quota.consumeQuota(20) shouldBe true
+            quota.consumeQuota(1) shouldBe false
+
+            // Go forward and get a reset
+            every { timeStamper.nowUTC } returns startTime.plus(Duration.standardHours(1))
+            quota.consumeQuota(20) shouldBe true
+            quota.consumeQuota(1) shouldBe false
+
+            // Go backwards and don't gain a reset
+            every { timeStamper.nowUTC } returns startTime.minus(Duration.standardHours(1))
+            quota.consumeQuota(1) shouldBe false
+
+            // Go forward again, but no new reset happens
+            every { timeStamper.nowUTC } returns startTime.plus(Duration.standardHours(1))
+            quota.consumeQuota(1) shouldBe false
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/ScanResultTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/ScanResultTest.kt
index 2f7e78179372d2c27c2d55694274a65f0a44486b..ee4cd09b339d00404b05056550bb3403939be060 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/ScanResultTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/ScanResultTest.kt
@@ -23,7 +23,7 @@ class ScanResultTest {
 
     @Test
     fun containsValidGUID() {
-        //valid test
+        // valid test
         scanResult = QRScanResult("https://localhost/?$guid")
         scanResult.isValid shouldBe true
 
@@ -51,4 +51,3 @@ class ScanResultTest {
         QRScanResult("https://localhost/?$guid").guid shouldBe guid
     }
 }
-
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt
index f1d222553e27a11b1f4dfbab4cbb86add4466170..4768cb8c0beb02c4c1bc6d820d5b2b6b44ca0740 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt
@@ -6,6 +6,7 @@ import de.rki.coronawarnapp.http.WebRequestBuilder
 import de.rki.coronawarnapp.http.playbook.BackgroundNoise
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.storage.SubmissionRepository
+import de.rki.coronawarnapp.submission.Symptoms
 import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction
 import de.rki.coronawarnapp.util.formatter.TestResult
 import io.mockk.MockKAnnotations
@@ -33,6 +34,8 @@ class SubmissionServiceTest {
     @MockK
     private lateinit var backgroundNoise: BackgroundNoise
 
+    private val symptoms = Symptoms(Symptoms.StartOf.OneToTwoWeeksAgo, Symptoms.Indication.POSITIVE)
+
     @Before
     fun setUp() {
         MockKAnnotations.init(this)
@@ -136,17 +139,17 @@ class SubmissionServiceTest {
     @Test(expected = NoRegistrationTokenSetException::class)
     fun submitExposureKeysWithoutRegistrationTokenFails() {
         runBlocking {
-            SubmissionService.asyncSubmitExposureKeys(listOf())
+            SubmissionService.asyncSubmitExposureKeys(listOf(), symptoms)
         }
     }
 
     @Test
     fun submitExposureKeysSucceeds() {
         every { LocalData.registrationToken() } returns registrationToken
-        coEvery { SubmitDiagnosisKeysTransaction.start(registrationToken, any()) } just Runs
+        coEvery { SubmitDiagnosisKeysTransaction.start(registrationToken, any(), symptoms) } just Runs
 
         runBlocking {
-            SubmissionService.asyncSubmitExposureKeys(listOf())
+            SubmissionService.asyncSubmitExposureKeys(listOf(), symptoms)
         }
     }
 
@@ -162,5 +165,4 @@ class SubmissionServiceTest {
             LocalData.devicePairingSuccessfulTimestamp(0L)
         }
     }
-
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculationsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculationsTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..eb5801c317ef42a1d5f3fc3cde27787ef1a20227
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculationsTest.kt
@@ -0,0 +1,100 @@
+package de.rki.coronawarnapp.submission
+
+import KeyExportFormat
+import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+
+class ExposureKeyHistoryCalculationsTest {
+
+    private lateinit var instance: ExposureKeyHistoryCalculations
+    private lateinit var converter: KeyConverter
+
+    @Before
+    fun setUp() {
+        converter = object : KeyConverter {
+            override fun toExternalFormat(
+                key: TemporaryExposureKey,
+                riskValue: Int
+            ) =
+                KeyExportFormat.TemporaryExposureKey.newBuilder()
+                    .setRollingStartIntervalNumber(riskValue * 10)
+                    .build()
+        }
+        instance = ExposureKeyHistoryCalculations(TransmissionRiskVectorDeterminator(), converter)
+    }
+
+    @Test
+    fun test_limitKeyCount() {
+        val rollingStartIntervalNumber = 0
+        createKey(rollingStartIntervalNumber)
+        Assert.assertEquals(0, instance.limitKeyCount(emptyList<String>()).size)
+        Assert.assertEquals(
+            7, instance.limitKeyCount(
+                listOf(
+                    "1",
+                    "2",
+                    "3",
+                    "4",
+                    "5",
+                    "6",
+                    "7"
+                )
+            ).size
+        )
+        Assert.assertEquals(
+            14, instance.limitKeyCount(
+                listOf(
+                    "1",
+                    "2",
+                    "3",
+                    "4",
+                    "5",
+                    "6",
+                    "7",
+                    "8",
+                    "9",
+                    "10",
+                    "11",
+                    "12",
+                    "13",
+                    "14",
+                    "15"
+                )
+            ).size
+        )
+    }
+
+    @Test
+    fun test_toSortedHistory() {
+        Assert.assertArrayEquals(
+            intArrayOf(8, 4, 3, 2, 1), instance.toSortedHistory(
+                listOf(
+                    createKey(3),
+                    createKey(8),
+                    createKey(1),
+                    createKey(2),
+                    createKey(4)
+                )
+            ).map { it.rollingStartIntervalNumber }.toTypedArray().toIntArray()
+        )
+    }
+
+    @Test
+    fun test_toExternalFormat() {
+        Assert.assertArrayEquals(
+            intArrayOf(10, 20), instance.toExternalFormat(
+                listOf(
+                    createKey(0),
+                    createKey(1)
+                ),
+                TransmissionRiskVector(intArrayOf(0, 1, 2))
+            ).map { it.rollingStartIntervalNumber }.toTypedArray().toIntArray()
+        )
+    }
+
+    private fun createKey(rollingStartIntervalNumber: Int) =
+        TemporaryExposureKey.TemporaryExposureKeyBuilder()
+            .setRollingStartIntervalNumber(rollingStartIntervalNumber).build()
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminatorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminatorTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5c8a5fe29d41ae794f6ebbccf529a21b1fd723ae
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminatorTest.kt
@@ -0,0 +1,28 @@
+package de.rki.coronawarnapp.submission
+
+import org.junit.Assert
+import org.junit.Test
+
+class TransmissionRiskVectorDeterminatorTest {
+
+    @Test
+    fun test_determine() {
+        Assert.assertArrayEquals(
+            intArrayOf(5, 6, 7, 7, 7, 6, 4, 3, 2, 1, 1, 1, 1, 1, 1),
+            TransmissionRiskVectorDeterminator().determine(
+                Symptoms(
+                    null, Symptoms.Indication.NO_INFORMATION
+                )
+            ).raw
+        )
+    }
+
+    @Test
+    fun test_numberOfDays() {
+        Assert.assertEquals(
+            4,
+            TransmissionRiskVectorDeterminator.numberOfDays(
+                0,
+                1000 * 3600 * (24 * 4 + 2)))
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransactionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransactionTest.kt
index 3a7e3e3d4dd2a19ec1b7c52d58454998eba2cd90..930461f6e870ce0033ab76e79a5000d133783e51 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransactionTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransactionTest.kt
@@ -1,27 +1,30 @@
 package de.rki.coronawarnapp.transaction
 
-import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
+import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.util.GoogleAPIVersion
 import de.rki.coronawarnapp.util.di.AppInjector
 import de.rki.coronawarnapp.util.di.ApplicationComponent
+import io.mockk.MockKAnnotations
 import io.kotest.matchers.shouldBe
 import io.mockk.Runs
+import io.mockk.clearAllMocks
 import io.mockk.coEvery
+import io.mockk.coVerify
 import io.mockk.coVerifyOrder
 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.unmockkAll
 import kotlinx.coroutines.runBlocking
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
 import org.joda.time.Instant
 import org.joda.time.LocalDate
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
 import java.io.File
 import java.nio.file.Paths
 import java.util.Date
@@ -32,13 +35,19 @@ import java.util.UUID
  */
 class RetrieveDiagnosisKeysTransactionTest {
 
-    @Before
+    @MockK
+    lateinit var mockEnfClient: ENFClient
+
+    @BeforeEach
     fun setUp() {
+        MockKAnnotations.init(this)
+
         mockkObject(AppInjector)
         val appComponent = mockk<ApplicationComponent>().apply {
             every { transRetrieveKeysInjection } returns RetrieveDiagnosisInjectionHelper(
                 TransactionCoroutineScope(),
-                GoogleAPIVersion()
+                GoogleAPIVersion(),
+                mockEnfClient
             )
         }
         every { AppInjector.component } returns appComponent
@@ -49,29 +58,22 @@ class RetrieveDiagnosisKeysTransactionTest {
         mockkObject(LocalData)
 
         coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns true
-        coEvery {
-            InternalExposureNotificationClient.asyncProvideDiagnosisKeys(
-                any(),
-                any(),
-                any()
-            )
-        } returns mockk()
-        coEvery {
-            InternalExposureNotificationClient.getVersion()
-        } returns 17000000L
+
         coEvery { ApplicationConfigurationService.asyncRetrieveExposureConfiguration() } returns mockk()
         every { LocalData.googleApiToken(any()) } just Runs
         every { LocalData.lastTimeDiagnosisKeysFromServerFetch() } returns Date()
         every { LocalData.lastTimeDiagnosisKeysFromServerFetch(any()) } just Runs
         every { LocalData.googleApiToken() } returns UUID.randomUUID().toString()
-        every { LocalData.googleAPIProvideDiagnosisKeysCallCount = any() } just Runs
-        every { LocalData.googleAPIProvideDiagnosisKeysCallCount } returns 0
-        every { LocalData.nextTimeRateLimitingUnlocks = any() } just Runs
-        every { LocalData.nextTimeRateLimitingUnlocks } returns Instant.now()
+    }
+
+    @AfterEach
+    fun cleanUp() {
+        clearAllMocks()
     }
 
     @Test
-    fun testTransactionNoFiles() {
+    fun `unsuccessful ENF submission`() {
+        coEvery { mockEnfClient.provideDiagnosisKeys(any(), any(), any()) } returns false
         val requestedCountries = listOf("DE")
         coEvery {
             RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"](
@@ -81,22 +83,24 @@ class RetrieveDiagnosisKeysTransactionTest {
 
         runBlocking {
             RetrieveDiagnosisKeysTransaction.start(requestedCountries)
+        }
 
-            coVerifyOrder {
-                RetrieveDiagnosisKeysTransaction["executeSetup"]()
-                RetrieveDiagnosisKeysTransaction["executeQuotaCalculation"]()
-                RetrieveDiagnosisKeysTransaction["executeRetrieveRiskScoreParams"]()
-                RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"](
-                    requestedCountries
-                )
-                RetrieveDiagnosisKeysTransaction["executeFetchDateUpdate"](any<Date>())
-            }
+        coVerifyOrder {
+            RetrieveDiagnosisKeysTransaction["executeSetup"]()
+            RetrieveDiagnosisKeysTransaction["executeRetrieveRiskScoreParams"]()
+            RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"](
+                requestedCountries
+            )
+        }
+        coVerify(exactly = 0) {
+            RetrieveDiagnosisKeysTransaction["executeFetchDateUpdate"](any<Date>())
         }
     }
 
     @Test
-    fun testTransactionHasFiles() {
+    fun `successful submission`() {
         val file = Paths.get("src", "test", "resources", "keys.bin").toFile()
+        coEvery { mockEnfClient.provideDiagnosisKeys(listOf(file), any(), any()) } returns true
         val requestedCountries = listOf("DE")
 
         coEvery {
@@ -107,21 +111,16 @@ class RetrieveDiagnosisKeysTransactionTest {
 
         runBlocking {
             RetrieveDiagnosisKeysTransaction.start(requestedCountries)
+        }
 
-            coVerifyOrder {
-                RetrieveDiagnosisKeysTransaction["executeSetup"]()
-                RetrieveDiagnosisKeysTransaction["executeQuotaCalculation"]()
-                RetrieveDiagnosisKeysTransaction["executeRetrieveRiskScoreParams"]()
-                RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"](
-                    requestedCountries
-                )
-                RetrieveDiagnosisKeysTransaction["executeAPISubmission"](
-                    any<String>(),
-                    listOf(file),
-                    any<ExposureConfiguration>()
-                )
-                RetrieveDiagnosisKeysTransaction["executeFetchDateUpdate"](any<Date>())
-            }
+        coVerifyOrder {
+            RetrieveDiagnosisKeysTransaction["executeSetup"]()
+            RetrieveDiagnosisKeysTransaction["executeRetrieveRiskScoreParams"]()
+            RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"](
+                requestedCountries
+            )
+            mockEnfClient.provideDiagnosisKeys(listOf(file), any(), any())
+            RetrieveDiagnosisKeysTransaction["executeFetchDateUpdate"](any<Date>())
         }
     }
 
@@ -129,9 +128,4 @@ class RetrieveDiagnosisKeysTransactionTest {
     fun `conversion from date to localdate`() {
         LocalDate.fromDateFields(Date(0)) shouldBe LocalDate.parse("1970-01-01")
     }
-
-    @After
-    fun cleanUp() {
-        unmockkAll()
-    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransactionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransactionTest.kt
index 25d61722c61202975cab25cf1bcdea121ffe6fd0..6840c334425ae639fc8357eac807863ba3215bf0 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransactionTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransactionTest.kt
@@ -7,6 +7,7 @@ import de.rki.coronawarnapp.http.playbook.BackgroundNoise
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.service.submission.SubmissionService
 import de.rki.coronawarnapp.storage.LocalData
+import de.rki.coronawarnapp.submission.Symptoms
 import de.rki.coronawarnapp.util.di.AppInjector
 import de.rki.coronawarnapp.util.di.ApplicationComponent
 import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
@@ -39,6 +40,8 @@ class SubmitDiagnosisKeysTransactionTest {
     private val authString = "authString"
     private val registrationToken = "123"
 
+    private val symptoms = Symptoms(Symptoms.StartOf.OneToTwoWeeksAgo, Symptoms.Indication.POSITIVE)
+
     @Before
     fun setUp() {
         MockKAnnotations.init(this)
@@ -72,7 +75,7 @@ class SubmitDiagnosisKeysTransactionTest {
         coEvery { webRequestBuilder.asyncSubmitKeysToServer(authString, listOf()) } just Runs
 
         runBlocking {
-            SubmitDiagnosisKeysTransaction.start(registrationToken, listOf())
+            SubmitDiagnosisKeysTransaction.start(registrationToken, listOf(), symptoms)
 
             coVerifyOrder {
                 webRequestBuilder.asyncSubmitKeysToServer(authString, listOf())
@@ -98,7 +101,7 @@ class SubmitDiagnosisKeysTransactionTest {
         } just Runs
 
         runBlocking {
-            SubmitDiagnosisKeysTransaction.start(registrationToken, listOf(key))
+            SubmitDiagnosisKeysTransaction.start(registrationToken, listOf(key), symptoms)
 
             coVerifyOrder {
                 webRequestBuilder.asyncSubmitKeysToServer(authString, any())
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculationTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculationTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ad8e47590f0c812119283aa3f66442855d432736
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculationTest.kt
@@ -0,0 +1,116 @@
+package de.rki.coronawarnapp.ui.calendar
+
+import io.kotest.matchers.shouldBe
+import org.joda.time.DateTime
+import org.joda.time.format.DateTimeFormat
+import org.junit.Test
+
+class CalendarCalculationTest {
+
+    private var pattern = "dd.MM.yyyy"
+    private val formatter = DateTimeFormat.forPattern(pattern)
+
+    @Test
+    fun calculateSameYearSameMonth() {
+        var input = "27.08.2020"
+        val dateTime =
+            DateTime.parse(input, DateTimeFormat.forPattern(pattern))
+        val dates = CalendarCalculation().getDates(dateTime)
+
+        // First day - 3 of August
+        dates.first().date.dayOfMonth shouldBe 3
+        dates.first().date.monthOfYear shouldBe 8
+
+        // Last day - 30 of August
+        dates.last().date.dayOfMonth shouldBe 30
+        dates.last().date.monthOfYear shouldBe 8
+
+        CalendarCalculation().getMonthText(
+            dates.first().date,
+            dates.last().date
+        ) shouldBe "August 2020"
+    }
+
+    @Test
+    fun calculateSameYearDifferentMonth() {
+        var input = "15.09.2020"
+        val dateTime =
+            DateTime.parse(input, DateTimeFormat.forPattern(pattern))
+        val dates = CalendarCalculation().getDates(dateTime)
+
+        // First day - 24 of August
+        dates.first().date.dayOfMonth shouldBe 24
+        dates.first().date.monthOfYear shouldBe 8
+
+        // Last day - 20 of September
+        dates.last().date.dayOfMonth shouldBe 20
+        dates.last().date.monthOfYear shouldBe 9
+
+        CalendarCalculation().getMonthText(
+            dates.first().date,
+            dates.last().date
+        ) shouldBe "August - September 2020"
+    }
+
+    @Test
+    fun calculateDifferentYearDifferentMonth() {
+        var input = "12.01.2021"
+        val dateTime =
+            DateTime.parse(input, DateTimeFormat.forPattern(pattern))
+        val dates = CalendarCalculation().getDates(dateTime)
+
+        // First day - 21 of December 2020
+        dates.first().date.dayOfMonth shouldBe 21
+        dates.first().date.monthOfYear shouldBe 12
+        dates.first().date.year shouldBe 2020
+
+        // Last day - 17 of January 2021
+        dates.last().date.dayOfMonth shouldBe 17
+        dates.last().date.monthOfYear shouldBe 1
+        dates.last().date.year shouldBe 2021
+
+        CalendarCalculation().getMonthText(
+            dates.first().date,
+            dates.last().date
+        ) shouldBe "December 2020 - January 2021"
+    }
+
+    @Test
+    fun calculateEdgeCases() {
+        // new year
+        CalendarCalculation().getDates(DateTime.parse("27.12.2021", formatter)).apply {
+            // First day - 6 of December 2021
+            first().date.dayOfMonth shouldBe 6
+            first().date.monthOfYear shouldBe 12
+            first().date.year shouldBe 2021
+
+            // Last day - 2 of January 2022
+            last().date.dayOfMonth shouldBe 2
+            last().date.monthOfYear shouldBe 1
+            last().date.year shouldBe 2022
+
+            CalendarCalculation().getMonthText(
+                first().date,
+                last().date
+            ) shouldBe "December 2021 - January 2022"
+        }
+
+        // leap year
+        CalendarCalculation().getDates(DateTime.parse("29.02.2024", formatter)).apply {
+            // First day - 5 of February 2024
+            first().date.dayOfMonth shouldBe 5
+            first().date.monthOfYear shouldBe 2
+            first().date.year shouldBe 2024
+
+            // Last day - 2 of March 2024
+            last().date.dayOfMonth shouldBe 3
+            last().date.monthOfYear shouldBe 3
+            last().date.year shouldBe 2024
+
+            CalendarCalculation().getMonthText(
+                first().date,
+                last().date
+            ) shouldBe "February - March 2024"
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleAPIVersionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleAPIVersionTest.kt
index 581282e966e84ea61492fcbb3dd4ad20e198ab2b..110d8cbeed2aef3b469c0355c3a848025f1faadf 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleAPIVersionTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleAPIVersionTest.kt
@@ -40,7 +40,6 @@ internal class GoogleAPIVersionTest {
         runBlockingTest {
             classUnderTest.isAtLeast(GoogleAPIVersion.V16) shouldBe true
         }
-
     }
 
     @Test
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleQuotaCalculatorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleQuotaCalculatorTest.kt
deleted file mode 100644
index 995ed675179badf7985d26df0104a4593f192d00..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleQuotaCalculatorTest.kt
+++ /dev/null
@@ -1,293 +0,0 @@
-package de.rki.coronawarnapp.util
-
-import de.rki.coronawarnapp.storage.LocalData
-import io.mockk.every
-import io.mockk.mockkObject
-import io.mockk.unmockkObject
-import org.joda.time.DateTime
-import org.joda.time.DateTimeUtils
-import org.joda.time.DateTimeZone
-import org.joda.time.Duration
-import org.joda.time.Instant
-import org.joda.time.chrono.GJChronology
-import org.junit.jupiter.api.AfterEach
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import testhelpers.BaseTest
-import timber.log.Timber
-import java.util.concurrent.atomic.AtomicInteger
-import java.util.concurrent.atomic.AtomicLong
-
-internal class GoogleQuotaCalculatorTest : BaseTest() {
-
-    private val timeInTest = DateTimeUtils.currentTimeMillis()
-
-    private lateinit var classUnderTest: GoogleQuotaCalculator
-    private val nextTimeRateLimitingUnlocksInTesting = AtomicLong()
-    private val googleAPIProvideDiagnosisKeysCallCount = AtomicInteger()
-
-    private val defaultIncrementByAmountInTest = 14
-    private val defaultQuotaLimitInTest = 20
-
-    @BeforeEach
-    fun setUpClassUnderTest() {
-        classUnderTest = GoogleQuotaCalculator(
-            incrementByAmount = defaultIncrementByAmountInTest,
-            quotaLimit = defaultQuotaLimitInTest,
-            quotaResetPeriod = Duration.standardHours(24),
-            quotaTimeZone = DateTimeZone.UTC,
-            quotaChronology = GJChronology.getInstanceUTC()
-        )
-        DateTimeUtils.setCurrentMillisFixed(timeInTest)
-
-        // Since LocalData is simple to mock
-        mockkObject(LocalData)
-        every { LocalData.nextTimeRateLimitingUnlocks = any() } answers {
-            nextTimeRateLimitingUnlocksInTesting.set((this.arg(0) as Instant).millis)
-        }
-        every { LocalData.nextTimeRateLimitingUnlocks } answers {
-            Instant.ofEpochMilli(nextTimeRateLimitingUnlocksInTesting.get())
-        }
-        every { LocalData.googleAPIProvideDiagnosisKeysCallCount = any() } answers {
-            googleAPIProvideDiagnosisKeysCallCount.set(this.arg(0))
-        }
-        every { LocalData.googleAPIProvideDiagnosisKeysCallCount } answers {
-            googleAPIProvideDiagnosisKeysCallCount.get()
-        }
-    }
-
-    @Test
-    fun `isAboveQuota false if called initially`() {
-        assertEquals(classUnderTest.hasExceededQuota, false)
-    }
-
-    @Test
-    fun `isAboveQuota true if called above quota limit when calling with amount bigger than one`() {
-        for (callNumber in 1..5) {
-            classUnderTest.calculateQuota()
-            val aboveQuota = classUnderTest.hasExceededQuota
-            Timber.v("call number $callNumber above quota: $aboveQuota")
-            if (callNumber > 1) {
-                assertEquals(true, aboveQuota)
-            } else {
-                assertEquals(false, aboveQuota)
-            }
-        }
-    }
-
-    @Test
-    fun `getProgressTowardsQuota increases with calls to isAboveQuota but is stopped once increased above the quota`() {
-        var latestCallNumberWithoutLimiting = 1
-        for (callNumber in 1..5) {
-            classUnderTest.calculateQuota()
-            val aboveQuota = classUnderTest.hasExceededQuota
-            Timber.v("call number $callNumber above quota: $aboveQuota")
-            val expectedIncrement = callNumber * defaultIncrementByAmountInTest
-            if (expectedIncrement >= defaultQuotaLimitInTest) {
-                assertEquals(
-                    (latestCallNumberWithoutLimiting + 1) * defaultIncrementByAmountInTest,
-                    classUnderTest.getProgressTowardsQuota()
-                )
-            } else {
-                assertEquals(
-                    callNumber * defaultIncrementByAmountInTest,
-                    classUnderTest.getProgressTowardsQuota()
-                )
-                latestCallNumberWithoutLimiting = callNumber
-            }
-        }
-    }
-
-    @Test
-    fun `getProgressTowardsQuota is reset and the quota is not recalculated but isAboveQuota should still be false`() {
-        var latestCallNumberWithoutLimiting = 1
-        for (callNumber in 1..5) {
-            classUnderTest.calculateQuota()
-            val aboveQuota = classUnderTest.hasExceededQuota
-            Timber.v("call number $callNumber above quota: $aboveQuota")
-            val expectedIncrement = callNumber * defaultIncrementByAmountInTest
-            if (expectedIncrement >= defaultQuotaLimitInTest) {
-                assertEquals(
-                    (latestCallNumberWithoutLimiting + 1) * defaultIncrementByAmountInTest,
-                    classUnderTest.getProgressTowardsQuota()
-                )
-            } else {
-                assertEquals(
-                    callNumber * defaultIncrementByAmountInTest,
-                    classUnderTest.getProgressTowardsQuota()
-                )
-                latestCallNumberWithoutLimiting = callNumber
-            }
-        }
-
-        classUnderTest.resetProgressTowardsQuota(0)
-        assertEquals(false, classUnderTest.hasExceededQuota)
-    }
-
-    @Test
-    fun `getProgressTowardsQuota is reset but the reset value is no multiple of incrementByAmount`() {
-        var latestCallNumberWithoutLimiting = 1
-        for (callNumber in 1..5) {
-            classUnderTest.calculateQuota()
-            val aboveQuota = classUnderTest.hasExceededQuota
-            Timber.v("call number $callNumber above quota: $aboveQuota")
-            val expectedIncrement = callNumber * defaultIncrementByAmountInTest
-            if (expectedIncrement >= defaultQuotaLimitInTest) {
-                assertEquals(
-                    (latestCallNumberWithoutLimiting + 1) * defaultIncrementByAmountInTest,
-                    classUnderTest.getProgressTowardsQuota()
-                )
-            } else {
-                assertEquals(
-                    callNumber * defaultIncrementByAmountInTest,
-                    classUnderTest.getProgressTowardsQuota()
-                )
-                latestCallNumberWithoutLimiting = callNumber
-            }
-        }
-
-        assertThrows<IllegalArgumentException> {
-            classUnderTest.resetProgressTowardsQuota(defaultIncrementByAmountInTest + 1)
-        }
-    }
-
-    @Test
-    fun `getProgressTowardsQuota is reset and the quota is not recalculated and the progress should update`() {
-        var latestCallNumberWithoutLimiting = 1
-        for (callNumber in 1..5) {
-            classUnderTest.calculateQuota()
-            val aboveQuota = classUnderTest.hasExceededQuota
-            Timber.v("call number $callNumber above quota: $aboveQuota")
-            val expectedIncrement = callNumber * defaultIncrementByAmountInTest
-            if (expectedIncrement >= defaultQuotaLimitInTest) {
-                assertEquals(
-                    (latestCallNumberWithoutLimiting + 1) * defaultIncrementByAmountInTest,
-                    classUnderTest.getProgressTowardsQuota()
-                )
-            } else {
-                assertEquals(
-                    callNumber * defaultIncrementByAmountInTest,
-                    classUnderTest.getProgressTowardsQuota()
-                )
-                latestCallNumberWithoutLimiting = callNumber
-            }
-        }
-
-        val newProgressAfterReset = 14
-        classUnderTest.resetProgressTowardsQuota(newProgressAfterReset)
-        assertEquals(false, classUnderTest.hasExceededQuota)
-        assertEquals(newProgressAfterReset, classUnderTest.getProgressTowardsQuota())
-    }
-
-    @Test
-    fun `getProgressTowardsQuota is reset and the quota is not recalculated and the progress throws an error because of too high newProgress`() {
-        var latestCallNumberWithoutLimiting = 1
-        var progressBeforeReset: Int? = null
-        for (callNumber in 1..5) {
-            classUnderTest.calculateQuota()
-            val aboveQuota = classUnderTest.hasExceededQuota
-            Timber.v("call number $callNumber above quota: $aboveQuota")
-            val expectedIncrement = callNumber * defaultIncrementByAmountInTest
-            if (expectedIncrement >= defaultQuotaLimitInTest) {
-                progressBeforeReset =
-                    (latestCallNumberWithoutLimiting + 1) * defaultIncrementByAmountInTest
-                assertEquals(
-                    (latestCallNumberWithoutLimiting + 1) * defaultIncrementByAmountInTest,
-                    classUnderTest.getProgressTowardsQuota()
-                )
-            } else {
-                assertEquals(
-                    callNumber * defaultIncrementByAmountInTest,
-                    classUnderTest.getProgressTowardsQuota()
-                )
-                latestCallNumberWithoutLimiting = callNumber
-            }
-        }
-
-        val newProgressAfterReset = defaultQuotaLimitInTest + 1
-        assertThrows<IllegalArgumentException> {
-            classUnderTest.resetProgressTowardsQuota(newProgressAfterReset)
-        }
-        assertEquals(true, classUnderTest.hasExceededQuota)
-        assertEquals(
-            (progressBeforeReset
-                ?: throw IllegalStateException("progressBeforeReset was not set during test")),
-            classUnderTest.getProgressTowardsQuota()
-        )
-    }
-
-    @Test
-    fun `isAboveQuota true if called above quota limit when calling with amount one`() {
-        classUnderTest = GoogleQuotaCalculator(
-            incrementByAmount = 1,
-            quotaLimit = 3,
-            quotaResetPeriod = Duration.standardHours(24),
-            quotaTimeZone = DateTimeZone.UTC,
-            quotaChronology = GJChronology.getInstanceUTC()
-        )
-        for (callNumber in 1..15) {
-            classUnderTest.calculateQuota()
-            val aboveQuota = classUnderTest.hasExceededQuota
-            Timber.v("call number $callNumber above quota: $aboveQuota")
-            if (callNumber > 3) {
-                assertEquals(true, aboveQuota)
-            } else {
-                assertEquals(false, aboveQuota)
-            }
-        }
-    }
-
-    @Test
-    fun `isAboveQuota false if called above quota limit but next day resets quota`() {
-        for (callNumber in 1..5) {
-            classUnderTest.calculateQuota()
-            val aboveQuota = classUnderTest.hasExceededQuota
-            Timber.v("call number $callNumber above quota: $aboveQuota")
-            if (callNumber > 1) {
-                assertEquals(true, aboveQuota)
-            } else {
-                assertEquals(false, aboveQuota)
-            }
-        }
-
-        // Day Change
-        val timeInTestAdvancedByADay = timeInTest + Duration.standardDays(1).millis
-        DateTimeUtils.setCurrentMillisFixed(timeInTestAdvancedByADay)
-        classUnderTest.calculateQuota()
-        val aboveQuotaAfterDayAdvance = classUnderTest.hasExceededQuota
-        Timber.v("above quota after day advance: $aboveQuotaAfterDayAdvance")
-
-        assertEquals(false, aboveQuotaAfterDayAdvance)
-    }
-
-    @Test
-    fun `test if isAfter is affected by Timezone to make sure we do not run into Shifting Errors`() {
-        val testTimeUTC = DateTime(
-            timeInTest,
-            DateTimeZone.UTC
-        ).withChronology(GJChronology.getInstanceUTC())
-        val testTimeGMT = DateTime(
-            timeInTest,
-            DateTimeZone.forID("Etc/GMT+2")
-        ).withChronology(GJChronology.getInstanceUTC())
-
-        assertEquals(testTimeGMT, testTimeUTC)
-        assertEquals(testTimeGMT.millis, testTimeUTC.millis)
-
-        val testTimeUTCAfterGMT = testTimeUTC.plusMinutes(1)
-
-        assertEquals(true, testTimeUTCAfterGMT.isAfter(testTimeGMT))
-
-        val testTimeGMTAfterUTC = testTimeGMT.plusMinutes(1)
-
-        assertEquals(true, testTimeGMTAfterUTC.isAfter(testTimeUTC))
-    }
-
-    @AfterEach
-    fun cleanup() {
-        DateTimeUtils.setCurrentMillisSystem()
-        unmockkObject(LocalData)
-    }
-}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensionsTest.kt
deleted file mode 100644
index 9ffe27e56ca4d9ca4c6e2243be2751397d72cfa8..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensionsTest.kt
+++ /dev/null
@@ -1,124 +0,0 @@
-package de.rki.coronawarnapp.util
-
-import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
-import de.rki.coronawarnapp.util.ProtoFormatConverterExtensions.transformKeyHistoryToExternalFormat
-import org.hamcrest.CoreMatchers
-import org.hamcrest.MatcherAssert
-import org.junit.Test
-
-private const val DEFAULT_TRANSMISSION_RISK_LEVEL = 1
-private const val TRANSMISSION_RISK_DAY_0 = 5
-private const val TRANSMISSION_RISK_DAY_1 = 6
-private const val TRANSMISSION_RISK_DAY_2 = 8
-private const val TRANSMISSION_RISK_DAY_3 = 8
-private const val TRANSMISSION_RISK_DAY_4 = 8
-private const val TRANSMISSION_RISK_DAY_5 = 5
-private const val TRANSMISSION_RISK_DAY_6 = 3
-private const val TRANSMISSION_RISK_DAY_7 = 1
-
-class ProtoFormatConverterExtensionsTest {
-
-    @Test
-    fun areTransmissionRiskLevelsCorrectlyAssigned() {
-
-        val key1 = byteArrayOf(
-            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
-        )
-
-        val diagnosisKeyList = mutableListOf<TemporaryExposureKey>()
-        val numKeys = 13
-        for (pos in 0 until numKeys) {
-            diagnosisKeyList.add(
-                TemporaryExposureKey.TemporaryExposureKeyBuilder()
-                    .setKeyData(key1)
-                    .setRollingStartIntervalNumber(pos * 144)
-                    .setRollingPeriod(144)
-                    .setTransmissionRiskLevel(0)
-                    .build()
-            )
-        }
-
-        val transformedKeyList = diagnosisKeyList.transformKeyHistoryToExternalFormat()
-            .sortedWith(compareBy { it.rollingStartIntervalNumber })
-
-        MatcherAssert.assertThat(
-            transformedKeyList.size,
-            CoreMatchers.equalTo(numKeys)
-        )
-
-        val correctRiskLevels = arrayOf(
-            DEFAULT_TRANSMISSION_RISK_LEVEL,
-            DEFAULT_TRANSMISSION_RISK_LEVEL,
-            DEFAULT_TRANSMISSION_RISK_LEVEL,
-            DEFAULT_TRANSMISSION_RISK_LEVEL,
-            DEFAULT_TRANSMISSION_RISK_LEVEL,
-            DEFAULT_TRANSMISSION_RISK_LEVEL,
-            TRANSMISSION_RISK_DAY_7,
-            TRANSMISSION_RISK_DAY_6,
-            TRANSMISSION_RISK_DAY_5,
-            TRANSMISSION_RISK_DAY_4,
-            TRANSMISSION_RISK_DAY_3,
-            TRANSMISSION_RISK_DAY_2,
-            TRANSMISSION_RISK_DAY_1
-        )
-
-        for (pos in 0 until numKeys) {
-            val key = transformedKeyList[pos]
-            MatcherAssert.assertThat(
-                key.transmissionRiskLevel,
-                CoreMatchers.equalTo(correctRiskLevels[pos])
-            )
-            MatcherAssert.assertThat(
-                key.rollingStartIntervalNumber,
-                CoreMatchers.equalTo(pos * 144)
-            )
-        }
-    }
-
-    @Test
-    fun areTransmissionRiskLevelsCorrectlyAssignedWithOnlyOneKey() {
-
-        val key1 = byteArrayOf(
-            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
-        )
-
-        val diagnosisKeyList = mutableListOf<TemporaryExposureKey>()
-        val numKeys = 1
-        for (pos in 0 until numKeys) {
-            diagnosisKeyList.add(
-                TemporaryExposureKey.TemporaryExposureKeyBuilder()
-                    .setKeyData(key1)
-                    .setRollingStartIntervalNumber(pos * 144)
-                    .setRollingPeriod(144)
-                    .setTransmissionRiskLevel(0)
-                    .build()
-            )
-        }
-
-        val transformedKeyList = diagnosisKeyList.transformKeyHistoryToExternalFormat()
-            .sortedWith(compareBy { it.rollingStartIntervalNumber })
-
-        MatcherAssert.assertThat(
-            transformedKeyList.size,
-            CoreMatchers.equalTo(numKeys)
-        )
-
-        val correctRiskLevels = arrayOf(
-            TRANSMISSION_RISK_DAY_1
-        )
-
-        for (pos in 0 until numKeys) {
-            val key = transformedKeyList[pos]
-            MatcherAssert.assertThat(
-                key.transmissionRiskLevel,
-                CoreMatchers.equalTo(correctRiskLevels[pos])
-            )
-            MatcherAssert.assertThat(
-                key.rollingStartIntervalNumber,
-                CoreMatchers.equalTo(pos * 144)
-            )
-        }
-    }
-}
diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModelTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModelTest.kt
index 5f04e64c371d04d92ade5ef94b9dbcab8ca59c4a..db3450dbfac08368b08b90ffd21c8c49387e5d26 100644
--- a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModelTest.kt
+++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModelTest.kt
@@ -4,6 +4,7 @@ import android.content.Context
 import androidx.lifecycle.SavedStateHandle
 import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
 import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository
+import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction
 import de.rki.coronawarnapp.transaction.RiskLevelTransaction
 import io.kotest.matchers.shouldBe
@@ -12,6 +13,7 @@ import io.mockk.clearAllMocks
 import io.mockk.coEvery
 import io.mockk.coVerify
 import io.mockk.coVerifyOrder
+import io.mockk.every
 import io.mockk.impl.annotations.MockK
 import io.mockk.mockkObject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -29,6 +31,7 @@ class TestRiskLevelCalculationFragmentCWAViewModelTest : BaseTest() {
 
     @MockK lateinit var context: Context
     @MockK lateinit var savedStateHandle: SavedStateHandle
+    @MockK lateinit var enfClient: ENFClient
     @MockK lateinit var exposureNotificationClient: ExposureNotificationClient
     @MockK lateinit var keyCacheRepository: KeyCacheRepository
 
@@ -42,6 +45,7 @@ class TestRiskLevelCalculationFragmentCWAViewModelTest : BaseTest() {
         coEvery { RiskLevelTransaction.start() } returns Unit
 
         coEvery { keyCacheRepository.clear() } returns Unit
+        every { enfClient.internalClient } returns exposureNotificationClient
     }
 
     @AfterEach
@@ -54,7 +58,7 @@ class TestRiskLevelCalculationFragmentCWAViewModelTest : BaseTest() {
             handle = savedStateHandle,
             exampleArg = exampleArgs,
             context = context,
-            exposureNotificationClient = exposureNotificationClient,
+            enfClient = enfClient,
             keyCacheRepository = keyCacheRepository
         )
 
@@ -99,5 +103,4 @@ class TestRiskLevelCalculationFragmentCWAViewModelTest : BaseTest() {
 
         vm.startLocalQRCodeScanEvent.value shouldBe Unit
     }
-
 }