diff --git a/Corona-Warn-App/build.gradle b/Corona-Warn-App/build.gradle
index 948ff9a9f433ca51ceebe8bfe1726be49a643aec..f8ffb33b2ae96d524de4addad7bae3bf4e6d66ec 100644
--- a/Corona-Warn-App/build.gradle
+++ b/Corona-Warn-App/build.gradle
@@ -312,7 +312,6 @@ dependencies {
     androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutineVersion"
 
     // ANDROID STANDARD
-    def nav_version = "2.3.3"
     implementation 'androidx.appcompat:appcompat:1.2.0'
     implementation 'androidx.core:core-ktx:1.5.0'
     implementation 'com.google.android.material:material:1.3.0'
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsFragmentTest.kt
similarity index 95%
rename from Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragmentTest.kt
rename to Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsFragmentTest.kt
index c19839d46d1dbf9d72b428dec85bf4179944c579..5cb63237dc3c20ba83b91e3c3bc65fd2d2f2615e 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsFragmentTest.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.details
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.details
 
 import android.content.Context
 import android.graphics.Bitmap
@@ -13,7 +13,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import dagger.Module
 import dagger.android.ContributesAndroidInjector
 import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationCertificate
 import io.mockk.MockKAnnotations
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
@@ -86,8 +86,7 @@ class VaccinationDetailsFragmentTest : BaseUITest() {
     private fun vaccinationDetailsData(complete: Boolean): MutableLiveData<VaccinationDetails> {
         val formatter = DateTimeFormat.forPattern("dd.MM.yyyy")
         val mockCertificate = mockk<VaccinationCertificate>().apply {
-            every { firstName } returns "Max"
-            every { lastName } returns "Mustermann"
+            every { fullName } returns "Max Mustermann"
             every { dateOfBirth } returns LocalDate.parse("01.02.1976", formatter)
             every { vaccinatedAt } returns LocalDate.parse("18.02.2021", formatter)
             every { vaccineTypeName } returns "Comirnaty (mRNA)"
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListFragmentTest.kt
similarity index 86%
rename from Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentTest.kt
rename to Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListFragmentTest.kt
index a017ec7b73ddda132d9d8e5cd549a2c5c30e99bf..a35f99170a4d003c5a82a909b239ac50a9d0daf5 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListFragmentTest.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.list
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.list
 
 import android.content.Context
 import android.graphics.BitmapFactory
@@ -11,16 +11,16 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import dagger.Module
 import dagger.android.ContributesAndroidInjector
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson.Status.COMPLETE
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson.Status.IMMUNITY
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson.Status.INCOMPLETE
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.toDayFormat
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.COMPLETE
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.IMMUNITY
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.INCOMPLETE
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem
 import io.mockk.MockKAnnotations
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt
index 5d57baaa46585ec091a6c244c33f6753adb3bdc4..e12a5aa4f0fd3a606a469d5119c59b0ec0ce277f 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt
@@ -9,6 +9,9 @@ import de.rki.coronawarnapp.coronatest.type.pcr.SubmissionStatePCR.TestNegative
 import de.rki.coronawarnapp.coronatest.type.pcr.SubmissionStatePCR.TestPending
 import de.rki.coronawarnapp.coronatest.type.pcr.SubmissionStatePCR.TestPositive
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.SubmissionStateRAT
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.ImmuneVaccinationCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.VaccinationCard
 import de.rki.coronawarnapp.risk.RiskState
 import de.rki.coronawarnapp.submission.ui.homecards.PcrTestErrorCard
 import de.rki.coronawarnapp.submission.ui.homecards.PcrTestInvalidCard
@@ -31,9 +34,6 @@ import de.rki.coronawarnapp.tracing.ui.homecards.TracingDisabledCard
 import de.rki.coronawarnapp.tracing.ui.homecards.TracingFailedCard
 import de.rki.coronawarnapp.tracing.ui.homecards.TracingProgressCard
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
-import de.rki.coronawarnapp.vaccination.ui.cards.ImmuneVaccinationCard
-import de.rki.coronawarnapp.vaccination.ui.cards.VaccinationCard
 import io.mockk.every
 import io.mockk.mockk
 import org.joda.time.Duration
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateFragmentTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..68b8a1b80a3d8ae83fad80d050cced8549a2e6b0
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateFragmentTest.kt
@@ -0,0 +1,116 @@
+package de.rki.coronawarnapp.ui.submission.covidcertificate
+
+import androidx.lifecycle.MutableLiveData
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.action.ViewActions.swipeUp
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQRCode
+import de.rki.coronawarnapp.ui.submission.ApiRequestState
+import de.rki.coronawarnapp.ui.submission.qrcode.QrCodeRegistrationStateProcessor
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import org.joda.time.Instant
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import testhelpers.BaseUITest
+import testhelpers.Screenshot
+import testhelpers.launchFragmentInContainer2
+import testhelpers.takeScreenshot
+
+@RunWith(AndroidJUnit4::class)
+class RequestCovidCertificateFragmentTest : BaseUITest() {
+
+    @MockK lateinit var viewModel: RequestCovidCertificateViewModel
+
+    @Before
+    fun setup() {
+        MockKAnnotations.init(this, relaxed = true)
+
+        every { viewModel.birthDate } returns MutableLiveData(null)
+        every { viewModel.registrationState } returns MutableLiveData(
+            QrCodeRegistrationStateProcessor.RegistrationState(ApiRequestState.IDLE)
+        )
+
+        setupMockViewModel(
+            object : RequestCovidCertificateViewModel.Factory {
+                override fun create(
+                    coronaTestQrCode: CoronaTestQRCode,
+                    coronaTestConsent: Boolean,
+                    deleteOldTest: Boolean
+                ): RequestCovidCertificateViewModel = viewModel
+            }
+        )
+    }
+
+    @Test
+    fun launch_fragment_pcr() {
+        val args = RequestCovidCertificateFragmentArgs(
+            CoronaTestQRCode.PCR(qrCodeGUID = "GUID")
+        ).toBundle()
+        launchFragmentInContainer2<RequestCovidCertificateFragment>(fragmentArgs = args)
+    }
+
+    @Test
+    fun launch_fragment_rat() {
+        val args = RequestCovidCertificateFragmentArgs(
+            CoronaTestQRCode.RapidAntigen(hash = "hash", createdAt = Instant.EPOCH)
+        ).toBundle()
+        launchFragmentInContainer2<RequestCovidCertificateFragment>(fragmentArgs = args)
+    }
+
+    @Test
+    @Screenshot
+    fun capture_fragment_pcr() {
+        val args = RequestCovidCertificateFragmentArgs(
+            CoronaTestQRCode.PCR(qrCodeGUID = "GUID")
+        ).toBundle()
+        launchFragmentInContainer2<RequestCovidCertificateFragment>(fragmentArgs = args)
+        takeScreenshot<RequestCovidCertificateFragment>("pcr")
+
+        onView(withId(R.id.scrollview)).perform(swipeUp())
+        takeScreenshot<RequestCovidCertificateFragment>("pcr_2")
+    }
+
+    @Test
+    @Screenshot
+    fun capture_fragment_pcr_birthdate_dialog() {
+        val args = RequestCovidCertificateFragmentArgs(
+            CoronaTestQRCode.PCR(qrCodeGUID = "GUID")
+        ).toBundle()
+        launchFragmentInContainer2<RequestCovidCertificateFragment>(fragmentArgs = args)
+        onView(withId(R.id.date_input_edit)).perform(click())
+        takeScreenshot<RequestCovidCertificateFragment>("date_picker")
+    }
+
+    @Test
+    @Screenshot
+    fun capture_fragment_rat() {
+        val args = RequestCovidCertificateFragmentArgs(
+            CoronaTestQRCode.RapidAntigen(hash = "hash", createdAt = Instant.EPOCH)
+        ).toBundle()
+        launchFragmentInContainer2<RequestCovidCertificateFragment>(fragmentArgs = args)
+        takeScreenshot<RequestCovidCertificateFragment>("rat")
+
+        onView(withId(R.id.scrollview)).perform(swipeUp())
+        takeScreenshot<RequestCovidCertificateFragment>("rat_2")
+    }
+
+    @After
+    fun teardown() {
+        clearAllViewModels()
+    }
+}
+
+@Module
+abstract class RequestCovidCertificateFragmentTestModule {
+    @ContributesAndroidInjector
+    abstract fun requestCovidCertificateFragment(): RequestCovidCertificateFragment
+}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/vaccination/VaccinationConsentFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/vaccination/VaccinationConsentFragmentTest.kt
index 280bb1d9cb34dc1f474d92b548a24b4acdaee37c..3ef969a112b80105a768b6bf8eb7eb70a25d099f 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/vaccination/VaccinationConsentFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/vaccination/VaccinationConsentFragmentTest.kt
@@ -3,9 +3,9 @@ package de.rki.coronawarnapp.ui.vaccination
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import dagger.Module
 import dagger.android.ContributesAndroidInjector
-import de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentFragment
-import de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentFragmentArgs
-import de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentViewModel
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent.VaccinationConsentFragment
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent.VaccinationConsentFragmentArgs
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent.VaccinationConsentViewModel
 import io.mockk.MockKAnnotations
 import io.mockk.impl.annotations.MockK
 import org.junit.After
diff --git a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
index 937486ea384b8b2e3835c2dcc74aee533ff7a657..c8d1be3d5f7627a65ec5a00f7024e585f794c9af 100644
--- a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
+++ b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
@@ -3,6 +3,8 @@ package testhelpers
 import dagger.Module
 import de.rki.coronawarnapp.bugreporting.DebugLogTestModule
 import de.rki.coronawarnapp.bugreporting.DebugLogUploadTestModule
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.details.VaccinationDetailsFragmentTestModule
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListFragmentTestModule
 import de.rki.coronawarnapp.ui.contactdiary.ContactDiaryDayFragmentTestModule
 import de.rki.coronawarnapp.ui.contactdiary.ContactDiaryEditLocationsFragmentTestModule
 import de.rki.coronawarnapp.ui.contactdiary.ContactDiaryEditPersonsFragmentTestModule
@@ -35,10 +37,9 @@ import de.rki.coronawarnapp.ui.submission.SubmissionTestResultTestAvailableModul
 import de.rki.coronawarnapp.ui.submission.SubmissionTestResultTestModule
 import de.rki.coronawarnapp.ui.submission.SubmissionTestResultTestNegativeModule
 import de.rki.coronawarnapp.ui.submission.SubmissionYourConsentFragmentTestModule
+import de.rki.coronawarnapp.ui.submission.covidcertificate.RequestCovidCertificateFragmentTestModule
 import de.rki.coronawarnapp.ui.tracing.TracingDetailsFragmentTestTestModule
 import de.rki.coronawarnapp.ui.vaccination.VaccinationConsentFragmentTestModule
-import de.rki.coronawarnapp.vaccination.ui.details.VaccinationDetailsFragmentTestModule
-import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragmentTestModule
 
 @Module(
     includes = [
@@ -88,7 +89,8 @@ import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragmentTestModul
         // Vaccination
         VaccinationDetailsFragmentTestModule::class,
         VaccinationConsentFragmentTestModule::class,
-        VaccinationListFragmentTestModule::class
+        VaccinationListFragmentTestModule::class,
+        RequestCovidCertificateFragmentTestModule::class,
     ]
 )
 class FragmentTestModuleRegistrar
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt
index 7c18b62ce80dbb7d1966fd375d7b6a97519545de..f3b5ff6b4c25822fefc0c919ead8596cab32bbb3 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt
@@ -5,6 +5,8 @@ import android.os.Bundle
 import android.view.View
 import android.widget.RadioButton
 import android.widget.RadioGroup
+import androidx.core.text.buildSpannedString
+import androidx.core.text.color
 import androidx.core.view.ViewCompat
 import androidx.core.view.children
 import androidx.fragment.app.Fragment
@@ -13,6 +15,7 @@ import com.google.android.material.snackbar.Snackbar
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentTestDebugoptionsBinding
 import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
+import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat
 import de.rki.coronawarnapp.util.di.AutoInject
 import de.rki.coronawarnapp.util.ui.observe2
 import de.rki.coronawarnapp.util.ui.viewBinding
@@ -66,13 +69,14 @@ class DebugOptionsFragment : Fragment(R.layout.fragment_test_debugoptions), Auto
                     it.isChecked = it.text == state.current.rawKey
                 }
 
-                environmentCdnurlDownload.text = "Download CDN:\n${state.urlDownload}"
-                environmentCdnurlSubmission.text = "Submission CDN:\n${state.urlSubmission}"
-                environmentCdnurlVerification.text = "Verification CDN:\n${state.urlVerification}"
-                environmentUrlDatadonation.text = "DataDonation:\n${state.urlDataDonation}"
-                environmentUrlLogUpload.text = "LogUpload:\n${state.urlLogUpload}"
-                environmentPubkeyCrowdnotifier.text = "CrowdNotifierPubKey:\n${state.pubKeyCrowdNotifier}"
-                environmentPubkeyAppconfig.text = "AppConfigPubKey:\n${state.pubKeyAppConfig}"
+                environmentCdnurlDownload.text = "Download CDN" styleTo state.urlDownload
+                environmentCdnurlSubmission.text = "Submission CDN" styleTo state.urlSubmission
+                environmentCdnurlVerification.text = "Verification CDN" styleTo state.urlVerification
+                environmentUrlDatadonation.text = "DataDonation" styleTo state.urlDataDonation
+                environmentUrlLogUpload.text = "LogUpload" styleTo state.urlLogUpload
+                environmentPubkeyCrowdnotifier.text = "CrowdNotifierPubKey" styleTo state.pubKeyCrowdNotifier
+                environmentPubkeyAppconfig.text = "AppConfigPubKey" styleTo state.pubKeyAppConfig
+                environmentDccServerUrl.text = "DccServerUrl" styleTo state.dccServerUrl
             }
         }
         vm.environmentStateChange.observe2(this) {
@@ -80,6 +84,13 @@ class DebugOptionsFragment : Fragment(R.layout.fragment_test_debugoptions), Auto
         }
     }
 
+    private infix fun String.styleTo(value: String) = buildSpannedString {
+        val color = requireContext().getColorCompat(R.color.colorAccent)
+        append("${this@styleTo}:")
+        appendLine()
+        color(color) { append(value) }
+    }
+
     private fun showSnackBar(message: String) {
         Snackbar.make(requireView(), message, Snackbar.LENGTH_LONG).show()
     }
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt
index c9b907793ab6812a252f519c71a9bee66af2387a..7ef52de717b849e5bc03688bacddf2be2e57eba6 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt
@@ -12,6 +12,7 @@ data class EnvironmentState(
     val urlLogUpload: String,
     val pubKeyCrowdNotifier: String,
     val pubKeyAppConfig: String,
+    val dccServerUrl: String,
 ) {
     companion object {
         internal fun EnvironmentSetup.toEnvironmentState() = EnvironmentState(
@@ -24,6 +25,7 @@ data class EnvironmentState(
             urlLogUpload = logUploadServerUrl,
             pubKeyCrowdNotifier = crowdNotifierPublicKey,
             pubKeyAppConfig = appConfigPublicKey,
+            dccServerUrl = dccServerUrl,
         )
     }
 }
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt
index 12d682335609b9558ff9502c6ede71b33cf31f14..61cfe815eb6208a57c604b5f411f2f6ac365c1f0 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt
@@ -5,13 +5,13 @@ import androidx.lifecycle.asLiveData
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationSettings
 import de.rki.coronawarnapp.environment.BuildConfigWrap
 import de.rki.coronawarnapp.main.CWASettings
 import de.rki.coronawarnapp.presencetracing.TraceLocationSettings
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import de.rki.coronawarnapp.vaccination.core.VaccinationSettings
 
 class DeltaOnboardingFragmentViewModel @AssistedInject constructor(
     private val settings: CWASettings,
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/greencertificate/GreenCertificateTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/greencertificate/GreenCertificateTestFragment.kt
deleted file mode 100644
index c7d115bc504008facadbaf809f25495c639438a7..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/greencertificate/GreenCertificateTestFragment.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package de.rki.coronawarnapp.test.greencertificate
-
-import android.annotation.SuppressLint
-import android.os.Bundle
-import android.view.View
-import androidx.fragment.app.Fragment
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.databinding.FragmentTestGreenCertificateBinding
-import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
-import de.rki.coronawarnapp.util.di.AutoInject
-import de.rki.coronawarnapp.util.ui.doNavigate
-import de.rki.coronawarnapp.util.ui.viewBinding
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
-import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
-import javax.inject.Inject
-
-@SuppressLint("SetTextI18n")
-class GreenCertificateTestFragment : Fragment(R.layout.fragment_test_green_certificate), AutoInject {
-
-    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
-    private val viewModel: GreenCertificateTestFragmentViewModel by cwaViewModels { viewModelFactory }
-    private val binding by viewBinding<FragmentTestGreenCertificateBinding>()
-
-    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        super.onViewCreated(view, savedInstanceState)
-
-        binding.apply {
-            detailsScreen.setOnClickListener {
-                doNavigate(
-                    GreenCertificateTestFragmentDirections
-                        .actionGreenCertificateTestFragmentToGreenCertificateDetailsFragment()
-                )
-            }
-        }
-    }
-
-    companion object {
-        val MENU_ITEM = TestMenuItem(
-            title = "Green Certificate",
-            description = "View & Control green certificate related features.",
-            targetId = R.id.greenCertificateTestFragment
-        )
-    }
-}
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/greencertificate/GreenCertificateTestFragmentModule.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/greencertificate/GreenCertificateTestFragmentModule.kt
deleted file mode 100644
index c7bfa9d620f592e5a6df51de37c426b1b06528ae..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/greencertificate/GreenCertificateTestFragmentModule.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package de.rki.coronawarnapp.test.greencertificate
-
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoMap
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
-
-@Module
-abstract class GreenCertificateTestFragmentModule {
-    @Binds
-    @IntoMap
-    @CWAViewModelKey(GreenCertificateTestFragmentViewModel::class)
-    abstract fun testVaccinationFragment(
-        factory: GreenCertificateTestFragmentViewModel.Factory
-    ): CWAViewModelFactory<out CWAViewModel>
-}
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/greencertificate/GreenCertificateTestFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/greencertificate/GreenCertificateTestFragmentViewModel.kt
deleted file mode 100644
index 274a2af66555634d9fd53d8ee3547903573b2ce2..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/greencertificate/GreenCertificateTestFragmentViewModel.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package de.rki.coronawarnapp.test.greencertificate
-
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
-import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-
-class GreenCertificateTestFragmentViewModel @AssistedInject constructor(
-    dispatcherProvider: DispatcherProvider,
-) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
-
-    @AssistedFactory
-    interface Factory : SimpleCWAViewModelFactory<GreenCertificateTestFragmentViewModel>
-}
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt
index 915453e1673da71ace23199073150cb764cb4150..5481b8257082656430d2bc3b06d3bab62401cc68 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt
@@ -11,7 +11,6 @@ import de.rki.coronawarnapp.test.crash.ui.SettingsCrashReportFragment
 import de.rki.coronawarnapp.test.datadonation.ui.DataDonationTestFragment
 import de.rki.coronawarnapp.test.debugoptions.ui.DebugOptionsFragment
 import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaonboardingFragment
-import de.rki.coronawarnapp.test.greencertificate.GreenCertificateTestFragment
 import de.rki.coronawarnapp.test.hometestcards.ui.HomeTestCardsFragment
 import de.rki.coronawarnapp.test.keydownload.ui.KeyDownloadTestFragment
 import de.rki.coronawarnapp.test.playground.ui.PlaygroundFragment
@@ -22,7 +21,6 @@ import de.rki.coronawarnapp.test.tasks.ui.TestTaskControllerFragment
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import de.rki.coronawarnapp.vaccination.ui.VaccinationTestFragment
 
 class TestMenuFragmentViewModel @AssistedInject constructor() : CWAViewModel() {
 
@@ -43,8 +41,6 @@ class TestMenuFragmentViewModel @AssistedInject constructor() : CWAViewModel() {
             PresenceTracingTestFragment.MENU_ITEM,
             HomeTestCardsFragment.MENU_ITEM,
             CoronaTestTestFragment.MENU_ITEM,
-            VaccinationTestFragment.MENU_ITEM,
-            GreenCertificateTestFragment.MENU_ITEM,
         ).let { MutableLiveData(it) }
     }
     val showTestScreenEvent = SingleLiveEvent<TestMenuItem>()
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt
index 7827f307ab521991b40f3be03f38cc38119b3225..65aa2e6524a9f0a56a2ae9c9dff8d3e590c2e4fe 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt
@@ -16,8 +16,6 @@ import de.rki.coronawarnapp.test.debugoptions.ui.DebugOptionsFragment
 import de.rki.coronawarnapp.test.debugoptions.ui.DebugOptionsFragmentModule
 import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaOnboardingFragmentModule
 import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaonboardingFragment
-import de.rki.coronawarnapp.test.greencertificate.GreenCertificateTestFragment
-import de.rki.coronawarnapp.test.greencertificate.GreenCertificateTestFragmentModule
 import de.rki.coronawarnapp.test.hometestcards.ui.HomeTestCardsFragment
 import de.rki.coronawarnapp.test.hometestcards.ui.HomeTestCardsFragmentModule
 import de.rki.coronawarnapp.test.keydownload.ui.KeyDownloadTestFragment
@@ -36,8 +34,6 @@ import de.rki.coronawarnapp.test.submission.ui.SubmissionTestFragment
 import de.rki.coronawarnapp.test.submission.ui.SubmissionTestFragmentModule
 import de.rki.coronawarnapp.test.tasks.ui.TestTaskControllerFragment
 import de.rki.coronawarnapp.test.tasks.ui.TestTaskControllerFragmentModule
-import de.rki.coronawarnapp.vaccination.ui.VaccinationTestFragment
-import de.rki.coronawarnapp.vaccination.ui.VaccinationTestFragmentModule
 
 @Module
 abstract class MainActivityTestModule {
@@ -89,10 +85,4 @@ abstract class MainActivityTestModule {
 
     @ContributesAndroidInjector(modules = [CoronaTestTestFragmentModule::class])
     abstract fun coronaTest(): CoronaTestTestFragment
-
-    @ContributesAndroidInjector(modules = [VaccinationTestFragmentModule::class])
-    abstract fun vaccinationTest(): VaccinationTestFragment
-
-    @ContributesAndroidInjector(modules = [GreenCertificateTestFragmentModule::class])
-    abstract fun greenCertificateTestFragment(): GreenCertificateTestFragment
 }
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt
deleted file mode 100644
index 97cc21c5f6e96f4c5176c7c834cd97305b93ec87..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package de.rki.coronawarnapp.vaccination.ui
-
-import android.annotation.SuppressLint
-import android.os.Bundle
-import android.view.View
-import androidx.fragment.app.Fragment
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.databinding.FragmentTestVaccinationBinding
-import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
-import de.rki.coronawarnapp.util.di.AutoInject
-import de.rki.coronawarnapp.util.ui.doNavigate
-import de.rki.coronawarnapp.util.ui.viewBinding
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
-import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
-import javax.inject.Inject
-
-@SuppressLint("SetTextI18n")
-class VaccinationTestFragment : Fragment(R.layout.fragment_test_vaccination), AutoInject {
-
-    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
-    private val vm: VaccinationTestFragmentViewModel by cwaViewModels { viewModelFactory }
-
-    private val binding: FragmentTestVaccinationBinding by viewBinding()
-
-    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        super.onViewCreated(view, savedInstanceState)
-
-        binding.openVaccinationDetailsIncomplete.setOnClickListener {
-            doNavigate(
-                VaccinationTestFragmentDirections
-                    .actionVaccinationTestFragmentToVaccinationDetailsFragment(
-                        "05930482748454836478695764787840"
-                    )
-            )
-        }
-
-        binding.openVaccinationDetailsComplete.setOnClickListener {
-            doNavigate(
-                VaccinationTestFragmentDirections
-                    .actionVaccinationTestFragmentToVaccinationDetailsFragment(
-                        "05930482748454836478695764787841"
-                    )
-            )
-        }
-    }
-
-    companion object {
-        val MENU_ITEM = TestMenuItem(
-            title = "Vaccination",
-            description = "View & Control vaccination related features.",
-            targetId = R.id.vaccinationTestFragment
-        )
-    }
-}
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragmentModule.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragmentModule.kt
deleted file mode 100644
index fb24039c60b2b4cfbea5e2a91e7d9672922eb806..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragmentModule.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package de.rki.coronawarnapp.vaccination.ui
-
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoMap
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
-
-@Module
-abstract class VaccinationTestFragmentModule {
-    @Binds
-    @IntoMap
-    @CWAViewModelKey(VaccinationTestFragmentViewModel::class)
-    abstract fun testVaccinationFragment(
-        factory: VaccinationTestFragmentViewModel.Factory
-    ): CWAViewModelFactory<out CWAViewModel>
-}
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragmentViewModel.kt
deleted file mode 100644
index b9e4d4498f23b25c08f5e004052c04cab18e71de..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragmentViewModel.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package de.rki.coronawarnapp.vaccination.ui
-
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
-import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-
-class VaccinationTestFragmentViewModel @AssistedInject constructor(
-    dispatcherProvider: DispatcherProvider,
-) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
-
-    @AssistedFactory
-    interface Factory : SimpleCWAViewModelFactory<VaccinationTestFragmentViewModel>
-}
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml
index 165e76a5873ac28d6015f1d63ec99802ff2c4a4f..c29c720b6e742330b7614283234a1a2c75a51ca5 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml
@@ -55,12 +55,12 @@
             </androidx.constraintlayout.widget.ConstraintLayout>
 
             <LinearLayout
-                android:orientation="vertical"
                 android:id="@+id/environment_container"
                 style="@style/Card"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_margin="@dimen/spacing_tiny">
+                android:layout_margin="@dimen/spacing_tiny"
+                android:orientation="vertical">
 
                 <TextView
                     android:id="@+id/environment_title"
@@ -109,6 +109,14 @@
                     android:layout_marginTop="4dp"
                     tools:text="LogUpload: ?" />
 
+                <TextView
+                    android:id="@+id/environment_dcc_server_url"
+                    style="@style/TextAppearance.MaterialComponents.Caption"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="4dp"
+                    tools:text="Dcc Server Url: ?" />
+
                 <TextView
                     android:id="@+id/environment_pubkey_appconfig"
                     style="@style/TextAppearance.MaterialComponents.Caption"
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_green_certificate.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_green_certificate.xml
deleted file mode 100644
index b35ae07c4ee791a7744cd05a5c8b6917343b1e60..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_green_certificate.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    tools:ignore="HardcodedText">
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_margin="8dp"
-        android:orientation="vertical"
-        android:paddingBottom="32dp">
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Request DCC screen" />
-
-        <com.google.android.material.button.MaterialButton
-            android:id="@+id/details_screen"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="Details screen" />
-
-    </LinearLayout>
-</androidx.core.widget.NestedScrollView>
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_vaccination.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_vaccination.xml
deleted file mode 100644
index 36066d516e9ac6475d02e86438e9d657c04bd1c7..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_vaccination.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<androidx.core.widget.NestedScrollView 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"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    tools:ignore="HardcodedText">
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_margin="8dp"
-        android:orientation="vertical"
-        android:paddingBottom="32dp">
-
-        <androidx.constraintlayout.widget.ConstraintLayout
-            style="@style/Card"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_margin="@dimen/spacing_tiny"
-            android:layout_marginStart="8dp"
-            android:layout_marginEnd="8dp"
-            android:orientation="vertical">
-
-            <TextView
-                android:id="@+id/textView2"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="Vaccinations"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toTopOf="parent" />
-
-            <com.google.android.material.button.MaterialButton
-                android:id="@+id/open_vaccination_details_complete"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="10dp"
-                android:text="Vaccination details - complete"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toBottomOf="@+id/textView2" />
-
-            <com.google.android.material.button.MaterialButton
-                android:id="@+id/open_vaccination_details_incomplete"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="10dp"
-                android:text="Vaccination details - incomplete"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toBottomOf="@+id/open_vaccination_details_complete" />
-
-        </androidx.constraintlayout.widget.ConstraintLayout>
-
-    </LinearLayout>
-</androidx.core.widget.NestedScrollView>
diff --git a/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml b/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml
index 0e531f26af962639a18c07bc84e222c19160dc9c..e8d813f071f07a78cf8989f8140d3d4a18148d65 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml
@@ -55,12 +55,6 @@
         <action
             android:id="@+id/action_test_menu_fragment_to_coronaTestTestFragment"
             app:destination="@id/coronaTestTestFragment" />
-        <action
-            android:id="@+id/action_test_menu_fragment_to_vaccinationTestFragment"
-            app:destination="@id/vaccinationTestFragment" />
-        <action
-            android:id="@+id/action_test_menu_fragment_to_greenCertificateTestFragment"
-            app:destination="@id/greenCertificateTestFragment" />
     </fragment>
 
     <fragment
@@ -168,40 +162,5 @@
         android:name="de.rki.coronawarnapp.test.coronatest.ui.CoronaTestTestFragment"
         android:label="CoronaTestTestFragment"
         tools:layout="@layout/fragment_test_coronatest" />
-    <fragment
-        android:id="@+id/vaccinationTestFragment"
-        android:name="de.rki.coronawarnapp.vaccination.ui.VaccinationTestFragment"
-        android:label="VaccinationTestFragment"
-        tools:layout="@layout/fragment_test_vaccination">
-
-        <action
-            android:id="@+id/action_vaccinationTestFragment_to_vaccinationDetailsFragment"
-            app:destination="@id/vaccinationDetailsFragment" />
-
-    </fragment>
-
-    <fragment
-        android:id="@+id/vaccinationDetailsFragment"
-        android:name="de.rki.coronawarnapp.vaccination.ui.details.VaccinationDetailsFragment"
-        android:label="fragment_vaccination_details"
-        tools:layout="@layout/fragment_vaccination_details">
-        <argument
-            android:name="vaccinationCertificateId"
-            app:argType="string" />
-    </fragment>
-    <fragment
-        android:id="@+id/greenCertificateTestFragment"
-        android:name="de.rki.coronawarnapp.test.greencertificate.GreenCertificateTestFragment"
-        android:label="GreenCertificateTestFragment"
-        tools:layout="@layout/fragment_test_green_certificate" >
-        <action
-            android:id="@+id/action_greenCertificateTestFragment_to_greenCertificateDetailsFragment"
-            app:destination="@id/greenCertificateDetailsFragment" />
-    </fragment>
-    <fragment
-        android:id="@+id/greenCertificateDetailsFragment"
-        android:name="de.rki.coronawarnapp.greencertificate.ui.certificates.details.GreenCertificateDetailsFragment"
-        android:label="GreenCertificateDetailsFragment"
-        tools:layout="@layout/fragment_greencertificate_details" />
 
 </navigation>
diff --git a/Corona-Warn-App/src/main/assets/privacy_de.html b/Corona-Warn-App/src/main/assets/privacy_de.html
index 34d84e3ce1d59b9210ee3fff6299de20fb1dec52..b6d195dc142220347427bb120dd9b985a8ed482b 100644
--- a/Corona-Warn-App/src/main/assets/privacy_de.html
+++ b/Corona-Warn-App/src/main/assets/privacy_de.html
@@ -7,7 +7,7 @@
 <p>
     Folgende Themen werden behandelt:
 </p>
-<ul>
+<ol>
     <li><strong>1. Wer ist Herausgeber der Corona-Warn-App?</strong></li>
     <li><strong>2. Ist die Nutzung der App freiwillig?</strong></li>
     <li><strong>3. Auf welcher Rechtsgrundlage werden Ihre Daten verarbeitet?</strong></li>
@@ -22,7 +22,7 @@
     <li><strong>12. Wie können Sie Ihr Einverständnis zurücknehmen?</strong></li>
     <li><strong>13. Welche weiteren Datenschutzrechte haben Sie?</strong></li>
     <li><strong>14. Datenschutzbeauftragter und Kontakt</strong></li>
-</ul>
+</ol>
 <p>
     Damit dieser Text für alle Nutzer verständlich ist, bemühen wir uns um eine
     einfache und möglichst untechnische Darstellung.
@@ -50,24 +50,41 @@
 </h2>
 <p>
     Die Nutzung der App ist freiwillig. Es ist allein Ihre Entscheidung, ob Sie die App
-    installieren, welche App-Funktionen Sie nutzen und ob Sie Daten mit anderen teilen. Alle
-    App-Funktionen, die eine Weitergabe Ihrer personenbezogenen Daten an das RKI oder an andere
-    Nutzer erfordern, holen vorher Ihr ausdrückliches Einverständnis ein. Falls Sie ein
-    Einverständnis nicht erteilen oder nachträglich zurücknehmen, entstehen Ihnen keine Nachteile.
-
+    installieren, welche App-Funktionen Sie nutzen und ob Sie Daten mit anderen teilen.
+    Grundsätzlich holen die Haupt-Funktionen der App, die eine Weitergabe Ihrer personenbezogenen
+    Daten an das RKI oder an andere Nutzer erfordern, vorher Ihr ausdrückliches Einverständnis ein.
+    Im Zusammenhang mit den offiziellen digitalen COVID-Zertifikaten (COVID-Testzertifikat und
+    COVID-Impfzertifikat) gibt es neue gesetzliche Grundlagen für die Erstellung der Nachweise. In
+    diesem Zusammenhang ist daher keine zusätzliche Einwilligung erforderlich. Die Zertifikate
+    werden aber nur erstellt, wenn Sie dies wünschen. Die Anforderung und Verwendung der digitalen
+    COVID-Zertifikate ist freiwillig.
+</p>
+<p>
+    Falls Sie ein Einverständnis nicht erteilen oder nachträglich zurücknehmen oder keine digitalen
+    COVID-Zertifikate anfordern, entstehen Ihnen keine Nachteile.
 </p>
 <h2>
     3. Auf welcher Rechtsgrundlage werden Ihre Daten verarbeitet?
 </h2>
 <p>
-    Ihre Daten werden vom RKI grundsätzlich nur verarbeitet, wenn Sie zuvor Ihr ausdrückliches
-    Einverständnis erteilt haben. Die Rechtsgrundlage ist Art. 6 Abs. 1 S. 1 lit. a DSGVO sowie im
-    Falle von Gesundheitsdaten Art. 9 Abs. 2 lit. a DSGVO. Sie können ein einmal erteiltes
-    Einverständnis jederzeit wieder zurücknehmen (sogenanntes Widerrufsrecht). Weitere Informationen
-    zu Ihrem Widerrufsrecht finden Sie unter Punkt 12. Die Verarbeitung von Zugriffsdaten für die
-    Bereitstellung der täglichen Statistiken (siehe hierzu Punkt 6.e.) erfolgt im Rahmen der
-    Information der Öffentlichkeit durch das RKI gem. § 4 Abs. 4 BGA-NachfG auf Basis von Art. 6
-    Abs. 1 lit e. DSGVO i.V.m § 3 BDSG.
+    Ihre Daten werden im Zusammenhang mit Risiko-Ermittlung und der Warnung Anderer vom RKI
+    grundsätzlich nur verarbeitet, wenn Sie zuvor Ihr ausdrückliches Einverständnis erteilt haben.
+    Die Rechtsgrundlage ist Art. 6 Abs. 1 S. 1 lit. a DSGVO sowie im Falle von Gesundheitsdaten Art.
+    9 Abs. 2 lit. a DSGVO. Sie können ein einmal erteiltes Einverständnis jederzeit wieder
+    zurücknehmen (sogenanntes Widerrufsrecht). Weitere Informationen zu Ihrem Widerrufsrecht finden
+    Sie unter Punkt 12.
+</p>
+<p>
+    Im Zusammenhang mit den offiziellen digitalen COVID-Zertifikaten (COVID-Testzertifikat und
+    COVID-Impfzertifikat) ist die Datenverarbeitung gesetzlich geregelt. Die Erstellung und
+    Bescheinigung von Impfzertifikaten erfolgt auf Basis von Art. 9 Abs. 2 lit. g DSGVO i.V.m § 22
+    Abs. 5 IfSG. Die Erstellung und Bescheinigung von Testzertifikaten erfolgt auf Basis von Art. 9
+    Abs. 2 lit. g DSGVO i.V.m § 22 Abs. 7 IfSG.
+</p>
+<p>
+    Die Verarbeitung von Zugriffsdaten für die Bereitstellung der täglichen Statistiken (siehe
+    hierzu Punkt 6 f.) erfolgt im Rahmen der Information der Öffentlichkeit durch das RKI gem. § 4
+    Abs. 4 BGA-NachfG auf Basis von Art. 6 Abs. 1 lit e. DSGVO i.V.m § 3 BDSG.
 </p>
 <h2>
     4. An wen richtet sich die App?
@@ -85,18 +102,20 @@
     verarbeitet werden. Das bedeutet, dass das System bei der Risiko-Ermittlung, der Warnung anderer
     und dem Abruf des Testergebnisses keine Daten erfassen muss, die es dem RKI oder anderen Nutzern
     ermöglichen, auf Ihre Identität, Ihren Namen, Ihren Standort oder andere persönliche Details zu
-    schließen. Eine Ausnahme gilt nur für die Funktion „Schnelltest-Ergebnis nachweisen“, mit der
-    Sie eine auf Ihren Namen ausgestellte Bestätigung für negative Schnelltest-Ergebnisse anzeigen
-    lassen können (siehe hierzu Punkt 6 c.) sowie die Funktion zum Anlegen eines
-    „Schnelltest-Profils“, mit der Sie einer Teststelle die zur Durchführung eines Schnelltests
-    erforderlichen Daten bereitstellen können (siehe hierzu Punkt 6 d.). Die App verzichtet
-    standardmäßig auf die Auswertung Ihres Nutzungsverhaltens durch Analyse-Tools. Nur wenn Sie
-    ausdrücklich der freiwilligen Datenspende zustimmen oder einen Fehlerbericht aufzeichnen und mit
-    dem RKI teilen, werden bestimmte Daten über Ihre Nutzung der App an das RKI übermittelt (siehe
-    hierzu Punkt 5 i. und Punkt 5 k.).
+    schließen.
+</p>
+<p>
+    Ausnahmen gelten für die Funktionen „Schnelltest-Ergebnis nachweisen“, mit der Sie eine auf
+    Ihren Namen ausgestellte Bestätigung für negative Schnelltest-Ergebnisse anzeigen lassen können
+    (siehe hierzu Punkt 6 c.), die Funktion zum Anlegen eines „Schnelltest-Profils“, mit der Sie
+    einer Teststelle die zur Durchführung eines Schnelltests erforderlichen Daten bereitstellen
+    können (siehe hierzu Punkt 6 d.) und wenn Sie digitale COVID-Zertifikate in der App hinzufügen.
+</p>
+<p>
     Die App verzichtet standardmäßig auf die Auswertung Ihres Nutzungsverhaltens durch
-    Analyse-Tools. Nur wenn Sie ausdrücklich der freiwilligen Datenspende zustimmen, werden
-    bestimmte Daten über Ihre Nutzung der App an das RKI übermittelt (siehe hierzu Punkt 5 h.).
+    Analyse-Tools. Nur wenn Sie ausdrücklich der freiwilligen Datenspende zustimmen oder einen
+    Fehlerbericht aufzeichnen und mit dem RKI teilen, werden bestimmte Daten über Ihre Nutzung der
+    App an das RKI übermittelt (siehe hierzu Punkt 5 j. und Punkt 5 l.).
 </p>
 <p>
     Die von der App verarbeiteten Daten lassen sich den folgenden Kategorien
@@ -262,7 +281,7 @@
     (Bezeichnung des Events/Ortes, Adresse/Ort, typische Aufenthaltsdauer und ggf. Startzeit des
     Events) sowie die Check-in-Zeit auf Ihrem Smartphone gespeichert. Zudem leitet Ihre App anhand
     der im QR-Code enthaltenen Informationen eine dem Event eindeutig zuordenbare verschlüsselte
-    Kennung (im Folgenden: Event-ID) ab. Aus der Event-ID ergeben sich keine Rückschlüssel auf das
+    Kennung (im Folgenden: Event-ID) ab. Aus der Event-ID ergeben sich keine Rückschlüsse auf das
     Event oder den Ort. Wenn Sie sich in der App auschecken oder nach Ablauf der vom Gastgeber
     voreingestellten Zeit automatisch ausgecheckt werden, wird der Auscheck-Zeitpunkt auf Ihrem
     Smartphone gespeichert.
@@ -315,7 +334,8 @@
         wenn Sie Angaben zum Beginn von eventuellen Corona-Symptomen machen oder
     </li>
     <li>
-        wenn Sie digitale Impfzertifikate in der App hinzufügen.
+        wenn Sie digitale COVID-Zertifikate (Impfzertifikate oder Testzertifikate) in der App
+        hinzufügen.
     </li>
 </ul>
 <p>
@@ -348,13 +368,14 @@
 
 </p>
 <h3>
-    h. Daten über Ihre Corona-Impfung
+    h. Daten über Ihre Corona-Impfung (Daten im COVID-Impfzertifikat)
 </h3>
 <p>
-    Sie können Ihre Impfzertifikate in der App hinzufügen, die Sie bei der Impfung erhalten haben.
-    Die Anforderung des digitalen Impfzertifikats ist freiwillig. Sollten Sie dieses Angebot
-    wahrnehmen, erhalten Sie bei der Impfung einen Ausdruck mit einem QR-Code. In diesem sind die
-    folgenden Daten zu Ihrer Corona-Impfung kodiert:
+    Sie können Ihre offiziellen Impfzertifikate (digitale COVID-Impfzertifikate) in der App
+    hinzufügen, die Sie bei der Impfung erhalten haben. Die Anforderung des digitalen
+    Impfzertifikats ist freiwillig. Sollten Sie dieses Angebot wahrnehmen, erhalten Sie bei der
+    Impfung einen Ausdruck mit einem QR-Code. In diesem sind die folgenden Daten zu Ihrer
+    Corona-Impfung kodiert:
 </p>
 <ul>
     <li>
@@ -375,7 +396,28 @@
     scannen. Diese Daten wurden zuvor bei Ihrer Impfung erhoben.
 </p>
 <h3>
-    i. Nutzungsdaten (Datenspende)
+    i. Daten im COVID-Testzertifikat
+</h3>
+<p>
+    Sie können über die App offizielle Testzertifikate (digitale COVID-Testzertifikate) anfordern.
+    Die Anforderung des digitalen Testzertifikats ist freiwillig und erfolgt nur, wenn ein negatives
+    Testergebnis vorliegt. Sie erhalten dann ihr Testzertifikat mit einem QR-Code in der App. In
+    diesem sind die folgenden Daten zu Ihrem Testergebnis enthalten:
+</p>
+<ul>
+    <li>Daten zu Ihrer Person (Name, Vorname, Geburtsdatum)</li>
+    <li>Informationen zum Test (Krankheit, Art des Tests, Produkt, Hersteller)</li>
+    <li>Informationen zur Testdurchführung (Datum und Uhrzeit des Tests, Ort an dem sich das
+        Testzentrum befindet)
+    </li>
+    <li>Testergebnis</li>
+    <li>Eindeutige Kennung des Testzertifikats.</li>
+</ul>
+<p>
+    Die Daten werden in der App gespeichert, sobald Ihr Testergebnis vorliegt.
+</p>
+<h3>
+    j. Nutzungsdaten (Datenspende)
 
 </h3>
 <p>
@@ -434,15 +476,6 @@
     Zusätzlich können Sie weitere optionale Angaben zu Ihrer Region sowie zu Ihrer Altersgruppe
     machen, die zusammen mit den Nutzungsdaten an das RKI übermittelt werden.
 </p>
-<ul>
-    <li>Angaben zum Modell und der Version Ihres Smartphones und zur Version Ihrer App sowie dem
-        verwendeten Betriebssystem.
-    </li>
-</ul>
-<p>
-    Zusätzlich können Sie weitere freiwilligen Angaben zu Ihrer Region sowie zu Ihrer Altersgruppe
-    machen, die zusammen mit den Nutzungsdaten an das RKI übermittelt werden.
-</p>
 <p>
     Das RKI wird die Nutzungsdaten und eventuelle optionale Angaben zu anonymisierten Statistiken
     zusammenfassen und auswerten, um die Wirksamkeit und Funktionsweise der App zu bewerten und
@@ -454,13 +487,13 @@
     unter Punkt 5 l. und Punkt 11).
 </p>
 <h3>
-    j. Teilnahme an einer Befragung
+    k. Teilnahme an einer Befragung
 </h3>
 <p>
     Einigen Nutzern wird in der App die Teilnahme an einer Befragung des RKI angeboten. In der Regel
     wird das Angebot zur Teilnahme an der Befragung abhängig von bestimmten in der App registrierten
-    Ereignissen sein (z.&nbsp;B. der Anzeige eines erhöhten Risikos). Mit der Teilnahme an der
-    Befragung helfen Sie dem RKI, die Wirksamkeit der App zu bewerten, die App zu verbessern und
+    Ereignissen sein (z.B. der Anzeige eines erhöhten Risikos). Mit der Teilnahme an der Befragung
+    helfen Sie dem RKI, die Wirksamkeit der App zu bewerten, die App zu verbessern und
     beispielsweise zu verstehen, ob und wie Warnungen über die App dabei helfen, weitere
     Ansteckungen zu verhindern.
 </p>
@@ -469,11 +502,11 @@
     Befragung teilnehmen möchten und Daten hierfür an das RKI übermittelt werden sollen. Die
     Befragungen finden auf einer Webseite außerhalb der App statt, auf die Sie weitergeleitet
     werden. Die Teilnahme an einer Befragung setzt die Bestätigung der Echtheit Ihrer App voraus
-    (Beachten Sie bitte die weitere Informationen hierzu unter Punkt 5 j. und Punkt 11).
+    (Beachten Sie bitte die weiteren Informationen hierzu unter Punkt 5 l. und Punkt 11).
 
 </p>
 <h3>
-    k. Inhalte der Fehlerberichte
+    l. Inhalte der Fehlerberichte
 </h3>
 <p>
     Um den technischen Support der App bei der Fehleranalyse zu unterstützen, können Sie in der App
@@ -489,7 +522,7 @@
             <li>
                 zur Risiko-Ermittlung (z.B. zur Funktionsweise der Verarbeitung der Begegnungsdaten,
                 der Berechnung des Ansteckungsrisikos, der Aktualisierung der Positiv-Listen, der
-                Anzeige des errechneten Risikostatus
+                Anzeige des errechneten Risikostatus,
             </li>
             <li>
                 zum Abruf und der Anzeige von Testergebnissen und
@@ -510,9 +543,9 @@
 <p>
     Der Fehlerbericht enthält jedoch keine Informationen über QR-Codes für die Testregistrierung,
     das in Ihrer App gespeicherte Token (siehe dazu unten Punkt 6 b. unter „Testergebnis abrufen“),
-    Schnelltest-Ergebnisse, Impfzertifikate und Einträge in Ihrem Kontakt-Tagebuch. Der
-    Fehlerbericht enthält auch nicht Ihren Namen oder andere Angaben, mit denen Sie vom RKI
-    identifiziert werden können.
+    Schnelltest-Ergebnisse, digitale COVID-Impf- und Testzertifikate und Einträge in Ihrem
+    Kontakt-Tagebuch. Der Fehlerbericht enthält auch nicht Ihren Namen oder andere Angaben, mit
+    denen Sie vom RKI identifiziert werden können.
 </p>
 <p>
     Sie können die Aufzeichnung des Fehlerberichts jederzeit stoppen und den Fehlerbericht löschen.
@@ -527,11 +560,11 @@
     Die Erstellung und Ãœbersendung eines Fehlerberichts an das RKI ist freiwillig. Sie entscheiden
     selbst darüber, ob Sie einen Fehlerbericht aufzeichnen möchten und diesen an den technischen
     Support der App übersenden. Die Übersendung des Fehlerberichts setzt die Bestätigung der
-    Echtheit Ihrer App voraus (Beachten Sie bitte die weiteren Informationen hierzu unter Punkt 5 l.
+    Echtheit Ihrer App voraus (Beachten Sie bitte die weiteren Informationen hierzu unter Punkt 5 m.
     und Punkt 11).
 </p>
 <h3>
-    l. Bestätigung der Echtheit Ihrer App
+    m. Bestätigung der Echtheit Ihrer App
 </h3>
 <p>
     Einige Funktionen der App setzen voraus, dass vorab die Echtheit Ihrer App geprüft und gegenüber
@@ -543,9 +576,9 @@
     werden Daten an Apple übermittelt). Die Kennung enthält Informationen über die Version Ihres
     Smartphones und die Version der App. Möglicherweise kann der Anbieter Ihres Betriebssystems
     anhand der Kennung auf Ihre Identität schließen und nachvollziehen, dass die Echtheitsprüfung
-    Ihres Smartphones stattgefunden hat. Weitere Angaben aus der App, z.&nbsp;B. Begegnungsdaten,
-    erhält der Anbieter Ihres Betriebssystems nicht. Die Anbieter des Betriebssystems nutzen die
-    Kennung, um die Echtheit Ihrer App gegenüber dem RKI zu bestätigen. Die Nutzung der Funktion zur
+    Ihres Smartphones stattgefunden hat. Weitere Angaben aus der App, z.B. Begegnungsdaten, erhält
+    der Anbieter Ihres Betriebssystems nicht. Die Anbieter des Betriebssystems nutzen die Kennung,
+    um die Echtheit Ihrer App gegenüber dem RKI zu bestätigen. Die Nutzung der Funktion zur
     Bestätigung der Echtheit ist freiwillig. Wenn Sie mit der Bestätigung der Echtheit Ihrer App
     nicht einverstanden sind, kann es jedoch sein, dass Ihnen andere Funktionen der App nicht zur
     Verfügung stehen.
@@ -576,7 +609,7 @@
 </p>
 <p>
     Die Zufalls-IDs und Event-IDs in den Positiv-Listen enthalten zusätzlich einen
-    Übertragungsrisiko-Wert und eine Angabe zur Art der Diagnose (siehe hierzu Punkt 6 e.).
+    Ãœbertragungsrisiko-Wert und eine Angabe zur Art der Diagnose (siehe hierzu Punkt 6 e.).
 </p>
 <p>
     Die App gibt die Zufalls-IDs aus der Positiv-Liste an das COVID-19-Benachrichtigungssystem
@@ -691,7 +724,10 @@
     zu der gehashten Kennzahl tatsächlich ein positives Testergebnis vorliegt.
     Sofern dies bestätigt wird, erzeugt das Serversystem die TAN und übermittelt
     sie an die App. Eine Kopie der TAN verbleibt auf dem Serversystem.
-
+</p>
+<p>
+    Die Testergebnisse werden auch in Ihrem Kontakt-Tagebuch hinterlegt. Sie können diese dort
+    jederzeit wieder entfernen.
 </p>
 <h3>
     c. Nachweis des Schnelltest-Ergebnisses
@@ -727,11 +763,15 @@
     Schnelltestdaten (Kennzahl, Testzeitpunkt) werden gelöscht, sobald das positive
     Schnelltest-Ergebnis nicht mehr in der App angezeigt wird.
 </p>
+<p>
+    Die Schnelltest-Ergebnisse werden auch in Ihrem Kontakt-Tagebuch hinterlegt. Sie können diese
+    dort jederzeit wieder entfernen.
+</p>
 <h3>
     d. Schnelltest-Profil
 </h3>
 <p>
-    Das Schnelltest-Profil bietet Ihnen die Möglichkeit die Datenerfassung in teilnehmenden
+    Das Schnelltest-Profil bietet Ihnen die Möglichkeit, die Datenerfassung in teilnehmenden
     Teststellen zu beschleunigen. Sie können hierfür Angaben zu Ihrer Person in Ihrem
     Schnelltest-Profil in der App speichern und diese in Ihren persönlichen QR-Code umwandeln, der
     alle eingegebenen Daten enthält. In der Teststelle können Sie den QR-Code Ihres
@@ -857,7 +897,7 @@
 
 </p>
 <h3>
-    h. Digitaler Impfnachweis
+    h. Digitaler Impfnachweis (COVID-Impfzertifikat)
 
 </h3>
 <p>
@@ -892,7 +932,49 @@
     dass die Daten ausgelesen werden.
 </p>
 <h3>
-    i. Datenspende
+    i. Digitaler Testnachweis (COVID-Testzertifikat)
+
+</h3>
+<p>
+    Die App erlaubt es Ihnen, Ihre Testzertifikate zu speichern und in digitaler Form bei sich zu
+    führen. Bei Bedarf können Sie dann die App nutzen, um in den gesetzlich vorgesehenen Fällen
+    nachzuweisen, dass Sie negativ getestet wurden.
+</p>
+<p>
+    Ein Testzertifikat können Sie in der App anfordern, wenn Sie einen Test registrieren. Scannen
+    Sie hierfür den QR-Code, den Sie beim Test erhalten haben. Die App liest die Daten zu Ihrem Test
+    aus dem QR-Code aus und erhält das Testergebnis vom Server. Wenn Sie einen PCR-Test gemacht
+    haben, wird der Abruf des Ergebnisses und des Testzertifikats zusätzlich mit Ihrem Geburtsdatum
+    gesichert. Aus dem Geburtsdatum wird ein Sicherheitscode erstellt (in Form eines sog.
+    Hashwertes) und mit dem Server des RKI abgeglichen. Auf diese Weise wird sichergestellt, dass
+    andere Personen nicht Ihr Testergebnis abrufen können.
+</p>
+<p>
+    Die Daten zum Testzertifikat speichert die App in einem gesicherten Bereich Ihres Smartphones.
+    Wenn Sie ein positives Testergebnis abgerufen haben, wird kein Testzertifikat erstellt.
+</p>
+<p>
+    Auf dem Homescreen wird Ihr aktuelles Testzertifikat in der App angezeigt. Zum Nachweis können
+    Sie den in der App dargestellten QR-Code des digitalen Testzertifikats vorzeigen. Mit der
+    offiziellen Prüf-App kann dieser QR-Code gescannt werden, die Daten im Testzertifikat (siehe
+    Punkt 5 i.) werden dabei ausgelesen. In der Prüf-App wird dann angezeigt, ob Sie negativ
+    getestet sind und wann der Test durchgeführt wurde. Zusätzlich werden auch Ihr Name und Ihr
+    Geburtsdatum angezeigt, damit die prüfende Person diese Angaben mit Ihrem offiziellen
+    Ausweisdokument abgleichen kann.
+</p>
+<p>
+    Bitte beachten Sie, dass die Verwendung der Funktion zum Anfordern und Speichern Ihrer
+    COVID-Testzertifikate in der App freiwillig ist. Sie können in den gesetzlich vorgesehenen
+    Fällen den Nachweis Ihres Testergebnisses auch auf andere Weise erbringen.
+</p>
+<p>
+    Bitte beachten Sie, dass der QR-Code Ihres digitalen Testzertifikates Ihre Daten enthält. Zeigen
+    Sie diesen nur vor, wenn Sie Ihr negatives Testergebnis nachweisen möchten. Stellen Sie die
+    Testzertifikate und QR-Codes niemandem zur Verfügung, wenn Sie nicht wollen, dass die Daten
+    ausgelesen werden.
+</p>
+<h3>
+    j. Datenspende
 
 </h3>
 <p>
@@ -916,11 +998,11 @@
     </li>
     <li>
         Informationen und Hilfestellungen zur App ermöglichen – Es soll möglich werden, zu erkennen,
-        ob es z.&nbsp;B. bei der Nutzung der App im Zusammenhang mit bestimmten Testeinrichtungen
-        und Laboren oder in bestimmten Regionen zu Problemen kommt. Dies kann festgestellt werden,
-        wenn aufgrund der Datenspende auffällt, dass in bestimmten Regionen Testergebnisse verspätet
-        zur Verfügung stehen. So können die zuständigen Gesundheitsbehörden auch gezielt auf
-        mögliche technische Störungen hingewiesen werden.
+        ob es z.B. bei der Nutzung der App im Zusammenhang mit bestimmten Testeinrichtungen und
+        Laboren oder in bestimmten Regionen zu Problemen kommt. Dies kann festgestellt werden, wenn
+        aufgrund der Datenspende auffällt, dass in bestimmten Regionen Testergebnisse verspätet zur
+        Verfügung stehen. So können die zuständigen Gesundheitsbehörden auch gezielt auf mögliche
+        technische Störungen hingewiesen werden.
     </li>
     <li>
         Verbesserung der Statistiken über den Pandemieverlauf – Die Daten können Aufschluss über die
@@ -934,7 +1016,7 @@
     oder wen Sie getroffen haben.
 </p>
 <h3>
-    j. Fehlerberichte
+    k. Fehlerberichte
 </h3>
 <p>
     Das RKI ist bemüht, eine fehlerfreie App anzubieten. Aufgrund der großen Anzahl verschiedener
@@ -951,7 +1033,7 @@
     Offenlegung Ihrer Identität (z. B. per E-Mail) mitteilen.
 </p>
 <h3>
-    k. Befragungen
+    l. Befragungen
 </h3>
 <p>
     Befragungen finden auf einer Webseite außerhalb der App statt, auf die Sie weitergeleitet
@@ -960,7 +1042,7 @@
     Befragung auf der Befragungs-Webseite beschrieben.
 </p>
 <h3>
-    l. Bestätigung der Echtheit Ihrer App
+    m. Bestätigung der Echtheit Ihrer App
 </h3>
 <p>
     Zur Bestätigung der Echtheit Ihrer App wird eine Funktion des Betriebssystems Ihres Smartphones
@@ -1023,7 +1105,7 @@
         festgelegt (Durchführungsbeschluss (EU) 2020/1023 vom 15. Juli 2020, abrufbar unter <a
                 href="https://eur-lex.europa.eu/eli/dec_impl/2020/1023/oj">
             https://eur-lex.europa.eu/eli/dec_impl/2020/1023/oj
-        </a>. Für die Verarbeitung der in den Positiv-Listen enthaltenen Angaben (Zufalls-IDs und
+        </a>). Für die Verarbeitung der in den Positiv-Listen enthaltenen Angaben (Zufalls-IDs und
         eventuelle Angaben zum Symptombeginn) auf den Austausch-Servern zur Ermöglichung der
         länderübergreifenden Risiko-Ermittlung und Warnung ist das RKI danach mit den jeweils
         zuständigen Gesundheitsbehörden der teilnehmenden Länder gemeinsam verantwortlich.
@@ -1049,8 +1131,7 @@
             title="Follow link"
     >
         https://www.coronawarn.app/de/faq/#interoperability_countries
-    </a>
-    .
+    </a>.
 
 </p>
 <h2>
@@ -1170,15 +1251,15 @@
 </h3>
 <p>
     Die Positiv-Listen werden nach 14 Tagen aus dem App-Speicher gelöscht. Event-Daten im Bereich
-    „Meine Check-Ins“ werden nach 14 Tagen automatisch gelöscht. Alternativ können Sie Einträge im
-    Bereich „Meine Check-Ins“ jederzeit händisch löschen. Das für Sie ermittelte Ansteckungsrisiko
+    „Meine Check-ins“ werden nach 14 Tagen automatisch gelöscht. Alternativ können Sie Einträge im
+    Bereich „Meine Check-ins“ jederzeit händisch löschen. Das für Sie ermittelte Ansteckungsrisiko
     (z. B. „niedriges Risiko“) wird nach jeder Aktualisierung, spätestens aber nach 14 Tagen aus dem
     App-Speicher gelöscht. Sofern Sie ein positives Testergebnis abgerufen haben, wird das Token im
     App-Speicher gelöscht, sobald Sie eine Warnung auslösen. Die Einträge im Kontakt-Tagebuch
     bleiben für 16 Tage auf Ihrem Smartphone gespeichert und werden dann automatisch gelöscht. Sie
     können diese Einträge jederzeit auch vorzeitig selbst löschen. Bitte beachten Sie, dass beim
     Einchecken zu einem Event oder an einem Ort übernommene Einträge im Kontakt-Tagebuch auch nach
-    der Löschung des zugehörigen Check-Ins dort noch gespeichert sind. Wenn Sie Ihr
+    der Löschung des zugehörigen Check-ins dort noch gespeichert sind. Wenn Sie Ihr
     Schnelltest-Profil einmal angelegt haben, bleibt dieses so lange in der App gespeichert, bis Sie
     es selbst wieder löschen. Wenn Sie Impfzertifikate gescannt haben, bleiben auch diese so lange
     in der App gespeichert, bis Sie sie selbst wieder löschen.
@@ -1237,21 +1318,16 @@
     EU-Länder haben die jeweils zuständigen nationalen Gesundheitsbehörden die EU-Kommission als
     Auftragsverarbeiter beauftragt. Der Austausch-Server für länderübergreifende Warnungen zwischen
     der Corona-Warn-App und der schweizerischen Corona-App wird vom Bundesamt für Gesundheit der
-    Schweizerischen Eidgenossenschaft in Abstimmung mit dem RKI betrieben und gewartet.
-</p>
-<p>
-    Mit dem Betrieb und der Wartung eines Teils der technischen Infrastruktur
-    der App (z.&nbsp;B. Serversysteme, Hotline) hat das RKI die T-Systems
-    International GmbH und die SAP Deutschland SE &amp; Co. KG beauftragt, die
-    als Auftragsverarbeiter des RKI tätig werden. Diese Unternehmen sind von
-    der EU-Kommission zudem als Unterauftragsverarbeiter mit der technischen
-    Bereitstellung und Verwaltung des gemeinsam betriebenen Warnsystems der
-    teilnehmenden Länder beauftragt. Im Übrigen gibt das RKI Ihre Daten, die im Zusammenhang mit der
-    Nutzung der
-    App erhoben werden, nur an Dritte weiter, soweit das RKI rechtlich dazu
-    verpflichtet ist oder die Weitergabe im Falle von Angriffen auf die
-    technische Infrastruktur der App zur Rechts- oder Strafverfolgung
-    erforderlich ist. Eine Weitergabe durch das RKI in anderen Fällen erfolgt grundsätzlich nicht.
+    Schweizerischen Eidgenossenschaft in Abstimmung mit dem RKI betrieben und gewartet. Mit dem
+    Betrieb und der Wartung eines Teils der technischen Infrastruktur der App (z.B. Serversysteme,
+    Hotline) hat das RKI die T-Systems International GmbH und die SAP Deutschland SE &amp; Co. KG
+    beauftragt, die als Auftragsverarbeiter des RKI tätig werden. Diese Unternehmen sind von der
+    EU-Kommission zudem als Unterauftragsverarbeiter mit der technischen Bereitstellung und
+    Verwaltung des gemeinsam betriebenen Warnsystems der teilnehmenden Länder beauftragt. Im Übrigen
+    gibt das RKI Ihre Daten, die im Zusammenhang mit der Nutzung der App erhoben werden, nur an
+    Dritte weiter, soweit das RKI rechtlich dazu verpflichtet ist oder die Weitergabe im Falle von
+    Angriffen auf die technische Infrastruktur der App zur Rechts- oder Strafverfolgung erforderlich
+    ist. Eine Weitergabe durch das RKI in anderen Fällen erfolgt grundsätzlich nicht.
 </p>
 <h2>
     11. Werden Ihre Daten in Länder außerhalb der EU übermittelt?
@@ -1456,6 +1532,5 @@
     <a href="mailto:datenschutz@rki.de">datenschutz@rki.de</a>.
 </p>
 <p>
-    Stand: 28.05.2021
+    Stand: 17.06.2021
 </p>
-	
diff --git a/Corona-Warn-App/src/main/assets/privacy_en.html b/Corona-Warn-App/src/main/assets/privacy_en.html
index 2d69b43027d732d97a4ecafbda1b0875d7634323..63fcebb108630872c2db99bd5763648caf8cd69e 100644
--- a/Corona-Warn-App/src/main/assets/privacy_en.html
+++ b/Corona-Warn-App/src/main/assets/privacy_en.html
@@ -6,7 +6,7 @@
 <p>
     It covers the following topics:
 </p>
-<ul>
+<ol>
     <li><strong>1. Who is the Corona-Warn-App published by?</strong></li>
     <li><strong>2. Is using the app voluntary?</strong></li>
     <li><strong>3. On what legal basis is your data processed?</strong></li>
@@ -21,7 +21,7 @@
     <li><strong>12. How can you withdraw your consent?</strong></li>
     <li><strong>13. What other rights do you have under data protection law?</strong></li>
     <li><strong>14. Data protection officer and contact</strong></li>
-</ul>
+</ol>
 <p>
     To make sure that this text can be understood by all users, we have made
     every effort to make it simple and as non-technical as possible.
@@ -52,25 +52,41 @@
 </h2>
 <p>
     Using the app is voluntary. It is entirely up to you whether you install the app, which of the
-    app’s features you use, and whether you share data with others. All of the app’s features that
-    require the transfer of your personal data to the RKI or to other users will obtain your express
-    consent in advance. If you do not give your consent or if you subsequently withdraw it, this
-    will not result in any disadvantages for you.
-
+    app’s features you use, and whether you share data with others. As a matter of principle, all of
+    the app’s main features that require the transfer of your personal data to the RKI or to other
+    users will obtain your express consent in advance. In the context of the official digital COVID
+    certificates (COVID test certificate and COVID vaccination certificate), new legal requirements
+    apply to the creation of the certificates. For this reason, no additional consent is required in
+    this context. However, the certificates will only be created if you wish for this to happen.
+    Requesting and using digital COVID certificates is voluntary.
+</p>
+<p>
+    If you do not give your consent, if you subsequently withdraw it, or if you do not request any
+    digital COVID certificates, this will not result in any disadvantages for you.
 </p>
 <h2>
     3. On what legal basis is your data processed?
 
 </h2>
 <p>
-    The RKI will only process your data if you have given your express consent beforehand. The legal
-    basis is Art. 6(1) Sentence 1(a) GDPR and, in the case of health data, Art. 9(2)(a) GDPR. After
-    giving your consent, you can withdraw it at any time (so-called right of withdrawal). Please
-    refer to Section 12 for further information about your right of withdrawal. On the basis of Art.
-    6(1) Sentence 1(e) GDPR in conjunction with Sect. 3 of the German Federal Data Protection Act
-    (BDSG), the processing of access data for the provision of daily statistics (see Section 6 e.)
-    is performed as part of the RKI’s duty to inform the public pursuant to Sect. 4(4) of the Act on
-    Successor Agencies to the Federal Health Agency (BGA-NachfG).
+    As a matter of principle, the RKI will only process your data for the purposes of exposure
+    logging and warning others if you have given your express consent beforehand. The legal basis is
+    Art. 6(1) Sentence 1(a) GDPR and, in the case of health data, Art. 9(2)(a) GDPR. After giving
+    your consent, you can withdraw it at any time (so-called right of withdrawal). Please refer to
+    Section 12 for further information about your right of withdrawal.
+</p>
+<p>
+    In the context of the official digital COVID certificates (COVID test certificate and COVID
+    vaccination certificate), data processing is regulated by law. The creation and confirmation of
+    vaccination certificates is based on Art. 9(2)(g) GDPR in conjunction with Sect. 22(5) of the
+    Infection Protection Act (IfSG). The creation and confirmation of test certificates is based on
+    Art. 9(2)(g) GDPR in conjunction with Sect. 22(7) IfSG.
+</p>
+<p>
+    On the basis of Art. 6(1) Sentence 1(e) GDPR in conjunction with Sect. 3 of the German Federal
+    Data Protection Act (BDSG), the processing of access data for the provision of daily statistics
+    (see Section 6 f.) is performed as part of the RKI’s duty to inform the public pursuant to Sect.
+    4(4) of the Act on Successor Agencies to the Federal Health Agency (BGA-NachfG).
 </p>
 <h2>
     4. Who is the app aimed at?
@@ -95,10 +111,17 @@
     rapid test profile, which allows you to provide a testing point with the data required to
     perform a rapid test (see Section 6 d.).
 </p>
+<p>
+    Exceptions apply to the feature for proving a rapid test result, which allows you to display a
+    confirmation issued in your name for negative rapid test results (see Section 6 c.), the feature
+    for creating a rapid test profile, which allows you to provide a testing point with the data
+    required to perform a rapid test (see Section 6 d.) and if you add digital COVID certificates in
+    the app.
+</p>
 <p>
     The app refrains by default from using analysis tools to evaluate the way you use it. Only if
     you expressly agree to voluntarily share data or to record an error report and share it with the
-    RKI (see Sections 5 i. and 5 k.), will certain data about your use of the app be transmitted to
+    RKI (see Sections 5 j. and 5 l.), will certain data about your use of the app be transmitted to
     the RKI.
 </p>
 
@@ -153,9 +176,9 @@
 
 </h3>
 <p>
-    As soon as you enable your iPhone’s or your Android smartphone’s COVID-19
+    As soon as you enable your iPhone’s or your Android smartphone’s COVID
     exposure notification system (which is called “Exposure Notifications” or
-    “COVID-19 Exposure Notifications” respectively), your smartphone transmits
+    “COVID Exposure Notifications” respectively), your smartphone transmits
     so-called exposure data via Bluetooth, which other smartphones in your
     vicinity can record. Your smartphone, in turn, also receives the exposure
     data of other smartphones. The exposure data transmitted by your smartphone
@@ -194,7 +217,7 @@
     smartphones of other app users.
 </p>
 <p>
-    Please note: the COVID-19 exposure notification system functionality is
+    Please note: the COVID exposure notification system functionality is
     part of your operating system. The providers responsible for this system
     are therefore Apple (if you have an iPhone) and Google (if you have an
     Android smartphone). In this respect, the data processing is subject to
@@ -207,7 +230,7 @@
 <ul>
     <li>
         If you have an Android smartphone, you can find information from Google
-        on your device by going to “Settings” &gt; “Google” &gt; “COVID-19
+        on your device by going to “Settings” &gt; “Google” &gt; “COVID
         exposure notifications” and tapping on “Learn more”.
     </li>
     <li>
@@ -268,7 +291,7 @@
     stored on your smartphone.
 </p>
 <p>
-    An entry will also be created in your contact journal by default. Sections 5 g. and 6.g. explain
+    An entry will also be created in your contact journal by default. Sections 5 g. and 6 g. explain
     this in more detail. If you do not want to create an entry in your contact journal for an event
     or place, you can simply switch off this feature using the corresponding toggle switch.
 </p>
@@ -314,7 +337,8 @@
         If you provide information about the onset of any coronavirus symptoms or
     </li>
     <li>
-        If you add digital vaccination certificates in the app.
+        If you add digital COVID certificates (vaccination certificates or test certificates) in the
+        app.
     </li>
 </ul>
 <p>
@@ -345,14 +369,15 @@
 
 </p>
 <h3>
-    h. Data about your COVID-19 vaccination
+    h. Data about your COVID vaccination (data in the COVID vaccination certificate)
 
 </h3>
 <p>
-    In the app, it is possible to add your vaccination certificates that you received when you were
-    vaccinated. Requesting a digital vaccination certificate is voluntary. If you choose to use this
-    service, you will receive a printout with a QR code at the time of your vaccination. This will
-    contain the following data about your COVID-19 vaccination in encoded form:
+    In the app, it is possible to add your official vaccination certificates (digital COVID
+    certificates) that you received when you were vaccinated. Requesting a digital vaccination
+    certificate is voluntary. If you choose to use this service, you will receive a printout with a
+    QR code at the time of your vaccination. This will contain the following data about your COVID
+    vaccination in encoded form:
 </p>
 <ul>
     <li>
@@ -373,7 +398,28 @@
     certificate. This data will have been collected previously at the time of your vaccination.
 </p>
 <h3>
-    i. Usage Data (data sharing)
+    i. Data in the COVID test certificate
+</h3>
+<p>
+    You request official test certificates (digital COVID test certificates) through the app.
+    Requesting a digital test certificate is voluntary and only possible if a negative test result
+    is available. You will then receive your test certificate with a QR code in the app. This
+    contains the following data about your test result:
+</p>
+<ul>
+    <li>Personal data (last name, first name, date of birth)</li>
+    <li>Information about the test (disease, type of test, product, manufacturer)</li>
+    <li>Information about the testing procedure (date and time of the test, location of the testing
+        centre)
+    </li>
+    <li>Test result</li>
+    <li>Unique test certificate identifier.</li>
+</ul>
+<p>
+    The data is stored in the app as soon as your test result is available.
+</p>
+<h3>
+    j. Usage Data (data sharing)
 
 </h3>
 <p>
@@ -403,7 +449,7 @@
         the relevant test registration
     </li>
     <li>Whether you have used the feature for warning others and, if so, which step you reached in
-        the process (e.g. the part that asks about your symptoms)
+        the process (e.g. the part that asks about your symptoms).
     </li>
 </ul>
 <p>
@@ -434,10 +480,10 @@
 <p>
     Participation in data sharing is voluntary. To enable the data sharing feature, the authenticity
     of your app first needs to be confirmed (please note the further information about this under
-    Sections 5&nbsp;l. and 11).
+    Sections 5&nbsp;m. and 11).
 </p>
 <h3>
-    j. Participation in a survey
+    k. Participation in a survey
 </h3>
 <p>
     Some app users are offered to participate in a survey by the RKI. This offer to participate in
@@ -451,11 +497,11 @@
     in a survey and whether data should be transmitted to the RKI for this purpose. The surveys take
     place on a website outside of the app, which you will be redirected to. To enable participation
     in a survey, the authenticity of your app first needs to be confirmed (please note the further
-    information about this in Sections 5&nbsp;j. and 11).
+    information about this in Sections 5&nbsp;m. and 11).
 
 </p>
 <h3>
-    k. Contents of the error reports
+    l. Contents of the error reports
 </h3>
 <p>
     To assist the app’s technical support team with error analysis, you can record an error report
@@ -463,7 +509,7 @@
 </p>
 <ul>
     <li>
-        the steps you take in the app
+        the steps you take in the app,
     </li>
     <li>
         the technical steps and processes as well as status messages involving
@@ -489,9 +535,10 @@
 </p>
 <p>
     However, the error report does not contain information about QR codes for test registration, the
-    token stored in your app (see “Retrieving a test result” in Section 6 b. below) rapid test
-    results, vaccination certificates and entries in your contact journal. Furthermore, the error
-    report does not contain your name or other information with which the RKI can identify you.
+    token stored in your app (see “Retrieving a test result” in Section 6 b. below), rapid test
+    results, digital COVID vaccination and test certificates and entries in your contact journal.
+    Furthermore, the error report does not contain your name or other information with which the RKI
+    can identify you.
 </p>
 <p>
     You can stop recording the error report and delete the error report at any time. If you choose
@@ -506,10 +553,10 @@
     Creating and sending an error report to the RKI is voluntary. You decide yourself whether you
     want to record an error report and send it to the app’s technical support team. To send the
     error report, the authenticity of your app first needs to be confirmed (please note the further
-    information about this in Sections 5 l. and 11).
+    information about this in Sections 5 m. and 11).
 </p>
 <h3>
-    l. Confirmation of the authenticity of your app
+    m. Confirmation of the authenticity of your app
 </h3>
 <p>
     Before you can use some of the app’s features, the authenticity of your app first needs to be
@@ -532,7 +579,7 @@
 
 </h2>
 <h3>
-    a. Exposure logging
+    a.
 
 </h3>
 <p>
@@ -609,7 +656,9 @@
     separate consent to your test result being sent. It is not possible to display test results from
     testing facilities that are not connected to the app’s server system. If you have not received a
     QR code, then you cannot use this feature either.
-
+</p>
+<p>
+    The test results are also stored in your contact journal. You can delete them there at any time
 </p>
 <p>
     <u>Scanning the QR code</u>
@@ -698,6 +747,10 @@
     data (code, time you were tested) will be deleted as soon as the positive rapid test result is
     no longer displayed in the app.
 </p>
+<p>
+    The rapid test results are also stored in your contact journal. You can delete them there at any
+    time.
+</p>
 <h3>
     d. Rapid test profile
 
@@ -799,10 +852,9 @@
 <p>
     The app automatically receives the daily statistics that appear in the app
     via the server system. This generates access data. Websites linked in the app, such as
-    <a href="http://www.bundesregierung.de/">www.bundesregierung.de</a>, are
-    opened and displayed in your smartphone’s standard browser (Android
-    smartphones) or within the app (iPhones). Which data is processed in this context depends on the
-    respective providers of the websites accessed.
+    <a href="http://www.bundesregierung.de/">www.bundesregierung.de</a>, are opened and displayed in
+    your standard browser (Android smartphones) or within the app (iPhones). Which data is processed
+    in this context depends on the respective providers of the websites accessed.
 
 </p>
 <h3>
@@ -821,7 +873,7 @@
 
 </p>
 <h3>
-    h. Digital vaccination certificate
+    h. Digital vaccination certificate (COVID vaccination certificate)
 </h3>
 <p>
     The app allows you to save your vaccination certificates and keep them with you in digital form.
@@ -837,8 +889,8 @@
     Fourteen days after receiving the last vaccination dose required, the home screen in the app
     will show that you are fully vaccinated. To prove this, you can show the QR code from your
     digital vaccination certificate, which will be displayed in the app. The official verification
-    app can be used to scan this QR code and read the information about your COVID-19 vaccination.
-    The verification app will then show whether you are fully vaccinated. In addition, your name and
+    app can be used to scan this QR code and read the information about your COVID vaccination. The
+    verification app will then show whether you are fully vaccinated. In addition, your name and
     date of birth will also be displayed so that the person verifying your vaccination status can
     check this information against your official identification document.
 </p>
@@ -848,13 +900,51 @@
     do this in other ways.
 </p>
 <p>
-    Please note that the QR code from your digital vaccination certificate contains your COVID-19
+    Please note that the QR code from your digital vaccination certificate contains your COVID
     vaccination details. You should only show it if you wish to prove your vaccination status. Do
     not provide vaccination certificates or QR codes to anyone if you do not want the data to be
     read.
 </p>
 <h3>
-    i. Data sharing
+    i. Digital test certificate (COVID test certificate)
+</h3>
+<p>
+    The app allows you to save your test certificates and keep them with you in digital form. If
+    necessary, you can then use the app to prove that you have tested negative if required by law
+</p>
+<p>
+    You can request a test certificate in the app when you register a test. To do this, scan the QR
+    code you received during the test. The app will read the information about your test from the QR
+    code and receive the test result from the server. If you have taken a PCR test, retrieving the
+    result and the test certificate is additionally secured by means of your date of birth. A
+    security code is generated from your date of birth (in the form of what’s known as a hash value)
+    and compared with the RKI server. This ensures that no one else can retrieve your test result.
+</p>
+<p>
+    The app stores the test certificate data in a secure area on your smartphone. If you retrieved a
+    positive test result, no test certificate will be generated.
+</p>
+<p>
+    Your current test certificate is displayed on the app’s home screen. To prove this, you can show
+    the QR code from your digital test certificate, which will be displayed in the app. The official
+    verification app can be used to scan this QR code and read the information in the test
+    certificate (see Section 5 i.). The verification app will then show whether you tested negative
+    and when the test was performed. In addition, your name and date of birth will also be displayed
+    so that the person verifying your vaccination status can check this information against your
+    official identification document.
+</p>
+<p>
+    Please note that using the feature for requesting and saving your COVID test certificates in the
+    app is voluntary. In cases where you are required to do so by law, there are other ways to prove
+    your test result.
+</p>
+<p>
+    Please note that the QR code from your digital test certificate contains your data. You should
+    only show it if you wish to prove your negative test result. Do not provide test certificates or
+    QR codes to anyone if you do not want the data to be read.
+</p>
+<h3>
+    j. Data sharing
 </h3>
 <p>
     Data sharing is an additional feature of the app. The usage data and other voluntary information
@@ -896,7 +986,7 @@
 
 </p>
 <h3>
-    j. Error reports
+    k. Error reports
 </h3>
 <p>
     The RKI strives to offer a bug-free app. However, due to the large number of different systems
@@ -912,7 +1002,7 @@
     (e.g. by email), this may reveal information about your identity.
 </p>
 <h3>
-    k. Surveys
+    l. Surveys
 </h3>
 <p>
     The surveys take place on a website outside of the app, which you will be redirected to. The app
@@ -921,7 +1011,7 @@
 
 </p>
 <h3>
-    l. Confirmation of the authenticity of your app
+    m. Confirmation of the authenticity of your app
 
 </h3>
 <p>
@@ -970,7 +1060,7 @@
     Each server system merges the positive lists received in this way with its
     own positive list, which allows the exposure logging feature to also
     take into account possible exposures involving users of another coronavirus
-    app (see point 6&nbsp;e.) The other participating countries proceed in the same
+    app (see Section 6&nbsp;e.) The other participating countries proceed in the same
     way with the positive lists provided by the RKI.
 
 </p>
@@ -1136,8 +1226,8 @@
     time. Please note that if entries are added to the contact journal when you check in at an event
     or place, these will still be stored there even after you delete the associated check-in. Once
     you have created your rapid test profile, it will be stored in the app until you delete it
-    yourself. Once you have scanned your vaccination certificates, these will also be stored in the
-    app until you delete them yourself.
+    yourself. Once you have scanned your COVID vaccination or test certificates, these will also be
+    stored in the app until you delete them yourself.
 </p>
 
 <h3>
@@ -1226,7 +1316,7 @@
 </p>
 
 <p>
-    The EU has issued an adequacy decision for Switzerland, which determines the adequacy of the level of data protection in the country (Art. 45 GDPR). In addition, please note that users can retrieve the latest positive lists regardless of where they are (even if they are abroad on holiday or on a business trip, for example). In addition, the confirmation of the authenticity of your app may involve the transfer of data
+    In addition, the confirmation of the authenticity of your app may involve the transfer of data
     to a country outside the EU. The identifier generated by your smartphone, which contains
     information about the version of your smartphone and the app, will be transmitted to the
     provider of your smartphone’s operating system (Apple or Google). This may result in data being
@@ -1256,7 +1346,7 @@
 
 </p>
 <h3>
-    a. Consent to “exposure logging”
+    a. Consent to "exposure logging"
 
 </h3>
 <p>
@@ -1392,7 +1482,7 @@
 </ul>
 <p>
     You also have these data protection rights vis-à-vis the health authorities responsible for data
-    processing in the countries participating in the exchange server, insofar as you have
+    processing in the countries participating in the exchange servers, insofar as you have
     transmitted your random IDs from recent days to warn other people (see Section 7).
 
 </p>
@@ -1420,5 +1510,5 @@
     13353 Berlin, or by emailing <a href="mailto:datenschutz@rki.de">datenschutz@rki.de</a>.
 </p>
 <p>
-    Last amended: 28 May 2021
-</p>
+    Last amended: 17 June 2021
+</p>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/assets/privacy_tr.html b/Corona-Warn-App/src/main/assets/privacy_tr.html
index 1bf1c47d818fef8153a98ab5305c240b96401ef8..9458a6179c7ec17323366c45db95e628bd40c3d3 100644
--- a/Corona-Warn-App/src/main/assets/privacy_tr.html
+++ b/Corona-Warn-App/src/main/assets/privacy_tr.html
@@ -7,7 +7,7 @@
 <p>
     Burada aşağıdaki konular ele alınmaktadır:
 </p>
-<ul>
+<ol>
     <li><strong>1. Corona-Warn-App’ın yayımcısı kimdir?</strong></li>
     <li><strong>2. Uygulamanın kullanılması isteğe bağlı mı?</strong></li>
     <li><strong>3. Verileriniz işlenmesinde hangi yasal dayanaklar söz konusudur?</strong></li>
@@ -22,7 +22,7 @@
     <li><strong>12. Verdiğiniz rıza beyanını nasıl geri alabilirsiniz?</strong></li>
     <li><strong>13. Başka hangi veri koruma haklarına sahipsiniz?</strong></li>
     <li><strong>14. Veri koruma görevlisi ve iletişim</strong></li>
-</ul>
+</ol>
 <p>
     Bu metnin tüm kullanıcılar için anlaşılabilir olması amacıyla, mümkün olduğunca basit ve teknik
     terimler içermeyen bir metin hazırladık.
@@ -49,23 +49,41 @@
 <p>
     Uygulamanın kullanılması isteğe bağlıdır. Uygulamayı yüklemeniz, Uygulamanın hangi işlevlerini
     kullanmanız ve verileri diğer kişilerle paylaşmanız noktasında yalnızca siz karar verirsiniz.
-    Kişisel verilerinizin RKI’ye veya diğer kullanıcılara aktarılmasını gerektiren Uygulamanın tüm
-    ana işlevleri, sizden önceden açıkça rızanızı vermenizi gerektirir. Rızanızı vermezseniz veya
-    sonradan bu rızayı geri alırsanız, bu durum sizin için bir sakınca doğurmaz.
+    Kişisel verilerinizin RKI’ye veya diğer kullanıcılara aktarılmasını gerektiren Uygulamanın temel
+    işlevleri için sizden önceden açıkça rızanızı vermenizi istiyoruz. Resmi dijital Covid
+    sertifikalarına (Covid test sertifikası ve Covid aşı sertifikası) ilişkin kanıtların sağlanması
+    için yeni yasal dayanaklar söz konusudur. Bu bağlamda sizin ayrıca bir rıza beyanında bulunmanız
+    gerekmemektedir. Ancak bu sertifikalar yalnızca sizin talebiniz doğrultusunda oluşturulmaktadır.
+    Dijital Covid test sertifikalarını talep etmek ve kullanmak isteğe bağlıdır.
+</p>
+<p>
+    Bu konuda rızanızı vermezseniz, sonradan bu rızayı geri alırsanız veya dijital Covid sertifikası
+    talep etmezseniz, bu durum sizin için bir sakınca doğurmaz.
 </p>
 <h2>
     3. Verileriniz işlenmesinde hangi yasal dayanaklar söz konusudur?
 </h2>
 <p>
-    Esas itibariyle yalnızca siz daha önce açık bir şekilde rıza beyanında bulunmuşsanız,
-    verileriniz ancak o zaman RKI tarafından işlenir. Buradaki yasal dayanak, GVKT (Genel Veri
-    Koruma Tüzüğü) madde 6, fıkra 1, cümle 1, bent a ve sağlık verileri durumundaki yasal dayanak
-    ise GVKT madde 9, fıkra 2, bent a’dır. Daha önce vermiş olduğunuz rızanızı, istediği zaman geri
-    alabilirsiniz (geri alma hakkı). Onayınız geri alma hakkı ile ilgili ayrıntılı bilgileri Madde
-    12’de bulabilirsiniz. Günlük istatistiklerin sağlanması için erişim verilerinin işlenmesi (bkz.
-    Madde 6 f.), GVKT madde 6, fıkra 1, bent e ile bağlantılı olarak BGA-NachfG (Federal Sağlık
-    Kurumu Halef Kuruluşları hakkında Kanun) madde 4, fıkra 4 uyarınca RKI tarafından toplumun
-    bilgilendirilmesi kapsamında gerçekleşir.
+    Esas itibariyle yalnızca siz daha önce açıkça rıza beyanında bulunmuşsanız, verileriniz ancak o
+    zaman RKI tarafından risk değerlendirmesi ile bağlantılı olarak işlenir. Buradaki yasal dayanak,
+    GVKT (Genel Veri Koruma Tüzüğü) madde 6, fıkra 1, cümle 1, bent a ve sağlık verileri durumundaki
+    yasal dayanak ise GVKT madde 9, fıkra 2, bent a’dır. Daha önce vermiş olduğunuz rızanızı,
+    istediği zaman geri alabilirsiniz (geri alma hakkı).
+</p>
+<p>
+    Resmi dijital Covid sertifikalarına (Covid test sertifikası ve Covid aşı sertifikası) ilişkin
+    veri işleme süreçleri yasalar çerçevesinde düzenlenmiştir. Aşı sertifikalarının oluşturulması ve
+    belgelendirilmesi, GVKT (Genel Veri Koruma Tüzüğü) madde 9, fıkra 2, bent g ile bağlantılı
+    olarak IfSG (Enfeksiyondan Korunma Yasası) madde 22, fıkra 5’e dayanmaktadır. Test
+    sertifikalarının oluşturulması ve belgelendirilmesi, GVKT madde 9, fıkra 2, bent g ile
+    bağlantılı olarak IfSG madde 22, fıkra 7’ye dayanmaktadır.
+</p>
+<p>
+    Onayınız geri alma hakkı ile ilgili ayrıntılı bilgileri Madde 12’de bulabilirsiniz. Günlük
+    istatistiklerin sağlanması için erişim verilerinin işlenmesi (bkz. Madde 6 f), GVKT madde 6,
+    fıkra 1, bent e ile bağlantılı olarak BGA-NachfG (Federal Sağlık Kurumu Halef Kuruluşları
+    hakkında Kanun) madde 4, fıkra 4 uyarınca RKI tarafından toplumun bilgilendirilmesi kapsamında
+    gerçekleşir.
 </p>
 <h2>
     4. Uygulama kimleri hedefler?
@@ -81,19 +99,20 @@
     programlanmıştır. Bu demektir ki sistem, risk değerlendirmesi, diğer kişilerin uyarılması ve
     test sonucunun alınması için, RKI’nin veya diğer kullanıcıların sizin kimliğinizi, adınızı,
     konumunuzu veya diğer kişisel bilgilerinizi öğrenmesine olanak tanıyan verileri toplamamaktadır.
-    Kendi adınıza düzenlenen negatif hızlı test sonucu için onayı görüntüleyebileceğiniz (bkz. Madde
-    6c) “hızlı test sonucunu kanıtlama” fonksiyonu için istisna ve test merkezinde hızlı testin
-    uygulanması için gereken verilerin hazırlandığı “hızlı test profili”oluşturma fonksiyonu söz
-    konusudur (bunun için bkz. Madde 6d.).
 </p>
-
+<p>
+    Bu bağlamda istisnalar yalnızca, kendi adınıza düzenlenen negatif hızlı test sonucuna ilişkin
+    onayı görüntüleyebileceğiniz “Hızlı test sonucunu kanıtla” işlevinde (bkz. Madde 6 c), bir test
+    merkezinde hızlı testin uygulanması için gereken verilerin hazırlandığı “Hızlı test profili”
+    oluşturma işlevinde (bunun için bkz. Madde 6 d) ve bunların yanı sıra Uygulamaya dijital Covid
+    sertifikaları eklediğinizde söz konusudur.
+</p>
 <p>
     Dolayısıyla Uygulama, standart olarak analiz araçları üzerinden kullanıcı davranışınızın
     herhangi bir değerlendirmesini yapmaz. Sadece isteğe bağlı veri bağışına açıkça onay vermeniz
     veya bir hata raporu kaydetmeniz ve bunu RKI’ye iletmeniz durumunda, Uygulama kullanımınıza
-    ilişkin belirli veriler, RKI’ye aktarılacaktır (bkz. Madde 5 i ve Madde 5 k.).
+    ilişkin belirli veriler, RKI’ye aktarılacaktır (bkz. Madde 5 j ve Madde 5 l).
 </p>
-
 <p>
     Uygulama tarafından işlenen veriler aşağıdaki kategorilerde sınıflandırılabilir:
 </p>
@@ -295,7 +314,8 @@
         Olası Korona semptomlarının başlangıcına ilişkin beyanda bulunursanız veya
     </li>
     <li>
-        Uygulamaya dijital aşı sertifikaları eklediğinizde.
+        Uygulamaya dijital Covid sertifikaları (aşı sertifikaları veya test sertifikaları)
+        eklediÄŸinizde.
     </li>
 </ul>
 <p>
@@ -326,12 +346,12 @@
 
 </p>
 <h3>
-    h. Korona aşılarınıza ilişkin veriler
+    h. Korona aşılarınıza ilişkin veriler (Covid aşı sertifikasındaki veriler)
 </h3>
 <p>
-    Aşı olduğunuzda size sağlanan aşı sertifikalarınızı Uygulamaya ekleyebilirsiniz. Dijital aşı
-    sertifikasını talep etmeniz isteğe bağlıdır. Bu olanaktan yararlanmak isterseniz, aşı olduktan
-    sonra size QR kodlu bir çıktı verilir. Bu kod, Korona aşılamanızla ilgili şu verileri içerir:
+    Aşı olduğunuzda size sağlanan resmi aşı sertifikalarınızı (dijital Covid aşı sertifikaları)
+    Uygulamaya ekleyebilirsiniz. Bu olanaktan yararlanmak isterseniz, aşı olduktan sonra size QR
+    kodlu bir çıktı verilir. Bu kod, Korona aşılamanızla ilgili şu verileri içerir
 </p>
 <ul>
     <li>
@@ -353,7 +373,27 @@
     Uygulamaya kaydedilir.
 </p>
 <h3>
-    i. Kullanım verileri (veri bağışı)
+    i. Covid test sertifikasındaki veriler
+</h3>
+<p>
+    Uygulama üzerinden resmi test sertifikaları (dijital Covid test sertifikaları) talep
+    edebilirsiniz. Dijital test sertifikası talep etmek isteğe bağlıdır ve yalnızca test sonucu
+    negatifse gerçekleşir. Bu durumda test sertifikanız, bir QR kod ile birlikte Uygulamaya
+    gönderilir. Burada test sonucunuza ilişkin şu veriler bulunmaktadır:
+</p>
+<ul>
+    <li>Kişisel veriler (adı, soyadı, doğum tarihi)</li>
+    <li>Testle ilgili bilgiler (hastalık, test türü, ürün, üretici)</li>
+    <li>Testin yapılışına ilişkin veriler (testin tarihi ve saati, test merkezinin bulunduğu yer)
+    </li>
+    <li>Test sonucu</li>
+    <li>Test sertifikasının benzersiz kimlik kodu.</li>
+</ul>
+<p>
+    Bu veriler, test sonucunuz hazır olur olmaz Uygulamaya kaydedilir.
+</p>
+<h3>
+    j. Kullanım verileri (veri bağışı)
 </h3>
 <p>
     Veri bağışını etkinleştirdiğinizde Uygulama, Uygulama kullanımınıza ilişkin belirli verileri
@@ -406,15 +446,15 @@
 <p>
     RKI, Uygulamanın etki gücünü ve işlevselliğini değerlendirmek ve pandemi hakkında yeni
     çıkarımlar elde etmek için, kullanım verilerini olası opsiyonel veriler ile birleştirecek ve
-    anonimleÅŸtirilmiÅŸ istatistikler olarak deÄŸerlendirecektir
+    anonimleÅŸtirilmiÅŸ istatistikler olarak deÄŸerlendirecektir.
 </p>
 <p>
     Veri bağışına katılım, gönüllü olarak gerçekleşmektedir. Veri bağışının etkinleştirilmesi,
     Uygulamanızın orijinalliğinin doğrulanmasını gerektirir (bu konuyla ilgili daha fazla bilgi için
-    bkz. Madde 5&nbsp;l. ve 11.).
+    bkz. Madde 5 m. ve Madde 11).
 </p>
 <h3>
-    j. Ankete katılım
+    k. Ankete katılım
 </h3>
 
 <p>
@@ -429,10 +469,10 @@
     Ankete katılım isteğe bağlıdır. Bir ankete katılmaya ve kullanım verilerinin RKI’ye
     aktarılmasına, siz kendiniz karar verirsiniz. Bu anketler, yönlendirileceğiniz Uygulama
     dışındaki bir web sitesinde gerçekleştirilir. Ankete katılım, Uygulamanızın orijinalliğinin
-    doğrulanmasını gerektirir (bu konuyla ilgili daha fazla bilgi için bkz. Madde 5&nbsp;j. ve 11.).
+    doğrulanmasını gerektirir (bu konuyla ilgili daha fazla bilgi için bkz. Madde 5 m. ve Madde 11).
 </p>
 <h3>
-    k. Hata raporlarının içerikleri
+    l. Hata raporlarının içerikleri
 </h3>
 <p>
     Hata analizi ile ilgili olarak Uygulama teknik desteğine yardımcı olmak için Uygulamanızda hata
@@ -468,9 +508,9 @@
 </p>
 <p>
     Ancak hata raporu, test kaydı QR kodları ile Uygulamanızda depolanan belirteç, hızlı test
-    sonuçları, aşı sertifikaları ve temas günlüğünüzdeki veri girişlerine ilişkin herhangi bir bilgi
-    içermez. Hata raporu, adınızı ve RKI tarafından kimliğinizin tanımlanmasını sağlayacak diğer
-    verileri içermez.
+    sonuçları, dijital Covid aşı ve test sertifikaları ve temas günlüğünüzdeki veri girişlerine
+    ilişkin herhangi bir bilgi içermez. Hata raporu, adınızı ve RKI tarafından kimliğinizin
+    tanımlanmasını sağlayacak diğer verileri içermez.
 </p>
 <p>
     İstediğiniz zaman hata raporunu kaydını durdurabilir ve hata raporunu silebilirsiniz. Hata
@@ -488,7 +528,7 @@
     doğrulanmasını gerektirir (bu konuyla ilgili daha fazla bilgi için bkz. Madde 5 l ve Madde 11).
 </p>
 <h3>
-    l. Uygulamanızın orijinalliğinin doğrulanması
+    m. Uygulamanızın orijinalliğinin doğrulanması
 </h3>
 
 <p>
@@ -531,21 +571,28 @@
 </p>
 <p>
     Pozitif listedeki rastgele kimlik numaralarını ve olay kimliklerini, ek olarak bir taşıma riski
-    değeri ve tanı tipi hakkında bilgi de içerir (bkz. Madde 6 e.).
+    değeri ve tanı tipi hakkında bilgi de içerir (bkz. Madde 6 e).
 </p>
 <p>
-    Uygulama pozitif listeden aldığı bu rastgele kimlik numaralarını, COVID-19 bildirim sistemine
-    aktarır ve bu sistem bu kodları, karşılaşmalarınızda kaydedilen rastgele kimlik numaraları ile
-    karşılaştırır. COVID-19 bildirim sistemi bir eşleşme saptarsa, söz konusu maruz kalma için
-    kaydedilen maruz kalma verilerini Uygulamaya aktarır. Bu maruz kalma verileri ve pozitif
-    listedeki bilgiler (taşıma riski değeri, semptomların başlangıcına ilişkin bilgiler) enfeksiyon
-    riskinizi belirlemek için Uygulama tarafından değerlendirmeye alınır. Bu veriler için olan
-    değerlendirme kuralları, RKI’nin güncel bilimsel bulgularına (örn. temas süresinin enfeksiyon
-    riski üzerindeki etkisi) dayanmaktadır. Yeni bulgular olması durumunda RKI, Uygulamanın
-    değerlendirme ayarları üzerinden bu değerlendirme kurallarını güncelleyebilmektedir. Bu durumda,
-    yeni değerlendirme ayarları pozitif listeyle birlikte Uygulamaya aktarılır.
+    Uygulama pozitif listeden aldığı bu rastgele kimlik numaralarını ve olay kimliklerini, COVID-19
+    bildirim sistemine aktarır ve bu sistem bu kodları, karşılaşmalarınızda kaydedilen rastgele
+    kimlik numaraları ile karşılaştırır. COVID-19 bildirim sistemi bir eşleşme saptarsa, söz konusu
+    maruz kalma için kaydedilen maruz kalma verilerini Uygulamaya aktarır.
+</p>
+<p>
+    Bundan başka Uygulama, Korona testi pozitif çıkan kullanıcılarla aynı anda bir olayda veya
+    konumda bulunmuş olmanızı saptamak için pozitif listedeki olay kimliklerini giriş
+    denetimlerinizin olay kimlikleriyle karşılaştırır.
+</p>
+<p>
+    Bu maruz kalma verileri, olay kimlikleri (ilişkili giriş ve çıkış saatleri de dahil) ve pozitif
+    listelerdeki bilgiler (taşıma riski değeri, semptomların başlangıcına ilişkin bilgiler)
+    enfeksiyon riskinizi belirlemek için Uygulama tarafından değerlendirmeye alınır. Bu veriler için
+    olan değerlendirme kuralları, RKI’nin güncel bilimsel bulgularına (örn. temas süresinin
+    enfeksiyon riski üzerindeki etkisi) dayanmaktadır. Yeni bulgular olması durumunda RKI,
+    Uygulamanın değerlendirme ayarları üzerinden bu değerlendirme kurallarını güncelleyebilmektedir.
+    Bu durumda, yeni değerlendirme ayarları pozitif listeler ile birlikte Uygulamaya aktarılır.
 </p>
-
 <p>
     Enfeksiyon riski, yalnızca Uygulama içinde hesaplanır ve COVID-19 bildirim sistemine veya diğer
     alıcılara (RKI, Almanya’daki diğer sağlık kurumları veya diğer ülkeler, Apple, Google ve diğer
@@ -555,12 +602,15 @@
 <p>
     Sizin için bir enfeksiyon riski hesaplanırsa, bu değer Uygulamada görüntülenecektir.
     Görüntülenen bu risk değeri yüksek ise, bunun anlamı, sizin Korona testi pozitif çıkan ve bir
-    uyarı tetikleyen diğer kullanıcılarla bir veya daha çok kez karşılaşmış olmanızdır. Son 14 gün
-    için hesaplanan risk, iletişim günlüğünün takvim görünümünde görüntülenir. Lütfen riskin
-    kaynağıyla ilgili yanlış çıkarımlar yapmaktan kaçının: Belli bir gün için hesaplanan ve
+    uyarı tetikleyen diğer kullanıcılarla bir veya daha çok kez karşılaşmış veya bu tür kullanıcılar
+    ile aynı anda bir olay veya bir konuma giriş yapmış olmanızdır.
+</p>
+<p>
+    Son 14 gün için hesaplanan risk, iletişim günlüğünün takvim görünümünde görüntülenir. Lütfen
+    riskin kaynağıyla ilgili yanlış çıkarımlar yapmaktan kaçının: Belli bir gün için hesaplanan ve
     görüntülenen bir risk, tanımadığınız kullanıcılarla farkına varmadığınız bir karşılaşmaya kadar
-    geri gidebilir ve mutlaka iletişim günlüğüne girdiğiniz kişiler veya yerlerle ilgili olması
-    gerekmez.
+    geri gidebilir ve mutlaka iletişim günlüğüne girdiğiniz kişiler, konumlar veya olaylar ile
+    ilgili olması gerekmez.
 </p>
 <h3>
     b. Test sonucu çağırın
@@ -630,6 +680,10 @@
     mevcudiyetini doğrulamasını ister. İlgili doğrulama alındığında, sunucu sistemi TAN’ı oluşturur
     ve bunu uygulamaya iletir. Bu TAN’ın bir kopyası sunucu sisteminde kalır.
 </p>
+<p>
+    Test sonuçları ayrıca temas günlüğünüzde de saklanır. Bunları istediğiniz zaman oradan
+    kaldırabilirsiniz.
+</p>
 <h3>
     c. Hızlı test sonucunun kanıtı
 </h3>
@@ -661,6 +715,10 @@
     Uygulamadan hemen silinir. Diğer hızlı test verileriniz Uygulamada poztif çıkan hızlı test
     sonucu görüntülenmediği anda (kodlar, test zamanı) silinir.
 </p>
+<p>
+    Hızlı test sonuçları ayrıca temas günlüğünüzde de saklanır. Bunları istediğiniz zaman oradan
+    kaldırabilirsiniz.
+</p>
 <h3>
     d. Hızlı test profili
 </h3>
@@ -780,7 +838,7 @@
     enfeksiyonların önüne geçebilir.
 </p>
 <h3>
-    h. Dijital aşı sertifikası
+    h. Dijital aşı sertifikası (Covid aşı sertifikası)
 </h3>
 <p>
     Uygulama, aşı sertifikalarınızı kaydetmenizi ve dijital olarak yanınızda bulundurmanızı mümkün
@@ -812,13 +870,51 @@
     okunmasını istemiyorsanız, aşı sertifikasını ve QR kodu hiç kimseye göstermeyin.
 </p>
 <h3>
-    i. Veri bağışı
+    i. Dijital test kanıtı (Covid test sertifikası)
+</h3>
+<p>
+    Uygulama, test sertifikalarınızı kaydetmenizi ve dijital olarak yanınızda bulundurmanızı mümkün
+    kılar. Gerekli olduğunda, yasal açıdan zorunlu durumlarda, yaptırdığınız testin negatif
+    çıktığını kanıtlamak için Uygulamayı kullanabilirsiniz.
+</p>
+<p>
+    Bir testi kaydettiğinizde, Uygulamada bir test sertifikası talep edebilirsiniz. Bunun için, test
+    işlemi sırasında aldığınız QR kodu tarayın. Uygulama, testinize ilişkin verileri QR kod
+    üzerinden okur ve test sonucunu ilgili sunucudan alır. Bir PCR testi yaptırdığınızda, ilgili
+    sonuç alınıp, test sertifikası ve ayrıca doğum tarihinizle birlikte kaydedilir. Doğum tarihinden
+    bir güvenlik kodu (hash değeri şeklinde) oluşturulur ve bu değer, RKI sunucusu ile
+    karşılaştırılır. Bu sayede diğer kişilerin test sonucunuzu çağırmasının önüne geçilir.
+</p>
+<p>
+    Uygulama, aldığı test sertifikası verilerini akıllı telefonunuzun güvenli bir alanına kaydeder.
+    Test sonucunuz pozitif çıkmışsa, herhangi bir test sertifikası oluşturulmaz.
+</p>
+<p>
+    Uygulamadaki ana ekranda güncel test sertifikanız görüntülenir. Uygulamadaki dijital test
+    sertifikasının QR kodu gerektiğinde kanıt olarak gösterebilirsiniz. Bu QR kod, resmi kontrol
+    uygulamasıyla taranabilir ve test sertifikasındaki veriler buradan okunabilir (Bkz. Madde 5 i).
+    Daha sonra kontrol uygulamasında ne zaman test yaptırdığınız ve test sonucunuzun negatif çıkıp
+    çıkmadığı görüntülenir. Ayrıca adınız ve doğum tarihiniz de görüntülenir, bu sayede kontrol eden
+    kişi bu bilgileri resmi kimlik belgenizdeki bilgiler ile karşılaştırabilir.
+</p>
+<p>
+    Uygulamadaki Covid test sertifikalarınızı talep etme ve kaydetme işlevlerini kullanmanın isteğe
+    bağlı olduğunu lütfen göz önünde bulundurun. Yasal açıdan zorunlu durumlarda test sonucunuzu
+    diğer yöntemlerle de kanıtlayabilirsiniz.
+</p>
+<p>
+    Dijital test sertifikanızdaki QR kodun veriler içerdiğini lütfen unutmayın. Yalnızca negatif
+    test sonucunu kanıtlamak istediğinizde bunu gösterin. Söz konusu verilerin okunmasını
+    istemiyorsanız, test sertifikasını ve QR kodu hiç kimseye göstermeyin.
+</p>
+<h3>
+    j. Veri bağışı
 </h3>
 
 <p>
-    Veri bağışı, Uygulamanın ek bir işlevidir. Veri bağışı kapsamında RKI’ye aktarılan kullanım
-    verileri ve diğer isteğe bağlı veriler, Uygulamanın etki gücünü ölçmek ve aşağıda sıralanan
-    iyileştirmeleri sağlamak üzere değerlendirmeler yapmak üzere kullanılır:
+    Veri bağışı kapsamında RKI’ye aktarılan kullanım verileri ve diğer isteğe bağlı veriler,
+    Uygulamanın etki gücünü ölçmek ve aşağıda sıralanan iyileştirmeleri sağlamak üzere
+    değerlendirmeler yapmak üzere kullanılır:
 </p>
 <ul>
     <li>
@@ -839,7 +935,7 @@
         tesisler ve laboratuvarlarla bağlantılı olarak veya belirli coğrafi bölgelerde Uygulamanın
         kullanımıyla ilgili olası sorunların varlığını saptamak hedeflenir. Böylece veri bağışı
         nedeniyle örneğin, test sonuçlarının belirli coğrafi bölgelerde geç elde edileceğinin
-        farkına varılabilmektedir. Bu sayede sorumlu sağlık kurumu yetkilileri de olası teknik
+        farkına varmak mümkün olabilir. Bu sayede sorumlu sağlık kurumu yetkilileri de olası teknik
         arızalar hakkında bilgilendirilebilmektedir.
     </li>
     <li>
@@ -854,7 +950,7 @@
     öğrenmez.
 </p>
 <h3>
-    j. Hata raporları
+    k. Hata raporları
 </h3>
 
 <p>
@@ -872,7 +968,7 @@
     çıkarabileceğini göz önünde bulundurun.
 </p>
 <h3>
-    k. Anketler
+    l. Anketler
 </h3>
 
 <p>
@@ -881,7 +977,7 @@
     amaçları, anket web sitesinde anketteki bilgilerde yer almaktadır.
 </p>
 <h3>
-    l. Uygulamanızın orijinalliğinin doğrulanması
+    m. Uygulamanızın orijinalliğinin doğrulanması
 </h3>
 
 <p>
@@ -900,8 +996,7 @@
     Diğer ülkelerdeki resmi Korona uygulamalarının kullanıcılarının da uyarılmasını için RKI, bu
     ülkelerdeki sorumlu merciler ve kurumlar (bundan böyle: <strong>sağlık kurumları</strong>) ile
     birlikte uyarı mesajlarının sınır ötesi değişimine yönelik merkezi uyarı sunucuları(bundan
-    böyle: <strong>veri değişim sunucusu</strong>) kurmuştur. Veri değişim sunucusu, elektronik
-    sağlık hizmetleri için üye devletler arasında kurulmuş olan ağın dijital altyapısını kullanır.
+    böyle: <strong>veri değişim sunucusu</strong>) kurmuştur.
 </p>
 <ul>
     <li>Avrupa Birliği üye devletlerinden katılımcı ülkelerin veri değişim sunucusu, üye devletler
@@ -939,16 +1034,16 @@
         Kararı (AB) 2020/1023, bu karara <a
                 href="https://eur-lex.europa.eu/eli/dec_impl/2020/1023/oj">
             https://eur-lex.europa.eu/eli/dec_impl/2020/1023/oj
-        </a>. adresinden erişebilirsiniz. RKI ve katılımcı ülkelerin yetkili sağlık kurumları, sınır
-        ötesi risk değerlendirmesi ve uyarısı sağlamak üzere veri değişim sunucularında bulunan
-        pozitif listelerde yer alan verilerin (rastgele kimlik numaraları ve semptomların
+        </a>). adresinden erişebilirsiniz. RKI ve katılımcı ülkelerin yetkili sağlık kurumları,
+        sınır ötesi risk değerlendirmesi ve uyarısı sağlamak üzere veri değişim sunucularında
+        bulunan pozitif listelerde yer alan verilerin (rastgele kimlik numaraları ve semptomların
         başlangıcına ilişkin olası bilgiler) işlenmesinden müştereken sorumludur.
     </li>
     <li>
         İsviçre ile ortaklaşa işletilen veri değişim sunucusunun çalışması ve veri alışverişi, RKI
         ve İsviçre arasında özel bir anlaşmada düzenlenmekte olup, ayrıntıları <a
             href="https://www.rki.de/DE/Content/InfAZ/N/Neuartiges_Coronavirus/WarnApp/Warn_App.html">
-        https://www.rki.de/DE/Content/InfAZ/N/Neuartiges_Coronavirus/WarnApp/Warn_App.html</a>
+        https://www.rki.de/DE/Content/InfAZ/N/Neuartiges_Coronavirus/WarnApp/Warn_App.html</a>.
         adresinden erişilebilir. Veri değişim sunucusunun teknik işletimi, İsviçre Federal Sağlık
         Dairesi tarafından gerçekleştirilmektedir. Pozitif listelerin saklanması, sağlanması ve daha
         sonra silinmesinden, RKI ve İsviçre Federal Halk Sağlığı Dairesi müştereken sorumludur.
@@ -1074,8 +1169,8 @@
     silinir. Ancak bu verileri istediÄŸiniz zaman, daha erken de silebilirsiniz. Bir olaya veya bir
     konuma giriş denetimi yaptırdığınızda, ilgili giriş denetimi kaydı silindikten sonra bile temas
     günlüğündeki verilerin hâlâ orada saklı kaldıklarını lütfen unutmayın. Bir kez hızlı test
-    profili oluşturduysanız bu, siz tekrar silene kadar uygulamada kalır. Aşı sertifikalarını
-    taradıysanız, bu veriler siz onları silene kadar Uygulamada kayıtlı kalacaktır.
+    profili oluşturduysanız bu, siz tekrar silene kadar uygulamada kalır. Covid aşı ve test
+    sertifikalarını taradıysanız, bu veriler siz onları silene kadar Uygulamada kayıtlı kalacaktır.
 </p>
 <h3>
     b. Sunucu sistemlerindeki veriler
@@ -1083,7 +1178,8 @@
 
 <p>
     Pozitif listeler, 14 gün sonra tüm sunucu sistemlerinden (değişim sunucuları dahil) silinir.
-    Diğer tüm veriler en geç 21 gün sonra silinir.
+    Veri bağışı kapsamında ve Uygulamanızın orijinalliğinin doğrulanması için aktarılan veriler
+    haricinde diğer tüm veriler en geç 21 gün sonra silinir.
 </p>
 <h3>
     c. Veri bağışı
@@ -1328,5 +1424,5 @@ Diğer insanları uyarmak için test sonucunuzun ( (daha doğrusu, son 14 güne
     görevlisi), Nordufer 20,13353 Berlin veya e-posta yoluyla: <a href="mailto:datenschutz@rki.de">datenschutz@rki.de</a>.
 </p>
 <p>
-    Baskı 28.05.2021
+    Baskı 17.06.2021
 </p>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
index b6a78237228f270bc1fd9ec93efd44eb389e0f0c..e9b71a70568681e1083261c7ff6011b1fd4b81e7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
@@ -21,6 +21,8 @@ import de.rki.coronawarnapp.coronatest.type.pcr.execution.PCRResultScheduler
 import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultScheduler
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.notification.RATTestResultAvailableNotificationService
+import de.rki.coronawarnapp.covidcertificate.test.core.execution.TestCertificateRetrievalScheduler
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.VaccinationUpdateScheduler
 import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsScheduler
 import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler
 import de.rki.coronawarnapp.exception.reporting.ErrorReportReceiver
@@ -42,7 +44,6 @@ import de.rki.coronawarnapp.util.device.ForegroundState
 import de.rki.coronawarnapp.util.di.AppInjector
 import de.rki.coronawarnapp.util.di.ApplicationComponent
 import de.rki.coronawarnapp.util.hasAPILevel
-import de.rki.coronawarnapp.vaccination.core.execution.VaccinationUpdateScheduler
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
@@ -83,6 +84,7 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
     @Inject lateinit var pcrTestResultAvailableNotificationService: PCRTestResultAvailableNotificationService
     @Inject lateinit var raTestResultAvailableNotificationService: RATTestResultAvailableNotificationService
     @Inject lateinit var vaccinationUpdateScheduler: VaccinationUpdateScheduler
+    @Inject lateinit var testCertificateRetrievalScheduler: TestCertificateRetrievalScheduler
 
     @AppScope
     @Inject lateinit var appScope: CoroutineScope
@@ -138,6 +140,7 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
         Timber.v("Setting up test result available notification services.")
         pcrTestResultAvailableNotificationService.setup()
         raTestResultAvailableNotificationService.setup()
+        testCertificateRetrievalScheduler.setup()
 
         Timber.v("Setting up vaccination data update scheduler.")
         vaccinationUpdateScheduler.setup()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigModule.kt
index d076c040865e4500f5022287c34febb3fe5b2857..f1377d38f70d387cd484bca2f4b4a2193232c7d8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigModule.kt
@@ -7,6 +7,7 @@ import de.rki.coronawarnapp.appconfig.download.AppConfigApiV2
 import de.rki.coronawarnapp.appconfig.mapping.AnalyticsConfigMapper
 import de.rki.coronawarnapp.appconfig.mapping.CWAConfigMapper
 import de.rki.coronawarnapp.appconfig.mapping.CoronaTestConfigMapper
+import de.rki.coronawarnapp.appconfig.mapping.CovidCertificateConfigMapper
 import de.rki.coronawarnapp.appconfig.mapping.ExposureDetectionConfigMapper
 import de.rki.coronawarnapp.appconfig.mapping.ExposureWindowRiskCalculationConfigMapper
 import de.rki.coronawarnapp.appconfig.mapping.KeyDownloadParametersMapper
@@ -96,6 +97,10 @@ class AppConfigModule {
     fun coronaTestConfigMapper(mapper: CoronaTestConfigMapper):
         CoronaTestConfig.Mapper = mapper
 
+    @Provides
+    fun covidCertificateConfigMapper(mapper: CovidCertificateConfigMapper):
+        CovidCertificateConfig.Mapper = mapper
+
     companion object {
         private val HTTP_TIMEOUT_APPCONFIG = Duration.standardSeconds(10)
         private const val DEFAULT_CACHE_SIZE = 2 * 1024 * 1024L // 5MB
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/CovidCertificateConfig.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/CovidCertificateConfig.kt
new file mode 100644
index 0000000000000000000000000000000000000000..620b5e4ab2cbfb2432a70b889c27fd47b3385711
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/CovidCertificateConfig.kt
@@ -0,0 +1,16 @@
+package de.rki.coronawarnapp.appconfig
+
+import de.rki.coronawarnapp.appconfig.mapping.ConfigMapper
+import org.joda.time.Duration
+
+interface CovidCertificateConfig {
+
+    val testCertificate: TestCertificate
+
+    interface TestCertificate {
+        val waitAfterPublicKeyRegistration: Duration
+        val waitForRetry: Duration
+    }
+
+    interface Mapper : ConfigMapper<CovidCertificateConfig>
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ConfigMapping.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ConfigMapping.kt
index d0d3790269465d69bc2423d9ea0175395f2275d4..aaac8ae61dc174a5b5e618200dee68fd1c165b9a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ConfigMapping.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ConfigMapping.kt
@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.appconfig.mapping
 import de.rki.coronawarnapp.appconfig.AnalyticsConfig
 import de.rki.coronawarnapp.appconfig.CWAConfig
 import de.rki.coronawarnapp.appconfig.CoronaTestConfig
+import de.rki.coronawarnapp.appconfig.CovidCertificateConfig
 import de.rki.coronawarnapp.appconfig.ExposureDetectionConfig
 import de.rki.coronawarnapp.appconfig.ExposureWindowRiskCalculationConfig
 import de.rki.coronawarnapp.appconfig.KeyDownloadConfig
@@ -24,4 +25,5 @@ interface ConfigMapping :
     val logUpload: LogUploadConfig
     val presenceTracing: PresenceTracingConfig
     val coronaTestParameters: CoronaTestConfig
+    val covidCertificateParameters: CovidCertificateConfig
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ConfigParser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ConfigParser.kt
index ced74a1e8d5cd4bc74b31b88e94c3a0c30466333..b29c6b17d9e056b96b9a563e6d91ea493564954d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ConfigParser.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ConfigParser.kt
@@ -4,6 +4,7 @@ import dagger.Reusable
 import de.rki.coronawarnapp.appconfig.AnalyticsConfig
 import de.rki.coronawarnapp.appconfig.CWAConfig
 import de.rki.coronawarnapp.appconfig.CoronaTestConfig
+import de.rki.coronawarnapp.appconfig.CovidCertificateConfig
 import de.rki.coronawarnapp.appconfig.ExposureDetectionConfig
 import de.rki.coronawarnapp.appconfig.ExposureWindowRiskCalculationConfig
 import de.rki.coronawarnapp.appconfig.KeyDownloadConfig
@@ -14,6 +15,7 @@ import de.rki.coronawarnapp.server.protocols.internal.v2.AppConfigAndroid
 import timber.log.Timber
 import javax.inject.Inject
 
+@Suppress("LongParameterList")
 @Reusable
 class ConfigParser @Inject constructor(
     private val cwaConfigMapper: CWAConfig.Mapper,
@@ -25,6 +27,7 @@ class ConfigParser @Inject constructor(
     private val logUploadConfigMapper: LogUploadConfig.Mapper,
     private val presenceTracingConfigMapper: PresenceTracingConfig.Mapper,
     private val coronaTestConfigMapper: CoronaTestConfig.Mapper,
+    private val covidCertificateConfigMapper: CovidCertificateConfig.Mapper,
 ) {
 
     fun parse(configBytes: ByteArray): ConfigMapping = try {
@@ -39,7 +42,8 @@ class ConfigParser @Inject constructor(
                 analytics = analyticsConfigMapper.map(it),
                 logUpload = logUploadConfigMapper.map(it),
                 presenceTracing = presenceTracingConfigMapper.map(it),
-                coronaTestParameters = coronaTestConfigMapper.map(it)
+                coronaTestParameters = coronaTestConfigMapper.map(it),
+                covidCertificateParameters = covidCertificateConfigMapper.map(it),
             )
         }
     } catch (e: Exception) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/CovidCertificateConfigMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/CovidCertificateConfigMapper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e0ca90bd9242a383e173be4d47e3336a786c2079
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/CovidCertificateConfigMapper.kt
@@ -0,0 +1,59 @@
+package de.rki.coronawarnapp.appconfig.mapping
+
+import dagger.Reusable
+import de.rki.coronawarnapp.appconfig.CovidCertificateConfig
+import de.rki.coronawarnapp.server.protocols.internal.v2.AppConfigAndroid
+import de.rki.coronawarnapp.server.protocols.internal.v2.DgcParameters
+import org.joda.time.Duration
+import timber.log.Timber
+import javax.inject.Inject
+
+@Reusable
+class CovidCertificateConfigMapper @Inject constructor() : CovidCertificateConfig.Mapper {
+    override fun map(rawConfig: AppConfigAndroid.ApplicationConfigurationAndroid): CovidCertificateConfig {
+        if (!rawConfig.hasDgcParameters()) {
+            Timber.w("Config has no DCC parameters.")
+            return CovidCertificateConfigContainer()
+        }
+
+        return CovidCertificateConfigContainer(
+            testCertificate = rawConfig.dgcParameters.mapCovidCertificateConfig()
+        )
+    }
+
+    private fun DgcParameters.DGCParameters.mapCovidCertificateConfig(): CovidCertificateConfig.TestCertificate {
+        if (!this.hasTestCertificateParameters()) {
+            Timber.w("DCC config has no test certificate parameters.")
+            return TestCertificateConfigContainer()
+        }
+        return with(testCertificateParameters) {
+            TestCertificateConfigContainer(
+                waitAfterPublicKeyRegistration = waitAfterPublicKeyRegistrationInSeconds.let {
+                    if (it !in 0..60) {
+                        Timber.e("Invalid value for waitAfterPublicKeyRegistration: %s", it)
+                        TestCertificateConfigContainer().waitAfterPublicKeyRegistration
+                    } else {
+                        Duration.standardSeconds(it.toLong())
+                    }
+                },
+                waitForRetry = waitForRetryInSeconds.let {
+                    if (it !in 0..60) {
+                        Timber.e("Invalid value for waitForRetryInSeconds: %s", it)
+                        TestCertificateConfigContainer().waitForRetry
+                    } else {
+                        Duration.standardSeconds(it.toLong())
+                    }
+                }
+            )
+        }
+    }
+
+    data class CovidCertificateConfigContainer(
+        override val testCertificate: CovidCertificateConfig.TestCertificate = TestCertificateConfigContainer()
+    ) : CovidCertificateConfig
+
+    data class TestCertificateConfigContainer(
+        override val waitAfterPublicKeyRegistration: Duration = Duration.standardSeconds(10),
+        override val waitForRetry: Duration = Duration.standardSeconds(10),
+    ) : CovidCertificateConfig.TestCertificate
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/DefaultConfigMapping.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/DefaultConfigMapping.kt
index 220c854e09f792a985f353684c937fd5b0f655a1..fe11403406d419a66895c4b9d78987d7448b9cd0 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/DefaultConfigMapping.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/DefaultConfigMapping.kt
@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.appconfig.mapping
 import de.rki.coronawarnapp.appconfig.AnalyticsConfig
 import de.rki.coronawarnapp.appconfig.CWAConfig
 import de.rki.coronawarnapp.appconfig.CoronaTestConfig
+import de.rki.coronawarnapp.appconfig.CovidCertificateConfig
 import de.rki.coronawarnapp.appconfig.ExposureDetectionConfig
 import de.rki.coronawarnapp.appconfig.ExposureWindowRiskCalculationConfig
 import de.rki.coronawarnapp.appconfig.KeyDownloadConfig
@@ -22,6 +23,7 @@ data class DefaultConfigMapping(
     override val logUpload: LogUploadConfig,
     override val presenceTracing: PresenceTracingConfig,
     override val coronaTestParameters: CoronaTestConfig,
+    override val covidCertificateParameters: CovidCertificateConfig,
 ) : ConfigMapping,
     CWAConfig by cwaConfig,
     KeyDownloadConfig by keyDownloadConfig,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt
index 83c22418c7b6b6abe8cb5eaca26ac82b059009c4..8ea9f61d764bd44df49652abd76dce8ee9e8ba1c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt
@@ -3,8 +3,9 @@ package de.rki.coronawarnapp.bugreporting.censors.vaccination
 import dagger.Reusable
 import de.rki.coronawarnapp.bugreporting.censors.BugCensor
 import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensorContainer
-import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
 import java.util.LinkedList
 import javax.inject.Inject
 
@@ -35,7 +36,7 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor {
 
                 newMessage = censorNameData(nameData, newMessage)
 
-                vaccinationDatas.forEach { data ->
+                payload.let { data ->
                     newMessage = censorVaccinationData(data, newMessage)
                 }
             }
@@ -45,7 +46,7 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor {
     }
 
     private fun censorVaccinationData(
-        vaccinationData: VaccinationDGCV1.VaccinationData,
+        vaccinationData: VaccinationDccV1.VaccinationData,
         message: CensorContainer
     ): CensorContainer {
         var newMessage = message
@@ -76,8 +77,8 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor {
         )
 
         newMessage = newMessage.censor(
-            vaccinationData.countryOfVaccination,
-            "vaccinationData/countryOfVaccination"
+            vaccinationData.certificateCountry,
+            "vaccinationData/certificateCountry"
         )
 
         newMessage = newMessage.censor(
@@ -100,7 +101,7 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor {
         return newMessage
     }
 
-    private fun censorNameData(nameData: VaccinationDGCV1.NameData, message: CensorContainer): CensorContainer {
+    private fun censorNameData(nameData: Dcc.NameData, message: CensorContainer): CensorContainer {
         var newMessage = message
 
         nameData.familyName?.let { fName ->
@@ -146,8 +147,8 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor {
 
         fun clearQRCodeStringToCensor() = synchronized(qrCodeStringsToCensor) { qrCodeStringsToCensor.clear() }
 
-        private val certsToCensor = LinkedList<VaccinationCertificateData>()
-        fun addCertificateToCensor(cert: VaccinationCertificateData) = synchronized(certsToCensor) {
+        private val certsToCensor = LinkedList<DccData<VaccinationDccV1>>()
+        fun addCertificateToCensor(cert: DccData<VaccinationDccV1>) = synchronized(certsToCensor) {
             certsToCensor.apply {
                 if (contains(cert)) return@apply
                 addFirst(cert)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryCoronaTestEntity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryCoronaTestEntity.kt
index d0c63e34ebdf841d46c6b1cbb8eb799512251180..cf20181d55891f596a560624e7f60d46c3628413 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryCoronaTestEntity.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryCoronaTestEntity.kt
@@ -48,7 +48,7 @@ fun Map.Entry<CoronaTestGUID, CoronaTest>.asTestResultEntity(): ContactDiaryCoro
             testType = if (type == CoronaTest.Type.PCR) PCR else ANTIGEN,
             result = if (isPositive) POSITIVE else NEGATIVE,
             time = when (this) {
-                is RACoronaTest -> testedAt
+                is RACoronaTest -> testTakenAt
                 else -> registeredAt
             }
         )
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestModule.kt
index b4295fc63485450d62cca4ca0ddcdd2552c533fe..1445d927e4f2eed79b3ba219c0708249eb33ee07 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestModule.kt
@@ -5,8 +5,8 @@ import dagger.Module
 import dagger.multibindings.IntoSet
 import de.rki.coronawarnapp.coronatest.server.VerificationModule
 import de.rki.coronawarnapp.coronatest.type.CoronaTestProcessor
-import de.rki.coronawarnapp.coronatest.type.pcr.PCRProcessor
-import de.rki.coronawarnapp.coronatest.type.rapidantigen.RAProcessor
+import de.rki.coronawarnapp.coronatest.type.pcr.PCRTestProcessor
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.RATestProcessor
 
 @Module(
     includes = [VerificationModule::class]
@@ -16,12 +16,12 @@ abstract class CoronaTestModule {
     @Binds
     @IntoSet
     abstract fun pcrProcessor(
-        processor: PCRProcessor
+        processor: PCRTestProcessor
     ): CoronaTestProcessor
 
     @Binds
     @IntoSet
     abstract fun ratProcessor(
-        processor: RAProcessor
+        processor: RATestProcessor
     ): CoronaTestProcessor
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepository.kt
index c0815c4f3ca43e16e2bab4cc6146b0e488909d99..9af108afeaf5050149af78eed0d289005709cea8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepository.kt
@@ -224,6 +224,14 @@ class CoronaTestRepository @Inject constructor(
         }
     }
 
+    suspend fun markDccAsCreated(identifier: TestIdentifier, created: Boolean) {
+        Timber.tag(TAG).i("markDccAsCreated(identifier=%s, created=%b)", identifier, created)
+
+        modifyTest(identifier) { processor, before ->
+            processor.markDccCreated(before, created)
+        }
+    }
+
     companion object {
         const val TAG = "CoronaTestRepository"
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractor.kt
index 703886f8eb57475d09d92de7a2779394d92972ac..2265512e021fba44f390d1bc7eb90bd4d79d4e7a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractor.kt
@@ -147,15 +147,9 @@ class RapidAntigenQrCodeExtractor @Inject constructor() : QrCodeExtractor<Corona
 
         private fun requireValidHash() {
             val isQrCodeWithPersonalData = firstName != null && lastName != null && dateOfBirth != null
-            val rawBuilder = StringBuilder(
+            val generatedHash =
                 "${raw.dateOfBirth}#${raw.firstName}#${raw.lastName}#${raw.timestamp}#${raw.testid}#${raw.salt}"
-            )
-            if (raw.dgc != null) {
-                val asInt = if (raw.dgc == true) 1 else 0
-                rawBuilder.append("#$asInt")
-            }
-
-            val generatedHash = rawBuilder.toString().toSHA256()
+                    .toSHA256()
             if (isQrCodeWithPersonalData && !generatedHash.equals(hash, true)) {
                 throw InvalidQRCodeException("Generated hash doesn't match QRCode hash")
             }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
index f516a6e5e67ed5e7f74e72661b2c4411b60e5b9e..824a468b746938f0b30c3c532cc7f00800ad8cd4 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
@@ -43,7 +43,7 @@ interface CoronaTest {
     // Is the digital green certificate supported by the point of care that issued the test
     val isDccSupportedByPoc: Boolean
 
-    // Has the user given consent to us obtaining the DGC
+    // Has the user given consent to us obtaining the DCC
     val isDccConsentGiven: Boolean
 
     // Has the corresponding entry been created in the test certificate storage
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTestProcessor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTestProcessor.kt
index 68b69445ce7604d310952cb757277f46d3ff4883..32351e107021eafe1e4fbd2ad37d2979f7980a2b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTestProcessor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTestProcessor.kt
@@ -24,4 +24,6 @@ interface CoronaTestProcessor {
     suspend fun updateSubmissionConsent(test: CoronaTest, consented: Boolean): CoronaTest
 
     suspend fun updateResultNotification(test: CoronaTest, sent: Boolean): CoronaTest
+
+    suspend fun markDccCreated(test: CoronaTest, created: Boolean): CoronaTest
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRTestProcessor.kt
similarity index 95%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessor.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRTestProcessor.kt
index a4e0346e2479e26e990de87ed99e6fa993ff00d9..58bfe8a28d16fd55ab3d07efd251fd7f4458e288 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRTestProcessor.kt
@@ -37,7 +37,7 @@ import timber.log.Timber
 import javax.inject.Inject
 
 @Reusable
-class PCRProcessor @Inject constructor(
+class PCRTestProcessor @Inject constructor(
     private val timeStamper: TimeStamper,
     private val submissionService: CoronaTestService,
     private val analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector,
@@ -129,6 +129,7 @@ class PCRProcessor @Inject constructor(
             registrationToken = response.registrationToken,
             testResult = testResult,
             testResultReceivedAt = determineReceivedDate(null, testResult),
+            isDccConsentGiven = request.isDccConsentGiven,
         )
     }
 
@@ -245,6 +246,13 @@ class PCRProcessor @Inject constructor(
         return test.copy(isResultAvailableNotificationSent = sent)
     }
 
+    override suspend fun markDccCreated(test: CoronaTest, created: Boolean): CoronaTest {
+        Timber.tag(TAG).v("markDccCreated(test=%s, created=%b)", test, created)
+        test as PCRCoronaTest
+
+        return test.copy(isDccDataSetCreated = created)
+    }
+
     companion object {
         private val FINAL_STATES = setOf(PCR_POSITIVE, PCR_NEGATIVE, PCR_REDEEMED)
         internal const val TAG = "PCRProcessor"
@@ -269,7 +277,7 @@ private fun CoronaTestResult.toValidatedResult(): CoronaTestResult {
     return if (isValid) {
         this
     } else {
-        Timber.tag(PCRProcessor.TAG).e("Server returned invalid PCR testresult $this")
+        Timber.tag(PCRTestProcessor.TAG).e("Server returned invalid PCR testresult $this")
         PCR_INVALID
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RAProcessor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RATestProcessor.kt
similarity index 95%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RAProcessor.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RATestProcessor.kt
index c2b3911c61d37aa919b21a2cdd1d1ddd8c17f37f..075881497a8447e524264062768309f02867f60d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RAProcessor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RATestProcessor.kt
@@ -21,7 +21,6 @@ import de.rki.coronawarnapp.coronatest.server.VerificationServer
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.coronatest.type.CoronaTestProcessor
 import de.rki.coronawarnapp.coronatest.type.CoronaTestService
-import de.rki.coronawarnapp.coronatest.type.common.DateOfBirthKey
 import de.rki.coronawarnapp.coronatest.type.isOlderThan21Days
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
 import de.rki.coronawarnapp.datadonation.analytics.modules.testresult.AnalyticsTestResultCollector
@@ -36,7 +35,7 @@ import timber.log.Timber
 import javax.inject.Inject
 
 @Reusable
-class RAProcessor @Inject constructor(
+class RATestProcessor @Inject constructor(
     private val timeStamper: TimeStamper,
     private val submissionService: CoronaTestService,
     private val analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector,
@@ -56,13 +55,9 @@ class RAProcessor @Inject constructor(
         analyticsKeySubmissionCollector.reset(type)
         analyticsTestResultCollector.clear(type)
 
-        val dateOfBirthKey = if (request.isDccConsentGiven && request.dateOfBirth != null) {
-            DateOfBirthKey(request.registrationIdentifier, request.dateOfBirth)
-        } else null
-
         val serverRequest = RegistrationRequest(
             key = request.registrationIdentifier,
-            dateOfBirthKey = dateOfBirthKey,
+            dateOfBirthKey = null,
             type = VerificationKeyType.GUID
         )
 
@@ -102,6 +97,7 @@ class RAProcessor @Inject constructor(
             dateOfBirth = request.dateOfBirth,
             sampleCollectedAt = sampleCollectedAt,
             isDccSupportedByPoc = request.isDccSupportedByPoc,
+            isDccConsentGiven = request.isDccConsentGiven,
         )
     }
 
@@ -224,6 +220,13 @@ class RAProcessor @Inject constructor(
         return test.copy(isResultAvailableNotificationSent = sent)
     }
 
+    override suspend fun markDccCreated(test: CoronaTest, created: Boolean): CoronaTest {
+        Timber.tag(TAG).v("markDccCreated(test=%s, created=%b)", test, created)
+        test as RACoronaTest
+
+        return test.copy(isDccDataSetCreated = created)
+    }
+
     companion object {
         private val FINAL_STATES = setOf(RAT_POSITIVE, RAT_NEGATIVE, RAT_REDEEMED)
         internal const val TAG = "RapidAntigenProcessor"
@@ -248,7 +251,7 @@ private fun CoronaTestResult.toValidatedResult(): CoronaTestResult {
     return if (isValid) {
         this
     } else {
-        Timber.tag(RAProcessor.TAG).e("Server returned invalid RapidAntigen testresult $this")
+        Timber.tag(RATestProcessor.TAG).e("Server returned invalid RapidAntigen testresult $this")
         RAT_INVALID
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/DigitalCovidCertificateModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/DigitalCovidCertificateModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f99403437330ace983a3c86c592dac778b2710eb
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/DigitalCovidCertificateModule.kt
@@ -0,0 +1,15 @@
+package de.rki.coronawarnapp.covidcertificate
+
+import dagger.Module
+import de.rki.coronawarnapp.covidcertificate.test.core.server.TestCertificateServerModule
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationModule
+import de.rki.coronawarnapp.covidcertificate.valueset.CertificateValueSetModule
+
+@Module(
+    includes = [
+        CertificateValueSetModule::class,
+        TestCertificateServerModule::class,
+        VaccinationModule::class,
+    ]
+)
+abstract class DigitalCovidCertificateModule
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifier.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CertificatePersonIdentifier.kt
similarity index 53%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifier.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CertificatePersonIdentifier.kt
index aea20ab9b2e412ec1f7862b0bb8f12f8d1c710e3..3148343d4e36ea6d868b1aef3547109cd29658ed 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifier.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CertificatePersonIdentifier.kt
@@ -1,14 +1,13 @@
-package de.rki.coronawarnapp.vaccination.core
+package de.rki.coronawarnapp.covidcertificate.common.certificate
 
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_DOB_MISMATCH
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_NAME_MISMATCH
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
 import de.rki.coronawarnapp.util.HashExtensions.toSHA256
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode
-import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateQRCode
 import org.joda.time.LocalDate
 import timber.log.Timber
 
-data class VaccinatedPersonIdentifier(
+data class CertificatePersonIdentifier(
     val dateOfBirth: LocalDate,
     val lastNameStandardized: String,
     val firstNameStandardized: String?
@@ -32,28 +31,18 @@ data class VaccinatedPersonIdentifier(
         code.toSHA256()
     }
 
-    fun requireMatch(other: VaccinatedPersonIdentifier) {
+    fun requireMatch(other: CertificatePersonIdentifier) {
         if (lastNameStandardized != other.lastNameStandardized) {
             Timber.d("Family name does not match, got ${other.lastNameStandardized}, expected $lastNameStandardized")
-            throw InvalidHealthCertificateException(ErrorCode.VC_NAME_MISMATCH)
+            throw InvalidVaccinationCertificateException(VC_NAME_MISMATCH)
         }
         if (firstNameStandardized != other.firstNameStandardized) {
             Timber.d("Given name does not match, got ${other.firstNameStandardized}, expected $firstNameStandardized")
-            throw InvalidHealthCertificateException(ErrorCode.VC_NAME_MISMATCH)
+            throw InvalidVaccinationCertificateException(VC_NAME_MISMATCH)
         }
         if (dateOfBirth != other.dateOfBirth) {
             Timber.d("Date of birth does not match, got ${other.dateOfBirth}, expected $dateOfBirth")
-            throw InvalidHealthCertificateException(ErrorCode.VC_DOB_MISMATCH)
+            throw InvalidVaccinationCertificateException(VC_DOB_MISMATCH)
         }
     }
 }
-
-val VaccinationDGCV1.personIdentifier: VaccinatedPersonIdentifier
-    get() = VaccinatedPersonIdentifier(
-        dateOfBirth = dateOfBirth,
-        lastNameStandardized = nameData.familyNameStandardized,
-        firstNameStandardized = nameData.givenNameStandardized
-    )
-
-val VaccinationCertificateQRCode.personIdentifier: VaccinatedPersonIdentifier
-    get() = parsedData.certificate.personIdentifier
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bd58201d2ebc0e8e4968d8dff2fa241679b874c0
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt
@@ -0,0 +1,29 @@
+package de.rki.coronawarnapp.covidcertificate.common.certificate
+
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
+import org.joda.time.Instant
+import org.joda.time.LocalDate
+
+/**
+ * For use with the UI
+ */
+interface CwaCovidCertificate {
+    // Header
+    val issuer: String
+    val issuedAt: Instant
+    val expiresAt: Instant
+
+    val qrCode: QrCodeString
+
+    val firstName: String?
+
+    val lastName: String
+    val fullName: String
+    val dateOfBirth: LocalDate
+
+    val personIdentifier: CertificatePersonIdentifier
+
+    val certificateIssuer: String
+    val certificateCountry: String
+    val certificateId: String
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/Dcc.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/Dcc.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8d8c4b030802099b01ee409d6f422c46f96b1c2c
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/Dcc.kt
@@ -0,0 +1,50 @@
+package de.rki.coronawarnapp.covidcertificate.common.certificate
+
+import com.google.gson.annotations.SerializedName
+import org.joda.time.LocalDate
+
+interface Dcc<PayloadType : Dcc.Payload> {
+    data class NameData(
+        @SerializedName("fn") internal val familyName: String?,
+        @SerializedName("fnt") internal val familyNameStandardized: String,
+        @SerializedName("gn") internal val givenName: String?,
+        @SerializedName("gnt") internal val givenNameStandardized: String?,
+    ) {
+        val firstName: String?
+            get() = if (givenName.isNullOrBlank()) givenNameStandardized else givenName
+
+        val lastName: String
+            get() = if (familyName.isNullOrBlank()) familyNameStandardized else familyName
+
+        val fullName: String
+            get() = when {
+                firstName.isNullOrBlank() -> lastName
+                else -> "$firstName $lastName"
+            }
+    }
+
+    val version: String
+    val nameData: NameData
+    val dob: String
+
+    val dateOfBirth: LocalDate
+        get() = LocalDate.parse(dob)
+
+    val payloads: List<PayloadType>
+    val payload: PayloadType
+        get() = payloads.single()
+
+    val personIdentifier: CertificatePersonIdentifier
+        get() = CertificatePersonIdentifier(
+            dateOfBirth = dateOfBirth,
+            lastNameStandardized = nameData.familyNameStandardized,
+            firstNameStandardized = nameData.givenNameStandardized
+        )
+
+    interface Payload {
+        val targetId: String
+        val certificateCountry: String
+        val certificateIssuer: String
+        val uniqueCertificateIdentifier: String
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..89a2aac6b817b69cd06a50167364ef15651ba2f4
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccData.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.covidcertificate.common.certificate
+
+data class DccData<CertT : Dcc<*>>(
+    val header: DccHeader,
+    val certificate: CertT,
+)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccHeader.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccHeader.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4964d707431c1bb29a0fb79e88e4b14d4383d19e
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccHeader.kt
@@ -0,0 +1,9 @@
+package de.rki.coronawarnapp.covidcertificate.common.certificate
+
+import org.joda.time.Instant
+
+data class DccHeader(
+    val issuer: String,
+    val issuedAt: Instant,
+    val expiresAt: Instant,
+)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccCoseDecoder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccCoseDecoder.kt
new file mode 100644
index 0000000000000000000000000000000000000000..51773c92558ee0ef541cc8dc95ebe284dad85e8d
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccCoseDecoder.kt
@@ -0,0 +1,59 @@
+package de.rki.coronawarnapp.covidcertificate.common.decoder
+
+import com.upokecenter.cbor.CBORObject
+import de.rki.coronawarnapp.covidcertificate.cryptography.AesCryptography
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.AES_DECRYPTION_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_COSE_MESSAGE_INVALID
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_COSE_TAG_INVALID
+import timber.log.Timber
+import javax.inject.Inject
+
+class DccCoseDecoder @Inject constructor(
+    private val aesEncryptor: AesCryptography
+) {
+
+    fun decode(input: RawCOSEObject): CBORObject = try {
+        val messageObject = CBORObject.DecodeFromBytes(input).validate()
+        val content = messageObject[2].GetByteString()
+        CBORObject.DecodeFromBytes(content)
+    } catch (e: InvalidHealthCertificateException) {
+        throw e
+    } catch (e: Throwable) {
+        Timber.e(e)
+        throw InvalidHealthCertificateException(HC_COSE_MESSAGE_INVALID)
+    }
+
+    fun decryptMessage(input: RawCOSEObject, decryptionKey: ByteArray): RawCOSEObject = try {
+        val messageObject = CBORObject.DecodeFromBytes(input).validate()
+        val content = messageObject[2].GetByteString()
+        val decrypted = content.decrypt(decryptionKey)
+        messageObject[2] = CBORObject.FromObject(decrypted)
+        messageObject.EncodeToBytes()
+    } catch (e: InvalidHealthCertificateException) {
+        throw e
+    } catch (e: Throwable) {
+        Timber.e(e)
+        throw InvalidHealthCertificateException(HC_COSE_MESSAGE_INVALID)
+    }
+
+    private fun ByteArray.decrypt(decryptionKey: ByteArray) = try {
+        aesEncryptor.decrypt(
+            decryptionKey = decryptionKey,
+            encryptedData = this
+        )
+    } catch (e: Throwable) {
+        Timber.e(e)
+        throw InvalidHealthCertificateException(AES_DECRYPTION_FAILED)
+    }
+
+    private fun CBORObject.validate(): CBORObject {
+        if (size() != 4) {
+            throw InvalidHealthCertificateException(HC_COSE_MESSAGE_INVALID)
+        }
+        if (!HasTag(18)) {
+            throw InvalidHealthCertificateException(HC_COSE_TAG_INVALID)
+        }
+        return this
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateHeaderParser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccHeaderParser.kt
similarity index 51%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateHeaderParser.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccHeaderParser.kt
index e9368782021d3b05e0d79f38b5982e17bb8c28ed..2bac92a71c8847e5cd20d3d8cd572cbb315aa20e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateHeaderParser.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccHeaderParser.kt
@@ -1,28 +1,30 @@
-package de.rki.coronawarnapp.vaccination.core.certificate
+package de.rki.coronawarnapp.covidcertificate.common.decoder
 
 import com.upokecenter.cbor.CBORObject
 import dagger.Reusable
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_HC_CWT_NO_EXP
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_HC_CWT_NO_ISS
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccHeader
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_EXP
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_ISS
 import org.joda.time.Instant
 import javax.inject.Inject
 
 @Reusable
-class HealthCertificateHeaderParser @Inject constructor() {
+class DccHeaderParser @Inject constructor() {
 
-    fun parse(map: CBORObject): CoseCertificateHeader = try {
-        val issuer: String = map[keyIssuer]?.AsString() ?: throw InvalidHealthCertificateException(VC_HC_CWT_NO_ISS)
+    fun parse(map: CBORObject): DccHeader = try {
+        val issuer: String = map[keyIssuer]?.AsString() ?: throw InvalidHealthCertificateException(HC_CWT_NO_ISS)
 
         val issuedAt: Instant = map[keyIssuedAt]?.run {
             Instant.ofEpochSecond(AsNumber().ToInt64Checked())
-        } ?: throw InvalidHealthCertificateException(VC_HC_CWT_NO_ISS)
+        } ?: throw InvalidHealthCertificateException(HC_CWT_NO_ISS)
 
         val expiresAt: Instant = map[keyExpiresAt]?.run {
             Instant.ofEpochSecond(AsNumber().ToInt64Checked())
-        } ?: throw InvalidHealthCertificateException(VC_HC_CWT_NO_EXP)
+        } ?: throw InvalidHealthCertificateException(HC_CWT_NO_EXP)
 
-        HealthCertificateHeader(
+        DccHeader(
             issuer = issuer,
             issuedAt = issuedAt,
             expiresAt = expiresAt,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/RawCOSEObject.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/RawCOSEObject.kt
new file mode 100644
index 0000000000000000000000000000000000000000..233796803fd4c90fd7e02f5ef7d3af35d0d08395
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/RawCOSEObject.kt
@@ -0,0 +1,3 @@
+package de.rki.coronawarnapp.covidcertificate.common.decoder
+
+typealias RawCOSEObject = ByteArray
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/DccQrCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/DccQrCode.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9d1527dd0afb14850f7abd32e41edfcdde9421af
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/DccQrCode.kt
@@ -0,0 +1,16 @@
+package de.rki.coronawarnapp.covidcertificate.common.qrcode
+
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+
+interface DccQrCode<DccT : Dcc<*>> {
+    val qrCode: QrCodeString
+    val data: DccData<DccT>
+
+    val personIdentifier: CertificatePersonIdentifier
+        get() = data.certificate.personIdentifier
+
+    val uniqueCertificateIdentifier: String
+        get() = data.certificate.payload.uniqueCertificateIdentifier
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/QrCodeString.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/QrCodeString.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9c8208fe1c4978bfc8f5f4e941228ca16d1ac329
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/QrCodeString.kt
@@ -0,0 +1,3 @@
+package de.rki.coronawarnapp.covidcertificate.common.qrcode
+
+typealias QrCodeString = String
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptography.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptography.kt
index 80ad40d4c48bd224b6cf62eef0dbce49b9ac0379..ac294903083ca20e2b70d57069d63223fc9d7c18 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptography.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptography.kt
@@ -1,16 +1,25 @@
 package de.rki.coronawarnapp.covidcertificate.cryptography
 
-import dagger.Reusable
-import okio.ByteString
+import com.google.android.gms.common.util.Hex
+import javax.crypto.Cipher
+import javax.crypto.spec.IvParameterSpec
+import javax.crypto.spec.SecretKeySpec
 import javax.inject.Inject
 
-@Reusable
 class AesCryptography @Inject constructor() {
 
     fun decrypt(
         decryptionKey: ByteArray,
-        encryptedData: ByteString
-    ): ByteArray {
-        throw NotImplementedError()
+        encryptedData: ByteArray
+    ): ByteArray = with(Cipher.getInstance(TRANSFORMATION)) {
+        val keySpec = SecretKeySpec(decryptionKey, ALGORITHM)
+        init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec)
+        doFinal(encryptedData)
     }
+
+    private val ivParameterSpec
+        get() = IvParameterSpec(Hex.stringToBytes("00000000000000000000000000000000"))
 }
+
+private const val ALGORITHM = "AES"
+private const val TRANSFORMATION = "AES/CBC/PKCS5Padding"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/ErrorMessage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/ErrorMessage.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5ecf0593827d5792b950265dc93e22783894578a
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/ErrorMessage.kt
@@ -0,0 +1,12 @@
+package de.rki.coronawarnapp.covidcertificate.exception
+
+import de.rki.coronawarnapp.R
+
+const val ERROR_MESSAGE_GENERIC = R.string.errors_generic_text_unknown_error_cause
+const val ERROR_MESSAGE_TRY_AGAIN = R.string.error_tc_try_again
+const val ERROR_MESSAGE_DCC_NOT_SUPPORTED_BY_LAB = R.string.error_tc_dcc_not_supported_by_lab
+const val ERROR_MESSAGE_NO_NETWORK = R.string.error_tc_no_network
+const val ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE = R.string.error_tc_e2e_error_call_hotline
+const val ERROR_MESSAGE_TRY_AGAIN_DCC_NOT_AVAILABLE_YET = R.string.error_tc_try_again_dcc_not_available_yet
+const val ERROR_MESSAGE_CLIENT_ERROR_CALL_HOTLINE = R.string.error_tc_client_error_call_hotline
+const val ERROR_MESSAGE_DCC_EXPIRED = R.string.error_tc_dcc_expired
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9a85a5416babe7fab493a861ffb35bb737753397
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt
@@ -0,0 +1,52 @@
+package de.rki.coronawarnapp.covidcertificate.exception
+
+import android.content.Context
+import de.rki.coronawarnapp.coronatest.qrcode.InvalidQRCodeException
+import de.rki.coronawarnapp.util.HasHumanReadableError
+import de.rki.coronawarnapp.util.HumanReadableError
+import de.rki.coronawarnapp.util.ui.CachedString
+import de.rki.coronawarnapp.util.ui.LazyString
+
+@Suppress("MaxLineLength")
+open class InvalidHealthCertificateException(
+    val errorCode: ErrorCode
+) : HasHumanReadableError, InvalidQRCodeException(errorCode.message) {
+    enum class ErrorCode(
+        val message: String
+    ) {
+        HC_BASE45_DECODING_FAILED("Base45 decoding failed."),
+        HC_BASE45_ENCODING_FAILED("Base45 encoding failed."),
+        HC_ZLIB_DECOMPRESSION_FAILED("Zlib decompression failed."),
+        HC_ZLIB_COMPRESSION_FAILED("Zlib compression failed."),
+        HC_COSE_TAG_INVALID("COSE tag invalid."),
+        HC_COSE_MESSAGE_INVALID("COSE message invalid."),
+        HC_CBOR_DECODING_FAILED("CBOR decoding failed."),
+        VC_NO_VACCINATION_ENTRY("Vaccination certificate missing."),
+        NO_TEST_ENTRY("Test certificate missing."),
+        VC_PREFIX_INVALID("Prefix invalid."),
+        VC_STORING_FAILED("Storing failed."),
+        JSON_SCHEMA_INVALID("Json schema invalid."),
+        VC_NAME_MISMATCH("Name does not match."),
+        VC_ALREADY_REGISTERED("Certificate already registered."),
+        VC_DOB_MISMATCH("Date of birth does not match."),
+        HC_CWT_NO_DGC("Dgc missing."),
+        HC_CWT_NO_EXP("Expiration date missing."),
+        HC_CWT_NO_HCERT("Health certificate missing."),
+        HC_CWT_NO_ISS("Issuer missing."),
+
+        AES_DECRYPTION_FAILED("AES decryption failed"),
+        RSA_DECRYPTION_FAILED("RSA decryption failed."),
+        RSA_KP_GENERATION_FAILED("RSA key pair generation failed."),
+    }
+
+    open val errorMessage: LazyString
+        get() = CachedString { context ->
+            context.getString(ERROR_MESSAGE_GENERIC)
+        }
+
+    override fun toHumanReadableError(context: Context): HumanReadableError {
+        return HumanReadableError(
+            description = errorMessage.get(context) + " ($errorCode)"
+        )
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt
new file mode 100644
index 0000000000000000000000000000000000000000..29cec2e55dc52617bfd9e1fc1f5459e800356fac
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt
@@ -0,0 +1,37 @@
+package de.rki.coronawarnapp.covidcertificate.exception
+
+import android.content.Context
+import de.rki.coronawarnapp.util.HumanReadableError
+import de.rki.coronawarnapp.util.ui.CachedString
+import de.rki.coronawarnapp.util.ui.LazyString
+
+class InvalidTestCertificateException(errorCode: ErrorCode) : InvalidHealthCertificateException(errorCode) {
+    override fun toHumanReadableError(context: Context): HumanReadableError {
+        return HumanReadableError(
+            description = errorMessage.get(context) + " ($errorCode)"
+        )
+    }
+
+    override val errorMessage: LazyString
+        get() = when (errorCode) {
+            ErrorCode.AES_DECRYPTION_FAILED,
+            ErrorCode.RSA_DECRYPTION_FAILED,
+            ErrorCode.HC_COSE_MESSAGE_INVALID,
+            ErrorCode.HC_COSE_TAG_INVALID -> CachedString { context ->
+                context.getString(ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE)
+            }
+
+            ErrorCode.RSA_KP_GENERATION_FAILED -> CachedString { context ->
+                context.getString(ERROR_MESSAGE_TRY_AGAIN)
+            }
+
+            ErrorCode.HC_BASE45_DECODING_FAILED,
+            ErrorCode.HC_BASE45_ENCODING_FAILED,
+            ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED,
+            ErrorCode.HC_ZLIB_COMPRESSION_FAILED -> CachedString { context ->
+                context.getString(ERROR_MESSAGE_CLIENT_ERROR_CALL_HOTLINE)
+            }
+
+            else -> super.errorMessage
+        }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidVaccinationCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidVaccinationCertificateException.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4254cd9b3c11eeb6427b40c4e0d182cddcc7d9c2
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidVaccinationCertificateException.kt
@@ -0,0 +1,61 @@
+package de.rki.coronawarnapp.covidcertificate.exception
+
+import android.content.Context
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.util.HumanReadableError
+import de.rki.coronawarnapp.util.ui.CachedString
+import de.rki.coronawarnapp.util.ui.LazyString
+
+class InvalidVaccinationCertificateException(errorCode: ErrorCode) : InvalidHealthCertificateException(errorCode) {
+    override fun toHumanReadableError(context: Context): HumanReadableError {
+        var errorCodeString = errorCode.toString()
+        errorCodeString = if (errorCodeString.startsWith(PREFIX_VC)) errorCodeString else PREFIX_VC + errorCodeString
+        return HumanReadableError(
+            description = errorMessage.get(context) + " ($errorCodeString)"
+        )
+    }
+
+    override val errorMessage: LazyString
+        get() = when (errorCode) {
+            ErrorCode.VC_PREFIX_INVALID,
+            ErrorCode.HC_BASE45_DECODING_FAILED,
+            ErrorCode.HC_CBOR_DECODING_FAILED,
+            ErrorCode.HC_COSE_MESSAGE_INVALID,
+            ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED,
+            ErrorCode.HC_COSE_TAG_INVALID,
+            ErrorCode.HC_CWT_NO_DGC,
+            ErrorCode.HC_CWT_NO_EXP,
+            ErrorCode.HC_CWT_NO_HCERT,
+            ErrorCode.HC_CWT_NO_ISS,
+            ErrorCode.JSON_SCHEMA_INVALID,
+            -> CachedString { context ->
+                context.getString(ERROR_MESSAGE_VC_INVALID)
+            }
+
+            ErrorCode.VC_NO_VACCINATION_ENTRY -> CachedString { context ->
+                context.getString(ERROR_MESSAGE_VC_NOT_YET_SUPPORTED)
+            }
+
+            ErrorCode.VC_STORING_FAILED -> CachedString { context ->
+                context.getString(ERROR_MESSAGE_VC_SCAN_AGAIN)
+            }
+
+            ErrorCode.VC_NAME_MISMATCH,
+            ErrorCode.VC_DOB_MISMATCH -> CachedString { context ->
+                context.getString(ERROR_MESSAGE_VC_DIFFERENT_PERSON)
+            }
+
+            ErrorCode.VC_ALREADY_REGISTERED -> CachedString { context ->
+                context.getString(ERROR_MESSAGE_VC_ALREADY_REGISTERED)
+            }
+            else -> super.errorMessage
+        }
+}
+
+private const val PREFIX_VC = "VC_"
+
+private const val ERROR_MESSAGE_VC_INVALID = R.string.error_vc_invalid
+private const val ERROR_MESSAGE_VC_NOT_YET_SUPPORTED = R.string.error_vc_not_yet_supported
+private const val ERROR_MESSAGE_VC_SCAN_AGAIN = R.string.error_vc_scan_again
+private const val ERROR_MESSAGE_VC_DIFFERENT_PERSON = R.string.error_vc_different_person
+private const val ERROR_MESSAGE_VC_ALREADY_REGISTERED = R.string.error_vc_already_registered
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/TestCertificateServerException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/TestCertificateServerException.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6cbe138c4d7109ece44e02e86542fdd94b06176a
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/TestCertificateServerException.kt
@@ -0,0 +1,99 @@
+package de.rki.coronawarnapp.covidcertificate.exception
+
+import android.content.Context
+import androidx.annotation.StringRes
+import de.rki.coronawarnapp.util.HasHumanReadableError
+import de.rki.coronawarnapp.util.HumanReadableError
+import de.rki.coronawarnapp.util.ui.CachedString
+import de.rki.coronawarnapp.util.ui.LazyString
+
+class TestCertificateServerException(
+    val errorCode: ErrorCode
+) : HasHumanReadableError, Exception(errorCode.message) {
+
+    override fun toHumanReadableError(context: Context): HumanReadableError {
+        return HumanReadableError(
+            description = errorMessage.get(context)
+        )
+    }
+
+    val errorMessage: LazyString
+        get() = CachedString { context ->
+            context.getString(errorCode.stringRes)
+        }
+
+    enum class ErrorCode(
+        val message: String,
+        @StringRes val stringRes: Int
+    ) {
+        DCC_COMP_202(
+            "DCC Components request failed with error 202: DCC pending.",
+            ERROR_MESSAGE_TRY_AGAIN_DCC_NOT_AVAILABLE_YET
+        ),
+        DCC_COMP_400(
+            "DCC Components request failed with error 400: Bad request (e.g. wrong format of registration token)",
+            ERROR_MESSAGE_CLIENT_ERROR_CALL_HOTLINE
+        ),
+        DCC_COMP_404(
+            "DCC Components request failed with error 404: Registration token does not exist.",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        DCC_COMP_410(
+            "DCC Components request failed with error 410: DCC already cleaned up.",
+            ERROR_MESSAGE_DCC_EXPIRED
+        ),
+        DCC_COMP_412(
+            "DCC Components request failed with error 412: Test result not yet received",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        DCC_COMP_500(
+            "DCC Test Certificate Components failed with error 500: Internal server error.",
+            ERROR_MESSAGE_TRY_AGAIN
+        ),
+        DCC_COMP_500_LAB_INVALID_RESPONSE(
+            "DCC Components failed with error 500: Lab Invalid response",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        DCC_COMP_500_SIGNING_CLIENT_ERROR(
+            "DCC Components failed with error 500: Signing client error",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        DCC_COMP_500_SIGNING_SERVER_ERROR(
+            "DCC Components failed with error 500: Signing server error",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        DCC_COMP_NO_NETWORK(
+            "DCC Test Certificate Components failed due to no network connection.",
+            ERROR_MESSAGE_NO_NETWORK
+        ),
+        PKR_400(
+            "Public Key Registration failed with 400: " +
+                "Bad request (e.g. wrong format of registration token or public key).",
+            ERROR_MESSAGE_CLIENT_ERROR_CALL_HOTLINE
+        ),
+        PKR_403(
+            "Public Key Registration failed with 403: Registration token is not allowed to issue a DCC.",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        PKR_404(
+            "Public Key Registration failed with 404: Registration token does not exist.",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        PKR_409(
+            "Public Key Registration failed with 409: Registration token is already assigned to a public key.",
+            ERROR_MESSAGE_GENERIC
+        ),
+        PKR_500(
+            "Public Key Registration failed with 500: Internal server error.",
+            ERROR_MESSAGE_TRY_AGAIN
+        ),
+        PKR_FAILED(
+            "Private key request failed.",
+            ERROR_MESSAGE_TRY_AGAIN
+        ),
+        PKR_NO_NETWORK(
+            "Private key request failed due to no network connection.",
+            ERROR_MESSAGE_NO_NETWORK
+        ),
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateData.kt
deleted file mode 100644
index 8858296812f1cd3fe089cf7ac88f8c599a3c8e00..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateData.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package de.rki.coronawarnapp.covidcertificate.test
-
-import de.rki.coronawarnapp.vaccination.core.certificate.CoseCertificateHeader
-
-data class TestCertificateData(
-    val header: CoseCertificateHeader,
-    val certificate: TestCertificateDccV1,
-)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateDccV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateDccV1.kt
deleted file mode 100644
index d66086dfe7b5fb8b64b64ee9fba7362cc5a8006b..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateDccV1.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package de.rki.coronawarnapp.covidcertificate.test
-
-import com.google.gson.annotations.SerializedName
-import org.joda.time.Instant
-import org.joda.time.LocalDate
-
-data class TestCertificateDccV1(
-    @SerializedName("ver") val version: String,
-    @SerializedName("nam") val nameData: NameData,
-    @SerializedName("dob") val dob: String,
-    @SerializedName("v") val testCertificateData: List<TestCertificateData>,
-) {
-    data class NameData(
-        @SerializedName("fn") val familyName: String?,
-        @SerializedName("fnt") val familyNameStandardized: String,
-        @SerializedName("gn") val givenName: String?,
-        @SerializedName("gnt") val givenNameStandardized: String?,
-    )
-
-    data class TestCertificateData(
-        // Disease or agent targeted, e.g. "tg": "840539006"
-        @SerializedName("tg") val targetId: String,
-        // Vaccine or prophylaxis, e.g. "vp": "1119349007"
-        @SerializedName("vp") val vaccineId: String,
-        // Vaccine medicinal product,e.g. "mp": "EU/1/20/1528",
-        @SerializedName("mp") val medicalProductId: String,
-        // Marketing Authorization Holder, e.g. "ma": "ORG-100030215",
-        @SerializedName("ma") val marketAuthorizationHolderId: String,
-        // Date/Time of Sample Collection (required)
-        // "sc": "2021-04-13T14:20:00+00:00",
-        @SerializedName("sc") val sampleCollectedAt: Instant,
-        // Date/Time of Test Result
-        // "dr": "2021-04-13T14:40:01+00:00",
-        @SerializedName("dr") val testResultAt: Instant,
-        // Testing Center (required)
-        // "tc": "GGD Fryslân, L-Heliconweg",
-        @SerializedName("tc") val testCenter: String,
-        // Country of Vaccination, e.g. "co": "NL"
-        @SerializedName("co") val countryOfVaccination: String,
-        // Certificate Issuer, e.g. "is": "Ministry of Public Health, Welfare and Sport",
-        @SerializedName("is") val certificateIssuer: String,
-        // Unique Certificate Identifier, e.g.  "ci": "urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ"
-        @SerializedName("ci") val uniqueCertificateIdentifier: String
-    )
-
-    val dateOfBirth: LocalDate
-        get() = LocalDate.parse(dob)
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCode.kt
deleted file mode 100644
index 6cc65a07b63d365aed9841ef0618609961f02c0c..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCode.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package de.rki.coronawarnapp.covidcertificate.test
-
-data class TestCertificateQRCode(
-    val qrCode: String,
-    val testCertificateData: TestCertificateData,
-)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractor.kt
deleted file mode 100644
index e5c34fc642af841c670cdb405349fb6201a439b1..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractor.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package de.rki.coronawarnapp.covidcertificate.test
-
-import dagger.Reusable
-import okio.ByteString
-import javax.inject.Inject
-
-@Reusable
-class TestCertificateQRCodeExtractor @Inject constructor() {
-
-    /**
-     * May throw an **[InvalidHealthCertificateException]**
-     */
-    fun extract(
-        decryptionKey: ByteArray,
-        encryptedCoseComponents: ByteString,
-    ): TestCertificateData {
-        throw NotImplementedError()
-    }
-
-    /**
-     * May throw an **[InvalidHealthCertificateException]**
-     */
-    fun extract(qrCode: String): TestCertificateQRCode {
-        throw NotImplementedError()
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b4589236afa4541e4266755cd1a88cd6ab5022b6
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt
@@ -0,0 +1,27 @@
+package de.rki.coronawarnapp.covidcertificate.test.core
+
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CwaCovidCertificate
+import org.joda.time.Instant
+
+interface TestCertificate : CwaCovidCertificate {
+
+    /**
+     * Disease or agent targeted (required)
+     */
+    val targetName: String
+    val testType: String
+    val testResult: String
+
+    /**
+     * NAA Test Name (only for PCR tests, but not required)
+     */
+    val testName: String?
+
+    /**
+     * RAT Test name and manufacturer (only for RAT tests, but not required)
+     */
+    val testNameAndManufactor: String?
+    val sampleCollectedAt: Instant
+    val testResultAt: Instant?
+    val testCenter: String
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ed383c7d1fa83bb75448b86cb217054caeea4445
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateRepository.kt
@@ -0,0 +1,268 @@
+package de.rki.coronawarnapp.covidcertificate.test.core
+
+import de.rki.coronawarnapp.bugreporting.reportProblem
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.PCRCertificateData
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.RACertificateData
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateContainer
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateIdentifier
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateProcessor
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateStorage
+import de.rki.coronawarnapp.covidcertificate.valueset.ValueSetsRepository
+import de.rki.coronawarnapp.util.coroutine.AppScope
+import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
+import de.rki.coronawarnapp.util.flow.HotDataFlow
+import de.rki.coronawarnapp.util.flow.combine
+import de.rki.coronawarnapp.util.mutate
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.plus
+import kotlinx.coroutines.withContext
+import timber.log.Timber
+import java.util.UUID
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+@Suppress("LongParameterList")
+class TestCertificateRepository @Inject constructor(
+    @AppScope private val appScope: CoroutineScope,
+    private val dispatcherProvider: DispatcherProvider,
+    private val storage: TestCertificateStorage,
+    private val qrCodeExtractor: TestCertificateQRCodeExtractor,
+    private val processor: TestCertificateProcessor,
+    valueSetsRepository: ValueSetsRepository,
+) {
+
+    private val internalData: HotDataFlow<Map<TestCertificateIdentifier, TestCertificateContainer>> = HotDataFlow(
+        loggingTag = TAG,
+        scope = appScope + dispatcherProvider.Default,
+        sharingBehavior = SharingStarted.Eagerly,
+    ) {
+        storage.testCertificates
+            .map {
+                TestCertificateContainer(
+                    data = it,
+                    qrCodeExtractor = qrCodeExtractor
+                )
+            }
+            .map { it.identifier to it }
+            .toMap().also {
+                Timber.tag(TAG).v("Restored TestCertificate data: %s", it)
+            }
+    }
+
+    val certificates: Flow<Set<TestCertificateWrapper>> = combine(
+        internalData.data,
+        valueSetsRepository.latestTestCertificateValueSets
+    ) { certMap, valueSets ->
+        certMap.values.map { container ->
+            TestCertificateWrapper(
+                valueSets = valueSets,
+                container = container,
+            )
+        }.toSet()
+    }
+
+    init {
+        internalData.data
+            .onStart { Timber.tag(TAG).d("Observing TestCertificateContainer data.") }
+            .onEach { entrySets ->
+                val values = entrySets.values
+                Timber.tag(TAG).v("TestCertificateContainer data changed: %s", values)
+                storage.testCertificates = values.map { it.data }.toSet()
+            }
+            .catch {
+                it.reportProblem(TAG, "Failed to snapshot TestCertificateContainer data to storage.")
+                throw it
+            }
+            .launchIn(appScope + dispatcherProvider.Default)
+    }
+
+    /**
+     * Will create a new test certificate entry.
+     * Automation via [de.rki.coronawarnapp.coronatest.type.common.TestCertificateRetrievalScheduler] will kick in.
+     *
+     * Throws an exception if there already is a test certificate entry for this test
+     * or this is not a valid test (no consent, not supported by PoC).
+     */
+    suspend fun requestCertificate(test: CoronaTest): TestCertificateContainer {
+        Timber.tag(TAG).d("requestCertificate(test.identifier=%s)", test.identifier)
+
+        val newData = internalData.updateBlocking {
+            if (values.any { it.registrationToken == test.registrationToken }) {
+                Timber.tag(TAG).e("Certificate entry already exists for %s", test.identifier)
+                throw IllegalArgumentException("A certificate was already created for this ${test.identifier}")
+            }
+            if (!test.isDccSupportedByPoc) {
+                throw IllegalArgumentException("DCC is not supported by PoC for this test: ${test.identifier}")
+            }
+            if (!test.isDccConsentGiven) {
+                throw IllegalArgumentException("DCC was not given for this test: ${test.identifier}")
+            }
+
+            val identifier = UUID.randomUUID().toString()
+
+            val data = when (test.type) {
+                CoronaTest.Type.PCR -> PCRCertificateData(
+                    identifier = identifier,
+                    registeredAt = test.registeredAt,
+                    registrationToken = test.registrationToken,
+                )
+                CoronaTest.Type.RAPID_ANTIGEN -> RACertificateData(
+                    identifier = identifier,
+                    registeredAt = test.registeredAt,
+                    registrationToken = test.registrationToken,
+                )
+            }
+            val container = TestCertificateContainer(
+                data = data,
+                qrCodeExtractor = qrCodeExtractor,
+            )
+            Timber.tag(TAG).d("Adding test certificate entry: %s", container)
+            mutate { this[container.identifier] = container }
+        }
+
+        return newData.values.single { it.registrationToken == test.registrationToken }
+    }
+
+    /**
+     * If [error] is NULL, then [certificateContainer] will be the refreshed entry.
+     * If [error] is not NULL, then [certificateContainer] is the latest version before the exception occured.
+     * Due to refresh being a multiple process, some steps can successed, while others fail.
+     */
+    data class RefreshResult(
+        val certificateContainer: TestCertificateContainer,
+        val error: Exception? = null,
+    )
+
+    /**
+     * The refresh call checks each certificate entry for public keys and certificate state.
+     * It will be triggered via TestCertificateRetrievalScheduler.
+     * After requestCertificate, calling refresh often enough should yield a certificate eventually.
+     *
+     * This returns a set of [RefreshResult], one for each refreshed test certificate entry.
+     * If you specify  an identifier, then the set will only contain a single element.
+     *
+     * [refresh] itself will NOT throw an exception.
+     */
+    suspend fun refresh(identifier: TestCertificateIdentifier? = null): Set<RefreshResult> {
+        Timber.tag(TAG).d("refresh(identifier=%s)", identifier)
+
+        val refreshCallResults = mutableMapOf<TestCertificateIdentifier, RefreshResult>()
+
+        val workedOnIds = mutableSetOf<TestCertificateIdentifier>()
+
+        internalData.updateBlocking {
+            val toRefresh = values
+                .filter { it.identifier == identifier || identifier == null } // Targets of our refresh
+                .filter { !it.isUpdatingData && it.isCertificateRetrievalPending } // Those that need refreshing
+
+            mutate {
+                toRefresh.forEach {
+                    workedOnIds.add(it.identifier)
+                    this[it.identifier] = it.copy(isUpdatingData = true)
+                }
+            }
+        }
+
+        internalData.updateBlocking {
+            Timber.tag(TAG).d("Checking for unregistered public keys.")
+
+            val refreshedCerts = values
+                .filter { workedOnIds.contains(it.identifier) } // Refresh targets
+                .filter { !it.isPublicKeyRegistered } // Targets of this step
+                .map { cert ->
+                    withContext(dispatcherProvider.IO) {
+                        try {
+                            val updatedData = processor.registerPublicKey(cert.data)
+                            RefreshResult(cert.copy(data = updatedData))
+                        } catch (e: Exception) {
+                            Timber.tag(TAG).e(e, "Failed to register public key for %s", cert)
+                            RefreshResult(cert, e)
+                        }
+                    }
+                }
+
+            refreshedCerts.forEach {
+                refreshCallResults[it.certificateContainer.identifier] = it
+            }
+
+            mutate {
+                refreshedCerts
+                    .filter { it.error == null }
+                    .map { it.certificateContainer }
+                    .forEach { this[it.identifier] = it }
+            }
+        }
+
+        internalData.updateBlocking {
+            Timber.tag(TAG).d("Checking for pending certificates.")
+
+            val refreshedCerts = values
+                .filter { workedOnIds.contains(it.identifier) } // Refresh targets
+                .filter { it.isPublicKeyRegistered && it.isCertificateRetrievalPending } // Targets of this step
+                .map { cert ->
+                    withContext(dispatcherProvider.IO) {
+                        try {
+                            val updatedData = processor.obtainCertificate(cert.data)
+                            RefreshResult(cert.copy(data = updatedData))
+                        } catch (e: Exception) {
+                            Timber.tag(TAG).e(e, "Failed to retrieve certificate components for %s", cert)
+                            RefreshResult(cert, e)
+                        }
+                    }
+                }
+
+            refreshedCerts.forEach {
+                refreshCallResults[it.certificateContainer.identifier] = it
+            }
+
+            mutate {
+                refreshedCerts
+                    .filter { it.error == null }
+                    .map { it.certificateContainer }
+                    .forEach { this[it.identifier] = it }
+            }
+        }
+
+        internalData.updateBlocking {
+            val certs = values.filter { workedOnIds.contains(it.identifier) }
+
+            mutate {
+                certs.forEach {
+                    this[it.identifier] = it.copy(isUpdatingData = false)
+                }
+            }
+        }
+
+        return refreshCallResults.values.toSet()
+    }
+
+    /**
+     * [deleteCertificate] does not throw an exception, if the deletion target already does not exist.
+     */
+    suspend fun deleteCertificate(identifier: TestCertificateIdentifier) {
+        Timber.tag(TAG).d("deleteTestCertificate(identifier=%s)", identifier)
+        internalData.updateBlocking {
+            mutate {
+                remove(identifier)
+            }
+        }
+    }
+
+    suspend fun clear() {
+        Timber.tag(TAG).i("clear()")
+        internalData.updateBlocking { emptyMap() }
+    }
+
+    companion object {
+        private val TAG = TestCertificateRepository::class.simpleName!!
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateWrapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateWrapper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2be76074c81765443b9c52167bf4d028cceadaab
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateWrapper.kt
@@ -0,0 +1,23 @@
+package de.rki.coronawarnapp.covidcertificate.test.core
+
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateContainer
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateIdentifier
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.TestCertificateValueSets
+
+data class TestCertificateWrapper(
+    private val valueSets: TestCertificateValueSets,
+    private val container: TestCertificateContainer
+) {
+
+    val identifier: TestCertificateIdentifier = container.identifier
+
+    val isCertificateRetrievalPending = container.isCertificateRetrievalPending
+
+    val isUpdatingData = container.isUpdatingData
+
+    val registeredAt = container.registeredAt
+
+    val testCertificate: TestCertificate? by lazy {
+        container.toTestCertificate(valueSets)
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccParser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccParser.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7f4cfe2d8aad8a8f55c4bbb8639dcb93accf78b1
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccParser.kt
@@ -0,0 +1,69 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.certificate
+
+import com.google.gson.Gson
+import com.upokecenter.cbor.CBORObject
+import dagger.Reusable
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_DGC
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_HCERT
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.JSON_SCHEMA_INVALID
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.NO_TEST_ENTRY
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidTestCertificateException
+import de.rki.coronawarnapp.util.serialization.BaseGson
+import de.rki.coronawarnapp.util.serialization.fromJson
+import timber.log.Timber
+import javax.inject.Inject
+
+@Reusable
+class TestDccParser @Inject constructor(
+    @BaseGson private val gson: Gson,
+) {
+    fun parse(map: CBORObject): TestDccV1 = try {
+        map[keyHCert]?.run {
+            this[keyEuDgcV1]?.run {
+                toCertificate()
+            } ?: throw InvalidTestCertificateException(HC_CWT_NO_DGC)
+        } ?: throw InvalidTestCertificateException(HC_CWT_NO_HCERT)
+    } catch (e: InvalidTestCertificateException) {
+        throw e
+    } catch (e: Throwable) {
+        throw InvalidTestCertificateException(HC_CBOR_DECODING_FAILED)
+    }
+
+    @Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
+    private fun TestDccV1.validate(): TestDccV1 {
+        if (payloads.isNullOrEmpty()) {
+            throw InvalidTestCertificateException(NO_TEST_ENTRY)
+        }
+        // check for non null (Gson does not enforce it) & force date parsing
+        require(version.isNotBlank())
+        require(nameData.familyNameStandardized.isNotBlank())
+        dateOfBirth
+        payload.let {
+            it.testResultAt
+            it.sampleCollectedAt
+            require(it.certificateIssuer.isNotBlank())
+            require(it.certificateCountry.isNotBlank())
+            require(it.targetId.isNotBlank())
+            require(it.testCenter.isNotBlank())
+            require(it.testResult.isNotBlank())
+            require(it.testType.isNotBlank())
+        }
+        return this
+    }
+
+    private fun CBORObject.toCertificate() = try {
+        val json = ToJSONString()
+        gson.fromJson<TestDccV1>(json).validate()
+    } catch (e: InvalidTestCertificateException) {
+        throw e
+    } catch (e: Throwable) {
+        Timber.e(e)
+        throw InvalidTestCertificateException(JSON_SCHEMA_INVALID)
+    }
+
+    companion object {
+        private val keyEuDgcV1 = CBORObject.FromObject(1)
+        private val keyHCert = CBORObject.FromObject(-260)
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccV1.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c105167986ab66c556716285921ab8978fddef9b
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccV1.kt
@@ -0,0 +1,45 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.certificate
+
+import com.google.gson.annotations.SerializedName
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
+import org.joda.time.Instant
+
+data class TestDccV1(
+    @SerializedName("ver") override val version: String,
+    @SerializedName("nam") override val nameData: Dcc.NameData,
+    @SerializedName("dob") override val dob: String,
+    @SerializedName("t") override val payloads: List<TestCertificateData>,
+) : Dcc<TestDccV1.TestCertificateData> {
+
+    data class TestCertificateData(
+        // Disease or agent targeted, e.g. "tg": "840539006"
+        @SerializedName("tg") override val targetId: String,
+        // Type of Test (required) eg "LP217198-3"
+        @SerializedName("tt") val testType: String,
+        // Test Result (required) e. g. "tr": "260415000"
+        @SerializedName("tr") val testResult: String,
+        // NAA Test Name (only for PCR tests, but not required) "nm": "Roche LightCycler qPCR",
+        @SerializedName("nm") val testName: String? = null,
+        // RAT Test name and manufacturer (only for RAT tests, but not required)
+        @SerializedName("ma") val testNameAndManufactor: String? = null,
+        // Date/Time of Sample Collection (required) "sc": "2021-04-13T14:20:00+00:00"
+        @SerializedName("sc") val sc: String,
+        // Date/Time of Test Result "dr": "2021-04-13T14:40:01+00:00",
+        @SerializedName("dr") val dr: String? = null,
+        // Testing Center (required) "tc": "GGD Fryslân, L-Heliconweg",
+        @SerializedName("tc") val testCenter: String,
+        // Country of Test (required)
+        @SerializedName("co") override val certificateCountry: String,
+        // Certificate Issuer, e.g. "is": "Ministry of Public Health, Welfare and Sport",
+        @SerializedName("is") override val certificateIssuer: String,
+        // Unique Certificate Identifier, e.g.  "ci": "urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ"
+        @SerializedName("ci") override val uniqueCertificateIdentifier: String
+    ) : Dcc.Payload {
+
+        val testResultAt: Instant?
+            get() = dr?.let { Instant.parse(it) }
+
+        val sampleCollectedAt: Instant
+            get() = Instant.parse(sc)
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/execution/TestCertificateRetrievalScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/execution/TestCertificateRetrievalScheduler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2ad3ee6454b7fa8be7038f7c5b0fd0bb5654db43
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/execution/TestCertificateRetrievalScheduler.kt
@@ -0,0 +1,118 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.execution
+
+import androidx.work.BackoffPolicy
+import androidx.work.Constraints
+import androidx.work.ExistingWorkPolicy
+import androidx.work.NetworkType
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkManager
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.type.common.ResultScheduler
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.util.coroutine.AppScope
+import de.rki.coronawarnapp.util.device.ForegroundState
+import de.rki.coronawarnapp.util.flow.combine
+import de.rki.coronawarnapp.worker.BackgroundConstants
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import timber.log.Timber
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class TestCertificateRetrievalScheduler @Inject constructor(
+    @AppScope private val appScope: CoroutineScope,
+    private val workManager: WorkManager,
+    private val certificateRepo: TestCertificateRepository,
+    private val testRepo: CoronaTestRepository,
+    private val foregroundState: ForegroundState,
+) : ResultScheduler(
+    workManager = workManager
+) {
+    private val processedNewCerts = mutableSetOf<String>()
+
+    private val creationTrigger = testRepo.coronaTests
+        .map { tests ->
+            tests
+                .filter { it.isDccSupportedByPoc } // Only those that support it
+                .filter { it.isNegative } // Certs only to proof negative state
+                .filter { it.isDccConsentGiven && !it.isDccDataSetCreated } // Consent and doesn't exist already?
+        }
+        .distinctUntilChanged()
+
+    private val refreshTrigger = combine(
+        certificateRepo.certificates,
+        foregroundState.isInForeground,
+    ) { certificates, isForeground ->
+
+        val hasNewCert = certificates.any {
+            val isNew = !processedNewCerts.contains(it.identifier)
+            if (isNew) processedNewCerts.add(it.identifier)
+            isNew
+        }
+
+        val hasWorkToDo = certificates.any { it.isCertificateRetrievalPending && !it.isUpdatingData }
+        Timber.tag(TAG).v("shouldPollDcc? hasNewCert=$hasNewCert, hasWorkTodo=$hasWorkToDo, foreground=$isForeground")
+        (isForeground || hasNewCert) && hasWorkToDo
+    }
+
+    fun setup() {
+        Timber.tag(TAG).i("setup() - TestCertificateRetrievalScheduler")
+
+        // Create a certificate entry for each viable test that has none
+        creationTrigger
+            .onEach { testsWithoutCert ->
+                Timber.tag(TAG).d("State change: testsWithoutCert=$testsWithoutCert")
+                testsWithoutCert.forEach { test ->
+                    val cert = certificateRepo.requestCertificate(test)
+                    Timber.tag(TAG).v("Certificate was created: %s", cert)
+                    testRepo.markDccAsCreated(test.identifier, created = true)
+                }
+            }
+            .catch { Timber.tag(TAG).e(it, "Creation trigger failed.") }
+            .launchIn(appScope)
+
+        // For each change to the set of existing certificates, check if we need to refresh/load data
+        refreshTrigger
+            .onEach { checkCerts ->
+                Timber.tag(TAG).d("State change: checkCerts=$checkCerts")
+                if (checkCerts) scheduleWorker()
+            }
+            .catch { Timber.tag(TAG).e(it, "Refresh trigger failed.") }
+            .launchIn(appScope)
+    }
+
+    internal suspend fun scheduleWorker() {
+        Timber.tag(TAG).i("scheduleWorker()")
+
+        if (isScheduled(WORKER_ID)) {
+            Timber.tag(TAG).d("Worker already queued, skipping requeue.")
+        }
+
+        Timber.tag(TAG).d("enqueueUniqueWork PCR_TESTRESULT_WORKER_UNIQUEUNAME")
+        workManager.enqueueUniqueWork(
+            WORKER_ID,
+            ExistingWorkPolicy.KEEP,
+            buildWorkerRequest()
+        )
+    }
+
+    private fun buildWorkerRequest() =
+        OneTimeWorkRequestBuilder<TestCertificateRetrievalWorker>()
+            .setConstraints(
+                Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
+            )
+            .setBackoffCriteria(BackoffPolicy.LINEAR, BackgroundConstants.KIND_DELAY, TimeUnit.MINUTES)
+            .build()
+
+    companion object {
+        private const val WORKER_ID = "TestCertificateRetrievalWorker"
+
+        private val TAG = TestCertificateRetrievalScheduler::class.simpleName!!
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/execution/TestCertificateRetrievalWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/execution/TestCertificateRetrievalWorker.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8dc80c437b24c3db1d710c14ad741a62e763f214
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/execution/TestCertificateRetrievalWorker.kt
@@ -0,0 +1,51 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.execution
+
+import android.content.Context
+import androidx.work.CoroutineWorker
+import androidx.work.WorkerParameters
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.util.worker.InjectedWorkerFactory
+import de.rki.coronawarnapp.worker.BackgroundConstants
+import timber.log.Timber
+
+class TestCertificateRetrievalWorker @AssistedInject constructor(
+    @Assisted val context: Context,
+    @Assisted workerParams: WorkerParameters,
+    private val testCertificateRepository: TestCertificateRepository,
+) : CoroutineWorker(context, workerParams) {
+
+    override suspend fun doWork(): Result {
+        Timber.tag(TAG).d("$id: doWork() started. Run attempt: $runAttemptCount")
+
+        if (runAttemptCount > BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD) {
+            Timber.tag(TAG).d("$id doWork() failed after $runAttemptCount attempts. Aborting...")
+            return Result.failure()
+        }
+
+        return try {
+            Timber.tag(TAG).v("Refreshing test certificates.")
+            val results = testCertificateRepository.refresh()
+
+            if (results.any { it.error != null }) {
+                Timber.tag(TAG).w("Some test certificates failed refresh, will retry.")
+                Result.retry()
+            } else {
+                Timber.tag(TAG).d("No errors during test certificate refresh :).")
+                Result.success()
+            }
+        } catch (e: Exception) {
+            Timber.tag(TAG).e(e, "Test result retrieval worker failed.")
+            Result.retry()
+        }
+    }
+
+    @AssistedFactory
+    interface Factory : InjectedWorkerFactory<TestCertificateRetrievalWorker>
+
+    companion object {
+        private val TAG = TestCertificateRetrievalWorker::class.java.simpleName
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCode.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5e20630680c30cd7107d81348e6ece36cc82fcdd
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCode.kt
@@ -0,0 +1,11 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.qrcode
+
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.DccQrCode
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccV1
+
+data class TestCertificateQRCode(
+    override val qrCode: QrCodeString,
+    override val data: DccData<TestDccV1>,
+) : DccQrCode<TestDccV1>
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractor.kt
new file mode 100644
index 0000000000000000000000000000000000000000..51a8de2f1f8bc7087001278a0005b77fed23af5e
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractor.kt
@@ -0,0 +1,133 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.qrcode
+
+import com.upokecenter.cbor.CBORObject
+import dagger.Reusable
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccCoseDecoder
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccHeaderParser
+import de.rki.coronawarnapp.covidcertificate.common.decoder.RawCOSEObject
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_BASE45_ENCODING_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_COSE_MESSAGE_INVALID
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_COMPRESSION_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidTestCertificateException
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccParser
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccV1
+import de.rki.coronawarnapp.util.compression.deflate
+import de.rki.coronawarnapp.util.compression.inflate
+import de.rki.coronawarnapp.util.encoding.Base45Decoder
+import timber.log.Timber
+import javax.inject.Inject
+
+@Reusable
+class TestCertificateQRCodeExtractor @Inject constructor(
+    private val coseDecoder: DccCoseDecoder,
+    private val headerParser: DccHeaderParser,
+    private val bodyParser: TestDccParser,
+) {
+
+    /**
+     * May throw an **[InvalidTestCertificateException]**
+     */
+    fun extract(
+        decryptionKey: ByteArray,
+        rawCoseObjectEncrypted: ByteArray,
+    ): TestCertificateQRCode {
+        val rawCoseObject = rawCoseObjectEncrypted.decrypt(decryptionKey)
+        return TestCertificateQRCode(
+            data = rawCoseObject.decode(),
+            qrCode = rawCoseObject.encode()
+        )
+    }
+
+    /**
+     * May throw an **[InvalidTestCertificateException]**
+     */
+    fun extract(qrCode: String) = TestCertificateQRCode(
+        data = qrCode.extract(),
+        qrCode = qrCode
+    )
+
+    private fun RawCOSEObject.decrypt(decryptionKey: ByteArray): RawCOSEObject = try {
+        coseDecoder.decryptMessage(
+            input = this,
+            decryptionKey = decryptionKey
+        )
+    } catch (e: InvalidHealthCertificateException) {
+        throw InvalidTestCertificateException(e.errorCode)
+    } catch (e: Throwable) {
+        Timber.e(e, HC_COSE_MESSAGE_INVALID.toString())
+        throw InvalidTestCertificateException(HC_COSE_MESSAGE_INVALID)
+    }
+
+    private fun String.extract(): DccData<TestDccV1> =
+        removePrefix(PREFIX)
+            .decodeBase45()
+            .decompress()
+            .decode()
+
+    private fun RawCOSEObject.encode(): String {
+        return PREFIX + compress().encodeBase45()
+    }
+
+    private fun RawCOSEObject.decode(): DccData<TestDccV1> = try {
+        coseDecoder.decode(this).parse()
+    } catch (e: InvalidHealthCertificateException) {
+        throw InvalidTestCertificateException(e.errorCode)
+    } catch (e: Throwable) {
+        Timber.e(e, HC_COSE_MESSAGE_INVALID.toString())
+        throw InvalidTestCertificateException(HC_COSE_MESSAGE_INVALID)
+    }
+
+    private fun CBORObject.parse(): DccData<TestDccV1> = try {
+        DccData(
+            header = headerParser.parse(this),
+            certificate = bodyParser.parse(this)
+        ).also {
+            Timber.v("Parsed test certificate for %s", it.certificate.nameData.givenNameStandardized)
+        }
+    } catch (e: InvalidHealthCertificateException) {
+        throw InvalidTestCertificateException(e.errorCode)
+    } catch (e: Throwable) {
+        Timber.e(e, HC_CBOR_DECODING_FAILED.toString())
+        throw InvalidTestCertificateException(HC_CBOR_DECODING_FAILED)
+    }
+
+    private fun String.decodeBase45(): ByteArray = try {
+        Base45Decoder.decode(this)
+    } catch (e: Throwable) {
+        Timber.e(e, HC_BASE45_DECODING_FAILED.toString())
+        throw InvalidTestCertificateException(HC_BASE45_DECODING_FAILED)
+    }
+
+    private fun ByteArray.encodeBase45(): String = try {
+        Base45Decoder.encode(this)
+    } catch (e: Throwable) {
+        Timber.e(e, HC_BASE45_ENCODING_FAILED.toString())
+        throw InvalidTestCertificateException(HC_BASE45_ENCODING_FAILED)
+    }
+
+    private fun RawCOSEObject.compress(): ByteArray = try {
+        this.deflate()
+    } catch (e: Throwable) {
+        Timber.e(e, HC_ZLIB_COMPRESSION_FAILED.toString())
+        throw InvalidTestCertificateException(HC_ZLIB_COMPRESSION_FAILED)
+    }
+
+    private fun ByteArray.decompress(): RawCOSEObject = try {
+        this.inflate(sizeLimit = DEFAULT_SIZE_LIMIT)
+    } catch (e: Throwable) {
+        Timber.e(e, HC_ZLIB_DECOMPRESSION_FAILED.toString())
+        throw InvalidTestCertificateException(HC_ZLIB_DECOMPRESSION_FAILED)
+    }
+
+    companion object {
+        private const val PREFIX = "HC1:"
+
+        // Zip bomb
+        private const val DEFAULT_SIZE_LIMIT = 1024L * 1024 * 10L // 10 MB
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateApiV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateApiV1.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e8b7558e353f28b0b91f9c1117a887e1a7ec91f6
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateApiV1.kt
@@ -0,0 +1,41 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.server
+
+import com.google.gson.annotations.SerializedName
+import retrofit2.Response
+import retrofit2.http.Body
+import retrofit2.http.POST
+
+interface TestCertificateApiV1 {
+
+    data class PublicKeyUploadRequest(
+        @SerializedName("registrationToken") val registrationToken: String,
+        @SerializedName("publicKey") val publicKey: String
+    )
+
+    @POST("/version/v1/publicKey")
+    suspend fun sendPublicKey(
+        @Body requestBody: PublicKeyUploadRequest
+    ): Response<Unit>
+
+    data class ComponentsRequest(
+        @SerializedName("registrationToken") val registrationToken: String,
+    )
+
+    data class ComponentsResponse(
+        @SerializedName("dek") val dek: String? = null,
+        @SerializedName("dcc") val dcc: String? = null,
+        @SerializedName("reason") val errorReason: String? = null
+    ) {
+        enum class Reason(val errorString: String) {
+            SIGNING_CLIENT_ERROR("SIGNING_CLIENT_ERROR"),
+            SIGNING_SERVER_ERROR("SIGNING_SERVER_ERROR"),
+            LAB_INVALID_RESPONSE("LAB_INVALID_RESPONSE"),
+            INTERNAL("INTERNAL")
+        }
+    }
+
+    @POST("/version/v1/dcc")
+    suspend fun getComponents(
+        @Body requestBody: ComponentsRequest
+    ): Response<ComponentsResponse?>
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateComponents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateComponents.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c0f71f4803763d2fb3c29b4664c8ff7f9d185792
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateComponents.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.server
+
+data class TestCertificateComponents(
+    val dataEncryptionKeyBase64: String,
+    val encryptedCoseTestCertificateBase64: String,
+)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateServer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d0d7a71319fa7698aa5d3e2bd2746f4d7f9ef519
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateServer.kt
@@ -0,0 +1,114 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.server
+
+import dagger.Lazy
+import dagger.Reusable
+import de.rki.coronawarnapp.coronatest.type.RegistrationToken
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_202
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_400
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_404
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_410
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_412
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_500
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_500_LAB_INVALID_RESPONSE
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_500_SIGNING_CLIENT_ERROR
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_500_SIGNING_SERVER_ERROR
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_NO_NETWORK
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_400
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_403
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_404
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_409
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_500
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_NO_NETWORK
+import de.rki.coronawarnapp.covidcertificate.test.core.server.TestCertificateApiV1.ComponentsResponse.Reason.INTERNAL
+import de.rki.coronawarnapp.covidcertificate.test.core.server.TestCertificateApiV1.ComponentsResponse.Reason.LAB_INVALID_RESPONSE
+import de.rki.coronawarnapp.covidcertificate.test.core.server.TestCertificateApiV1.ComponentsResponse.Reason.SIGNING_CLIENT_ERROR
+import de.rki.coronawarnapp.covidcertificate.test.core.server.TestCertificateApiV1.ComponentsResponse.Reason.SIGNING_SERVER_ERROR
+import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
+import de.rki.coronawarnapp.util.encryption.rsa.RSAKey
+import de.rki.coronawarnapp.util.network.NetworkStateProvider
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.withContext
+import timber.log.Timber
+import javax.inject.Inject
+
+@Reusable
+class TestCertificateServer @Inject constructor(
+    private val dccApi: Lazy<TestCertificateApiV1>,
+    private val dispatcherProvider: DispatcherProvider,
+    private val networkStateProvider: NetworkStateProvider
+) {
+
+    private val api: TestCertificateApiV1
+        get() = dccApi.get()
+
+    @Throws(TestCertificateServerException::class)
+    suspend fun registerPublicKeyForTest(
+        testRegistrationToken: RegistrationToken,
+        publicKey: RSAKey.Public,
+    ): Unit = withContext(dispatcherProvider.IO) {
+        Timber.tag(TAG).v("registerPublicKeyForTest(token=%s, key=%s)", testRegistrationToken, publicKey)
+        if (!isInternetAvailable()) {
+            throw TestCertificateServerException(PKR_NO_NETWORK)
+        }
+        try {
+            val response = api.sendPublicKey(
+                requestBody = TestCertificateApiV1.PublicKeyUploadRequest(
+                    registrationToken = testRegistrationToken,
+                    publicKey = publicKey.base64
+                )
+            )
+            when (response.code()) {
+                400 -> throw TestCertificateServerException(PKR_400)
+                403 -> throw TestCertificateServerException(PKR_403)
+                404 -> throw TestCertificateServerException(PKR_404)
+                409 -> throw TestCertificateServerException(PKR_409)
+                500 -> throw TestCertificateServerException(PKR_500)
+            }
+        } catch (e: Exception) {
+            Timber.tag(TAG).w(e, "registerPublicKeyForTest failed")
+            throw TestCertificateServerException(PKR_FAILED)
+        }
+    }
+
+    @Throws(TestCertificateServerException::class)
+    suspend fun requestCertificateForTest(
+        testRegistrationToken: RegistrationToken,
+    ): TestCertificateComponents = withContext(dispatcherProvider.IO) {
+        Timber.tag(TAG).v("requestCertificateForTest(token=%s)", testRegistrationToken)
+        if (!isInternetAvailable()) {
+            throw TestCertificateServerException(DCC_COMP_NO_NETWORK)
+        }
+        val response = api.getComponents(
+            requestBody = TestCertificateApiV1.ComponentsRequest(testRegistrationToken)
+        )
+        when (response.code()) {
+            202 -> throw TestCertificateServerException(DCC_COMP_202)
+            400 -> throw TestCertificateServerException(DCC_COMP_400)
+            404 -> throw TestCertificateServerException(DCC_COMP_404)
+            410 -> throw TestCertificateServerException(DCC_COMP_410)
+            412 -> throw TestCertificateServerException(DCC_COMP_412)
+            500 -> when (response.body()?.errorReason) {
+                INTERNAL.errorString -> throw TestCertificateServerException(DCC_COMP_500)
+                SIGNING_CLIENT_ERROR.errorString ->
+                    throw TestCertificateServerException(DCC_COMP_500_SIGNING_CLIENT_ERROR)
+                SIGNING_SERVER_ERROR.errorString ->
+                    throw TestCertificateServerException(DCC_COMP_500_SIGNING_SERVER_ERROR)
+                LAB_INVALID_RESPONSE.errorString ->
+                    throw TestCertificateServerException(DCC_COMP_500_LAB_INVALID_RESPONSE)
+            }
+        }
+        val result = response.body()!! // throw exception?
+        TestCertificateComponents(
+            dataEncryptionKeyBase64 = result.dek!!,
+            encryptedCoseTestCertificateBase64 = result.dcc!!
+        )
+    }
+
+    private suspend fun isInternetAvailable() = networkStateProvider.networkState.first().isInternetAvailable
+
+    companion object {
+        private const val TAG = "CovidCertificateServer"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateServerModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateServerModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4949f5161ede63238719035c55f7975a5c3d92e2
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/server/TestCertificateServerModule.kt
@@ -0,0 +1,49 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.server
+
+import dagger.Module
+import dagger.Provides
+import dagger.Reusable
+import de.rki.coronawarnapp.environment.covidcertificate.DCCHttpClient
+import de.rki.coronawarnapp.environment.covidcertificate.DCCServerUrl
+import okhttp3.OkHttpClient
+import okhttp3.ResponseBody
+import retrofit2.Converter
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import java.lang.reflect.Type
+
+@Module
+class TestCertificateServerModule {
+
+    /**
+     * Handles DCC server 202 "retry later" response with 0-byte bodies.
+     */
+    private val nullConverter = object : Converter.Factory() {
+        fun factoryRef() = this
+        override fun responseBodyConverter(
+            type: Type,
+            annotations: Array<out Annotation>,
+            retrofit: Retrofit
+        ) = object : Converter<ResponseBody, Any?> {
+            val nextConverter = retrofit.nextResponseBodyConverter<Any?>(factoryRef(), type, annotations)
+
+            override fun convert(value: ResponseBody): Any? {
+                return if (value.contentLength() != 0L) nextConverter.convert(value) else null
+            }
+        }
+    }
+
+    @Reusable
+    @Provides
+    fun apiV1(
+        @DCCHttpClient httpClient: OkHttpClient,
+        @DCCServerUrl url: String,
+        gsonConverterFactory: GsonConverterFactory
+    ): TestCertificateApiV1 = Retrofit.Builder()
+        .client(httpClient)
+        .baseUrl(url)
+        .addConverterFactory(nullConverter)
+        .addConverterFactory(gsonConverterFactory)
+        .build()
+        .create(TestCertificateApiV1::class.java)
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/PCRCertificateData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/PCRCertificateData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..118bf5bc112a3fc4399a49210542b1f6069c7256
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/PCRCertificateData.kt
@@ -0,0 +1,52 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.storage
+
+import com.google.gson.annotations.SerializedName
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.RegistrationToken
+import de.rki.coronawarnapp.util.encryption.rsa.RSAKey
+import okio.ByteString
+import org.joda.time.Instant
+
+data class PCRCertificateData internal constructor(
+    @SerializedName("identifier")
+    override val identifier: String,
+
+    @SerializedName("registrationToken")
+    override val registrationToken: RegistrationToken,
+
+    @SerializedName("registeredAt")
+    override val registeredAt: Instant,
+
+    @SerializedName("publicKeyRegisteredAt")
+    override val publicKeyRegisteredAt: Instant? = null,
+
+    @SerializedName("rsaPublicKey")
+    override val rsaPublicKey: RSAKey.Public? = null,
+
+    @SerializedName("rsaPrivateKey")
+    override val rsaPrivateKey: RSAKey.Private? = null,
+
+    @SerializedName("certificateReceivedAt")
+    override val certificateReceivedAt: Instant? = null,
+
+    @SerializedName("encryptedDataEncryptionkey")
+    override val encryptedDataEncryptionkey: ByteString? = null,
+
+    @SerializedName("encryptedDccCose")
+    override val encryptedDccCose: ByteString? = null,
+
+    @SerializedName("testCertificateQrCode")
+    override val testCertificateQrCode: String? = null,
+) : StoredTestCertificateData {
+
+    // Otherwise GSON unsafes reflection to create this class, and sets the LAZY to null
+    @Suppress("unused")
+    constructor() : this(
+        identifier = "",
+        registrationToken = "",
+        registeredAt = Instant.EPOCH
+    )
+
+    override val type: CoronaTest.Type
+        get() = CoronaTest.Type.PCR
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/RACertificateData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/RACertificateData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..dfcb82bad80c8f2000c505ce3929fb62dc6f1f64
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/RACertificateData.kt
@@ -0,0 +1,52 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.storage
+
+import com.google.gson.annotations.SerializedName
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.RegistrationToken
+import de.rki.coronawarnapp.util.encryption.rsa.RSAKey
+import okio.ByteString
+import org.joda.time.Instant
+
+data class RACertificateData(
+    @SerializedName("identifier")
+    override val identifier: String,
+
+    @SerializedName("registrationToken")
+    override val registrationToken: RegistrationToken,
+
+    @SerializedName("registeredAt")
+    override val registeredAt: Instant,
+
+    @SerializedName("publicKeyRegisteredAt")
+    override val publicKeyRegisteredAt: Instant? = null,
+
+    @SerializedName("rsaPublicKey")
+    override val rsaPublicKey: RSAKey.Public? = null,
+
+    @SerializedName("rsaPrivateKey")
+    override val rsaPrivateKey: RSAKey.Private? = null,
+
+    @SerializedName("certificateReceivedAt")
+    override val certificateReceivedAt: Instant? = null,
+
+    @SerializedName("encryptedDataEncryptionkey")
+    override val encryptedDataEncryptionkey: ByteString? = null,
+
+    @SerializedName("encryptedDccCose")
+    override val encryptedDccCose: ByteString? = null,
+
+    @SerializedName("testCertificateQrCode")
+    override val testCertificateQrCode: String? = null,
+) : StoredTestCertificateData {
+
+    // Otherwise GSON unsafes reflection to create this class, and sets the LAZY to null
+    @Suppress("unused")
+    constructor() : this(
+        identifier = "",
+        registrationToken = "",
+        registeredAt = Instant.EPOCH
+    )
+
+    override val type: CoronaTest.Type
+        get() = CoronaTest.Type.RAPID_ANTIGEN
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/StoredTestCertificateData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/StoredTestCertificateData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..131c18e26608fb530f939f6cccc0cbb49128133d
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/StoredTestCertificateData.kt
@@ -0,0 +1,21 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.storage
+
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.RegistrationToken
+import de.rki.coronawarnapp.util.encryption.rsa.RSAKey
+import okio.ByteString
+import org.joda.time.Instant
+
+interface StoredTestCertificateData {
+    val identifier: TestCertificateIdentifier
+    val registrationToken: RegistrationToken
+    val type: CoronaTest.Type
+    val registeredAt: Instant
+    val publicKeyRegisteredAt: Instant?
+    val rsaPublicKey: RSAKey.Public?
+    val rsaPrivateKey: RSAKey.Private?
+    val certificateReceivedAt: Instant?
+    val encryptedDataEncryptionkey: ByteString?
+    val encryptedDccCose: ByteString?
+    val testCertificateQrCode: String?
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..972fcc5db5ee6c333fb06819ec23d70eb719632c
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt
@@ -0,0 +1,99 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.storage
+
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificate
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccV1
+import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.TestCertificateValueSets
+import org.joda.time.Instant
+import org.joda.time.LocalDate
+import java.util.Locale
+
+data class TestCertificateContainer(
+    internal val data: StoredTestCertificateData,
+    private val qrCodeExtractor: TestCertificateQRCodeExtractor,
+    val isUpdatingData: Boolean = false,
+) : StoredTestCertificateData by data {
+
+    @delegate:Transient
+    private val certificateData: DccData<TestDccV1> by lazy {
+        data.testCertificateQrCode!!.let { qrCodeExtractor.extract(it).data }
+    }
+
+    val isPublicKeyRegistered: Boolean
+        get() = data.publicKeyRegisteredAt != null
+
+    val isCertificateRetrievalPending: Boolean
+        get() = data.certificateReceivedAt == null
+
+    val certificateId: String?
+        get() {
+            if (isCertificateRetrievalPending) return null
+            return certificateData.certificate.payload.uniqueCertificateIdentifier
+        }
+
+    fun toTestCertificate(
+        valueSet: TestCertificateValueSets?,
+        userLocale: Locale = Locale.getDefault(),
+    ): TestCertificate? {
+        if (isCertificateRetrievalPending) return null
+
+        val header = certificateData.header
+        val certificate = certificateData.certificate
+        val testCertificate = certificate.payload
+
+        return object : TestCertificate {
+            override val personIdentifier: CertificatePersonIdentifier
+                get() = certificate.personIdentifier
+
+            override val firstName: String?
+                get() = certificate.nameData.firstName
+
+            override val lastName: String
+                get() = certificate.nameData.lastName
+
+            override val fullName: String
+                get() = certificate.nameData.fullName
+
+            override val dateOfBirth: LocalDate
+                get() = certificate.dateOfBirth
+
+            override val targetName: String
+                get() = valueSet?.getDisplayText(testCertificate.targetId) ?: testCertificate.targetId
+            override val testType: String
+                get() = valueSet?.getDisplayText(testCertificate.testType) ?: testCertificate.testType
+            override val testResult: String
+                get() = valueSet?.getDisplayText(testCertificate.testResult) ?: testCertificate.testResult
+            override val testName: String?
+                get() = testCertificate.testName?.let { valueSet?.getDisplayText(it) ?: it }
+            override val testNameAndManufactor: String?
+                get() = testCertificate.testNameAndManufactor?.let { valueSet?.getDisplayText(it) ?: it }
+            override val sampleCollectedAt: Instant
+                get() = testCertificate.sampleCollectedAt
+            override val testResultAt: Instant?
+                get() = testCertificate.testResultAt
+            override val testCenter: String
+                get() = testCertificate.testCenter
+
+            override val certificateIssuer: String
+                get() = header.issuer
+            override val certificateCountry: String
+                get() = Locale(userLocale.language, testCertificate.certificateCountry.uppercase())
+                    .getDisplayCountry(userLocale)
+            override val certificateId: String
+                get() = testCertificate.uniqueCertificateIdentifier
+
+            override val issuer: String
+                get() = header.issuer
+            override val issuedAt: Instant
+                get() = header.issuedAt
+            override val expiresAt: Instant
+                get() = header.expiresAt
+
+            override val qrCode: QrCodeString
+                get() = data.testCertificateQrCode!!
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateIdentifier.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateIdentifier.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9de185a474a05502f427bab0f19b5f0bdad703e5
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateIdentifier.kt
@@ -0,0 +1,3 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.storage
+
+typealias TestCertificateIdentifier = String
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateProcessor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateProcessor.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4d7e14c25ec6582142e155f6fd4a0cd1fa090f44
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateProcessor.kt
@@ -0,0 +1,156 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.storage
+
+import dagger.Reusable
+import de.rki.coronawarnapp.appconfig.AppConfigProvider
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidTestCertificateException
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException
+import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.test.core.server.TestCertificateComponents
+import de.rki.coronawarnapp.covidcertificate.test.core.server.TestCertificateServer
+import de.rki.coronawarnapp.util.TimeStamper
+import de.rki.coronawarnapp.util.encryption.rsa.RSACryptography
+import de.rki.coronawarnapp.util.encryption.rsa.RSAKeyPairGenerator
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.first
+import okio.ByteString.Companion.decodeBase64
+import org.joda.time.Duration
+import timber.log.Timber
+import javax.inject.Inject
+
+@Reusable
+class TestCertificateProcessor @Inject constructor(
+    private val timeStamper: TimeStamper,
+    private val certificateServer: TestCertificateServer,
+    private val rsaKeyPairGenerator: RSAKeyPairGenerator,
+    private val rsaCryptography: RSACryptography,
+    private val appConfigProvider: AppConfigProvider,
+    private val qrCodeExtractor: TestCertificateQRCodeExtractor,
+) {
+
+    /**
+     * Register the public key with the server, a shortwhile later,
+     * the test certificate components should be available, via [obtainCertificate].
+     */
+    internal suspend fun registerPublicKey(
+        data: StoredTestCertificateData
+    ): StoredTestCertificateData {
+        Timber.tag(TAG).d("registerPublicKey(cert=%s)", data)
+
+        if (data.publicKeyRegisteredAt != null) {
+            Timber.tag(TAG).d("Public key is already registered for %s", data)
+            return data
+        }
+
+        val rsaKeyPair = try {
+            rsaKeyPairGenerator.generate()
+        } catch (e: Throwable) {
+            throw InvalidTestCertificateException(InvalidHealthCertificateException.ErrorCode.RSA_KP_GENERATION_FAILED)
+        }
+
+        certificateServer.registerPublicKeyForTest(
+            testRegistrationToken = data.registrationToken,
+            publicKey = rsaKeyPair.publicKey,
+        )
+        Timber.tag(TAG).i("Public key successfully registered for %s", data)
+
+        val nowUTC = timeStamper.nowUTC
+
+        return when (data.type) {
+            CoronaTest.Type.PCR -> (data as PCRCertificateData).copy(
+                publicKeyRegisteredAt = nowUTC,
+                rsaPublicKey = rsaKeyPair.publicKey,
+                rsaPrivateKey = rsaKeyPair.privateKey,
+            )
+            CoronaTest.Type.RAPID_ANTIGEN -> (data as RACertificateData).copy(
+                publicKeyRegisteredAt = nowUTC,
+                rsaPublicKey = rsaKeyPair.publicKey,
+                rsaPrivateKey = rsaKeyPair.privateKey,
+            )
+        }
+    }
+
+    /**
+     * Try to obtain the actual certificate.
+     * PublicKey registration and certificate retrieval are two steps, because if we manage to register our public key,
+     * but fail to get the certificate, we are still one step further.
+     *
+     * The server does not immediately return the test certificate components after registering the public key.
+     */
+    internal suspend fun obtainCertificate(
+        data: StoredTestCertificateData
+    ): StoredTestCertificateData {
+        Timber.tag(TAG).d("requestCertificate(cert=%s)", data)
+
+        if (data.publicKeyRegisteredAt == null) {
+            throw IllegalStateException("Public key is not registered yet.")
+        }
+
+        if (data.certificateReceivedAt != null) {
+            Timber.tag(TAG).d("Dcc has already been retrieved for %s", data)
+            return data
+        }
+
+        val certConfig = appConfigProvider.currentConfig.first().covidCertificateParameters.testCertificate
+
+        val nowUTC = timeStamper.nowUTC
+        val certAvailableAt = data.publicKeyRegisteredAt!!.plus(certConfig.waitAfterPublicKeyRegistration)
+        val certAvailableIn = Duration(nowUTC, certAvailableAt)
+
+        if (certAvailableIn > Duration.ZERO && certAvailableIn <= certConfig.waitAfterPublicKeyRegistration) {
+            Timber.tag(TAG)
+                .d("Delaying certificate retrieval by %d ms", certAvailableIn.millis)
+            delay(certAvailableIn.millis)
+        }
+
+        val executeRequest: suspend () -> TestCertificateComponents = {
+            certificateServer.requestCertificateForTest(testRegistrationToken = data.registrationToken)
+        }
+
+        val components = try {
+            executeRequest()
+        } catch (e: TestCertificateServerException) {
+            if (e.errorCode == TestCertificateServerException.ErrorCode.DCC_COMP_202) {
+                delay(certConfig.waitForRetry.millis)
+                executeRequest()
+            } else {
+                throw e
+            }
+        }
+        Timber.tag(TAG)
+            .i("Test certificate components successfully request for %s: %s", data, components)
+
+        val encryptionKey = try {
+            rsaCryptography.decrypt(
+                toDecrypt = components.dataEncryptionKeyBase64.decodeBase64()!!,
+                privateKey = data.rsaPrivateKey!!
+            )
+        } catch (e: Throwable) {
+            Timber.tag(TAG).e(e, "RSA_DECRYPTION_FAILED")
+            throw InvalidTestCertificateException(InvalidHealthCertificateException.ErrorCode.RSA_DECRYPTION_FAILED)
+        }
+
+        val extractedData = qrCodeExtractor.extract(
+            decryptionKey = encryptionKey.toByteArray(),
+            rawCoseObjectEncrypted = components.encryptedCoseTestCertificateBase64.decodeBase64()!!.toByteArray()
+        )
+
+        val nowUtc = timeStamper.nowUTC
+
+        return when (data.type) {
+            CoronaTest.Type.PCR -> (data as PCRCertificateData).copy(
+                testCertificateQrCode = extractedData.qrCode,
+                certificateReceivedAt = nowUtc,
+            )
+            CoronaTest.Type.RAPID_ANTIGEN -> (data as RACertificateData).copy(
+                testCertificateQrCode = extractedData.qrCode,
+                certificateReceivedAt = nowUtc,
+            )
+        }
+    }
+
+    companion object {
+        private val TAG = TestCertificateProcessor::class.simpleName!!
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateStorage.kt
new file mode 100644
index 0000000000000000000000000000000000000000..087486024444e89c955a9d87d4ba1b3ed5123e0c
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateStorage.kt
@@ -0,0 +1,99 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.storage
+
+import android.content.Context
+import androidx.core.content.edit
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.ContainerPostProcessor
+import de.rki.coronawarnapp.util.di.AppContext
+import de.rki.coronawarnapp.util.serialization.BaseGson
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class TestCertificateStorage @Inject constructor(
+    @AppContext val context: Context,
+    @BaseGson val baseGson: Gson,
+    private val containerPostProcessor: ContainerPostProcessor,
+) {
+
+    private val prefs by lazy {
+        context.getSharedPreferences("coronatest_certificate_localdata", Context.MODE_PRIVATE)
+    }
+
+    private val gson by lazy {
+        baseGson.newBuilder().apply {
+            registerTypeAdapter(CoronaTestResult::class.java, CoronaTestResult.GsonAdapter())
+            registerTypeAdapterFactory(containerPostProcessor)
+        }.create()
+    }
+
+    private val typeTokenPCR by lazy {
+        object : TypeToken<Set<PCRCertificateData>>() {}.type
+    }
+
+    private val typeTokenRA by lazy {
+        object : TypeToken<Set<RACertificateData>>() {}.type
+    }
+
+    var testCertificates: Collection<StoredTestCertificateData>
+        get() {
+            Timber.tag(TAG).d("load()")
+
+            val pcrCertContainers: Set<PCRCertificateData> = run {
+                val raw = prefs.getString(PKEY_DATA_PCR, null) ?: return@run emptySet()
+                gson.fromJson<Set<PCRCertificateData>>(raw, typeTokenPCR).onEach {
+                    Timber.tag(TAG).v("PCR loaded: %s", it)
+                    requireNotNull(it.identifier)
+                    requireNotNull(it.type) { "PCR type should not be null, GSON footgun." }
+                }
+            }
+
+            val raCerts: Set<RACertificateData> = run {
+                val raw = prefs.getString(PKEY_DATA_RA, null) ?: return@run emptySet()
+                gson.fromJson<Set<RACertificateData>>(raw, typeTokenRA).onEach {
+                    Timber.tag(TAG).v("RA loaded: %s", it)
+                    requireNotNull(it.identifier)
+                    requireNotNull(it.type) { "RA type should not be null, GSON footgun." }
+                }
+            }
+
+            return (pcrCertContainers + raCerts).also {
+                Timber.tag(TAG).v("Loaded %d certificates.", it.size)
+            }
+        }
+        set(value) {
+            Timber.tag(TAG).d("save(testCertificates=%s)", value)
+            prefs.edit {
+                value.filter { it.type == CoronaTest.Type.PCR }.run {
+                    if (isNotEmpty()) {
+                        val raw = gson.toJson(this, typeTokenPCR)
+                        Timber.tag(TAG).v("PCR storing: %s", raw)
+                        putString(PKEY_DATA_PCR, raw)
+                    } else {
+                        Timber.tag(TAG).v("No PCR certificates available, clearing.")
+                        remove(PKEY_DATA_PCR)
+                    }
+                }
+                value.filter { it.type == CoronaTest.Type.RAPID_ANTIGEN }.run {
+                    if (isNotEmpty()) {
+                        val raw = gson.toJson(this, typeTokenRA)
+                        Timber.tag(TAG).v("RA storing: %s", raw)
+                        putString(PKEY_DATA_RA, raw)
+                    } else {
+                        Timber.tag(TAG).v("No RA certificates available, clearing.")
+                        remove(PKEY_DATA_RA)
+                    }
+                }
+            }
+        }
+
+    companion object {
+        private const val TAG = "TestCertificateStorage"
+        private const val PKEY_DATA_RA = "testcertificate.data.ra"
+        private const val PKEY_DATA_PCR = "testcertificate.data.pcr"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesAdapter.kt
similarity index 61%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesAdapter.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesAdapter.kt
index aabec57cb42dd9b9404422c3bfa085c03cf1b7cf..41a700c645df7214a93cbec367d066dbf862b589 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesAdapter.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesAdapter.kt
@@ -1,9 +1,16 @@
-package de.rki.coronawarnapp.greencertificate.ui.certificates
+package de.rki.coronawarnapp.covidcertificate.test.ui
 
 import android.view.ViewGroup
 import androidx.annotation.LayoutRes
 import androidx.viewbinding.ViewBinding
-import de.rki.coronawarnapp.greencertificate.ui.certificates.items.CertificatesItem
+import de.rki.coronawarnapp.covidcertificate.test.ui.cards.CovidTestCertificateCard
+import de.rki.coronawarnapp.covidcertificate.test.ui.cards.CovidTestCertificateErrorCard
+import de.rki.coronawarnapp.covidcertificate.test.ui.items.CertificatesItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.CreateVaccinationCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.HeaderInfoVaccinationCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.ImmuneVaccinationCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.NoCovidTestCertificatesCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.VaccinationCard
 import de.rki.coronawarnapp.util.lists.BindableVH
 import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffUtilAdapter
 import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffer
@@ -11,11 +18,6 @@ import de.rki.coronawarnapp.util.lists.modular.ModularAdapter
 import de.rki.coronawarnapp.util.lists.modular.mods.DataBinderMod
 import de.rki.coronawarnapp.util.lists.modular.mods.StableIdMod
 import de.rki.coronawarnapp.util.lists.modular.mods.TypedVHCreatorMod
-import de.rki.coronawarnapp.vaccination.ui.cards.BottomInfoVaccinationCard
-import de.rki.coronawarnapp.vaccination.ui.cards.CreateVaccinationCard
-import de.rki.coronawarnapp.vaccination.ui.cards.HeaderInfoVaccinationCard
-import de.rki.coronawarnapp.vaccination.ui.cards.ImmuneVaccinationCard
-import de.rki.coronawarnapp.vaccination.ui.cards.VaccinationCard
 
 class CertificatesAdapter :
     ModularAdapter<CertificatesAdapter.CertificatesItemVH<CertificatesItem, ViewBinding>>(),
@@ -36,7 +38,11 @@ class CertificatesAdapter :
                 },
                 TypedVHCreatorMod({ data[it] is CreateVaccinationCard.Item }) { CreateVaccinationCard(it) },
                 TypedVHCreatorMod({ data[it] is HeaderInfoVaccinationCard.Item }) { HeaderInfoVaccinationCard(it) },
-                TypedVHCreatorMod({ data[it] is BottomInfoVaccinationCard.Item }) { BottomInfoVaccinationCard(it) },
+                TypedVHCreatorMod({ data[it] is NoCovidTestCertificatesCard.Item }) { NoCovidTestCertificatesCard(it) },
+                TypedVHCreatorMod({ data[it] is CovidTestCertificateCard.Item }) { CovidTestCertificateCard(it) },
+                TypedVHCreatorMod({ data[it] is CovidTestCertificateErrorCard.Item }) {
+                    CovidTestCertificateErrorCard(it)
+                },
             )
         )
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..96263715b079593f273d3a19bddbcd80c0d736a2
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt
@@ -0,0 +1,99 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.widget.Toolbar
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.DefaultItemAnimator
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListFragment
+import de.rki.coronawarnapp.databinding.FragmentCertificatesBinding
+import de.rki.coronawarnapp.util.DialogHelper
+import de.rki.coronawarnapp.util.di.AutoInject
+import de.rki.coronawarnapp.util.lists.decorations.TopBottomPaddingDecorator
+import de.rki.coronawarnapp.util.lists.diffutil.update
+import de.rki.coronawarnapp.util.ui.doNavigate
+import de.rki.coronawarnapp.util.ui.findNestedGraph
+import de.rki.coronawarnapp.util.ui.observe2
+import de.rki.coronawarnapp.util.ui.viewBinding
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
+import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
+import javax.inject.Inject
+
+class CertificatesFragment : Fragment(R.layout.fragment_certificates), AutoInject {
+
+    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
+    private val viewModel by cwaViewModels<CertificatesViewModel> { viewModelFactory }
+    private val binding by viewBinding<FragmentCertificatesBinding>()
+
+    private val certificatesAdapter = CertificatesAdapter()
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        binding.apply {
+            setupMenu(mainTracing)
+            recyclerView.apply {
+                itemAnimator = DefaultItemAnimator()
+                addItemDecoration(TopBottomPaddingDecorator(topPadding = R.dimen.spacing_tiny))
+                adapter = certificatesAdapter
+            }
+        }
+
+        viewModel.screenItems.observe2(this) { items -> certificatesAdapter.update(items) }
+        viewModel.events.observe2(this) { event ->
+            when (event) {
+                is CertificatesFragmentEvents.GoToVaccinationList -> findNavController().navigate(
+                    VaccinationListFragment.navigationUri(event.personIdentifierCodeSha256)
+                )
+                is CertificatesFragmentEvents.OpenVaccinationRegistrationGraph -> {
+                    findNestedGraph(R.id.vaccination_nav_graph).startDestination = R.id.vaccinationQrCodeScanFragment
+                    doNavigate(CertificatesFragmentDirections.actionCertificatesFragmentToVaccinationNavGraph())
+                }
+                is CertificatesFragmentEvents.GoToCovidCertificateDetailScreen -> {
+                    doNavigate(
+                        CertificatesFragmentDirections
+                            .actionCertificatesFragmentToCovidCertificateDetailsFragment(event.identifier)
+                    )
+                }
+                is CertificatesFragmentEvents.ShowRefreshErrorCertificateDialog -> {
+                    val dialog = DialogHelper.DialogInstance(
+                        context = requireContext(),
+                        title = R.string.test_certificate_refresh_dialog_title,
+                        message = event.error.localizedMessage,
+                        positiveButton = R.string.test_certificate_refresh_dialog_confirm_button,
+                        cancelable = false
+                    )
+                    DialogHelper.showDialog(dialog)
+                }
+                is CertificatesFragmentEvents.ShowDeleteErrorCertificateDialog -> {
+                    val dialog = DialogHelper.DialogInstance(
+                        context = requireContext(),
+                        title = R.string.test_certificate_delete_dialog_title,
+                        message = R.string.test_certificate_delete_dialog_body,
+                        positiveButton = R.string.test_certificate_delete_dialog_confirm_button,
+                        negativeButton = R.string.test_certificate_delete_dialog_cancel_button,
+                        cancelable = false,
+                        positiveButtonFunction = {
+                            viewModel.deleteTestCertificate(event.identifier)
+                        }
+                    )
+                    DialogHelper.showDialog(dialog)
+                }
+            }
+        }
+    }
+
+    private fun setupMenu(toolbar: Toolbar) = toolbar.apply {
+        setOnMenuItemClickListener {
+            when (it.itemId) {
+                R.id.menu_information -> {
+                    doNavigate(CertificatesFragmentDirections.actionCertificatesFragmentToConsentFragment())
+                    true
+                }
+                else -> onOptionsItemSelected(it)
+            }
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragmentEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragmentEvents.kt
new file mode 100644
index 0000000000000000000000000000000000000000..259f0feb5c669db1f99a271c1ffc7d11a7869061
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragmentEvents.kt
@@ -0,0 +1,17 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui
+
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateIdentifier
+
+sealed class CertificatesFragmentEvents {
+
+    data class OpenVaccinationRegistrationGraph(val registrationAcknowledged: Boolean) : CertificatesFragmentEvents()
+
+    data class GoToVaccinationList(val personIdentifierCodeSha256: String) : CertificatesFragmentEvents()
+
+    data class GoToCovidCertificateDetailScreen(val identifier: String) : CertificatesFragmentEvents()
+
+    data class ShowRefreshErrorCertificateDialog(val error: Exception) : CertificatesFragmentEvents()
+
+    data class ShowDeleteErrorCertificateDialog(val identifier: TestCertificateIdentifier) :
+        CertificatesFragmentEvents()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragmentModule.kt
similarity index 89%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesFragmentModule.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragmentModule.kt
index a0e9ec938fef274d033efae607e075cc3050bb38..ae38d73a53186cf059b1c83015771378e1db27d7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesFragmentModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragmentModule.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.greencertificate.ui.certificates
+package de.rki.coronawarnapp.covidcertificate.test.ui
 
 import dagger.Binds
 import dagger.Module
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..374c269b475ecea16b6f5fe41bc4f6896b73937e
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesViewModel.kt
@@ -0,0 +1,131 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.asLiveData
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateWrapper
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateIdentifier
+import de.rki.coronawarnapp.covidcertificate.test.ui.cards.CovidTestCertificateCard
+import de.rki.coronawarnapp.covidcertificate.test.ui.cards.CovidTestCertificateErrorCard
+import de.rki.coronawarnapp.covidcertificate.test.ui.items.CertificatesItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationSettings
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.CreateVaccinationCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.HeaderInfoVaccinationCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.ImmuneVaccinationCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.NoCovidTestCertificatesCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.VaccinationCard
+import de.rki.coronawarnapp.util.ui.SingleLiveEvent
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
+import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
+import kotlinx.coroutines.flow.combine
+
+class CertificatesViewModel @AssistedInject constructor(
+    vaccinationRepository: VaccinationRepository,
+    private val vaccinationSettings: VaccinationSettings,
+    private val testCertificateRepository: TestCertificateRepository
+) : CWAViewModel() {
+
+    val events = SingleLiveEvent<CertificatesFragmentEvents>()
+
+    private fun refreshTestCertificate(identifier: TestCertificateIdentifier) {
+        launch {
+            val error = testCertificateRepository.refresh(identifier).mapNotNull { it.error }.singleOrNull()
+            if (error != null) {
+                events.postValue(CertificatesFragmentEvents.ShowRefreshErrorCertificateDialog(error))
+            }
+        }
+    }
+
+    fun deleteTestCertificate(identifier: TestCertificateIdentifier) {
+        launch {
+            testCertificateRepository.deleteCertificate(identifier)
+        }
+    }
+
+    val screenItems: LiveData<List<CertificatesItem>> =
+        vaccinationRepository.vaccinationInfos
+            .combine(testCertificateRepository.certificates) { vaccinatedPersons, certificates ->
+                mutableListOf<CertificatesItem>().apply {
+                    add(HeaderInfoVaccinationCard.Item)
+                    if (vaccinatedPersons.isEmpty()) {
+                        add(
+                            CreateVaccinationCard.Item(
+                                onClickAction = {
+                                    CertificatesFragmentEvents.OpenVaccinationRegistrationGraph(
+                                        vaccinationSettings.registrationAcknowledged
+                                    ).run { events.postValue(this) }
+                                }
+                            )
+                        )
+                    } else {
+                        addAll(vaccinatedPersons.toCertificateItems())
+                    }
+
+                    if (certificates.isEmpty()) {
+                        add(NoCovidTestCertificatesCard.Item)
+                    } else {
+                        addAll(certificates.toCertificateItems())
+                    }
+                }
+            }.asLiveData()
+
+    private fun Set<VaccinatedPerson>.toCertificateItems(): List<CertificatesItem> = map { vaccinatedPerson ->
+        when (vaccinatedPerson.getVaccinationStatus()) {
+            VaccinatedPerson.Status.COMPLETE,
+            VaccinatedPerson.Status.INCOMPLETE -> VaccinationCard.Item(
+                vaccinatedPerson = vaccinatedPerson,
+                onClickAction = {
+                    CertificatesFragmentEvents.GoToVaccinationList(
+                        vaccinatedPerson.identifier.codeSHA256
+                    ).run { events.postValue(this) }
+                }
+            )
+            VaccinatedPerson.Status.IMMUNITY -> ImmuneVaccinationCard.Item(
+                vaccinatedPerson = vaccinatedPerson,
+                onClickAction = {
+                    CertificatesFragmentEvents.GoToVaccinationList(
+                        vaccinatedPerson.identifier.codeSHA256
+                    ).run { events.postValue(this) }
+                }
+            )
+        }
+    }
+
+    private fun Collection<TestCertificateWrapper>.toCertificateItems(): List<CertificatesItem> = map { certificate ->
+        if (certificate.isCertificateRetrievalPending) {
+            CovidTestCertificateErrorCard.Item(
+                testDate = certificate.registeredAt,
+                isUpdatingData = certificate.isUpdatingData,
+                onRetryAction = {
+                    refreshTestCertificate(certificate.identifier)
+                },
+                onDeleteAction = {
+                    events.postValue(
+                        CertificatesFragmentEvents.ShowDeleteErrorCertificateDialog(
+                            certificate.identifier
+                        )
+                    )
+                }
+            )
+        } else {
+            CovidTestCertificateCard.Item(
+                testDate = certificate.registeredAt,
+                testPerson =
+                certificate.testCertificate?.firstName + " " +
+                    certificate.testCertificate?.lastName,
+                onClickAction = {
+                    CertificatesFragmentEvents.GoToCovidCertificateDetailScreen(
+                        certificate.identifier
+                    ).run { events.postValue(this) }
+                }
+            )
+        }
+    }
+
+    @AssistedFactory
+    interface Factory : SimpleCWAViewModelFactory<CertificatesViewModel>
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CovidCertificateUIModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CovidCertificateUIModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8bc95ef2ad4b954ec34eb1f43dc84f68180aab3d
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CovidCertificateUIModule.kt
@@ -0,0 +1,16 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui
+
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import de.rki.coronawarnapp.covidcertificate.test.ui.details.CovidCertificateDetailsFragment
+import de.rki.coronawarnapp.covidcertificate.test.ui.details.CovidCertificateDetailsModule
+
+@Module
+abstract class CovidCertificateUIModule {
+
+    @ContributesAndroidInjector(modules = [CertificatesFragmentModule::class])
+    abstract fun certificatesFragment(): CertificatesFragment
+
+    @ContributesAndroidInjector(modules = [CovidCertificateDetailsModule::class])
+    abstract fun certificateDetailsFragment(): CovidCertificateDetailsFragment
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/cards/CovidCertificateTestItem.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/cards/CovidCertificateTestItem.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bc27a92dd94416a5e9e1f45b22b9f384af8f8856
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/cards/CovidCertificateTestItem.kt
@@ -0,0 +1,11 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui.cards
+
+import de.rki.coronawarnapp.covidcertificate.test.ui.items.CertificatesItem
+import org.joda.time.Instant
+
+interface CovidCertificateTestItem : CertificatesItem {
+    val testDate: Instant
+
+    override val stableId: Long
+        get() = testDate.hashCode().toLong()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/cards/CovidTestCertificateCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/cards/CovidTestCertificateCard.kt
new file mode 100644
index 0000000000000000000000000000000000000000..791baaf5ab8d8625f9aa814583dd4d9975107aad
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/cards/CovidTestCertificateCard.kt
@@ -0,0 +1,45 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui.cards
+
+import android.view.ViewGroup
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.test.ui.CertificatesAdapter
+import de.rki.coronawarnapp.databinding.CovidTestSuccessCardBinding
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortDayFormat
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortTimeFormat
+import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer
+import org.joda.time.Instant
+
+class CovidTestCertificateCard(parent: ViewGroup) :
+    CertificatesAdapter.CertificatesItemVH<CovidTestCertificateCard.Item, CovidTestSuccessCardBinding>(
+        R.layout.home_card_container_layout,
+        parent
+    ) {
+
+    override val viewBinding = lazy {
+        CovidTestSuccessCardBinding.inflate(layoutInflater, itemView.findViewById(R.id.card_container), true)
+    }
+
+    override val onBindData: CovidTestSuccessCardBinding.(
+        item: Item,
+        payloads: List<Any>
+    ) -> Unit = { item, payloads ->
+        val curItem = payloads.filterIsInstance<Item>().singleOrNull() ?: item
+        testTime.text = context.getString(
+            R.string.test_certificate_time,
+            curItem.testDate.toShortDayFormat(),
+            curItem.testDate.toShortTimeFormat(),
+        )
+
+        personName.text = curItem.testPerson
+
+        itemView.setOnClickListener { curItem.onClickAction(curItem) }
+    }
+
+    data class Item(
+        override val testDate: Instant,
+        val testPerson: String,
+        val onClickAction: (Item) -> Unit,
+    ) : CovidCertificateTestItem, HasPayloadDiffer {
+        override fun diffPayload(old: Any, new: Any): Any? = if (old::class == new::class) new else null
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/cards/CovidTestCertificateErrorCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/cards/CovidTestCertificateErrorCard.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3377a129fe47ba8d15b4ac6677af453871b3e028
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/cards/CovidTestCertificateErrorCard.kt
@@ -0,0 +1,63 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui.cards
+
+import android.view.ViewGroup
+import androidx.core.view.isGone
+import androidx.core.view.isInvisible
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.test.ui.CertificatesAdapter
+import de.rki.coronawarnapp.databinding.CovidTestErrorCardBinding
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortDayFormat
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortTimeFormat
+import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer
+import org.joda.time.Instant
+
+class CovidTestCertificateErrorCard(parent: ViewGroup) :
+    CertificatesAdapter.CertificatesItemVH<CovidTestCertificateErrorCard.Item, CovidTestErrorCardBinding>(
+        R.layout.home_card_container_layout,
+        parent
+    ) {
+
+    override val viewBinding = lazy {
+        CovidTestErrorCardBinding.inflate(layoutInflater, itemView.findViewById(R.id.card_container), true)
+    }
+
+    override val onBindData: CovidTestErrorCardBinding.(
+        item: Item,
+        payloads: List<Any>
+    ) -> Unit = { item, _ ->
+
+        testTime.text = context.getString(
+            R.string.test_certificate_time,
+            item.testDate.toShortDayFormat(),
+            item.testDate.toShortTimeFormat(),
+        )
+
+        retryButton.setOnClickListener {
+            item.onRetryAction(item)
+        }
+
+        if (item.isUpdatingData) {
+            refreshStatus.isGone = false
+            progressBar.show()
+            retryButton.isInvisible = true
+            deleteButton.isInvisible = true
+            body.text = context.getString(R.string.test_certificate_error_label_refreshing)
+        } else {
+            refreshStatus.isGone = true
+            progressBar.hide()
+            retryButton.isInvisible = false
+            deleteButton.isInvisible = false
+            body.text = context.getString(R.string.test_certificate_error_label)
+        }
+        deleteButton.setOnClickListener { item.onDeleteAction(item) }
+    }
+
+    data class Item(
+        override val testDate: Instant,
+        val onRetryAction: (Item) -> Unit,
+        val onDeleteAction: (Item) -> Unit,
+        val isUpdatingData: Boolean,
+    ) : CovidCertificateTestItem, HasPayloadDiffer {
+        override fun diffPayload(old: Any, new: Any): Any? = if (old::class == new::class) new else null
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ae32afd1905d6b97daf944cccf12e4eb8487214a
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsFragment.kt
@@ -0,0 +1,172 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui.details
+
+import android.graphics.Bitmap
+import android.os.Bundle
+import android.view.View
+import android.widget.LinearLayout
+import androidx.coordinatorlayout.widget.CoordinatorLayout
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.FragmentNavigatorExtras
+import androidx.navigation.fragment.findNavController
+import androidx.navigation.fragment.navArgs
+import com.google.android.material.appbar.AppBarLayout
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.bugreporting.ui.toErrorDialogBuilder
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificate
+import de.rki.coronawarnapp.databinding.FragmentCovidCertificateDetailsBinding
+import de.rki.coronawarnapp.ui.qrcode.fullscreen.QrCodeFullScreenFragmentArgs
+import de.rki.coronawarnapp.ui.view.onOffsetChange
+import de.rki.coronawarnapp.util.DialogHelper
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.toDayFormat
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortDayFormat
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortTimeFormat
+import de.rki.coronawarnapp.util.di.AutoInject
+import de.rki.coronawarnapp.util.setUrl
+import de.rki.coronawarnapp.util.ui.popBackStack
+import de.rki.coronawarnapp.util.ui.viewBinding
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
+import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted
+import javax.inject.Inject
+
+class CovidCertificateDetailsFragment : Fragment(R.layout.fragment_covid_certificate_details), AutoInject {
+
+    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
+    private val binding by viewBinding<FragmentCovidCertificateDetailsBinding>()
+    private val args by navArgs<CovidCertificateDetailsFragmentArgs>()
+    private val viewModel: CovidCertificateDetailsViewModel by cwaViewModelsAssisted(
+        factoryProducer = { viewModelFactory },
+        constructorCall = { factory, _ ->
+            factory as CovidCertificateDetailsViewModel.Factory
+            factory.create(
+                testCertificateIdentifier = args.testCertificateIdentifier
+            )
+        }
+    )
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) = with(binding) {
+        qrCodeCard.title.setText(R.string.detail_green_certificate_card_title)
+        appBarLayout.onOffsetChange { titleAlpha, subtitleAlpha ->
+            title.alpha = titleAlpha
+            subtitle.alpha = subtitleAlpha
+        }
+
+        bindTravelNoticeViews()
+        bindToolbar()
+        setToolbarOverlay()
+
+        viewModel.qrCode.observe(viewLifecycleOwner) { onQrCodeReady(it) }
+        viewModel.errors.observe(viewLifecycleOwner) { onError(it) }
+        viewModel.events.observe(viewLifecycleOwner) { onNavEvent(it) }
+        viewModel.covidCertificate.observe(viewLifecycleOwner) { it?.let { onCertificateReady(it) } }
+    }
+
+    private fun FragmentCovidCertificateDetailsBinding.onCertificateReady(
+        testCertificate: TestCertificate
+    ) {
+        qrCodeCard.subtitle.text = getString(
+            R.string.detail_green_certificate_card_subtitle,
+            testCertificate.sampleCollectedAt.toShortDayFormat(),
+            testCertificate.sampleCollectedAt.toShortTimeFormat(),
+        )
+        name.text = testCertificate.run { "$firstName $lastName" }
+        birthDate.text = testCertificate.dateOfBirth.toDayFormat()
+        diseaseType.text = testCertificate.targetName
+        testType.text = testCertificate.testType
+        testName.text = testCertificate.testName
+        testManufacturer.text = testCertificate.testNameAndManufactor
+        testDate.text = "%s %s".format(
+            testCertificate.sampleCollectedAt.toShortDayFormat(),
+            testCertificate.sampleCollectedAt.toShortTimeFormat()
+        )
+        testResult.text = testCertificate.testResult
+        testCenter.text = testCertificate.testCenter
+        certificateCountry.text = testCertificate.certificateCountry
+        certificateIssuer.text = testCertificate.certificateIssuer
+        certificateId.text = testCertificate.certificateId
+    }
+
+    private fun FragmentCovidCertificateDetailsBinding.onQrCodeReady(bitmap: Bitmap?) {
+        qrCodeCard.apply {
+            image.setImageBitmap(bitmap)
+            progressBar.hide()
+            bitmap?.let { image.setOnClickListener { viewModel.openFullScreen() } }
+        }
+    }
+
+    private fun FragmentCovidCertificateDetailsBinding.onError(error: Throwable) {
+        qrCodeCard.progressBar.hide()
+        error.toErrorDialogBuilder(requireContext()).show()
+    }
+
+    private fun FragmentCovidCertificateDetailsBinding.onNavEvent(event: CovidCertificateDetailsNavigation) {
+        when (event) {
+            CovidCertificateDetailsNavigation.Back -> popBackStack()
+            is CovidCertificateDetailsNavigation.FullQrCode -> findNavController().navigate(
+                R.id.action_global_qrCodeFullScreenFragment,
+                QrCodeFullScreenFragmentArgs(event.qrCodeText).toBundle(),
+                null,
+                FragmentNavigatorExtras(qrCodeCard.image to qrCodeCard.image.transitionName)
+            )
+        }
+    }
+
+    private fun FragmentCovidCertificateDetailsBinding.bindTravelNoticeViews() {
+        if (travelNoticeGerman.text ==
+            getString(R.string.green_certificate_attribute_certificate_travel_notice_german)
+        ) {
+            travelNoticeGerman.setUrl(
+                R.string.green_certificate_attribute_certificate_travel_notice_german,
+                R.string.green_certificate_travel_notice_link_de,
+                R.string.green_certificate_travel_notice_link_de
+            )
+        }
+
+        if (travelNoticeEnglish.text ==
+            getString(R.string.green_certificate_attribute_certificate_travel_notice_english)
+        ) {
+            travelNoticeEnglish.setUrl(
+                R.string.green_certificate_attribute_certificate_travel_notice_english,
+                R.string.green_certificate_travel_notice_link_en,
+                R.string.green_certificate_travel_notice_link_en
+            )
+        }
+    }
+
+    private fun FragmentCovidCertificateDetailsBinding.bindToolbar() = toolbar.apply {
+        setNavigationOnClickListener { popBackStack() }
+        setOnMenuItemClickListener {
+            when (it.itemId) {
+                R.id.menu_covid_certificate_delete -> {
+                    DialogHelper.showDialog(deleteTestConfirmationDialog)
+                    true
+                }
+                else -> onOptionsItemSelected(it)
+            }
+        }
+    }
+
+    private fun setToolbarOverlay() {
+        val width = requireContext().resources.displayMetrics.widthPixels
+        val params: CoordinatorLayout.LayoutParams = binding.scrollView.layoutParams as (CoordinatorLayout.LayoutParams)
+
+        val textParams = binding.subtitle.layoutParams as (LinearLayout.LayoutParams)
+        textParams.bottomMargin = (width / 3) + 170
+        binding.subtitle.requestLayout()
+
+        val behavior: AppBarLayout.ScrollingViewBehavior = params.behavior as (AppBarLayout.ScrollingViewBehavior)
+        behavior.overlayTop = (width / 3) + 170
+    }
+
+    private val deleteTestConfirmationDialog by lazy {
+        DialogHelper.DialogInstance(
+            requireActivity(),
+            R.string.green_certificate_details_dialog_remove_test_title,
+            R.string.green_certificate_details_dialog_remove_test_message,
+            R.string.green_certificate_details_dialog_remove_test_button_positive,
+            R.string.green_certificate_details_dialog_remove_test_button_negative,
+            positiveButtonFunction = {
+                viewModel.onDeleteTestConfirmed()
+            }
+        )
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsModule.kt
similarity index 62%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsModule.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsModule.kt
index 363a483bf8bd6ba41eb6fb1e408055eb3bda9189..2846c57e371822be705c0cd4be3d455a752b4814 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsModule.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.greencertificate.ui.certificates.details
+package de.rki.coronawarnapp.covidcertificate.test.ui.details
 
 import dagger.Binds
 import dagger.Module
@@ -8,12 +8,12 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
 
 @Module
-abstract class GreenCertificateDetailsModule {
+abstract class CovidCertificateDetailsModule {
 
     @Binds
     @IntoMap
-    @CWAViewModelKey(GreenCertificateDetailsViewModel::class)
+    @CWAViewModelKey(CovidCertificateDetailsViewModel::class)
     abstract fun greenCertificateDetailsFragment(
-        factory: GreenCertificateDetailsViewModel.Factory
+        factory: CovidCertificateDetailsViewModel.Factory
     ): CWAViewModelFactory<out CWAViewModel>
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsNavigation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsNavigation.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b064ccfdaeecd4a2ae2c6b472e7aed57ce1a9304
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsNavigation.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui.details
+
+sealed class CovidCertificateDetailsNavigation {
+    object Back : CovidCertificateDetailsNavigation()
+    data class FullQrCode(val qrCodeText: String) : CovidCertificateDetailsNavigation()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..62e1bef00fac4029c59d563f8108cf8db1d58a03
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsViewModel.kt
@@ -0,0 +1,66 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui.details
+
+import android.graphics.Bitmap
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.asLiveData
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificate
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateIdentifier
+import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator
+import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
+import de.rki.coronawarnapp.util.ui.SingleLiveEvent
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
+import kotlinx.coroutines.flow.map
+import timber.log.Timber
+
+class CovidCertificateDetailsViewModel @AssistedInject constructor(
+    dispatcherProvider: DispatcherProvider,
+    @Assisted private val testCertificateIdentifier: TestCertificateIdentifier,
+    private val qrCodeGenerator: QrCodeGenerator,
+    private val testCertificateRepository: TestCertificateRepository
+) : CWAViewModel(dispatcherProvider) {
+
+    private var qrCodeText: String? = null
+    private val bitmapStateData = MutableLiveData<Bitmap>()
+    val qrCode: LiveData<Bitmap> = bitmapStateData
+    val events = SingleLiveEvent<CovidCertificateDetailsNavigation>()
+    val errors = SingleLiveEvent<Throwable>()
+    val covidCertificate = testCertificateRepository.certificates.map { certificates ->
+        certificates.find { it.identifier == testCertificateIdentifier }?.testCertificate
+            .also { generateQrCode(it) }
+    }.asLiveData(dispatcherProvider.Default)
+
+    fun onClose() = events.postValue(CovidCertificateDetailsNavigation.Back)
+
+    fun openFullScreen() = qrCodeText?.let { events.postValue(CovidCertificateDetailsNavigation.FullQrCode(it)) }
+
+    fun onDeleteTestConfirmed() = launch {
+        Timber.d("Removing Test Certificate=$testCertificateIdentifier")
+        testCertificateRepository.deleteCertificate(testCertificateIdentifier)
+        events.postValue(CovidCertificateDetailsNavigation.Back)
+    }
+
+    private fun generateQrCode(testCertificate: TestCertificate?) = launch {
+        try {
+            bitmapStateData.postValue(
+                testCertificate?.let { certificate ->
+                    qrCodeGenerator.createQrCode(certificate.qrCode.also { qrCodeText = it })
+                }
+            )
+        } catch (e: Exception) {
+            Timber.d(e, "generateQrCode failed for covidCertificate=%s", testCertificateIdentifier)
+            bitmapStateData.postValue(null)
+            errors.postValue(e)
+        }
+    }
+
+    @AssistedFactory
+    interface Factory : CWAViewModelFactory<CovidCertificateDetailsViewModel> {
+        fun create(testCertificateIdentifier: TestCertificateIdentifier): CovidCertificateDetailsViewModel
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/items/CertificatesItem.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/items/CertificatesItem.kt
similarity index 58%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/items/CertificatesItem.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/items/CertificatesItem.kt
index c0d0ec32ca135bd6dd1740a4f2a0668b1555c92d..ec7c5198c6016e25bee488d6bedbf3fd5af6db63 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/items/CertificatesItem.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/items/CertificatesItem.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.greencertificate.ui.certificates.items
+package de.rki.coronawarnapp.covidcertificate.test.ui.items
 
 import de.rki.coronawarnapp.util.lists.HasStableId
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinatedPerson.kt
similarity index 76%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinatedPerson.kt
index 597a623db6757ffc4bf574373ec8851176610a52..942fe20bd7096d0eb936facb7a8e867abfc99c8c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinatedPerson.kt
@@ -1,19 +1,20 @@
-package de.rki.coronawarnapp.vaccination.core
+package de.rki.coronawarnapp.covidcertificate.vaccination.core
 
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinatedPersonData
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.VaccinationValueSets
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinatedPersonData
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet
 import org.joda.time.Duration
 import org.joda.time.Instant
 import org.joda.time.LocalDate
 
 data class VaccinatedPerson(
     internal val data: VaccinatedPersonData,
-    private val valueSet: VaccinationValueSet?,
+    private val valueSet: VaccinationValueSets?,
     val isUpdatingData: Boolean = false,
     val lastError: Throwable? = null,
 ) {
-    val identifier: VaccinatedPersonIdentifier
+    val identifier: CertificatePersonIdentifier
         get() = data.identifier
 
     val vaccinationCertificates: Set<VaccinationCertificate> by lazy {
@@ -23,17 +24,8 @@ data class VaccinatedPerson(
     val vaccineName: String
         get() = vaccinationCertificates.first().vaccineTypeName
 
-    val firstName: String?
-        get() = vaccinationCertificates.first().firstName
-
-    val lastName: String
-        get() = vaccinationCertificates.first().lastName
-
     val fullName: String
-        get() = when {
-            firstName == null -> lastName
-            else -> "$firstName $lastName"
-        }
+        get() = vaccinationCertificates.first().fullName
 
     val dateOfBirth: LocalDate
         get() = vaccinationCertificates.first().dateOfBirth
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt
new file mode 100644
index 0000000000000000000000000000000000000000..21efe369b7c65a85c67f367f07f5a799308a7647
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt
@@ -0,0 +1,16 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.core
+
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CwaCovidCertificate
+import org.joda.time.LocalDate
+
+interface VaccinationCertificate : CwaCovidCertificate {
+
+    val vaccinatedAt: LocalDate
+
+    val vaccineTypeName: String
+    val vaccineManufacturer: String
+    val medicalProductName: String
+
+    val doseNumber: Int
+    val totalSeriesOfDoses: Int
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationException.kt
similarity index 62%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationException.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationException.kt
index 4963bf1bd500fddac6397d6da57a8f06a5d8eaf5..da1c1911f63931bd18a6bb237bdd51f455053989 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationException.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.core
+package de.rki.coronawarnapp.covidcertificate.vaccination.core
 
 open class VaccinationException(
     cause: Throwable?,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationModule.kt
similarity index 62%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationModule.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationModule.kt
index e8c20bd7126a10e2af24b8d262145783ddaf83a1..047534e6edbe942345297ea3a1ddd14b9d68a28a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationModule.kt
@@ -1,19 +1,14 @@
-package de.rki.coronawarnapp.vaccination.core
+package de.rki.coronawarnapp.covidcertificate.vaccination.core
 
 import dagger.Binds
 import dagger.Module
 import dagger.multibindings.IntoMap
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.task.VaccinationUpdateTask
 import de.rki.coronawarnapp.task.Task
 import de.rki.coronawarnapp.task.TaskFactory
 import de.rki.coronawarnapp.task.TaskTypeKey
-import de.rki.coronawarnapp.vaccination.core.execution.task.VaccinationUpdateTask
-import de.rki.coronawarnapp.vaccination.core.server.VaccinationServerModule
 
-@Module(
-    includes = [
-        VaccinationServerModule::class
-    ]
-)
+@Module
 abstract class VaccinationModule {
     @Binds
     @IntoMap
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationPreferences.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationPreferences.kt
similarity index 91%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationPreferences.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationPreferences.kt
index 1c0597590793b93d1a4979249a0992f0f48fe738..dfef6623a2aa8e1a5f5f1a5c2daee99dec73666f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationPreferences.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationPreferences.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.core
+package de.rki.coronawarnapp.covidcertificate.vaccination.core
 
 import android.content.Context
 import de.rki.coronawarnapp.util.di.AppContext
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationSettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationSettings.kt
similarity index 85%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationSettings.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationSettings.kt
index 1fe9dbda18b8e4178555e078f2e1b6ba55c5d239..ae1f8443addc2c02f6620c2ee25488636b32456e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationSettings.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationSettings.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.core
+package de.rki.coronawarnapp.covidcertificate.vaccination.core
 
 import javax.inject.Inject
 import javax.inject.Singleton
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/VaccinationDGCV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1.kt
similarity index 56%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/VaccinationDGCV1.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1.kt
index 0fca7a0101289b434bd8069951df51e84a323327..3583458aa0c5211d4524647a6c449e81b5bd6af6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/VaccinationDGCV1.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1.kt
@@ -1,24 +1,19 @@
-package de.rki.coronawarnapp.vaccination.core.certificate
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate
 
 import com.google.gson.annotations.SerializedName
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
 import org.joda.time.LocalDate
 
-data class VaccinationDGCV1(
-    @SerializedName("ver") val version: String,
-    @SerializedName("nam") val nameData: NameData,
-    @SerializedName("dob") val dob: String,
-    @SerializedName("v") val vaccinationDatas: List<VaccinationData>,
-) {
-    data class NameData(
-        @SerializedName("fn") val familyName: String?,
-        @SerializedName("fnt") val familyNameStandardized: String,
-        @SerializedName("gn") val givenName: String?,
-        @SerializedName("gnt") val givenNameStandardized: String?,
-    )
+data class VaccinationDccV1(
+    @SerializedName("ver") override val version: String,
+    @SerializedName("nam") override val nameData: Dcc.NameData,
+    @SerializedName("dob") override val dob: String,
+    @SerializedName("v") override val payloads: List<VaccinationData>,
+) : Dcc<VaccinationDccV1.VaccinationData> {
 
     data class VaccinationData(
         // Disease or agent targeted, e.g. "tg": "840539006"
-        @SerializedName("tg") val targetId: String,
+        @SerializedName("tg") override val targetId: String,
         // Vaccine or prophylaxis, e.g. "vp": "1119349007"
         @SerializedName("vp") val vaccineId: String,
         // Vaccine medicinal product,e.g. "mp": "EU/1/20/1528",
@@ -32,16 +27,13 @@ data class VaccinationDGCV1(
         // Date of Vaccination, e.g. "dt" : "2021-04-21"
         @SerializedName("dt") val dt: String,
         // Country of Vaccination, e.g. "co": "NL"
-        @SerializedName("co") val countryOfVaccination: String,
+        @SerializedName("co") override val certificateCountry: String,
         // Certificate Issuer, e.g. "is": "Ministry of Public Health, Welfare and Sport",
-        @SerializedName("is") val certificateIssuer: String,
+        @SerializedName("is") override val certificateIssuer: String,
         // Unique Certificate Identifier, e.g.  "ci": "urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ"
-        @SerializedName("ci") val uniqueCertificateIdentifier: String
-    ) {
+        @SerializedName("ci") override val uniqueCertificateIdentifier: String
+    ) : Dcc.Payload {
         val vaccinatedAt: LocalDate
             get() = LocalDate.parse(dt)
     }
-
-    val dateOfBirth: LocalDate
-        get() = LocalDate.parse(dob)
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1Parser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1Parser.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c2547d460f2ef7a0b2e45edffaf604877e506464
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1Parser.kt
@@ -0,0 +1,69 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate
+
+import com.google.gson.Gson
+import com.upokecenter.cbor.CBORObject
+import dagger.Reusable
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_DGC
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_HCERT
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.JSON_SCHEMA_INVALID
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_NO_VACCINATION_ENTRY
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
+import de.rki.coronawarnapp.util.serialization.BaseGson
+import de.rki.coronawarnapp.util.serialization.fromJson
+import javax.inject.Inject
+
+@Reusable
+class VaccinationDccV1Parser @Inject constructor(
+    @BaseGson private val gson: Gson
+) {
+
+    fun parse(map: CBORObject): VaccinationDccV1 = try {
+        map[keyHCert]?.run {
+            this[keyEuDgcV1]?.run {
+                toCertificate()
+            } ?: throw InvalidVaccinationCertificateException(HC_CWT_NO_DGC)
+        } ?: throw InvalidVaccinationCertificateException(HC_CWT_NO_HCERT)
+    } catch (e: InvalidHealthCertificateException) {
+        throw e
+    } catch (e: Throwable) {
+        throw InvalidVaccinationCertificateException(HC_CBOR_DECODING_FAILED)
+    }
+
+    @Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
+    private fun VaccinationDccV1.validate(): VaccinationDccV1 {
+        if (payloads.isNullOrEmpty()) {
+            throw InvalidVaccinationCertificateException(VC_NO_VACCINATION_ENTRY)
+        }
+        // check for non null (Gson does not enforce it) & force date parsing
+        require(version.isNotBlank())
+        require(nameData.familyNameStandardized.isNotBlank())
+        dateOfBirth
+        payload.let {
+            it.vaccinatedAt
+            require(it.certificateIssuer.isNotBlank())
+            require(it.certificateCountry.isNotBlank())
+            require(it.marketAuthorizationHolderId.isNotBlank())
+            require(it.medicalProductId.isNotBlank())
+            require(it.targetId.isNotBlank())
+            require(it.doseNumber > 0)
+            require(it.totalSeriesOfDoses > 0)
+        }
+        return this
+    }
+
+    private fun CBORObject.toCertificate() = try {
+        val json = ToJSONString()
+        gson.fromJson<VaccinationDccV1>(json).validate()
+    } catch (e: InvalidVaccinationCertificateException) {
+        throw e
+    } catch (e: Throwable) {
+        throw InvalidVaccinationCertificateException(JSON_SCHEMA_INVALID)
+    }
+
+    companion object {
+        private val keyEuDgcV1 = CBORObject.FromObject(1)
+        private val keyHCert = CBORObject.FromObject(-260)
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/VaccinationUpdateScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/VaccinationUpdateScheduler.kt
similarity index 92%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/VaccinationUpdateScheduler.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/VaccinationUpdateScheduler.kt
index 5393642f6da98b91c3e16e73b3260c7bedb1a8cc..b58242c8e03bbe328feac51024972f609794d76a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/VaccinationUpdateScheduler.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/VaccinationUpdateScheduler.kt
@@ -1,8 +1,11 @@
-package de.rki.coronawarnapp.vaccination.core.execution
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.execution
 
 import androidx.work.ExistingPeriodicWorkPolicy
 import androidx.work.WorkInfo
 import androidx.work.WorkManager
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.task.VaccinationUpdateTask
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.worker.VaccinationUpdateWorkerRequestBuilder
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
 import de.rki.coronawarnapp.task.TaskController
 import de.rki.coronawarnapp.task.TaskFactory
 import de.rki.coronawarnapp.task.common.DefaultTaskRequest
@@ -11,9 +14,6 @@ import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.coroutine.AppScope
 import de.rki.coronawarnapp.util.coroutine.await
 import de.rki.coronawarnapp.util.device.ForegroundState
-import de.rki.coronawarnapp.vaccination.core.execution.task.VaccinationUpdateTask
-import de.rki.coronawarnapp.vaccination.core.execution.worker.VaccinationUpdateWorkerRequestBuilder
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.catch
 import kotlinx.coroutines.flow.combine
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/task/VaccinationUpdateTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/task/VaccinationUpdateTask.kt
similarity index 93%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/task/VaccinationUpdateTask.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/task/VaccinationUpdateTask.kt
index fdb14d5e90df4e916c192a18b504460112397c4e..77d919a9f8cab99b00c50ecbdf82667d0a6511cb 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/task/VaccinationUpdateTask.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/task/VaccinationUpdateTask.kt
@@ -1,13 +1,13 @@
-package de.rki.coronawarnapp.vaccination.core.execution.task
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.task
 
 import de.rki.coronawarnapp.appconfig.AppConfigProvider
 import de.rki.coronawarnapp.bugreporting.reportProblem
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
 import de.rki.coronawarnapp.task.Task
 import de.rki.coronawarnapp.task.TaskFactory
+import de.rki.coronawarnapp.task.common.DefaultProgress
 import de.rki.coronawarnapp.task.common.Finished
 import de.rki.coronawarnapp.task.common.Started
-import de.rki.coronawarnapp.task.common.DefaultProgress
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import org.joda.time.Duration
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/worker/VaccinationUpdateWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/worker/VaccinationUpdateWorker.kt
similarity index 92%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/worker/VaccinationUpdateWorker.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/worker/VaccinationUpdateWorker.kt
index a22d1c1f885925005fb62c74e54bb99ccbe13302..e308b3789ba3093974520ea8500d42b40d7bbbc1 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/worker/VaccinationUpdateWorker.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/worker/VaccinationUpdateWorker.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.core.execution.worker
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.worker
 
 import android.content.Context
 import androidx.work.CoroutineWorker
@@ -7,12 +7,12 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.bugreporting.reportProblem
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.task.VaccinationUpdateTask
 import de.rki.coronawarnapp.task.TaskController
 import de.rki.coronawarnapp.task.TaskFactory
 import de.rki.coronawarnapp.task.common.DefaultTaskRequest
 import de.rki.coronawarnapp.task.submitBlocking
 import de.rki.coronawarnapp.util.worker.InjectedWorkerFactory
-import de.rki.coronawarnapp.vaccination.core.execution.task.VaccinationUpdateTask
 import timber.log.Timber
 
 class VaccinationUpdateWorker @AssistedInject constructor(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/worker/VaccinationUpdateWorkerRequestBuilder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/worker/VaccinationUpdateWorkerRequestBuilder.kt
similarity index 93%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/worker/VaccinationUpdateWorkerRequestBuilder.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/worker/VaccinationUpdateWorkerRequestBuilder.kt
index 62b491fe6415cd54eef28cf5891720c64a2e1b02..c97b9f6bf087a5e3c795d958195057a06ff842a6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/execution/worker/VaccinationUpdateWorkerRequestBuilder.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/worker/VaccinationUpdateWorkerRequestBuilder.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.core.execution.worker
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.worker
 
 import androidx.work.BackoffPolicy
 import androidx.work.Constraints
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateQRCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateQRCode.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ad88fb5911610916e6ad6a1c1b2abf2493c2c5bb
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateQRCode.kt
@@ -0,0 +1,11 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode
+
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.DccQrCode
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
+
+data class VaccinationCertificateQRCode(
+    override val qrCode: QrCodeString,
+    override val data: DccData<VaccinationDccV1>
+) : DccQrCode<VaccinationDccV1>
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt
new file mode 100644
index 0000000000000000000000000000000000000000..362c7f7a621ca4628383e5c97f0cf286b405cea3
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt
@@ -0,0 +1,83 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode
+
+import de.rki.coronawarnapp.bugreporting.censors.vaccination.CertificateQrCodeCensor
+import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccCoseDecoder
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccHeaderParser
+import de.rki.coronawarnapp.covidcertificate.common.decoder.RawCOSEObject
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1Parser
+import de.rki.coronawarnapp.util.compression.inflate
+import de.rki.coronawarnapp.util.encoding.Base45Decoder
+import timber.log.Timber
+import javax.inject.Inject
+
+class VaccinationQRCodeExtractor @Inject constructor(
+    private val coseDecoder: DccCoseDecoder,
+    private val headerParser: DccHeaderParser,
+    private val bodyParser: VaccinationDccV1Parser,
+) : QrCodeExtractor<VaccinationCertificateQRCode> {
+
+    override fun canHandle(rawString: String): Boolean = rawString.startsWith(PREFIX)
+
+    override fun extract(rawString: String): VaccinationCertificateQRCode {
+        CertificateQrCodeCensor.addQRCodeStringToCensor(rawString)
+
+        val parsedData = rawString
+            .removePrefix(PREFIX)
+            .decodeBase45()
+            .decompress()
+            .parse()
+
+        return VaccinationCertificateQRCode(
+            qrCode = rawString,
+            data = parsedData,
+        )
+    }
+
+    private fun String.decodeBase45(): ByteArray = try {
+        Base45Decoder.decode(this)
+    } catch (e: Throwable) {
+        Timber.e(e)
+        throw InvalidVaccinationCertificateException(HC_BASE45_DECODING_FAILED)
+    }
+
+    private fun ByteArray.decompress(): RawCOSEObject = try {
+        this.inflate(sizeLimit = DEFAULT_SIZE_LIMIT)
+    } catch (e: Throwable) {
+        Timber.e(e)
+        throw InvalidVaccinationCertificateException(HC_ZLIB_DECOMPRESSION_FAILED)
+    }
+
+    fun RawCOSEObject.parse(): DccData<VaccinationDccV1> = try {
+        Timber.v("Parsing COSE for vaccination certificate.")
+        val cbor = coseDecoder.decode(this)
+
+        DccData(
+            header = headerParser.parse(cbor),
+            certificate = bodyParser.parse(cbor)
+        ).also {
+            CertificateQrCodeCensor.addCertificateToCensor(it)
+        }.also {
+            Timber.v("Parsed vaccination certificate for %s", it.certificate.nameData.familyNameStandardized)
+        }
+    } catch (e: InvalidHealthCertificateException) {
+        throw InvalidVaccinationCertificateException(e.errorCode)
+    } catch (e: Throwable) {
+        Timber.e(e)
+        throw InvalidVaccinationCertificateException(HC_CBOR_DECODING_FAILED)
+    }
+
+    companion object {
+        private const val PREFIX = "HC1:"
+
+        // Zip bomb
+        private const val DEFAULT_SIZE_LIMIT = 1024L * 1024 * 10L // 10 MB
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeValidator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeValidator.kt
similarity index 70%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeValidator.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeValidator.kt
index 3e7f603962d7306ea8bde1da607008559c94c7c1..9fe4b3a577c755f5667297e0d18d4282ed2e65aa 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeValidator.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeValidator.kt
@@ -1,9 +1,9 @@
-package de.rki.coronawarnapp.vaccination.core.qrcode
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode
 
 import dagger.Reusable
 import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_PREFIX_INVALID
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_PREFIX_INVALID
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
 import timber.log.Timber
 import javax.inject.Inject
 
@@ -19,7 +19,7 @@ class VaccinationQRCodeValidator @Inject constructor(
         return findExtractor(rawString)
             ?.extract(rawString)
             ?.also { Timber.i("Extracted data from QR code is %s", it) }
-            ?: throw InvalidHealthCertificateException(VC_PREFIX_INVALID)
+            ?: throw InvalidVaccinationCertificateException(VC_PREFIX_INVALID)
     }
 
     private fun findExtractor(rawString: String): QrCodeExtractor<VaccinationCertificateQRCode>? {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/VaccinationRepository.kt
similarity index 79%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepository.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/VaccinationRepository.kt
index ab3b35f4dfc2e3c48e4f5c94e586fcf66f7e6c6e..187a85d33b612ccf70bd1bd64b16530b1c42bb89 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/VaccinationRepository.kt
@@ -1,24 +1,24 @@
-package de.rki.coronawarnapp.vaccination.core.repository
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository
 
 import de.rki.coronawarnapp.bugreporting.reportProblem
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_ALREADY_REGISTERED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationCertificate
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationCertificateQRCode
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.errors.VaccinationCertificateNotFoundException
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinatedPersonData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinationContainer
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinationStorage
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.toVaccinationContainer
+import de.rki.coronawarnapp.covidcertificate.valueset.ValueSetsRepository
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.coroutine.AppScope
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.flow.HotDataFlow
 import de.rki.coronawarnapp.util.flow.combine
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPersonIdentifier
-import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode
-import de.rki.coronawarnapp.vaccination.core.personIdentifier
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateQRCode
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractor
-import de.rki.coronawarnapp.vaccination.core.repository.errors.VaccinationCertificateNotFoundException
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinatedPersonData
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationContainer
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationStorage
-import de.rki.coronawarnapp.vaccination.core.repository.storage.toVaccinationContainer
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
@@ -75,7 +75,7 @@ class VaccinationRepository @Inject constructor(
 
     val vaccinationInfos: Flow<Set<VaccinatedPerson>> = combine(
         internalData.data,
-        valueSetsRepository.latestValueSet
+        valueSetsRepository.latestVaccinationValueSets
     ) { personDatas, currentValueSet ->
         personDatas.map { it.copy(valueSet = currentValueSet) }.toSet()
     }
@@ -101,7 +101,7 @@ class VaccinationRepository @Inject constructor(
 
             if (originalPerson.data.vaccinations.any { it.certificateId == qrCode.uniqueCertificateIdentifier }) {
                 Timber.tag(TAG).e("Certificate is already registered: %s", qrCode.uniqueCertificateIdentifier)
-                throw InvalidHealthCertificateException(ErrorCode.VC_ALREADY_REGISTERED)
+                throw InvalidVaccinationCertificateException(VC_ALREADY_REGISTERED)
             }
 
             val newCertificate = qrCode.toVaccinationContainer(
@@ -132,7 +132,7 @@ class VaccinationRepository @Inject constructor(
      * Passing null as identifier will refresh all available data, if within constraints.
      * Throws VaccinatedPersonNotFoundException is you try to refresh a person that is unknown.
      */
-    suspend fun refresh(personIdentifier: VaccinatedPersonIdentifier? = null) {
+    suspend fun refresh(personIdentifier: CertificatePersonIdentifier? = null) {
         Timber.tag(TAG).d("refresh(personIdentifier=%s)", personIdentifier)
 
         // NOOP
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/errors/VaccinatedPersonNotFoundException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/errors/VaccinatedPersonNotFoundException.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8ad45faa3eef29ea9c59a0d59b97c21a140d0dfb
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/errors/VaccinatedPersonNotFoundException.kt
@@ -0,0 +1,10 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.errors
+
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationException
+
+class VaccinatedPersonNotFoundException(
+    message: String
+) : VaccinationException(
+    message = message,
+    cause = null
+)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/errors/VaccinationCertificateNotFoundException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/errors/VaccinationCertificateNotFoundException.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f67ab42fb802d1eaffc117a8f736131a5b8ed63f
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/errors/VaccinationCertificateNotFoundException.kt
@@ -0,0 +1,10 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.errors
+
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationException
+
+class VaccinationCertificateNotFoundException(
+    message: String
+) : VaccinationException(
+    message = message,
+    cause = null
+)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ContainerPostProcessor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/ContainerPostProcessor.kt
similarity index 77%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ContainerPostProcessor.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/ContainerPostProcessor.kt
index c4f2debb082773d1baefb0f9483151182d42e0b5..ce35f0c23ab1a56326830e7e2c8590046daa0561 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ContainerPostProcessor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/ContainerPostProcessor.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.core.repository.storage
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage
 
 import com.google.gson.Gson
 import com.google.gson.TypeAdapter
@@ -7,14 +7,14 @@ import com.google.gson.reflect.TypeToken
 import com.google.gson.stream.JsonReader
 import com.google.gson.stream.JsonWriter
 import dagger.Reusable
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeExtractor
 import timber.log.Timber
 import java.io.IOException
 import javax.inject.Inject
 
 @Reusable
 class ContainerPostProcessor @Inject constructor(
-    private val qrCodeExtractor: VaccinationQRCodeExtractor,
+    private val vaccinationQrCodeExtractor: VaccinationQRCodeExtractor,
 ) : TypeAdapterFactory {
     override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T> {
         val delegate = gson.getDelegateAdapter(this, type)
@@ -30,7 +30,7 @@ class ContainerPostProcessor @Inject constructor(
                 when (obj) {
                     is VaccinationContainer -> {
                         Timber.v("Injecting VaccinationContainer %s", obj.hashCode())
-                        obj.qrCodeExtractor = qrCodeExtractor
+                        obj.qrCodeExtractor = vaccinationQrCodeExtractor
                     }
                 }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinatedPersonData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinatedPersonData.kt
similarity index 52%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinatedPersonData.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinatedPersonData.kt
index 06978d4907f11613336a3c1e85929a4228fa8021..ab4663c66ad5b6c44b4a7287ace60be7986d9eb6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinatedPersonData.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinatedPersonData.kt
@@ -1,11 +1,11 @@
-package de.rki.coronawarnapp.vaccination.core.repository.storage
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage
 
 import com.google.gson.annotations.SerializedName
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
 
 data class VaccinatedPersonData(
     @SerializedName("vaccinationData") val vaccinations: Set<VaccinationContainer> = emptySet()
 ) {
-    val identifier: VaccinatedPersonIdentifier
+    val identifier: CertificatePersonIdentifier
         get() = vaccinations.first().personIdentifier
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt
similarity index 63%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt
index 9694f5f9d6875b21d3075f90a8dfd52068574962..61aa1c59989870f4ec1c28cb53496093cf72040b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt
@@ -1,18 +1,16 @@
-package de.rki.coronawarnapp.vaccination.core.repository.storage
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage
 
 import androidx.annotation.Keep
 import com.google.gson.annotations.SerializedName
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPersonIdentifier
-import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate
-import de.rki.coronawarnapp.vaccination.core.certificate.CoseCertificateHeader
-import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1
-import de.rki.coronawarnapp.vaccination.core.personIdentifier
-import de.rki.coronawarnapp.vaccination.core.qrcode.QrCodeString
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateQRCode
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractor
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet
-import de.rki.coronawarnapp.vaccination.core.server.valueset.getDisplayText
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccHeader
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationCertificate
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationCertificateQRCode
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.VaccinationValueSets
 import org.joda.time.Instant
 import org.joda.time.LocalDate
 import java.util.Locale
@@ -25,43 +23,47 @@ data class VaccinationContainer internal constructor(
 
     // Either set by [ContainerPostProcessor] or via [toVaccinationContainer]
     @Transient lateinit var qrCodeExtractor: VaccinationQRCodeExtractor
-    @Transient internal var preParsedData: VaccinationCertificateData? = null
+    @Transient internal var preParsedData: DccData<VaccinationDccV1>? = null
 
     // Otherwise GSON unsafes reflection to create this class, and sets the LAZY to null
     @Suppress("unused")
     constructor() : this("", Instant.EPOCH)
 
     @delegate:Transient
-    internal val certificateData: VaccinationCertificateData by lazy {
-        preParsedData ?: qrCodeExtractor.extract(vaccinationQrCode).parsedData
+    internal val certificateData: DccData<VaccinationDccV1> by lazy {
+        preParsedData ?: qrCodeExtractor.extract(vaccinationQrCode).data
     }
 
-    val header: CoseCertificateHeader
+    val header: DccHeader
         get() = certificateData.header
 
-    val certificate: VaccinationDGCV1
+    val certificate: VaccinationDccV1
         get() = certificateData.certificate
 
-    val vaccination: VaccinationDGCV1.VaccinationData
-        get() = certificate.vaccinationDatas.single()
+    val vaccination: VaccinationDccV1.VaccinationData
+        get() = certificate.payload
 
     val certificateId: String
         get() = vaccination.uniqueCertificateIdentifier
 
-    val personIdentifier: VaccinatedPersonIdentifier
+    val personIdentifier: CertificatePersonIdentifier
         get() = certificate.personIdentifier
 
     fun toVaccinationCertificate(
-        valueSet: VaccinationValueSet?,
+        valueSet: VaccinationValueSets?,
         userLocale: Locale = Locale.getDefault(),
     ) = object : VaccinationCertificate {
-        override val personIdentifier: VaccinatedPersonIdentifier
+        override val personIdentifier: CertificatePersonIdentifier
             get() = certificate.personIdentifier
 
         override val firstName: String?
-            get() = certificate.nameData.givenName
+            get() = certificate.nameData.firstName
+
         override val lastName: String
-            get() = certificate.nameData.familyName ?: certificate.nameData.familyNameStandardized
+            get() = certificate.nameData.lastName
+
+        override val fullName: String
+            get() = certificate.nameData.fullName
 
         override val dateOfBirth: LocalDate
             get() = certificate.dateOfBirth
@@ -87,7 +89,7 @@ data class VaccinationContainer internal constructor(
         override val certificateCountry: String
             get() = Locale(
                 userLocale.language,
-                vaccination.countryOfVaccination.uppercase()
+                vaccination.certificateCountry.uppercase()
             ).getDisplayCountry(userLocale)
 
         override val certificateId: String
@@ -100,7 +102,7 @@ data class VaccinationContainer internal constructor(
         override val expiresAt: Instant
             get() = header.expiresAt
 
-        override val vaccinationQrCodeString: QrCodeString
+        override val qrCode: QrCodeString
             get() = vaccinationQrCode
     }
 }
@@ -109,9 +111,9 @@ fun VaccinationCertificateQRCode.toVaccinationContainer(
     scannedAt: Instant,
     qrCodeExtractor: VaccinationQRCodeExtractor,
 ) = VaccinationContainer(
-    vaccinationQrCode = this.qrCodeString,
+    vaccinationQrCode = this.qrCode,
     scannedAt = scannedAt,
 ).apply {
     this.qrCodeExtractor = qrCodeExtractor
-    preParsedData = parsedData
+    preParsedData = data
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationStorage.kt
similarity index 96%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorage.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationStorage.kt
index 1424b943171378f04cc41ee44a398e0705afc95f..0b92bea2a9e707bedccb08b461d7794f6b36dc96 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorage.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationStorage.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.core.repository.storage
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage
 
 import android.content.Context
 import androidx.core.content.edit
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/VaccinationUIModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/VaccinationUIModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a912530513999c63b31b1dac6b1df6ef02fffa38
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/VaccinationUIModule.kt
@@ -0,0 +1,28 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui
+
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent.VaccinationConsentFragment
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent.VaccinationConsentFragmentModule
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.details.VaccinationDetailsFragment
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.details.VaccinationDetailsFragmentModule
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListFragment
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListFragmentModule
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.scan.VaccinationQrCodeScanFragment
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.scan.VaccinationQrCodeScanModule
+
+@Module
+abstract class VaccinationUIModule {
+
+    @ContributesAndroidInjector(modules = [VaccinationListFragmentModule::class])
+    abstract fun vaccinationListFragment(): VaccinationListFragment
+
+    @ContributesAndroidInjector(modules = [VaccinationDetailsFragmentModule::class])
+    abstract fun vaccinationDetailsFragment(): VaccinationDetailsFragment
+
+    @ContributesAndroidInjector(modules = [VaccinationQrCodeScanModule::class])
+    abstract fun vaccinationQrCodeScanFragment(): VaccinationQrCodeScanFragment
+
+    @ContributesAndroidInjector(modules = [VaccinationConsentFragmentModule::class])
+    abstract fun vaccinationConsentFragment(): VaccinationConsentFragment
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/CreateVaccinationCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/CreateVaccinationCard.kt
similarity index 85%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/CreateVaccinationCard.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/CreateVaccinationCard.kt
index 7332aa4cee7a388119ecc3240e96daddcc775caf..e45d550ef3b1dfa80d2adfb7197a9c3f6ed9dbc9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/CreateVaccinationCard.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/CreateVaccinationCard.kt
@@ -1,10 +1,10 @@
-package de.rki.coronawarnapp.vaccination.ui.cards
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards
 
 import android.view.ViewGroup
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.test.ui.CertificatesAdapter
+import de.rki.coronawarnapp.covidcertificate.test.ui.items.CertificatesItem
 import de.rki.coronawarnapp.databinding.VaccinationHomeRegistrationCardBinding
-import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesAdapter
-import de.rki.coronawarnapp.greencertificate.ui.certificates.items.CertificatesItem
 import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer
 
 class CreateVaccinationCard(parent: ViewGroup) :
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/HeaderInfoVaccinationCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/HeaderInfoVaccinationCard.kt
similarity index 78%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/HeaderInfoVaccinationCard.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/HeaderInfoVaccinationCard.kt
index e62941fc9bfffa16aae2b11fa60b9c93682d8ffb..a2026dfa69f6b8ee8061f7a914e5e1b113876b57 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/HeaderInfoVaccinationCard.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/HeaderInfoVaccinationCard.kt
@@ -1,10 +1,10 @@
-package de.rki.coronawarnapp.vaccination.ui.cards
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards
 
 import android.view.ViewGroup
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.test.ui.CertificatesAdapter
+import de.rki.coronawarnapp.covidcertificate.test.ui.items.CertificatesItem
 import de.rki.coronawarnapp.databinding.VaccinationHeaderInfoCardBinding
-import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesAdapter
-import de.rki.coronawarnapp.greencertificate.ui.certificates.items.CertificatesItem
 
 class HeaderInfoVaccinationCard(parent: ViewGroup) :
     CertificatesAdapter.CertificatesItemVH<HeaderInfoVaccinationCard.Item, VaccinationHeaderInfoCardBinding>(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/ImmuneVaccinationCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/ImmuneVaccinationCard.kt
similarity index 70%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/ImmuneVaccinationCard.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/ImmuneVaccinationCard.kt
index f3bf89f9cefc467bd0020754fd60bc79de4e5a3a..09e83c5d9e14fc1f2d056528405f6dbbdcca238c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/ImmuneVaccinationCard.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/ImmuneVaccinationCard.kt
@@ -1,11 +1,12 @@
-package de.rki.coronawarnapp.vaccination.ui.cards
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards
 
 import android.view.ViewGroup
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.test.ui.CertificatesAdapter
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
 import de.rki.coronawarnapp.databinding.VaccinationHomeImmuneCardBinding
-import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesAdapter
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.toDayFormat
 import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
 
 class ImmuneVaccinationCard(parent: ViewGroup) :
     CertificatesAdapter.CertificatesItemVH<ImmuneVaccinationCard.Item, VaccinationHomeImmuneCardBinding>(
@@ -24,6 +25,10 @@ class ImmuneVaccinationCard(parent: ViewGroup) :
         val curItem = payloads.filterIsInstance<Item>().singleOrNull() ?: item
 
         personName.text = curItem.vaccinatedPerson.fullName
+        vaccinationState.text = context.getString(
+            R.string.vaccination_card_status_vaccination_complete,
+            curItem.vaccinatedPerson.getMostRecentVaccinationCertificate.expiresAt.toDayFormat()
+        )
 
         itemView.setOnClickListener { curItem.onClickAction(item) }
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/BottomInfoVaccinationCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/NoCovidTestCertificatesCard.kt
similarity index 62%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/BottomInfoVaccinationCard.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/NoCovidTestCertificatesCard.kt
index c2b5fe49130b2786d5c822e86d5aa31cec82c30e..dae5c0dba1c885464b7000b4135013f5a65b8f91 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/BottomInfoVaccinationCard.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/NoCovidTestCertificatesCard.kt
@@ -1,13 +1,13 @@
-package de.rki.coronawarnapp.vaccination.ui.cards
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards
 
 import android.view.ViewGroup
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.test.ui.CertificatesAdapter
+import de.rki.coronawarnapp.covidcertificate.test.ui.items.CertificatesItem
 import de.rki.coronawarnapp.databinding.VaccinationBottomInfoCardBinding
-import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesAdapter
-import de.rki.coronawarnapp.greencertificate.ui.certificates.items.CertificatesItem
 
-class BottomInfoVaccinationCard(parent: ViewGroup) :
-    CertificatesAdapter.CertificatesItemVH<BottomInfoVaccinationCard.Item, VaccinationBottomInfoCardBinding>(
+class NoCovidTestCertificatesCard(parent: ViewGroup) :
+    CertificatesAdapter.CertificatesItemVH<NoCovidTestCertificatesCard.Item, VaccinationBottomInfoCardBinding>(
         R.layout.dashed_line_container_layout,
         parent
     ) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/VaccinationCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/VaccinationCard.kt
similarity index 83%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/VaccinationCard.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/VaccinationCard.kt
index 7377a6d5d25227896da653c6b120604208792889..911ca7e1e45c52100006acaf2b1cdb2a86418dc5 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/VaccinationCard.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/VaccinationCard.kt
@@ -1,11 +1,11 @@
-package de.rki.coronawarnapp.vaccination.ui.cards
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards
 
 import android.view.ViewGroup
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.test.ui.CertificatesAdapter
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
 import de.rki.coronawarnapp.databinding.VaccinationHomeCardBinding
-import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesAdapter
 import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
 
 class VaccinationCard(parent: ViewGroup) :
     CertificatesAdapter.CertificatesItemVH<VaccinationCard.Item, VaccinationHomeCardBinding>(
@@ -32,11 +32,9 @@ class VaccinationCard(parent: ViewGroup) :
                     days,
                     days
                 )
-                icon.setImageResource(R.drawable.vaccination_card_icon_complete)
             }
             else -> {
                 vaccinationState.setText(R.string.vaccination_card_status_vaccination_incomplete)
-                icon.setImageResource(R.drawable.vaccination_card_icon_incomplete)
             }
         }
         itemView.setOnClickListener { curItem.onClickAction(item) }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/VaccinationStatusItem.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/VaccinationStatusItem.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0216d7eea4c3df9009ba8aaf52cd76a67c349c07
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/cards/VaccinationStatusItem.kt
@@ -0,0 +1,11 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards
+
+import de.rki.coronawarnapp.covidcertificate.test.ui.items.CertificatesItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+
+interface VaccinationStatusItem : CertificatesItem {
+    val vaccinatedPerson: VaccinatedPerson
+
+    override val stableId: Long
+        get() = vaccinatedPerson.identifier.hashCode().toLong()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentFragment.kt
similarity index 97%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentFragment.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentFragment.kt
index b19db038c8926c515f017f2cdff8a8e6436bbd55..49e64766849f48005f1f3d71582d288d475f8c82 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentFragment.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.consent
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent
 
 import android.os.Bundle
 import android.view.View
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentFragmentModule.kt
similarity index 88%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentFragmentModule.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentFragmentModule.kt
index cfb33134fdcaaa9b47f312769c2fb5055fa66e14..e2a7be9f3813590c08dd498e7c8c2c1206a55860 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentFragmentModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentFragmentModule.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.consent
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent
 
 import dagger.Binds
 import dagger.Module
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentNavigationEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentNavigationEvent.kt
similarity index 73%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentNavigationEvent.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentNavigationEvent.kt
index 865937c0df0906298bf6d610cf6c658645ca0094..52a1b33fb0c2d747fd9992d5ead645064a7b568c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentNavigationEvent.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentNavigationEvent.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.consent
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent
 
 sealed class VaccinationConsentNavigationEvent {
     object NavigateToDataPrivacy : VaccinationConsentNavigationEvent()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentViewModel.kt
similarity index 87%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentViewModel.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentViewModel.kt
index 28327dfb7eacbd5c5aa09b3d2c419802570051b6..0c2c4bafd184936a2b7e9466c9919fa4c713e385 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/consent/VaccinationConsentViewModel.kt
@@ -1,12 +1,12 @@
-package de.rki.coronawarnapp.vaccination.ui.consent
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent
 
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationSettings
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import de.rki.coronawarnapp.vaccination.core.VaccinationSettings
 
 class VaccinationConsentViewModel @AssistedInject constructor(
     private val vaccinationSettings: VaccinationSettings,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsFragment.kt
similarity index 96%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragment.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsFragment.kt
index b76fd07b7e133d4deb7e7114b2f1e08eae9ecafc..8ea0ed355e85b3fd4167a9cacc2add4d19036a6b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsFragment.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.details
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.details
 
 import android.os.Bundle
 import android.view.View
@@ -11,6 +11,7 @@ import androidx.navigation.fragment.navArgs
 import com.google.android.material.appbar.AppBarLayout
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.bugreporting.ui.toErrorDialogBuilder
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationCertificate
 import de.rki.coronawarnapp.databinding.FragmentVaccinationDetailsBinding
 import de.rki.coronawarnapp.ui.qrcode.fullscreen.QrCodeFullScreenFragmentArgs
 import de.rki.coronawarnapp.ui.view.onOffsetChange
@@ -20,7 +21,6 @@ import de.rki.coronawarnapp.util.ui.popBackStack
 import de.rki.coronawarnapp.util.ui.viewBinding
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted
-import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate
 import org.joda.time.format.DateTimeFormat
 import javax.inject.Inject
 
@@ -87,7 +87,7 @@ class VaccinationDetailsFragment : Fragment(R.layout.fragment_vaccination_detail
     private fun FragmentVaccinationDetailsBinding.bindCertificateViews(
         certificate: VaccinationCertificate
     ) {
-        name.text = certificate.run { "$firstName $lastName" }
+        name.text = certificate.fullName
         birthDate.text = getString(
             R.string.vaccination_details_birth_date,
             certificate.dateOfBirth.toDayFormat()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsFragmentModule.kt
similarity index 88%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragmentModule.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsFragmentModule.kt
index 62e9906d2577086ae40ee382f6e66fede9fa27f4..f4d86d341dbcca83744f16a35722e99910893fcb 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragmentModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsFragmentModule.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.details
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.details
 
 import dagger.Binds
 import dagger.Module
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsNavigation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsNavigation.kt
similarity index 72%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsNavigation.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsNavigation.kt
index d1151ff28fdef732ead8dc049bedc638f3f2d871..45d2d1754f6f2c43e364b0f3fabd4807b4857c41 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsNavigation.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsNavigation.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.details
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.details
 
 sealed class VaccinationDetailsNavigation {
     object Back : VaccinationDetailsNavigation()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsViewModel.kt
similarity index 87%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsViewModel.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsViewModel.kt
index 3a1181d329277738c9fe8c4abe76c30403ca9724..9cb494dd22f82ea6a76c3595dc0d393a2e0d289b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsViewModel.kt
@@ -1,18 +1,18 @@
-package de.rki.coronawarnapp.vaccination.ui.details
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.details
 
 import android.graphics.Bitmap
 import androidx.lifecycle.asLiveData
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationCertificate
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
 import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
-import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.map
 import timber.log.Timber
@@ -60,8 +60,8 @@ class VaccinationDetailsViewModel @AssistedInject constructor(
     private fun generateQrCode(certificate: VaccinationCertificate?) = launch {
         try {
             mutableStateFlow.value = certificate?.let {
-                qrCodeText = it.vaccinationQrCodeString
-                qrCodeGenerator.createQrCode(it.vaccinationQrCodeString)
+                qrCodeText = it.qrCode
+                qrCodeGenerator.createQrCode(it.qrCode)
             }
         } catch (e: Exception) {
             Timber.d(e, "generateQrCode failed for vaccinationCertificate=%s", certificate)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListFragment.kt
similarity index 90%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListFragment.kt
index 9c3768891b87a83378c714760d5f9f1949dc9b9f..b129fd94038631bb80221271c1a3a1d1e2b6fe5c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListFragment.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.list
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.list
 
 import android.os.Bundle
 import android.view.View
@@ -14,6 +14,12 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.android.material.imageview.ShapeableImageView
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.bugreporting.ui.toErrorDialogBuilder
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListViewModel.Event.DeleteVaccinationEvent
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListViewModel.Event.NavigateBack
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListViewModel.Event.NavigateToVaccinationCertificateDetails
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListViewModel.Event.NavigateToVaccinationQrCodeScanScreen
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListAdapter
 import de.rki.coronawarnapp.databinding.FragmentVaccinationListBinding
 import de.rki.coronawarnapp.ui.qrcode.fullscreen.QrCodeFullScreenFragmentArgs
 import de.rki.coronawarnapp.ui.view.onOffsetChange
@@ -25,12 +31,6 @@ import de.rki.coronawarnapp.util.ui.popBackStack
 import de.rki.coronawarnapp.util.ui.viewBinding
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
-import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListViewModel.Event.DeleteVaccinationEvent
-import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListViewModel.Event.NavigateBack
-import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListViewModel.Event.NavigateToVaccinationCertificateDetails
-import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListViewModel.Event.NavigateToVaccinationQrCodeScanScreen
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter
 import javax.inject.Inject
 
 class VaccinationListFragment : Fragment(R.layout.fragment_vaccination_list), AutoInject {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListFragmentModule.kt
similarity index 88%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentModule.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListFragmentModule.kt
index 86c2cb094926468e4163fcdc2c637f1d04ac2ca6..bcffd957ae6b59439f17b73c75ee09eb75386cb7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListFragmentModule.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.list
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.list
 
 import dagger.Binds
 import dagger.Module
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListViewModel.kt
similarity index 87%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListViewModel.kt
index a4e200153ccea27b40c5e3422cd31964e594ff8f..9dea2c3500fe560abdba6ef75945cd14967b6087 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListViewModel.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.list
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.list
 
 import android.content.Context
 import android.graphics.Bitmap
@@ -8,6 +8,14 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.contactdiary.util.getLocale
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem
+import de.rki.coronawarnapp.covidcertificate.valueset.ValueSetsRepository
 import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.toDayFormat
 import de.rki.coronawarnapp.util.coroutine.AppScope
@@ -15,14 +23,6 @@ import de.rki.coronawarnapp.util.di.AppContext
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
-import de.rki.coronawarnapp.vaccination.core.repository.ValueSetsRepository
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.catch
@@ -56,7 +56,7 @@ class VaccinationListViewModel @AssistedInject constructor(
         // immediately ...
         emit(null)
         // ... and after the QR code was generated, it is emitted
-        emit(qrCodeGenerator.createQrCode(it.getMostRecentVaccinationCertificate.vaccinationQrCodeString))
+        emit(qrCodeGenerator.createQrCode(it.getMostRecentVaccinationCertificate.qrCode))
     }
 
     val uiState: LiveData<UiState> = combine(vaccinatedPersonFlow, vaccinationQrCodeFlow) { vaccinatedPerson, qrCode ->
@@ -92,7 +92,7 @@ class VaccinationListViewModel @AssistedInject constructor(
                     onQrCodeClick = {
                         events.postValue(
                             Event.NavigateToQrCodeFullScreen(
-                                qrCode = vaccinatedPerson.getMostRecentVaccinationCertificate.vaccinationQrCodeString,
+                                qrCode = vaccinatedPerson.getMostRecentVaccinationCertificate.qrCode,
                                 positionInList = 0
                             )
                         )
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/VaccinationListAdapter.kt
similarity index 63%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/VaccinationListAdapter.kt
index 0bca114ae463ddd046ecd17410c90d4a6a11d794..3fa17a05ab738cfa642fb761ba0c36a475aa1c1e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/VaccinationListAdapter.kt
@@ -1,8 +1,16 @@
-package de.rki.coronawarnapp.vaccination.ui.list.adapter
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter
 
 import android.view.ViewGroup
 import androidx.annotation.LayoutRes
 import androidx.viewbinding.ViewBinding
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem
 import de.rki.coronawarnapp.util.lists.BindableVH
 import de.rki.coronawarnapp.util.lists.HasStableId
 import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffUtilAdapter
@@ -11,14 +19,6 @@ import de.rki.coronawarnapp.util.lists.modular.ModularAdapter
 import de.rki.coronawarnapp.util.lists.modular.mods.DataBinderMod
 import de.rki.coronawarnapp.util.lists.modular.mods.StableIdMod
 import de.rki.coronawarnapp.util.lists.modular.mods.TypedVHCreatorMod
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem
 
 class VaccinationListAdapter :
     ModularAdapter<VaccinationListAdapter.ItemVH<VaccinationListItem, ViewBinding>>(),
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListImmunityInformationCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListImmunityInformationCardItemVH.kt
similarity index 74%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListImmunityInformationCardItemVH.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListImmunityInformationCardItemVH.kt
index f6824b79b04a1ca22d84eb29a73a7871ff0bc2d0..8f30d3940133de55144206c9b31e1f9d9a4ae4ac 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListImmunityInformationCardItemVH.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListImmunityInformationCardItemVH.kt
@@ -1,11 +1,11 @@
-package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder
 
 import android.view.ViewGroup
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListAdapter
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem
 import de.rki.coronawarnapp.databinding.VaccinationListImmunityCardBinding
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem
 import org.joda.time.Duration
 
 class VaccinationListImmunityInformationCardItemVH(parent: ViewGroup) :
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListNameCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListNameCardItemVH.kt
similarity index 71%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListNameCardItemVH.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListNameCardItemVH.kt
index 5cd1501ca2a27854aeedeb23575a690a5938ec3e..f073acb5408a1946401aadb4b707c8c128d807a3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListNameCardItemVH.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListNameCardItemVH.kt
@@ -1,11 +1,11 @@
-package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder
 
 import android.view.ViewGroup
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListAdapter
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem
 import de.rki.coronawarnapp.databinding.VaccinationListNameCardBinding
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem
 
 class VaccinationListNameCardItemVH(parent: ViewGroup) :
     VaccinationListAdapter.ItemVH<VaccinationListNameCardItem, VaccinationListNameCardBinding>(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListQrCodeCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListQrCodeCardItemVH.kt
similarity index 81%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListQrCodeCardItemVH.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListQrCodeCardItemVH.kt
index 3c84ae55250f6e9d91255b4326ba5365fc3892ca..11c936aab9ae69672c0a68055770002b906d12a4 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListQrCodeCardItemVH.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListQrCodeCardItemVH.kt
@@ -1,13 +1,13 @@
-package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder
 
 import android.graphics.Bitmap
 import android.view.ViewGroup
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListAdapter
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem
 import de.rki.coronawarnapp.databinding.IncludeCertificateQrcodeCardBinding
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortDayFormat
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem
 import org.joda.time.Instant
 import org.joda.time.LocalDate
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt
similarity index 86%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt
index 82f2a8388585b70ba8f570710b5728f9f1f91889..5c254efe417d573d3618d90ce26e8ccd91d16d38 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt
@@ -1,19 +1,19 @@
-package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder
 
 import android.view.Gravity
 import android.view.ViewGroup
 import androidx.appcompat.widget.PopupMenu
 import androidx.recyclerview.widget.RecyclerView
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson.Status.COMPLETE
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson.Status.IMMUNITY
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson.Status.INCOMPLETE
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListAdapter
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.VaccinationListItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem
 import de.rki.coronawarnapp.databinding.VaccinationListVaccinationCardBinding
 import de.rki.coronawarnapp.util.list.Swipeable
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.COMPLETE
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.IMMUNITY
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.INCOMPLETE
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem
-import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem
 import java.util.Objects
 
 class VaccinationListVaccinationCardItemVH(parent: ViewGroup) :
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt
similarity index 98%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt
index 48a09d1257473491fbe4bd5167242d3af602a449..ffb9537416eda49f1d4d29d61afed701da3542a7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.scan
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.scan
 
 import android.Manifest
 import android.content.pm.PackageManager
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanModule.kt
similarity index 89%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanModule.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanModule.kt
index aa5cd02dfd000d4e78466d6a5e9d5fd85f072ea7..bc581306a761d7bdfd9e46489b4ca2f98e401dc8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanModule.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.ui.scan
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.scan
 
 import dagger.Binds
 import dagger.Module
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanViewModel.kt
similarity index 86%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanViewModel.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanViewModel.kt
index 5f8695e78f98984d521d1009476ec8bb96a6bc21..adbddadf7608994aa37288d4413cd22436cbcb95 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanViewModel.kt
@@ -1,14 +1,14 @@
-package de.rki.coronawarnapp.vaccination.ui.scan
+package de.rki.coronawarnapp.covidcertificate.vaccination.ui.scan
 
 import com.journeyapps.barcodescanner.BarcodeResult
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeValidator
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
 import de.rki.coronawarnapp.util.permission.CameraSettings
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeValidator
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
 import timber.log.Timber
 
 class VaccinationQrCodeScanViewModel @AssistedInject constructor(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/CertificateValueSetModule.kt
similarity index 82%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetModule.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/CertificateValueSetModule.kt
index 2b3413d14169f086392e7ab3df76a867f2acb57a..dd3100e22d9a3ead782e003f58422054f80c39b1 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/CertificateValueSetModule.kt
@@ -1,9 +1,11 @@
-package de.rki.coronawarnapp.vaccination.core.server.valueset
+package de.rki.coronawarnapp.covidcertificate.valueset
 
 import android.content.Context
 import dagger.Module
 import dagger.Provides
 import dagger.Reusable
+import de.rki.coronawarnapp.covidcertificate.valueset.server.CertificateValueSet
+import de.rki.coronawarnapp.covidcertificate.valueset.server.CertificateValueSetApiV1
 import de.rki.coronawarnapp.environment.download.DownloadCDNHttpClient
 import de.rki.coronawarnapp.environment.download.DownloadCDNServerUrl
 import de.rki.coronawarnapp.util.di.AppContext
@@ -17,10 +19,10 @@ import java.io.File
 import java.util.concurrent.TimeUnit
 
 @Module
-class VaccinationValueSetModule {
+class CertificateValueSetModule {
 
     @Reusable
-    @ValueSet
+    @CertificateValueSet
     @Provides
     fun cache(
         @AppContext context: Context
@@ -35,8 +37,8 @@ class VaccinationValueSetModule {
     fun api(
         @DownloadCDNHttpClient httpClient: OkHttpClient,
         @DownloadCDNServerUrl url: String,
-        @ValueSet cache: Cache
-    ): VaccinationValueSetApiV1 {
+        @CertificateValueSet cache: Cache
+    ): CertificateValueSetApiV1 {
         val client = httpClient.newBuilder()
             .addNetworkInterceptor(CacheInterceptor())
             .cache(cache)
@@ -46,7 +48,7 @@ class VaccinationValueSetModule {
             .client(client)
             .baseUrl(url)
             .build()
-            .create(VaccinationValueSetApiV1::class.java)
+            .create(CertificateValueSetApiV1::class.java)
     }
 
     private class CacheInterceptor : Interceptor {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/ValueSetsRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/ValueSetsRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..eae1302048eae9d8c9cf8c89af6dbb08873e8425
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/ValueSetsRepository.kt
@@ -0,0 +1,93 @@
+package de.rki.coronawarnapp.covidcertificate.valueset
+
+import dagger.Reusable
+import de.rki.coronawarnapp.covidcertificate.valueset.server.CertificateValueSetServer
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.TestCertificateValueSets
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.VaccinationValueSets
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.ValueSetsContainer
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.ValueSetsStorage
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.emptyValueSetsContainer
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.isEmpty
+import de.rki.coronawarnapp.util.coroutine.AppScope
+import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
+import de.rki.coronawarnapp.util.flow.HotDataFlow
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.plus
+import timber.log.Timber
+import java.util.Locale
+import javax.inject.Inject
+
+@Reusable
+class ValueSetsRepository @Inject constructor(
+    private val certificateValueSetServer: CertificateValueSetServer,
+    private val valueSetsStorage: ValueSetsStorage,
+    @AppScope private val scope: CoroutineScope,
+    dispatcherProvider: DispatcherProvider
+) {
+
+    private val internalData: HotDataFlow<ValueSetsContainer> = HotDataFlow(
+        loggingTag = TAG,
+        scope = scope,
+        coroutineContext = dispatcherProvider.IO,
+        sharingBehavior = SharingStarted.Lazily,
+        startValueProvider = {
+            valueSetsStorage.valueSetsContainer.also { Timber.v("Loaded initial value sets %s", it) }
+        }
+    )
+
+    init {
+        internalData.data
+            .onStart { Timber.d("Observing value set") }
+            .onEach { valueSetsStorage.valueSetsContainer = it }
+            .catch { Timber.e(it, "Storing new value sets failed.") }
+            .launchIn(scope + dispatcherProvider.IO)
+    }
+
+    val latestVaccinationValueSets: Flow<VaccinationValueSets> = internalData.data
+        .map { it.vaccinationValueSets }
+
+    val latestTestCertificateValueSets: Flow<TestCertificateValueSets> = internalData.data
+        .map { it.testCertificateValueSets }
+
+    fun triggerUpdateValueSet(languageCode: Locale) {
+        Timber.d("triggerUpdateValueSet(languageCode=%s)", languageCode)
+        internalData.updateAsync(
+            onUpdate = { getValueSetFromServer(languageCode = languageCode) ?: this },
+            onError = { Timber.e(it, "Updating value sets failed") }
+        )
+    }
+
+    private suspend fun getValueSetFromServer(languageCode: Locale): ValueSetsContainer? {
+        Timber.v("getValueSetFromServer(languageCode=%s)", languageCode)
+        var container = certificateValueSetServer.getVaccinationValueSets(languageCode = languageCode)
+
+        if (container.isEmpty()) {
+            Timber.d(
+                "Got no value sets from server for %s... Try fallback to value sets for en",
+                languageCode.language
+            )
+            container = certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.ENGLISH)
+        }
+
+        return container
+            .also { Timber.v("New value sets %s", it) }
+    }
+
+    suspend fun clear() {
+        Timber.d("Clearing value sets")
+        certificateValueSetServer.clear()
+        internalData.updateBlocking {
+            Timber.v("Resetting value sets")
+            emptyValueSetsContainer
+        }
+    }
+}
+
+private const val TAG = "ValueSetsRepository"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/internal/DccValueSetMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/internal/DccValueSetMapper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5833e17c1b96a8058775827efdd36a49b8789a9c
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/internal/DccValueSetMapper.kt
@@ -0,0 +1,44 @@
+package de.rki.coronawarnapp.covidcertificate.valueset.internal
+
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.DefaultValueSet
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.TestCertificateValueSets
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.VaccinationValueSets
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.ValueSetsContainer
+import de.rki.coronawarnapp.server.protocols.internal.dgc.ValueSetsOuterClass
+import timber.log.Timber
+import java.util.Locale
+
+internal fun ValueSetsOuterClass.ValueSets.toValueSetsContainer(languageCode: Locale): ValueSetsContainer {
+    Timber.d("toValueSetsContainer(valueSets=%s, languageCode=%s)", this, languageCode)
+    return ValueSetsContainer(
+        vaccinationValueSets = toVaccinationValueSets(languageCode = languageCode),
+        testCertificateValueSets = toTestCertificateValueSets(languageCode = languageCode)
+    ).also { Timber.tag(TAG).d("Created %s", it) }
+}
+
+internal fun ValueSetsOuterClass.ValueSets.toVaccinationValueSets(languageCode: Locale): VaccinationValueSets =
+    VaccinationValueSets(
+        languageCode = languageCode,
+        tg = tg.toValueSet(),
+        vp = vp.toValueSet(),
+        mp = mp.toValueSet(),
+        ma = ma.toValueSet()
+    )
+
+internal fun ValueSetsOuterClass.ValueSets.toTestCertificateValueSets(languageCode: Locale): TestCertificateValueSets =
+    TestCertificateValueSets(
+        languageCode = languageCode,
+        tg = tg.toValueSet(),
+        tt = tcTt.toValueSet(),
+        ma = tcMa.toValueSet(),
+        tr = tcTr.toValueSet()
+    )
+
+internal fun ValueSetsOuterClass.ValueSet.toValueSet() = DefaultValueSet(items = itemsList.map { it.toItem() })
+
+internal fun ValueSetsOuterClass.ValueSetItem.toItem() = DefaultValueSet.DefaultItem(
+    key = key,
+    displayText = displayText
+)
+
+private const val TAG: String = "ValueSetMapper"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/ValueSetInvalidSignatureException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/internal/ValueSetInvalidSignatureException.kt
similarity index 80%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/ValueSetInvalidSignatureException.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/internal/ValueSetInvalidSignatureException.kt
index 6de24adafb228da191c3f7d076ef1729b8ad3540..5a218d35a9c556aa1fba85f6d4115007e221ae00 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/ValueSetInvalidSignatureException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/internal/ValueSetInvalidSignatureException.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.core.server.valueset.internal
+package de.rki.coronawarnapp.covidcertificate.valueset.internal
 
 import de.rki.coronawarnapp.exception.reporting.ErrorCodes
 import de.rki.coronawarnapp.util.security.InvalidSignatureException
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSet.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSet.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9721ba413f8e50ef7c5bead14159a54a04d2220d
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSet.kt
@@ -0,0 +1,8 @@
+package de.rki.coronawarnapp.covidcertificate.valueset.server
+
+import javax.inject.Qualifier
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class CertificateValueSet
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetApiV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSetApiV1.kt
similarity index 71%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetApiV1.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSetApiV1.kt
index d30f63ada3e13187b20aa2952192c35b9ea9df20..b7f560ac677316edd296e62eb4db83e18e9808c6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetApiV1.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSetApiV1.kt
@@ -1,11 +1,11 @@
-package de.rki.coronawarnapp.vaccination.core.server.valueset
+package de.rki.coronawarnapp.covidcertificate.valueset.server
 
 import okhttp3.ResponseBody
 import retrofit2.Response
 import retrofit2.http.GET
 import retrofit2.http.Path
 
-interface VaccinationValueSetApiV1 {
+interface CertificateValueSetApiV1 {
 
     @GET("/version/v1/ehn-dgc/{lang}/value-sets")
     suspend fun getValueSets(@Path("lang") languageCode: String): Response<ResponseBody>
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSetServer.kt
similarity index 83%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServer.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSetServer.kt
index 5e064692b159c9123f431138dbbc4520a33228f3..8d88f880b6b5b53e205cfd43f35a442ab595b0cb 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServer.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSetServer.kt
@@ -1,15 +1,16 @@
-package de.rki.coronawarnapp.vaccination.core.server.valueset
+package de.rki.coronawarnapp.covidcertificate.valueset.server
 
 import androidx.annotation.VisibleForTesting
 import dagger.Lazy
 import dagger.Reusable
+import de.rki.coronawarnapp.covidcertificate.valueset.internal.ValueSetInvalidSignatureException
+import de.rki.coronawarnapp.covidcertificate.valueset.internal.toValueSetsContainer
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.ValueSetsContainer
 import de.rki.coronawarnapp.server.protocols.internal.dgc.ValueSetsOuterClass
 import de.rki.coronawarnapp.util.ZipHelper.readIntoMap
 import de.rki.coronawarnapp.util.ZipHelper.unzip
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.security.SignatureValidation
-import de.rki.coronawarnapp.vaccination.core.server.valueset.internal.ValueSetInvalidSignatureException
-import de.rki.coronawarnapp.vaccination.core.server.valueset.internal.toVaccinationValueSet
 import kotlinx.coroutines.withContext
 import okhttp3.Cache
 import okhttp3.ResponseBody
@@ -24,14 +25,14 @@ import javax.inject.Inject
  * Talks with CWA servers
  */
 @Reusable
-class VaccinationServer @Inject constructor(
-    @ValueSet private val cache: Cache,
-    private val apiV1: Lazy<VaccinationValueSetApiV1>,
+class CertificateValueSetServer @Inject constructor(
+    @CertificateValueSet private val cache: Cache,
+    private val apiV1: Lazy<CertificateValueSetApiV1>,
     private val dispatcherProvider: DispatcherProvider,
     private val signatureValidation: SignatureValidation
 ) {
 
-    suspend fun getVaccinationValueSets(languageCode: Locale): VaccinationValueSet? =
+    suspend fun getVaccinationValueSets(languageCode: Locale): ValueSetsContainer? =
         withContext(dispatcherProvider.Default) {
             return@withContext try {
                 val response = requestValueSets(languageCode.language)
@@ -39,7 +40,7 @@ class VaccinationServer @Inject constructor(
 
                 val body = requireNotNull(response.body()) { "Body of response was null" }
                 val valueSetsProtobuf = body.parseBody()
-                valueSetsProtobuf.toVaccinationValueSet(languageCode = languageCode)
+                valueSetsProtobuf.toValueSetsContainer(languageCode = languageCode)
             } catch (e: Exception) {
                 Timber.e(e, "Getting vaccination value sets from server failed cause: ${e.message}")
                 null
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/DefaultValueSet.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/DefaultValueSet.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bf8d268cdc339982862689ee482b7375d6cfe624
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/DefaultValueSet.kt
@@ -0,0 +1,15 @@
+package de.rki.coronawarnapp.covidcertificate.valueset.valuesets
+
+import androidx.annotation.Keep
+import com.google.gson.annotations.SerializedName
+
+@Keep
+data class DefaultValueSet(
+    @SerializedName("items") override val items: List<DefaultItem> = emptyList()
+) : ValueSets.ValueSet {
+    @Keep
+    data class DefaultItem(
+        @SerializedName("key") override val key: String,
+        @SerializedName("displayText") override val displayText: String
+    ) : ValueSets.ValueSet.Item
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/TestCertificateValueSets.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/TestCertificateValueSets.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c412d2656ab71d99f10788fac12cc54404f665ae
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/TestCertificateValueSets.kt
@@ -0,0 +1,31 @@
+package de.rki.coronawarnapp.covidcertificate.valueset.valuesets
+
+import androidx.annotation.Keep
+import com.google.gson.annotations.SerializedName
+import java.util.Locale
+
+@Keep
+data class TestCertificateValueSets(
+    @SerializedName("languageCode") override val languageCode: Locale,
+    @SerializedName("tg") override val tg: DefaultValueSet,
+    @SerializedName("tt") val tt: DefaultValueSet, // Type of Test
+    @SerializedName("ma") val ma: DefaultValueSet, // RAT Test name and manufacturer
+    @SerializedName("tr") val tr: DefaultValueSet, // Test Result
+) : ValueSets {
+
+    override val isEmpty: Boolean
+        get() = tg.items.isEmpty() && tt.items.isEmpty() && ma.items.isEmpty() && tr.items.isEmpty()
+
+    override fun getDisplayText(key: String): String? =
+        tg.getDisplayText(key) ?: tt.getDisplayText(key) ?: ma.getDisplayText(key) ?: tr.getDisplayText(key)
+}
+
+val emptyTestCertificateValueSets: TestCertificateValueSets by lazy {
+    TestCertificateValueSets(
+        languageCode = Locale.ENGLISH,
+        tg = DefaultValueSet(),
+        tt = DefaultValueSet(),
+        ma = DefaultValueSet(),
+        tr = DefaultValueSet()
+    )
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/VaccinationValueSets.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/VaccinationValueSets.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c15738bfce2e3881e0afa81052e7ff2aa59cc333
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/VaccinationValueSets.kt
@@ -0,0 +1,31 @@
+package de.rki.coronawarnapp.covidcertificate.valueset.valuesets
+
+import androidx.annotation.Keep
+import com.google.gson.annotations.SerializedName
+import java.util.Locale
+
+@Keep
+data class VaccinationValueSets(
+    @SerializedName("languageCode") override val languageCode: Locale,
+    @SerializedName("tg") override val tg: DefaultValueSet,
+    @SerializedName("vp") val vp: DefaultValueSet, // Vaccine or prophylaxis
+    @SerializedName("mp") val mp: DefaultValueSet, // Vaccine medicinal product
+    @SerializedName("ma") val ma: DefaultValueSet, // Marketing Authorization Holder
+) : ValueSets {
+
+    override val isEmpty: Boolean
+        get() = tg.items.isEmpty() && vp.items.isEmpty() && mp.items.isEmpty() && ma.items.isEmpty()
+
+    override fun getDisplayText(key: String): String? =
+        tg.getDisplayText(key) ?: vp.getDisplayText(key) ?: mp.getDisplayText(key) ?: ma.getDisplayText(key)
+}
+
+val emptyVaccinationValueSets: VaccinationValueSets by lazy {
+    VaccinationValueSets(
+        languageCode = Locale.ENGLISH,
+        tg = DefaultValueSet(),
+        vp = DefaultValueSet(),
+        mp = DefaultValueSet(),
+        ma = DefaultValueSet()
+    )
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/ValueSets.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/ValueSets.kt
new file mode 100644
index 0000000000000000000000000000000000000000..80a7321bcc2fdf9af227ad873358e287be513e20
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/ValueSets.kt
@@ -0,0 +1,27 @@
+package de.rki.coronawarnapp.covidcertificate.valueset.valuesets
+
+import java.util.Locale
+
+interface ValueSets {
+
+    val languageCode: Locale
+
+    // Disease or agent targeted
+    val tg: ValueSet
+
+    val isEmpty: Boolean
+
+    fun getDisplayText(key: String): String?
+
+    interface ValueSet {
+        val items: List<Item>
+
+        // Use custom item instead of map to allow for future extensions
+        interface Item {
+            val key: String
+            val displayText: String
+        }
+    }
+}
+
+fun ValueSets.ValueSet.getDisplayText(key: String): String? = items.find { key == it.key }?.displayText
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/ValueSetsContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/ValueSetsContainer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d1af578833b007c0a41254fb8e07f05676bff20a
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/ValueSetsContainer.kt
@@ -0,0 +1,20 @@
+package de.rki.coronawarnapp.covidcertificate.valueset.valuesets
+
+import androidx.annotation.Keep
+import com.google.gson.annotations.SerializedName
+
+@Keep
+data class ValueSetsContainer(
+    @SerializedName("vaccinationValueSets") val vaccinationValueSets: VaccinationValueSets,
+    @SerializedName("testCertificateValueSets") val testCertificateValueSets: TestCertificateValueSets
+)
+
+fun ValueSetsContainer?.isEmpty(): Boolean =
+    (this == null) || vaccinationValueSets.isEmpty && testCertificateValueSets.isEmpty
+
+val emptyValueSetsContainer: ValueSetsContainer by lazy {
+    ValueSetsContainer(
+        vaccinationValueSets = emptyVaccinationValueSets,
+        testCertificateValueSets = emptyTestCertificateValueSets
+    )
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/ValueSetsStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/ValueSetsStorage.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9c45cf1edc9529097b92d5db1105bdb94281c7a6
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/valueset/valuesets/ValueSetsStorage.kt
@@ -0,0 +1,61 @@
+package de.rki.coronawarnapp.covidcertificate.valueset.valuesets
+
+import android.content.Context
+import android.content.SharedPreferences
+import androidx.core.content.edit
+import com.google.gson.Gson
+import dagger.Reusable
+import de.rki.coronawarnapp.util.di.AppContext
+import de.rki.coronawarnapp.util.serialization.BaseGson
+import de.rki.coronawarnapp.util.serialization.fromJson
+import timber.log.Timber
+import javax.inject.Inject
+
+@Reusable
+class ValueSetsStorage @Inject constructor(
+    @AppContext private val context: Context,
+    @BaseGson private val gson: Gson
+) {
+
+    private val prefs: SharedPreferences by lazy {
+        context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
+            .also { removeLeftOver(it) }
+    }
+
+    var valueSetsContainer: ValueSetsContainer
+        get() = getValueSet()
+        set(value) = setValueSet(value)
+
+    private fun getValueSet(): ValueSetsContainer {
+        Timber.v("Loading value sets container")
+        val valueSetString = prefs.getString(PKEY_VALUE_SETS_CONTAINER_PREFIX, null)
+        return when (valueSetString != null) {
+            true -> gson.fromJson(valueSetString)
+            else -> emptyValueSetsContainer
+        }.also { loaded -> Timber.v("Loaded value sets container %s", loaded) }
+    }
+
+    private fun setValueSet(value: ValueSetsContainer) {
+        Timber.v("Saving value sets container %s", value)
+        prefs.edit {
+            val json = gson.toJson(value, ValueSetsContainer::class.java)
+            Timber.v("Writing %s to prefs", json)
+            putString(PKEY_VALUE_SETS_CONTAINER_PREFIX, json)
+        }
+    }
+
+    private fun removeLeftOver(prefs: SharedPreferences) {
+        Timber.v("Checking for leftover and removing it")
+        if (prefs.contains(PKEY_VALUE_SETS_PREFIX)) {
+            prefs.edit(commit = true) {
+                remove(PKEY_VALUE_SETS_PREFIX)
+            }
+        }
+    }
+
+    companion object {
+        private const val PREF_NAME = "valuesets_localdata"
+        private const val PKEY_VALUE_SETS_PREFIX = "valueset"
+        private const val PKEY_VALUE_SETS_CONTAINER_PREFIX = "valuesets_container"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/testresult/AnalyticsTestResultDonor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/testresult/AnalyticsTestResultDonor.kt
index 8ec58e10709d6dbaefb48c8764bb71c417056d1d..33720b0c900ee121e2180a8b747cc481169d8ef3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/testresult/AnalyticsTestResultDonor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/testresult/AnalyticsTestResultDonor.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.datadonation.analytics.modules.testresult
 
 import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.datadonation.analytics.common.isFinal
 import de.rki.coronawarnapp.datadonation.analytics.common.isPending
 import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule
@@ -16,19 +17,25 @@ import javax.inject.Singleton
 class AnalyticsPCRTestResultDonor @Inject constructor(
     testResultSettings: AnalyticsPCRTestResultSettings,
     timeStamper: TimeStamper,
-) : AnalyticsTestResultDonor(testResultSettings, timeStamper)
+) : AnalyticsTestResultDonor(testResultSettings, timeStamper) {
+    override val type = CoronaTest.Type.PCR
+}
 
 @Singleton
 class AnalyticsRATestResultDonor @Inject constructor(
     testResultSettings: AnalyticsRATestResultSettings,
     timeStamper: TimeStamper,
-) : AnalyticsTestResultDonor(testResultSettings, timeStamper)
+) : AnalyticsTestResultDonor(testResultSettings, timeStamper) {
+    override val type = CoronaTest.Type.RAPID_ANTIGEN
+}
 
 abstract class AnalyticsTestResultDonor(
     private val testResultSettings: AnalyticsTestResultSettings,
     private val timeStamper: TimeStamper,
 ) : DonorModule {
 
+    abstract val type: CoronaTest.Type
+
     override suspend fun beginDonation(request: DonorModule.Request): DonorModule.Contribution {
         val timestampAtRegistration = testResultSettings.testRegisteredAt.value
         if (timestampAtRegistration == null) {
@@ -145,9 +152,14 @@ abstract class AnalyticsTestResultDonor(
 
     private fun CoronaTestResult.toPPATestResult(): PpaData.PPATestResult {
         return when (this) {
-            CoronaTestResult.PCR_OR_RAT_PENDING -> PpaData.PPATestResult.TEST_RESULT_PENDING
+            CoronaTestResult.PCR_OR_RAT_PENDING -> when (type) {
+                CoronaTest.Type.PCR -> PpaData.PPATestResult.TEST_RESULT_PENDING
+                CoronaTest.Type.RAPID_ANTIGEN -> PpaData.PPATestResult.TEST_RESULT_RAT_PENDING
+            }
             CoronaTestResult.PCR_POSITIVE -> PpaData.PPATestResult.TEST_RESULT_POSITIVE
             CoronaTestResult.PCR_NEGATIVE -> PpaData.PPATestResult.TEST_RESULT_NEGATIVE
+            CoronaTestResult.RAT_NEGATIVE -> PpaData.PPATestResult.TEST_RESULT_RAT_NEGATIVE
+            CoronaTestResult.RAT_POSITIVE -> PpaData.PPATestResult.TEST_RESULT_RAT_POSITIVE
             else -> PpaData.PPATestResult.TEST_RESULT_UNKNOWN
         }
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt
index b99710e6d4a6bd5a07a5bb7d08931aecf4594746..10fa9b9785e9ac1ca074fc3e5bf2700212bb26f8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.environment
 
 import dagger.Module
 import de.rki.coronawarnapp.environment.bugreporting.BugReportingServerModule
+import de.rki.coronawarnapp.environment.covidcertificate.DCCModule
 import de.rki.coronawarnapp.environment.datadonation.DataDonationCDNModule
 import de.rki.coronawarnapp.environment.download.DownloadCDNModule
 import de.rki.coronawarnapp.environment.submission.SubmissionCDNModule
@@ -13,7 +14,8 @@ import de.rki.coronawarnapp.environment.verification.VerificationCDNModule
         SubmissionCDNModule::class,
         VerificationCDNModule::class,
         DataDonationCDNModule::class,
-        BugReportingServerModule::class
+        BugReportingServerModule::class,
+        DCCModule::class
     ]
 )
 class EnvironmentModule
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt
index d44e8e88ef378eaae6e78f7c4e73591be7c08e93..bc62e8baba75f858aa927329b247a50ce0c694e6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt
@@ -7,6 +7,7 @@ import com.google.gson.JsonObject
 import com.google.gson.JsonPrimitive
 import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.CROWD_NOTIFIER_PUBLIC_KEY
 import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DATA_DONATION
+import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DCC
 import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DOWNLOAD
 import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.LOG_UPLOAD
 import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.SAFETYNET_API_KEY
@@ -37,7 +38,8 @@ class EnvironmentSetup @Inject constructor(
         DATA_DONATION("DATA_DONATION_CDN_URL"),
         LOG_UPLOAD("LOG_UPLOAD_SERVER_URL"),
         SAFETYNET_API_KEY("SAFETYNET_API_KEY"),
-        CROWD_NOTIFIER_PUBLIC_KEY("CROWD_NOTIFIER_PUBLIC_KEY")
+        CROWD_NOTIFIER_PUBLIC_KEY("CROWD_NOTIFIER_PUBLIC_KEY"),
+        DCC("DCC_SERVER_URL"),
     }
 
     enum class Type(val rawKey: String) {
@@ -135,6 +137,9 @@ class EnvironmentSetup @Inject constructor(
     val logUploadServerUrl: String
         get() = getEnvironmentValue(LOG_UPLOAD).asString
 
+    val dccServerUrl: String
+        get() = getEnvironmentValue(DCC).asString
+
     companion object {
         private const val PKEY_CURRENT_ENVINROMENT = "environment.current"
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/covidcertificate/DCCHttpClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/covidcertificate/DCCHttpClient.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d34bb8687820f5fb0f22bf0ae6920be1e883e809
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/covidcertificate/DCCHttpClient.kt
@@ -0,0 +1,8 @@
+package de.rki.coronawarnapp.environment.covidcertificate
+
+import javax.inject.Qualifier
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class DCCHttpClient
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/covidcertificate/DCCModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/covidcertificate/DCCModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..47821bb169e4569cea0d18e5ab100e245fba7f1c
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/covidcertificate/DCCModule.kt
@@ -0,0 +1,28 @@
+package de.rki.coronawarnapp.environment.covidcertificate
+
+import dagger.Module
+import dagger.Provides
+import dagger.Reusable
+import de.rki.coronawarnapp.environment.BaseEnvironmentModule
+import de.rki.coronawarnapp.environment.EnvironmentSetup
+import de.rki.coronawarnapp.http.HttpClientDefault
+import okhttp3.OkHttpClient
+import javax.inject.Singleton
+
+@Module
+class DCCModule : BaseEnvironmentModule() {
+
+    @Reusable
+    @DCCHttpClient
+    @Provides
+    fun dccHttpClient(@HttpClientDefault defaultHttpClient: OkHttpClient): OkHttpClient =
+        defaultHttpClient.newBuilder().build()
+
+    @Singleton
+    @DCCServerUrl
+    @Provides
+    fun dccServerUrl(environment: EnvironmentSetup): String {
+        val url = environment.dccServerUrl
+        return requireValidUrl(url)
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/ValueSet.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/covidcertificate/DCCServerUrl.kt
similarity index 53%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/ValueSet.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/covidcertificate/DCCServerUrl.kt
index 1300c045c0d8f448781ddcaa327bb7f2959fe09f..8c9cffcad317bb4eb1dad008c63d6e1264ddc804 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/ValueSet.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/covidcertificate/DCCServerUrl.kt
@@ -1,8 +1,8 @@
-package de.rki.coronawarnapp.vaccination.core.server.valueset
+package de.rki.coronawarnapp.environment.covidcertificate
 
 import javax.inject.Qualifier
 
 @Qualifier
 @MustBeDocumented
 @Retention(AnnotationRetention.RUNTIME)
-annotation class ValueSet
+annotation class DCCServerUrl
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/GreenCertificateUIModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/GreenCertificateUIModule.kt
deleted file mode 100644
index 62cacdaf517d4f183508f95368ab68c367e92937..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/GreenCertificateUIModule.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package de.rki.coronawarnapp.greencertificate.ui
-
-import dagger.Module
-import dagger.android.ContributesAndroidInjector
-import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesFragment
-import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesFragmentModule
-import de.rki.coronawarnapp.greencertificate.ui.certificates.details.GreenCertificateDetailsFragment
-import de.rki.coronawarnapp.greencertificate.ui.certificates.details.GreenCertificateDetailsModule
-
-@Module
-abstract class GreenCertificateUIModule {
-
-    @ContributesAndroidInjector(modules = [CertificatesFragmentModule::class])
-    abstract fun certificatesFragment(): CertificatesFragment
-
-    @ContributesAndroidInjector(modules = [GreenCertificateDetailsModule::class])
-    abstract fun certificateDetailsFragment(): GreenCertificateDetailsFragment
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesFragment.kt
deleted file mode 100644
index b9be3ef8f0c8da5a2f8bc30338d97b99cff70bd6..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesFragment.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package de.rki.coronawarnapp.greencertificate.ui.certificates
-
-import android.os.Bundle
-import android.view.View
-import androidx.fragment.app.Fragment
-import androidx.navigation.fragment.findNavController
-import androidx.recyclerview.widget.DefaultItemAnimator
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.databinding.FragmentCertificatesBinding
-import de.rki.coronawarnapp.util.di.AutoInject
-import de.rki.coronawarnapp.util.lists.decorations.TopBottomPaddingDecorator
-import de.rki.coronawarnapp.util.lists.diffutil.update
-import de.rki.coronawarnapp.util.ui.doNavigate
-import de.rki.coronawarnapp.util.ui.findNestedGraph
-import de.rki.coronawarnapp.util.ui.observe2
-import de.rki.coronawarnapp.util.ui.viewBinding
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
-import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
-import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragment
-import javax.inject.Inject
-
-class CertificatesFragment : Fragment(R.layout.fragment_certificates), AutoInject {
-
-    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
-    private val viewModel by cwaViewModels<CertificatesViewModel> { viewModelFactory }
-    private val binding by viewBinding<FragmentCertificatesBinding>()
-
-    private val certificatesAdapter = CertificatesAdapter()
-
-    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        super.onViewCreated(view, savedInstanceState)
-
-        binding.recyclerView.apply {
-            itemAnimator = DefaultItemAnimator()
-            addItemDecoration(TopBottomPaddingDecorator(topPadding = R.dimen.spacing_tiny))
-            adapter = certificatesAdapter
-        }
-
-        viewModel.screenItems.observe2(this) { items -> certificatesAdapter.update(items) }
-        viewModel.events.observe2(this) { event ->
-            when (event) {
-                is CertificatesFragmentEvents.GoToVaccinationList -> findNavController().navigate(
-                    VaccinationListFragment.navigationUri(event.personIdentifierCodeSha256)
-                )
-                is CertificatesFragmentEvents.OpenVaccinationRegistrationGraph -> {
-                    // TODO: update when certifications info screen is done
-                    findNestedGraph(R.id.vaccination_nav_graph).startDestination = R.id.vaccinationQrCodeScanFragment
-                    doNavigate(CertificatesFragmentDirections.actionCertificatesFragmentToVaccinationNavGraph())
-                }
-            }
-        }
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesFragmentEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesFragmentEvents.kt
deleted file mode 100644
index 4682805714cb0ae55fca91abc0b7b34f03bc00d0..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesFragmentEvents.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package de.rki.coronawarnapp.greencertificate.ui.certificates
-
-sealed class CertificatesFragmentEvents {
-
-    data class OpenVaccinationRegistrationGraph(val registrationAcknowledged: Boolean) : CertificatesFragmentEvents()
-
-    data class GoToVaccinationList(val personIdentifierCodeSha256: String) : CertificatesFragmentEvents()
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesViewModel.kt
deleted file mode 100644
index 41e545fdc82e919188b1f9739227bbaa2fcd7d13..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/CertificatesViewModel.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-package de.rki.coronawarnapp.greencertificate.ui.certificates
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.asLiveData
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import de.rki.coronawarnapp.greencertificate.ui.certificates.items.CertificatesItem
-import de.rki.coronawarnapp.util.ui.SingleLiveEvent
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
-import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
-import de.rki.coronawarnapp.vaccination.core.VaccinationSettings
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
-import de.rki.coronawarnapp.vaccination.ui.cards.BottomInfoVaccinationCard
-import de.rki.coronawarnapp.vaccination.ui.cards.CreateVaccinationCard
-import de.rki.coronawarnapp.vaccination.ui.cards.HeaderInfoVaccinationCard
-import de.rki.coronawarnapp.vaccination.ui.cards.ImmuneVaccinationCard
-import de.rki.coronawarnapp.vaccination.ui.cards.VaccinationCard
-import kotlinx.coroutines.flow.map
-
-class CertificatesViewModel @AssistedInject constructor(
-    vaccinationRepository: VaccinationRepository,
-    private val vaccinationSettings: VaccinationSettings
-) : CWAViewModel() {
-
-    val events = SingleLiveEvent<CertificatesFragmentEvents>()
-
-    // TODO: cards should be adjusted in the following PR
-    val screenItems: LiveData<List<CertificatesItem>> =
-        vaccinationRepository.vaccinationInfos.map { vaccinatedPersons ->
-            mutableListOf<CertificatesItem>().apply {
-                add(HeaderInfoVaccinationCard.Item)
-
-                vaccinatedPersons.forEach { vaccinatedPerson ->
-                    val card = when (vaccinatedPerson.getVaccinationStatus()) {
-                        VaccinatedPerson.Status.COMPLETE,
-                        VaccinatedPerson.Status.INCOMPLETE -> VaccinationCard.Item(
-                            vaccinatedPerson = vaccinatedPerson,
-                            onClickAction = {
-                                events.postValue(
-                                    CertificatesFragmentEvents.GoToVaccinationList(
-                                        vaccinatedPerson.identifier.codeSHA256
-                                    )
-                                )
-                            }
-                        )
-                        VaccinatedPerson.Status.IMMUNITY -> ImmuneVaccinationCard.Item(
-                            vaccinatedPerson = vaccinatedPerson,
-                            onClickAction = {
-                                events.postValue(
-                                    CertificatesFragmentEvents.GoToVaccinationList(
-                                        vaccinatedPerson.identifier.codeSHA256
-                                    )
-                                )
-                            }
-                        )
-                    }
-                    add(card)
-                }
-
-                add(
-                    CreateVaccinationCard.Item(
-                        onClickAction = {
-                            events.postValue(
-                                CertificatesFragmentEvents.OpenVaccinationRegistrationGraph(
-                                    vaccinationSettings.registrationAcknowledged
-                                )
-                            )
-                        }
-                    )
-                )
-                add(BottomInfoVaccinationCard.Item)
-            }
-        }.asLiveData()
-
-    @AssistedFactory
-    interface Factory : SimpleCWAViewModelFactory<CertificatesViewModel>
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsFragment.kt
deleted file mode 100644
index ff9e0a78ba067f6d66397a33b22fe303151a6c80..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsFragment.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-package de.rki.coronawarnapp.greencertificate.ui.certificates.details
-
-import android.os.Bundle
-import android.view.View
-import android.widget.LinearLayout
-import androidx.coordinatorlayout.widget.CoordinatorLayout
-import androidx.fragment.app.Fragment
-import com.google.android.material.appbar.AppBarLayout
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.databinding.FragmentGreencertificateDetailsBinding
-import de.rki.coronawarnapp.ui.view.onOffsetChange
-import de.rki.coronawarnapp.util.di.AutoInject
-import de.rki.coronawarnapp.util.setUrl
-import de.rki.coronawarnapp.util.ui.popBackStack
-import de.rki.coronawarnapp.util.ui.viewBinding
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
-import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
-import javax.inject.Inject
-
-class GreenCertificateDetailsFragment : Fragment(R.layout.fragment_greencertificate_details), AutoInject {
-
-    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
-    private val binding: FragmentGreencertificateDetailsBinding by viewBinding()
-    private val viewModel: GreenCertificateDetailsViewModel by cwaViewModels { viewModelFactory }
-
-    override fun onViewCreated(view: View, savedInstanceState: Bundle?) =
-        with(binding) {
-            toolbar.setNavigationOnClickListener { popBackStack() }
-
-            qrCodeCard.title.text = getString(R.string.detail_green_certificate_card_title)
-            qrCodeCard.subtitle.text = "Test durchgeführt am 12.05.21 18:01" // will be changed
-
-            appBarLayout.onOffsetChange { titleAlpha, subtitleAlpha ->
-                title.alpha = titleAlpha
-                subtitle.alpha = subtitleAlpha
-            }
-
-            if (travelNoticeGerman.text ==
-                requireContext().getString(R.string.green_certificate_attribute_certificate_travel_notice_german)
-            ) {
-                travelNoticeGerman.setUrl(
-                    R.string.green_certificate_attribute_certificate_travel_notice_german,
-                    R.string.green_certificate_travel_notice_link_de,
-                    R.string.green_certificate_travel_notice_link_de
-                )
-            }
-
-            if (travelNoticeEnglish.text ==
-                requireContext().getString(R.string.green_certificate_attribute_certificate_travel_notice_english)
-            ) {
-                travelNoticeEnglish.setUrl(
-                    R.string.green_certificate_attribute_certificate_travel_notice_english,
-                    R.string.green_certificate_travel_notice_link_en,
-                    R.string.green_certificate_travel_notice_link_en
-                )
-            }
-
-            setToolbarOverlay()
-
-            viewModel.qrCode.observe(viewLifecycleOwner) {
-                qrCodeCard.image.setImageBitmap(it)
-                it?.let {
-                    qrCodeCard.image.setOnClickListener { viewModel.openFullScreen() }
-                    qrCodeCard.progressBar.hide()
-                }
-            }
-
-            // TODO: Will in the future be called when the data is loaded from the database
-            viewModel.generateQrCode()
-        }
-
-    private fun setToolbarOverlay() {
-        val width = requireContext().resources.displayMetrics.widthPixels
-        val params: CoordinatorLayout.LayoutParams = binding.scrollView.layoutParams
-            as (CoordinatorLayout.LayoutParams)
-
-        val textParams = binding.subtitle.layoutParams as (LinearLayout.LayoutParams)
-        textParams.bottomMargin = (width / 3) + 170
-        binding.subtitle.requestLayout()
-
-        val behavior: AppBarLayout.ScrollingViewBehavior = params.behavior as (AppBarLayout.ScrollingViewBehavior)
-        behavior.overlayTop = (width / 3) + 170
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsNavigation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsNavigation.kt
deleted file mode 100644
index 029b09bdc085eb4cedc5b22bf9b86dabee7e6db1..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsNavigation.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package de.rki.coronawarnapp.greencertificate.ui.certificates.details
-
-sealed class GreenCertificateDetailsNavigation {
-    object Back : GreenCertificateDetailsNavigation()
-    data class FullQrCode(val qrCodeText: String) : GreenCertificateDetailsNavigation()
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsViewModel.kt
deleted file mode 100644
index c1996855f250724b0466791cdd1de45dcc5a1e05..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/greencertificate/ui/certificates/details/GreenCertificateDetailsViewModel.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package de.rki.coronawarnapp.greencertificate.ui.certificates.details
-
-import android.graphics.Bitmap
-import androidx.lifecycle.asLiveData
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator
-import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
-import de.rki.coronawarnapp.util.ui.SingleLiveEvent
-import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
-import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import kotlinx.coroutines.flow.MutableStateFlow
-import timber.log.Timber
-
-class GreenCertificateDetailsViewModel @AssistedInject constructor(
-    private val qrCodeGenerator: QrCodeGenerator,
-    dispatcherProvider: DispatcherProvider,
-) : CWAViewModel(dispatcherProvider) {
-
-    private var qrCodeText: String? = null
-    private val mutableStateFlow = MutableStateFlow<Bitmap?>(null)
-    val qrCode = mutableStateFlow.asLiveData(dispatcherProvider.Default)
-
-    val events = SingleLiveEvent<GreenCertificateDetailsNavigation>()
-
-    fun onClose() = events.postValue(GreenCertificateDetailsNavigation.Back)
-
-    fun openFullScreen() = qrCodeText?.let { events.postValue(GreenCertificateDetailsNavigation.FullQrCode(it)) }
-
-    /* TODO: Adapt to Green Certificate */
-    fun generateQrCode() = launch {
-        try {
-            mutableStateFlow.value = qrCodeGenerator.createQrCode("Sample String")
-        } catch (e: Exception) {
-            Timber.d(e, "generateQrCode failed for greenCertificate=%s", "Sample Certificate")
-            mutableStateFlow.value = null
-        }
-    }
-
-    @AssistedFactory
-    interface Factory : SimpleCWAViewModelFactory<GreenCertificateDetailsViewModel>
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTask.kt
index a55f59dbd258a45c9ba9252411bed5b2173cbd84..7b05ff4b3a0705dd0e78b0d9893387e8915910b0 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTask.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTask.kt
@@ -15,7 +15,6 @@ import de.rki.coronawarnapp.presencetracing.warning.storage.TraceWarningReposito
 import de.rki.coronawarnapp.task.Task
 import de.rki.coronawarnapp.task.TaskCancellationException
 import de.rki.coronawarnapp.task.TaskFactory
-import de.rki.coronawarnapp.task.common.Finished
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.first
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt
index 8a5d733cb1be611c57e6d695c6609ade158d1ee4..b174210001f84d9573e95a6f995ac2e2370f57be 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt
@@ -19,9 +19,9 @@ import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.task.Task
 import de.rki.coronawarnapp.task.TaskCancellationException
 import de.rki.coronawarnapp.task.TaskFactory
+import de.rki.coronawarnapp.task.common.DefaultProgress
 import de.rki.coronawarnapp.task.common.Finished
 import de.rki.coronawarnapp.task.common.Started
-import de.rki.coronawarnapp.task.common.DefaultProgress
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.device.BackgroundModeStatus
 import kotlinx.coroutines.flow.Flow
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/additionalinfos/FindDetailsInJournalBox.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/additionalinfos/FindDetailsInJournalBox.kt
index 48cf2f853edc29e64603db9296b367b1872eaedc..a87e584ec8a5e3da332bc353616754e10036d71e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/additionalinfos/FindDetailsInJournalBox.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/additionalinfos/FindDetailsInJournalBox.kt
@@ -5,11 +5,12 @@ import androidx.annotation.LayoutRes
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.TracingDetailsFindDetailsInJournalBinding
 import de.rki.coronawarnapp.tracing.ui.details.TracingDetailsAdapter
+import de.rki.coronawarnapp.tracing.ui.details.items.additionalinfos.FindDetailsInJournalBox.Item
 
 class FindDetailsInJournalBox(
     parent: ViewGroup,
     @LayoutRes containerLayout: Int = R.layout.tracing_details_find_details_in_journal
-) : TracingDetailsAdapter.DetailsItemVH<FindDetailsInJournalBox.Item, TracingDetailsFindDetailsInJournalBinding>(
+) : TracingDetailsAdapter.DetailsItemVH<Item, TracingDetailsFindDetailsInJournalBinding>(
     containerLayout,
     parent
 ) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt
index 552d7ccb8691c8d2b08a431b3ac725e87cf89804..b9a628633897316295d23bfff2b14ad59636323c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt
@@ -4,8 +4,9 @@ import dagger.Binds
 import dagger.Module
 import dagger.android.ContributesAndroidInjector
 import dagger.multibindings.IntoMap
+import de.rki.coronawarnapp.covidcertificate.test.ui.CovidCertificateUIModule
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.VaccinationUIModule
 import de.rki.coronawarnapp.datadonation.analytics.ui.AnalyticsUIModule
-import de.rki.coronawarnapp.greencertificate.ui.GreenCertificateUIModule
 import de.rki.coronawarnapp.release.NewReleaseInfoFragment
 import de.rki.coronawarnapp.release.NewReleaseInfoFragmentModule
 import de.rki.coronawarnapp.tracing.ui.details.TracingDetailsFragmentModule
@@ -26,7 +27,6 @@ import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionFragmentModule
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
-import de.rki.coronawarnapp.vaccination.ui.VaccinationUIModule
 
 @Module(
     includes = [
@@ -42,7 +42,7 @@ import de.rki.coronawarnapp.vaccination.ui.VaccinationUIModule
         PresenceTracingUIModule::class,
         RATProfileUIModule::class,
         VaccinationUIModule::class,
-        GreenCertificateUIModule::class,
+        CovidCertificateUIModule::class,
     ]
 )
 abstract class MainActivityModule {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt
index 7952b2e729d07b2ad1c0ea5151f75772c7cd3b7d..6fe194da45ba54ed22a245032879f0a93aeb8556 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt
@@ -6,6 +6,7 @@ import androidx.lifecycle.asLiveData
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationSettings
 import de.rki.coronawarnapp.environment.EnvironmentSetup
 import de.rki.coronawarnapp.playbook.BackgroundNoise
 import de.rki.coronawarnapp.presencetracing.TraceLocationSettings
@@ -17,7 +18,6 @@ import de.rki.coronawarnapp.util.device.BackgroundModeStatus
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import de.rki.coronawarnapp.vaccination.core.VaccinationSettings
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.map
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
index d549a308af695e9e842abd3586f7905127f49fb5..b75e523a1e49a607e4a4d52fe522fb96a5815d89 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
@@ -20,6 +20,8 @@ import de.rki.coronawarnapp.coronatest.type.pcr.toSubmissionState
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.SubmissionStateRAT
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.toSubmissionState
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationSettings
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
 import de.rki.coronawarnapp.main.CWASettings
 import de.rki.coronawarnapp.statistics.source.StatisticsProvider
 import de.rki.coronawarnapp.statistics.ui.homecards.StatisticsHomeCard
@@ -74,8 +76,6 @@ import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import de.rki.coronawarnapp.vaccination.core.VaccinationSettings
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateFragment.kt
similarity index 99%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateFragment.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateFragment.kt
index 6ada9a9747eacc1581735ae1d68ac13efdf885bd..2635a01a5d5cdcfec0d8b5f48f392d1616777c46 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateFragment.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.ui.submission.greencertificate
+package de.rki.coronawarnapp.ui.submission.covidcertificate
 
 import android.os.Bundle
 import androidx.fragment.app.Fragment
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateFragmentModule.kt
similarity index 90%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateFragmentModule.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateFragmentModule.kt
index 74c2e8f205297db138d98de358174a45ce2da4bc..6bc12c024573270581707f0cf504024d2be50ca2 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateFragmentModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateFragmentModule.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.ui.submission.greencertificate
+package de.rki.coronawarnapp.ui.submission.covidcertificate
 
 import dagger.Binds
 import dagger.Module
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateViewModel.kt
similarity index 98%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateViewModel.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateViewModel.kt
index e6603079d74c953af578d0f6655f1e588603476f..ff0e272e71fbba2a1b6de47be1defa317be6f66c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateViewModel.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.ui.submission.greencertificate
+package de.rki.coronawarnapp.ui.submission.covidcertificate
 
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestDccNavEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestDccNavEvent.kt
similarity index 72%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestDccNavEvent.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestDccNavEvent.kt
index 1bb251b76e2760f8183d4df792b992857304ad8c..d1b3d8c6075c668fb5410864e1a0eed51d37bf46 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestDccNavEvent.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestDccNavEvent.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.ui.submission.greencertificate
+package de.rki.coronawarnapp.ui.submission.covidcertificate
 
 sealed class RequestDccNavEvent
 object ToDispatcherScreen : RequestDccNavEvent()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt
index 2f0c1d50985049173bd6fc25c468936899b70776..fe135a5d3ae934c14066d17ee3cdd426cce8af24 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionFragmentModule.kt
@@ -8,8 +8,8 @@ import de.rki.coronawarnapp.ui.submission.fragment.SubmissionContactFragment
 import de.rki.coronawarnapp.ui.submission.fragment.SubmissionDispatcherFragment
 import de.rki.coronawarnapp.ui.submission.deletionwarning.SubmissionDeletionWarningFragment
 import de.rki.coronawarnapp.ui.submission.deletionwarning.SubmissionDeletionWarningModule
-import de.rki.coronawarnapp.ui.submission.greencertificate.RequestCovidCertificateFragment
-import de.rki.coronawarnapp.ui.submission.greencertificate.RequestCovidCertificateFragmentModule
+import de.rki.coronawarnapp.ui.submission.covidcertificate.RequestCovidCertificateFragment
+import de.rki.coronawarnapp.ui.submission.covidcertificate.RequestCovidCertificateFragmentModule
 import de.rki.coronawarnapp.ui.submission.qrcode.consent.SubmissionConsentFragment
 import de.rki.coronawarnapp.ui.submission.qrcode.consent.SubmissionConsentModule
 import de.rki.coronawarnapp.ui.submission.qrcode.scan.SubmissionQRCodeScanFragment
@@ -102,7 +102,7 @@ internal abstract class SubmissionFragmentModule {
     abstract fun submissionTestResultNoConsentScreen(): SubmissionTestResultNoConsentFragment
 
     @ContributesAndroidInjector(modules = [SubmissionResultPositiveOtherWarningNoConsentModule::class])
-    abstract fun SubmissionResultPositiveOtherWarningNoConsentScreen(): SubmissionResultPositiveOtherWarningNoConsentFragment
+    abstract fun submissionResultPositiveOtherWarningNoConsentScreen(): SubmissionResultPositiveOtherWarningNoConsentFragment
 
     @ContributesAndroidInjector(modules = [SubmissionDeletionWarningModule::class])
     abstract fun submissionDeletionWarningScreen(): SubmissionDeletionWarningFragment
@@ -114,5 +114,5 @@ internal abstract class SubmissionFragmentModule {
     abstract fun submissionTestResultKeysSharedScreen(): SubmissionTestResultKeysSharedFragment
 
     @ContributesAndroidInjector(modules = [RequestCovidCertificateFragmentModule::class])
-    abstract fun requestGreenCertificateFragment(): RequestCovidCertificateFragment
+    abstract fun requestCovidCertificateFragment(): RequestCovidCertificateFragment
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt
index df7f430bbe48c42f64406e73b64ed417d2750c51..1f6f88ae6974863c3da1262151001e7375c883e6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt
@@ -7,6 +7,10 @@ import de.rki.coronawarnapp.contactdiary.storage.ContactDiaryPreferences
 import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfileSettings
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationPreferences
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
+import de.rki.coronawarnapp.covidcertificate.valueset.ValueSetsRepository
 import de.rki.coronawarnapp.datadonation.analytics.Analytics
 import de.rki.coronawarnapp.datadonation.analytics.storage.AnalyticsSettings
 import de.rki.coronawarnapp.datadonation.survey.SurveySettings
@@ -25,9 +29,6 @@ import de.rki.coronawarnapp.storage.TracingSettings
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.submission.SubmissionSettings
 import de.rki.coronawarnapp.ui.presencetracing.TraceLocationPreferences
-import de.rki.coronawarnapp.vaccination.core.repository.ValueSetsRepository
-import de.rki.coronawarnapp.vaccination.core.VaccinationPreferences
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
 import timber.log.Timber
@@ -67,6 +68,7 @@ class DataReset @Inject constructor(
     private val valueSetsRepository: ValueSetsRepository,
     private val vaccinationPreferences: VaccinationPreferences,
     private val vaccinationRepository: VaccinationRepository,
+    private val testCertificateRepository: TestCertificateRepository,
 ) {
 
     private val mutex = Mutex()
@@ -109,6 +111,7 @@ class DataReset @Inject constructor(
         traceLocationRepository.deleteAllTraceLocations()
         checkInRepository.clear()
         coronaTestRepository.clear()
+        testCertificateRepository.clear()
         ratProfileSettings.deleteProfile()
 
         valueSetsRepository.clear()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt
index fb41bfffa07a8878bcf3fbb1f94618534a250e3f..897f618ef8b4b1c654e2aacb7ac839810ad88517 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt
@@ -25,6 +25,7 @@ object TimeAndDateExtensions {
 
     private val dayFormatter = DateTimeFormat.forPattern("dd.MM.yyyy")
     private val dayFormatter2DigitYear = DateTimeFormat.forPattern("dd.MM.yy")
+    private val shortTime = DateTimeFormat.shortTime()
 
     fun getCurrentHourUTC(): Int = DateTime(Instant.now(), DateTimeZone.UTC).hourOfDay().get()
 
@@ -119,6 +120,16 @@ object TimeAndDateExtensions {
      */
     fun LocalDate.toDayFormat(): String = toString(dayFormatter)
 
+    /**
+     * Returns a readable time String with the format "hh:mm" like 12:00 of a LocalDate
+     */
+    fun LocalDate.toShortTimeFormat(): String = toString(shortTime)
+
+    /**
+     * Returns a readable time String with the format "hh:mm" like 12:00 of a LocalDate
+     */
+    fun Instant.toShortTimeFormat(): String = toString(shortTime)
+
     /**
      * Returns a readable date String with the format "dd.MM.yy" like 23.05.89 of an Instant
      */
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/compression/ZLIBCompression.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/compression/ZLIBCompression.kt
index d03ef22a3372422c6651b5b12f62c12fdb4fa182..e4ddeec39b3881411dfe311b731491813938b141 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/compression/ZLIBCompression.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/compression/ZLIBCompression.kt
@@ -2,6 +2,9 @@ package de.rki.coronawarnapp.util.compression
 
 import okio.Buffer
 import okio.inflate
+import timber.log.Timber
+import java.io.ByteArrayOutputStream
+import java.util.zip.Deflater
 import java.util.zip.Inflater
 import javax.inject.Inject
 
@@ -25,8 +28,25 @@ class ZLIBCompression @Inject constructor() {
 
         sink.readByteArray()
     } catch (e: Throwable) {
+        Timber.e(e)
         throw InvalidInputException("ZLIB decompression failed.", e)
     }
+
+    fun compress(input: ByteArray): ByteArray {
+        val deflater = Deflater()
+        deflater.setInput(input)
+        val outputStream = ByteArrayOutputStream(input.size)
+        deflater.finish()
+        val buffer = ByteArray(1024)
+        while (!deflater.finished()) {
+            val count = deflater.deflate(buffer)
+            outputStream.write(buffer, 0, count)
+        }
+        outputStream.close()
+        return outputStream.toByteArray()
+    }
 }
 
 fun ByteArray.inflate(sizeLimit: Long = -1L) = ZLIBCompression().decompress(this, sizeLimit)
+
+fun ByteArray.deflate() = ZLIBCompression().compress(this)
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 471f0e5866c704de32490da16012ea6ad77b2081..7582acfcdef9c87909c9489f4c35def8bae162cb 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
@@ -14,6 +14,7 @@ import de.rki.coronawarnapp.bugreporting.BugReportingSharedModule
 import de.rki.coronawarnapp.bugreporting.debuglog.DebugLogger
 import de.rki.coronawarnapp.coronatest.CoronaTestModule
 import de.rki.coronawarnapp.coronatest.server.VerificationModule
+import de.rki.coronawarnapp.covidcertificate.DigitalCovidCertificateModule
 import de.rki.coronawarnapp.datadonation.DataDonationModule
 import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule
 import de.rki.coronawarnapp.diagnosiskeys.DownloadDiagnosisKeysTaskModule
@@ -45,7 +46,6 @@ import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
 import de.rki.coronawarnapp.util.security.SecurityModule
 import de.rki.coronawarnapp.util.serialization.SerializationModule
 import de.rki.coronawarnapp.util.worker.WorkerBinder
-import de.rki.coronawarnapp.vaccination.core.VaccinationModule
 import javax.inject.Singleton
 
 @Singleton
@@ -80,7 +80,7 @@ import javax.inject.Singleton
         SecurityModule::class,
         PresenceTracingModule::class,
         CoronaTestModule::class,
-        VaccinationModule::class,
+        DigitalCovidCertificateModule::class,
     ]
 )
 interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encoding/Base45Decoder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encoding/Base45Decoder.kt
index 39320eb27363a5bc8ecd9368316c8bde1d3042f7..b8cebf7a46c13f3a9efe04b17735f8402c6dd013 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encoding/Base45Decoder.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encoding/Base45Decoder.kt
@@ -23,7 +23,6 @@ import java.math.BigInteger
  * Based on
  * https://github.com/ehn-digital-green-development/hcert-kotlin/blob/23203fbb71f53524ee643a9df116264f87b5b32a/src/main/kotlin/ehn/techiop/hcert/kotlin/chain/common/Base45Encoder.kt
  */
-@OptIn(ExperimentalUnsignedTypes::class)
 object Base45Decoder {
     private const val alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
     private val int45 = BigInteger.valueOf(45)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryption/rsa/RSAKey.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryption/rsa/RSAKey.kt
index 1018360a12b96322ea1b89ba7d639bd6b3c53065..9e417278c1c23b1beed7ecdc70bf3243a5edac2e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryption/rsa/RSAKey.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/encryption/rsa/RSAKey.kt
@@ -1,8 +1,13 @@
 package de.rki.coronawarnapp.util.encryption.rsa
 
+import com.google.gson.TypeAdapter
+import com.google.gson.stream.JsonReader
+import com.google.gson.stream.JsonWriter
 import de.rki.coronawarnapp.util.trimToLength
 import okio.ByteString
+import okio.ByteString.Companion.decodeBase64
 import okio.ByteString.Companion.toByteString
+import org.json.JSONObject
 import java.security.Key
 import java.security.KeyFactory
 import java.security.PrivateKey
@@ -29,6 +34,18 @@ interface RSAKey {
             get() = KEY_FACTORY.generatePrivate(PKCS8EncodedKeySpec(rawKey.toByteArray()))
 
         override fun toString(): String = base64.trimToLength(16)
+
+        class GsonAdapter : TypeAdapter<Private>() {
+            override fun write(out: JsonWriter, value: Private?) {
+                if (value == null) out.nullValue()
+                else out.value(value.rawKey.base64())
+            }
+
+            override fun read(reader: JsonReader): Private? = when (reader.peek()) {
+                JSONObject.NULL -> reader.nextNull().let { null }
+                else -> Private(reader.nextString().decodeBase64()!!)
+            }
+        }
     }
 
     data class Public(override val rawKey: ByteString) : RSAKey {
@@ -39,5 +56,17 @@ interface RSAKey {
             get() = KEY_FACTORY.generatePublic(X509EncodedKeySpec(rawKey.toByteArray()))
 
         override fun toString(): String = base64.trimToLength(16)
+
+        class GsonAdapter : TypeAdapter<Public>() {
+            override fun write(out: JsonWriter, value: Public?) {
+                if (value == null) out.nullValue()
+                else out.value(value.rawKey.base64())
+            }
+
+            override fun read(reader: JsonReader): Public? = when (reader.peek()) {
+                JSONObject.NULL -> reader.nextNull().let { null }
+                else -> Public(reader.nextString().decodeBase64()!!)
+            }
+        }
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/SerializationModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/SerializationModule.kt
index 1a35bb0361d6c87e14447419bebb714fb747f23b..f7823f6e1f12f46ad430266b8bfb7af1a81416ff 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/SerializationModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/serialization/SerializationModule.kt
@@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder
 import dagger.Module
 import dagger.Provides
 import dagger.Reusable
+import de.rki.coronawarnapp.util.encryption.rsa.RSAKey
 import de.rki.coronawarnapp.util.serialization.adapter.ByteArrayAdapter
 import de.rki.coronawarnapp.util.serialization.adapter.ByteStringBase64Adapter
 import de.rki.coronawarnapp.util.serialization.adapter.DurationAdapter
@@ -27,5 +28,7 @@ class SerializationModule {
         .registerTypeAdapter(Duration::class.java, DurationAdapter())
         .registerTypeAdapter(ByteArray::class.java, ByteArrayAdapter())
         .registerTypeAdapter(ByteString::class.java, ByteStringBase64Adapter())
+        .registerTypeAdapter(RSAKey.Public::class.java, RSAKey.Public.GsonAdapter())
+        .registerTypeAdapter(RSAKey.Private::class.java, RSAKey.Private.GsonAdapter())
         .create()
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/worker/WorkerBinder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/worker/WorkerBinder.kt
index b877317c4215654c733750ac38793022a4f3b563..a80ff22e3751062ae654584672de2d5975996fe7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/worker/WorkerBinder.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/worker/WorkerBinder.kt
@@ -7,6 +7,8 @@ import dagger.multibindings.IntoMap
 import de.rki.coronawarnapp.contactdiary.retention.ContactDiaryRetentionWorker
 import de.rki.coronawarnapp.coronatest.type.pcr.execution.PCRResultRetrievalWorker
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultRetrievalWorker
+import de.rki.coronawarnapp.covidcertificate.test.core.execution.TestCertificateRetrievalWorker
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.worker.VaccinationUpdateWorker
 import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsPeriodicWorker
 import de.rki.coronawarnapp.deadman.DeadmanNotificationOneTimeWorker
 import de.rki.coronawarnapp.deadman.DeadmanNotificationPeriodicWorker
@@ -18,7 +20,6 @@ import de.rki.coronawarnapp.presencetracing.checkins.checkout.auto.AutoCheckOutW
 import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingWarningWorker
 import de.rki.coronawarnapp.presencetracing.storage.retention.TraceLocationDbCleanUpPeriodicWorker
 import de.rki.coronawarnapp.submission.auto.SubmissionWorker
-import de.rki.coronawarnapp.vaccination.core.execution.worker.VaccinationUpdateWorker
 
 @Module
 abstract class WorkerBinder {
@@ -127,4 +128,11 @@ abstract class WorkerBinder {
     abstract fun vaccinationUpdateWorker(
         factory: VaccinationUpdateWorker.Factory
     ): InjectedWorkerFactory<out ListenableWorker>
+
+    @Binds
+    @IntoMap
+    @WorkerKey(TestCertificateRetrievalWorker::class)
+    abstract fun testCertificateRetrievalWorker(
+        factory: TestCertificateRetrievalWorker.Factory
+    ): InjectedWorkerFactory<out ListenableWorker>
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationCertificate.kt
deleted file mode 100644
index 92e96ea0bc9693463b15072b973bc6ab0e940e2d..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationCertificate.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core
-
-import de.rki.coronawarnapp.vaccination.core.qrcode.QrCodeString
-import org.joda.time.Instant
-import org.joda.time.LocalDate
-
-interface VaccinationCertificate {
-    val firstName: String?
-    val lastName: String
-
-    val dateOfBirth: LocalDate
-    val vaccinatedAt: LocalDate
-
-    val vaccineTypeName: String
-    val vaccineManufacturer: String
-    val medicalProductName: String
-
-    val doseNumber: Int
-    val totalSeriesOfDoses: Int
-
-    val certificateIssuer: String
-    val certificateCountry: String
-    val certificateId: String
-
-    val personIdentifier: VaccinatedPersonIdentifier
-
-    val issuer: String
-    val issuedAt: Instant
-    val expiresAt: Instant
-
-    val vaccinationQrCodeString: QrCodeString
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/CoseCertificateHeader.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/CoseCertificateHeader.kt
deleted file mode 100644
index 2818cf35b5693f525a5acbf55cf977ff4b202556..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/CoseCertificateHeader.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.certificate
-
-import org.joda.time.Instant
-
-interface CoseCertificateHeader {
-    val issuer: String
-    val issuedAt: Instant
-    val expiresAt: Instant
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateCOSEDecoder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateCOSEDecoder.kt
deleted file mode 100644
index fbb291dcd3dee0f8be7c67f9d11813b453d6727b..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateCOSEDecoder.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.certificate
-
-import com.upokecenter.cbor.CBORObject
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_COSE_MESSAGE_INVALID
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_COSE_TAG_INVALID
-import timber.log.Timber
-import javax.inject.Inject
-
-class HealthCertificateCOSEDecoder @Inject constructor() {
-
-    fun decode(input: RawCOSEObject): CBORObject = try {
-        val messageObject = CBORObject.DecodeFromBytes(input).validate()
-        val content = messageObject[2].GetByteString()
-        CBORObject.DecodeFromBytes(content)
-    } catch (e: InvalidHealthCertificateException) {
-        throw e
-    } catch (e: Throwable) {
-        Timber.e(e)
-        throw InvalidHealthCertificateException(HC_COSE_MESSAGE_INVALID)
-    }
-
-    private fun CBORObject.validate(): CBORObject {
-        if (size() != 4) {
-            throw InvalidHealthCertificateException(HC_COSE_MESSAGE_INVALID)
-        }
-        if (!HasTag(18)) {
-            throw InvalidHealthCertificateException(HC_COSE_TAG_INVALID)
-        }
-        return this
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateHeader.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateHeader.kt
deleted file mode 100644
index 87271fc061c37e54f01a9cb6a4750b57df5ed631..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateHeader.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.certificate
-
-import org.joda.time.Instant
-
-data class HealthCertificateHeader(
-    override val issuer: String,
-    override val issuedAt: Instant,
-    override val expiresAt: Instant,
-) : CoseCertificateHeader
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/InvalidHealthCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/InvalidHealthCertificateException.kt
deleted file mode 100644
index 700ab2ddce25b728253bd2d58d46cd0ea9e795c6..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/InvalidHealthCertificateException.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.certificate
-
-import android.content.Context
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.coronatest.qrcode.InvalidQRCodeException
-import de.rki.coronawarnapp.util.HasHumanReadableError
-import de.rki.coronawarnapp.util.HumanReadableError
-import de.rki.coronawarnapp.util.ui.CachedString
-import de.rki.coronawarnapp.util.ui.LazyString
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_COSE_MESSAGE_INVALID
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_COSE_TAG_INVALID
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_ALREADY_REGISTERED
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_DOB_MISMATCH
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_HC_CWT_NO_DGC
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_HC_CWT_NO_EXP
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_HC_CWT_NO_HCERT
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_HC_CWT_NO_ISS
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_JSON_SCHEMA_INVALID
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_NAME_MISMATCH
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_NO_VACCINATION_ENTRY
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_PREFIX_INVALID
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_STORING_FAILED
-
-class InvalidHealthCertificateException(
-    val errorCode: ErrorCode
-) : HasHumanReadableError, InvalidQRCodeException(errorCode.message) {
-    enum class ErrorCode(
-        val message: String
-    ) {
-        HC_BASE45_DECODING_FAILED("Base45 decoding failed."),
-        HC_ZLIB_DECOMPRESSION_FAILED("Zlib decompression failed."),
-        HC_COSE_TAG_INVALID("COSE tag invalid."),
-        HC_COSE_MESSAGE_INVALID("COSE message invalid."),
-        HC_CBOR_DECODING_FAILED("CBOR decoding failed."),
-        VC_NO_VACCINATION_ENTRY("Vaccination certificate missing."),
-        VC_PREFIX_INVALID("Prefix invalid."),
-        VC_STORING_FAILED("Storing failed."),
-        VC_JSON_SCHEMA_INVALID("Json schema invalid."),
-        VC_NAME_MISMATCH("Name does not match."),
-        VC_ALREADY_REGISTERED("Certificate already registered."),
-        VC_DOB_MISMATCH("Date of birth does not match."),
-        VC_HC_CWT_NO_DGC("Dgc missing."),
-        VC_HC_CWT_NO_EXP("Expiration date missing."),
-        VC_HC_CWT_NO_HCERT("Health certificate missing."),
-        VC_HC_CWT_NO_ISS("Issuer missing."),
-    }
-
-    val errorMessage: LazyString
-        get() = when (errorCode) {
-            HC_BASE45_DECODING_FAILED,
-            HC_CBOR_DECODING_FAILED,
-            HC_COSE_MESSAGE_INVALID,
-            HC_ZLIB_DECOMPRESSION_FAILED,
-            HC_COSE_TAG_INVALID,
-            VC_PREFIX_INVALID,
-            VC_HC_CWT_NO_DGC,
-            VC_HC_CWT_NO_EXP,
-            VC_HC_CWT_NO_HCERT,
-            VC_HC_CWT_NO_ISS,
-            VC_JSON_SCHEMA_INVALID,
-            -> CachedString { context ->
-                context.getString(ERROR_MESSAGE_VC_INVALID)
-            }
-            VC_NO_VACCINATION_ENTRY -> CachedString { context ->
-                context.getString(ERROR_MESSAGE_VC_NOT_YET_SUPPORTED)
-            }
-            VC_STORING_FAILED -> CachedString { context ->
-                context.getString(ERROR_MESSAGE_VC_SCAN_AGAIN)
-            }
-            VC_NAME_MISMATCH, VC_DOB_MISMATCH -> CachedString { context ->
-                context.getString(ERROR_MESSAGE_VC_DIFFERENT_PERSON)
-            }
-            VC_ALREADY_REGISTERED -> CachedString { context ->
-                context.getString(ERROR_MESSAGE_ALREADY_REGISTERED)
-            }
-        }
-
-    override fun toHumanReadableError(context: Context): HumanReadableError {
-        var errorCodeString = errorCode.toString()
-        errorCodeString = if (errorCodeString.startsWith(PREFIX)) errorCodeString else PREFIX + errorCodeString
-        return HumanReadableError(
-            description = errorMessage.get(context) + "\n\n$errorCodeString"
-        )
-    }
-}
-
-private const val PREFIX = "VC_"
-private const val ERROR_MESSAGE_VC_INVALID = R.string.error_vc_invalid
-private const val ERROR_MESSAGE_VC_NOT_YET_SUPPORTED = R.string.error_vc_not_yet_supported
-private const val ERROR_MESSAGE_VC_SCAN_AGAIN = R.string.error_vc_scan_again
-private const val ERROR_MESSAGE_VC_DIFFERENT_PERSON = R.string.error_vc_different_person
-private const val ERROR_MESSAGE_ALREADY_REGISTERED = R.string.error_vc_already_registered
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/RawCOSEObject.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/RawCOSEObject.kt
deleted file mode 100644
index 0a13bb0971b82d0456b0539469d6e0e63a16d690..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/RawCOSEObject.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.certificate
-
-typealias RawCOSEObject = ByteArray
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/VaccinationDGCV1Parser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/VaccinationDGCV1Parser.kt
deleted file mode 100644
index e25defbc9cab81c1be8c37c0f6aba41716b14f75..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/VaccinationDGCV1Parser.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.certificate
-
-import com.google.gson.Gson
-import com.upokecenter.cbor.CBORObject
-import dagger.Reusable
-import de.rki.coronawarnapp.util.serialization.BaseGson
-import de.rki.coronawarnapp.util.serialization.fromJson
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_HC_CWT_NO_DGC
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_HC_CWT_NO_HCERT
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_JSON_SCHEMA_INVALID
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_NO_VACCINATION_ENTRY
-import javax.inject.Inject
-
-@Reusable
-class VaccinationDGCV1Parser @Inject constructor(
-    @BaseGson private val gson: Gson
-) {
-
-    fun parse(map: CBORObject): VaccinationDGCV1 = try {
-        val certificate: VaccinationDGCV1 = map[keyHCert]?.run {
-            this[keyEuDgcV1]?.run {
-                toCertificate()
-            } ?: throw InvalidHealthCertificateException(VC_HC_CWT_NO_DGC)
-        } ?: throw InvalidHealthCertificateException(VC_HC_CWT_NO_HCERT)
-
-        certificate.validate()
-    } catch (e: InvalidHealthCertificateException) {
-        throw e
-    } catch (e: Throwable) {
-        throw InvalidHealthCertificateException(HC_CBOR_DECODING_FAILED)
-    }
-
-    private fun VaccinationDGCV1.validate(): VaccinationDGCV1 {
-        if (vaccinationDatas.isEmpty()) {
-            throw InvalidHealthCertificateException(VC_NO_VACCINATION_ENTRY)
-        }
-        // Force date parsing
-        dateOfBirth
-        vaccinationDatas.forEach {
-            it.vaccinatedAt
-        }
-        return this
-    }
-
-    private fun CBORObject.toCertificate() = try {
-        val json = ToJSONString()
-        gson.fromJson<VaccinationDGCV1>(json)
-    } catch (e: Throwable) {
-        throw InvalidHealthCertificateException(VC_JSON_SCHEMA_INVALID)
-    }
-
-    companion object {
-        private val keyEuDgcV1 = CBORObject.FromObject(1)
-        private val keyHCert = CBORObject.FromObject(-260)
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationCertificateData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationCertificateData.kt
deleted file mode 100644
index 31da1c88bc2ad193a46614debcbcaea02feae7a6..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationCertificateData.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.qrcode
-
-import de.rki.coronawarnapp.vaccination.core.certificate.CoseCertificateHeader
-import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1
-
-/**
- * Represents the parsed data from the QR code
- */
-data class VaccinationCertificateData(
-    val header: CoseCertificateHeader,
-    val certificate: VaccinationDGCV1,
-)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationCertificateQRCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationCertificateQRCode.kt
deleted file mode 100644
index 5d72448a8a526c2954b15ffb67fa244fb20768b5..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationCertificateQRCode.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.qrcode
-
-data class VaccinationCertificateQRCode(
-    val qrCodeString: QrCodeString,
-    val parsedData: VaccinationCertificateData,
-) {
-    val uniqueCertificateIdentifier: String
-        get() = parsedData.certificate.vaccinationDatas.single().uniqueCertificateIdentifier
-}
-
-typealias QrCodeString = String
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt
deleted file mode 100644
index ae3065df399be47ee02e1d6fe5650ad3ea51b2a0..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.qrcode
-
-import de.rki.coronawarnapp.bugreporting.censors.vaccination.CertificateQrCodeCensor
-import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor
-import de.rki.coronawarnapp.util.compression.inflate
-import de.rki.coronawarnapp.util.encoding.Base45Decoder
-import de.rki.coronawarnapp.vaccination.core.certificate.HealthCertificateCOSEDecoder
-import de.rki.coronawarnapp.vaccination.core.certificate.HealthCertificateHeaderParser
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED
-import de.rki.coronawarnapp.vaccination.core.certificate.RawCOSEObject
-import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1Parser
-import timber.log.Timber
-import javax.inject.Inject
-
-class VaccinationQRCodeExtractor @Inject constructor(
-    private val coseDecoder: HealthCertificateCOSEDecoder,
-    private val headerParser: HealthCertificateHeaderParser,
-    private val bodyParser: VaccinationDGCV1Parser,
-) : QrCodeExtractor<VaccinationCertificateQRCode> {
-
-    override fun canHandle(rawString: String): Boolean = rawString.startsWith(PREFIX)
-
-    override fun extract(rawString: String): VaccinationCertificateQRCode {
-        CertificateQrCodeCensor.addQRCodeStringToCensor(rawString)
-
-        val parsedData = rawString
-            .removePrefix(PREFIX)
-            .decodeBase45()
-            .decompress()
-            .parse()
-
-        return VaccinationCertificateQRCode(
-            parsedData = parsedData,
-            qrCodeString = rawString,
-        )
-    }
-
-    private fun String.decodeBase45(): ByteArray = try {
-        Base45Decoder.decode(this)
-    } catch (e: Throwable) {
-        Timber.e(e)
-        throw InvalidHealthCertificateException(HC_BASE45_DECODING_FAILED)
-    }
-
-    private fun ByteArray.decompress(): RawCOSEObject = try {
-        this.inflate(sizeLimit = DEFAULT_SIZE_LIMIT)
-    } catch (e: Throwable) {
-        Timber.e(e)
-        throw InvalidHealthCertificateException(HC_ZLIB_DECOMPRESSION_FAILED)
-    }
-
-    fun RawCOSEObject.parse(): VaccinationCertificateData {
-        Timber.v("Parsing COSE for vaccination certificate.")
-        val cbor = coseDecoder.decode(this)
-
-        return VaccinationCertificateData(
-            header = headerParser.parse(cbor),
-            certificate = bodyParser.parse(cbor)
-        ).also {
-            CertificateQrCodeCensor.addCertificateToCensor(it)
-        }.also {
-            Timber.v("Parsed vaccination certificate for %s", it.certificate.nameData.familyNameStandardized)
-        }
-    }
-
-    companion object {
-        private const val PREFIX = "HC1:"
-
-        // Zip bomb
-        private const val DEFAULT_SIZE_LIMIT = 1024L * 1024 * 10L // 10 MB
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt
deleted file mode 100644
index 3c51b6df3aff83058514b6825a8497d602190d8e..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.repository
-
-import dagger.Reusable
-import de.rki.coronawarnapp.util.coroutine.AppScope
-import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
-import de.rki.coronawarnapp.util.flow.HotDataFlow
-import de.rki.coronawarnapp.vaccination.core.repository.storage.ValueSetsStorage
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationServer
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet
-import de.rki.coronawarnapp.vaccination.core.server.valueset.emptyVaccinationValueSet
-import de.rki.coronawarnapp.vaccination.core.server.valueset.isEmpty
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.distinctUntilChangedBy
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.plus
-import timber.log.Timber
-import java.util.Locale
-import javax.inject.Inject
-
-@Reusable
-class ValueSetsRepository @Inject constructor(
-    private val vaccinationServer: VaccinationServer,
-    private val valueSetsStorage: ValueSetsStorage,
-    @AppScope private val scope: CoroutineScope,
-    dispatcherProvider: DispatcherProvider
-) {
-
-    private fun Flow<VaccinationValueSet>.distinctUntilChangedByHash() = distinctUntilChangedBy { it.hashCode() }
-
-    private val internalData: HotDataFlow<VaccinationValueSet> = HotDataFlow(
-        loggingTag = TAG,
-        scope = scope,
-        coroutineContext = dispatcherProvider.IO,
-        sharingBehavior = SharingStarted.Lazily,
-        startValueProvider = {
-            valueSetsStorage.vaccinationValueSet.also { Timber.v("Loaded initial value set %s", it) }
-        }
-    )
-
-    init {
-        internalData.data
-            .distinctUntilChangedByHash()
-            .onStart { Timber.d("Observing value set") }
-            .onEach { valueSetsStorage.vaccinationValueSet = it }
-            .catch { Timber.e(it, "Storing new value set failed.") }
-            .launchIn(scope + dispatcherProvider.IO)
-    }
-
-    val latestValueSet: Flow<VaccinationValueSet> = internalData.data.distinctUntilChangedByHash()
-
-    fun triggerUpdateValueSet(languageCode: Locale) {
-        Timber.d("triggerUpdateValueSet(languageCode=%s)", languageCode)
-        internalData.updateAsync(
-            onUpdate = { getValueSetFromServer(languageCode = languageCode) ?: this },
-            onError = { Timber.e(it, "Updating value set failed") }
-        )
-    }
-
-    private suspend fun getValueSetFromServer(languageCode: Locale): VaccinationValueSet? {
-        Timber.v("getValueSetFromServer(languageCode=%s)", languageCode)
-        var valueSet = vaccinationServer.getVaccinationValueSets(languageCode = languageCode)
-
-        if (valueSet.isEmpty()) {
-            Timber.d(
-                "Got no value set from server for %s and local value set is empty... Try fallback to value set for en",
-                languageCode.language
-            )
-            valueSet = vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH)
-        }
-
-        return valueSet
-            .also { Timber.v("New value set %s", it) }
-    }
-
-    suspend fun clear() {
-        Timber.d("Clearing value sets")
-        vaccinationServer.clear()
-        internalData.updateBlocking {
-            Timber.v("Resetting value set to an empty value set")
-            emptyVaccinationValueSet
-        }
-    }
-}
-
-private const val TAG = "ValueSetsRepository"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinatedPersonNotFoundException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinatedPersonNotFoundException.kt
deleted file mode 100644
index 34e54c6f088361b3679092e07e728ca63d970a28..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinatedPersonNotFoundException.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.repository.errors
-
-import de.rki.coronawarnapp.vaccination.core.VaccinationException
-
-class VaccinatedPersonNotFoundException(
-    message: String
-) : VaccinationException(
-    message = message,
-    cause = null
-)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinationCertificateNotFoundException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinationCertificateNotFoundException.kt
deleted file mode 100644
index 2b3562f9093a0d15fe7e7c812d0de28f299ac056..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinationCertificateNotFoundException.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.repository.errors
-
-import de.rki.coronawarnapp.vaccination.core.VaccinationException
-
-class VaccinationCertificateNotFoundException(
-    message: String
-) : VaccinationException(
-    message = message,
-    cause = null
-)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorage.kt
deleted file mode 100644
index 63c2246e457b96b251dae2590186c4b5e108a214..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorage.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.repository.storage
-
-import android.content.Context
-import android.content.SharedPreferences
-import androidx.annotation.Keep
-import androidx.annotation.VisibleForTesting
-import androidx.core.content.edit
-import com.google.gson.Gson
-import com.google.gson.annotations.SerializedName
-import dagger.Reusable
-import de.rki.coronawarnapp.util.di.AppContext
-import de.rki.coronawarnapp.util.serialization.BaseGson
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet
-import de.rki.coronawarnapp.vaccination.core.server.valueset.emptyVaccinationValueSet
-import timber.log.Timber
-import java.util.Locale
-import javax.inject.Inject
-
-@Reusable
-class ValueSetsStorage @Inject constructor(
-    @AppContext private val context: Context,
-    @BaseGson private val gson: Gson
-) {
-
-    private val prefs: SharedPreferences by lazy {
-        context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
-    }
-
-    var vaccinationValueSet: VaccinationValueSet
-        get() = getValueSet()
-        set(value) = setValueSet(value)
-
-    private fun getValueSet(): VaccinationValueSet {
-        Timber.v("Loading value set")
-        val valueSetString = prefs.getString(PKEY_VALUE_SETS_PREFIX, null)
-        return when (valueSetString != null) {
-            true -> gson.fromJson(valueSetString, StoredVaccinationValueSet::class.java)
-            else -> emptyVaccinationValueSet
-        }.also { loaded -> Timber.v("Loaded value set %s", loaded) }
-    }
-
-    private fun setValueSet(value: VaccinationValueSet) {
-        Timber.v("Saving value set %s", value)
-        prefs.edit {
-            val json = gson.toJson(value.toStoredVaccinationValueSet(), StoredVaccinationValueSet::class.java)
-            Timber.v("Writing %s to prefs", json)
-            putString(PKEY_VALUE_SETS_PREFIX, json)
-        }
-    }
-
-    @VisibleForTesting
-    fun VaccinationValueSet.toStoredVaccinationValueSet(): StoredVaccinationValueSet =
-        StoredVaccinationValueSet(
-            languageCode = languageCode,
-            vp = vp.toStoredValueSet(),
-            mp = mp.toStoredValueSet(),
-            ma = ma.toStoredValueSet()
-        )
-
-    @VisibleForTesting
-    fun VaccinationValueSet.ValueSet.toStoredValueSet(): StoredVaccinationValueSet.StoredValueSet =
-        StoredVaccinationValueSet.StoredValueSet(
-            items = items.map { it.toStoredItem() }
-        )
-
-    @VisibleForTesting
-    fun VaccinationValueSet.ValueSet.Item.toStoredItem():
-        StoredVaccinationValueSet.StoredValueSet.StoredItem =
-            StoredVaccinationValueSet.StoredValueSet.StoredItem(
-                key = key,
-                displayText = displayText
-            )
-
-    @VisibleForTesting
-    data class StoredVaccinationValueSet(
-        @SerializedName("languageCode") override val languageCode: Locale,
-        @SerializedName("vp") override val vp: StoredValueSet,
-        @SerializedName("mp") override val mp: StoredValueSet,
-        @SerializedName("ma") override val ma: StoredValueSet
-    ) : VaccinationValueSet {
-
-        @Keep
-        data class StoredValueSet(
-            @SerializedName("items") override val items: List<StoredItem>
-        ) : VaccinationValueSet.ValueSet {
-
-            @Keep
-            data class StoredItem(
-                @SerializedName("key") override val key: String,
-                @SerializedName("displayText") override val displayText: String
-            ) : VaccinationValueSet.ValueSet.Item
-        }
-    }
-}
-
-private const val PREF_NAME = "valuesets_localdata"
-private const val PKEY_VALUE_SETS_PREFIX = "valueset"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/VaccinationServerModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/VaccinationServerModule.kt
deleted file mode 100644
index 0b7411416d8d8bd90e5f36241c5f211f6c43ed6f..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/VaccinationServerModule.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.server
-
-import dagger.Module
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSetModule
-
-@Module(
-    includes = [
-        VaccinationValueSetModule::class
-    ]
-)
-abstract class VaccinationServerModule
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/DefaultVaccinationValueSet.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/DefaultVaccinationValueSet.kt
deleted file mode 100644
index c7635321913b9267d867927ad2359afb41f7968d..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/DefaultVaccinationValueSet.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.server.valueset
-
-import java.util.Locale
-
-data class DefaultVaccinationValueSet(
-    override val languageCode: Locale,
-    override val vp: VaccinationValueSet.ValueSet,
-    override val mp: VaccinationValueSet.ValueSet,
-    override val ma: VaccinationValueSet.ValueSet
-) : VaccinationValueSet {
-
-    data class DefaultValueSet(
-        override val items: List<VaccinationValueSet.ValueSet.Item>
-    ) : VaccinationValueSet.ValueSet {
-
-        data class DefaultItem(
-            override val key: String,
-            override val displayText: String
-        ) : VaccinationValueSet.ValueSet.Item
-    }
-}
-
-internal val emptyVaccinationValueSet: VaccinationValueSet by lazy {
-    DefaultVaccinationValueSet(
-        languageCode = Locale.ENGLISH,
-        vp = DefaultVaccinationValueSet.DefaultValueSet(items = emptyList()),
-        mp = DefaultVaccinationValueSet.DefaultValueSet(items = emptyList()),
-        ma = DefaultVaccinationValueSet.DefaultValueSet(items = emptyList())
-    )
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt
deleted file mode 100644
index 23d5350fad4c4018dd2691784541febcb8ff42ad..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.server.valueset
-
-import java.util.Locale
-
-interface VaccinationValueSet {
-    val languageCode: Locale
-    val vp: ValueSet
-    val mp: ValueSet
-    val ma: ValueSet
-
-    interface ValueSet {
-        val items: List<Item>
-
-        // Use custom item instead of map to allow for future extensions
-        interface Item {
-            val key: String
-            val displayText: String
-        }
-    }
-}
-
-fun VaccinationValueSet.getDisplayText(key: String): String? =
-    vp.getDisplayText(key) ?: mp.getDisplayText(key) ?: ma.getDisplayText(key)
-
-fun VaccinationValueSet.ValueSet.getDisplayText(key: String): String? = items.find { key == it.key }?.displayText
-
-fun VaccinationValueSet?.isEmpty(): Boolean = (this == null) || (vp.isEmpty() && mp.isEmpty() && ma.isEmpty())
-
-fun VaccinationValueSet.ValueSet.isEmpty(): Boolean = items.isEmpty()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/VaccinationValueSetMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/VaccinationValueSetMapper.kt
deleted file mode 100644
index ad13f40aace7a84a4d73ac99b0d5b836fa8a2185..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/VaccinationValueSetMapper.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.server.valueset.internal
-
-import de.rki.coronawarnapp.server.protocols.internal.dgc.ValueSetsOuterClass
-import de.rki.coronawarnapp.vaccination.core.server.valueset.DefaultVaccinationValueSet
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet
-import timber.log.Timber
-import java.util.Locale
-
-internal fun ValueSetsOuterClass.ValueSets.toVaccinationValueSet(languageCode: Locale): VaccinationValueSet {
-    Timber.d("toVaccinationValueSet(valueSets=%s, languageCode=%s)", this, languageCode)
-    return DefaultVaccinationValueSet(
-        languageCode = languageCode,
-        vp = vp.toValueSet(),
-        mp = mp.toValueSet(),
-        ma = ma.toValueSet()
-    ).also { Timber.tag(TAG).d("Created %s", it) }
-}
-
-internal fun ValueSetsOuterClass.ValueSet.toValueSet(): VaccinationValueSet.ValueSet =
-    DefaultVaccinationValueSet.DefaultValueSet(items = itemsList.map { it.toItem() })
-
-internal fun ValueSetsOuterClass.ValueSetItem.toItem(): VaccinationValueSet.ValueSet.Item =
-    DefaultVaccinationValueSet.DefaultValueSet.DefaultItem(
-        key = key,
-        displayText = displayText
-    )
-
-private const val TAG: String = "ValueSetMapper"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/VaccinationUIModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/VaccinationUIModule.kt
deleted file mode 100644
index e01ea64a568da58ef96cea1812d585aec6ea2f9c..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/VaccinationUIModule.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package de.rki.coronawarnapp.vaccination.ui
-
-import dagger.Module
-import dagger.android.ContributesAndroidInjector
-import de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentFragment
-import de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentFragmentModule
-import de.rki.coronawarnapp.vaccination.ui.details.VaccinationDetailsFragment
-import de.rki.coronawarnapp.vaccination.ui.details.VaccinationDetailsFragmentModule
-import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragment
-import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragmentModule
-import de.rki.coronawarnapp.vaccination.ui.scan.VaccinationQrCodeScanFragment
-import de.rki.coronawarnapp.vaccination.ui.scan.VaccinationQrCodeScanModule
-
-@Module
-abstract class VaccinationUIModule {
-
-    @ContributesAndroidInjector(modules = [VaccinationListFragmentModule::class])
-    abstract fun vaccinationListFragment(): VaccinationListFragment
-
-    @ContributesAndroidInjector(modules = [VaccinationDetailsFragmentModule::class])
-    abstract fun vaccinationDetailsFragment(): VaccinationDetailsFragment
-
-    @ContributesAndroidInjector(modules = [VaccinationQrCodeScanModule::class])
-    abstract fun vaccinationQrCodeScanFragment(): VaccinationQrCodeScanFragment
-
-    @ContributesAndroidInjector(modules = [VaccinationConsentFragmentModule::class])
-    abstract fun vaccinationConsentFragment(): VaccinationConsentFragment
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/VaccinationStatusItem.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/VaccinationStatusItem.kt
deleted file mode 100644
index 18a09e0e752c94ff893aeeefac0e0c26ab36643e..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/cards/VaccinationStatusItem.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package de.rki.coronawarnapp.vaccination.ui.cards
-
-import de.rki.coronawarnapp.greencertificate.ui.certificates.items.CertificatesItem
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
-
-interface VaccinationStatusItem : CertificatesItem {
-    val vaccinatedPerson: VaccinatedPerson
-
-    override val stableId: Long
-        get() = vaccinatedPerson.identifier.hashCode().toLong()
-}
diff --git a/Corona-Warn-App/src/main/res/drawable/ic_complete_vaccination_shield.xml b/Corona-Warn-App/src/main/res/drawable/ic_complete_vaccination_shield.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d37d51142b63f2025174d5a1b3e0392a1f76e606
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/ic_complete_vaccination_shield.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="111dp"
+    android:height="189dp"
+    android:viewportWidth="111"
+    android:viewportHeight="189">
+  <path
+      android:pathData="M75.5,0.75L0.5,28.875V85.969C0.5,133.312 32.469,177.469 75.5,188.25C118.531,177.469 150.5,133.312 150.5,85.969V28.875L75.5,0.75ZM131.75,85.969C131.75,123.469 107.844,158.156 75.5,168.75C43.156,158.156 19.25,123.562 19.25,85.969V41.156L75.5,21.281L131.75,41.156V85.969ZM45.688,81.281L32.375,94.5L65.563,127.688L118.625,74.625L105.406,61.406L65.656,101.156L45.688,81.281Z"
+      android:fillColor="#007FAD"/>
+</vector>
diff --git a/Corona-Warn-App/src/main/res/drawable/ic_eu_stars.xml b/Corona-Warn-App/src/main/res/drawable/ic_eu_stars.xml
new file mode 100644
index 0000000000000000000000000000000000000000..04d246e2d1f25ee0486bbe9181a6b2b7319a6a32
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/ic_eu_stars.xml
@@ -0,0 +1,76 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="105dp"
+    android:height="200dp"
+    android:viewportWidth="105"
+    android:viewportHeight="200">
+  <path
+      android:pathData="M112.879,-9L110.99,-3.328H104.902L109.94,0.453L108.051,6.125L112.879,2.554L117.918,6.125L116.028,0.243L120.857,-3.118H114.769L112.879,-9Z"
+      android:fillColor="#ffffff"
+      android:fillAlpha="0.2"/>
+  <path
+      android:strokeWidth="1"
+      android:pathData="M113.356,-9.153L112.888,-10.608L112.405,-9.158L110.63,-3.828H104.902H103.403L104.602,-2.928L109.352,0.637L107.577,5.967L107.077,7.467L108.348,6.527L112.886,3.171L117.629,6.533L118.853,7.4L118.394,5.972L116.618,0.442L121.143,-2.708L122.45,-3.618H120.857H115.133L113.356,-9.153Z"
+      android:strokeAlpha="0.2"
+      android:fillColor="#00000000"
+      android:strokeColor="#ffffff"/>
+  <path
+      android:pathData="M62.496,4.654L60.607,10.326H54.519L59.557,14.107L57.668,19.779L62.496,16.208L67.325,19.779L65.435,13.897L70.474,10.536H64.386L62.496,4.654Z"
+      android:fillColor="#ffffff"
+      android:fillAlpha="0.2"/>
+  <path
+      android:strokeWidth="1"
+      android:pathData="M62.972,4.501L62.505,3.046L62.022,4.496L60.246,9.826H54.519H53.02L54.219,10.726L58.969,14.291L57.193,19.621L56.694,21.122L57.965,20.181L62.496,16.83L67.027,20.181L68.275,21.104L67.801,19.626L66.027,14.104L70.751,10.952L72.124,10.036H70.474H64.75L62.972,4.501Z"
+      android:strokeAlpha="0.2"
+      android:fillColor="#00000000"
+      android:strokeColor="#ffffff"/>
+  <path
+      android:pathData="M25.758,41.626L23.869,47.508H17.781L22.819,51.079L20.93,56.751L25.758,53.18L30.587,56.751L28.697,51.079L33.736,47.508H27.647L25.758,41.626Z"
+      android:fillColor="#ffffff"
+      android:fillAlpha="0.2"/>
+  <path
+      android:strokeWidth="1"
+      android:pathData="M26.234,41.474L25.758,39.992L25.282,41.474L23.504,47.008H17.781H16.211L17.492,47.916L22.228,51.273L20.455,56.593L19.955,58.094L21.227,57.153L25.758,53.802L30.289,57.153L31.561,58.094L31.061,56.593L29.289,51.273L34.025,47.916L35.306,47.008H33.736H28.012L26.234,41.474Z"
+      android:strokeAlpha="0.2"
+      android:fillColor="#00000000"
+      android:strokeColor="#ffffff"/>
+  <path
+      android:pathData="M11.903,92.043L10.013,97.714H3.925L8.754,101.285L6.864,107.167L11.903,103.596L16.731,107.167L14.842,101.285L19.67,97.924H13.792L11.903,92.043Z"
+      android:fillColor="#ffffff"
+      android:fillAlpha="0.2"/>
+  <path
+      android:strokeWidth="1"
+      android:pathData="M12.379,91.89L11.911,90.435L11.428,91.884L9.653,97.214H3.925H2.408L3.628,98.116L8.168,101.474L6.388,107.014L5.929,108.443L7.153,107.575L11.896,104.213L16.434,107.569L17.682,108.492L17.207,107.014L15.431,101.485L19.956,98.335L21.264,97.424H19.67H14.157L12.379,91.89Z"
+      android:strokeAlpha="0.2"
+      android:fillColor="#00000000"
+      android:strokeColor="#ffffff"/>
+  <path
+      android:pathData="M25.548,142.669L23.659,148.341H17.571L22.399,151.912L20.51,157.584L25.548,154.013L30.377,157.584L28.487,151.912L33.316,148.341H27.438L25.548,142.669Z"
+      android:fillColor="#ffffff"
+      android:fillAlpha="0.2"/>
+  <path
+      android:strokeWidth="1"
+      android:pathData="M26.023,142.511L25.548,141.087L25.074,142.511L23.298,147.841H17.571H16.054L17.274,148.743L21.81,152.098L20.035,157.426L19.553,158.875L20.799,157.992L25.542,154.63L30.079,157.986L31.351,158.926L30.851,157.426L29.076,152.098L33.613,148.743L34.833,147.841H33.316H27.798L26.023,142.511Z"
+      android:strokeAlpha="0.2"
+      android:fillColor="#00000000"
+      android:strokeColor="#ffffff"/>
+  <path
+      android:pathData="M62.496,179.641L60.607,185.313H54.519L59.347,188.884L57.458,194.766L62.496,191.195L67.325,194.766L65.435,188.884L70.264,185.313H64.386L62.496,179.641Z"
+      android:fillColor="#ffffff"
+      android:fillAlpha="0.2"/>
+  <path
+      android:strokeWidth="1"
+      android:pathData="M62.971,179.483L62.496,178.059L62.022,179.483L60.246,184.813H54.519H53.002L54.222,185.715L58.762,189.073L56.982,194.613L56.523,196.042L57.747,195.174L62.49,191.812L67.027,195.168L68.275,196.091L67.801,194.613L66.021,189.073L70.561,185.715L71.781,184.813H70.264H64.746L62.971,179.483Z"
+      android:strokeAlpha="0.2"
+      android:fillColor="#00000000"
+      android:strokeColor="#ffffff"/>
+  <path
+      android:pathData="M112.879,193.085L110.99,198.757H104.902L109.94,202.328L108.051,208L112.879,204.429L117.918,208L116.028,202.328L120.857,198.757H114.769L112.879,193.085Z"
+      android:fillColor="#ffffff"
+      android:fillAlpha="0.2"/>
+  <path
+      android:strokeWidth="1"
+      android:pathData="M113.354,192.927L112.879,191.503L112.405,192.927L110.63,198.257H104.902H103.332L104.613,199.165L109.349,202.522L107.577,207.842L107.077,209.342L108.348,208.402L112.886,205.046L117.629,208.408L118.875,209.291L118.392,207.842L116.617,202.514L121.154,199.159L122.374,198.257H120.857H115.129L113.354,192.927Z"
+      android:strokeAlpha="0.2"
+      android:fillColor="#00000000"
+      android:strokeColor="#ffffff"/>
+</vector>
diff --git a/Corona-Warn-App/src/main/res/drawable/ic_half_white_half_gray_shield.xml b/Corona-Warn-App/src/main/res/drawable/ic_half_white_half_gray_shield.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a3cf8929fe0eac92776df2631481582e95bdaf91
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/ic_half_white_half_gray_shield.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="18dp"
+    android:height="22dp"
+    android:viewportWidth="18"
+    android:viewportHeight="22">
+  <path
+      android:pathData="M7.1729,20.9509V2.4925V1.4556L16.5144,4.7739V11.8255L13.9897,17.6326L7.1729,20.9509Z"
+      android:fillColor="#616F7E"/>
+  <path
+      android:pathData="M9.0002,0L0.2002,3.3V9.999C0.2002,15.554 3.9512,20.735 9.0002,22C14.0492,20.735 17.8002,15.554 17.8002,9.999V3.3L9.0002,0ZM15.6002,9.999C15.6002,14.399 12.7952,18.469 9.0002,19.712C5.2052,18.469 2.4002,14.41 2.4002,9.999V4.829L9.0002,2.354L15.6002,4.829V9.999Z"
+      android:fillColor="#ffffff"/>
+  <path
+      android:pathData="M9.0004,20.3417V2.2678V1.2524L1.4866,4.5017V11.4063L3.5173,17.0924L9.0004,20.3417Z"
+      android:fillColor="#ffffff"/>
+</vector>
diff --git a/Corona-Warn-App/src/main/res/drawable/ic_incomplete_vaccination_shield.xml b/Corona-Warn-App/src/main/res/drawable/ic_incomplete_vaccination_shield.xml
new file mode 100644
index 0000000000000000000000000000000000000000..91692016cc895dee0ce5aff3c8d2918290074721
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/ic_incomplete_vaccination_shield.xml
@@ -0,0 +1,14 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="111dp"
+    android:height="188dp"
+    android:viewportWidth="111"
+    android:viewportHeight="188">
+  <path
+      android:pathData="M75.7,0.75L0.8,28.837V85.855C0.8,133.136 32.726,177.233 75.7,188C118.674,177.233 150.6,133.136 150.6,85.855V28.837L75.7,0.75ZM131.875,85.855C131.875,123.305 108,157.946 75.7,168.526C43.399,157.946 19.525,123.399 19.525,85.855V41.851L75.7,20.786L131.875,41.851V85.855Z"
+      android:fillColor="#ffffff"
+      android:fillAlpha="0.05"/>
+  <path
+      android:pathData="M75.7,168.526V20.786L19.525,41.851V85.855C19.525,85.855 18,113 37.049,139.5C53.698,162.66 75.7,168.526 75.7,168.526Z"
+      android:fillColor="#ffffff"
+      android:fillAlpha="0.05"/>
+</vector>
diff --git a/Corona-Warn-App/src/main/res/drawable/ic_white_shield_with_checkmark.xml b/Corona-Warn-App/src/main/res/drawable/ic_white_shield_with_checkmark.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d6e0f2ac23a1d0171efc9810f6a5e55e0a2c831e
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/ic_white_shield_with_checkmark.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="18dp"
+    android:height="22dp"
+    android:viewportWidth="18"
+    android:viewportHeight="22">
+  <path
+      android:pathData="M9,0L0,4V10C0,15.55 3.84,20.74 9,22C14.16,20.74 18,15.55 18,10V4L9,0Z"
+      android:fillColor="#ffffff"/>
+  <path
+      android:pathData="m5.141,10.1508 l-1.41,1.4968 4,4.2463 8,-8.4926 -1.41,-1.5074 -6.59,6.9958z"
+      android:fillColor="#007fad"/>
+</vector>
diff --git a/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_complete.xml b/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_complete.xml
deleted file mode 100644
index 29d4300db7f6465d9bbf75efd976043b3d8d1414..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_complete.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="78dp"
-    android:height="72dp"
-    android:viewportWidth="78"
-    android:viewportHeight="72">
-  <path
-      android:pathData="M44.2499,0V4.3846H46.4422V6.7139C42.0319,7.1507 38.0498,8.8463 34.7956,11.5096L33.1513,9.8654L34.6586,8.3582L31.5756,5.2752L25.4098,11.4411L28.4927,14.524L29.9999,13.0168L31.6441,14.6611C28.9808,17.9153 27.2852,21.8974 26.8485,26.3077H24.5191V24.1154H20.1345V32.8846H24.5191V30.6923H26.8485C27.2852,35.1369 29.0151,39.1447 31.7126,42.4075L29.9999,43.9832L28.4927,42.476L25.4098,45.5589L31.5756,51.7248L34.6586,48.6418L33.1513,47.1346L34.7956,45.4219C38.0583,48.1023 42.0233,49.8493 46.4422,50.2861V52.6154H44.2499V57H53.0191V52.6154H50.8268V50.2861C55.2457,49.8493 59.2107,48.1023 62.4735,45.4219H62.542L64.1177,47.1346L62.6105,48.6418L65.6934,51.7248L71.8593,45.5589L68.7763,42.476L67.2691,43.9832L65.5564,42.4075C65.5607,42.3989 65.5585,42.386 65.5564,42.3732C65.5543,42.3604 65.5521,42.3475 65.5564,42.3389C68.2368,39.0762 69.9838,35.1112 70.4206,30.6923H72.7499V32.8846H77.1345V24.1154H72.7499V26.3077H70.4206C69.9838,21.8974 68.2882,17.9153 65.6249,14.6611L67.2691,13.0168L68.7763,14.524L71.8593,11.4411L65.6934,5.2752L62.6105,8.3582L64.1177,9.8654L62.4735,11.5096C59.2193,8.8463 55.2371,7.1507 50.8268,6.7139V4.3846H53.0191V0H44.2499ZM48.635,10.9604C58.3462,10.9604 66.1734,18.7876 66.1734,28.4989C66.1734,38.2101 58.3462,46.0373 48.635,46.0373C38.9237,46.0373 31.0965,38.2101 31.0965,28.4989C31.0965,18.7876 38.9237,10.9604 48.635,10.9604ZM39.865,18.9777C39.865,17.1622 41.338,15.6893 43.1535,15.6893C44.969,15.6893 46.4419,17.1622 46.4419,18.9777C46.4419,20.7933 44.969,22.2662 43.1535,22.2662C41.338,22.2662 39.865,20.7933 39.865,18.9777ZM54.1155,15.6893C52.3,15.6893 50.827,17.1622 50.827,18.9777C50.827,20.7933 52.3,22.2662 54.1155,22.2662C55.931,22.2662 57.4039,20.7933 57.4039,18.9777C57.4039,17.1622 55.931,15.6893 54.1155,15.6893ZM34.3846,28.499C34.3846,26.6834 35.8575,25.2105 37.673,25.2105C39.4886,25.2105 40.9615,26.6834 40.9615,28.499C40.9615,30.3145 39.4886,31.7874 37.673,31.7874C35.8575,31.7874 34.3846,30.3145 34.3846,28.499ZM48.635,25.2105C46.8195,25.2105 45.3466,26.6834 45.3466,28.499C45.3466,30.3145 46.8195,31.7874 48.635,31.7874C50.4505,31.7874 51.9235,30.3145 51.9235,28.499C51.9235,26.6834 50.4505,25.2105 48.635,25.2105ZM56.3072,28.499C56.3072,26.6834 57.7802,25.2105 59.5957,25.2105C61.4112,25.2105 62.8841,26.6834 62.8841,28.499C62.8841,30.3145 61.4112,31.7874 59.5957,31.7874C57.7802,31.7874 56.3072,30.3145 56.3072,28.499ZM43.1535,34.7339C41.338,34.7339 39.865,36.2069 39.865,38.0224C39.865,39.8379 41.338,41.3108 43.1535,41.3108C44.969,41.3108 46.4419,39.8379 46.4419,38.0224C46.4419,36.2069 44.969,34.7339 43.1535,34.7339ZM50.827,38.0224C50.827,36.2069 52.3,34.7339 54.1155,34.7339C55.931,34.7339 57.4039,36.2069 57.4039,38.0224C57.4039,39.8379 55.931,41.3108 54.1155,41.3108C52.3,41.3108 50.827,39.8379 50.827,38.0224Z"
-      android:fillColor="#ffffff"
-      android:fillAlpha="0.2"
-      android:fillType="evenOdd"/>
-  <path
-      android:pathData="M22,18L0,27.8182V42.5455C0,56.1682 9.3867,68.9073 22,72C34.6133,68.9073 44,56.1682 44,42.5455V27.8182L22,18Z"
-      android:fillColor="#ffffff"/>
-  <path
-      android:pathData="M11.29,43.7909L8,47.2335L17.3333,57L36,37.4671L32.71,34L17.3333,50.0902L11.29,43.7909Z"
-      android:fillColor="#616F7E"/>
-</vector>
diff --git a/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_immune.xml b/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_immune.xml
deleted file mode 100644
index 47227abb719d617b587e8270164fbde8a3e9aaf8..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_immune.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="78dp"
-    android:height="72dp"
-    android:viewportWidth="78"
-    android:viewportHeight="72">
-  <path
-      android:pathData="M44.2502,0V4.3846H46.4425V6.7139C42.0321,7.1507 38.05,8.8463 34.7958,11.5096L33.1516,9.8654L34.6588,8.3582L31.5759,5.2752L25.41,11.4411L28.4929,14.524L30.0001,13.0168L31.6444,14.6611C28.9811,17.9153 27.2855,21.8974 26.8487,26.3077H24.5194V24.1154H20.1348V32.8846H24.5194V30.6923H26.8487C27.2855,35.1369 29.0153,39.1447 31.7129,42.4075L30.0001,43.9832L28.4929,42.476L25.41,45.5589L31.5759,51.7248L34.6588,48.6418L33.1516,47.1346L34.7958,45.4219C38.0586,48.1023 42.0236,49.8493 46.4425,50.2861V52.6154H44.2502V57H53.0194V52.6154H50.8271V50.2861C55.2459,49.8493 59.2109,48.1023 62.4737,45.4219H62.5422L64.1179,47.1346L62.6107,48.6418L65.6937,51.7248L71.8595,45.5589L68.7766,42.476L67.2694,43.9832L65.5566,42.4075C65.5609,42.3989 65.5588,42.386 65.5566,42.3732C65.5545,42.3604 65.5524,42.3475 65.5566,42.3389C68.2371,39.0762 69.9841,35.1112 70.4208,30.6923H72.7501V32.8846H77.1348V24.1154H72.7501V26.3077H70.4208C69.9841,21.8974 68.2885,17.9153 65.6251,14.6611L67.2694,13.0168L68.7766,14.524L71.8595,11.4411L65.6937,5.2752L62.6107,8.3582L64.1179,9.8654L62.4737,11.5096C59.2195,8.8463 55.2374,7.1507 50.8271,6.7139V4.3846H53.0194V0H44.2502ZM48.6352,10.9604C58.3465,10.9604 66.1737,18.7876 66.1737,28.4989C66.1737,38.2101 58.3465,46.0373 48.6352,46.0373C38.924,46.0373 31.0968,38.2101 31.0968,28.4989C31.0968,18.7876 38.924,10.9604 48.6352,10.9604ZM39.8653,18.9777C39.8653,17.1622 41.3382,15.6893 43.1537,15.6893C44.9692,15.6893 46.4422,17.1622 46.4422,18.9777C46.4422,20.7933 44.9692,22.2662 43.1537,22.2662C41.3382,22.2662 39.8653,20.7933 39.8653,18.9777ZM54.1157,15.6893C52.3002,15.6893 50.8273,17.1622 50.8273,18.9777C50.8273,20.7933 52.3002,22.2662 54.1157,22.2662C55.9312,22.2662 57.4042,20.7933 57.4042,18.9777C57.4042,17.1622 55.9312,15.6893 54.1157,15.6893ZM34.3848,28.499C34.3848,26.6834 35.8578,25.2105 37.6733,25.2105C39.4888,25.2105 40.9618,26.6834 40.9618,28.499C40.9618,30.3145 39.4888,31.7874 37.6733,31.7874C35.8578,31.7874 34.3848,30.3145 34.3848,28.499ZM48.6353,25.2105C46.8198,25.2105 45.3468,26.6834 45.3468,28.499C45.3468,30.3145 46.8198,31.7874 48.6353,31.7874C50.4508,31.7874 51.9237,30.3145 51.9237,28.499C51.9237,26.6834 50.4508,25.2105 48.6353,25.2105ZM56.3075,28.499C56.3075,26.6834 57.7804,25.2105 59.5959,25.2105C61.4114,25.2105 62.8844,26.6834 62.8844,28.499C62.8844,30.3145 61.4114,31.7874 59.5959,31.7874C57.7804,31.7874 56.3075,30.3145 56.3075,28.499ZM43.1537,34.7339C41.3382,34.7339 39.8653,36.2069 39.8653,38.0224C39.8653,39.8379 41.3382,41.3108 43.1537,41.3108C44.9692,41.3108 46.4422,39.8379 46.4422,38.0224C46.4422,36.2069 44.9692,34.7339 43.1537,34.7339ZM50.8273,38.0224C50.8273,36.2069 52.3002,34.7339 54.1157,34.7339C55.9312,34.7339 57.4042,36.2069 57.4042,38.0224C57.4042,39.8379 55.9312,41.3108 54.1157,41.3108C52.3002,41.3108 50.8273,39.8379 50.8273,38.0224Z"
-      android:fillColor="#ffffff"
-      android:fillAlpha="0.2"
-      android:fillType="evenOdd" />
-  <path
-      android:pathData="M22,18L0,27.8182V42.5455C0,56.1682 9.3867,68.9073 22,72C34.6133,68.9073 44,56.1682 44,42.5455V27.8182L22,18Z"
-      android:fillColor="#ffffff" />
-  <path
-      android:pathData="M11.29,43.7909L8,47.2335L17.3333,57L36,37.4671L32.71,34L17.3333,50.0902L11.29,43.7909Z"
-      android:fillColor="#007FAD" />
-</vector>
diff --git a/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_incomplete.xml b/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_incomplete.xml
deleted file mode 100644
index f51cc4182dc3e363ea51e1759488a01cf48f9831..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_incomplete.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="78dp"
-    android:height="73dp"
-    android:viewportWidth="78"
-    android:viewportHeight="73">
-  <path
-      android:pathData="M44.4167,0V4.3846H46.609V6.7139C42.1987,7.1507 38.2165,8.8463 34.9623,11.5096L33.3181,9.8654L34.8253,8.3582L31.7424,5.2752L25.5765,11.4411L28.6594,14.524L30.1667,13.0168L31.8109,14.6611C29.1476,17.9153 27.452,21.8974 27.0152,26.3077H24.6859V24.1154H20.3013V32.8846H24.6859V30.6923H27.0152C27.452,35.1369 29.1818,39.1447 31.8794,42.4075L30.1667,43.9832L28.6594,42.476L25.5765,45.5589L31.7424,51.7248L34.8253,48.6418L33.3181,47.1346L34.9623,45.4219C38.2251,48.1023 42.1901,49.8493 46.609,50.2861V52.6154H44.4167V57H53.1859V52.6154H50.9936V50.2861C55.4124,49.8493 59.3774,48.1023 62.6402,45.4219H62.7087L64.2844,47.1346L62.7772,48.6418L65.8602,51.7248L72.026,45.5589L68.9431,42.476L67.4359,43.9832L65.7231,42.4075C65.7274,42.3989 65.7253,42.386 65.7231,42.3732C65.721,42.3604 65.7189,42.3475 65.7231,42.3389C68.4036,39.0762 70.1506,35.1112 70.5873,30.6923H72.9166V32.8846H77.3013V24.1154H72.9166V26.3077H70.5873C70.1506,21.8974 68.455,17.9153 65.7916,14.6611L67.4359,13.0168L68.9431,14.524L72.026,11.4411L65.8602,5.2752L62.7772,8.3582L64.2844,9.8654L62.6402,11.5096C59.386,8.8463 55.4039,7.1507 50.9936,6.7139V4.3846H53.1859V0H44.4167ZM48.8017,10.9604C58.513,10.9604 66.3402,18.7876 66.3402,28.4989C66.3402,38.2101 58.513,46.0373 48.8017,46.0373C39.0905,46.0373 31.2633,38.2101 31.2633,28.4989C31.2633,18.7876 39.0905,10.9604 48.8017,10.9604ZM40.0318,18.9777C40.0318,17.1622 41.5047,15.6893 43.3202,15.6893C45.1357,15.6893 46.6087,17.1622 46.6087,18.9777C46.6087,20.7933 45.1357,22.2662 43.3202,22.2662C41.5047,22.2662 40.0318,20.7933 40.0318,18.9777ZM54.2822,15.6893C52.4667,15.6893 50.9938,17.1622 50.9938,18.9777C50.9938,20.7933 52.4667,22.2662 54.2822,22.2662C56.0977,22.2662 57.5707,20.7933 57.5707,18.9777C57.5707,17.1622 56.0977,15.6893 54.2822,15.6893ZM34.5513,28.499C34.5513,26.6834 36.0243,25.2105 37.8398,25.2105C39.6553,25.2105 41.1283,26.6834 41.1283,28.499C41.1283,30.3145 39.6553,31.7874 37.8398,31.7874C36.0243,31.7874 34.5513,30.3145 34.5513,28.499ZM48.8018,25.2105C46.9863,25.2105 45.5133,26.6834 45.5133,28.499C45.5133,30.3145 46.9863,31.7874 48.8018,31.7874C50.6173,31.7874 52.0902,30.3145 52.0902,28.499C52.0902,26.6834 50.6173,25.2105 48.8018,25.2105ZM56.474,28.499C56.474,26.6834 57.9469,25.2105 59.7624,25.2105C61.5779,25.2105 63.0509,26.6834 63.0509,28.499C63.0509,30.3145 61.5779,31.7874 59.7624,31.7874C57.9469,31.7874 56.474,30.3145 56.474,28.499ZM43.3202,34.7339C41.5047,34.7339 40.0318,36.2069 40.0318,38.0224C40.0318,39.8379 41.5047,41.3108 43.3202,41.3108C45.1357,41.3108 46.6087,39.8379 46.6087,38.0224C46.6087,36.2069 45.1357,34.7339 43.3202,34.7339ZM50.9938,38.0224C50.9938,36.2069 52.4667,34.7339 54.2822,34.7339C56.0977,34.7339 57.5707,36.2069 57.5707,38.0224C57.5707,39.8379 56.0977,41.3108 54.2822,41.3108C52.4667,41.3108 50.9938,39.8379 50.9938,38.0224Z"
-      android:fillColor="#ffffff"
-      android:fillAlpha="0.2"
-      android:fillType="evenOdd" />
-  <path
-      android:pathData="M17.167,70V24.5532V22L40.167,30.1702V47.5319L33.9508,61.8298L17.167,70Z"
-      android:fillColor="#616F7E" />
-  <path
-      android:pathData="M21.6667,18.4167L0,26.5417V43.0355C0,56.7126 9.2354,69.4688 21.6667,72.5834C34.0979,69.4688 43.3333,56.7126 43.3333,43.0355V26.5417L21.6667,18.4167ZM37.9167,43.0355C37.9167,53.8688 31.0104,63.8897 21.6667,66.9501C12.3229,63.8897 5.4167,53.8959 5.4167,43.0355V30.3063L21.6667,24.2126L37.9167,30.3063V43.0355Z"
-      android:fillColor="#ffffff" />
-  <path
-      android:pathData="M21.667,68.5V24V21.5L3.167,29.5V46.5L8.167,60.5L21.667,68.5Z"
-      android:fillColor="#ffffff" />
-</vector>
diff --git a/Corona-Warn-App/src/main/res/drawable/vaccination_test_success_gradient.xml b/Corona-Warn-App/src/main/res/drawable/vaccination_test_success_gradient.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d391deadf06bbbf197fc3fb1022764eb1fa3dbad
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/vaccination_test_success_gradient.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+        android:angle="180"
+        android:endColor="#2E854B"
+        android:startColor="#35B55F" />
+</shape>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/layout/covid_test_error_card.xml b/Corona-Warn-App/src/main/res/layout/covid_test_error_card.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d71d688299aaac25ba702daa4ca0ec8ee1ccb976
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/layout/covid_test_error_card.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout 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"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="200dp">
+
+    <TextView
+        android:id="@+id/card_title"
+        style="@style/headline5"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/card_padding"
+        android:layout_marginTop="@dimen/card_padding"
+        android:layout_marginEnd="@dimen/card_padding"
+        android:focusable="false"
+        android:text="@string/info_banner_title_1"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/vaccination_label"
+        style="@style/headline5"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/card_padding"
+        android:layout_marginEnd="@dimen/card_padding"
+        android:focusable="false"
+        android:text="@string/info_banner_title_2"
+        android:textStyle="bold"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/card_title" />
+
+    <TextView
+        android:id="@+id/body"
+        style="@style/subtitle"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/card_padding"
+        android:layout_marginTop="@dimen/spacing_small"
+        android:layout_marginEnd="@dimen/card_padding"
+        android:focusable="false"
+        android:text="@string/test_certificate_error_label"
+        android:textStyle="bold"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/vaccination_label" />
+
+    <TextView
+        android:id="@+id/test_time"
+        style="@style/body2"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/card_padding"
+        android:layout_marginTop="@dimen/spacing_mega_tiny"
+        android:layout_marginEnd="@dimen/card_padding"
+        android:focusable="false"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/body"
+        tools:text="Test durchgeführt am 12.04.21, 18:01 Uhr " />
+
+    <com.google.android.material.progressindicator.CircularProgressIndicator
+        android:id="@+id/progress_bar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/card_padding"
+        android:layout_marginTop="@dimen/spacing_small"
+        android:layout_marginEnd="@dimen/card_padding"
+        android:layout_marginBottom="@dimen/spacing_small"
+        android:indeterminate="true"
+        android:visibility="gone"
+        app:indicatorColor="@color/colorAccent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/test_time"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:showAnimationBehavior="inward"
+        app:trackColor="@android:color/transparent" />
+
+    <TextView
+        android:id="@+id/refresh_status"
+        style="@style/body2"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/spacing_small"
+        android:layout_marginEnd="@dimen/card_padding"
+        android:focusable="false"
+        android:visibility="gone"
+        android:text="@string/test_certificate_error_refreshing_status"
+        app:layout_constraintStart_toEndOf="@id/progress_bar"
+        app:layout_constraintTop_toTopOf="@id/progress_bar"
+        app:layout_constraintEnd_toEndOf="parent"
+        tools:text="@string/test_certificate_error_refreshing_status" />
+
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/retry_button"
+        style="@style/Widget.MaterialComponents.Button.OutlinedButton"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/card_padding"
+        android:layout_marginTop="@dimen/spacing_small"
+        android:layout_marginEnd="@dimen/card_padding"
+        android:layout_marginBottom="@dimen/spacing_small"
+        android:text="@string/test_certificate_error_retry_button"
+        android:textColor="@color/colorAccent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/test_time"
+        app:strokeColor="@color/colorAccent" />
+
+    <Button
+        android:id="@+id/delete_button"
+        style="@style/buttonLight"
+        android:backgroundTint="@color/button_main_tracing"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/card_padding"
+        android:layout_marginEnd="@dimen/card_padding"
+        android:layout_marginBottom="@dimen/spacing_small"
+        android:text="@string/test_certificate_error_delete_button"
+        android:textColor="@color/colorAccent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/retry_button"
+        app:strokeColor="@color/colorAccent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/layout/covid_test_success_card.xml b/Corona-Warn-App/src/main/res/layout/covid_test_success_card.xml
new file mode 100644
index 0000000000000000000000000000000000000000..985db99698b8ea87746cd30ba4799edbf9d88e4b
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/layout/covid_test_success_card.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout 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"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/vaccination_test_success_gradient"
+    android:minHeight="200dp"
+    tools:ignore="UnusedAttribute">
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:importantForAccessibility="no"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:srcCompat="@drawable/ic_eu_stars" />
+
+    <TextView
+        android:id="@+id/title1"
+        style="@style/headline5"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginHorizontal="@dimen/card_padding"
+        android:layout_marginTop="@dimen/spacing_small"
+        android:accessibilityHeading="true"
+        android:focusable="false"
+        android:text="@string/info_banner_title_1"
+        android:textColor="@color/colorTextPrimary1InvertedStable"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/title2"
+        style="@style/headline5"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginHorizontal="@dimen/card_padding"
+        android:accessibilityHeading="true"
+        android:focusable="false"
+        android:text="@string/info_banner_title_2"
+        android:textColor="@color/colorTextPrimary1InvertedStable"
+        android:textStyle="bold"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/title1" />
+
+    <ImageView
+        android:id="@+id/prc_icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginStart="@dimen/card_padding"
+        android:importantForAccessibility="no"
+        app:layout_constraintBottom_toBottomOf="@id/test_time"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@id/test_time"
+        app:srcCompat="@drawable/ic_risk_details_pcr"
+        app:tint="@color/colorStableLight" />
+
+    <TextView
+        android:id="@+id/person_name"
+        style="@style/body1"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginHorizontal="@dimen/card_padding"
+        android:layout_marginTop="@dimen/spacing_small"
+        android:accessibilityHeading="true"
+        android:focusable="false"
+        android:textColor="@color/colorTextPrimary1InvertedStable"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/title2"
+        tools:text="Andrea Schneider" />
+
+    <TextView
+        android:id="@+id/test_time"
+        style="@style/body2"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginBottom="@dimen/spacing_normal"
+        android:accessibilityHeading="true"
+        android:focusable="false"
+        android:textColor="@color/colorTextPrimary1InvertedStable"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@id/prc_icon"
+        app:layout_constraintTop_toBottomOf="@id/person_name"
+        app:layout_constraintVertical_bias="1"
+        app:layout_constraintVertical_chainStyle="packed"
+        tools:text="Test durchgeführt am 12.04.21, 18:01 Uhr" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_certificates.xml b/Corona-Warn-App/src/main/res/layout/fragment_certificates.xml
index 1ce0b67b87f725d81edb1179dd1cc278950d5768..54fc467de2af5903216a7a1d94e0f275eddc0180 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_certificates.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_certificates.xml
@@ -4,7 +4,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".greencertificate.ui.certificates.CertificatesFragment">
+    tools:context=".covidcertificate.test.ui.CertificatesFragment">
 
     <com.google.android.material.appbar.AppBarLayout
         android:layout_width="match_parent"
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_greencertificate_details.xml b/Corona-Warn-App/src/main/res/layout/fragment_covid_certificate_details.xml
similarity index 92%
rename from Corona-Warn-App/src/main/res/layout/fragment_greencertificate_details.xml
rename to Corona-Warn-App/src/main/res/layout/fragment_covid_certificate_details.xml
index 057a3da6aa7a3487beec29da4cee0fa991857ce9..fbc6609fc04b6843a7471cc82f45db687a79a15b 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_greencertificate_details.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_covid_certificate_details.xml
@@ -44,10 +44,10 @@
                     android:layout_marginTop="90dp"
                     android:layout_marginBottom="12dp"
                     android:gravity="center"
+                    android:text="@string/detail_green_certificate_title"
                     android:textColor="@android:color/white"
                     android:textSize="20sp"
-                    android:textStyle="bold"
-                    android:text="@string/detail_green_certificate_title"/>
+                    android:textStyle="bold" />
 
                 <TextView
                     android:id="@+id/subtitle"
@@ -59,7 +59,7 @@
                     android:gravity="center"
                     android:text="@string/detail_green_certificate_test_type"
                     android:textColor="@android:color/white"
-                    android:textSize="18sp"/>
+                    android:textSize="18sp" />
 
             </LinearLayout>
 
@@ -67,8 +67,10 @@
                 android:id="@+id/toolbar"
                 android:layout_width="match_parent"
                 android:layout_height="?attr/actionBarSize"
+                android:theme="@style/CWAToolbar.Theme"
                 app:layout_collapseMode="pin"
                 app:layout_scrollFlags="scroll|enterAlways"
+                app:menu="@menu/menu_covid_certificate_detail"
                 app:navigationIcon="@drawable/ic_back"
                 app:navigationIconTint="@android:color/white">
 
@@ -82,7 +84,7 @@
                     <ImageView
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        android:layout_marginEnd="72dp"
+                        android:layout_marginEnd="32dp"
                         android:importantForAccessibility="no"
                         app:srcCompat="@drawable/ic_cwa_logo_white" />
 
@@ -115,7 +117,7 @@
                 android:layout_marginBottom="6dp" />
 
             <LinearLayout
-                style="@style/Card.Greencertificate"
+                style="@style/Card.GreenCertificate"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginHorizontal="24dp"
@@ -126,7 +128,6 @@
                     style="@style/body1Medium"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="12dp"
                     android:text="@string/green_certificate_attribute_name" />
 
                 <TextView
@@ -134,7 +135,6 @@
                     style="@style/body1"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="Andrea Schneider"
                     tools:text="Andrea Schneider" />
 
                 <TextView
@@ -150,7 +150,6 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="18.04.1943"
                     tools:text="18.04.1943" />
 
                 <TextView
@@ -166,7 +165,6 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="SARS-CoV-2"
                     tools:text="SARS-CoV-2" />
 
                 <TextView
@@ -182,7 +180,6 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="Rapid Antigen Test"
                     tools:text="Rapid Antigen Test" />
 
                 <TextView
@@ -193,12 +190,11 @@
                     android:text="@string/green_certificate_attribute_test_name" />
 
                 <TextView
-                    android:id="@+id/medical_product_name"
+                    android:id="@+id/test_name"
                     style="@style/body1"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="Xep"
                     tools:text="Xep" />
 
                 <TextView
@@ -214,7 +210,6 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="Xup"
                     tools:text="Xup" />
 
                 <TextView
@@ -230,7 +225,6 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="12.05.21 19:00"
                     tools:text="12.05.21 19:00" />
 
                 <TextView
@@ -246,7 +240,6 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="negative"
                     tools:text="negative" />
 
                 <TextView
@@ -262,7 +255,6 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="AB123"
                     tools:text="AB123" />
 
                 <TextView
@@ -273,12 +265,11 @@
                     android:text="@string/green_certificate_attribute_state_of_testing" />
 
                 <TextView
-                    android:id="@+id/test_country"
+                    android:id="@+id/certificate_country"
                     style="@style/body1"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="Germany"
                     tools:text="Germany" />
 
                 <TextView
@@ -294,7 +285,6 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="G05930482748454836478695764787840"
                     tools:text="G05930482748454836478695764787840" />
 
 
@@ -311,14 +301,13 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="4dp"
-                    android:text="05930482748454836478695764787840"
                     tools:text="05930482748454836478695764787840" />
 
 
             </LinearLayout>
 
             <LinearLayout
-                style="@style/Card.Greencertificate"
+                style="@style/Card.GreenCertificate"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginHorizontal="24dp"
@@ -331,8 +320,7 @@
                     style="@style/body2"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="4dp"
-                    android:text="@string/green_certificate_attribute_certificate_travel_notice_german"/>
+                    android:text="@string/green_certificate_attribute_certificate_travel_notice_german" />
 
                 <TextView
                     android:id="@+id/travel_notice_english"
@@ -340,7 +328,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginTop="24dp"
-                    android:text="@string/green_certificate_attribute_certificate_travel_notice_english"/>
+                    android:text="@string/green_certificate_attribute_certificate_travel_notice_english" />
             </LinearLayout>
         </LinearLayout>
 
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_request_covid_certificate.xml b/Corona-Warn-App/src/main/res/layout/fragment_request_covid_certificate.xml
index 7129eb51e8c8e4b22b94a8866299d6d63fece73f..31c266359a5d50b349373be2e991227bd614083e 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_request_covid_certificate.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_request_covid_certificate.xml
@@ -5,7 +5,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@color/colorBackground"
-    tools:context="ui.submission.greencertificate.RequestCovidCertificateFragment">
+    tools:context="ui.submission.covidcertificate.RequestCovidCertificateFragment">
 
     <com.google.android.material.appbar.MaterialToolbar
         android:id="@+id/toolbar"
diff --git a/Corona-Warn-App/src/main/res/layout/tracing_details_find_details_in_journal.xml b/Corona-Warn-App/src/main/res/layout/tracing_details_find_details_in_journal.xml
index 943d16269bbf2c13e5607be54e75c52bb30bdad7..e5e2d9d83c0cbf75eabe881a9c0328ed770e6fb1 100644
--- a/Corona-Warn-App/src/main/res/layout/tracing_details_find_details_in_journal.xml
+++ b/Corona-Warn-App/src/main/res/layout/tracing_details_find_details_in_journal.xml
@@ -1,14 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/risk_details_find_details_in_journal"
-    style="@style/body1"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_marginHorizontal="@dimen/spacing_normal"
-    android:layout_marginTop="@dimen/spacing_normal"
-    android:focusable="true"
-    android:text="@string/risk_details_find_details_in_journal"
-    app:layout_constraintEnd_toEndOf="parent"
-    app:layout_constraintStart_toStartOf="parent"
-    app:layout_constraintTop_toTopOf="parent" />
\ No newline at end of file
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <TextView
+        android:id="@+id/risk_details_find_details_in_journal"
+        style="@style/body1"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginHorizontal="@dimen/spacing_normal"
+        android:layout_marginTop="@dimen/spacing_normal"
+        android:focusable="true"
+        android:text="@string/risk_details_find_details_in_journal"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+</layout>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml b/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml
index 340a37d67711f201d31569b43ee49985906fc420..3cff980a655c035a27775b1683995824b2ad2736 100644
--- a/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml
+++ b/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml
@@ -5,7 +5,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@color/colorBackground"
-    tools:context="de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentFragment">
+    tools:context="de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent.VaccinationConsentFragment">
 
     <com.google.android.material.appbar.MaterialToolbar
         android:id="@+id/toolbar"
diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml
index 6b257338d0594edc84e27b44740d00190c9554df..8d6853daebc5542e665479f3d2284195825f1590 100644
--- a/Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml
+++ b/Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml
@@ -5,75 +5,75 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="@drawable/vaccination_incomplete"
-    android:padding="@dimen/card_padding"
+    android:minHeight="200dp"
     tools:ignore="UnusedAttribute">
 
-
-    <ImageView
-        android:id="@+id/show_more_action"
-        android:layout_width="@dimen/icon_size_risk_card"
-        android:layout_height="@dimen/icon_size_risk_card"
-        android:importantForAccessibility="no"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:srcCompat="@drawable/ic_forward"
-        app:tint="@color/colorStableLight" />
-
     <ImageView
         android:id="@+id/icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
         android:importantForAccessibility="no"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/show_more_action"
-        app:srcCompat="@drawable/vaccination_card_icon_incomplete" />
-
+        app:layout_constraintTop_toTopOf="parent"
+        app:srcCompat="@drawable/ic_incomplete_vaccination_shield" />
 
     <TextView
-        android:id="@+id/card_title"
-        style="@style/body2"
+        android:id="@+id/title1"
+        style="@style/headline5"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="8dp"
+        android:layout_marginHorizontal="@dimen/card_padding"
+        android:layout_marginTop="@dimen/spacing_small"
         android:accessibilityHeading="true"
         android:focusable="false"
-        android:text="@string/vaccination_card_status_title"
+        android:text="@string/vaccination_card_registration_title_line_1"
         android:textColor="@color/colorTextPrimary1InvertedStable"
-        app:layout_constraintEnd_toStartOf="@id/show_more_action"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
     <TextView
-        android:id="@+id/vaccination_label"
-        style="@style/headline5Bold"
+        android:id="@+id/title2"
+        style="@style/headline5"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="16dp"
+        android:layout_marginHorizontal="@dimen/card_padding"
         android:accessibilityHeading="true"
         android:focusable="false"
-        android:text="@string/vaccination_card_status_vaccination_name"
+        android:text="@string/vaccination_card_registration_title_line_2"
         android:textColor="@color/colorTextPrimary1InvertedStable"
-        app:layout_constraintEnd_toStartOf="@+id/icon"
+        android:textStyle="bold"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/card_title" />
+        app:layout_constraintTop_toBottomOf="@id/title1" />
+
+    <ImageView
+        android:id="@+id/shield_icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginStart="@dimen/card_padding"
+        android:importantForAccessibility="no"
+        app:layout_constraintBottom_toBottomOf="@id/vaccination_state"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@id/vaccination_state"
+        app:srcCompat="@drawable/ic_half_white_half_gray_shield" />
 
     <TextView
         android:id="@+id/vaccination_state"
-        style="@style/body1"
+        style="@style/body2"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:layout_marginEnd="16dp"
+        android:layout_marginStart="8dp"
+        android:layout_marginBottom="@dimen/spacing_normal"
         android:accessibilityHeading="true"
         android:focusable="false"
         android:text="@string/vaccination_card_status_vaccination_incomplete"
         android:textColor="@color/colorTextPrimary1InvertedStable"
-        app:layout_constraintBottom_toTopOf="@+id/person_name"
-        app:layout_constraintEnd_toStartOf="@+id/icon"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/vaccination_label"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@id/shield_icon"
+        app:layout_constraintTop_toBottomOf="@id/person_name"
+        app:layout_constraintVertical_bias="1"
         app:layout_constraintVertical_chainStyle="packed" />
 
     <TextView
@@ -81,16 +81,14 @@
         style="@style/body1"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginTop="8dp"
-        android:layout_marginEnd="16dp"
+        android:layout_marginHorizontal="@dimen/card_padding"
+        android:layout_marginTop="@dimen/spacing_small"
         android:accessibilityHeading="true"
         android:focusable="false"
         android:textColor="@color/colorTextPrimary1InvertedStable"
-        android:visibility="gone"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toStartOf="@+id/icon"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/vaccination_state"
+        app:layout_constraintTop_toBottomOf="@id/title2"
         tools:text="Andrea Schneider" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml
index 611102ebee2f729324ed8ab39c8e427abf2993de..8da269c8163145d38375e0e578e9fa33dde004b6 100644
--- a/Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml
+++ b/Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml
@@ -5,20 +5,9 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="@drawable/vaccination_compelete_gradient"
-    android:padding="@dimen/card_padding"
+    android:minHeight="200dp"
     tools:ignore="UnusedAttribute">
 
-
-    <ImageView
-        android:id="@+id/show_more_action"
-        android:layout_width="@dimen/icon_size_risk_card"
-        android:layout_height="@dimen/icon_size_risk_card"
-        android:importantForAccessibility="no"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:srcCompat="@drawable/ic_forward"
-        app:tint="@color/colorStableLight" />
-
     <ImageView
         android:id="@+id/icon"
         android:layout_width="wrap_content"
@@ -26,52 +15,80 @@
         android:importantForAccessibility="no"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/show_more_action"
-        app:srcCompat="@drawable/vaccination_card_icon_immune" />
+        app:layout_constraintTop_toTopOf="parent"
+        app:srcCompat="@drawable/ic_complete_vaccination_shield" />
 
     <TextView
-        android:id="@+id/card_title"
-        style="@style/body2"
+        android:id="@+id/title1"
+        style="@style/headline5"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="8dp"
+        android:layout_marginHorizontal="@dimen/card_padding"
+        android:layout_marginTop="@dimen/spacing_small"
         android:accessibilityHeading="true"
         android:focusable="false"
-        android:text="@string/vaccination_card_status_title"
+        android:text="@string/vaccination_card_registration_title_line_1"
         android:textColor="@color/colorTextPrimary1InvertedStable"
-        app:layout_constraintEnd_toStartOf="@id/show_more_action"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
     <TextView
-        android:id="@+id/vaccination_label"
-        style="@style/headline5Bold"
+        android:id="@+id/title2"
+        style="@style/headline5"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="16dp"
+        android:layout_marginHorizontal="@dimen/card_padding"
         android:accessibilityHeading="true"
         android:focusable="false"
-        android:text="@string/vaccination_card_status_vaccination_name"
+        android:text="@string/vaccination_card_registration_title_line_2"
         android:textColor="@color/colorTextPrimary1InvertedStable"
-        app:layout_constraintEnd_toStartOf="@+id/icon"
+        android:textStyle="bold"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/card_title" />
+        app:layout_constraintTop_toBottomOf="@id/title1" />
+
+    <ImageView
+        android:id="@+id/shield_icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginStart="@dimen/card_padding"
+        android:importantForAccessibility="no"
+        app:layout_constraintBottom_toBottomOf="@id/vaccination_state"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@id/vaccination_state"
+        app:srcCompat="@drawable/ic_white_shield_with_checkmark" />
+
+    <TextView
+        android:id="@+id/vaccination_state"
+        style="@style/body2"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginBottom="@dimen/spacing_normal"
+        android:accessibilityHeading="true"
+        android:focusable="false"
+        android:textColor="@color/colorTextPrimary1InvertedStable"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@id/shield_icon"
+        app:layout_constraintTop_toBottomOf="@id/person_name"
+        app:layout_constraintVertical_bias="1"
+        app:layout_constraintVertical_chainStyle="packed"
+        tools:text="@string/vaccination_card_status_vaccination_complete" />
 
     <TextView
         android:id="@+id/person_name"
         style="@style/body1"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:layout_marginEnd="16dp"
+        android:layout_marginHorizontal="@dimen/card_padding"
+        android:layout_marginTop="@dimen/spacing_small"
         android:accessibilityHeading="true"
         android:focusable="false"
         android:textColor="@color/colorTextPrimary1InvertedStable"
-        android:visibility="gone"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toStartOf="@+id/icon"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/vaccination_label"
+        app:layout_constraintTop_toBottomOf="@id/title2"
         tools:text="Andrea Schneider" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/menu/menu_covid_certificate_detail.xml b/Corona-Warn-App/src/main/res/menu/menu_covid_certificate_detail.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4ae3a0733d51d12c97901516365d9ec307aedcad
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/menu/menu_covid_certificate_detail.xml
@@ -0,0 +1,6 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item
+        android:id="@+id/menu_covid_certificate_delete"
+        android:title="@string/green_certificate_details_menu_item_delete" />
+</menu>
diff --git a/Corona-Warn-App/src/main/res/navigation/green_certificate_graph.xml b/Corona-Warn-App/src/main/res/navigation/green_certificate_graph.xml
index 3605a787c2a0d0ae5ca3b732be091d62d7a506c3..f38cdb7fb4db60bb48e3abf7159527a05fd8e3e2 100644
--- a/Corona-Warn-App/src/main/res/navigation/green_certificate_graph.xml
+++ b/Corona-Warn-App/src/main/res/navigation/green_certificate_graph.xml
@@ -7,21 +7,28 @@
 
     <fragment
         android:id="@+id/certificatesFragment"
-        android:name="de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesFragment"
+        android:name="de.rki.coronawarnapp.covidcertificate.test.ui.CertificatesFragment"
         android:label="fragment_certificates"
-        tools:layout="@layout/fragment_certificates" >
+        tools:layout="@layout/fragment_certificates">
 
         <action
             android:id="@+id/action_certificatesFragment_to_vaccinationNavGraph"
             app:destination="@id/vaccination_nav_graph" />
+        <action
+            android:id="@+id/action_certificatesFragment_to_covidCertificateDetailsFragment"
+            app:destination="@id/covidCertificateDetailsFragment" />
+
+        <action
+            android:id="@+id/action_certificatesFragment_to_consentFragment"
+            app:destination="@id/vaccinationConsentFragment" />
 
     </fragment>
 
     <fragment
         android:id="@+id/vaccinationConsentFragment"
-        android:name="de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentFragment"
+        android:name="de.rki.coronawarnapp.covidcertificate.vaccination.ui.consent.VaccinationConsentFragment"
         android:label="vaccination_consent_fragment"
-        tools:layout="@layout/vaccination_consent_fragment" >
+        tools:layout="@layout/vaccination_consent_fragment">
         <argument
             android:name="showBottomNav"
             android:defaultValue="true"
@@ -42,4 +49,14 @@
         android:label="privacyFragment"
         tools:layout="@layout/fragment_information_privacy" />
 
+    <fragment
+        android:id="@+id/covidCertificateDetailsFragment"
+        android:name="de.rki.coronawarnapp.covidcertificate.test.ui.details.CovidCertificateDetailsFragment"
+        android:label="CovidCertificateDetailsFragment"
+        tools:layout="@layout/fragment_covid_certificate_details">
+
+        <argument
+            android:name="testCertificateIdentifier"
+            app:argType="string" />
+    </fragment>
 </navigation>
\ 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 919fadb96bacaf782dd41ab5ee9e32c21e9fbf64..8d879a4bb77ffea0650d57ebc6590f0d199bfeae 100644
--- a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml
+++ b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml
@@ -830,7 +830,7 @@
         app:destination="@id/qrCodeFullScreenFragment" />
     <fragment
         android:id="@+id/requestCovidCertificateFragment"
-        android:name="de.rki.coronawarnapp.ui.submission.greencertificate.RequestCovidCertificateFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.covidcertificate.RequestCovidCertificateFragment"
         android:label="fragment_request_covid_certificate"
         tools:layout="@layout/fragment_request_covid_certificate">
         <argument
diff --git a/Corona-Warn-App/src/main/res/navigation/vaccination_nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/vaccination_nav_graph.xml
index 74ba33a60f5af566e4f12927b5e33765ad4e985d..aeb23461ad7891fb411110910168880b6693ae5d 100644
--- a/Corona-Warn-App/src/main/res/navigation/vaccination_nav_graph.xml
+++ b/Corona-Warn-App/src/main/res/navigation/vaccination_nav_graph.xml
@@ -7,7 +7,7 @@
 
     <fragment
         android:id="@+id/vaccinationQrCodeScanFragment"
-        android:name="de.rki.coronawarnapp.vaccination.ui.scan.VaccinationQrCodeScanFragment"
+        android:name="de.rki.coronawarnapp.covidcertificate.vaccination.ui.scan.VaccinationQrCodeScanFragment"
         android:label="VaccinationQrCodeScanFragment"
         tools:layout="@layout/fragment_scan_qr_code">
         <action
@@ -20,7 +20,7 @@
 
     <fragment
         android:id="@+id/vaccinationListFragment"
-        android:name="de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragment"
+        android:name="de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListFragment"
         android:label="fragment_vaccination_list"
         tools:layout="@layout/fragment_vaccination_list">
         <argument
@@ -37,7 +37,7 @@
 
     <fragment
         android:id="@+id/vaccinationDetailsFragment"
-        android:name="de.rki.coronawarnapp.vaccination.ui.details.VaccinationDetailsFragment"
+        android:name="de.rki.coronawarnapp.covidcertificate.vaccination.ui.details.VaccinationDetailsFragment"
         android:label="fragment_vaccination_details"
         tools:layout="@layout/fragment_vaccination_details">
         <argument
diff --git a/Corona-Warn-App/src/main/res/values-bg/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-bg/antigen_strings.xml
index a68f5f5d1b1316c18578d74b68211659f5cb5996..100652ed537682e1f90c188696f927b0ad0de261 100644
--- a/Corona-Warn-App/src/main/res/values-bg/antigen_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/antigen_strings.xml
@@ -6,8 +6,7 @@
     <!-- XHED: Register test homescreen card: title -->
     <string name="ag_homescreen_card_test_register_title">"Регистрирайте своя тест"</string>
     <!-- XTXT: Register test homescreen card: body -->
-    <string name="ag_homescreen_card_test_register_body">"Използвайте приложението, за да регистрирате тестовете си и да извлечете резултатите от тях, за да можете предупредите останалите по-бързо."</string>
-
+    <string name="ag_homescreen_card_test_register_body">"Използвайте приложението, за да регистрирате тестовете си и да извлечете резултатите от тях, за да можете да предупредите останалите по-бързо или за да заявите своя сертификат за тестване за COVID."</string>
     <!-- ####################################
         Homescreen cards - common buttons
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml
index fb165acc4816cc19117521807662ccf0fc0ecfd0..3de30155be44db04c32e8c5a1fd62c7dfe83f991 100644
--- a/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml
@@ -182,4 +182,13 @@
     <string name="contact_diary_location_visit_duration_hour">"ч"</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Забележка (напр. препълнено)"</string>
+
+    <!-- XTXT: PCR test title in the day overview -->
+    <string name="contact_diary_corona_test_pcr_title">"PCR тестът е регистриран"</string>
+    <!-- XTXT: RAT test title in the day overview -->
+    <string name="contact_diary_corona_test_rat_title">"Бързият тест е извършен"</string>
+    <!-- XTXT: positive test result in the day overview -->
+    <string name="contact_diary_corona_test_positive">"Положителен резултат"</string>
+    <!-- XTXT: negative test result in the day overview -->
+    <string name="contact_diary_corona_test_negative">"Отрицателен резултат"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-bg/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values-bg/event_registration_strings.xml
index b2ad81cbba3031fe16075204c7edeedcbb7a65d5..1a5025ded05a1c659e401ec4f2a939b92e3631f0 100644
--- a/Corona-Warn-App/src/main/res/values-bg/event_registration_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/event_registration_strings.xml
@@ -210,6 +210,8 @@
     <string name="trace_location_organizer_detail_item_duration">"%1$s, %2$s - %3$s"</string>
     <!-- XTXT: Event organizer detail qr-code: duration with multiple date -->
     <string name="trace_location_organizer_detail_item_duration_multiple_days">"%1$s, %2$s - %3$s, %4$s"</string>
+    <!-- XTXT: Past Event Info duration -->
+    <string name="trace_location_attendee_past_event_duration">"%1$s"</string>
 
     <!-- XBUT: Event organiser list item: menu: information button  -->
     <string name="trace_location_organizer_list_item_menu_duplicate_btn">"Дублиране"</string>
diff --git a/Corona-Warn-App/src/main/res/values-bg/green_certificate_strings.xml b/Corona-Warn-App/src/main/res/values-bg/green_certificate_strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ddae0a81127cfe8a2349f50c4d572b3b68e19b95
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/values-bg/green_certificate_strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
+    <!-- XTXT: Request green certificate title -->
+    <string name="request_green_certificate_title">"Сертификат за тест за COVID"</string>
+    <!-- XTXT: Request green certificate subtitle -->
+    <string name="request_green_certificate_subtitle">"Можете да използвате приложението, за да заявите официален електронен сертификат за тестване, който ще бъде добавен в приложението."</string>
+    <!-- XTXT: Request green certificate body section 1 -->
+    <string name="request_green_certificate_body_1">"Сертификатът за тестване се издава само ако получите отрицателен резултат от теста."</string>
+    <!-- XTXT: Request green certificate body section 2 -->
+    <string name="request_green_certificate_body_2">"Сертификатът за тестване е валидно доказателство за отрицателен резултат от тест в рамките на ЕС (например при пътуване)."</string>
+    <!-- XTXT: Request green certificate body section 3 -->
+    <string name="request_green_certificate_body_3">"Сертификатът за тестване съдържа валидни данни, които позволяват на приложението за проверка да валидира сертификата ви."</string>
+    <!-- XBUT: Request green certificate agree button -->
+    <string name="request_green_certificate_agree_button">"Заявете тестов сертификат"</string>
+    <!-- XBUT: Request green certificate disagree button -->
+    <string name="request_green_certificate_disagree_button">"Не, благодаря!"</string>
+    <!-- XTXT: Request green certificate birth date description -->
+    <string name="request_green_certificate_birthdate_description">"С цел сигурност, резултатът от теста е защитен с датата Ви на раждане. Той може да бъде издаден само ако посочите правилната дата."</string>
+    <!-- XTXT: Request green certificate birth date hint -->
+    <string name="request_green_certificate_birthdate_hint">"Дата на раждане"</string>
+    <!-- XTXT: Request green certificate exit dialog title -->
+    <string name="request_gc_dialog_title">"Отмяна на регистрация"</string>
+    <!-- XTXT: Request green certificate exit dialog message -->
+    <string name="request_gc_dialog_message">"Ако отмените регистрацията на теста, няма да може да получите резултата от него в приложението."</string>
+    <!-- XBUT: Request green certificate exit dialog negative button -->
+    <string name="request_gc_dialog_positive_button">"ОК"</string>
+    <!-- XBUT: Request green certificate exit dialog negative button -->
+    <string name="request_gc_dialog_negative_button">"Отказ"</string>
+    <!-- XTXT: Detail green certificate title -->
+    <string name="detail_green_certificate_title">"Електронен сертификат на ЕС за тестване за COVID"</string>
+    <!-- XTXT: Detail green certificate test type -->
+    <string name="detail_green_certificate_test_type">"Тест за SARS-CoV-2"</string>
+    <!-- XTXT: Detail green certificate card title -->
+    <string name="detail_green_certificate_card_title">"Сертификат за тестване"</string>
+    <!-- XTXT: Detail green certificate travel notice link en -->
+    <string name="green_certificate_travel_notice_link_en">"https://reopen.europa.eu/en"</string>
+    <!-- XTXT: Detail green certificate travel notice link de -->
+    <string name="green_certificate_travel_notice_link_de">"https://reopen.europa.eu/de"</string>
+    <!-- XTXT: Green certificate main screen title -->
+    <string name="certification_screen_title">"Сертификати"</string>
+    <!-- XTXT: Green certificate menu item -->
+    <string name="menu_certification_information">"Информация"</string>
+    <!-- XTXT: Green certificate main screen header text -->
+    <string name="green_certification_header_info">"Тук се показват електронните ви сертификати за ваксиниране и за тествания."</string>
+    <!-- XTXT: Green certificate info card title 1st line -->
+    <string name="info_banner_title_1">"Електронен COVID-19"</string>
+    <!-- XTXT: Green certificate info card title 2nd line  -->
+    <string name="info_banner_title_2">"Сертификат за тест за COVID"</string>
+    <!-- XTXT: Green certificate info card body  -->
+    <string name="info_banner_body">"Регистрирайте тест на началния екран и дайте съгласие да получите електронен сертификат за тестване. Той ще се покаже тук веднага щом е наличен."</string>
+</resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml
index c36ffbe1836a1a5f7bbe701ea251a8f2810d7e63..335aaa6f5ae1578642ab3329cc65f47890fe16bd 100644
--- a/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation">
     <!-- ####################################
-                 Release Info Screen 1.14
+                 Release Info Screen
      ###################################### -->
 
     <!-- XHED: Title for the release info screen -->
@@ -16,22 +16,26 @@
 
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
-        <item>"Електронно доказателство за ваксиниране"</item>
+        <item>"Сертификат за тест за COVID"</item>
+        <item>"Разширение на дневника с контакти"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
-        <item>"Вече можете да добавите в приложението сертификатите си за ваксиниране и да ги представите чрез QR код. Приложението ще покаже пълна защита от ваксиниране 14 дни след крайната ваксинация."</item>
+        <item>"Вече можете да заявите чрез приложението официален електронен сертификат за тестване и след това да го добавите в него. Този сертификат може да се използва (чрез QR код) в рамките на ЕС като доказателство за отрицателен резултат от тест (например при международни пътувания)."</item>
+        <item>"В момента, в който резултатът от теста Ви е наличен, той ще бъде добавен към дневника Ви с контакти."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
+        <item/>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
+        <item/>
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-bg/strings.xml b/Corona-Warn-App/src/main/res/values-bg/strings.xml
index 9f392a30db6e2f798aaf9f265e735983dde4d7b9..9d754260bca4c26af7a54b40655eac90a195aa73 100644
--- a/Corona-Warn-App/src/main/res/values-bg/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/strings.xml
@@ -281,6 +281,8 @@
     <string name="risk_details_behavior_body_wear_mask">"Носете маска при контакт с други хора."</string>
     <!-- XMSG: risk details - stay 1,5 away, something like a bullet point -->
     <string name="risk_details_behavior_body_stay_away">"Спазвайте дистанция от поне 1,5 м от околните."</string>
+    <!-- XTXT: find details about exposures in the contact journal -->
+    <string name="risk_details_find_details_in_journal">"Ще намерите още информация относно излаганията ви на риск във вашия дневник на контактите."</string>
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"Ако се тествате, вижте Процедура за тестване в ЧЗВ, за да получите допълнителна информация."</string>
@@ -1027,6 +1029,8 @@
     <string name="submission_consent_call_test_result_scan_your_test_only">"Сега сканирайте QR кода от Вашия тест, за да получите резултата."</string>
     <!-- YTXT:  Body sub text 2 for Submission Consent call test result   -->
     <string name="submission_consent_call_test_result_scan_test_only_once">"Можете да сканирате Вашия тест само веднъж. Приложението може да обработва едновременно само един бърз тест и един PCR тест."</string>
+    <!-- YTXT:  Body sub text 3 for Submission Consent call test result   -->
+    <string name="submission_consent_call_test_result_checkmark_text">"Ако резултатът от теста ви е отрицателен, може да го потвърдите с официален сертификат за тестване за COVID. За да направите това, заявете сертификата като следвате стъпките."</string>
     <!-- XHED: Page subheadline for consent help by warning others  -->
     <string name="submission_consent_help_by_warning_others_headline">"Моля, помогнете на хората, с които сте имали контакт, като ги предупредите!"</string>
     <!-- YTXT: Body for consent help by warning others -->
@@ -1087,6 +1091,15 @@
     <!-- YTXT: Body text for next steps section of waiting test result page -->
     <string name="submission_test_result_pending_steps_contact_diary_body">"Резултатът от Вашия тест ще се покаже в приложението веднага щом бъде готов."</string>
 
+    <!-- XHED: Page headline for test result certifcate info title  -->
+    <string name="submission_test_result_pending_steps_test_certificate_heading">"Вашият сертификат за тестване"</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not supported, RAT Test -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_supported_body">"Не е наличен сертификат за тестване, защото този пункт за тестване не поддържа издаването на такива сертификати."</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not available yet, PCR Test consent given -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_available_yet_body">"Сертификатът Ви за тестване все още не е наличен. Когато това се случи, той ще се покаже в приложението Ви."</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not desired by the user, PCR Test no consent given -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_desired_by_user_body">"Не е издаден сертификат, отговарящ на искането Ви."</string>
+
     <!-- XBUT: test result pending : refresh button -->
     <string name="submission_test_result_pending_refresh_button">"Актуализиране"</string>
     <!-- XBUT: test result pending : remove the test button -->
@@ -1179,7 +1192,7 @@
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"Сканиране на QR код"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
-    <string name="submission_dispatcher_qr_card_text">"Получете резултата си в приложението и предупредете останалите."</string>
+    <string name="submission_dispatcher_qr_card_text">"Получете резултата си в приложението и предупредете останалите или заявете своя сертификат за тестване за COVID."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
     <string name="submission_dispatcher_card_tan_code">"Въведете ТАН код за PCR тест"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
@@ -1838,7 +1851,8 @@
     <string name="bottom_nav_diary_title">"Дневник"</string>
     <!-- XHED: Title for BottomNav check-in screen title -->
     <string name="bottom_nav_check_ins_title">"Регистрация"</string>
-
+    <!-- XHED: Title for BottomNav certificates screen title -->
+    <string name="bottom_nav_certificates_title">"Сертификати"</string>
     <!-- ####################################
            Data Donation & Survey
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml
index 13a3e4af27d0abdb57084860df4927f1802e62a7..6eeeb4c291f99bd1526977a9094253cd04784d8e 100644
--- a/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml
@@ -36,7 +36,7 @@
     <string name="vaccination_list_vaccination_card_subtitle">"Извършено на %1$s"</string>
     <!-- XTXT: Vaccination List immunity information card body-->
     <plurals name="vaccination_list_immunity_card_body">
-        <item quantity="one">"Получихте всички планирани за момента ваксинации, но защитата ви от ваксиниране ще е пълна едва след %1$d ден."</item>
+        <item quantity="one">"Получихте всички планирани за момента ваксинации, но защитата ви от ваксиниране ще е пълна след %1$d ден."</item>
         <item quantity="other">"Получихте всички планирани за момента ваксинации, но защитата ви от ваксиниране ще е пълна едва след %1$d дни."</item>
         <item quantity="zero">"Получихте всички планирани за момента ваксинации, но защитата ви от ваксиниране ще е пълна едва след %1$d дни."</item>
         <item quantity="two">"Получихте всички планирани за момента ваксинации, но защитата ви от ваксиниране ще е пълна едва след %1$d дни."</item>
@@ -62,9 +62,11 @@
         Homescreen cards
     ###################################### -->
     <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_title">"Добавете сертификат за ваксиниране"</string>
+    <string name="vaccination_card_registration_title_line_1">"Добавете електронно доказателство"</string>
+    <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
+    <string name="vaccination_card_registration_title_line_2">"за ваксиниране"</string>
     <!-- YTXT: Body text for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_body">"Добавете ваксинационни сертификати в приложението, за да са винаги с вас. За да направите това, сканирайте QR кода от вашия документ."</string>
+    <string name="vaccination_card_registration_body">"Добавете ваксинационните си сертификати в приложението, за да са винаги с вас. За да направите това, сканирайте QR кода от вашия документ."</string>
     <!-- XBUT: button for Vaccination Certificate Registration Home Card -->
     <string name="vaccination_card_register">"Добавяне"</string>
     <!-- XHED: Homescreen vaccination status card title -->
@@ -97,17 +99,17 @@
     <!-- XTXT: Vaccination Consent title-->
     <string name="vaccination_consent_title">"Вашето съгласие"</string>
     <!-- XTXT: Vaccination Consent subtitle-->
-    <string name="vaccination_consent_headline">"Добавете сертификат за ваксиниране"</string>
+    <string name="vaccination_consent_headline">"Добавете сертификати"</string>
     <!-- XTXT: Vaccination Consent subtitle of qr info -->
-    <string name="vaccination_consent_info_subtitle_text">"Добавете електронния си сертификат за ваксиниране. Когато ваксинационната ви защита бъде завършена, можете да представяте QR кода в приложението си като доказателство за ваксиниране."</string>
+    <string name="vaccination_consent_info_subtitle_text">"Добавете електронните си сертификати за COVID в приложението. Така ще можете да доказвате ваксинационната си защита или резултата от отрицателен тест чрез приложението."</string>
     <!-- XTXT: Vaccination Consent text of qr info -->
-    <string name="vaccination_consent_qr_info_text">"За да добавите сертификат за ваксиниране в приложението, сканирайте QR кода, който сте получили по време на ваксинирането."</string>
+    <string name="vaccination_consent_qr_info_text">"Можете да добавите в приложението сертификатите си за ваксиниране срещу COVID или сертификатите за тествания за COVID."</string>
     <!-- XTXT: Vaccination Consent qr code text -->
-    <string name="vaccination_consent_qr_info_qr_code_text">"Приложението чете информацията от QR кода и го запазва в защитена област в смартфона ви."</string>
+    <string name="vaccination_consent_qr_info_qr_code_text">"Тези сертификати се считат за валидно доказателство в рамките на ЕС (например при пътуване)."</string>
     <!-- XTXT: Vaccination Consent time text  -->
-    <string name="vaccination_consent_qr_info_time_text">"Данните ще останат в смартфона. Те ще бъдат предадени на другите само ако представите ваксинационния си сертификат за проверка."</string>
+    <string name="vaccination_consent_qr_info_time_text">"След като добавите сертификат, той ще се запази в смартфона Ви. Ще се споделя с останалите само ако представите сертификат за ваксиниране."</string>
     <!-- XTXT: Text for vaccination consent legal information button -->
-    <string name="vaccination_consent_onboarding_legal_information">"За повече информация прочетете декларацията за поверителност."</string>
+    <string name="vaccination_consent_onboarding_legal_information">"За повече информация относно обработката на данни, прочетете декларацията за поверителност."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Напред"</string>
 
diff --git a/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml
index c9b3779b5b3df64ea415c7a12a21924f4d712c37..3eb70a980ce8286f10c6cb13bcb86e4971d746de 100644
--- a/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml
@@ -7,7 +7,7 @@
     <!-- XHED: Register test homescreen card: title -->
     <string name="ag_homescreen_card_test_register_title">"Test registrieren"</string>
     <!-- XTXT: Register test homescreen card: body -->
-    <string name="ag_homescreen_card_test_register_body">"Nutzen Sie die App, um Ihr Testergebnis abzurufen und andere schneller warnen zu können, oder um Ihr COVID-19-Testzertifikat anzufordern."</string>
+    <string name="ag_homescreen_card_test_register_body">"Nutzen Sie die App, um Ihr Testergebnis abzurufen und andere schneller warnen zu können, oder um Ihr COVID-Testzertifikat anzufordern."</string>
     <!-- ####################################
         Homescreen cards - common buttons
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-de/green_certificate_strings.xml b/Corona-Warn-App/src/main/res/values-de/green_certificate_strings.xml
index 0ee17fb2adc309974247759ad6fdbc37ba8cfd61..bd91fd49db9ec7b6a5e8639e4dcab7e007dbbf12 100644
--- a/Corona-Warn-App/src/main/res/values-de/green_certificate_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/green_certificate_strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
     <!-- XTXT: Request green certificate title -->
-    <string name="request_green_certificate_title">COVID-19-Testzertifikat</string>
+    <string name="request_green_certificate_title">COVID-Testzertifikat</string>
     <!-- XTXT: Request green certificate subtitle -->
     <string name="request_green_certificate_subtitle">Sie können über die App ein offizielles digitales Testzertifikat anfordern, das anschließend in der App hinzugefügt wird.</string>
     <!-- XTXT: Request green certificate body section 1 -->
@@ -32,12 +32,25 @@
     <string name="detail_green_certificate_test_type">SARS-CoV-2-Test</string>
     <!-- XTXT: Detail green certificate card title -->
     <string name="detail_green_certificate_card_title">"Testzertifikat"</string>
+    <!-- XTXT: Detail green certificate card subtitle -->
+    <string name="detail_green_certificate_card_subtitle">"Test durchgeführt am %1$s %2$s"</string>
     <!-- XTXT: Detail green certificate travel notice link en -->
     <string name="green_certificate_travel_notice_link_en">"https://reopen.europa.eu/en"</string>
     <!-- XTXT: Detail green certificate travel notice link de -->
     <string name="green_certificate_travel_notice_link_de">"https://reopen.europa.eu/de"</string>
+    <!-- XTXT: Detail green certificate menu item: delete -->
+    <string name="green_certificate_details_menu_item_delete">"Entfernen"</string>
+    <!-- XTXT: Detail green certificate diaglog title -->
+    <string name="green_certificate_details_dialog_remove_test_title">"Wollen Sie das Testzertifikat wirklich entfernen?"</string>
+    <!-- XTXT: Detail green certificate diaglog message -->
+    <string name="green_certificate_details_dialog_remove_test_message">"Wenn Sie das Testzertifikat entfernen, können Sie es nicht mehr als Nachweis in der App verwenden."</string>
+    <!-- XTXT: Detail green certificate diaglog positive -->
+    <string name="green_certificate_details_dialog_remove_test_button_positive">"Entfernen"</string>
+    <!-- XTXT: Detail green certificate diaglog negative -->
+    <string name="green_certificate_details_dialog_remove_test_button_negative">"Abbrechen"</string>
+
     <!-- XTXT: Green certificate main screen title -->
-    <string name="certification_screen_title">Nachweise</string>
+    <string name="certification_screen_title">Zertifikate</string>
     <!-- XTXT: Green certificate menu item -->
     <string name="menu_certification_information">Informationen</string>
     <!-- XTXT: Green certificate main screen header text -->
@@ -45,7 +58,46 @@
     <!-- XTXT: Green certificate info card title 1st line -->
     <string name="info_banner_title_1">Digitales</string>
     <!-- XTXT: Green certificate info card title 2nd line  -->
-    <string name="info_banner_title_2">COVID-19-Testzertifikat</string>
+    <string name="info_banner_title_2">COVID-Testzertifikat</string>
     <!-- XTXT: Green certificate info card body  -->
     <string name="info_banner_body">Registrieren Sie einen Test auf der Startseite und stimmen Sie zu, ein digitales Testzertifikat zu erhalten. Sobald das Zertifikat vorliegt, wird es hier angezeigt.</string>
+
+    <!-- XTXT: Test certificate time -->
+    <string name="test_certificate_time">Test durchgeführt am %1$s, %2$s Uhr</string>
+    <!-- XTXT: Test error label -->
+    <string name="test_certificate_error_label">Fehler bei der Zertifikatsabfrage</string>
+    <!-- XBUT: Test error retry button -->
+    <string name="test_certificate_error_retry_button">Nochmal versuchen</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_try_again">Es konnte keine Verbindung hergestellt werden. Bitte versuchen Sie es erneut.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_dcc_not_supported_by_lab">Ein Testzertifikat kann nicht angefordert werden, da diese Teststelle die Ausstellung von Testzertifikaten nicht unterstützt. Bitte entfernen Sie das Zertifikat oder kontaktieren Sie die technische Hotline über App-Informationen -> Technische Hotline.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_no_network">Ihre Internetverbindung wurde unterbrochen. Bitte prüfen Sie die Verbindung und versuchen Sie es erneut.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_e2e_error_call_hotline">Ein Fehler ist aufgetreten. Bitte versuchen Sie es später noch einmal oder kontaktieren Sie die technische Hotline über App-Informationen -> Technische Hotline.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_try_again_dcc_not_available_yet">Ihr Zertifikat liegt noch nicht vor. Bitte versuchen Sie es noch einmal. Sollte der Fehler weiterhin bestehen, kontaktieren Sie bitte die technische Hotline über App-Informationen -> Technische Hotline.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_client_error_call_hotline">Ein Fehler ist aufgetreten. Bitte versuchen Sie es später noch einmal oder kontaktieren Sie die technische Hotline über App-Informationen -> Technische Hotline.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_dcc_expired">Das Zertifikat ist nicht mehr aktuell, Sie können es aus der Corona-App entfernen.</string>
+    <!-- XBUT: Test error delete button -->
+    <string name="test_certificate_error_delete_button">Testzertifikat entfernen</string>
+    <!-- XTXT: Test error refresh dialog title -->
+    <string name="test_certificate_refresh_dialog_title">"Es gibt weiterhin Probleme bei der Abfrage"</string>
+    <!-- XBUT: Test error refresh dialog confirm button -->
+    <string name="test_certificate_refresh_dialog_confirm_button">"OK"</string>
+    <!-- XTXT: Test error delete dialog title -->
+    <string name="test_certificate_delete_dialog_title">"Wollen Sie das Zertifikat wirklich entfernen?"</string>
+    <!-- XTXT: Test error delete dialog body -->
+    <string name="test_certificate_delete_dialog_body">"Wenn das Zertifikat enfernt wird, kann es nicht noch einmal angefordert werden."</string>
+    <!-- XBUT: Test error delete dialog confirm button -->
+    <string name="test_certificate_delete_dialog_confirm_button">"Entfernen"</string>
+    <!-- XBUT: Test error delete dialog cancel button -->
+    <string name="test_certificate_delete_dialog_cancel_button">"Abbrechen"</string>
+    <!-- XTXT: Test error card body refreshing -->
+    <string name="test_certificate_error_label_refreshing">"Ihr Zertifikat wird gerade erstellt…"</string>
+    <!-- XTXT: Test error card body refreshing -->
+    <string name="test_certificate_error_refreshing_status">"Ihr Zertifikat wird gerade angefragt, dies kann einige Minuten dauern…"</string>
 </resources>
diff --git a/Corona-Warn-App/src/main/res/values-de/legal_strings.xml b/Corona-Warn-App/src/main/res/values-de/legal_strings.xml
index 2b0d81b0c5cefe7062a88339699da55e7c339d1b..d10ff685cd7ce7fee733a4757f8237505e5aad53 100644
--- a/Corona-Warn-App/src/main/res/values-de/legal_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/legal_strings.xml
@@ -185,13 +185,13 @@
     <!-- XTXT: Request GC title for privacy card -->
     <string name="request_green_certificate_privacy_title">Datenschutz und Datensicherheit</string>
     <!-- XTXT: Request GC bullet point 1 for privacy card -->
-    <string name="request_green_certificate_privacy_section_1" translatable="false">Die Anforderung und Verwendung des digitalen COVID-19-Testzertifikats ist freiwillig. Der Nachweis eines negativen Testergebnisses kann auch auf andere Weise erbracht werden.</string>
+    <string name="request_green_certificate_privacy_section_1" translatable="false">Die Anforderung und Verwendung des digitalen COVID-Testzertifikats ist freiwillig. Der Nachweis eines negativen Testergebnisses kann auch auf andere Weise erbracht werden.</string>
     <!-- XTXT: Request GC bullet point 3 for privacy card -->
     <string name="request_green_certificate_privacy_section_2" translatable="false">Zur Erstellung Ihres Testzertifikats werden Daten einmalig verschlüsselt an das RKI übermittelt. Das RKI signiert die Daten elektronisch, um die Gültigkeit zu bestätigen. Die Daten werden beim RKI nicht gespeichert.</string>
     <!-- XTXT: Request GC extra bullet point PCR test  for privacy card -->
     <string name="request_green_certificate_privacy_pcr_extra_section" translatable="false">Um sicherzustellen, dass niemand mit Ihrem QR-Code Ihr Testergebnis abrufen kann, wird es mit Ihrem Geburtsdatum geschützt. Ihr Geburtsdatum wird verschlüsselt an das Labor übermittelt, um das Testergebnis abzurufen.</string>
     <!-- XTXT: Request GC bullet point 3 for privacy card -->
-    <string name="request_green_certificate_privacy_section_3" translatable="false">Das COVID-19-Testzertifikat enthält die Daten über Ihren Corona-Test. Zum Nachweis des negativen Testergebnisses in den gesetzlich vorgesehenen Fällen genügt das Vorzeigen des QR-Codes in der App. Stellen Sie das Testzertifikat niemandem zur Verfügung, wenn Sie nicht wollen, dass die Daten ausgelesen werden.</string>
+    <string name="request_green_certificate_privacy_section_3" translatable="false">Das COVID-Testzertifikat enthält die Daten über Ihren Corona-Test. Zum Nachweis des negativen Testergebnisses in den gesetzlich vorgesehenen Fällen genügt das Vorzeigen des QR-Codes in der App. Stellen Sie das Testzertifikat niemandem zur Verfügung, wenn Sie nicht wollen, dass die Daten ausgelesen werden.</string>
     <!-- XTXT: Request GC bullet point 4 for privacy card -->
     <string name="request_green_certificate_privacy_section_4" translatable="false">Wenn Sie den QR-Code des Testzertifikats in der App vorzeigen und dieser mit der Prüf-App gescannt wird, können andere Personen Ihr Testergebnis nachvollziehen. Bei der Prüfung werden in der offiziellen Prüf-App auch Ihr Name und Ihr Geburtsdatum angezeigt.</string>
     <!-- XTXT: Request GC bullet point 5 for privacy card -->
diff --git a/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml
index a6cbbe492b6992fdf059623c3e726c29ee41198c..bf012a6726c6eb8605a6c00fbd1cdc72000ac910 100644
--- a/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation">
     <!-- ####################################
-                 Release Info Screen 1.14
+                 Release Info Screen
      ###################################### -->
 
     <!-- XHED: Title for the release info screen -->
@@ -17,22 +17,26 @@
 
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
-        <item>Digitaler Impfnachweis</item>
+        <item>COVID-Testzertifikat</item>
+        <item>Erweiterung Kontakt-Tagebuch</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
-        <item>Sie können jetzt Ihre Impfzertifikate in der App hinzufügen und per QR-Code vorweisen. 14 Tage nach der letzten Impfung zeigt die App den vollständigen Impfschutz an.</item>
+        <item>Sie können nun über die App ein offizielles digitales Testzertifikat anfordern und anschließend in der App hinzufügen. Sie können das Testzertifikat (QR-Code) innerhalb der EU verwenden, um ein negatives Testergebnis nachzuweisen (z.B. für Auslandsreisen).</item>
+        <item>Sobald Ihr Testergebnis vorliegt, wird es nun auch Ihrem Kontakt-Tagebuch hinzugefügt.</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item></item>
+        <item></item>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item></item>
+        <item></item>
     </string-array>
 
 </resources>
diff --git a/Corona-Warn-App/src/main/res/values-de/strings.xml b/Corona-Warn-App/src/main/res/values-de/strings.xml
index 84d82a8f6995062c1ae472b157ac0de81af3b1af..3c2ca8c99dbbce8683002e84e14fedda9ea8a9e0 100644
--- a/Corona-Warn-App/src/main/res/values-de/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/strings.xml
@@ -1031,7 +1031,7 @@
     <!-- YTXT:  Body sub text 2 for Submission Consent call test result   -->
     <string name="submission_consent_call_test_result_scan_test_only_once">"Jeder Test kann nur einmal gescannt werden. Die App kann maximal einen Schnelltest und einen PCR-Test gleichzeitig verwalten."</string>
     <!-- YTXT:  Body sub text 3 for Submission Consent call test result   -->
-    <string name="submission_consent_call_test_result_checkmark_text">"Wenn Ihr Testergebnis negativ ist, können Sie dies in Form eines offiziellen COVID-19-Testzertifikats bestätigen lassen. Fordern Sie hierfür in den folgenden Schritten das Testzertifikat an."</string>
+    <string name="submission_consent_call_test_result_checkmark_text">"Wenn Ihr Testergebnis negativ ist, können Sie dies in Form eines offiziellen COVID-Testzertifikats bestätigen lassen. Fordern Sie hierfür in den folgenden Schritten das Testzertifikat an."</string>
     <!-- XHED: Page subheadline for consent help by warning others  -->
     <string name="submission_consent_help_by_warning_others_headline">"Helfen Sie mit, indem Sie andere warnen, denen Sie begegnet sind!"</string>
     <!-- YTXT: Body for consent help by warning others -->
@@ -1193,7 +1193,7 @@
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"QR-Code scannen"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
-    <string name="submission_dispatcher_qr_card_text">"Erhalten Sie Ihr Testergebnis in der App und warnen Sie andere oder fordern Sie Ihr COVID-19-Testzertifikat an."</string>
+    <string name="submission_dispatcher_qr_card_text">"Erhalten Sie Ihr Testergebnis in der App und warnen Sie andere oder fordern Sie Ihr COVID-Testzertifikat an."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
     <string name="submission_dispatcher_card_tan_code">"TAN für PCR-Test eingeben"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
@@ -1853,7 +1853,7 @@
     <!-- XHED: Title for BottomNav check-in screen title -->
     <string name="bottom_nav_check_ins_title">Check-in</string>
     <!-- XHED: Title for BottomNav certificates screen title -->
-    <string name="bottom_nav_certificates_title">"Nachweise"</string>
+    <string name="bottom_nav_certificates_title">"Zertifikate"</string>
     <!-- ####################################
            Data Donation & Survey
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml
index e3dbe17b033fd3d75789f0335d08e9beb91a9368..073658eb88562ccd8179fb6d7d22387431636cd3 100644
--- a/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml
@@ -71,7 +71,9 @@
     <!-- XBUT: button for Vaccination Certificate Registration Home Card -->
     <string name="vaccination_card_register">"Hinzufügen"</string>
     <!-- XHED: Homescreen vaccination status card title -->
-    <string name="vaccination_card_status_title">Digitaler Impfnachweis</string>
+    <string name="vaccination_card_status_title_line_1">"Digitaler"</string>
+    <!-- XHED: Homescreen vaccination status card title -->
+    <string name="vaccination_card_status_title_line_2">"Impfnachweis"</string>
     <!-- XHED: Homescreen vaccination status card vaccination name -->
     <string name="vaccination_card_status_vaccination_name">SARS-CoV-2 Impfschutz</string>
     <!-- XTXT: Homescreen card incomplete vaccination status label -->
@@ -85,6 +87,8 @@
         <item quantity="few">Vollständiger Impfschutz in %1$d Tagen</item>
         <item quantity="many">Vollständiger Impfschutz in %1$d Tagen</item>
     </plurals>
+    <!-- XTXT: Homescreen card complete vaccination status label -->
+    <string name="vaccination_card_status_vaccination_complete">"Gültig bis einschließlich %s"</string>
 
     <!-- XTXT: Vaccination QR code scan error message-->
     <string name="error_vc_invalid">Dieser QR-Code ist kein gültiges Impfzertifikat.</string>
diff --git a/Corona-Warn-App/src/main/res/values-en/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-en/antigen_strings.xml
index be0ef44805562242bd599d048b3af7c66de14283..566c614eb2cf7ad4f67557ea834c5a065deca493 100644
--- a/Corona-Warn-App/src/main/res/values-en/antigen_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/antigen_strings.xml
@@ -6,8 +6,7 @@
     <!-- XHED: Register test homescreen card: title -->
     <string name="ag_homescreen_card_test_register_title">"Register Your Test"</string>
     <!-- XTXT: Register test homescreen card: body -->
-    <string name="ag_homescreen_card_test_register_body">"Use the app to register your tests and retrieve your test results, so you can warn others more quickly."</string>
-
+    <string name="ag_homescreen_card_test_register_body">"Use the app to register your tests and retrieve your test results, so you can warn others more quickly, or to request your COVID test certificate."</string>
     <!-- ####################################
         Homescreen cards - common buttons
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml
index d323982a0fcdcb275c2296e8ba8af2a7a94781c1..27451f4224fd79befd9bd7c158edcc459f5835e7 100644
--- a/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml
@@ -182,4 +182,13 @@
     <string name="contact_diary_location_visit_duration_hour">"hrs"</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Note (e.g. very full)"</string>
+
+    <!-- XTXT: PCR test title in the day overview -->
+    <string name="contact_diary_corona_test_pcr_title">"PCR Test Registered"</string>
+    <!-- XTXT: RAT test title in the day overview -->
+    <string name="contact_diary_corona_test_rat_title">"Rapid Test Performed"</string>
+    <!-- XTXT: positive test result in the day overview -->
+    <string name="contact_diary_corona_test_positive">"Positive Diagnosis"</string>
+    <!-- XTXT: negative test result in the day overview -->
+    <string name="contact_diary_corona_test_negative">"Negative Diagnosis"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-en/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values-en/event_registration_strings.xml
index 5c5c18dfeed7053489d00d31ed5824149ff60271..c6b317bfcf80acb99f637af506137f0f6578d223 100644
--- a/Corona-Warn-App/src/main/res/values-en/event_registration_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/event_registration_strings.xml
@@ -210,6 +210,8 @@
     <string name="trace_location_organizer_detail_item_duration">"%1$s, %2$s - %3$s"</string>
     <!-- XTXT: Event organizer detail qr-code: duration with multiple date -->
     <string name="trace_location_organizer_detail_item_duration_multiple_days">"%1$s, %2$s - %3$s, %4$s"</string>
+    <!-- XTXT: Past Event Info duration -->
+    <string name="trace_location_attendee_past_event_duration">"%1$s"</string>
 
     <!-- XBUT: Event organiser list item: menu: information button  -->
     <string name="trace_location_organizer_list_item_menu_duplicate_btn">"Duplicate"</string>
diff --git a/Corona-Warn-App/src/main/res/values-en/green_certificate_strings.xml b/Corona-Warn-App/src/main/res/values-en/green_certificate_strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4d945372179f5d78a3cd8891514823e8e52f5377
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/values-en/green_certificate_strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
+    <!-- XTXT: Request green certificate title -->
+    <string name="request_green_certificate_title">"COVID Test Certificate"</string>
+    <!-- XTXT: Request green certificate subtitle -->
+    <string name="request_green_certificate_subtitle">"You can use the app to request an official digital test certificate, which is then added in the app."</string>
+    <!-- XTXT: Request green certificate body section 1 -->
+    <string name="request_green_certificate_body_1">"The test certificate is only issued if your test result is negative."</string>
+    <!-- XTXT: Request green certificate body section 2 -->
+    <string name="request_green_certificate_body_2">"The test certificate is valid proof of a negative test result within the EU (e.g. for travel)."</string>
+    <!-- XTXT: Request green certificate body section 3 -->
+    <string name="request_green_certificate_body_3">"The test certificate contains valid that enables the verification app to validate your certificate."</string>
+    <!-- XBUT: Request green certificate agree button -->
+    <string name="request_green_certificate_agree_button">"Request Test Certificate"</string>
+    <!-- XBUT: Request green certificate disagree button -->
+    <string name="request_green_certificate_disagree_button">"No Thank You"</string>
+    <!-- XTXT: Request green certificate birth date description -->
+    <string name="request_green_certificate_birthdate_description">"For security purposes, your test result is protected with your date of birth. The test result can only be issued if you specify the correct date of birth."</string>
+    <!-- XTXT: Request green certificate birth date hint -->
+    <string name="request_green_certificate_birthdate_hint">"Date of Birth"</string>
+    <!-- XTXT: Request green certificate exit dialog title -->
+    <string name="request_gc_dialog_title">"Cancel Registration"</string>
+    <!-- XTXT: Request green certificate exit dialog message -->
+    <string name="request_gc_dialog_message">"If you cancel the test registration, you cannot receive your test result in the app."</string>
+    <!-- XBUT: Request green certificate exit dialog negative button -->
+    <string name="request_gc_dialog_positive_button">"OK"</string>
+    <!-- XBUT: Request green certificate exit dialog negative button -->
+    <string name="request_gc_dialog_negative_button">"Cancel"</string>
+    <!-- XTXT: Detail green certificate title -->
+    <string name="detail_green_certificate_title">"EU Digital COVID Test Certificate"</string>
+    <!-- XTXT: Detail green certificate test type -->
+    <string name="detail_green_certificate_test_type">"SARS-CoV-2 Test"</string>
+    <!-- XTXT: Detail green certificate card title -->
+    <string name="detail_green_certificate_card_title">"Test Certificate"</string>
+    <!-- XTXT: Detail green certificate travel notice link en -->
+    <string name="green_certificate_travel_notice_link_en">"https://reopen.europa.eu/en"</string>
+    <!-- XTXT: Detail green certificate travel notice link de -->
+    <string name="green_certificate_travel_notice_link_de">"https://reopen.europa.eu/de"</string>
+    <!-- XTXT: Green certificate main screen title -->
+    <string name="certification_screen_title">"Certificates"</string>
+    <!-- XTXT: Green certificate menu item -->
+    <string name="menu_certification_information">"Information"</string>
+    <!-- XTXT: Green certificate main screen header text -->
+    <string name="green_certification_header_info">"Your digital vaccination certificates and test certificates are displayed here."</string>
+    <!-- XTXT: Green certificate info card title 1st line -->
+    <string name="info_banner_title_1">"Digital COVID-19"</string>
+    <!-- XTXT: Green certificate info card title 2nd line  -->
+    <string name="info_banner_title_2">"COVID Test Certificate"</string>
+    <!-- XTXT: Green certificate info card body  -->
+    <string name="info_banner_body">"Register a test on the home screen and agree to receive a digital test certificate. As soon as the certificate is available, it is displayed here."</string>
+</resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml
index 5302462e1984ec8a7b1b38c1fffa68c67b1c991a..275ba2d9f3649f533c1a874bc1ae18d6de887ee7 100644
--- a/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation">
     <!-- ####################################
-                 Release Info Screen 1.14
+                 Release Info Screen
      ###################################### -->
 
     <!-- XHED: Title for the release info screen -->
@@ -16,22 +16,26 @@
 
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
-        <item>"Digital Proof of Vaccination"</item>
+        <item>"COVID Test Certificate"</item>
+        <item>"Contact Journal Enhancement"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
-        <item>"You can now add your vaccination certificates in the app and present them via QR code. The app displays full vaccination protection 14 days after the final vaccination."</item>
+        <item>"You can now request an official digital test certificate through the app and then add it in the app. You can use this test certificate (QR code) within the EU to prove a negative test result (for international travel, for example)."</item>
+        <item>"As soon as your test result is available, it is now also added to your contact journal."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
+        <item/>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
+        <item/>
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-en/strings.xml b/Corona-Warn-App/src/main/res/values-en/strings.xml
index 08e17636898a81ca4b380c7e6f3baf6a56b1a3ed..d4eeb5af5155c76c7800fd3ce6fc77badebc2c26 100644
--- a/Corona-Warn-App/src/main/res/values-en/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/strings.xml
@@ -281,6 +281,8 @@
     <string name="risk_details_behavior_body_wear_mask">"Wear a face mask when you encounter other people."</string>
     <!-- XMSG: risk details - stay 1,5 away, something like a bullet point -->
     <string name="risk_details_behavior_body_stay_away">"Keep at least 1.5 meters distance from other people."</string>
+    <!-- XTXT: find details about exposures in the contact journal -->
+    <string name="risk_details_find_details_in_journal">"You will find more information about your exposures in your contact journal."</string>
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"If you get tested, you will find additional information about the testing procedure in the FAQ."</string>
@@ -1027,6 +1029,8 @@
     <string name="submission_consent_call_test_result_scan_your_test_only">"Now scan the QR code for your test and retrieve your test result."</string>
     <!-- YTXT:  Body sub text 2 for Submission Consent call test result   -->
     <string name="submission_consent_call_test_result_scan_test_only_once">"Each test can only be scanned once. The app can manage a maximum of one rapid test and one PCR test at the same time."</string>
+    <!-- YTXT:  Body sub text 3 for Submission Consent call test result   -->
+    <string name="submission_consent_call_test_result_checkmark_text">"If your test result is negative, you can confirm this with an official COVID test certificate. To do so, request the test certificate in the following steps."</string>
     <!-- XHED: Page subheadline for consent help by warning others  -->
     <string name="submission_consent_help_by_warning_others_headline">"Please help others you have encountered by warning them!"</string>
     <!-- YTXT: Body for consent help by warning others -->
@@ -1087,6 +1091,15 @@
     <!-- YTXT: Body text for next steps section of waiting test result page -->
     <string name="submission_test_result_pending_steps_contact_diary_body">"As soon as your test result becomes available, it will be displayed in the app."</string>
 
+    <!-- XHED: Page headline for test result certifcate info title  -->
+    <string name="submission_test_result_pending_steps_test_certificate_heading">"Your Test Certificate"</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not supported, RAT Test -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_supported_body">"No test certificate is available because this testing point does not support the issuing of test certificates."</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not available yet, PCR Test consent given -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_available_yet_body">"Your test certificate is not available yet. As soon as it becomes available, it will be displayed in your app."</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not desired by the user, PCR Test no consent given -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_desired_by_user_body">"No test certificate was issued, as per your request."</string>
+
     <!-- XBUT: test result pending : refresh button -->
     <string name="submission_test_result_pending_refresh_button">"Update"</string>
     <!-- XBUT: test result pending : remove the test button -->
@@ -1179,7 +1192,7 @@
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"Scan QR Code"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
-    <string name="submission_dispatcher_qr_card_text">"Receive your test result in the app and warn others."</string>
+    <string name="submission_dispatcher_qr_card_text">"Receive your test result in the app and warn others or request your COVID test certificate."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
     <string name="submission_dispatcher_card_tan_code">"Enter TAN for PCR Test"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
@@ -1838,7 +1851,8 @@
     <string name="bottom_nav_diary_title">"Journal"</string>
     <!-- XHED: Title for BottomNav check-in screen title -->
     <string name="bottom_nav_check_ins_title">"Check In"</string>
-
+    <!-- XHED: Title for BottomNav certificates screen title -->
+    <string name="bottom_nav_certificates_title">"Certificates"</string>
     <!-- ####################################
            Data Donation & Survey
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml
index 544947973a502df92d8333e1759afba156598408..7ba8457914219ee27e49c4a26182a820c56031a0 100644
--- a/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml
@@ -8,7 +8,7 @@
     <!-- XTXT: Vaccination Details vaccine manufacturer -->
     <string name="vaccination_details_vaccine_manufacturer">"Manufacturer"</string>
     <!-- XTXT: Vaccination Details vaccine type -->
-    <string name="vaccination_details_vaccine_medical_product_name">"Vaccine type"</string>
+    <string name="vaccination_details_vaccine_medical_product_name">"Vaccine Type"</string>
     <!-- XTXT: Vaccination Details certificate issuer -->
     <string name="vaccination_details_certificate_issuer">"Issuer"</string>
     <!-- XTXT: Vaccination Details certificate country -->
@@ -20,9 +20,9 @@
     <!-- XTXT: Vaccination Details title-->
     <string name="vaccination_details_title">"Vaccination %1$d of %2$d"</string>
     <!-- XTXT: Vaccination Qr Code card title-->
-    <string name="vaccination_qrcode_card_title">"Vaccination certificate %1$d of %2$d"</string>
+    <string name="vaccination_qrcode_card_title">"Vaccination Certificate %1$d of %2$d"</string>
     <!-- XTXT: Vaccination Qr Code card subtitle-->
-    <string name="vaccination_qrcode_card_subtitle">"Vaccinated %1$s - valid to %2$s"</string>
+    <string name="vaccination_qrcode_card_subtitle">"Vaccinated %1$s - Valid to %2$s"</string>
 
     <!-- XTXT: Vaccination List title-->
     <string name="vaccination_list_title">"Digital Proof of Vaccination"</string>
@@ -36,12 +36,12 @@
     <string name="vaccination_list_vaccination_card_subtitle">"Performed on %1$s"</string>
     <!-- XTXT: Vaccination List immunity information card body-->
     <plurals name="vaccination_list_immunity_card_body">
-        <item quantity="one">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d day."</item>
-        <item quantity="other">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
-        <item quantity="zero">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
-        <item quantity="two">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
-        <item quantity="few">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
-        <item quantity="many">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
+        <item quantity="one">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d day."</item>
+        <item quantity="other">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
+        <item quantity="zero">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
+        <item quantity="two">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
+        <item quantity="few">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
+        <item quantity="many">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
     </plurals>
     <!-- XBUT: Vaccination List register additional vaccination button -->
     <string name="vaccination_list_register_new_vaccination_button">"Register Another Vaccination"</string>
@@ -62,9 +62,11 @@
         Homescreen cards
     ###################################### -->
     <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_title">"Add Vaccination Certificate"</string>
+    <string name="vaccination_card_registration_title_line_1">"Add Digital Proof"</string>
+    <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
+    <string name="vaccination_card_registration_title_line_2">"of Vaccination"</string>
     <!-- YTXT: Body text for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_body">"Add vaccination certificates in the app so you always have them with you. To do so, scan the QR code on your document."</string>
+    <string name="vaccination_card_registration_body">"Add your vaccination certificates in the app so you always have them with you. To do so, scan the QR code on your document."</string>
     <!-- XBUT: button for Vaccination Certificate Registration Home Card -->
     <string name="vaccination_card_register">"Add"</string>
     <!-- XHED: Homescreen vaccination status card title -->
@@ -97,17 +99,17 @@
     <!-- XTXT: Vaccination Consent title-->
     <string name="vaccination_consent_title">"Your Consent"</string>
     <!-- XTXT: Vaccination Consent subtitle-->
-    <string name="vaccination_consent_headline">"Add Vaccination Certificate"</string>
+    <string name="vaccination_consent_headline">"Add Certificates"</string>
     <!-- XTXT: Vaccination Consent subtitle of qr info -->
-    <string name="vaccination_consent_info_subtitle_text">"Add your digital vaccination certificate in the app. As soon as your vaccination protection is complete, you can present the QR code in your app as proof of your vaccination."</string>
+    <string name="vaccination_consent_info_subtitle_text">"Add your digital COVID certificates in the app. This will enable you to prove your vaccination protection or a negative test result with the app."</string>
     <!-- XTXT: Vaccination Consent text of qr info -->
-    <string name="vaccination_consent_qr_info_text">"To add a vaccination certificate in the app, scan the QR code that you received during your vaccination."</string>
+    <string name="vaccination_consent_qr_info_text">"You can add digital COVID vaccination certificates or COVID test certificates in the app."</string>
     <!-- XTXT: Vaccination Consent qr code text -->
-    <string name="vaccination_consent_qr_info_qr_code_text">"The app reads the information from the QR code and saves it in a secure area on your smartphone."</string>
+    <string name="vaccination_consent_qr_info_qr_code_text">"These certificates are considered to be valid proof within the EU (e.g. for travel)."</string>
     <!-- XTXT: Vaccination Consent time text  -->
-    <string name="vaccination_consent_qr_info_time_text">"The data will remain on the smartphone. It will only be transmitted to others if you present your vaccination certificate for verification."</string>
+    <string name="vaccination_consent_qr_info_time_text">"After you add a certificate, it will remain on your smartphone. It will only be shared with others if you present a certificate for verification."</string>
     <!-- XTXT: Text for vaccination consent legal information button -->
-    <string name="vaccination_consent_onboarding_legal_information">"For more information, please refer to the privacy notice."</string>
+    <string name="vaccination_consent_onboarding_legal_information">"For more detailed information about data processing, please refer to the privacy notice."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Continue"</string>
 
diff --git a/Corona-Warn-App/src/main/res/values-pl/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-pl/antigen_strings.xml
index 40fe4308ce558ebe27f659c9020180cf9245dd15..076c006f193cb06bc1c01751e391bf4f5bb3e6b2 100644
--- a/Corona-Warn-App/src/main/res/values-pl/antigen_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/antigen_strings.xml
@@ -6,8 +6,7 @@
     <!-- XHED: Register test homescreen card: title -->
     <string name="ag_homescreen_card_test_register_title">"Zarejestruj test"</string>
     <!-- XTXT: Register test homescreen card: body -->
-    <string name="ag_homescreen_card_test_register_body">"Korzystaj z aplikacji do rejestrowania swoich testów i pobierania ich wyników, aby szybciej ostrzegać innych."</string>
-
+    <string name="ag_homescreen_card_test_register_body">"Aplikacji możesz używać do rejestrowania testów i pobierania ich wyników, aby szybciej ostrzegać innych. Za jej pośrednictwem możesz także poprosić o wydanie certyfikatu testu na COVID."</string>
     <!-- ####################################
         Homescreen cards - common buttons
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-pl/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-pl/contact_diary_strings.xml
index dcec3c8b4cf4e134170a6e6d278facaee44e05dd..0ab0471521c6c34e9e4437023f6d092014ce785b 100644
--- a/Corona-Warn-App/src/main/res/values-pl/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/contact_diary_strings.xml
@@ -182,4 +182,13 @@
     <string name="contact_diary_location_visit_duration_hour">"godz."</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Uwaga (np. bardzo pełny)"</string>
+
+    <!-- XTXT: PCR test title in the day overview -->
+    <string name="contact_diary_corona_test_pcr_title">"Zarejestrowano test PCR"</string>
+    <!-- XTXT: RAT test title in the day overview -->
+    <string name="contact_diary_corona_test_rat_title">"Wykonano szybki test"</string>
+    <!-- XTXT: positive test result in the day overview -->
+    <string name="contact_diary_corona_test_positive">"Diagnoza: zakażenie"</string>
+    <!-- XTXT: negative test result in the day overview -->
+    <string name="contact_diary_corona_test_negative">"Diagnoza: brak zakażenia"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-pl/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values-pl/event_registration_strings.xml
index 599ee758e5045059155d1660fac10953155c06a0..e699fcc2bb2acdf3f7044d21629be8f488b55f13 100644
--- a/Corona-Warn-App/src/main/res/values-pl/event_registration_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/event_registration_strings.xml
@@ -210,6 +210,8 @@
     <string name="trace_location_organizer_detail_item_duration">"%1$s, %2$s - %3$s"</string>
     <!-- XTXT: Event organizer detail qr-code: duration with multiple date -->
     <string name="trace_location_organizer_detail_item_duration_multiple_days">"%1$s, %2$s - %3$s, %4$s"</string>
+    <!-- XTXT: Past Event Info duration -->
+    <string name="trace_location_attendee_past_event_duration">"%1$s"</string>
 
     <!-- XBUT: Event organiser list item: menu: information button  -->
     <string name="trace_location_organizer_list_item_menu_duplicate_btn">"Duplikuj"</string>
diff --git a/Corona-Warn-App/src/main/res/values-pl/green_certificate_strings.xml b/Corona-Warn-App/src/main/res/values-pl/green_certificate_strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0ab72d844ebb07cf949604ed985321f1a6f6bdb7
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/values-pl/green_certificate_strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
+    <!-- XTXT: Request green certificate title -->
+    <string name="request_green_certificate_title">"Certyfikat testu na COVID"</string>
+    <!-- XTXT: Request green certificate subtitle -->
+    <string name="request_green_certificate_subtitle">"Za pomocą aplikacji możesz poprosić o oficjalny cyfrowy certyfikat testu, który zostanie następnie w niej dodany."</string>
+    <!-- XTXT: Request green certificate body section 1 -->
+    <string name="request_green_certificate_body_1">"Certyfikat testu jest wydawany tylko wtedy, gdy wynik testu jest negatywny."</string>
+    <!-- XTXT: Request green certificate body section 2 -->
+    <string name="request_green_certificate_body_2">"Certyfikat testu jest ważnym dowodem negatywnego wyniku testu na terenie UE (np. dla celów podróży)."</string>
+    <!-- XTXT: Request green certificate body section 3 -->
+    <string name="request_green_certificate_body_3">"Certyfikat zawiera ważne dane, które umożliwiają aplikacji weryfikacyjnej jego walidację."</string>
+    <!-- XBUT: Request green certificate agree button -->
+    <string name="request_green_certificate_agree_button">"PoproÅ› o certyfikat testu"</string>
+    <!-- XBUT: Request green certificate disagree button -->
+    <string name="request_green_certificate_disagree_button">"Nie, dziękuję"</string>
+    <!-- XTXT: Request green certificate birth date description -->
+    <string name="request_green_certificate_birthdate_description">"Ze względów bezpieczeństwa wynik testu jest zabezpieczony za pomocą daty urodzenia. Wynik testu może zostać wydany tylko po podaniu prawidłowej daty urodzenia."</string>
+    <!-- XTXT: Request green certificate birth date hint -->
+    <string name="request_green_certificate_birthdate_hint">"Data urodzenia"</string>
+    <!-- XTXT: Request green certificate exit dialog title -->
+    <string name="request_gc_dialog_title">"Anuluj rejestracjÄ™"</string>
+    <!-- XTXT: Request green certificate exit dialog message -->
+    <string name="request_gc_dialog_message">"Anulowanie rejestracji testu uniemożliwi otrzymanie wyniku testu w aplikacji."</string>
+    <!-- XBUT: Request green certificate exit dialog negative button -->
+    <string name="request_gc_dialog_positive_button">"OK"</string>
+    <!-- XBUT: Request green certificate exit dialog negative button -->
+    <string name="request_gc_dialog_negative_button">"Anuluj"</string>
+    <!-- XTXT: Detail green certificate title -->
+    <string name="detail_green_certificate_title">"Unijny cyfrowy certyfikat testu na COVID"</string>
+    <!-- XTXT: Detail green certificate test type -->
+    <string name="detail_green_certificate_test_type">"Test SARS-CoV-2"</string>
+    <!-- XTXT: Detail green certificate card title -->
+    <string name="detail_green_certificate_card_title">"Certyfikat testu"</string>
+    <!-- XTXT: Detail green certificate travel notice link en -->
+    <string name="green_certificate_travel_notice_link_en">"https://reopen.europa.eu/en"</string>
+    <!-- XTXT: Detail green certificate travel notice link de -->
+    <string name="green_certificate_travel_notice_link_de">"https://reopen.europa.eu/de"</string>
+    <!-- XTXT: Green certificate main screen title -->
+    <string name="certification_screen_title">"Certyfikaty"</string>
+    <!-- XTXT: Green certificate menu item -->
+    <string name="menu_certification_information">"Informacje"</string>
+    <!-- XTXT: Green certificate main screen header text -->
+    <string name="green_certification_header_info">"Tutaj wyświetlane są Twoje cyfrowe świadectwa szczepień i certyfikaty testów."</string>
+    <!-- XTXT: Green certificate info card title 1st line -->
+    <string name="info_banner_title_1">"Cyfrowy COVID-19"</string>
+    <!-- XTXT: Green certificate info card title 2nd line  -->
+    <string name="info_banner_title_2">"Certyfikat testu na COVID"</string>
+    <!-- XTXT: Green certificate info card body  -->
+    <string name="info_banner_body">"Zarejestruj test na ekranie głównym i wyraź zgodę na otrzymanie cyfrowego certyfikatu testu. Gdy tylko certyfikat będzie dostępny, pojawi się w tym miejscu."</string>
+</resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml
index db68e982dfac05b2d6862c89aadd7f113c60398f..36caa53180961d8cf85a5a88791ab0b99c3e4a64 100644
--- a/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation">
     <!-- ####################################
-                 Release Info Screen 1.14
+                 Release Info Screen
      ###################################### -->
 
     <!-- XHED: Title for the release info screen -->
@@ -16,22 +16,26 @@
 
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
-        <item>"Cyfrowy dowód szczepienia"</item>
+        <item>"Certyfikat testu na COVID"</item>
+        <item>"Rozszerzenie dziennika kontaktów"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
-        <item>"Teraz możesz dodać swoje świadectwa szczepienia w aplikacji i okazywać je za pomocą kodu QR. Aplikacja wyświetla pełną ochronę poszczepienną 14 dni po ostatnim szczepieniu."</item>
+        <item>"Możesz teraz poprosić o oficjalny cyfrowy certyfikat testu za pośrednictwem aplikacji, a następnie dodać go w aplikacji. Certyfikatu testu (kodu QR) możesz używać w UE jako dowodu negatywnego wyniku testu (na przykład w przypadku podróży międzynarodowych)."</item>
+        <item>"Gdy tylko Twój wynik testu będzie dostępny, zostanie on również dodany do Twojego dziennika kontaktów."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
+        <item/>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
+        <item/>
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-pl/strings.xml b/Corona-Warn-App/src/main/res/values-pl/strings.xml
index 0ceebd83a9b4b094d92da9609691f7ec2ddfad30..e7ebf5e3ecead984375f3a3f95010e35aaed009c 100644
--- a/Corona-Warn-App/src/main/res/values-pl/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/strings.xml
@@ -281,6 +281,8 @@
     <string name="risk_details_behavior_body_wear_mask">"Załóż maseczkę na twarz, mając kontakt z innymi osobami."</string>
     <!-- XMSG: risk details - stay 1,5 away, something like a bullet point -->
     <string name="risk_details_behavior_body_stay_away">"Zachowuj odległość co najmniej 1,5 metra od innych osób."</string>
+    <!-- XTXT: find details about exposures in the contact journal -->
+    <string name="risk_details_find_details_in_journal">"Więcej informacji na temat narażeń znajdziesz w swoim dzienniku kontaktów."</string>
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"Jeśli poddasz się testowi, dodatkowe informacje na temat procedury testowania znajdziesz w „Często zadawanych pytaniach”."</string>
@@ -1027,6 +1029,8 @@
     <string name="submission_consent_call_test_result_scan_your_test_only">"Zeskanuj teraz kod QR dla swojego testu i pobierz wynik testu."</string>
     <!-- YTXT:  Body sub text 2 for Submission Consent call test result   -->
     <string name="submission_consent_call_test_result_scan_test_only_once">"Test można zeskanować tylko raz. Aplikacja może zarządzać maksymalnie jednym szybkim testem i jednym testem PCR jednocześnie."</string>
+    <!-- YTXT:  Body sub text 3 for Submission Consent call test result   -->
+    <string name="submission_consent_call_test_result_checkmark_text">"Jeśli wynik Twojego testu jest negatywny, możesz to potwierdzić oficjalnym certyfikatem testu na COVID. W tym celu poproś o certyfikat testu, wykonując następujące kroki."</string>
     <!-- XHED: Page subheadline for consent help by warning others  -->
     <string name="submission_consent_help_by_warning_others_headline">"Pomóż osobom, z którymi miałeś(-aś) kontakt, ostrzegając ich!"</string>
     <!-- YTXT: Body for consent help by warning others -->
@@ -1087,6 +1091,15 @@
     <!-- YTXT: Body text for next steps section of waiting test result page -->
     <string name="submission_test_result_pending_steps_contact_diary_body">"Wynik testu zostanie wyświetlony w aplikacji, jak tylko będzie dostępny."</string>
 
+    <!-- XHED: Page headline for test result certifcate info title  -->
+    <string name="submission_test_result_pending_steps_test_certificate_heading">"Twój certyfikat testu "</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not supported, RAT Test -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_supported_body">"Certyfikat testu jest niedostępny, ponieważ ten punkt testowania nie wydaje certyfikatów testów."</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not available yet, PCR Test consent given -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_available_yet_body">"Twój certyfikat testu nie jest jeszcze dostępny. Gdy tylko stanie się dostępny, pojawi się w Twojej aplikacji."</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not desired by the user, PCR Test no consent given -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_desired_by_user_body">"Zgodnie z Twoją prośbą nie wydano certyfikatu testu."</string>
+
     <!-- XBUT: test result pending : refresh button -->
     <string name="submission_test_result_pending_refresh_button">"Aktualizuj"</string>
     <!-- XBUT: test result pending : remove the test button -->
@@ -1179,7 +1192,7 @@
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"Skanuj kod QR"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
-    <string name="submission_dispatcher_qr_card_text">"Odbierz wynik testu w aplikacji i ostrzegaj innych."</string>
+    <string name="submission_dispatcher_qr_card_text">"Odbierz wynik testu w aplikacji i ostrzegaj innych lub poproÅ› o certyfikat testu na COVID."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
     <string name="submission_dispatcher_card_tan_code">"Wpisz TAN do testu PCR"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
@@ -1838,7 +1851,8 @@
     <string name="bottom_nav_diary_title">"Dziennik"</string>
     <!-- XHED: Title for BottomNav check-in screen title -->
     <string name="bottom_nav_check_ins_title">"Zamelduj siÄ™"</string>
-
+    <!-- XHED: Title for BottomNav certificates screen title -->
+    <string name="bottom_nav_certificates_title">"Certyfikaty"</string>
     <!-- ####################################
            Data Donation & Survey
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml
index cee8e892c5edb5e37b6490b96dcda379bdb770f6..b0453ba0a663964ad8981315f5c3bca5759cce57 100644
--- a/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml
@@ -20,9 +20,9 @@
     <!-- XTXT: Vaccination Details title-->
     <string name="vaccination_details_title">"Szczepienie %1$d / %2$d"</string>
     <!-- XTXT: Vaccination Qr Code card title-->
-    <string name="vaccination_qrcode_card_title">"Åšwiadectwo szczepienia %1$d / %2$d"</string>
+    <string name="vaccination_qrcode_card_title">"Åšwiadectwo szczepienia %1$d %2$d"</string>
     <!-- XTXT: Vaccination Qr Code card subtitle-->
-    <string name="vaccination_qrcode_card_subtitle">"Zaszczepiony(-a) %1$s - ważne do %2$s"</string>
+    <string name="vaccination_qrcode_card_subtitle">"Zaszczepiono %1$s - ważne do %2$s"</string>
 
     <!-- XTXT: Vaccination List title-->
     <string name="vaccination_list_title">"Cyfrowy dowód szczepienia"</string>
@@ -36,12 +36,12 @@
     <string name="vaccination_list_vaccination_card_subtitle">"Wykonano dnia %1$s"</string>
     <!-- XTXT: Vaccination List immunity information card body-->
     <plurals name="vaccination_list_immunity_card_body">
-        <item quantity="one">"Otrzymałeś(-aś) już wszystkie szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dzień."</item>
-        <item quantity="other">"Otrzymałeś(-aś) już wszystkie szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dni."</item>
-        <item quantity="zero">"Otrzymałeś(-aś) już wszystkie szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dni."</item>
-        <item quantity="two">"Otrzymałeś(-aś) już wszystkie szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dni."</item>
-        <item quantity="few">"Otrzymałeś(-aś) już wszystkie szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dni."</item>
-        <item quantity="many">"Otrzymałeś(-aś) już wszystkie szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dni."</item>
+        <item quantity="one">"Otrzymałeś(-aś) już wszystkie zaplanowane dotychczas szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dzień."</item>
+        <item quantity="other">"Otrzymałeś(-aś) już wszystkie zaplanowane dotychczas szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dnia."</item>
+        <item quantity="zero">"Otrzymałeś(-aś) już wszystkie zaplanowane dotychczas szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dni."</item>
+        <item quantity="two">"Otrzymałeś(-aś) już wszystkie zaplanowane dotychczas szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dni."</item>
+        <item quantity="few">"Otrzymałeś(-aś) już wszystkie zaplanowane dotychczas szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dni."</item>
+        <item quantity="many">"Otrzymałeś(-aś) już wszystkie zaplanowane dotychczas szczepienia, jednak pełną ochronę poszczepienną uzyskasz dopiero za %1$d dni."</item>
     </plurals>
     <!-- XBUT: Vaccination List register additional vaccination button -->
     <string name="vaccination_list_register_new_vaccination_button">"Zarejestruj kolejne szczepienie"</string>
@@ -62,9 +62,11 @@
         Homescreen cards
     ###################################### -->
     <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_title">"Dodaj świadectwo szczepienia"</string>
+    <string name="vaccination_card_registration_title_line_1">"Dodaj cyfrowy dowód"</string>
+    <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
+    <string name="vaccination_card_registration_title_line_2">"szczepienia"</string>
     <!-- YTXT: Body text for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_body">"Dodaj świadectwa szczepienia w aplikacji, aby mieć je zawsze przy sobie. W tym celu zeskanuj kod QR znajdujący się na dokumencie."</string>
+    <string name="vaccination_card_registration_body">"Dodaj swoje świadectwa szczepienia w aplikacji, aby mieć je zawsze przy sobie. W tym celu zeskanuj kod QR znajdujący się na dokumencie."</string>
     <!-- XBUT: button for Vaccination Certificate Registration Home Card -->
     <string name="vaccination_card_register">"Dodaj"</string>
     <!-- XHED: Homescreen vaccination status card title -->
@@ -97,17 +99,17 @@
     <!-- XTXT: Vaccination Consent title-->
     <string name="vaccination_consent_title">"Twoja zgoda"</string>
     <!-- XTXT: Vaccination Consent subtitle-->
-    <string name="vaccination_consent_headline">"Dodaj świadectwo szczepienia"</string>
+    <string name="vaccination_consent_headline">"Dodaj świadectwa"</string>
     <!-- XTXT: Vaccination Consent subtitle of qr info -->
-    <string name="vaccination_consent_info_subtitle_text">"Dodaj cyfrowe świadectwo szczepienia w aplikacji. Gdy uzyskasz pełną ochronę poszczepienną, będziesz mógł (mogła) okazywać kod QR z aplikacji jako dowód szczepienia."</string>
+    <string name="vaccination_consent_info_subtitle_text">"Dodaj cyfrowe świadectwa szczepienia przeciw COVID w aplikacji. Umożliwi Ci to udowodnienie za pomocą aplikacji posiadanie ochrony poszczepiennej lub negatywnego wyniku testu."</string>
     <!-- XTXT: Vaccination Consent text of qr info -->
-    <string name="vaccination_consent_qr_info_text">"Aby dodać świadectwo szczepienia w aplikacji, zeskanuj kod QR, który otrzymałeś(-aś) podczas szczepienia."</string>
+    <string name="vaccination_consent_qr_info_text">"W aplikacji możesz dodać cyfrowe świadectwa szczepień przeciw COVID lub certyfikaty testów na COVID."</string>
     <!-- XTXT: Vaccination Consent qr code text -->
-    <string name="vaccination_consent_qr_info_qr_code_text">"Aplikacja odczytuje informacje z kodu QR i zapisuje je w bezpiecznym miejscu na Twoim smartfonie."</string>
+    <string name="vaccination_consent_qr_info_qr_code_text">"Takie świadectwa i certyfikaty są uznawane za ważny dowód w UE (np. w przypadku podróży)."</string>
     <!-- XTXT: Vaccination Consent time text  -->
-    <string name="vaccination_consent_qr_info_time_text">"Dane pozostaną na smartfonie. Będą one przekazywane innym osobom tylko wtedy, gdy będziesz przedstawiać świadectwo szczepienia do weryfikacji."</string>
+    <string name="vaccination_consent_qr_info_time_text">"Po dodaniu certyfikatu pozostanie on na Twoim smartfonie. Zostanie on udostępniony innym tylko podczas jego okazywania w celu weryfikacji."</string>
     <!-- XTXT: Text for vaccination consent legal information button -->
-    <string name="vaccination_consent_onboarding_legal_information">"Więcej informacji znajduje się w oświadczeniu o ochronie prywatności."</string>
+    <string name="vaccination_consent_onboarding_legal_information">"Więcej informacji na temat przetwarzania danych znajduje się w oświadczeniu o ochronie prywatności."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Kontynuuj"</string>
 
diff --git a/Corona-Warn-App/src/main/res/values-ro/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-ro/antigen_strings.xml
index 2a990d20c38dfc36f0632f9e6f06aa74b670fa1a..245102cd46f431beef2ed97554a2d35b0bf68f95 100644
--- a/Corona-Warn-App/src/main/res/values-ro/antigen_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/antigen_strings.xml
@@ -6,8 +6,7 @@
     <!-- XHED: Register test homescreen card: title -->
     <string name="ag_homescreen_card_test_register_title">"ÃŽnregistrarea testului dvs."</string>
     <!-- XTXT: Register test homescreen card: body -->
-    <string name="ag_homescreen_card_test_register_body">"Utilizați aplicația pentru a înregistra testele dvs. și a afla rezultatele testelor dvs. pentru a-i putea avertiza pe ceilalți mai rapid."</string>
-
+    <string name="ag_homescreen_card_test_register_body">"Utilizați aplicația pentru a înregistra testele dvs. și a afla rezultatele testelor dvs. pentru a-i putea avertiza pe ceilalți mai rapid sau pentru a solicita certificatul dvs. de test COVID."</string>
     <!-- ####################################
         Homescreen cards - common buttons
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml
index 74c6a300dd3ad7dd45598b880be494b962a29d81..be9b9e63c85d12a702bee2245b3f1abf8614ef80 100644
--- a/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml
@@ -182,4 +182,13 @@
     <string name="contact_diary_location_visit_duration_hour">"ore"</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Notă (de ex., foarte plin)"</string>
+
+    <!-- XTXT: PCR test title in the day overview -->
+    <string name="contact_diary_corona_test_pcr_title">"Test PCR înregistrat"</string>
+    <!-- XTXT: RAT test title in the day overview -->
+    <string name="contact_diary_corona_test_rat_title">"Test rapid efectuat"</string>
+    <!-- XTXT: positive test result in the day overview -->
+    <string name="contact_diary_corona_test_positive">"Diagnostic pozitiv"</string>
+    <!-- XTXT: negative test result in the day overview -->
+    <string name="contact_diary_corona_test_negative">"Diagnostic negativ"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-ro/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values-ro/event_registration_strings.xml
index d6927fcd4b62b48262dc552417930e15c8a64afa..59e14a2ecd1a29bf638ce5b091ef83f63a4a7c55 100644
--- a/Corona-Warn-App/src/main/res/values-ro/event_registration_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/event_registration_strings.xml
@@ -210,6 +210,8 @@
     <string name="trace_location_organizer_detail_item_duration">"%1$s, %2$s - %3$s"</string>
     <!-- XTXT: Event organizer detail qr-code: duration with multiple date -->
     <string name="trace_location_organizer_detail_item_duration_multiple_days">"%1$s, %2$s - %3$s, %4$s"</string>
+    <!-- XTXT: Past Event Info duration -->
+    <string name="trace_location_attendee_past_event_duration">"%1$s"</string>
 
     <!-- XBUT: Event organiser list item: menu: information button  -->
     <string name="trace_location_organizer_list_item_menu_duplicate_btn">"Duplicare"</string>
diff --git a/Corona-Warn-App/src/main/res/values-ro/green_certificate_strings.xml b/Corona-Warn-App/src/main/res/values-ro/green_certificate_strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..348c6a1a29591723d6f8606f85c57b92eb9308d2
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/values-ro/green_certificate_strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
+    <!-- XTXT: Request green certificate title -->
+    <string name="request_green_certificate_title">"Certificat de test COVID"</string>
+    <!-- XTXT: Request green certificate subtitle -->
+    <string name="request_green_certificate_subtitle">"Puteți utiliza aplicația pentru a solicita un certificat de test digital oficial, care este apoi adăugat în aplicație."</string>
+    <!-- XTXT: Request green certificate body section 1 -->
+    <string name="request_green_certificate_body_1">"Certificatul de test este emis doar dacă rezultatul testului dvs. este negativ."</string>
+    <!-- XTXT: Request green certificate body section 2 -->
+    <string name="request_green_certificate_body_2">"Certificatul de test este o dovadă valabilă a unui rezultat de test negativ în UE (de exemplu, în scop de călătorie)."</string>
+    <!-- XTXT: Request green certificate body section 3 -->
+    <string name="request_green_certificate_body_3">"Certificatul de test conține date care îi permit aplicației de verificare să vă valideze certificatul."</string>
+    <!-- XBUT: Request green certificate agree button -->
+    <string name="request_green_certificate_agree_button">"Solicitare certificat de test"</string>
+    <!-- XBUT: Request green certificate disagree button -->
+    <string name="request_green_certificate_disagree_button">"Nu, mulțumesc"</string>
+    <!-- XTXT: Request green certificate birth date description -->
+    <string name="request_green_certificate_birthdate_description">"În scop de securitate, rezultatul testului dvs. este protejat cu data nașterii dvs. Rezultatul de test poate fi emis doar dacă specificați data corectă a nașterii."</string>
+    <!-- XTXT: Request green certificate birth date hint -->
+    <string name="request_green_certificate_birthdate_hint">"Data nașterii"</string>
+    <!-- XTXT: Request green certificate exit dialog title -->
+    <string name="request_gc_dialog_title">"Anulare înregistrare"</string>
+    <!-- XTXT: Request green certificate exit dialog message -->
+    <string name="request_gc_dialog_message">"Dacă anulați înregistrarea testului, nu puteți primi rezultatul testului dvs. în aplicație."</string>
+    <!-- XBUT: Request green certificate exit dialog negative button -->
+    <string name="request_gc_dialog_positive_button">"OK"</string>
+    <!-- XBUT: Request green certificate exit dialog negative button -->
+    <string name="request_gc_dialog_negative_button">"Anulare"</string>
+    <!-- XTXT: Detail green certificate title -->
+    <string name="detail_green_certificate_title">"Certificat de test COVID digital UE"</string>
+    <!-- XTXT: Detail green certificate test type -->
+    <string name="detail_green_certificate_test_type">"Test SARS-CoV-2"</string>
+    <!-- XTXT: Detail green certificate card title -->
+    <string name="detail_green_certificate_card_title">"Certificat de test"</string>
+    <!-- XTXT: Detail green certificate travel notice link en -->
+    <string name="green_certificate_travel_notice_link_en">"https://reopen.europa.eu/en"</string>
+    <!-- XTXT: Detail green certificate travel notice link de -->
+    <string name="green_certificate_travel_notice_link_de">"https://reopen.europa.eu/de"</string>
+    <!-- XTXT: Green certificate main screen title -->
+    <string name="certification_screen_title">"Certificate"</string>
+    <!-- XTXT: Green certificate menu item -->
+    <string name="menu_certification_information">"Informații"</string>
+    <!-- XTXT: Green certificate main screen header text -->
+    <string name="green_certification_header_info">"Certificatele dvs. de vaccinare digitale și certificatele de test digitale sunt afișate aici."</string>
+    <!-- XTXT: Green certificate info card title 1st line -->
+    <string name="info_banner_title_1">"Certificat de test"</string>
+    <!-- XTXT: Green certificate info card title 2nd line  -->
+    <string name="info_banner_title_2">"Certificat de test COVID"</string>
+    <!-- XTXT: Green certificate info card body  -->
+    <string name="info_banner_body">"Înregistrați un test pe ecranul inițial și consimțiți să primiți un certificat de test digital. De îndată ce este disponibil certificatul, acesta este afișat aici."</string>
+</resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml
index e9834861c1fde15d9569a64200fd224bc8d85a93..69ae9eb9e9b9c797adce02846358ec69a298ac2b 100644
--- a/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation">
     <!-- ####################################
-                 Release Info Screen 1.14
+                 Release Info Screen
      ###################################### -->
 
     <!-- XHED: Title for the release info screen -->
@@ -16,22 +16,26 @@
 
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
-        <item>"Dovada digitală a vaccinării"</item>
+        <item>"Certificat de test COVID"</item>
+        <item>"Extinderea jurnalului de contacte"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
-        <item>"Acum puteți adăuga certificatele dvs. de vaccinare în aplicație și le puteți prezenta prin codul QR. Aplicația arată protecția prin vaccinarea completă la 14 zile de la vaccinarea finală."</item>
+        <item>"Acum puteți solicita un certificat de test digital oficial prin aplicație și apoi îl puteți adăuga în aplicație. Puteți utiliza acest certificat de test (cod QR) în UE pentru a face dovada unui rezultat de test negativ (de exemplu, pentru călătoria internațională)."</item>
+        <item>"De îndată ce rezultatul testului dvs. este disponibil, acum acesta este adăugat și la jurnalul dvs. de contacte."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
+        <item/>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
+        <item/>
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-ro/strings.xml b/Corona-Warn-App/src/main/res/values-ro/strings.xml
index 2307b28d73abd0aa099f4eb10ab33d7406464485..fc3960ab897d37077eb075fc61d29a13f771909b 100644
--- a/Corona-Warn-App/src/main/res/values-ro/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/strings.xml
@@ -281,6 +281,8 @@
     <string name="risk_details_behavior_body_wear_mask">"Purtați o mască facială când întâlniți alte persoane."</string>
     <!-- XMSG: risk details - stay 1,5 away, something like a bullet point -->
     <string name="risk_details_behavior_body_stay_away">"Păstrați o distanță de cel puțin 1,5 metri față de alte persoane."</string>
+    <!-- XTXT: find details about exposures in the contact journal -->
+    <string name="risk_details_find_details_in_journal">"Veți găsi mai multe informații despre expunerile dvs. în jurnalul dvs. de contacte."</string>
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"Dacă vă testați, veți găsi mai multe informații despre procedura de testare în Întrebările frecvente."</string>
@@ -1027,6 +1029,8 @@
     <string name="submission_consent_call_test_result_scan_your_test_only">"Acum scanați codul QR de pe testul dvs. și aflați rezultatul testului."</string>
     <!-- YTXT:  Body sub text 2 for Submission Consent call test result   -->
     <string name="submission_consent_call_test_result_scan_test_only_once">"Fiecare test poate fi scanat o singură dată. Aplicația poate gestiona cel mult un test rapid și un test PCR în același timp."</string>
+    <!-- YTXT:  Body sub text 3 for Submission Consent call test result   -->
+    <string name="submission_consent_call_test_result_checkmark_text">"Dacă rezultatul testului dvs. este negativ, puteți confirma acest lucru cu un certificat de test COVID oficial. Pentru aceasta, solicitați certificatul de test în următoarele etape."</string>
     <!-- XHED: Page subheadline for consent help by warning others  -->
     <string name="submission_consent_help_by_warning_others_headline">"Vă rugăm să îi ajutați pe ceilalți cu care v-ați întâlnit, avertizându-i!"</string>
     <!-- YTXT: Body for consent help by warning others -->
@@ -1087,6 +1091,15 @@
     <!-- YTXT: Body text for next steps section of waiting test result page -->
     <string name="submission_test_result_pending_steps_contact_diary_body">"Imediat ce devine disponibil, rezultatul testului dvs. va fi afișat în aplicație."</string>
 
+    <!-- XHED: Page headline for test result certifcate info title  -->
+    <string name="submission_test_result_pending_steps_test_certificate_heading">"Certificatul dvs. de test"</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not supported, RAT Test -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_supported_body">"Nu este disponibil niciun certificat de test deoarece acest punct de testare nu suportă emiterea de certificate de test."</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not available yet, PCR Test consent given -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_available_yet_body">"Certificatul dvs. de test nu este disponibil încă. De îndată ce devine disponibil, va fi afișat în aplicație."</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not desired by the user, PCR Test no consent given -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_desired_by_user_body">"Nu a fost emis niciun certificat de test, conform cererii dvs."</string>
+
     <!-- XBUT: test result pending : refresh button -->
     <string name="submission_test_result_pending_refresh_button">"Actualizare"</string>
     <!-- XBUT: test result pending : remove the test button -->
@@ -1179,7 +1192,7 @@
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"Scanare cod QR"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
-    <string name="submission_dispatcher_qr_card_text">"Primiți rezultatul testului dvs. în aplicație și avertizați-i pe ceilalți."</string>
+    <string name="submission_dispatcher_qr_card_text">"Primiți rezultatul testului dvs. în aplicație și avertizați-i pe ceilalți sau solicitați certificatul dvs. de test COVID."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
     <string name="submission_dispatcher_card_tan_code">"Introduceți codul TAN pentru testul PCR"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
@@ -1838,7 +1851,8 @@
     <string name="bottom_nav_diary_title">"Jurnal"</string>
     <!-- XHED: Title for BottomNav check-in screen title -->
     <string name="bottom_nav_check_ins_title">"Check-in"</string>
-
+    <!-- XHED: Title for BottomNav certificates screen title -->
+    <string name="bottom_nav_certificates_title">"Certificate"</string>
     <!-- ####################################
            Data Donation & Survey
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml
index d1de410afd00a13237bd8524e08f5efea2a4fdd7..94892166137f4678ec56347e3ab69beac5b9893e 100644
--- a/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml
@@ -36,12 +36,12 @@
     <string name="vaccination_list_vaccination_card_subtitle">"Efectuată pe %1$s"</string>
     <!-- XTXT: Vaccination List immunity information card body-->
     <plurals name="vaccination_list_immunity_card_body">
-        <item quantity="one">"Acum ați efectuat toate vaccinările. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d zi."</item>
-        <item quantity="other">"Acum ați efectuat toate vaccinările. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d de zile."</item>
-        <item quantity="zero">"Acum ați efectuat toate vaccinările. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d zile."</item>
-        <item quantity="two">"Acum ați efectuat toate vaccinările. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d zile."</item>
-        <item quantity="few">"Acum ați efectuat toate vaccinările. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d zile."</item>
-        <item quantity="many">"Acum ați efectuat toate vaccinările. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d zile."</item>
+        <item quantity="one">"Acum ați efectuat toate vaccinările planificate curente. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d zi."</item>
+        <item quantity="other">"Acum ați efectuat toate vaccinările planificate curente. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d de zile."</item>
+        <item quantity="zero">"Acum ați efectuat toate vaccinările planificate curente. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d zile."</item>
+        <item quantity="two">"Acum ați efectuat toate vaccinările planificate curente. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d zile."</item>
+        <item quantity="few">"Acum ați efectuat toate vaccinările planificate curente. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d zile."</item>
+        <item quantity="many">"Acum ați efectuat toate vaccinările planificate curente. Totuși, protecția prin vaccinare nu va fi completă timp de încă %1$d zile."</item>
     </plurals>
     <!-- XBUT: Vaccination List register additional vaccination button -->
     <string name="vaccination_list_register_new_vaccination_button">"Înregistrare altă vaccinare"</string>
@@ -62,9 +62,11 @@
         Homescreen cards
     ###################################### -->
     <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_title">"Adăugare certificat de vaccinare"</string>
+    <string name="vaccination_card_registration_title_line_1">"Adăugarea dovezii"</string>
+    <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
+    <string name="vaccination_card_registration_title_line_2">"vaccinării digitale"</string>
     <!-- YTXT: Body text for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_body">"Adăugați certificate de vaccinare în aplicație pentru a le avea mereu cu dvs. Pentru aceasta, scanați codul QR din documentul dvs."</string>
+    <string name="vaccination_card_registration_body">"Adăugați certificatele dvs. de vaccinare în aplicație pentru a le avea mereu cu dvs. Pentru aceasta, scanați codul QR din documentul dvs."</string>
     <!-- XBUT: button for Vaccination Certificate Registration Home Card -->
     <string name="vaccination_card_register">"Adăugare"</string>
     <!-- XHED: Homescreen vaccination status card title -->
@@ -97,17 +99,17 @@
     <!-- XTXT: Vaccination Consent title-->
     <string name="vaccination_consent_title">"Consimțământul dvs."</string>
     <!-- XTXT: Vaccination Consent subtitle-->
-    <string name="vaccination_consent_headline">"Adăugare certificat de vaccinare"</string>
+    <string name="vaccination_consent_headline">"Adăugarea certificatelor"</string>
     <!-- XTXT: Vaccination Consent subtitle of qr info -->
-    <string name="vaccination_consent_info_subtitle_text">"Adăugați certificatul de vaccinare digital în aplicație. De îndată ce protecția prin vaccinare este completă, puteți prezenta codul QR în aplicație ca dovadă a vaccinării."</string>
+    <string name="vaccination_consent_info_subtitle_text">"Adăugați certificatele dvs. de COVID digitale în aplicație. Acest lucru vă ajută să dovediți protecția dvs. prin vaccinare sau să arătați un rezultat de test negativ în aplicație."</string>
     <!-- XTXT: Vaccination Consent text of qr info -->
-    <string name="vaccination_consent_qr_info_text">"Pentru a adăuga un certificat de vaccinare în aplicație, scanați codul QR pe care l-ați primit la vaccinare."</string>
+    <string name="vaccination_consent_qr_info_text">"Puteți adăuga certificate de vaccinare COVID digitale sau certificate de test COVID în aplicație."</string>
     <!-- XTXT: Vaccination Consent qr code text -->
-    <string name="vaccination_consent_qr_info_qr_code_text">"Aplicația citește informațiile de la codul QR și le salvează într-o zonă securizată pe smartphone-ul dvs."</string>
+    <string name="vaccination_consent_qr_info_qr_code_text">"Aceste certificate sunt considerate o dovadă valabilă în UE (de exemplu, în scop de călătorie)."</string>
     <!-- XTXT: Vaccination Consent time text  -->
-    <string name="vaccination_consent_qr_info_time_text">"Datele vor rămâne pe smartphone. Vor fi transmise altor persoane doar dacă prezentați certificatul de vaccinare pentru verificare."</string>
+    <string name="vaccination_consent_qr_info_time_text">"După ce adăugați un certificat, acesta rămâne pe smartphone-ul dvs. Va fi partajat cu alte persoane doar dacă prezentați un certificat pentru verificare."</string>
     <!-- XTXT: Text for vaccination consent legal information button -->
-    <string name="vaccination_consent_onboarding_legal_information">"Pentru mai multe informații, consultați înștiințarea de confidențialitate."</string>
+    <string name="vaccination_consent_onboarding_legal_information">"Pentru mai multe informații despre prelucrarea datelor, consultați înștiințarea de confidențialitate."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Continuare"</string>
 
diff --git a/Corona-Warn-App/src/main/res/values-tr/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-tr/antigen_strings.xml
index 4efff6cfacdfd5ca21328260bf94a0d251a9fa5a..3a2d0403eb184b10f202d8ae22e5c541653714b1 100644
--- a/Corona-Warn-App/src/main/res/values-tr/antigen_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/antigen_strings.xml
@@ -6,8 +6,7 @@
     <!-- XHED: Register test homescreen card: title -->
     <string name="ag_homescreen_card_test_register_title">"Testinizi Kaydedin"</string>
     <!-- XTXT: Register test homescreen card: body -->
-    <string name="ag_homescreen_card_test_register_body">"Diğer kullanıcıları daha hızlı uyarmak için testlerinizi kaydetmek ve test sonuçlarınızı almak üzere uygulamayı kullanın."</string>
-
+    <string name="ag_homescreen_card_test_register_body">"Diğer kullanıcıları daha hızlı uyarmak için testlerinizi kaydetmek ve test sonuçlarınızı almak ya da COVID test sertifikanızı talep etmek üzere uygulamayı kullanın."</string>
     <!-- ####################################
         Homescreen cards - common buttons
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml
index 09183f04e8434e1d2265920dd08218b601daf913..ffb433096cb24cec3b0baf6d92a7f856ba323488 100644
--- a/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml
@@ -182,4 +182,13 @@
     <string name="contact_diary_location_visit_duration_hour">"sa"</string>
     <!-- XTXT: Option - person encounter - circumstances hint-->
     <string name="contact_diary_location_visit_circumstances_hint">"Not (ör. çok dolu)"</string>
+
+    <!-- XTXT: PCR test title in the day overview -->
+    <string name="contact_diary_corona_test_pcr_title">"PCR Testi Kaydedildi"</string>
+    <!-- XTXT: RAT test title in the day overview -->
+    <string name="contact_diary_corona_test_rat_title">"Hızlı Test Gerçekleştirildi"</string>
+    <!-- XTXT: positive test result in the day overview -->
+    <string name="contact_diary_corona_test_positive">"Pozitif Tanı"</string>
+    <!-- XTXT: negative test result in the day overview -->
+    <string name="contact_diary_corona_test_negative">"Negatif Tanı"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-tr/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values-tr/event_registration_strings.xml
index f2c3a5cdb31c2e7e142f5e5371321517b8be5245..47a6314bc43e7f89841ab5e07b159866ffceffe7 100644
--- a/Corona-Warn-App/src/main/res/values-tr/event_registration_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/event_registration_strings.xml
@@ -210,6 +210,8 @@
     <string name="trace_location_organizer_detail_item_duration">"%1$s, %2$s - %3$s"</string>
     <!-- XTXT: Event organizer detail qr-code: duration with multiple date -->
     <string name="trace_location_organizer_detail_item_duration_multiple_days">"%1$s, %2$s - %3$s, %4$s"</string>
+    <!-- XTXT: Past Event Info duration -->
+    <string name="trace_location_attendee_past_event_duration">"%1$s"</string>
 
     <!-- XBUT: Event organiser list item: menu: information button  -->
     <string name="trace_location_organizer_list_item_menu_duplicate_btn">"Çoğalt"</string>
diff --git a/Corona-Warn-App/src/main/res/values-tr/green_certificate_strings.xml b/Corona-Warn-App/src/main/res/values-tr/green_certificate_strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fc5992cfe8200a789105192fd25303a52d7474e0
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/values-tr/green_certificate_strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
+    <!-- XTXT: Request green certificate title -->
+    <string name="request_green_certificate_title">"COVID Test Sertifikası"</string>
+    <!-- XTXT: Request green certificate subtitle -->
+    <string name="request_green_certificate_subtitle">"Uygulamayı kullanarak resmi bir dijital test sertifikası talep edebilirsiniz. Ardından bu sertifika uygulamaya eklenir."</string>
+    <!-- XTXT: Request green certificate body section 1 -->
+    <string name="request_green_certificate_body_1">"Test sertifikası yalnızca test sonucunuz negatifse düzenlenir."</string>
+    <!-- XTXT: Request green certificate body section 2 -->
+    <string name="request_green_certificate_body_2">"Test sertifikası, AB’de geçerli bir negatif test sonucu kanıtıdır (ör. seyahat için)."</string>
+    <!-- XTXT: Request green certificate body section 3 -->
+    <string name="request_green_certificate_body_3">"Test sertifikası, doğrulama uygulamasının sertifikanızı doğrulamasını sağlayan geçerli değer içerir."</string>
+    <!-- XBUT: Request green certificate agree button -->
+    <string name="request_green_certificate_agree_button">"Test Sertifikası Talep Et"</string>
+    <!-- XBUT: Request green certificate disagree button -->
+    <string name="request_green_certificate_disagree_button">"Hayır Teşekkürler"</string>
+    <!-- XTXT: Request green certificate birth date description -->
+    <string name="request_green_certificate_birthdate_description">"Güvenlik amaçları nedeniyle test sonucunuz doğum tarihinizle korunmaktadır. Test sonucu yalnızca doğru doğum tarihini belirtirseniz düzenlenebilir."</string>
+    <!-- XTXT: Request green certificate birth date hint -->
+    <string name="request_green_certificate_birthdate_hint">"DoÄŸum Tarihi"</string>
+    <!-- XTXT: Request green certificate exit dialog title -->
+    <string name="request_gc_dialog_title">"Kaydı İptal Et"</string>
+    <!-- XTXT: Request green certificate exit dialog message -->
+    <string name="request_gc_dialog_message">"Test kaydını iptal ederseniz test sonucunuzu uygulamaya alamazsınız."</string>
+    <!-- XBUT: Request green certificate exit dialog negative button -->
+    <string name="request_gc_dialog_positive_button">"Tamam"</string>
+    <!-- XBUT: Request green certificate exit dialog negative button -->
+    <string name="request_gc_dialog_negative_button">"Ä°ptal Et"</string>
+    <!-- XTXT: Detail green certificate title -->
+    <string name="detail_green_certificate_title">"AB Dijital COVID Test Sertifikası"</string>
+    <!-- XTXT: Detail green certificate test type -->
+    <string name="detail_green_certificate_test_type">"SARS-CoV-2 Testi"</string>
+    <!-- XTXT: Detail green certificate card title -->
+    <string name="detail_green_certificate_card_title">"Test Sertifikası"</string>
+    <!-- XTXT: Detail green certificate travel notice link en -->
+    <string name="green_certificate_travel_notice_link_en">"https://reopen.europa.eu/en"</string>
+    <!-- XTXT: Detail green certificate travel notice link de -->
+    <string name="green_certificate_travel_notice_link_de">"https://reopen.europa.eu/de"</string>
+    <!-- XTXT: Green certificate main screen title -->
+    <string name="certification_screen_title">"Sertifikalar"</string>
+    <!-- XTXT: Green certificate menu item -->
+    <string name="menu_certification_information">"Bilgi"</string>
+    <!-- XTXT: Green certificate main screen header text -->
+    <string name="green_certification_header_info">"Dijital aşı sertifikalarınız ve test sertifikalarınız burada görüntülenir."</string>
+    <!-- XTXT: Green certificate info card title 1st line -->
+    <string name="info_banner_title_1">"Dijital COVID-19"</string>
+    <!-- XTXT: Green certificate info card title 2nd line  -->
+    <string name="info_banner_title_2">"COVID Test Sertifikası"</string>
+    <!-- XTXT: Green certificate info card body  -->
+    <string name="info_banner_body">"Ana ekranda bir testi kaydedin ve dijital test sertifikası almayı kabul edin. Sertifika düzenlenir düzenlenmez burada görüntülenir."</string>
+</resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml
index a551f52bc1ec4ddbb7332fa1c53a956b85619b23..31d323ce844cd02f3816db2e69d96193f12e4fcb 100644
--- a/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation">
     <!-- ####################################
-                 Release Info Screen 1.14
+                 Release Info Screen
      ###################################### -->
 
     <!-- XHED: Title for the release info screen -->
@@ -16,22 +16,26 @@
 
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
-        <item>"Dijital Aşı Kanıtı"</item>
+        <item>"COVID Test Sertifikası"</item>
+        <item>"Temas Güncesi Geliştirmesi"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
-        <item>"Artık aşı sertifikalarınızı uygulamaya kaydedebilir ve QR kod aracılığıyla sunabilirsiniz. Uygulama, son aşıdan 14 gün sonra tam aşı korumasını görüntüler."</item>
+        <item>"Artık uygulama üzerinden resmi bir dijital test sertifikası talebinde bulunabilir ve sertifikayı uygulamaya ekleyebilirsiniz. Daha sonra bu test sertifikasını (QR kod) AB içinde negatif test sonucunu kanıtlamak için kullanabilirsiniz (örneğin, uluslararası seyahat için)."</item>
+        <item>"Artık test sonucunuz çıkar çıkmaz temas güncenize eklenir."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item/>
+        <item/>
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item/>
+        <item/>
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-tr/strings.xml b/Corona-Warn-App/src/main/res/values-tr/strings.xml
index 6af43c944accaa5322b4e22c2a9181f479fd3b63..f8752dd07863f43e4e9e0343df0acac4d73b68ff 100644
--- a/Corona-Warn-App/src/main/res/values-tr/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/strings.xml
@@ -281,6 +281,8 @@
     <string name="risk_details_behavior_body_wear_mask">"Diğer insanlarla karşılaştığınızda yüz maskesi takın."</string>
     <!-- XMSG: risk details - stay 1,5 away, something like a bullet point -->
     <string name="risk_details_behavior_body_stay_away">"Diğer insanlarla aranızda en az 1,5 metre mesafeyi koruyun."</string>
+    <!-- XTXT: find details about exposures in the contact journal -->
+    <string name="risk_details_find_details_in_journal">"Temas güncenizde maruz kalmalarınız hakkında daha fazla bilgi bulabilirsiniz."</string>
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"Test yaptırırsanız SSS bölümünde test prosedürü hakkında ek bilgi bulabilirsiniz."</string>
@@ -1027,6 +1029,8 @@
     <string name="submission_consent_call_test_result_scan_your_test_only">"Şimdi, testinizin QR kodunu tarayın ve test sonucunuzu alın."</string>
     <!-- YTXT:  Body sub text 2 for Submission Consent call test result   -->
     <string name="submission_consent_call_test_result_scan_test_only_once">"Her bir test yalnızca bir kez taranabilir. Uygulama tek seferde en fazla bir hızlı testi ve bir PCR testini yönetebilir."</string>
+    <!-- YTXT:  Body sub text 3 for Submission Consent call test result   -->
+    <string name="submission_consent_call_test_result_checkmark_text">"Testinizin sonucu negatifse bunu resmi bir COVID test sertifikası ile onaylayabilirsiniz. Bu işlemi gerçekleştirmek için, aşağıda belirtilen adımları uygulayarak test sertifikası talebinde bulunun."</string>
     <!-- XHED: Page subheadline for consent help by warning others  -->
     <string name="submission_consent_help_by_warning_others_headline">"Lütfen karşılaştığınız diğer kullanıcıları uyararak onlara yardımcı olun!"</string>
     <!-- YTXT: Body for consent help by warning others -->
@@ -1087,6 +1091,15 @@
     <!-- YTXT: Body text for next steps section of waiting test result page -->
     <string name="submission_test_result_pending_steps_contact_diary_body">"Test sonucunuz çıkar çıkmaz uygulamada görüntülenecektir."</string>
 
+    <!-- XHED: Page headline for test result certifcate info title  -->
+    <string name="submission_test_result_pending_steps_test_certificate_heading">"Test Sertifikanız"</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not supported, RAT Test -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_supported_body">"Bu test noktasında test sertifikalarını düzenleme işlevi desteklenmediğinden hiçbir test sertifikası bulunmamaktadır."</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not available yet, PCR Test consent given -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_available_yet_body">"Test sertifikanız henüz çıkmadı. Çıkar çıkmaz uygulamanızda görüntülenecektir."</string>
+    <!-- YTXT: Body text for test result certifcate info, if certifcate is not desired by the user, PCR Test no consent given -->
+    <string name="submission_test_result_pending_steps_test_certificate_not_desired_by_user_body">"Talebiniz üzerine, hiçbir test sertifikası düzenlenmedi."</string>
+
     <!-- XBUT: test result pending : refresh button -->
     <string name="submission_test_result_pending_refresh_button">"Güncelle"</string>
     <!-- XBUT: test result pending : remove the test button -->
@@ -1179,7 +1192,7 @@
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"QR Kodu Tara"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
-    <string name="submission_dispatcher_qr_card_text">"Uygulamada test sonucunuzu alın ve diğer kullanıcıları uyarın."</string>
+    <string name="submission_dispatcher_qr_card_text">"Uygulamada test sonucunuzu alın ve diğer kullanıcıları uyarın ya da COVID test sertifikanızı talep edin."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
     <string name="submission_dispatcher_card_tan_code">"PCR Testi için TAN girin"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
@@ -1838,7 +1851,8 @@
     <string name="bottom_nav_diary_title">"Günce"</string>
     <!-- XHED: Title for BottomNav check-in screen title -->
     <string name="bottom_nav_check_ins_title">"Check In"</string>
-
+    <!-- XHED: Title for BottomNav certificates screen title -->
+    <string name="bottom_nav_certificates_title">"Sertifikalar"</string>
     <!-- ####################################
            Data Donation & Survey
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml
index 68130d5019207d80bd419c0aac3977bb55ddc2fe..90a2fe7d930d9215b73f187569875264b208e2ec 100644
--- a/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml
@@ -8,7 +8,7 @@
     <!-- XTXT: Vaccination Details vaccine manufacturer -->
     <string name="vaccination_details_vaccine_manufacturer">"Ãœretici"</string>
     <!-- XTXT: Vaccination Details vaccine type -->
-    <string name="vaccination_details_vaccine_medical_product_name">"Aşı tipi"</string>
+    <string name="vaccination_details_vaccine_medical_product_name">"Aşı Tipi"</string>
     <!-- XTXT: Vaccination Details certificate issuer -->
     <string name="vaccination_details_certificate_issuer">"Düzenleyen"</string>
     <!-- XTXT: Vaccination Details certificate country -->
@@ -20,9 +20,9 @@
     <!-- XTXT: Vaccination Details title-->
     <string name="vaccination_details_title">"Aşı %1$d / %2$d"</string>
     <!-- XTXT: Vaccination Qr Code card title-->
-    <string name="vaccination_qrcode_card_title">"%1$d / %2$d aşı sertifikası"</string>
+    <string name="vaccination_qrcode_card_title">"%1$d / %2$d Aşı Sertifikası"</string>
     <!-- XTXT: Vaccination Qr Code card subtitle-->
-    <string name="vaccination_qrcode_card_subtitle">"%1$s için aşı yapıldı - geçerlilik sonu: %2$s"</string>
+    <string name="vaccination_qrcode_card_subtitle">"%1$s için Aşı Yapıldı - Geçerlilik Sonu: %2$s"</string>
 
     <!-- XTXT: Vaccination List title-->
     <string name="vaccination_list_title">"Dijital Aşı Kanıtı"</string>
@@ -36,12 +36,12 @@
     <string name="vaccination_list_vaccination_card_subtitle">"Gerçekleştirilme tarihi: %1$s"</string>
     <!-- XTXT: Vaccination List immunity information card body-->
     <plurals name="vaccination_list_immunity_card_body">
-        <item quantity="one">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
-        <item quantity="other">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
-        <item quantity="zero">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
-        <item quantity="two">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
-        <item quantity="few">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
-        <item quantity="many">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
+        <item quantity="one">"Şu anda planlanan tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
+        <item quantity="other">"Şu anda planlanan tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
+        <item quantity="zero">"Şu anda planlanan tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
+        <item quantity="two">"Şu anda planlanan tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
+        <item quantity="few">"Şu anda planlanan tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
+        <item quantity="many">"Şu anda planlanan tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item>
     </plurals>
     <!-- XBUT: Vaccination List register additional vaccination button -->
     <string name="vaccination_list_register_new_vaccination_button">"Başka Aşı Kaydet"</string>
@@ -62,9 +62,11 @@
         Homescreen cards
     ###################################### -->
     <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_title">"Aşı Sertifikası Ekle"</string>
+    <string name="vaccination_card_registration_title_line_1">"Dijital Aşı Kanıtı"</string>
+    <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
+    <string name="vaccination_card_registration_title_line_2">"Ekle"</string>
     <!-- YTXT: Body text for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_body">"Her zaman erişebilmek için uygulamaya aşı sertifikaları ekleyin. Bunun için, belgenizdeki QR kodu tarayın."</string>
+    <string name="vaccination_card_registration_body">"Her zaman erişebilmek için uygulamaya aşı sertifikalarınızı ekleyin. Bunun için, belgenizdeki QR kodu tarayın."</string>
     <!-- XBUT: button for Vaccination Certificate Registration Home Card -->
     <string name="vaccination_card_register">"Ekle"</string>
     <!-- XHED: Homescreen vaccination status card title -->
@@ -97,17 +99,17 @@
     <!-- XTXT: Vaccination Consent title-->
     <string name="vaccination_consent_title">"Ä°zniniz"</string>
     <!-- XTXT: Vaccination Consent subtitle-->
-    <string name="vaccination_consent_headline">"Aşı Sertifikası Ekle"</string>
+    <string name="vaccination_consent_headline">"Sertifikalar Ekle"</string>
     <!-- XTXT: Vaccination Consent subtitle of qr info -->
-    <string name="vaccination_consent_info_subtitle_text">"Uygulamaya dijital aşı sertifikanızı ekleyin. Aşı korumanız tamamlanır tamamlanmaz uygulamanıza aşınızın kanıtı olarak QR kodu sunabilirsiniz."</string>
+    <string name="vaccination_consent_info_subtitle_text">"Uygulamaya dijital COVID sertifikalarınızı ekleyin. Bu sayede uygulamada aşı korumanızı ya da negatif test sonucunu kanıtlayabilirsiniz."</string>
     <!-- XTXT: Vaccination Consent text of qr info -->
-    <string name="vaccination_consent_qr_info_text">"Uygulamaya bir aşı sertifikası eklemek için aşınız sırasında size verilen QR kodu tarayın."</string>
+    <string name="vaccination_consent_qr_info_text">"Uygulamaya dijital COVID aşı sertifikaları ya da COVID test sertifikaları ekleyebilirsiniz."</string>
     <!-- XTXT: Vaccination Consent qr code text -->
-    <string name="vaccination_consent_qr_info_qr_code_text">"Uygulama, QR kodun bilgilerini okur ve akıllı telefonunuzda güvenli bir alana kaydeder."</string>
+    <string name="vaccination_consent_qr_info_qr_code_text">"Bu sertifikalar, AB’de geçerli bir kanıt olarak değerlendirilir (ör. seyahat için)."</string>
     <!-- XTXT: Vaccination Consent time text  -->
-    <string name="vaccination_consent_qr_info_time_text">"Veriler, akıllı telefonda kalır. Yalnızca, doğrulama için aşı sertifikanızı sunarsanız diğer kullanıcılara aktarılır."</string>
+    <string name="vaccination_consent_qr_info_time_text">"Siz sertifikayı ekledikten sonra sertifika akıllı telefonunuzda kalır. Yalnızca doğrulama için bir aşı sunarsanız diğer kullanıcılarla paylaşılır."</string>
     <!-- XTXT: Text for vaccination consent legal information button -->
-    <string name="vaccination_consent_onboarding_legal_information">"Daha fazla bilgi için lütfen gizlilik bildirimine başvurun."</string>
+    <string name="vaccination_consent_onboarding_legal_information">"Veri işleme hakkında daha ayrıntılı bilgi için lütfen gizlilik bildirimine başvurun."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Devam Et"</string>
 
diff --git a/Corona-Warn-App/src/main/res/values/antigen_strings.xml b/Corona-Warn-App/src/main/res/values/antigen_strings.xml
index 736cd35cfdc6f3b9f83d73048c72ee2dc105a9db..525e5937055eca395d017b6a1745b89c8754106f 100644
--- a/Corona-Warn-App/src/main/res/values/antigen_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/antigen_strings.xml
@@ -7,8 +7,7 @@
     <!-- XHED: Register test homescreen card: title -->
     <string name="ag_homescreen_card_test_register_title">"Register Your Test"</string>
     <!-- XTXT: Register test homescreen card: body -->
-    <string name="ag_homescreen_card_test_register_body">"Use the app to register your tests and retrieve your test results, so you can warn others more quickly."</string>
-
+    <string name="ag_homescreen_card_test_register_body">"Use the app to register your tests and retrieve your test results, so you can warn others more quickly, or to request your COVID test certificate."</string>
     <!-- ####################################
         Homescreen cards - common buttons
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml
index fc49c3ebb20fe28e2e6b205f8fadb43ddeb2e628..acd72cf7fdf970ff9e6432d7c2b0210a4aed2caa 100644
--- a/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml
@@ -84,6 +84,7 @@
     <!-- XTXT: Indicates this trace location caused a lows risk -->
     <string name="contact_diary_trace_location_risk_low">"low risk"</string>
 
+
     <!-- XTXT: content description of contact journal image on home screen -->
     <string name="contact_diary_homescreen_card_image_content_description">"A closed book with a bookmark"</string>
     <!-- XTXT: content description of contact journal header image on onboarding screen -->
@@ -125,34 +126,6 @@
     <!-- XTXT: Message for the contact diary dialog to delete a single person -->
     <string name="contact_diary_delete_person_message">"If you remove a person, all the entries for that person will be removed from your journal."</string>
 
-    <!-- EXPORT -->
-    <!-- XHED: Title for the contact journal export email subject -->
-    <string name="contact_diary_export_subject" translatable="false">"Mein Kontakt-Tagebuch"</string>
-    <!-- XTXT: Intro text for the contact journal email export part one-->
-    <string name="contact_diary_export_intro_one" translatable="false">"Kontakte der letzten 15 Tage (%1$s - %2$s)"</string>
-    <!-- XTXT: Intro text for the contact journal email export part two-->
-    <string name="contact_diary_export_intro_two" translatable="false">"Die nachfolgende Liste dient dem zuständigen Gesundheitsamt zur Kontaktnachverfolgung gem. § 25 IfSG."</string>
-    <!-- XTXT: Phone number prefix in the contact journal export-->
-    <string name="contact_diary_export_prefix_phone" translatable="false">"Tel."</string>
-    <!-- XTXT: EMail prefix in the contact journal export-->
-    <string name="contact_diary_export_prefix_email" translatable="false">"E-Mail"</string>
-    <!-- XTXT: Additional information about duration that was longer than 15 minutes in the contact journal export-->
-    <string name="contact_diary_export_durations_longer_than_15min" translatable="false">"Kontaktdauer &gt; 15 Minuten"</string>
-    <!-- XTXT: Additional information about duration that was less than 15 minutes in the contact journal export-->
-    <string name="contact_diary_export_durations_less_than_15min" translatable="false">"Kontaktdauer &lt; 15 Minuten"</string>
-    <!-- XTXT: Additional information about wearing a mask in the contact journal export-->
-    <string name="contact_diary_export_wearing_mask" translatable="false">"mit Maske"</string>
-    <!-- XTXT: Additional information about wearing no mask in the contact journal export-->
-    <string name="contact_diary_export_wearing_no_mask" translatable="false">"ohne Maske"</string>
-    <!-- XTXT: Additional information about being indoors in the contact journal export-->
-    <string name="contact_diary_export_indoor" translatable="false">"im Gebäude"</string>
-    <!-- XTXT: Additional information about being outdoor in the contact journal export-->
-    <string name="contact_diary_export_outdoor" translatable="false">"im Freien"</string>
-    <!-- XTXT: Location duration prefix in the contact journal export-->
-    <string name="contact_diary_export_location_duration_prefix" translatable="false">"Dauer"</string>
-    <!-- XTXT: Location duration postfix in the contact journal export-->
-    <string name="contact_diary_export_location_duration_suffix" translatable="false">"h"</string>
-
     <!-- XHED: Title for the contact diary comment info screen -->
     <string name="contact_diary_comment_info_screen_title">"Note"</string>
     <!-- XTXT: Description for contact diary comment info screen -->
@@ -211,11 +184,11 @@
     <string name="contact_diary_location_visit_circumstances_hint">"Note (e.g. very full)"</string>
 
     <!-- XTXT: PCR test title in the day overview -->
-    <string name="contact_diary_corona_test_pcr_title">PCR-Test registriert</string>
+    <string name="contact_diary_corona_test_pcr_title">"PCR Test Registered"</string>
     <!-- XTXT: RAT test title in the day overview -->
-    <string name="contact_diary_corona_test_rat_title">Schnelltest durchgeführt</string>
+    <string name="contact_diary_corona_test_rat_title">"Rapid Test Performed"</string>
     <!-- XTXT: positive test result in the day overview -->
-    <string name="contact_diary_corona_test_positive">Befund positiv</string>
+    <string name="contact_diary_corona_test_positive">"Positive Diagnosis"</string>
     <!-- XTXT: negative test result in the day overview -->
-    <string name="contact_diary_corona_test_negative">Befund negativ</string>
+    <string name="contact_diary_corona_test_negative">"Negative Diagnosis"</string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values/contact_diary_strings_export.xml b/Corona-Warn-App/src/main/res/values/contact_diary_strings_export.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b641a9be20ae4076fa743daa0b5ede91997136db
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/values/contact_diary_strings_export.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation">
+    <!-- ####################################
+        Special string files for the strings that should
+        always keep the german version independent from
+        the selected system language
+    ###################################### -->
+    <!-- XHED: Title for the contact journal export email subject -->
+    <string name="contact_diary_export_subject" translatable="false">"Mein Kontakt-Tagebuch"</string>
+    <!-- XTXT: Intro text for the contact journal email export part one-->
+    <string name="contact_diary_export_intro_one" translatable="false">"Kontakte der letzten 15 Tage (%1$s - %2$s)"</string>
+    <!-- XTXT: Intro text for the contact journal email export part two-->
+    <string name="contact_diary_export_intro_two" translatable="false">"Die nachfolgende Liste dient dem zuständigen Gesundheitsamt zur Kontaktnachverfolgung gem. § 25 IfSG."</string>
+    <!-- XTXT: Phone number prefix in the contact journal export-->
+    <string name="contact_diary_export_prefix_phone" translatable="false">"Tel."</string>
+    <!-- XTXT: EMail prefix in the contact journal export-->
+    <string name="contact_diary_export_prefix_email" translatable="false">"E-Mail"</string>
+    <!-- XTXT: Additional information about duration that was longer than 15 minutes in the contact journal export-->
+    <string name="contact_diary_export_durations_longer_than_15min" translatable="false">"Kontaktdauer &gt; 15 Minuten"</string>
+    <!-- XTXT: Additional information about duration that was less than 15 minutes in the contact journal export-->
+    <string name="contact_diary_export_durations_less_than_15min" translatable="false">"Kontaktdauer &lt; 15 Minuten"</string>
+    <!-- XTXT: Additional information about wearing a mask in the contact journal export-->
+    <string name="contact_diary_export_wearing_mask" translatable="false">"mit Maske"</string>
+    <!-- XTXT: Additional information about wearing no mask in the contact journal export-->
+    <string name="contact_diary_export_wearing_no_mask" translatable="false">"ohne Maske"</string>
+    <!-- XTXT: Additional information about being indoors in the contact journal export-->
+    <string name="contact_diary_export_indoor" translatable="false">"im Gebäude"</string>
+    <!-- XTXT: Additional information about being outdoor in the contact journal export-->
+    <string name="contact_diary_export_outdoor" translatable="false">"im Freien"</string>
+    <!-- XTXT: Location duration prefix in the contact journal export-->
+    <string name="contact_diary_export_location_duration_prefix" translatable="false">"Dauer"</string>
+    <!-- XTXT: Location duration postfix in the contact journal export-->
+    <string name="contact_diary_export_location_duration_suffix" translatable="false">"h"</string>
+</resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values/event_registration_strings.xml
index c20aad17a42470fad13c809f0948a4be2940607a..c6b317bfcf80acb99f637af506137f0f6578d223 100644
--- a/Corona-Warn-App/src/main/res/values/event_registration_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/event_registration_strings.xml
@@ -211,7 +211,7 @@
     <!-- XTXT: Event organizer detail qr-code: duration with multiple date -->
     <string name="trace_location_organizer_detail_item_duration_multiple_days">"%1$s, %2$s - %3$s, %4$s"</string>
     <!-- XTXT: Past Event Info duration -->
-    <string name="trace_location_attendee_past_event_duration">"%1$s Uhr"</string>
+    <string name="trace_location_attendee_past_event_duration">"%1$s"</string>
 
     <!-- XBUT: Event organiser list item: menu: information button  -->
     <string name="trace_location_organizer_list_item_menu_duplicate_btn">"Duplicate"</string>
diff --git a/Corona-Warn-App/src/main/res/values/green_certificate_attribute_strings.xml b/Corona-Warn-App/src/main/res/values/green_certificate_attribute_strings.xml
index 66f4eddbb30c0dc5c6e1a415b625df29fe6f5f72..97061edf82bca7596eb2cceb9b44db8599dabcb5 100644
--- a/Corona-Warn-App/src/main/res/values/green_certificate_attribute_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/green_certificate_attribute_strings.xml
@@ -1,8 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
-<resources>
-
+<resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation">
     <!-- ####################################
-             Special string files for the strings that should always keep the german / englisch version independent from the selected system language
+        Special string files for the strings
+        that should always keep the german / english
+        version independent from the selected system language
     ###################################### -->
     <!-- XTXT: Green Certificate Detail Screen Attribute: Name -->
     <string name="green_certificate_attribute_name" translatable="false">"Name, Vorname / Name, First Name"</string>
diff --git a/Corona-Warn-App/src/main/res/values/green_certificate_strings.xml b/Corona-Warn-App/src/main/res/values/green_certificate_strings.xml
index b256dd248b7b99fed45bd147de5fd858b223e2dd..ece39a2784ecdbf679e5cbfca640fee0a8a12d3d 100644
--- a/Corona-Warn-App/src/main/res/values/green_certificate_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/green_certificate_strings.xml
@@ -1,52 +1,102 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
     <!-- XTXT: Request green certificate title -->
-    <string name="request_green_certificate_title">COVID-19-Testzertifikat</string>
+    <string name="request_green_certificate_title">"COVID Test Certificate"</string>
     <!-- XTXT: Request green certificate subtitle -->
-    <string name="request_green_certificate_subtitle">Sie können über die App ein offizielles digitales Testzertifikat anfordern, das anschließend in der App hinzugefügt wird.</string>
+    <string name="request_green_certificate_subtitle">"You can use the app to request an official digital test certificate, which is then added in the app."</string>
     <!-- XTXT: Request green certificate body section 1 -->
-    <string name="request_green_certificate_body_1">Das Testzertifikat wird nur bei einem negativen Testergebnis ausgestellt.</string>
+    <string name="request_green_certificate_body_1">"The test certificate is only issued if your test result is negative."</string>
     <!-- XTXT: Request green certificate body section 2 -->
-    <string name="request_green_certificate_body_2">Das Testzertifikat gilt innerhalb der EU als gültiger Nachweis eines negativen Testergebnisses (z.B. für Reisen).</string>
+    <string name="request_green_certificate_body_2">"The test certificate is valid proof of a negative test result within the EU (e.g. for travel)."</string>
     <!-- XTXT: Request green certificate body section 3 -->
-    <string name="request_green_certificate_body_3">Das Testzertifikat enthält Daten, die der Prüf-App die Validierung Ihres Zertifikats erlauben.</string>
+    <string name="request_green_certificate_body_3">"The test certificate contains valid that enables the verification app to validate your certificate."</string>
     <!-- XBUT: Request green certificate agree button -->
-    <string name="request_green_certificate_agree_button">Testzertifikat Anfordern</string>
+    <string name="request_green_certificate_agree_button">"Request Test Certificate"</string>
     <!-- XBUT: Request green certificate disagree button -->
-    <string name="request_green_certificate_disagree_button">Nein Danke</string>
+    <string name="request_green_certificate_disagree_button">"No Thank You"</string>
     <!-- XTXT: Request green certificate birth date description -->
-    <string name="request_green_certificate_birthdate_description">Zur Sicherheit wird Ihr Testergebnis mit Ihrem Geburtsdatum geschützt. Das Testergebnis kann nur bei korrekt angegebenem Geburtstdatum zugestellt werden.</string>
+    <string name="request_green_certificate_birthdate_description">"For security purposes, your test result is protected with your date of birth. The test result can only be issued if you specify the correct date of birth."</string>
     <!-- XTXT: Request green certificate birth date hint -->
-    <string name="request_green_certificate_birthdate_hint">Geburtsdatum</string>
+    <string name="request_green_certificate_birthdate_hint">"Date of Birth"</string>
     <!-- XTXT: Request green certificate exit dialog title -->
-    <string name="request_gc_dialog_title">Registrierung abbrechen</string>
+    <string name="request_gc_dialog_title">"Cancel Registration"</string>
     <!-- XTXT: Request green certificate exit dialog message -->
-    <string name="request_gc_dialog_message">Wenn Sie die Test-Registrierung abbrechen, können Sie Ihr Testergebnis nicht in der App erhalten.</string>
+    <string name="request_gc_dialog_message">"If you cancel the test registration, you cannot receive your test result in the app."</string>
     <!-- XBUT: Request green certificate exit dialog negative button -->
-    <string name="request_gc_dialog_positive_button">OK</string>
+    <string name="request_gc_dialog_positive_button">"OK"</string>
     <!-- XBUT: Request green certificate exit dialog negative button -->
-    <string name="request_gc_dialog_negative_button">Abbrechen</string>
+    <string name="request_gc_dialog_negative_button">"Cancel"</string>
     <!-- XTXT: Detail green certificate title -->
-    <string name="detail_green_certificate_title">EU Digitales COVID-Testzertifikat</string>
+    <string name="detail_green_certificate_title">"EU Digital COVID Test Certificate"</string>
     <!-- XTXT: Detail green certificate test type -->
-    <string name="detail_green_certificate_test_type">SARS-CoV-2-Test</string>
+    <string name="detail_green_certificate_test_type">"SARS-CoV-2 Test"</string>
     <!-- XTXT: Detail green certificate card title -->
-    <string name="detail_green_certificate_card_title">"Testzertifikat"</string>
+    <string name="detail_green_certificate_card_title">"Test Certificate"</string>
+    <!-- XTXT: Detail green certificate card subtitle -->
+    <string name="detail_green_certificate_card_subtitle">"Test durchgeführt am %1$s %2$s"</string>
     <!-- XTXT: Detail green certificate travel notice link en -->
     <string name="green_certificate_travel_notice_link_en">"https://reopen.europa.eu/en"</string>
     <!-- XTXT: Detail green certificate travel notice link de -->
     <string name="green_certificate_travel_notice_link_de">"https://reopen.europa.eu/de"</string>
+    <!-- XTXT: Detail green certificate menu item: delete -->
+    <string name="green_certificate_details_menu_item_delete">"Entfernen"</string>
+    <!-- XTXT: Detail green certificate diaglog title -->
+    <string name="green_certificate_details_dialog_remove_test_title">"Wollen Sie das Testzertifikat wirklich entfernen?"</string>
+    <!-- XTXT: Detail green certificate diaglog message -->
+    <string name="green_certificate_details_dialog_remove_test_message">"Wenn Sie das Testzertifikat entfernen, können Sie es nicht mehr als Nachweis in der App verwenden."</string>
+    <!-- XTXT: Detail green certificate diaglog positive -->
+    <string name="green_certificate_details_dialog_remove_test_button_positive">"Abbrechen"</string>
+    <!-- XTXT: Detail green certificate diaglog negative -->
+    <string name="green_certificate_details_dialog_remove_test_button_negative">"Entfernen"</string>
+
     <!-- XTXT: Green certificate main screen title -->
-    <string name="certification_screen_title">Nachweise</string>
+    <string name="certification_screen_title">"Certificates"</string>
     <!-- XTXT: Green certificate menu item -->
-    <string name="menu_certification_information">Information</string>
+    <string name="menu_certification_information">"Information"</string>
     <!-- XTXT: Green certificate main screen header text -->
-    <string name="green_certification_header_info">Hier werden Ihre digitalen Impfzertifikate und Testzertifikate angezeigt.</string>
+    <string name="green_certification_header_info">"Your digital vaccination certificates and test certificates are displayed here."</string>
     <!-- XTXT: Green certificate info card title 1st line -->
-    <string name="info_banner_title_1">Digitales</string>
+    <string name="info_banner_title_1">"Digital COVID-19"</string>
     <!-- XTXT: Green certificate info card title 2nd line  -->
-    <string name="info_banner_title_2">COVID-19-Testzertifikat</string>
+    <string name="info_banner_title_2">"COVID Test Certificate"</string>
     <!-- XTXT: Green certificate info card body  -->
-    <string name="info_banner_body">Registrieren Sie einen Test auf der Startseite und stimmen Sie zu, ein digitales Testzertifikat zu erhalten. Sobald das Zertifikat vorliegt, wird es hier angezeigt.</string>
-
-</resources>
\ No newline at end of file
+    <string name="info_banner_body">"Register a test on the home screen and agree to receive a digital test certificate. As soon as the certificate is available, it is displayed here."</string>
+    <!-- XTXT: Test certificate time -->
+    <string name="test_certificate_time">Test durchgeführt am %1$s, %2$s</string>
+    <!-- XTXT: Test error label -->
+    <string name="test_certificate_error_label">Fehler bei der Zertifikatsabfrage</string>
+    <!-- XBUT: Test error retry button -->
+    <string name="test_certificate_error_retry_button">Nochmal versuchen</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_try_again">Es konnte keine Verbindung hergestellt werden. Bitte versuchen Sie es erneut.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_dcc_not_supported_by_lab">Ein Testzertifikat kann nicht angefordert werden, da diese Teststelle die Ausstellung von Testzertifikaten nicht unterstützt. Bitte entfernen Sie das Zertifikat oder kontaktieren Sie die technische Hotline über App-Informationen -> Technische Hotline.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_no_network">Ihre Internetverbindung wurde unterbrochen. Bitte prüfen Sie die Verbindung und versuchen Sie es erneut.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_e2e_error_call_hotline">Ein Fehler ist aufgetreten. Bitte versuchen Sie es später noch einmal oder kontaktieren Sie die technische Hotline über App-Informationen -> Technische Hotline.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_try_again_dcc_not_available_yet">Ihr Zertifikat liegt noch nicht vor. Bitte versuchen Sie es noch einmal. Sollte der Fehler weiterhin bestehen, kontaktieren Sie bitte die technische Hotline über App-Informationen -> Technische Hotline.</string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_client_error_call_hotline">Ein Fehler ist aufgetreten. Bitte versuchen Sie es später noch einmal oder kontaktieren Sie die technische Hotline über App-Informationen -> Technische Hotline.></string>
+    <!-- XTXT: Error text -->
+    <string name="error_tc_dcc_expired">Das Zertifikat ist nicht mehr aktuell, Sie können es aus der Corona-App entfernen.</string>
+    <!-- XBUT: Test error delete button -->
+    <string name="test_certificate_error_delete_button">Testzertifikat entfernen</string>
+    <!-- XTXT: Test error refresh dialog title -->
+    <string name="test_certificate_refresh_dialog_title">"Es gibt weiterhin Probleme bei der Abfrage"</string>
+    <!-- XBUT: Test error refresh dialog confirm button -->
+    <string name="test_certificate_refresh_dialog_confirm_button">"OK"</string>
+    <!-- XTXT: Test error delete dialog title -->
+    <string name="test_certificate_delete_dialog_title">"Wollen Sie das Zertifikat wirklich entfernen?"</string>
+    <!-- XTXT: Test error delete dialog body -->
+    <string name="test_certificate_delete_dialog_body">"Wenn das Zertifikat enfernt wird, kann es nicht noch einmal angefordert werden."</string>
+    <!-- XBUT: Test error delete dialog confirm button -->
+    <string name="test_certificate_delete_dialog_confirm_button">"Entfernen"</string>
+    <!-- XBUT: Test error delete dialog cancel button -->
+    <string name="test_certificate_delete_dialog_cancel_button">"Abbrechen"</string>
+    <!-- XTXT: Test error card body refreshing -->
+    <string name="test_certificate_error_label_refreshing">"Ihr Zertifikat wird gerade erstellt…"</string>
+    <!-- XTXT: Test error card body refreshing -->
+    <string name="test_certificate_error_refreshing_status">"Ihr Zertifikat wird gerade angefragt, dies kann einige Minuten dauern…"</string>
+</resources>
diff --git a/Corona-Warn-App/src/main/res/values/release_info_strings.xml b/Corona-Warn-App/src/main/res/values/release_info_strings.xml
index 0139fcb8d8bae46019ffc85b06b1b8b89c02f793..fe38659e640ec864f7fd2d2af7c04dca67ce7f14 100644
--- a/Corona-Warn-App/src/main/res/values/release_info_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/release_info_strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation">
     <!-- ####################################
-                 Release Info Screen 1.14
+                 Release Info Screen
      ###################################### -->
 
     <!-- XHED: Title for the release info screen -->
@@ -17,22 +17,26 @@
 
     <!-- XHED: Titles for the release info screen bullet points -->
     <string-array name="new_release_title">
-        <item>"Digital Proof of Vaccination"</item>
+        <item>"COVID Test Certificate"</item>
+        <item>"Contact Journal Enhancement"</item>
     </string-array>
 
     <!-- XTXT: Text bodies for the release info screen bullet points -->
     <string-array name="new_release_body">
-        <item>"You can now add your vaccination certificates in the app and present them via QR code. The app displays full vaccination protection 14 days after the final vaccination."</item>
+        <item>"You can now request an official digital test certificate through the app and then add it in the app. You can use this test certificate (QR code) within the EU to prove a negative test result (for international travel, for example)."</item>
+        <item>"As soon as your test result is available, it is now also added to your contact journal."</item>
     </string-array>
 
     <!-- XTXT: Text labels that will be converted to Links -->
     <string-array name="new_release_linkified_labels">
         <item />
+        <item />
     </string-array>
 
     <!-- XTXT: URL destinations for the lables in new_release_linkified_labels -->
     <string-array name="new_release_target_urls">
         <item />
+        <item />
     </string-array>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml
index e82ee117aed4299f0c3255d82845e2b001f1a28a..5f70fd55b741fd292e7e66e3375b84278211384a 100644
--- a/Corona-Warn-App/src/main/res/values/strings.xml
+++ b/Corona-Warn-App/src/main/res/values/strings.xml
@@ -283,7 +283,7 @@
     <!-- XMSG: risk details - stay 1,5 away, something like a bullet point -->
     <string name="risk_details_behavior_body_stay_away">"Keep at least 1.5 meters distance from other people."</string>
     <!-- XTXT: find details about exposures in the contact journal -->
-    <string name="risk_details_find_details_in_journal"></string>
+    <string name="risk_details_find_details_in_journal">"You will find more information about your exposures in your contact journal."</string>
 
     <!-- XMSG: risk details - link to faq, something like a bullet point -->
     <string name="risk_details_increased_risk_faq_link_text">"If you get tested, you will find additional information about the testing procedure in the FAQ."</string>
@@ -1031,7 +1031,7 @@
     <!-- YTXT:  Body sub text 2 for Submission Consent call test result   -->
     <string name="submission_consent_call_test_result_scan_test_only_once">"Each test can only be scanned once. The app can manage a maximum of one rapid test and one PCR test at the same time."</string>
     <!-- YTXT:  Body sub text 3 for Submission Consent call test result   -->
-    <string name="submission_consent_call_test_result_checkmark_text">"Wenn Ihr Testergebnis negativ ist, können Sie dies in Form eines offiziellen COVID-19-Testzertifikats bestätigen lassen. Fordern Sie hierfür in den folgenden Schritten das Testzertifikat an."</string>
+    <string name="submission_consent_call_test_result_checkmark_text">"If your test result is negative, you can confirm this with an official COVID test certificate. To do so, request the test certificate in the following steps."</string>
     <!-- XHED: Page subheadline for consent help by warning others  -->
     <string name="submission_consent_help_by_warning_others_headline">"Please help others you have encountered by warning them!"</string>
     <!-- YTXT: Body for consent help by warning others -->
@@ -1093,13 +1093,13 @@
     <string name="submission_test_result_pending_steps_contact_diary_body">"As soon as your test result becomes available, it will be displayed in the app."</string>
 
     <!-- XHED: Page headline for test result certifcate info title  -->
-    <string name="submission_test_result_pending_steps_test_certificate_heading">"Ihr Testzertifikat"</string>
+    <string name="submission_test_result_pending_steps_test_certificate_heading">"Your Test Certificate"</string>
     <!-- YTXT: Body text for test result certifcate info, if certifcate is not supported, RAT Test -->
-    <string name="submission_test_result_pending_steps_test_certificate_not_supported_body">"Es liegt kein Testzertifikat vor, da diese Teststelle die Ausstellung von Testzertifikaten nicht unterstützt."</string>
+    <string name="submission_test_result_pending_steps_test_certificate_not_supported_body">"No test certificate is available because this testing point does not support the issuing of test certificates."</string>
     <!-- YTXT: Body text for test result certifcate info, if certifcate is not available yet, PCR Test consent given -->
-    <string name="submission_test_result_pending_steps_test_certificate_not_available_yet_body">"Ihr Testzertifikat liegt noch nicht vor. Sobald es vorliegt, wird es Ihnen in der App angezeigt."</string>
+    <string name="submission_test_result_pending_steps_test_certificate_not_available_yet_body">"Your test certificate is not available yet. As soon as it becomes available, it will be displayed in your app."</string>
     <!-- YTXT: Body text for test result certifcate info, if certifcate is not desired by the user, PCR Test no consent given -->
-    <string name="submission_test_result_pending_steps_test_certificate_not_desired_by_user_body">"Auf Ihren Wunsch hin wurde kein Testzertifikat ausgestellt."</string>
+    <string name="submission_test_result_pending_steps_test_certificate_not_desired_by_user_body">"No test certificate was issued, as per your request."</string>
 
     <!-- XBUT: test result pending : refresh button -->
     <string name="submission_test_result_pending_refresh_button">"Update"</string>
@@ -1193,7 +1193,7 @@
     <!-- YTXT: Dispatcher text for QR code option -->
     <string name="submission_dispatcher_card_qr">"Scan QR Code"</string>
     <!-- YTXT: Body text for QR code dispatcher option -->
-    <string name="submission_dispatcher_qr_card_text">"Receive your test result in the app and warn others."</string>
+    <string name="submission_dispatcher_qr_card_text">"Receive your test result in the app and warn others or request your COVID test certificate."</string>
     <!-- YTXT: Dispatcher text for TAN code option -->
     <string name="submission_dispatcher_card_tan_code">"Enter TAN for PCR Test"</string>
     <!-- YTXT: Body text for TAN code dispatcher option -->
@@ -1853,8 +1853,7 @@
     <!-- XHED: Title for BottomNav check-in screen title -->
     <string name="bottom_nav_check_ins_title">"Check In"</string>
     <!-- XHED: Title for BottomNav certificates screen title -->
-    <string name="bottom_nav_certificates_title">"Nachweise"</string>
-
+    <string name="bottom_nav_certificates_title">"Certificates"</string>
     <!-- ####################################
            Data Donation & Survey
     ###################################### -->
diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml
index e81fe78b15ebf0a921ed33b1a094de345cec4f18..5577e401916f0278a009ae24ab8f956924cde910 100644
--- a/Corona-Warn-App/src/main/res/values/styles.xml
+++ b/Corona-Warn-App/src/main/res/values/styles.xml
@@ -239,7 +239,7 @@
         <item name="android:backgroundTint">@color/colorVaccinationCardBackground</item>
     </style>
 
-    <style name="Card.Greencertificate" parent="Card.NoElevation">
+    <style name="Card.GreenCertificate" parent="Card.NoElevation">
         <item name="android:backgroundTint">@color/colorVaccinationCardBackground</item>
     </style>
 
diff --git a/Corona-Warn-App/src/main/res/values/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values/vaccination_strings.xml
index b138356683f194ae34df51ae85d23153029f1914..fd2e7fedf15353a3b458ff5bffe859868add1115 100644
--- a/Corona-Warn-App/src/main/res/values/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/vaccination_strings.xml
@@ -9,7 +9,7 @@
     <!-- XTXT: Vaccination Details vaccine manufacturer -->
     <string name="vaccination_details_vaccine_manufacturer">"Manufacturer"</string>
     <!-- XTXT: Vaccination Details vaccine type -->
-    <string name="vaccination_details_vaccine_medical_product_name">"Vaccine type"</string>
+    <string name="vaccination_details_vaccine_medical_product_name">"Vaccine Type"</string>
     <!-- XTXT: Vaccination Details certificate issuer -->
     <string name="vaccination_details_certificate_issuer">"Issuer"</string>
     <!-- XTXT: Vaccination Details certificate country -->
@@ -21,9 +21,9 @@
     <!-- XTXT: Vaccination Details title-->
     <string name="vaccination_details_title">"Vaccination %1$d of %2$d"</string>
     <!-- XTXT: Vaccination Qr Code card title-->
-    <string name="vaccination_qrcode_card_title">"Vaccination certificate %1$d of %2$d"</string>
+    <string name="vaccination_qrcode_card_title">"Vaccination Certificate %1$d of %2$d"</string>
     <!-- XTXT: Vaccination Qr Code card subtitle-->
-    <string name="vaccination_qrcode_card_subtitle">"Vaccinated %1$s - valid to %2$s"</string>
+    <string name="vaccination_qrcode_card_subtitle">"Vaccinated %1$s - Valid to %2$s"</string>
 
     <!-- XTXT: Vaccination List title-->
     <string name="vaccination_list_title">"Digital Proof of Vaccination"</string>
@@ -37,12 +37,12 @@
     <string name="vaccination_list_vaccination_card_subtitle">"Performed on %1$s"</string>
     <!-- XTXT: Vaccination List immunity information card body-->
     <plurals name="vaccination_list_immunity_card_body">
-        <item quantity="one">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d day."</item>
-        <item quantity="other">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
-        <item quantity="zero">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
-        <item quantity="two">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
-        <item quantity="few">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
-        <item quantity="many">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
+        <item quantity="one">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d day."</item>
+        <item quantity="other">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
+        <item quantity="zero">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
+        <item quantity="two">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
+        <item quantity="few">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
+        <item quantity="many">"You have now received all the currently planned vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item>
     </plurals>
     <!-- XBUT: Vaccination List register additional vaccination button -->
     <string name="vaccination_list_register_new_vaccination_button">"Register Another Vaccination"</string>
@@ -63,17 +63,19 @@
         Homescreen cards
     ###################################### -->
     <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_title">"Add Vaccination Certificate"</string>
+    <string name="vaccination_card_registration_title_line_1">"Add Digital Proof"</string>
     <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_title_line_1">"Digitalen"</string>
-    <!-- XHED: Title for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_title_line_2">"Impfnachweis hinzufügen"</string>
+    <string name="vaccination_card_registration_title_line_2">"of Vaccination"</string>
     <!-- YTXT: Body text for Vaccination Certificate Registration Home Card -->
-    <string name="vaccination_card_registration_body">"Add vaccination certificates in the app so you always have them with you. To do so, scan the QR code on your document."</string>
+    <string name="vaccination_card_registration_body">"Add your vaccination certificates in the app so you always have them with you. To do so, scan the QR code on your document."</string>
     <!-- XBUT: button for Vaccination Certificate Registration Home Card -->
     <string name="vaccination_card_register">"Add"</string>
     <!-- XHED: Homescreen vaccination status card title -->
     <string name="vaccination_card_status_title">"Digital Proof of Vaccination"</string>
+    <!-- XHED: Homescreen vaccination status card title -->
+    <string name="vaccination_card_status_title_line_1">"Digitaler"</string>
+    <!-- XHED: Homescreen vaccination status card title -->
+    <string name="vaccination_card_status_title_line_2">"Impfnachweis"</string>
     <!-- XHED: Homescreen vaccination status card vaccination name -->
     <string name="vaccination_card_status_vaccination_name">"SARS-CoV-2 Vaccination"</string>
     <!-- XTXT: Homescreen card incomplete vaccination status label -->
@@ -87,7 +89,8 @@
         <item quantity="few">"Full vaccination protection in %1$d days"</item>
         <item quantity="many">"Full vaccination protection in %1$d days"</item>
     </plurals>
-
+    <!-- XTXT: Homescreen card complete vaccination status label -->
+    <string name="vaccination_card_status_vaccination_complete">"Gültig bis einschließlich %s"</string>
     <!-- XTXT: Vaccination QR code scan error message-->
     <string name="error_vc_invalid">"This QR code is not a valid vaccination certificate."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
@@ -102,17 +105,17 @@
     <!-- XTXT: Vaccination Consent title-->
     <string name="vaccination_consent_title">"Your Consent"</string>
     <!-- XTXT: Vaccination Consent subtitle-->
-    <string name="vaccination_consent_headline">"Nachweise hinzufügen"</string>
+    <string name="vaccination_consent_headline">"Add Certificates"</string>
     <!-- XTXT: Vaccination Consent subtitle of qr info -->
-    <string name="vaccination_consent_info_subtitle_text">"Fügen Sie ihre digitalen COVID-Zertifikate in der App hinzu, um mit der App Ihren Impfschutz oder ein negatives Testergebnis nachweisen zu können."</string>
+    <string name="vaccination_consent_info_subtitle_text">"Add your digital COVID certificates in the app. This will enable you to prove your vaccination protection or a negative test result with the app."</string>
     <!-- XTXT: Vaccination Consent text of qr info -->
-    <string name="vaccination_consent_qr_info_text">"Sie können digitale COVID-19-Impfzertifikate oder COVID-19-Testzertifikate in der App hinzufügen."</string>
+    <string name="vaccination_consent_qr_info_text">"You can add digital COVID vaccination certificates or COVID test certificates in the app."</string>
     <!-- XTXT: Vaccination Consent qr code text -->
-    <string name="vaccination_consent_qr_info_qr_code_text">"Die Zertifikate gelten innerhalb der EU als gültiger Nachweis (z.B. für Reisen)."</string>
+    <string name="vaccination_consent_qr_info_qr_code_text">"These certificates are considered to be valid proof within the EU (e.g. for travel)."</string>
     <!-- XTXT: Vaccination Consent time text  -->
-    <string name="vaccination_consent_qr_info_time_text">"Nach dem Hinzufügen bleiben die Zertifikate auf Ihrem Smartphone. Andere Personen können Ihre Daten nur einsehen, wenn Sie diesen ein Zertifikat zur Überprüfung vorzeigen."</string>
+    <string name="vaccination_consent_qr_info_time_text">"After you add a certificate, it will remain on your smartphone. It will only be shared with others if you present a certificate for verification."</string>
     <!-- XTXT: Text for vaccination consent legal information button -->
-    <string name="vaccination_consent_onboarding_legal_information">"Ausführliche Informationen zur Datenverarbeitung finden Sie in der Datenschutzerklärung."</string>
+    <string name="vaccination_consent_onboarding_legal_information">"For more detailed information about data processing, please refer to the privacy notice."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Continue"</string>
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/CoronaWarnApplicationTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/CoronaWarnApplicationTest.kt
index c32f6f68c44a8c0b6575ebf2dcf44f826ced6fc9..4a47302e03614b11a1b1720f7916f1a958f0c195 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/CoronaWarnApplicationTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/CoronaWarnApplicationTest.kt
@@ -11,6 +11,8 @@ import de.rki.coronawarnapp.coronatest.type.pcr.execution.PCRResultScheduler
 import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultScheduler
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.notification.RATTestResultAvailableNotificationService
+import de.rki.coronawarnapp.covidcertificate.test.core.execution.TestCertificateRetrievalScheduler
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.VaccinationUpdateScheduler
 import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsScheduler
 import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler
 import de.rki.coronawarnapp.notification.GeneralNotifications
@@ -27,7 +29,6 @@ import de.rki.coronawarnapp.util.WatchdogService
 import de.rki.coronawarnapp.util.device.ForegroundState
 import de.rki.coronawarnapp.util.di.AppInjector
 import de.rki.coronawarnapp.util.di.ApplicationComponent
-import de.rki.coronawarnapp.vaccination.core.execution.VaccinationUpdateScheduler
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
 import io.mockk.every
@@ -70,6 +71,7 @@ class CoronaWarnApplicationTest : BaseTest() {
     @MockK lateinit var presenceTracingRiskWorkScheduler: PresenceTracingRiskWorkScheduler
     @MockK lateinit var pcrTestResultScheduler: PCRResultScheduler
     @MockK lateinit var raTestResultScheduler: RAResultScheduler
+    @MockK lateinit var testCertificateRetrievalScheduler: TestCertificateRetrievalScheduler
 
     @MockK lateinit var pcrTestResultAvailableNotificationService: PCRTestResultAvailableNotificationService
 
@@ -126,6 +128,7 @@ class CoronaWarnApplicationTest : BaseTest() {
                 app.pcrTestResultAvailableNotificationService = pcrTestResultAvailableNotificationService
                 app.raTestResultAvailableNotificationService = raTestResultAvailableNotificationService
                 app.vaccinationUpdateScheduler = vaccinationUpdateScheduler
+                app.testCertificateRetrievalScheduler = testCertificateRetrievalScheduler
                 app.appScope = TestCoroutineScope()
                 app.rollingLogHistory = object : Timber.Tree() {
                     override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
@@ -157,6 +160,7 @@ class CoronaWarnApplicationTest : BaseTest() {
 
             pcrTestResultAvailableNotificationService.setup()
             raTestResultAvailableNotificationService.setup()
+            testCertificateRetrievalScheduler.setup()
 
             vaccinationUpdateScheduler.setup()
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/ConfigParserTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/ConfigParserTest.kt
index d33e8d77414ac19e08efe5d0d45710e4c9d9536f..bbfdba52c11e2412fb8a13a40c53abae7d92434d 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/ConfigParserTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/ConfigParserTest.kt
@@ -4,6 +4,7 @@ import com.google.protobuf.InvalidProtocolBufferException
 import de.rki.coronawarnapp.appconfig.AnalyticsConfig
 import de.rki.coronawarnapp.appconfig.CWAConfig
 import de.rki.coronawarnapp.appconfig.CoronaTestConfig
+import de.rki.coronawarnapp.appconfig.CovidCertificateConfig
 import de.rki.coronawarnapp.appconfig.ExposureDetectionConfig
 import de.rki.coronawarnapp.appconfig.ExposureWindowRiskCalculationConfig
 import de.rki.coronawarnapp.appconfig.KeyDownloadConfig
@@ -34,6 +35,7 @@ class ConfigParserTest : BaseTest() {
     @MockK lateinit var logUploadConfigMapper: LogUploadConfig.Mapper
     @MockK lateinit var presenceTracingConfigMapper: PresenceTracingConfig.Mapper
     @MockK lateinit var coronaTestConfigMapper: CoronaTestConfig.Mapper
+    @MockK lateinit var covidCertificateConfigMapper: CovidCertificateConfig.Mapper
 
     private val appConfig171 = File("src/test/resources/appconfig_1_7_1.bin")
     private val appConfig180 = File("src/test/resources/appconfig_1_8_0.bin")
@@ -51,6 +53,7 @@ class ConfigParserTest : BaseTest() {
         every { logUploadConfigMapper.map(any()) } returns mockk()
         every { presenceTracingConfigMapper.map(any()) } returns mockk()
         every { coronaTestConfigMapper.map(any()) } returns mockk()
+        every { covidCertificateConfigMapper.map(any()) } returns mockk()
 
         appConfig171.exists() shouldBe true
         appConfig180.exists() shouldBe true
@@ -66,6 +69,7 @@ class ConfigParserTest : BaseTest() {
         logUploadConfigMapper = logUploadConfigMapper,
         presenceTracingConfigMapper = presenceTracingConfigMapper,
         coronaTestConfigMapper = coronaTestConfigMapper,
+        covidCertificateConfigMapper = covidCertificateConfigMapper,
     )
 
     @Test
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/CovidCertificateConfigMapperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/CovidCertificateConfigMapperTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1e9af041d366a966c24535fe9aa45f2c8ddf8f76
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/CovidCertificateConfigMapperTest.kt
@@ -0,0 +1,68 @@
+package de.rki.coronawarnapp.appconfig.mapping
+
+import de.rki.coronawarnapp.server.protocols.internal.v2.AppConfigAndroid
+import de.rki.coronawarnapp.server.protocols.internal.v2.DgcParameters
+import io.kotest.matchers.shouldBe
+import org.joda.time.Duration
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class CovidCertificateConfigMapperTest : BaseTest() {
+
+    private fun createInstance() = CovidCertificateConfigMapper()
+
+    @Test
+    fun `values are mapped`() {
+        val config = AppConfigAndroid.ApplicationConfigurationAndroid.newBuilder()
+            .setDgcParameters(
+                DgcParameters.DGCParameters.newBuilder()
+                    .setTestCertificateParameters(
+                        DgcParameters.DGCTestCertificateParameters.newBuilder()
+                            .setWaitForRetryInSeconds(60)
+                            .setWaitAfterPublicKeyRegistrationInSeconds(60)
+                    )
+            )
+            .build()
+        createInstance().map(config).apply {
+            testCertificate.waitAfterPublicKeyRegistration shouldBe Duration.standardSeconds(60)
+            testCertificate.waitForRetry shouldBe Duration.standardSeconds(60)
+        }
+    }
+
+    @Test
+    fun `defaults are returned if all dcc parameters are missing`() {
+        createInstance().map(AppConfigAndroid.ApplicationConfigurationAndroid.getDefaultInstance()).apply {
+            testCertificate.waitAfterPublicKeyRegistration shouldBe Duration.standardSeconds(10)
+            testCertificate.waitForRetry shouldBe Duration.standardSeconds(10)
+        }
+    }
+
+    @Test
+    fun `defaults are returned if just test certificate parameters are missing`() {
+        val config = AppConfigAndroid.ApplicationConfigurationAndroid.newBuilder()
+            .setDgcParameters(DgcParameters.DGCParameters.getDefaultInstance())
+            .build()
+        createInstance().map(config).apply {
+            testCertificate.waitAfterPublicKeyRegistration shouldBe Duration.standardSeconds(10)
+            testCertificate.waitForRetry shouldBe Duration.standardSeconds(10)
+        }
+    }
+
+    @Test
+    fun `values are checked for sanity`() {
+        val config = AppConfigAndroid.ApplicationConfigurationAndroid.newBuilder()
+            .setDgcParameters(
+                DgcParameters.DGCParameters.newBuilder()
+                    .setTestCertificateParameters(
+                        DgcParameters.DGCTestCertificateParameters.newBuilder()
+                            .setWaitForRetryInSeconds(61)
+                            .setWaitAfterPublicKeyRegistrationInSeconds(61)
+                    )
+            )
+            .build()
+        createInstance().map(config).apply {
+            testCertificate.waitAfterPublicKeyRegistration shouldBe Duration.standardSeconds(10)
+            testCertificate.waitForRetry shouldBe Duration.standardSeconds(10)
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt
index d76f485edcb574882a874c0d91ee5c66624af335..ed3ee7d48e3af793155877f19fa6e39e9b7bb831 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt
@@ -1,7 +1,8 @@
 package de.rki.coronawarnapp.bugreporting.censors.vaccination
 
-import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.mockk
@@ -15,19 +16,19 @@ internal class CertificateQrCodeCensorTest {
 
     private val testRawString =
         "HC1:6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3.ZH9M9ESIGUBA KWML/O6HXK 0D+4O5VC9:BPCNYKMXEE1JAA/CZIK0JK1WL260X638J3-E3GG396B-43FZT-43:S0X37*ZV+FNI6HXY0ZSVILVQJF//05MVZJ5V.499TXY9KK9+OC+G9QJPNF67J6QW67KQY466PPM4MLJE+.PDB9L6Q2+PFQ5DB96PP5/P-59A%N+892 7J235II3NJ7PK7SLQMIJSBHVA7UJQWT.+S+ND%%M%331BH.IA.C8KRDL4O54O4IGUJKJGI0JAXD15IAXMFU*GSHGHD63DAOC9JU0H11+*4.\$S6ZC0JBZAB-C3QHISKE MCAOI8%M3V96-PY\$N6XOWLIBPIAYU:*JIRHUF2XZQ4H9 XJ72WG1K36VF/9BL56%E8T1OEEG%5TW5A 6YO67N6UCE:WT6BT-UMM:ABJK2TMDN1:FW-%T+\$D78NDSC3%5F61NYS-P9LOE0%J/ZAY:N5L4H-H/LH:AO3FU JHG7K46IOIMT.RE%PHLA21JRI3HTC\$AH"
-    private val testCertificateData = VaccinationCertificateData(
+    private val testCertificateData = DccData(
         header = mockk(),
-        certificate = VaccinationDGCV1(
+        certificate = VaccinationDccV1(
             version = "1",
-            nameData = VaccinationDGCV1.NameData(
+            nameData = Dcc.NameData(
                 familyName = "Kevin",
                 familyNameStandardized = "KEVIN",
                 givenName = "Bob",
                 givenNameStandardized = "BOB"
             ),
             dob = "1969-11-16",
-            vaccinationDatas = listOf(
-                VaccinationDGCV1.VaccinationData(
+            payloads = listOf(
+                VaccinationDccV1.VaccinationData(
                     targetId = "12345",
                     vaccineId = "1214765",
                     medicalProductId = "aaEd/easd",
@@ -35,7 +36,7 @@ internal class CertificateQrCodeCensorTest {
                     doseNumber = 2,
                     totalSeriesOfDoses = 5,
                     dt = "1969-04-20",
-                    countryOfVaccination = "DE",
+                    certificateCountry = "DE",
                     certificateIssuer = "Herbert",
                     uniqueCertificateIdentifier = "urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ"
                 )
@@ -77,7 +78,7 @@ internal class CertificateQrCodeCensorTest {
             "vaccinationCertificate/dateOfBirth, i have been vaccinated with: vaccinationData/targetId " +
             "vaccinationData/vaccineId vaccinationData/medicalProductId" +
             " vaccinationData/marketAuthorizationHolderId vaccinationData/vaccinatedAt" +
-            " vaccinationData/countryOfVaccination vaccinationData/certificateIssuer" +
+            " vaccinationData/certificateCountry vaccinationData/certificateIssuer" +
             " vaccinationData/uniqueCertificateIdentifier"
     }
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/CoronaTestRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/CoronaTestRepositoryTest.kt
index 267613b4ada2052a2b2e0e5086468ed12c2ba75e..7eb566a58f9810a6458f0c3499b0d2d6243e4a1a 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/CoronaTestRepositoryTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/CoronaTestRepositoryTest.kt
@@ -6,9 +6,9 @@ import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
 import de.rki.coronawarnapp.coronatest.storage.CoronaTestStorage
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest
-import de.rki.coronawarnapp.coronatest.type.pcr.PCRProcessor
+import de.rki.coronawarnapp.coronatest.type.pcr.PCRTestProcessor
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest
-import de.rki.coronawarnapp.coronatest.type.rapidantigen.RAProcessor
+import de.rki.coronawarnapp.coronatest.type.rapidantigen.RATestProcessor
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
 import io.mockk.coEvery
@@ -38,9 +38,9 @@ class CoronaTestRepositoryTest : BaseTest() {
         registrationToken = "token",
         testResult = CoronaTestResult.PCR_REDEEMED,
     )
-    @MockK lateinit var pcrProcessor: PCRProcessor
+    @MockK lateinit var pcrProcessor: PCRTestProcessor
 
-    @MockK lateinit var raProcessor: RAProcessor
+    @MockK lateinit var raProcessor: RATestProcessor
     private val raTest = RACoronaTest(
         identifier = "ra-identifier",
         lastUpdatedAt = Instant.EPOCH,
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/CoronaTestTestComponent.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/CoronaTestTestComponent.kt
new file mode 100644
index 0000000000000000000000000000000000000000..cc0db91130df0ad8c2d29e579cdfcd938471d211
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/CoronaTestTestComponent.kt
@@ -0,0 +1,29 @@
+package de.rki.coronawarnapp.coronatest
+
+import dagger.Component
+import dagger.Module
+import de.rki.coronawarnapp.coronatest.type.TestCertificateContainerTest
+import de.rki.coronawarnapp.covidcertificate.storage.TestCertificateStorageTest
+import de.rki.coronawarnapp.util.serialization.SerializationModule
+import javax.inject.Singleton
+
+@Singleton
+@Component(
+    modules = [
+        CoronaTestMockProvider::class,
+        SerializationModule::class
+    ]
+)
+interface CoronaTestTestComponent {
+
+    fun inject(testClass: TestCertificateStorageTest)
+    fun inject(testClass: TestCertificateContainerTest)
+
+    @Component.Factory
+    interface Factory {
+        fun create(): CoronaTestTestComponent
+    }
+}
+
+@Module
+class CoronaTestMockProvider
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/TestCertificateContainerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/TestCertificateContainerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8c42b1e213257a704b966a54a50df594a490bf29
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/TestCertificateContainerTest.kt
@@ -0,0 +1,55 @@
+package de.rki.coronawarnapp.coronatest.type
+
+import de.rki.coronawarnapp.coronatest.DaggerCoronaTestTestComponent
+import de.rki.coronawarnapp.covidcertificate.test.TestCertificateTestData
+import io.kotest.matchers.shouldBe
+import io.kotest.matchers.shouldNotBe
+import io.mockk.mockk
+import org.joda.time.Instant
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import javax.inject.Inject
+
+class TestCertificateContainerTest : BaseTest() {
+
+    @Inject lateinit var certificateTestData: TestCertificateTestData
+
+    @BeforeEach
+    fun setup() {
+        DaggerCoronaTestTestComponent.factory().create().inject(this)
+    }
+
+    @Test
+    fun `ui facing test certificate creation and fallbacks`() {
+        certificateTestData.personATest2CertContainer.apply {
+            isPublicKeyRegistered shouldBe true
+            isCertificateRetrievalPending shouldBe false
+            certificateId shouldBe "URN:UVCI:V1:DE:7WR8CE12Y8O2AN4NK320TPNKB1"
+            data.testCertificateQrCode shouldBe certificateTestData.personATest2CertQRCodeString
+            data.certificateReceivedAt shouldBe Instant.parse("1970-01-02T10:17:36.789Z")
+            toTestCertificate(null) shouldNotBe null
+        }
+    }
+
+    @Test
+    fun `pending check and nullability`() {
+        certificateTestData.personATest3CertNokeyContainer.apply {
+            isPublicKeyRegistered shouldBe false
+            isCertificateRetrievalPending shouldBe true
+            certificateId shouldBe null
+            data.testCertificateQrCode shouldBe null
+            data.certificateReceivedAt shouldBe null
+            toTestCertificate(mockk()) shouldBe null
+        }
+
+        certificateTestData.personATest4CertPendingContainer.apply {
+            isPublicKeyRegistered shouldBe true
+            isCertificateRetrievalPending shouldBe true
+            certificateId shouldBe null
+            data.testCertificateQrCode shouldBe null
+            data.certificateReceivedAt shouldBe null
+            toTestCertificate(mockk()) shouldBe null
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt
index 82bfa938238018c59fffc3ff91af83a5891ea49b..04e5a7110f6f46ccf7ebac591793fc89b0892b98 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt
@@ -35,6 +35,7 @@ import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.runBlockingTest
 import org.joda.time.Duration
 import org.joda.time.Instant
+import org.joda.time.LocalDate
 import org.junit.jupiter.api.AfterEach
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
@@ -99,7 +100,7 @@ class PCRProcessorTest : BaseTest() {
         runBlocking { PcrTeleTanCensor.clearTans() }
     }
 
-    fun createInstance() = PCRProcessor(
+    fun createInstance() = PCRTestProcessor(
         timeStamper = timeStamper,
         submissionService = submissionService,
         analyticsKeySubmissionCollector = analyticsKeySubmissionCollector,
@@ -275,4 +276,51 @@ class PCRProcessorTest : BaseTest() {
             isAdvancedConsentGiven = false
         )
     }
+
+    @Test
+    fun `request parameters for dcc are mapped`() = runBlockingTest {
+        val registrationData = RegistrationData(
+            registrationToken = "regtoken",
+            testResultResponse = CoronaTestResultResponse(
+                coronaTestResult = PCR_OR_RAT_PENDING,
+                sampleCollectedAt = null,
+            )
+        )
+        coEvery { submissionService.registerTest(any()) } answers { registrationData }
+
+        createInstance().create(
+            CoronaTestQRCode.PCR(
+                qrCodeGUID = "guid",
+                isDccConsentGiven = true,
+                dateOfBirth = LocalDate.parse("2021-06-02"),
+            )
+        ).apply {
+            isDccConsentGiven shouldBe true
+            isDccDataSetCreated shouldBe false
+            isDccSupportedByPoc shouldBe true
+        }
+
+        createInstance().create(
+            CoronaTestQRCode.PCR(
+                qrCodeGUID = "guid",
+                dateOfBirth = LocalDate.parse("2021-06-02"),
+            )
+        ).apply {
+            isDccConsentGiven shouldBe false
+            isDccDataSetCreated shouldBe false
+            isDccSupportedByPoc shouldBe true
+        }
+    }
+
+    @Test
+    fun `marking dcc as created`() = runBlockingTest {
+        val instance = createInstance()
+
+        instance.markDccCreated(defaultTest, true) shouldBe defaultTest.copy(
+            isDccDataSetCreated = true
+        )
+        instance.markDccCreated(defaultTest, false) shouldBe defaultTest.copy(
+            isDccDataSetCreated = false
+        )
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RAProcessorTest.kt
similarity index 80%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessorTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RAProcessorTest.kt
index 8f5ba33f398a61df2d28ab818c2d9926d28b58d6..2846d0f54b9f17b104b72c59e83d4295f94f8f4f 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenProcessorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RAProcessorTest.kt
@@ -16,6 +16,7 @@ import de.rki.coronawarnapp.coronatest.server.CoronaTestResult.values
 import de.rki.coronawarnapp.coronatest.server.CoronaTestResultResponse
 import de.rki.coronawarnapp.coronatest.server.RegistrationData
 import de.rki.coronawarnapp.coronatest.server.RegistrationRequest
+import de.rki.coronawarnapp.coronatest.server.VerificationKeyType
 import de.rki.coronawarnapp.coronatest.type.CoronaTest.Type.RAPID_ANTIGEN
 import de.rki.coronawarnapp.coronatest.type.CoronaTestService
 import de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission.AnalyticsKeySubmissionCollector
@@ -26,17 +27,19 @@ import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
 import io.mockk.coEvery
+import io.mockk.coVerify
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
 import io.mockk.just
 import kotlinx.coroutines.test.runBlockingTest
 import org.joda.time.Duration
 import org.joda.time.Instant
+import org.joda.time.LocalDate
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 
-class RapidAntigenProcessorTest : BaseTest() {
+class RAProcessorTest : BaseTest() {
 
     @MockK lateinit var timeStamper: TimeStamper
     @MockK lateinit var submissionService: CoronaTestService
@@ -94,7 +97,7 @@ class RapidAntigenProcessorTest : BaseTest() {
         }
     }
 
-    fun createInstance() = RAProcessor(
+    fun createInstance() = RATestProcessor(
         timeStamper = timeStamper,
         submissionService = submissionService,
         analyticsKeySubmissionCollector = analyticsKeySubmissionCollector,
@@ -140,6 +143,27 @@ class RapidAntigenProcessorTest : BaseTest() {
         instance.pollServer(past60DaysTest).testResult shouldBe RAT_REDEEMED
     }
 
+    @Test
+    fun `registering a new test`() = runBlockingTest {
+        val request = CoronaTestQRCode.RapidAntigen(
+            hash = "hash",
+            createdAt = Instant.EPOCH,
+        )
+
+        val instance = createInstance()
+        instance.create(request)
+
+        val expectedServerRequest = RegistrationRequest(
+            key = request.registrationIdentifier,
+            type = VerificationKeyType.GUID,
+            dateOfBirthKey = null,
+        )
+
+        coVerify {
+            submissionService.registerTest(expectedServerRequest)
+        }
+    }
+
     @Test
     fun `registering a new test maps invalid results to INVALID state`() = runBlockingTest {
         var registrationData = RegistrationData(
@@ -280,4 +304,56 @@ class RapidAntigenProcessorTest : BaseTest() {
             isAdvancedConsentGiven = false
         )
     }
+
+    @Test
+    fun `request parameters for dcc are mapped`() = runBlockingTest {
+        val registrationData = RegistrationData(
+            registrationToken = "regtoken",
+            testResultResponse = CoronaTestResultResponse(
+                coronaTestResult = PCR_OR_RAT_PENDING,
+                sampleCollectedAt = null,
+            )
+        )
+        coEvery { submissionService.registerTest(any()) } answers { registrationData }
+
+        createInstance().create(
+            CoronaTestQRCode.RapidAntigen(
+                hash = "hash",
+                createdAt = Instant.EPOCH,
+                isDccConsentGiven = false,
+                dateOfBirth = LocalDate.parse("2021-06-02"),
+                isDccSupportedByPoc = false
+            )
+        ).apply {
+            isDccConsentGiven shouldBe false
+            isDccDataSetCreated shouldBe false
+            isDccSupportedByPoc shouldBe false
+        }
+
+        createInstance().create(
+            CoronaTestQRCode.RapidAntigen(
+                hash = "hash",
+                createdAt = Instant.EPOCH,
+                isDccConsentGiven = true,
+                dateOfBirth = LocalDate.parse("2021-06-02"),
+                isDccSupportedByPoc = true
+            )
+        ).apply {
+            isDccConsentGiven shouldBe true
+            isDccDataSetCreated shouldBe false
+            isDccSupportedByPoc shouldBe true
+        }
+    }
+
+    @Test
+    fun `marking dcc as created`() = runBlockingTest {
+        val instance = createInstance()
+
+        instance.markDccCreated(defaultTest, true) shouldBe defaultTest.copy(
+            isDccDataSetCreated = true
+        )
+        instance.markDccCreated(defaultTest, false) shouldBe defaultTest.copy(
+            isDccDataSetCreated = false
+        )
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifierTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/common/CertificatePersonIdentifierTest.kt
similarity index 64%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifierTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/common/CertificatePersonIdentifierTest.kt
index 5822f0e6951db3d730211a1a609c0c3d8c5fc608..f0b34bd137c7cd1357012aeeb38eb4877a7218cd 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifierTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/common/CertificatePersonIdentifierTest.kt
@@ -1,7 +1,9 @@
-package de.rki.coronawarnapp.vaccination.core
+package de.rki.coronawarnapp.covidcertificate.common
 
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_DOB_MISMATCH
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_NAME_MISMATCH
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
 import io.kotest.assertions.throwables.shouldNotThrowAny
 import io.kotest.assertions.throwables.shouldThrow
 import io.kotest.matchers.shouldBe
@@ -9,14 +11,14 @@ import org.joda.time.LocalDate
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 
-class VaccinatedPersonIdentifierTest : BaseTest() {
-    private val testPersonMaxData = VaccinatedPersonIdentifier(
+class CertificatePersonIdentifierTest : BaseTest() {
+    private val testPersonMaxData = CertificatePersonIdentifier(
         dateOfBirth = LocalDate.parse("1966-11-11"),
         firstNameStandardized = "ANDREAS",
         lastNameStandardized = "ASTRA<EINS"
     )
 
-    private val testPersonMin = VaccinatedPersonIdentifier(
+    private val testPersonMin = CertificatePersonIdentifier(
         dateOfBirth = LocalDate.parse("1900-01-01"),
         lastNameStandardized = "#",
         firstNameStandardized = null
@@ -37,7 +39,7 @@ class VaccinatedPersonIdentifierTest : BaseTest() {
     @Test
     fun `person equality`() {
         val person1 = testPersonMaxData
-        val person2 = VaccinatedPersonIdentifier(
+        val person2 = CertificatePersonIdentifier(
             dateOfBirth = LocalDate.parse("1966-11-11"),
             firstNameStandardized = "ANDREAS",
             lastNameStandardized = "ASTRA<EINS"
@@ -54,16 +56,16 @@ class VaccinatedPersonIdentifierTest : BaseTest() {
             testPersonMaxData.requireMatch(testPersonMaxData)
         }
 
-        shouldThrow<InvalidHealthCertificateException> {
+        shouldThrow<InvalidVaccinationCertificateException> {
             testPersonMaxData.requireMatch(testPersonMaxData.copy(firstNameStandardized = "nope"))
-        }.errorCode shouldBe ErrorCode.VC_NAME_MISMATCH
+        }.errorCode shouldBe VC_NAME_MISMATCH
 
-        shouldThrow<InvalidHealthCertificateException> {
+        shouldThrow<InvalidVaccinationCertificateException> {
             testPersonMaxData.requireMatch(testPersonMaxData.copy(lastNameStandardized = "nope"))
-        }.errorCode shouldBe ErrorCode.VC_NAME_MISMATCH
+        }.errorCode shouldBe VC_NAME_MISMATCH
 
-        shouldThrow<InvalidHealthCertificateException> {
+        shouldThrow<InvalidVaccinationCertificateException> {
             testPersonMaxData.requireMatch(testPersonMaxData.copy(dateOfBirth = LocalDate.parse("1900-12-31")))
-        }.errorCode shouldBe ErrorCode.VC_DOB_MISMATCH
+        }.errorCode shouldBe VC_DOB_MISMATCH
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptographyTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptographyTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b98b171ad5c9667de587c4dd45a260678d4fcab4
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptographyTest.kt
@@ -0,0 +1,19 @@
+package de.rki.coronawarnapp.covidcertificate.cryptography
+
+import io.kotest.matchers.shouldBe
+import okio.ByteString.Companion.decodeBase64
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class AesCryptographyTest : BaseTest() {
+
+    @Test
+    fun `decrypt Hello World`() {
+        val des = "d56t/juMw5r4qNx1n1igs1pobUjZBT5yq0Ct7MHUuKM=".decodeBase64()!!.toByteArray()
+        val encryptedString = "WFOLewp8DWqY/8IWUHEDwg==".decodeBase64()!!.toByteArray()
+        AesCryptography().decrypt(
+            des,
+            encryptedData = encryptedString
+        ) shouldBe "Hello World".toByteArray()
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateProcessorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateProcessorTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..605e0e21c8a1a7792f4a8c4b1fa4cd8b757f3191
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateProcessorTest.kt
@@ -0,0 +1,120 @@
+package de.rki.coronawarnapp.covidcertificate.execution
+
+import de.rki.coronawarnapp.appconfig.AppConfigProvider
+import de.rki.coronawarnapp.appconfig.ConfigData
+import de.rki.coronawarnapp.appconfig.CovidCertificateConfig
+import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCode
+import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.test.core.server.TestCertificateComponents
+import de.rki.coronawarnapp.covidcertificate.test.core.server.TestCertificateServer
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.PCRCertificateData
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.StoredTestCertificateData
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateProcessor
+import de.rki.coronawarnapp.util.TimeStamper
+import de.rki.coronawarnapp.util.encryption.rsa.RSACryptography
+import de.rki.coronawarnapp.util.encryption.rsa.RSAKeyPairGenerator
+import io.mockk.MockKAnnotations
+import io.mockk.Runs
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.just
+import io.mockk.mockk
+import kotlinx.coroutines.flow.flowOf
+import okio.ByteString
+import org.joda.time.Duration
+import org.joda.time.Instant
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import testhelpers.coroutines.runBlockingTest2
+
+class TestCertificateProcessorTest : BaseTest() {
+
+    @MockK lateinit var timeStamper: TimeStamper
+    @MockK lateinit var certificateServer: TestCertificateServer
+    @MockK lateinit var rsaCryptography: RSACryptography
+    @MockK lateinit var qrCodeExtractor: TestCertificateQRCodeExtractor
+    @MockK lateinit var appConfigProvider: AppConfigProvider
+    @MockK lateinit var appConfigData: ConfigData
+    @MockK lateinit var covidTestCertificateConfig: CovidCertificateConfig.TestCertificate
+
+    private val testCertificateNew = PCRCertificateData(
+        identifier = "identifier1",
+        registrationToken = "regtoken1",
+        registeredAt = Instant.EPOCH,
+    )
+
+    private val testCertificateWithPubKey = testCertificateNew.copy(
+        publicKeyRegisteredAt = Instant.EPOCH,
+        rsaPublicKey = mockk(),
+        rsaPrivateKey = mockk(),
+    )
+
+    private val testCerticateComponents = mockk<TestCertificateComponents>().apply {
+        every { dataEncryptionKeyBase64 } returns "dek"
+        every { encryptedCoseTestCertificateBase64 } returns ""
+    }
+
+    private var storageSet = mutableSetOf<StoredTestCertificateData>()
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        every { timeStamper.nowUTC } returns Instant.EPOCH
+
+        every { appConfigProvider.currentConfig } returns flowOf(appConfigData)
+        every { appConfigData.covidCertificateParameters } returns mockk<CovidCertificateConfig>().apply {
+            every { testCertificate } returns covidTestCertificateConfig
+        }
+
+        covidTestCertificateConfig.apply {
+            every { waitForRetry } returns Duration.standardSeconds(10)
+            every { waitAfterPublicKeyRegistration } returns Duration.standardSeconds(10)
+        }
+
+        certificateServer.apply {
+            coEvery { registerPublicKeyForTest(any(), any()) } just Runs
+            coEvery { requestCertificateForTest(any()) } returns testCerticateComponents
+        }
+
+        every { rsaCryptography.decrypt(any(), any()) } returns ByteString.Companion.EMPTY
+
+        coEvery { qrCodeExtractor.extract(any(), any()) } returns mockk<TestCertificateQRCode>().apply {
+            every { qrCode } returns "qrCode"
+            every { data } returns mockk()
+        }
+    }
+
+    private fun createInstance() = TestCertificateProcessor(
+        qrCodeExtractor = qrCodeExtractor,
+        timeStamper = timeStamper,
+        certificateServer = certificateServer,
+        rsaKeyPairGenerator = RSAKeyPairGenerator(),
+        rsaCryptography = rsaCryptography,
+        appConfigProvider = appConfigProvider,
+    )
+
+    @Test
+    fun `public key registration`() = runBlockingTest2(ignoreActive = true) {
+        val instance = createInstance()
+        instance.registerPublicKey(testCertificateNew)
+
+        coVerify {
+            certificateServer.registerPublicKeyForTest(testCertificateNew.registrationToken, any())
+        }
+    }
+
+    @Test
+    fun `obtain certificate components`() = runBlockingTest2(ignoreActive = true) {
+        val instance = createInstance()
+        instance.obtainCertificate(testCertificateWithPubKey)
+
+        coVerify {
+            covidTestCertificateConfig.waitAfterPublicKeyRegistration
+            certificateServer.requestCertificateForTest(testCertificateNew.registrationToken)
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateRetrievalSchedulerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateRetrievalSchedulerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..26617d4a7fedc92d88d0cf9facac1f1e8f9a153e
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateRetrievalSchedulerTest.kt
@@ -0,0 +1,138 @@
+package de.rki.coronawarnapp.covidcertificate.execution
+
+import androidx.work.OneTimeWorkRequest
+import androidx.work.WorkInfo
+import androidx.work.WorkManager
+import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateWrapper
+import de.rki.coronawarnapp.covidcertificate.test.core.execution.TestCertificateRetrievalScheduler
+import de.rki.coronawarnapp.util.device.ForegroundState
+import io.mockk.MockKAnnotations
+import io.mockk.Runs
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.just
+import io.mockk.mockk
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import testhelpers.coroutines.runBlockingTest2
+import testhelpers.gms.MockListenableFuture
+
+class TestCertificateRetrievalSchedulerTest : BaseTest() {
+
+    @MockK lateinit var workManager: WorkManager
+    @MockK lateinit var certificateRepo: TestCertificateRepository
+    @MockK lateinit var testRepo: CoronaTestRepository
+    @MockK lateinit var foregroundState: ForegroundState
+    @MockK lateinit var workInfo: WorkInfo
+
+    private val mockTest = mockk<CoronaTest>().apply {
+        every { identifier } returns "identifier1"
+        every { isDccConsentGiven } returns true
+        every { isDccDataSetCreated } returns false
+        every { isDccSupportedByPoc } returns true
+        every { isNegative } returns true
+    }
+
+    private val mockCertificate = mockk<TestCertificateWrapper>().apply {
+        every { identifier } returns "UUID"
+        every { isCertificateRetrievalPending } returns true
+        every { isUpdatingData } returns false
+    }
+
+    private val testsFlow = MutableStateFlow(setOf(mockTest))
+    private val certificatesFlow = MutableStateFlow(setOf(mockCertificate))
+    private val foregroundFlow = MutableStateFlow(false)
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        workManager.apply {
+            every { enqueueUniqueWork(any(), any(), any<OneTimeWorkRequest>()) } returns mockk()
+            every { getWorkInfosForUniqueWork(any()) } returns MockListenableFuture.forResult(listOf(workInfo))
+        }
+
+        every { workInfo.state } returns WorkInfo.State.SUCCEEDED
+
+        testRepo.apply {
+            every { testRepo.coronaTests } returns testsFlow
+            coEvery { markDccAsCreated(any(), any()) } just Runs
+        }
+        certificateRepo.apply {
+            every { certificates } returns certificatesFlow
+            coEvery { requestCertificate(any()) } returns mockk()
+        }
+
+        every { foregroundState.isInForeground } returns foregroundFlow
+    }
+
+    private fun createInstance(scope: CoroutineScope) = TestCertificateRetrievalScheduler(
+        appScope = scope,
+        workManager = workManager,
+        certificateRepo = certificateRepo,
+        foregroundState = foregroundState,
+        testRepo = testRepo,
+    )
+
+    @Test
+    fun `new negative corona tests create a dcc if supported and consented`() = runBlockingTest2(ignoreActive = true) {
+        createInstance(scope = this).setup()
+        coVerify { certificateRepo.requestCertificate(mockTest) }
+    }
+
+    @Test
+    fun `certificates only for negative results`() = runBlockingTest2(ignoreActive = true) {
+        every { mockTest.isNegative } returns false
+        createInstance(scope = this).setup()
+        advanceUntilIdle()
+        coVerify(exactly = 0) { certificateRepo.requestCertificate(any()) }
+    }
+
+    @Test
+    fun `no duplicate certificates for flaky test results`() = runBlockingTest2(ignoreActive = true) {
+        every { mockTest.isDccDataSetCreated } returns true
+        createInstance(scope = this).setup()
+        advanceUntilIdle()
+        coVerify(exactly = 0) { certificateRepo.requestCertificate(any()) }
+    }
+
+    @Test
+    fun `refresh on foreground`() = runBlockingTest2(ignoreActive = true) {
+        testsFlow.value = emptySet()
+
+        createInstance(scope = this).setup()
+        advanceUntilIdle()
+        coVerify(exactly = 1) { workManager.enqueueUniqueWork(any(), any(), any<OneTimeWorkRequest>()) }
+
+        foregroundFlow.value = true
+        advanceUntilIdle()
+        coVerify(exactly = 2) { workManager.enqueueUniqueWork(any(), any(), any<OneTimeWorkRequest>()) }
+    }
+
+    @Test
+    fun `refresh on new certificate entry`() = runBlockingTest2(ignoreActive = true) {
+        testsFlow.value = emptySet()
+        createInstance(scope = this).setup()
+
+        advanceUntilIdle()
+        coVerify(exactly = 1) { workManager.enqueueUniqueWork(any(), any(), any<OneTimeWorkRequest>()) }
+
+        val mockCertificate2 = mockk<TestCertificateWrapper>().apply {
+            every { identifier } returns "UUID2"
+            every { isCertificateRetrievalPending } returns true
+            every { isUpdatingData } returns false
+        }
+
+        certificatesFlow.value = setOf(mockCertificate, mockCertificate2)
+        advanceUntilIdle()
+        coVerify(exactly = 2) { workManager.enqueueUniqueWork(any(), any(), any<OneTimeWorkRequest>()) }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateRetrievalWorkerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateRetrievalWorkerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7739eb15d5af474f35a7418ff0a142cc2f557faf
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateRetrievalWorkerTest.kt
@@ -0,0 +1,75 @@
+package de.rki.coronawarnapp.covidcertificate.execution
+
+import android.content.Context
+import androidx.work.ListenableWorker
+import androidx.work.WorkRequest
+import androidx.work.WorkerParameters
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.covidcertificate.test.core.execution.TestCertificateRetrievalWorker
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.impl.annotations.RelaxedMockK
+import kotlinx.coroutines.test.runBlockingTest
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import java.net.UnknownHostException
+
+class TestCertificateRetrievalWorkerTest : BaseTest() {
+    @MockK lateinit var context: Context
+    @MockK lateinit var request: WorkRequest
+    @MockK lateinit var testCertificateRepository: TestCertificateRepository
+
+    @RelaxedMockK lateinit var workerParams: WorkerParameters
+
+    @BeforeEach
+    fun setUp() {
+        MockKAnnotations.init(this)
+
+        coEvery { testCertificateRepository.refresh() } returns emptySet()
+    }
+
+    private fun createWorker(
+        runAttempts: Int = 0
+    ) = TestCertificateRetrievalWorker(
+        context = context,
+        workerParams = workerParams.also {
+            every { it.runAttemptCount } returns runAttempts
+        },
+        testCertificateRepository = testCertificateRepository,
+    )
+
+    @Test
+    fun `certificate refresh`() = runBlockingTest {
+        val result = createWorker().doWork()
+
+        coVerify(exactly = 1) { testCertificateRepository.refresh() }
+
+        result shouldBe ListenableWorker.Result.success()
+    }
+
+    @Test
+    fun `retry on error`() = runBlockingTest {
+        coEvery { testCertificateRepository.refresh() } throws UnknownHostException()
+
+        val result = createWorker().doWork()
+
+        coVerify(exactly = 1) { testCertificateRepository.refresh() }
+
+        result shouldBe ListenableWorker.Result.retry()
+    }
+
+    @Test
+    fun `failure after 2 retries`() = runBlockingTest {
+
+        val result = createWorker(runAttempts = 3).doWork()
+
+        coVerify(exactly = 0) { testCertificateRepository.refresh() }
+
+        result shouldBe ListenableWorker.Result.failure()
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/storage/PCRTestCertificateTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/storage/PCRTestCertificateTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1c1beb77369e5bf92735c86069d46e0149749884
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/storage/PCRTestCertificateTest.kt
@@ -0,0 +1,5 @@
+package de.rki.coronawarnapp.covidcertificate.storage
+
+import testhelpers.BaseTest
+
+class PCRTestCertificateTest : BaseTest()
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/storage/RATestCertificateTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/storage/RATestCertificateTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a954074ce438de9d12fe48d501495f099671e3a0
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/storage/RATestCertificateTest.kt
@@ -0,0 +1,5 @@
+package de.rki.coronawarnapp.covidcertificate.storage
+
+import testhelpers.BaseTest
+
+class RATestCertificateTest : BaseTest()
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/storage/TestCertificateStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/storage/TestCertificateStorageTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..449f154a80d0a3b24da537e9cc5f3158724878cc
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/storage/TestCertificateStorageTest.kt
@@ -0,0 +1,108 @@
+package de.rki.coronawarnapp.covidcertificate.storage
+
+import android.content.Context
+import androidx.core.content.edit
+import de.rki.coronawarnapp.coronatest.DaggerCoronaTestTestComponent
+import de.rki.coronawarnapp.covidcertificate.test.TestCertificateTestData
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateStorage
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.ContainerPostProcessor
+import de.rki.coronawarnapp.util.serialization.SerializationModule
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import testhelpers.extensions.toComparableJsonPretty
+import testhelpers.preferences.MockSharedPreferences
+import javax.inject.Inject
+
+@Suppress("MaxLineLength")
+class TestCertificateStorageTest : BaseTest() {
+    @MockK lateinit var context: Context
+    private lateinit var mockPreferences: MockSharedPreferences
+    @Inject lateinit var certificateTestData: TestCertificateTestData
+    @Inject lateinit var postProcessor: ContainerPostProcessor
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        DaggerCoronaTestTestComponent.factory().create().inject(this)
+
+        mockPreferences = MockSharedPreferences()
+
+        every {
+            context.getSharedPreferences("coronatest_certificate_localdata", Context.MODE_PRIVATE)
+        } returns mockPreferences
+    }
+
+    private fun createInstance() = TestCertificateStorage(
+        context = context,
+        baseGson = SerializationModule().baseGson(),
+        containerPostProcessor = postProcessor,
+    )
+
+    @Test
+    fun `init is sideeffect free`() {
+        createInstance()
+    }
+
+    @Test
+    fun `storing empty set deletes data`() {
+        mockPreferences.edit {
+            putString("dontdeleteme", "test")
+            putString("testcertificate.data.ra", "test")
+            putString("testcertificate.data.pcr", "test")
+        }
+        createInstance().testCertificates = emptySet()
+
+        mockPreferences.dataMapPeek.keys.single() shouldBe "dontdeleteme"
+    }
+
+    @Test
+    fun `store two containers, one for each type`() {
+        createInstance().testCertificates = setOf(
+            certificateTestData.personATest1StoredData,
+            certificateTestData.personATest2CertStoredData
+        )
+
+        (mockPreferences.dataMapPeek["testcertificate.data.pcr"] as String).toComparableJsonPretty() shouldBe """
+            [
+              {
+                "identifier": "identifier",
+                "registrationToken": "registrationToken",
+                "registeredAt": 12345,
+                "publicKeyRegisteredAt": 6789,
+                "rsaPublicKey": "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA2+WCCvy0SNqZMy/V1FYYMkBTGp/5BQt/NxUW1nIkj84u6duqNNQh4GjugoDc8epyl/yi3D61Jt7qArwk+eTcnW4/jEOexT5pCabRKrFm6IMndSefYrP3CeaD86ZU47uhnRuCG3TcPhIqUN2E37EbOsI9Z59JXc5tmmB71CxTF0bjE0PNLgbTU2snnsO6+oz/JLo7D2nw6E9yxSJ8JBjM5j+FC4sYLuO2nYi/BzAGZL/wsKrajg2hjA3f8r1cgst8HdzAJjMUG90pb3UG2K2KVRScbvF8pvRrzLCvJ/gqAGDXX/M00jr407vU8V4O2A9YdSavaC02iRFTNail65cbOW96p3ptjeejofj8l5PO5eBYWERla8NrlD9EcW93+aSmswn4w9iSSq+j38GMyhYulLcOlhKTeWumc5goDjcHyri48Ki70ddGzrxFxggaC/FqlCG85A6/43fVaWH/Wi2uPDPzaRGNQzXRy4LCuE/dvUzp8TlkpcT0QFy/Q4Ke0u1dAgMBAAE\u003d",
+                "rsaPrivateKey": "MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDb5YIK/LRI2pkzL9XUVhgyQFMan/kFC383FRbWciSPzi7p26o01CHgaO6CgNzx6nKX/KLcPrUm3uoCvCT55Nydbj+MQ57FPmkJptEqsWbogyd1J59is/cJ5oPzplTju6GdG4IbdNw+EipQ3YTfsRs6wj1nn0ldzm2aYHvULFMXRuMTQ80uBtNTayeew7r6jP8kujsPafDoT3LFInwkGMzmP4ULixgu47adiL8HMAZkv/CwqtqODaGMDd/yvVyCy3wd3MAmMxQb3SlvdQbYrYpVFJxu8Xym9GvMsK8n+CoAYNdf8zTSOvjTu9TxXg7YD1h1Jq9oLTaJEVM1qKXrlxs5b3qnem2N56Oh+PyXk87l4FhYRGVrw2uUP0Rxb3f5pKazCfjD2JJKr6PfwYzKFi6Utw6WEpN5a6ZzmCgONwfKuLjwqLvR10bOvEXGCBoL8WqUIbzkDr/jd9VpYf9aLa48M/NpEY1DNdHLgsK4T929TOnxOWSlxPRAXL9Dgp7S7V0CAwEAAQKCAYBaazDh2682FczQ42aFfTFN2G1TkVwP2v5gY+eUHjMyfpGDz7NZLbEQWZVZTCuNvd2I6XT+IzrR1O9cWIjLyHN+uIqg3l02tcbzFQkFCRVLnkJnRfef2mhGRecUFNzrF4gI1frV12OIkmecALpWULjlnGErbq/4Rp2C0RGZ2PABrkBI96QyvNPAhVsxSUJlK/zt2TXXzLQmkiSbMubg4OG/+3Z1nKhA/5ljhYsnJXQ7kUEjI93ic3Bt6naflYWosop/jUa1QksEMv0HL2if8PIBymgTGKmU79MeQOuBJN0ggrmttk41df+lPzWQY0EFnBC7Kf1AtbenllDm8zCoqldwu5OBTp8pZs7vFbOaRp1zBdtQS9OeTy22HvRU14CMwJ7HXOUC4RuVhXXeNLqLjLEkXJPRGvUem0Wq+ppBliDDoq9ljHiqvR/LgnaH0OqxM6o4fo1OgKvgVhJ1ItPeTdYxu2ikuJUNzwFf32feectjncXUf18wF1OExlwgVpvTinECgcEA7lnLCAdufw18Moe2VqudLmU2vUsJl1SR2nLlIYNfM7bHlbXqT/Ido2odKXX8WVDZi/ChV43OAw2PKUgcVPIxSGmEiDg8bj+K+v8hZ/VFbQAjnfD9+olikRbNmFMOued2IazfFv2ydbZADjPDMcfK1W3+7qcHT2LxigEWB8XNA5NDBaMYU+EN+tATOcG0QZr3fNPxfUT4m4TKOY00jhBdOhubfyF5pU5rQQCZvkVqVIffcq6J1x7Jh7CGLwQ53lQ7AoHBAOwt5N4/GY/pFiIE/V85MlJN37HfBhB8K29CEPzqOdHfICnYZ3dqNXtXIAQqVE0lG+49O5moQjU/dTAr39kJwzDydzJaFsCGsR/rzxo+Ishz2SrjJ8+97g8B6Oxgy9qwMs9X5A+EvrWw5Lb3woZDjaZ0pPl4yb7y5IEDlYnNM/9QcmHFP0IFK2h6S3Qmm0XjboeVe1POz0oPD3z+xYruCnKr1Vj/X5eiLIbt2hxWlVQ9N+tvufFusR+OdgsBhxijRwKBwQCvfaN0ZOxhVY91MOD6zV5sc48rLl2Ac370JRY5Z52n2NL4krlTZYOW9yFDjqBfLp0OYPyaF0lwjAI1NefOT4gjtbUkCqvLzLNKfKCfB0K3r5uJxY9qcM8G3pA/sB+ulxIuVzbmmaJU8vwUuN3mACGCpXtHQemq9MG8h3IuBOAe2sVFGEFoONLvMVaGdu1+RFgmK3KpdifJcarnVuU0GC5cA0mo//+ty6BCeuu34SoZ1PSbXpEUt5FQe5NAeM8WuFMCgcEAuaA0kqz7dU1YVPKhBZeZwnBsUYudY5WEOdSuL2oUeawpxlnMsGFsmX1Xr45pZZy2ACBmWJWTO/CdNXg2Xoo6vJzFLHD8EuOKETGwO8r8YZoT5I5WuwNnOKpinG5TqpTzyl0k5UGK9piKmnfOjuJHUb258E2MGyUijXf4ry72IEPlMozp9ATGIj6EUU0Kmvpu4+eL38nayDVgEfjX4CLJWWlOrL1CL5aJ8p6836r5gRUAf233shcy5T997ZaMzMN/AoHADfrS372Vuovx21p8txO2w+VFTEUoR80XGGdy30NrIdweY2bfz4XYpGSiyXE41TWzpNBfrSZNCyBXzvJ7d3dBXhlruFZi3Ji3IR+fe+KpEz4FTssKLEWm+gSmbGIjFxGe0nAIy77jCMYjqfOjoFdhksQN1On1tcq3Y3XauAc4L82wDU30rOgxWt8kdbblJKCSdOaYPXm/D+4c+8ROvlcxY4afl+FDcroHNMvD3jjZ1TMd1Bef1E0qFN/oJJU2Pc2/",
+                "certificateReceivedAt": 123456789,
+                "encryptedDataEncryptionkey": "ZW5jcnlwdGVkRGF0YUVuY3J5cHRpb25rZXk\u003d",
+                "testCertificateQrCode": "${certificateTestData.personATest1CertQRCodeString}"
+              }
+            ]
+        """.toComparableJsonPretty()
+
+        (mockPreferences.dataMapPeek["testcertificate.data.ra"] as String).toComparableJsonPretty() shouldBe """
+            [
+              {
+                "identifier": "identifier2",
+                "registrationToken": "registrationToken2",
+                "registeredAt": 12345,
+                "publicKeyRegisteredAt": 6789,
+                "rsaPublicKey": "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAnrJ8PbmbOmEEmHB/8yg1bnkUT7jcF4Xfy2Me5imJgLVYQ0cL9UNP91cfFUrgMFV3fHOc0Uuay10TmrBLaEdzqDEZQH4Kj0uZ+hVCtzntVKFviuUoh08wxFlogtc5Sy0NhuTGyC1W/i2AX1SDvet2xMcc1fE44rITQEEAlG8+nfGpbppFHezUOxuZjs9XBTxavDjQyWeFwMD30UAJGakPhOOOj6ihXA19OvQ/tYuYTJ5C9QzeK90C/rYbg2fn+os3EGlb7iJZ2V3KGrNLdMcEtkiG5IiHicaNCn8OS/cI3d29iJE4ECaF711fyF8MG1H2tbkjULS3bsPNUvyvHfM2cjOPRhejayOh+CxQkc3wKar8ApvQCjiVRW05nO0ufHdPMcWJhUlchWYO5mOJTSO8vG/9YqpnTuDc2Gelc4gMK7KATdH3v1FsACPKNJdpt68IfZXgGYn5LtJ7zJB6Yw8Rewj1SaF/wFKXpYd+5JyK18wJTLVYSpiDzidh4DP+R6ZTAgMBAAE\u003d",
+                "rsaPrivateKey": "MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQCesnw9uZs6YQSYcH/zKDVueRRPuNwXhd/LYx7mKYmAtVhDRwv1Q0/3Vx8VSuAwVXd8c5zRS5rLXROasEtoR3OoMRlAfgqPS5n6FUK3Oe1UoW+K5SiHTzDEWWiC1zlLLQ2G5MbILVb+LYBfVIO963bExxzV8TjishNAQQCUbz6d8alumkUd7NQ7G5mOz1cFPFq8ONDJZ4XAwPfRQAkZqQ+E446PqKFcDX069D+1i5hMnkL1DN4r3QL+thuDZ+f6izcQaVvuIlnZXcoas0t0xwS2SIbkiIeJxo0Kfw5L9wjd3b2IkTgQJoXvXV/IXwwbUfa1uSNQtLduw81S/K8d8zZyM49GF6NrI6H4LFCRzfApqvwCm9AKOJVFbTmc7S58d08xxYmFSVyFZg7mY4lNI7y8b/1iqmdO4NzYZ6VziAwrsoBN0fe/UWwAI8o0l2m3rwh9leAZifku0nvMkHpjDxF7CPVJoX/AUpelh37knIrXzAlMtVhKmIPOJ2HgM/5HplMCAwEAAQKCAYEAhw8Bu4pduFZfEdkUm31J0+YJyjtaXE6cAr0ty9Xn5vjuz/sEC0ypHqgvlPBvUdM66FiASoMcjxx8lbaZxnqgzLBUfFWIaSF/Pp2fdM5A1Di79CpIzrcvmrs4vbmrUfZav8WuAyjLE3DoArmrkRN2tct7F/y+W/gPeCyZ8LmoQcUsXCvAzNIEYPWBP0/oEFWoJu33iqCm7T+M6LGlzQfbZE5BwrNR+ESmomjCW6AdEn/SHjlAT3Y9mUakrbXdcJXPAI+RleS90kn8AHiQuyjotlb32xhBVw6SOtfd0xkMyY67AbCo9R1f0ir54PayA38xs4yQ0O2OgNUSLTWYXV1T/mSQSQMaxNw556IEXWVQWRWIc91QwOI2TD/N+vIxLPbNtuW5lEyMCzrmBdxq7wIOGIpy62B11TW6UYU26GOkhHTXEnn7pmHGVtbCXPGoKzncxxKNhRFuGOPcd+yQkM5eYAf7dad2NySrOokMQ2eIacPwKxKFfA/QN0v9aPLj7Qa5AoHBAOynNxSKErA25ndt/xBaLwSdzPynkE5zkO3gedgqvO6/6bAGOsRkawTNGalkVTwhXEnGBUIidPqhW7ex5/ad1QPUsWT8YeeYzXoM+Gqgu6M8awpFK4cwUMCrpRJwaUBFUCNzYNDZgJoOZAOX2TKvSNH+9zFrmGrKY0KRZ0aK9T0Ksbxn8KrErvXYj05nG4A3MrsKRA8mwBtZm0/17bBtg0nYH6/Omt787LBO/sxCicwTZioJlUgndzAIwTw7BtFDzwKBwQCrq8Wx/MK+LA+HUzDmdTK04sgIebulBSTV95aSsWoN+MoNwmi9wVt3OJfpq4L7g1NVv0vNSIajk9BDIFeKvgmDcde8RV51LRCObQ9enCOQUH7e0eC3XI9Nxg3nIhQiYJuggG6QAtt07bybx3dWpYEXL4ZOPOEkTVXR5JRkx9MWw8VDTbLKTCfZJ34PPF4AdCrs3yId9FXk9pUmS68oJVRsFhnI+dSdky32Bc01G6kk0SlGOudKLzqx4fbr0itHIj0CgcAHDWCd0xOFfs1VZ8i/EwDtsUoniVLKk7UQ8ayP3Y4tyzhKj5T2v0tVJEuMebn0hcX7SNRlSSOVSHO0QK/58HAlohP7P24nea094t8QRmPxFF7YOoF2kOEHLNZJe2IXkTk3JTwQXTrw3FbsqHzHfuO7pk51gZBUNl3I4Q5j0sZGIGh1hd9tJ1lTaDW1D2uJYZu4aTDoBq6Y4g23z0tbA5hy/ebL1WtWE9F125TKP31dwII95HU3Zj2uB8TCZ7vnRo8CgcBfeUiZlFk6Kob4W+v2P3fT4cwd6pXRUOsLlIbJTqIM4zB8NoLKBZ84zuCttBVEi+Ts61bc9Fjs4GgS7QnCv63KzKWOr4W45Tcv/rdthqjAugPVKCQx1ehc+KkCwpEwDUqAGO1kajJi9VTPzj8wkRsaKfQnzvPnnJr+AIIHCpr7LiWnKK8mkvQWcUBKeOhOmEzHL9Fpl1mt3PVWNwFS8m/hLOlqPIdim1gUW2WlA50uPKUXyeqX92xNQb5xqJEpHoECgcEAw4FGJb47FivG25fD+e61GxzG/KrzQL0eVS3T2YRAiN5ZB7QyInm6vMTi0QKCScCRJjOjRyoI3VtCO7G8vUnm0UiCW4l11WqW9G4vVh5VuR0HJ+kH1CQcq1aheqF7bbZGjjK47iyZskehfa6kcEOfThE6n6G7mIE/oe5k8A6+wHoLGmBbdxwE2xuG3PorH0PgbAgva1KAgC57rTBJhHnm6ntT21vlPLev9QvrE5syo+LEDbagr5zHMC14qAwMH2fi",
+                "certificateReceivedAt": 123456789,
+                "encryptedDataEncryptionkey": "ZW5jcnlwdGVkRGF0YUVuY3J5cHRpb25rZXk\u003d",
+                "testCertificateQrCode": "${certificateTestData.personATest2CertQRCodeString}"
+              }
+            ]
+        """.toComparableJsonPretty()
+
+        createInstance().testCertificates shouldBe setOf(
+            certificateTestData.personATest1StoredData,
+            certificateTestData.personATest2CertStoredData
+        )
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateRepositoryTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..75e7d3204b206d34ced87d863b56b867d7307535
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateRepositoryTest.kt
@@ -0,0 +1,79 @@
+package de.rki.coronawarnapp.covidcertificate.test
+
+import de.rki.coronawarnapp.appconfig.CovidCertificateConfig
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCode
+import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.PCRCertificateData
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.StoredTestCertificateData
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateProcessor
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateStorage
+import de.rki.coronawarnapp.covidcertificate.valueset.ValueSetsRepository
+import io.mockk.MockKAnnotations
+import io.mockk.coEvery
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.mockk
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.emptyFlow
+import org.joda.time.Duration
+import org.joda.time.Instant
+import org.junit.jupiter.api.BeforeEach
+import testhelpers.BaseTest
+import testhelpers.TestDispatcherProvider
+
+class TestCertificateRepositoryTest : BaseTest() {
+
+    @MockK lateinit var storage: TestCertificateStorage
+    @MockK lateinit var qrCodeExtractor: TestCertificateQRCodeExtractor
+    @MockK lateinit var covidTestCertificateConfig: CovidCertificateConfig.TestCertificate
+    @MockK lateinit var valueSetsRepository: ValueSetsRepository
+    @MockK lateinit var testCertificateProcessor: TestCertificateProcessor
+
+    private val testCertificateNew = PCRCertificateData(
+        identifier = "identifier1",
+        registrationToken = "regtoken1",
+        registeredAt = Instant.EPOCH,
+    )
+
+    private val testCertificateWithPubKey = testCertificateNew.copy(
+        publicKeyRegisteredAt = Instant.EPOCH,
+        rsaPublicKey = mockk(),
+        rsaPrivateKey = mockk(),
+    )
+
+    private var storageSet = mutableSetOf<StoredTestCertificateData>()
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        covidTestCertificateConfig.apply {
+            every { waitForRetry } returns Duration.standardSeconds(10)
+            every { waitAfterPublicKeyRegistration } returns Duration.standardSeconds(10)
+        }
+
+        storage.apply {
+            every { storage.testCertificates = any() } answers {
+                storageSet.clear()
+                storageSet.addAll(arg(0))
+            }
+            every { storage.testCertificates } answers { storageSet }
+        }
+
+        coEvery { qrCodeExtractor.extract(any(), any()) } returns mockk<TestCertificateQRCode>().apply {
+            every { qrCode } returns "qrCode"
+            every { data } returns mockk()
+        }
+        every { valueSetsRepository.latestTestCertificateValueSets } returns emptyFlow()
+    }
+
+    private fun createInstance(scope: CoroutineScope) = TestCertificateRepository(
+        appScope = scope,
+        dispatcherProvider = TestDispatcherProvider(),
+        storage = storage,
+        qrCodeExtractor = qrCodeExtractor,
+        valueSetsRepository = valueSetsRepository,
+        processor = testCertificateProcessor,
+    )
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateTestData.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateTestData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e6da753eb92a102b7916032147d183d729219e3d
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateTestData.kt
@@ -0,0 +1,105 @@
+package de.rki.coronawarnapp.covidcertificate.test
+
+import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.PCRCertificateData
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.RACertificateData
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateContainer
+import de.rki.coronawarnapp.util.encryption.rsa.RSAKey
+import okio.ByteString.Companion.decodeBase64
+import org.joda.time.Instant
+import javax.inject.Inject
+
+@Suppress("MaxLineLength")
+class TestCertificateTestData @Inject constructor(
+    qrCodeExtractor: TestCertificateQRCodeExtractor
+) {
+
+    val personATest1CertQRCodeString =
+        "HC1:6BFQ$9FY7$\$Q00019C-5HQ57WDQTLUMS256TUMP49JLZCX/N4VB14NRINX6J7+KF\$UB.N83CMMPVNPAHJ035FT88%AJ1R*UOGR3ZWLC24+F7DO276HB.O*BEVJODVSKNOP0T4\$FZ.R/03N6QK3A05EQVBONNHSJ9WJT+B15H NBEZ3VI8-V77AFL4NY9V*JM *KOPC2H8PR5OG9:VIG$969FJRV28N9PORZJQ43EOIHIJ+83XDDRB201N.L58EB7 8GS8. 9GPNGHFV/6\$I3R3R4930TC/ZGZESM929.D59GO13E\$H7LMUGS18ABF6YD955C C6VPNMZU+3FJR1RVLBZDR2F*8A4MKWIH+/JPU1*H6E2CTHGYHPPU6U*FYFJ6RJO*I8P1T59S:V3V1SA86L8Y8A5XB*10112G8GHK77CBOK9QEI960TTNC.I3A4P8BM6DO:MI/98PC/ZP2:JW3JB.J:R2.5GX0J$1J.OOCYSS8A*DS\$AFVJR9RT-L6N%PS%CV%B8KL0%EL SXLBSA6 %M6JEN+E0Q8A:RAGW16KGUA627-Y2:EDH\$VFVT:29FWUTJSANSYCV4PSKNP\$ZV-8T27SV4CC3CJIV20TKBS22O$/MT/V*0Q0IUE0DBPT+UP03IR1CRFOP3"
+
+    val personATest1StoredData = run {
+        val publicKey = RSAKey.Public(
+            "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA2+WCCvy0SNqZMy/V1FYYMkBTGp/5BQt/NxUW1nIkj84u6duqNNQh4GjugoDc8epyl/yi3D61Jt7qArwk+eTcnW4/jEOexT5pCabRKrFm6IMndSefYrP3CeaD86ZU47uhnRuCG3TcPhIqUN2E37EbOsI9Z59JXc5tmmB71CxTF0bjE0PNLgbTU2snnsO6+oz/JLo7D2nw6E9yxSJ8JBjM5j+FC4sYLuO2nYi/BzAGZL/wsKrajg2hjA3f8r1cgst8HdzAJjMUG90pb3UG2K2KVRScbvF8pvRrzLCvJ/gqAGDXX/M00jr407vU8V4O2A9YdSavaC02iRFTNail65cbOW96p3ptjeejofj8l5PO5eBYWERla8NrlD9EcW93+aSmswn4w9iSSq+j38GMyhYulLcOlhKTeWumc5goDjcHyri48Ki70ddGzrxFxggaC/FqlCG85A6/43fVaWH/Wi2uPDPzaRGNQzXRy4LCuE/dvUzp8TlkpcT0QFy/Q4Ke0u1dAgMBAAE\u003d".decodeBase64()!!
+        )
+        val privateKey = RSAKey.Private(
+            "MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDb5YIK/LRI2pkzL9XUVhgyQFMan/kFC383FRbWciSPzi7p26o01CHgaO6CgNzx6nKX/KLcPrUm3uoCvCT55Nydbj+MQ57FPmkJptEqsWbogyd1J59is/cJ5oPzplTju6GdG4IbdNw+EipQ3YTfsRs6wj1nn0ldzm2aYHvULFMXRuMTQ80uBtNTayeew7r6jP8kujsPafDoT3LFInwkGMzmP4ULixgu47adiL8HMAZkv/CwqtqODaGMDd/yvVyCy3wd3MAmMxQb3SlvdQbYrYpVFJxu8Xym9GvMsK8n+CoAYNdf8zTSOvjTu9TxXg7YD1h1Jq9oLTaJEVM1qKXrlxs5b3qnem2N56Oh+PyXk87l4FhYRGVrw2uUP0Rxb3f5pKazCfjD2JJKr6PfwYzKFi6Utw6WEpN5a6ZzmCgONwfKuLjwqLvR10bOvEXGCBoL8WqUIbzkDr/jd9VpYf9aLa48M/NpEY1DNdHLgsK4T929TOnxOWSlxPRAXL9Dgp7S7V0CAwEAAQKCAYBaazDh2682FczQ42aFfTFN2G1TkVwP2v5gY+eUHjMyfpGDz7NZLbEQWZVZTCuNvd2I6XT+IzrR1O9cWIjLyHN+uIqg3l02tcbzFQkFCRVLnkJnRfef2mhGRecUFNzrF4gI1frV12OIkmecALpWULjlnGErbq/4Rp2C0RGZ2PABrkBI96QyvNPAhVsxSUJlK/zt2TXXzLQmkiSbMubg4OG/+3Z1nKhA/5ljhYsnJXQ7kUEjI93ic3Bt6naflYWosop/jUa1QksEMv0HL2if8PIBymgTGKmU79MeQOuBJN0ggrmttk41df+lPzWQY0EFnBC7Kf1AtbenllDm8zCoqldwu5OBTp8pZs7vFbOaRp1zBdtQS9OeTy22HvRU14CMwJ7HXOUC4RuVhXXeNLqLjLEkXJPRGvUem0Wq+ppBliDDoq9ljHiqvR/LgnaH0OqxM6o4fo1OgKvgVhJ1ItPeTdYxu2ikuJUNzwFf32feectjncXUf18wF1OExlwgVpvTinECgcEA7lnLCAdufw18Moe2VqudLmU2vUsJl1SR2nLlIYNfM7bHlbXqT/Ido2odKXX8WVDZi/ChV43OAw2PKUgcVPIxSGmEiDg8bj+K+v8hZ/VFbQAjnfD9+olikRbNmFMOued2IazfFv2ydbZADjPDMcfK1W3+7qcHT2LxigEWB8XNA5NDBaMYU+EN+tATOcG0QZr3fNPxfUT4m4TKOY00jhBdOhubfyF5pU5rQQCZvkVqVIffcq6J1x7Jh7CGLwQ53lQ7AoHBAOwt5N4/GY/pFiIE/V85MlJN37HfBhB8K29CEPzqOdHfICnYZ3dqNXtXIAQqVE0lG+49O5moQjU/dTAr39kJwzDydzJaFsCGsR/rzxo+Ishz2SrjJ8+97g8B6Oxgy9qwMs9X5A+EvrWw5Lb3woZDjaZ0pPl4yb7y5IEDlYnNM/9QcmHFP0IFK2h6S3Qmm0XjboeVe1POz0oPD3z+xYruCnKr1Vj/X5eiLIbt2hxWlVQ9N+tvufFusR+OdgsBhxijRwKBwQCvfaN0ZOxhVY91MOD6zV5sc48rLl2Ac370JRY5Z52n2NL4krlTZYOW9yFDjqBfLp0OYPyaF0lwjAI1NefOT4gjtbUkCqvLzLNKfKCfB0K3r5uJxY9qcM8G3pA/sB+ulxIuVzbmmaJU8vwUuN3mACGCpXtHQemq9MG8h3IuBOAe2sVFGEFoONLvMVaGdu1+RFgmK3KpdifJcarnVuU0GC5cA0mo//+ty6BCeuu34SoZ1PSbXpEUt5FQe5NAeM8WuFMCgcEAuaA0kqz7dU1YVPKhBZeZwnBsUYudY5WEOdSuL2oUeawpxlnMsGFsmX1Xr45pZZy2ACBmWJWTO/CdNXg2Xoo6vJzFLHD8EuOKETGwO8r8YZoT5I5WuwNnOKpinG5TqpTzyl0k5UGK9piKmnfOjuJHUb258E2MGyUijXf4ry72IEPlMozp9ATGIj6EUU0Kmvpu4+eL38nayDVgEfjX4CLJWWlOrL1CL5aJ8p6836r5gRUAf233shcy5T997ZaMzMN/AoHADfrS372Vuovx21p8txO2w+VFTEUoR80XGGdy30NrIdweY2bfz4XYpGSiyXE41TWzpNBfrSZNCyBXzvJ7d3dBXhlruFZi3Ji3IR+fe+KpEz4FTssKLEWm+gSmbGIjFxGe0nAIy77jCMYjqfOjoFdhksQN1On1tcq3Y3XauAc4L82wDU30rOgxWt8kdbblJKCSdOaYPXm/D+4c+8ROvlcxY4afl+FDcroHNMvD3jjZ1TMd1Bef1E0qFN/oJJU2Pc2/".decodeBase64()!!
+        )
+        PCRCertificateData(
+            identifier = "identifier",
+            registrationToken = "registrationToken",
+            registeredAt = Instant.ofEpochMilli(12345),
+            publicKeyRegisteredAt = Instant.ofEpochMilli(6789),
+            rsaPublicKey = publicKey,
+            rsaPrivateKey = privateKey,
+            certificateReceivedAt = Instant.ofEpochMilli(123456789),
+            encryptedDataEncryptionkey = "ZW5jcnlwdGVkRGF0YUVuY3J5cHRpb25rZXk=".decodeBase64()!!,
+            testCertificateQrCode = personATest1CertQRCodeString,
+        )
+    }
+
+    val personATest1Container = TestCertificateContainer(
+        data = personATest1StoredData,
+        qrCodeExtractor = qrCodeExtractor,
+    )
+
+    val personATest2CertQRCodeString =
+        "HC1:6BFT$9W08+J2DO3L6COM9W\$B8MG9DIV*GZHTGBS46FQ5G+/N1D9K1LV-50OIETJPEU63TT MA5B-+B%95V72UUSRST4662Z8NME.249C1Y*5TIT+TI0QG*%9%VBYBOIZV7UNM%2A8P1N3+IDXN38BO%619B4D515FT*5CR4F:U8M/P-7T%TGX2CDDTB/5GR8:0I$ G*+N0-CIF51925USMI2WX4XKJA0G2XHP268P7ODSZYC4TKJOO:WQ437D:E78V-5UM4LGFBKZ80YIU 8%/GWAIM%KG/VIM2 M4BKP7NI/204CE9BSYP2JGI9GJGQUJ-UEYM7YAQR6E DHZ3-RM3:BQ3KRDMIV5.WVBJ8HT8DG7T GMJ47O2HSA+P6UFGUNIPCNOPFJIPWP8E 8BB0C08F 75N6UW20BA800 8LWN3D NV:U6XRDWF9FOQ1LT+L07BFUBZU37D8ZBP+FBKWO:X1ZK8.0V9-AX02UD5PP8K81+VO*.L4*DJRR7WPEL4G-LYCL+ 9\$TBHFNU0R%GD0/ESSOQH7PZD2 BJA3R74E4WG3W02B67EF8WZN7L0J2*3R5EG0VB7OM2I92W/UMJ7G1 FNSCF O 4W4VSO2DOJUF6I8%10-65UR/JJI3AN2EW-BLRVHQN77J"
+
+    val personATest2CertStoredData = run {
+        val publicKey = RSAKey.Public(
+            "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAnrJ8PbmbOmEEmHB/8yg1bnkUT7jcF4Xfy2Me5imJgLVYQ0cL9UNP91cfFUrgMFV3fHOc0Uuay10TmrBLaEdzqDEZQH4Kj0uZ+hVCtzntVKFviuUoh08wxFlogtc5Sy0NhuTGyC1W/i2AX1SDvet2xMcc1fE44rITQEEAlG8+nfGpbppFHezUOxuZjs9XBTxavDjQyWeFwMD30UAJGakPhOOOj6ihXA19OvQ/tYuYTJ5C9QzeK90C/rYbg2fn+os3EGlb7iJZ2V3KGrNLdMcEtkiG5IiHicaNCn8OS/cI3d29iJE4ECaF711fyF8MG1H2tbkjULS3bsPNUvyvHfM2cjOPRhejayOh+CxQkc3wKar8ApvQCjiVRW05nO0ufHdPMcWJhUlchWYO5mOJTSO8vG/9YqpnTuDc2Gelc4gMK7KATdH3v1FsACPKNJdpt68IfZXgGYn5LtJ7zJB6Yw8Rewj1SaF/wFKXpYd+5JyK18wJTLVYSpiDzidh4DP+R6ZTAgMBAAE\u003d".decodeBase64()!!
+        )
+        val privateKey = RSAKey.Private(
+            "MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQCesnw9uZs6YQSYcH/zKDVueRRPuNwXhd/LYx7mKYmAtVhDRwv1Q0/3Vx8VSuAwVXd8c5zRS5rLXROasEtoR3OoMRlAfgqPS5n6FUK3Oe1UoW+K5SiHTzDEWWiC1zlLLQ2G5MbILVb+LYBfVIO963bExxzV8TjishNAQQCUbz6d8alumkUd7NQ7G5mOz1cFPFq8ONDJZ4XAwPfRQAkZqQ+E446PqKFcDX069D+1i5hMnkL1DN4r3QL+thuDZ+f6izcQaVvuIlnZXcoas0t0xwS2SIbkiIeJxo0Kfw5L9wjd3b2IkTgQJoXvXV/IXwwbUfa1uSNQtLduw81S/K8d8zZyM49GF6NrI6H4LFCRzfApqvwCm9AKOJVFbTmc7S58d08xxYmFSVyFZg7mY4lNI7y8b/1iqmdO4NzYZ6VziAwrsoBN0fe/UWwAI8o0l2m3rwh9leAZifku0nvMkHpjDxF7CPVJoX/AUpelh37knIrXzAlMtVhKmIPOJ2HgM/5HplMCAwEAAQKCAYEAhw8Bu4pduFZfEdkUm31J0+YJyjtaXE6cAr0ty9Xn5vjuz/sEC0ypHqgvlPBvUdM66FiASoMcjxx8lbaZxnqgzLBUfFWIaSF/Pp2fdM5A1Di79CpIzrcvmrs4vbmrUfZav8WuAyjLE3DoArmrkRN2tct7F/y+W/gPeCyZ8LmoQcUsXCvAzNIEYPWBP0/oEFWoJu33iqCm7T+M6LGlzQfbZE5BwrNR+ESmomjCW6AdEn/SHjlAT3Y9mUakrbXdcJXPAI+RleS90kn8AHiQuyjotlb32xhBVw6SOtfd0xkMyY67AbCo9R1f0ir54PayA38xs4yQ0O2OgNUSLTWYXV1T/mSQSQMaxNw556IEXWVQWRWIc91QwOI2TD/N+vIxLPbNtuW5lEyMCzrmBdxq7wIOGIpy62B11TW6UYU26GOkhHTXEnn7pmHGVtbCXPGoKzncxxKNhRFuGOPcd+yQkM5eYAf7dad2NySrOokMQ2eIacPwKxKFfA/QN0v9aPLj7Qa5AoHBAOynNxSKErA25ndt/xBaLwSdzPynkE5zkO3gedgqvO6/6bAGOsRkawTNGalkVTwhXEnGBUIidPqhW7ex5/ad1QPUsWT8YeeYzXoM+Gqgu6M8awpFK4cwUMCrpRJwaUBFUCNzYNDZgJoOZAOX2TKvSNH+9zFrmGrKY0KRZ0aK9T0Ksbxn8KrErvXYj05nG4A3MrsKRA8mwBtZm0/17bBtg0nYH6/Omt787LBO/sxCicwTZioJlUgndzAIwTw7BtFDzwKBwQCrq8Wx/MK+LA+HUzDmdTK04sgIebulBSTV95aSsWoN+MoNwmi9wVt3OJfpq4L7g1NVv0vNSIajk9BDIFeKvgmDcde8RV51LRCObQ9enCOQUH7e0eC3XI9Nxg3nIhQiYJuggG6QAtt07bybx3dWpYEXL4ZOPOEkTVXR5JRkx9MWw8VDTbLKTCfZJ34PPF4AdCrs3yId9FXk9pUmS68oJVRsFhnI+dSdky32Bc01G6kk0SlGOudKLzqx4fbr0itHIj0CgcAHDWCd0xOFfs1VZ8i/EwDtsUoniVLKk7UQ8ayP3Y4tyzhKj5T2v0tVJEuMebn0hcX7SNRlSSOVSHO0QK/58HAlohP7P24nea094t8QRmPxFF7YOoF2kOEHLNZJe2IXkTk3JTwQXTrw3FbsqHzHfuO7pk51gZBUNl3I4Q5j0sZGIGh1hd9tJ1lTaDW1D2uJYZu4aTDoBq6Y4g23z0tbA5hy/ebL1WtWE9F125TKP31dwII95HU3Zj2uB8TCZ7vnRo8CgcBfeUiZlFk6Kob4W+v2P3fT4cwd6pXRUOsLlIbJTqIM4zB8NoLKBZ84zuCttBVEi+Ts61bc9Fjs4GgS7QnCv63KzKWOr4W45Tcv/rdthqjAugPVKCQx1ehc+KkCwpEwDUqAGO1kajJi9VTPzj8wkRsaKfQnzvPnnJr+AIIHCpr7LiWnKK8mkvQWcUBKeOhOmEzHL9Fpl1mt3PVWNwFS8m/hLOlqPIdim1gUW2WlA50uPKUXyeqX92xNQb5xqJEpHoECgcEAw4FGJb47FivG25fD+e61GxzG/KrzQL0eVS3T2YRAiN5ZB7QyInm6vMTi0QKCScCRJjOjRyoI3VtCO7G8vUnm0UiCW4l11WqW9G4vVh5VuR0HJ+kH1CQcq1aheqF7bbZGjjK47iyZskehfa6kcEOfThE6n6G7mIE/oe5k8A6+wHoLGmBbdxwE2xuG3PorH0PgbAgva1KAgC57rTBJhHnm6ntT21vlPLev9QvrE5syo+LEDbagr5zHMC14qAwMH2fi".decodeBase64()!!
+        )
+        RACertificateData(
+            identifier = "identifier2",
+            registrationToken = "registrationToken2",
+            registeredAt = Instant.ofEpochMilli(12345),
+            publicKeyRegisteredAt = Instant.ofEpochMilli(6789),
+            rsaPublicKey = publicKey,
+            rsaPrivateKey = privateKey,
+            certificateReceivedAt = Instant.ofEpochMilli(123456789),
+            encryptedDataEncryptionkey = "ZW5jcnlwdGVkRGF0YUVuY3J5cHRpb25rZXk=".decodeBase64()!!,
+            testCertificateQrCode = personATest2CertQRCodeString
+        )
+    }
+
+    val personATest2CertContainer = TestCertificateContainer(
+        data = personATest2CertStoredData,
+        qrCodeExtractor = qrCodeExtractor,
+    )
+
+    val personATest3CertNokeyStoredData = run {
+        RACertificateData(
+            identifier = "identifier2",
+            registrationToken = "registrationToken2",
+            registeredAt = Instant.ofEpochMilli(12345),
+        )
+    }
+    val personATest3CertNokeyContainer = TestCertificateContainer(
+        data = personATest3CertNokeyStoredData,
+        qrCodeExtractor = qrCodeExtractor,
+    )
+    val personATest4CertPendingStoredData = run {
+        val publicKey = RSAKey.Public(
+            "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAnrJ8PbmbOmEEmHB/8yg1bnkUT7jcF4Xfy2Me5imJgLVYQ0cL9UNP91cfFUrgMFV3fHOc0Uuay10TmrBLaEdzqDEZQH4Kj0uZ+hVCtzntVKFviuUoh08wxFlogtc5Sy0NhuTGyC1W/i2AX1SDvet2xMcc1fE44rITQEEAlG8+nfGpbppFHezUOxuZjs9XBTxavDjQyWeFwMD30UAJGakPhOOOj6ihXA19OvQ/tYuYTJ5C9QzeK90C/rYbg2fn+os3EGlb7iJZ2V3KGrNLdMcEtkiG5IiHicaNCn8OS/cI3d29iJE4ECaF711fyF8MG1H2tbkjULS3bsPNUvyvHfM2cjOPRhejayOh+CxQkc3wKar8ApvQCjiVRW05nO0ufHdPMcWJhUlchWYO5mOJTSO8vG/9YqpnTuDc2Gelc4gMK7KATdH3v1FsACPKNJdpt68IfZXgGYn5LtJ7zJB6Yw8Rewj1SaF/wFKXpYd+5JyK18wJTLVYSpiDzidh4DP+R6ZTAgMBAAE\u003d".decodeBase64()!!
+        )
+        val privateKey = RSAKey.Private(
+            "MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQCesnw9uZs6YQSYcH/zKDVueRRPuNwXhd/LYx7mKYmAtVhDRwv1Q0/3Vx8VSuAwVXd8c5zRS5rLXROasEtoR3OoMRlAfgqPS5n6FUK3Oe1UoW+K5SiHTzDEWWiC1zlLLQ2G5MbILVb+LYBfVIO963bExxzV8TjishNAQQCUbz6d8alumkUd7NQ7G5mOz1cFPFq8ONDJZ4XAwPfRQAkZqQ+E446PqKFcDX069D+1i5hMnkL1DN4r3QL+thuDZ+f6izcQaVvuIlnZXcoas0t0xwS2SIbkiIeJxo0Kfw5L9wjd3b2IkTgQJoXvXV/IXwwbUfa1uSNQtLduw81S/K8d8zZyM49GF6NrI6H4LFCRzfApqvwCm9AKOJVFbTmc7S58d08xxYmFSVyFZg7mY4lNI7y8b/1iqmdO4NzYZ6VziAwrsoBN0fe/UWwAI8o0l2m3rwh9leAZifku0nvMkHpjDxF7CPVJoX/AUpelh37knIrXzAlMtVhKmIPOJ2HgM/5HplMCAwEAAQKCAYEAhw8Bu4pduFZfEdkUm31J0+YJyjtaXE6cAr0ty9Xn5vjuz/sEC0ypHqgvlPBvUdM66FiASoMcjxx8lbaZxnqgzLBUfFWIaSF/Pp2fdM5A1Di79CpIzrcvmrs4vbmrUfZav8WuAyjLE3DoArmrkRN2tct7F/y+W/gPeCyZ8LmoQcUsXCvAzNIEYPWBP0/oEFWoJu33iqCm7T+M6LGlzQfbZE5BwrNR+ESmomjCW6AdEn/SHjlAT3Y9mUakrbXdcJXPAI+RleS90kn8AHiQuyjotlb32xhBVw6SOtfd0xkMyY67AbCo9R1f0ir54PayA38xs4yQ0O2OgNUSLTWYXV1T/mSQSQMaxNw556IEXWVQWRWIc91QwOI2TD/N+vIxLPbNtuW5lEyMCzrmBdxq7wIOGIpy62B11TW6UYU26GOkhHTXEnn7pmHGVtbCXPGoKzncxxKNhRFuGOPcd+yQkM5eYAf7dad2NySrOokMQ2eIacPwKxKFfA/QN0v9aPLj7Qa5AoHBAOynNxSKErA25ndt/xBaLwSdzPynkE5zkO3gedgqvO6/6bAGOsRkawTNGalkVTwhXEnGBUIidPqhW7ex5/ad1QPUsWT8YeeYzXoM+Gqgu6M8awpFK4cwUMCrpRJwaUBFUCNzYNDZgJoOZAOX2TKvSNH+9zFrmGrKY0KRZ0aK9T0Ksbxn8KrErvXYj05nG4A3MrsKRA8mwBtZm0/17bBtg0nYH6/Omt787LBO/sxCicwTZioJlUgndzAIwTw7BtFDzwKBwQCrq8Wx/MK+LA+HUzDmdTK04sgIebulBSTV95aSsWoN+MoNwmi9wVt3OJfpq4L7g1NVv0vNSIajk9BDIFeKvgmDcde8RV51LRCObQ9enCOQUH7e0eC3XI9Nxg3nIhQiYJuggG6QAtt07bybx3dWpYEXL4ZOPOEkTVXR5JRkx9MWw8VDTbLKTCfZJ34PPF4AdCrs3yId9FXk9pUmS68oJVRsFhnI+dSdky32Bc01G6kk0SlGOudKLzqx4fbr0itHIj0CgcAHDWCd0xOFfs1VZ8i/EwDtsUoniVLKk7UQ8ayP3Y4tyzhKj5T2v0tVJEuMebn0hcX7SNRlSSOVSHO0QK/58HAlohP7P24nea094t8QRmPxFF7YOoF2kOEHLNZJe2IXkTk3JTwQXTrw3FbsqHzHfuO7pk51gZBUNl3I4Q5j0sZGIGh1hd9tJ1lTaDW1D2uJYZu4aTDoBq6Y4g23z0tbA5hy/ebL1WtWE9F125TKP31dwII95HU3Zj2uB8TCZ7vnRo8CgcBfeUiZlFk6Kob4W+v2P3fT4cwd6pXRUOsLlIbJTqIM4zB8NoLKBZ84zuCttBVEi+Ts61bc9Fjs4GgS7QnCv63KzKWOr4W45Tcv/rdthqjAugPVKCQx1ehc+KkCwpEwDUqAGO1kajJi9VTPzj8wkRsaKfQnzvPnnJr+AIIHCpr7LiWnKK8mkvQWcUBKeOhOmEzHL9Fpl1mt3PVWNwFS8m/hLOlqPIdim1gUW2WlA50uPKUXyeqX92xNQb5xqJEpHoECgcEAw4FGJb47FivG25fD+e61GxzG/KrzQL0eVS3T2YRAiN5ZB7QyInm6vMTi0QKCScCRJjOjRyoI3VtCO7G8vUnm0UiCW4l11WqW9G4vVh5VuR0HJ+kH1CQcq1aheqF7bbZGjjK47iyZskehfa6kcEOfThE6n6G7mIE/oe5k8A6+wHoLGmBbdxwE2xuG3PorH0PgbAgva1KAgC57rTBJhHnm6ntT21vlPLev9QvrE5syo+LEDbagr5zHMC14qAwMH2fi".decodeBase64()!!
+        )
+        RACertificateData(
+            identifier = "identifier2",
+            registrationToken = "registrationToken2",
+            registeredAt = Instant.ofEpochMilli(12345),
+            publicKeyRegisteredAt = Instant.ofEpochMilli(6789),
+            rsaPublicKey = publicKey,
+            rsaPrivateKey = privateKey,
+        )
+    }
+
+    val personATest4CertPendingContainer = TestCertificateContainer(
+        data = personATest4CertPendingStoredData,
+        qrCodeExtractor = qrCodeExtractor,
+    )
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestData.java b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestData.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1cab7986ed9589691167a7a27bdc82652826277
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestData.java
@@ -0,0 +1,22 @@
+package de.rki.coronawarnapp.covidcertificate.test;
+
+public class TestData {
+
+    static public class EllenCheng {
+        public String dek = "/9o5eVNb9us5CsGD4F3J36Ju1enJ71Y6+FpVvScGWkE=";
+        public String coseWithDecryptedPayload = "0oRNogEmBEiLxYhcyl5BXkBZAWGkAWtjd2EtYXBwLWNsaQQaYpdzwAYaYLZAQDkBA6EBpGN2ZXJlMS4wLjBjbmFtpGJnbmVFbGxlbmJmbmVDaGVuZ2NnbnRlRUxMRU5jZm50ZUNIRU5HY2RvYmoxOTY3LTA3LTE5YXSBq2J0Z2k4NDA1MzkwMDZidHRqTFAyMTcxOTgtM2JubXgZSVZDSUoxR1FaTTc4NzhFTE1VSU1BMDhER2JtYWQxMjQ0YnNjeBgyMDIxLTA1LTMxVDE2OjEzOjE2LjgzNlpiZHJ4GDIwMjEtMDYtMDFUMTQ6MTI6MTYuODM2WmJ0cmkyNjA0MTUwMDBidGNtVGVzdCBDZW50cmUgMWJjb2JERWJpc3ghQnVuZGVzbWluaXN0ZXJpdW0gZsO8ciBHZXN1bmRoZWl0YmNpeC8wMURFLzAwMDAwLzExMTkzNDkwMDcvRzdQU0JBWE1YVkEyTjBITTNVOFlWN1pNVFhA1NqKSb93S2El9dA0icVjK+DV4LbwVWajZmTmhqcsgzWhvl4/PmtAJ5/iT57FfoQvuOvlyhxRPgGSg33IuDnBCg==";
+        public String coseWithEncryptedPayload = "0oRNogEmBEiLxYhcyl5BXkBZAXBxvo73+06cLc73F5KIFuQdo7fLUnb7yF9QFtX9tIEmgSzHIXKbHcEiep5RTtb2UVS80vybmnwYa1k36HR2R2yTKGwvDWAUumw2ZjCnfp8CxKx3zQVRl6JrVdLiskWmo4qiK/EwyTHrw/5PZy4rd11vt9Y6wuZtlpOvFGDIDhGKpcgK93zfIQWY59xjxusr/4J3FCWpcy9YNehB6m4Az1NozXxOrL9DmFM38mWCkiHaPeWgedbqfKTg3x/vSrXSkXYnLpc6QHsRqW99r7yTXJffbK8X44KvgkUI9sIlVU5+2+IuwT4XBY2p/MLW4d9gfnAhZYTsn0nGuoj4KFHTo6fNkXsuZ6BWm5MurXR0dqiCd00B1ZKuTNV0QhdzaaB2pYtwBnxD65TW8D0VDrDDjZuYRzni032f5hgB7YDlvcWYWiv7o6T8DeCNAsJ0RdL/X1qe3bHvLOBvzF9XlTrg4vNF/3aeRn9libOf+0ufr5dEcVhA1NqKSb93S2El9dA0icVjK+DV4LbwVWajZmTmhqcsgzWhvl4/PmtAJ5/iT57FfoQvuOvlyhxRPgGSg33IuDnBCg==";
+    }
+
+    static public class BrianCalamandrei {
+        public String dek = "RinMlpTdzQGw7kllamU9Pz6bTHEWVZi1Ocb4q8wfFSk=";
+        public String coseWithEncryptedPayload = "0oRNogEmBEiLxYhcyl5BXkBZAXAN4hKvLEngs3MYcLe/cIyy0q0+0auk5A/Bme/WlymolXU8JSLJJcj3D7kwXCJoEOvsnU9P/IrVlTNF2fJBdWF6Oq22UzhyOPRuQiF7PvspbVzyeEo+H/PmtvbTZss6l/wLDoXPixjtCOaFn7Com6Z2pNQOZqkYGZzz4BanJfchoggM4HaH20H4AzANfMMqYa/rytHnz4BjlR82ZSOlg5e/Jbl78NRen6RkgLTwT3YSI1XV+gbLPK6Fhp5saqRmQgUQTTSO99Q/rdk6BG18RZxqw70zKb77ddxBzolgySbmRdUrpWdK9SvnsnivN3V1Auv5X18KpHO58SwyFoex7OUq73q6FAS9p+MdI2jh1e3LcwU12ZJaN56bRbTEAmT5MelZsYY+c6WWvcIND7tj3aDI5o8D9PyWZHPdz/uHn/Cesn7MgVEXvLQnfCVvuPkLDSGAGi47nRRmUoaN7+7GjPRYvTyrX5VWwnMK31QLADg9kFhAQ7d9IZ02KQ5OXt/fc3bpcombylOcXT2U+JXDwQadrFwHQdjeK1dw+RZM7UkD4l/TOQjO9B8JN13DlidhiqljGw==";
+        public String coseWithDecryptedPayload = "kzriyBRYZu5L/VqCz6qsomYv8vjOdjXp/giOGRa8vpXBM7Mjc3mjGaSUpHy8QLlCrFfrDAh8vwY4PKsI/ad/jFyEpyZwI13R6PW+Vft1Ld1nxHD74BwiNbhNv1ZjlmDohQsHXaq6MEbfNfT/uqPbZHToZlTPO3V9aeOD0E+kuMx8npVIbB+zbL48AS3VsrVyYthINdpplYmNsXyFdxsCvZfefGO3G5XIRsDfMBqFPVZO3uCIq1nLb4U8dcbZ5O2yrMG5UOJ2fiwWiiqSLevyCnlYjOvyv8Ot6nM1X7fncXwze3i4OT7Y/Y+36SAds/bCcpypOso0QIim8BBVecy3MN7bQOivc/DKyRX9dHHtc5iD/dgT5i5HBwFEcvTqAa/rlJyTSO4XL6CRevHD7lt3wdd/guRMWxilY1kgjao1w/KEum48frD/FD+J2IgFX+R9aP0CLqvvwvC8OuIj8O+F1WlGp55gKEd+Ps35o1Y8UfHyKDTUMVN5yZno6V15bVFP";
+    }
+
+    public static String qrCodeTestCertificate = "HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH+VEIOOP-IARC$E08WAN$6%W0AT4V22F/8X*G3M9BM9Z0BFU2P4JY73JC3KD34LT7A3523*BBXSJ$IJGX8R/S+:KLD3JJ3.+IJYCDN0TA3RK37MBZD3K%I17JLXKB6J57TJK57ALD-I3 28XGL4LQ/SLE50$499TVU1PK9PYLPN1VUU8C1VTE5ZM376 IE2IML07Z ESF6C.M1EE*2NY*6UJE4:6Q56FPEXM6IS6-Q64Y6N$E.%66PP33M19V2+PFQ51C5EWAC1A.GUQ$9WC54FQ68ENV0XTCM*4CZKHKB-43.E3KD3OAJA70:ZH/O1:O1AT1NQ1 WUQRENS431TN$IK.G47HB%0WT072HFHN/SNP.0FVV/SN7Y431TCRV$.PTW5CL52U50$EZ*N4IU4FKCPACPI2YUFJ6LX3+KG% BTVB3UQFJ6GL28LHXOAYJAUVPQRHIY1* HOQ1PRAAUICO1 IGBY05*H%XGU-PNQCSJ1A+3HJ5VBQR6G/:DS3GH9FW-SAOPNRFBYMBPJEODEN6%99SLNS9KKFC$OKT1GVKJTCW.IIX2S3V0$1D243B/J.H1RJVN01HI7T.H";
+
+    public static String cborObject = "a4041a60bc9f38061a60b9fc3801624154390103a101a4617481a962736374323032312d30322d32305431323a33343a35365a626d6164313233326274746a4c503231373139382d336274637754657374696e672063656e746572205669656e6e61203162636f624154626369783155524e3a555643493a30313a41543a37314545323535394445333843364246373330344642363541314134353145432333626973781b4d696e6973747279206f66204865616c74682c20417573747269616274676938343035333930303662747269323630343135303030636e616da463666e74754d5553544552465241553c474f455353494e47455262666e754d7573746572667261752d47c3b6c39f696e67657263676e74684741425249454c4562676e684761627269656c656376657265312e322e3163646f626a313939382d30322d3236";
+
+    public static String qrCodeMssingValues = "HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH0 MIOO6+IRKULA7GJLH1WU9T+QI6M8SA3/-2E%5TR5RVBFVAPUB1VCSWC%PDGZKBTC$JC6VCQVD. CL%2VTAQPIAK2K.C*/C/QDEZI8NBMZIVZJ4RLUTIT0KXRS*IJCSIYYKN63QR35VA2TBQMISVBYIJ33M+ZJ::A4O2OVPX0QON9Y46PK9$-0BZIKYJGCC:H3J1D1I3-*TW CXBDW33::SGKD2YC29DHSTY5TMGSR.CK.C2YC6YCBKDZJC9VC..DAVC55MVIJGDB0D48UJ06J9UBSVAXCIF4LEIIPBJ7OICWK%5BBS22T9PF5RBQ746B46O1N646BQ99Q9O$B ZJY1B QTOD3CQSP$SR$S3NDC9UOD3Y.TJET9G3DZI65BDM1F0J*XI-XIFRLL:F*ZR/MV$CT:Z2 /KU%CW.4WV2L4L$XKV7J$%25I3IC33835AL5:4A930JBB8G0 O4POY.6/IIYTE5NJJD2E9O%Q5G9WARD:QFMUU9K79LG-H9%K5.6MRXPDW5V$3/UR83LIBF2IVO7GXD9R$OB9MXUNTIDX 6-Z1YCN+VDKS0F5UV/H";
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateDccParserTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateDccParserTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f9f50f5c6da1cda8b97095a696dcd1055dc7515c
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateDccParserTest.kt
@@ -0,0 +1,44 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.qrcode
+
+import com.google.gson.Gson
+import com.upokecenter.cbor.CBORObject
+import de.rki.coronawarnapp.covidcertificate.test.TestData
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccParser
+import io.kotest.matchers.shouldBe
+import okio.ByteString.Companion.decodeHex
+import org.joda.time.LocalDate
+import org.junit.jupiter.api.Test
+
+class TestCertificateDccParserTest {
+
+    private val bodyParser = TestDccParser(Gson())
+
+    @Test
+    fun `happy path cose decryption with Ellen Cheng`() {
+        val coseObject = CBORObject.DecodeFromBytes(TestData.cborObject.decodeHex().toByteArray())
+        with(bodyParser.parse(coseObject)) {
+
+            with(nameData) {
+                familyName shouldBe "Musterfrau-Gößinger"
+                familyNameStandardized shouldBe "MUSTERFRAU<GOESSINGER"
+                givenName shouldBe "Gabriele"
+                givenNameStandardized shouldBe "GABRIELE"
+            }
+            dob shouldBe "1998-02-26"
+            dateOfBirth shouldBe LocalDate.parse("1998-02-26")
+            version shouldBe "1.2.1"
+
+            with(payloads[0]) {
+                uniqueCertificateIdentifier shouldBe "URN:UVCI:01:AT:71EE2559DE38C6BF7304FB65A1A451EC#3"
+                certificateCountry shouldBe "AT"
+                certificateIssuer shouldBe "Ministry of Health, Austria"
+                targetId shouldBe "840539006"
+                sampleCollectedAt shouldBe org.joda.time.Instant.parse("2021-02-20T12:34:56+00:00")
+                testType shouldBe "LP217198-3"
+                testCenter shouldBe "Testing center Vienna 1"
+                testNameAndManufactor shouldBe "1232"
+                testResult shouldBe "260415000"
+            }
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractorTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..39226fcec68b6fdf0526183fc6aba5a6b1cf5a75
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractorTest.kt
@@ -0,0 +1,130 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.qrcode
+
+import com.google.gson.Gson
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccCoseDecoder
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccHeaderParser
+import de.rki.coronawarnapp.covidcertificate.cryptography.AesCryptography
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidTestCertificateException
+import de.rki.coronawarnapp.covidcertificate.test.TestData
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccParser
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationQrCodeTestData
+import io.kotest.assertions.throwables.shouldThrow
+import io.kotest.matchers.shouldBe
+import okio.ByteString.Companion.decodeBase64
+import org.joda.time.Instant
+import org.joda.time.LocalDate
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class TestCertificateQRCodeExtractorTest : BaseTest() {
+    private val coseDecoder = DccCoseDecoder(AesCryptography())
+    private val headerParser = DccHeaderParser()
+    private val bodyParser = TestDccParser(Gson())
+    private val extractor = TestCertificateQRCodeExtractor(coseDecoder, headerParser, bodyParser)
+
+    @Test
+    fun `happy path qr code`() {
+        val qrCode = extractor.extract(TestData.qrCodeTestCertificate)
+        with(qrCode.data.header) {
+            issuer shouldBe "AT"
+            issuedAt shouldBe Instant.parse("2021-06-01T10:12:48.000Z")
+            expiresAt shouldBe Instant.parse("2021-06-03T10:12:48.000Z")
+        }
+
+        with(qrCode.data.certificate) {
+            with(nameData) {
+                familyName shouldBe "Musterfrau-Gößinger"
+                familyNameStandardized shouldBe "MUSTERFRAU<GOESSINGER"
+                givenName shouldBe "Gabriele"
+                givenNameStandardized shouldBe "GABRIELE"
+            }
+            dob shouldBe "1998-02-26"
+            dateOfBirth shouldBe LocalDate.parse("1998-02-26")
+            version shouldBe "1.2.1"
+
+            with(payloads[0]) {
+                uniqueCertificateIdentifier shouldBe "URN:UVCI:01:AT:71EE2559DE38C6BF7304FB65A1A451EC#3"
+                certificateCountry shouldBe "AT"
+                certificateIssuer shouldBe "Ministry of Health, Austria"
+                targetId shouldBe "840539006"
+                sampleCollectedAt shouldBe Instant.parse("2021-02-20T12:34:56+00:00")
+                testType shouldBe "LP217198-3"
+                testCenter shouldBe "Testing center Vienna 1"
+                testNameAndManufactor shouldBe "1232"
+                testResult shouldBe "260415000"
+            }
+        }
+    }
+
+    @Test
+    fun `happy path cose decryption with Ellen Cheng`() {
+        with(TestData.EllenCheng()) {
+            val coseObject = coseWithEncryptedPayload.decodeBase64()!!.toByteArray()
+            val dek = dek.decodeBase64()!!.toByteArray()
+            val result = extractor.extract(dek, coseObject)
+            with(result.data.certificate.nameData) {
+                familyName shouldBe "Cheng"
+                givenName shouldBe "Ellen"
+            }
+            val result2 = extractor.extract(result.qrCode)
+            with(result2.data.certificate.nameData) {
+                familyName shouldBe "Cheng"
+                givenName shouldBe "Ellen"
+            }
+        }
+    }
+
+    @Test
+    fun `happy path cose decryption with Brian Calamandrei`() {
+        with(TestData.BrianCalamandrei()) {
+            val coseObject = coseWithEncryptedPayload.decodeBase64()!!.toByteArray()
+            val dek = dek.decodeBase64()!!.toByteArray()
+            val result = extractor.extract(dek, coseObject)
+            with(result.data.certificate.nameData) {
+                familyName shouldBe "Calamandrei"
+                givenName shouldBe "Brian"
+            }
+            val result2 = extractor.extract(result.qrCode)
+            with(result2.data.certificate.nameData) {
+                familyName shouldBe "Calamandrei"
+                givenName shouldBe "Brian"
+            }
+        }
+    }
+
+    @Test
+    fun `valid encoding but not a health certificate fails with HC_CWT_NO_ISS`() {
+        shouldThrow<InvalidTestCertificateException> {
+            extractor.extract(VaccinationQrCodeTestData.validEncoded)
+        }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_ISS
+    }
+
+    @Test
+    fun `random string fails with HC_BASE45_DECODING_FAILED`() {
+        shouldThrow<InvalidTestCertificateException> {
+            extractor.extract("nothing here to see")
+        }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED
+    }
+
+    @Test
+    fun `uncompressed base45 string fails with HC_ZLIB_DECOMPRESSION_FAILED`() {
+        shouldThrow<InvalidTestCertificateException> {
+            extractor.extract("6BFOABCDEFGHIJKLMNOPQRSTUVWXYZ %*+-./:")
+        }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED
+    }
+
+    @Test
+    fun `vaccination certificate fails with NO_TEST_ENTRY`() {
+        shouldThrow<InvalidTestCertificateException> {
+            extractor.extract(VaccinationQrCodeTestData.certificateMissing)
+        }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.NO_TEST_ENTRY
+    }
+
+    @Test
+    fun `null values fail with JSON_SCHEMA_INVALID`() {
+        shouldThrow<InvalidTestCertificateException> {
+            extractor.extract(TestData.qrCodeMssingValues)
+        }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.JSON_SCHEMA_INVALID
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/server/CovidCertificateApiV1Test.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/server/CovidCertificateApiV1Test.kt
new file mode 100644
index 0000000000000000000000000000000000000000..cd0da93b8ce592dbd6f673a1ab5cba56ad14802a
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/server/CovidCertificateApiV1Test.kt
@@ -0,0 +1,67 @@
+package de.rki.coronawarnapp.covidcertificate.test.core.server
+
+import de.rki.coronawarnapp.http.HttpModule
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import kotlinx.coroutines.runBlocking
+import okhttp3.mockwebserver.MockWebServer
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import testhelpers.extensions.toJsonResponse
+import java.util.concurrent.TimeUnit
+
+class CovidCertificateApiV1Test : BaseTest() {
+
+    private lateinit var webServer: MockWebServer
+    private lateinit var serverAddress: String
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        webServer = MockWebServer()
+        webServer.start()
+        serverAddress = "http://${webServer.hostName}:${webServer.port}"
+    }
+
+    @AfterEach
+    fun teardown() {
+        webServer.shutdown()
+    }
+
+    private fun createAPI(): TestCertificateApiV1 {
+        val httpModule = HttpModule()
+
+        return TestCertificateServerModule().let {
+            val downloadHttpClient = httpModule.defaultHttpClient()
+            it.apiV1(
+                httpClient = downloadHttpClient,
+                url = serverAddress,
+                gsonConverterFactory = httpModule.provideGSONConverter()
+            )
+        }
+    }
+
+    @Test
+    fun `test upload`(): Unit = runBlocking {
+        val api = createAPI()
+        """
+            {
+            
+            }
+        """.toJsonResponse().apply { webServer.enqueue(this) }
+
+        api.sendPublicKey(
+            TestCertificateApiV1.PublicKeyUploadRequest(
+                registrationToken = "token1",
+                publicKey = "key1"
+            )
+        )
+
+        webServer.takeRequest(5, TimeUnit.SECONDS)!!.apply {
+            path shouldBe "/version/v1/publicKey"
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinatedPersonTest.kt
similarity index 90%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinatedPersonTest.kt
index c63461ce23343dccbe41d1d0efe3c1b21856707b..bd02d7face41c0a7a78cd705544b2e474caba389 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinatedPersonTest.kt
@@ -1,7 +1,7 @@
-package de.rki.coronawarnapp.vaccination.core
+package de.rki.coronawarnapp.covidcertificate.vaccination.core
 
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinatedPersonData
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationContainer
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinatedPersonData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinationContainer
 import io.kotest.matchers.shouldBe
 import io.mockk.every
 import io.mockk.mockk
@@ -36,14 +36,12 @@ class VaccinatedPersonTest : BaseTest() {
         )
 
         certificate.apply {
-            every { firstName } returns "Straw"
-            every { lastName } returns "Berry"
+            every { fullName } returns "Straw Berry"
         }
         vaccinatedPerson.fullName shouldBe "Straw Berry"
 
         certificate.apply {
-            every { firstName } returns null // Thermo
-            every { lastName } returns "Siphon"
+            every { fullName } returns "Siphon"
         }
         vaccinatedPerson.fullName shouldBe "Siphon"
     }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationQrCodeTestData.java b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationQrCodeTestData.java
similarity index 76%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationQrCodeTestData.java
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationQrCodeTestData.java
index 82558ff23b6f13453b7bfd5f22557633710f2d6f..57d6ad6ef5d0542319e8a2716773624f6ca2ec45 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationQrCodeTestData.java
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationQrCodeTestData.java
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.vaccination.core;
+package de.rki.coronawarnapp.covidcertificate.vaccination.core;
 
 public class VaccinationQrCodeTestData {
     static public String validVaccinationQrCode = "HC1:6BFOXN*TS0BI$ZD4N9:9S6RCVN5+O30K3/XIV0W23NTDEXWK G2EP4J0BGJLFX3R3VHXK.PJ:2DPF6R:5SVBHABVCNN95SWMPHQUHQN%A0SOE+QQAB-HQ/HQ7IR.SQEEOK9SAI4- 7Y15KBPD34  QWSP0WRGTQFNPLIR.KQNA7N95U/3FJCTG90OARH9P1J4HGZJKBEG%123ZC$0BCI757TLXKIBTV5TN%2LXK-$CH4TSXKZ4S/$K%0KPQ1HEP9.PZE9Q$95:UENEUW6646936HRTO$9KZ56DE/.QC$Q3J62:6LZ6O59++9-G9+E93ZM$96TV6NRN3T59YLQM1VRMP$I/XK$M8PK66YBTJ1ZO8B-S-*O5W41FD$ 81JP%KNEV45G1H*KESHMN2/TU3UQQKE*QHXSMNV25$1PK50C9B/9OK5NE1 9V2:U6A1ELUCT16DEETUM/UIN9P8Q:KPFY1W+UN MUNU8T1PEEG%5TW5A 6YO67N6BBEWED/3LS3N6YU.:KJWKPZ9+CQP2IOMH.PR97QC:ACZAH.SYEDK3EL-FIK9J8JRBC7ADHWQYSK48UNZGG NAVEHWEOSUI2L.9OR8FHB0T5HM7I";
@@ -8,4 +8,6 @@ public class VaccinationQrCodeTestData {
     static public String validVaccinationQrCode3 = "HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH%TAIOOW%I-1W0658WA/UAN9AAT4V22F/8X*G3M9JUPY0BX/KR96R/S09T./0LWTKD33236J3TA3M*4VV2 73-E3ND3DAJ-43%*48YIB73A*G3W19UEBY5:PI0EGSP4*2D$43B+2SEB7:I/2DY73CIBC:G 7376BXBJBAJ UNFMJCRN0H3PQN*E33H3OA70M3FMJIJN523S+0B/S7-SN2H N37J3JFTULJ5CB3ZCIATULV:SNS8F-67N%21Q21$48X2+36D-I/2DBAJDAJCNB-43SZ4RZ4E%5B/9OK53:UCT16DEZIE IE9.M CVCT1+9V*QERU1MK93P5 U02Y9.G9/G9F:QQ28R3U6/V.*NT*QM.SY$N-P1S29 34S0BYBRC.UYS1U%O6QKN*Q5-QFRMLNKNM8JI0EUGP$I/XK$M8-L9KDI:ZH2E4EVS6O0FVAQNJT:EZ6Q%D0*T1.XSDYV0.VI2OKSNODA.BOD:C.OTXS02:M5OGJIF4LHJW7FFJ2NLGFL/EE%CJF+KM%V$AUS:H+NARLK IBMMG";
     static public String validVaccinationQrCode4 = "HC1:6BFOXN*TS0BI$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3KXH9M9ESIGUBA KWML%6S5B9-+P70Q5VC9:BPCNYKMXEE1JAA/CXGG0JK1WL260X638J3-E3ND3DAJ-43TTTO3HK1H3QBCWNZ83UQJ:T0/8F7V0HKN:Q8.HBV+0SZ4GH00T9UKP0T9WC5PF6846A$Q$76QW6%V98T5$FQMI5DN9QZ5Y0Q$UPE%5MZ5*T57ZA$O7T6LEJOA+MZ55EII-EB1EKC422JBBD0D2K.EJJ14B2MP41WTRZPQEC5L64HX6IAS 8S8FT/MAMXP6QS03L0QIRR97I2HOAXL92L0. KOKG8VG5SI:TU+MMPZ55%PBT1YEGEA7IB65C94JBQ2NLEE:NQ% GC3MXHFLF9OIFN0IZ95LJL80P1FDLW452I8941:HH3M41GTNP8EFUNT$.FTD852IWKP/HLIJL8JF8JF172IMAS EDAHMXFBFBQSKJE72KV$FHJ%3O%6:XM+1QD+T2/VKKER3L3%1THL7MGY.1S:T:GLOX6OCE7+RWYL3.C-L27WNV0G::M74O%K7C50AAEI4";
     static public String qrCodeWithNonsenseCountry = "HC1:NCF3Y28.P-O0PS3JPU7RBWBA2*9VTS/9VZ+PLUOVTJ$EB7W3R9B3VN/3A44E./EZ.6Y8C$.C.IK6MA$00J1TQZ9$9IU+S7HP%X9%*MW09:4WB/5SWB20V5VFBBREWO+GIIUF4+PBZR7MNX/N1JIIML/X3Z.Q67RMB6:BJYE26A5NNL:CIM-A*/UZTM+QO: ACV6212500GUC+KM-5AUYGUD1330PFBA855/SNDPCSOC3KMR9X$DB61.0AESG$:THFGP-M/VI2SG/ 22SS+V8OP3R8LDJ50HR6S94JMN-84Q0C+2/8FUV9HH6N91GB3/YCHN6ALFFZL3M116O/IBU6QKJK/3FMQ0TLK-.UQOO$%A $J%H0%*J:DE6/DOKTG*F605WRK8G7S96JG0 4IF:B9VM0CIBRF/XNBOH9 SGIFJ/2CX593I0GE7FFDEQ6+UO5D+HM/2IDBI.ET/L725IHPKB/T/Q9KRJ* NOWN$6K8VOZIHJ5R29KQWSPYKYSDZRJ+1IVBFGPMXEVY6JIYI/ CVBTJ-FY%MO%RUTF17S:1OL8PVXHRPTUOTK/VF%U%:IR G";
+    static public String qrCodeWithNullValues = "HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH.TAIOO6+I2HU7A28WAI1G$H4AT4V22F/8X*G8QHJUPZ0BR/S09T./0LWTKD33236J3TA3M*4VV2 73-E3GG396B-43O058YIB73A*G3W19UEBY5:PIDHGNTI4L6YO1%UG/YL WO*Z7ON1 *L:O8PN1QP5O PLU9A/RUX96 B0V1ZZB.T12.H.ZJ$%HN 9GTBIQ16-I5NI5K1*TB3:U-1VVS1UU15%HVLIWQHYZKOP6OH6XO9IE5IVU5P2-GA*PE1H6IO2OO9$G40GHS-O:S9UZ4+FJE 4Y3L 78OAJ/9TL4T1C9 UPVD5BT17$1MV15K1DR1FIEC2F5+1T+UC2FSH9 UP+/UXJDTW5CL52U50$EZ*N.KUW*P .UUQKC.U%KIP3FY5LG1A614I%KZYNNEVQ KB+P8$JG+SB.V Q5FN9ZK1BCTD PPQ3X:J15RM*F9TVYPVE6G1OU-5Q.-OP*17:FX+52AWI1C0:HPE2%90Q:H2SFUGVP56O1W:W7MEGZNBC3WJ0J:*JITJ%W6XK2L3S.GA/S14 FD$G";
+    static public String qrCodeBlankLastNameStandardized = "HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH:XIIOO6+ID7BO:H.I5B88MQ3ZMIN9HNO4*J8OX4W$C2VL*LA 43/IE%TE6UG+ZEAT1HQ13W1:O1YUI%F1PN1/T1%%HRP5 R14SI.J9DYHZROVZ05QNZ 20OP748$NI4L6YO1%UG/YL WO*Z7ON1 *L:O8PN1QP5O PLU9A/RUX96 B0V1ZZB.T12.H.ZJ$%HN 9GTBIQ16-I5NI5K1*TB3:U-1VVS1UU15%HVLIWQHYZKOP6OH6XO9IE5IVU5P2-GA*PE1H6IO2OO9$G40GHS-O:S9UZ4+FJE 4Y3L 78OAJ/9TL4T1C9 UP+B9MK93P5AW0:G9.G9/G9F:QQ28R3U6/V.*NT*QM.SY$N-P1S29 34S0BYBRC.UYS1U%O6QKN*Q5-QFRMLNKNM8LK4IYOP$I/XK$M8-L9HCI:ZH2E4UE1B4GC:DN5E:UNJ17$CS*J7.HRT:A /NFZ1FG7K-NXM693K+DD1ET2 D13ST$LGMUW/O7P6CJSZ9NC+Q6DJ1ZJ65QG9MS 1M$FRFTS50*G5V0";
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestComponent.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestComponent.kt
similarity index 59%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestComponent.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestComponent.kt
index 181970bd621adbbc1eb156126f6bd70dcbd01dd7..8d1e04bbb267f7c39592ba80aa9f8e725072164e 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestComponent.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestComponent.kt
@@ -1,12 +1,12 @@
-package de.rki.coronawarnapp.vaccination.core
+package de.rki.coronawarnapp.covidcertificate.vaccination.core
 
 import dagger.Component
 import dagger.Module
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeExtractorTest
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepositoryTest
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinationContainerTest
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinationStorageTest
 import de.rki.coronawarnapp.util.serialization.SerializationModule
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractorTest
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepositoryTest
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationContainerTest
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationStorageTest
 import javax.inject.Singleton
 
 @Singleton
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestData.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestData.kt
similarity index 77%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestData.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestData.kt
index 5652d7054cc15d06706e37f97a889ad54e6ecc93..079022777951abd1eedc80dfd9e383b08853b2f4 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestData.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestData.kt
@@ -1,12 +1,13 @@
-package de.rki.coronawarnapp.vaccination.core
-
-import de.rki.coronawarnapp.vaccination.core.certificate.HealthCertificateHeader
-import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateQRCode
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractor
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinatedPersonData
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationContainer
+package de.rki.coronawarnapp.covidcertificate.vaccination.core
+
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccHeader
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationCertificateQRCode
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinatedPersonData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinationContainer
 import org.joda.time.Instant
 import javax.inject.Inject
 
@@ -19,17 +20,17 @@ class VaccinationTestData @Inject constructor(
     val personAVac1QRCodeString =
         "HC1:6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3KXH9M9ESIGUBA KWML%6S5B9-+P70Q5VC9:BPCNYKMXEE1JAA/CXGG0JK1WL260X638J3-E3ND3DAJ-43TTTO3HK1H3QBCWNZ83UQJ:T0/8F7V0HKN:Q8.HBV+0SZ4GH00T9UKP0T9WC5PF6846A\$Q$76QW6%V98T5\$FQMI5DN9QZ5Y0Q\$UPE%5MZ5*T57ZA\$O7T6LEJOA+MZ55EII-EB1EKC422JBBD0D2K.EJJ14B2MP41WTRZPQEC5L64HX6IAS 8S8FT/MAMXP6QS03L0QIRR97I2HOAXL92L0. KOKG8VG5SI:TU+MMPZ55%PBT1YEGEA7IB65C94JBQ2NLEE:NQ% GC3MXHFLF9OIFN0IZ95LJL80P1FDLW452I8941:HH3M41GTNP8EFUNT$.FTD852IWKP/HLIJL8JF8JF172IMAS EDAHMXFBFBQSKJE72KV\$FHJ%3O%6:XM+1QD+T2/VKKER3L3%1THL7MGY.1S:T:GLOX6OCE7+RWYL3.C-L27WNV0G::M74O%K7C50AAEI4"
 
-    val personAVac1Certificate = VaccinationDGCV1(
+    val personAVac1Certificate = VaccinationDccV1(
         version = "1.0.0",
-        nameData = VaccinationDGCV1.NameData(
+        nameData = Dcc.NameData(
             givenName = "Andreas",
             givenNameStandardized = "ANDREAS",
             familyName = "Astrá Eins",
             familyNameStandardized = "ASTRA<EINS",
         ),
         dob = "1966-11-11",
-        vaccinationDatas = listOf(
-            VaccinationDGCV1.VaccinationData(
+        payloads = listOf(
+            VaccinationDccV1.VaccinationData(
                 targetId = "840539006",
                 vaccineId = "1119305005",
                 medicalProductId = "EU/1/21/1529",
@@ -37,27 +38,27 @@ class VaccinationTestData @Inject constructor(
                 doseNumber = 1,
                 totalSeriesOfDoses = 2,
                 dt = "2021-03-01",
-                countryOfVaccination = "DE",
+                certificateCountry = "DE",
                 certificateIssuer = "Bundesministerium für Gesundheit - Test01",
                 uniqueCertificateIdentifier = "01DE/00001/1119305005/7T1UG87G61Y7NRXIBQJDTYQ9#S",
             )
         )
     )
 
-    val personAVac1CertificateHeader = HealthCertificateHeader(
+    val personAVac1CertificateHeader = DccHeader(
         issuer = "DE",
         issuedAt = Instant.parse("2021-05-11T09:25:00.000Z"),
         expiresAt = Instant.parse("2022-05-11T09:25:00.000Z"),
     )
 
-    val personAVac1CertificateData = VaccinationCertificateData(
+    val personAVac1CertificateData = DccData(
         certificate = personAVac1Certificate,
         header = personAVac1CertificateHeader
     )
 
     val personAVac1QRCode = VaccinationCertificateQRCode(
-        qrCodeString = personAVac1QRCodeString,
-        parsedData = personAVac1CertificateData,
+        qrCode = personAVac1QRCodeString,
+        data = personAVac1CertificateData,
     )
 
     val personAVac1Container = VaccinationContainer(
@@ -71,17 +72,17 @@ class VaccinationTestData @Inject constructor(
     val personAVac2QRCodeString =
         "6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3D H9M9ESIGUBA KWMLYX1HXK 0DV:D5VC9:BPCNYKMXEE1JAA/CZIK0JK1WL260X638J3-E3ND3DAJ-43TTTMDF6S8:B73QN VNZ.0K6HYI3CNN96BPHNW*0I85V.499TXY9KK9%OC+G9QJPNF67J6QW67KQ9G66PPM4MLJE+.PDB9L6Q2+PFQ5DB96PP5/P-59A%N+892 7J235II3NJ7PK7SLQMIPUBN9CIZI.EJJ14B2MP41IZRZPQEC5L64HX6IAS 8SAFT/MAMXP6QS03L0QIRR97I2HOAXL92L0. KOKGGVG5SI:TU+MMPZ55%PBT1YEGEA7IB65C94JBQ2NLEE:NQ% GC3MXHFLF9OIFN0IZ95LJL80P1FDLW452I8941:HH3M41GTNP8EFUNT\$.FTD852IWKP/HLIJL8JF8JF172E2JA0K*WDQMPB8T3%KLUSR43M.F\$QBQDR\$VT7V01Y7J0BOZLH+D-QF6MO\$R3%XB+.4QI596GY\$SITJP5BS0DFROC.7B.2RTB*UNYSM$*00HIL+H"
 
-    val personAVac2Certificate = VaccinationDGCV1(
+    val personAVac2Certificate = VaccinationDccV1(
         version = "1.0.0",
-        nameData = VaccinationDGCV1.NameData(
+        nameData = Dcc.NameData(
             givenName = "Andreas",
             givenNameStandardized = "ANDREAS",
             familyName = "Astrá Eins",
             familyNameStandardized = "ASTRA<EINS",
         ),
         dob = "1966-11-11",
-        vaccinationDatas = listOf(
-            VaccinationDGCV1.VaccinationData(
+        payloads = listOf(
+            VaccinationDccV1.VaccinationData(
                 targetId = "840539006",
                 vaccineId = "1119305005",
                 medicalProductId = "EU/1/21/1529",
@@ -89,27 +90,27 @@ class VaccinationTestData @Inject constructor(
                 doseNumber = 2,
                 totalSeriesOfDoses = 2,
                 dt = "2021-04-27",
-                countryOfVaccination = "DE",
+                certificateCountry = "DE",
                 certificateIssuer = "Bundesministerium für Gesundheit - Test01",
                 uniqueCertificateIdentifier = "01DE/00001/1119305005/6IPYBAIDWEWRWW73QEP92FQSN#S",
             )
         )
     )
 
-    val personAVac2CertificateHeader = HealthCertificateHeader(
+    val personAVac2CertificateHeader = DccHeader(
         issuer = "DE",
         issuedAt = Instant.parse("2021-05-11T09:26:08.000Z"),
         expiresAt = Instant.parse("2022-05-11T09:26:08.000Z"),
     )
 
-    val personAVac2CertificateData = VaccinationCertificateData(
+    val personAVac2CertificateData = DccData(
         certificate = personAVac2Certificate,
         header = personAVac2CertificateHeader
     )
 
     val personAVac2QRCode = VaccinationCertificateQRCode(
-        qrCodeString = personAVac2QRCodeString,
-        parsedData = personAVac2CertificateData,
+        qrCode = personAVac2QRCodeString,
+        data = personAVac2CertificateData,
     )
 
     val personAVac2Container = VaccinationContainer(
@@ -127,17 +128,17 @@ class VaccinationTestData @Inject constructor(
     val personBVac1QRCodeString =
         "HC1:6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3QVH9M9ESIGUBA KWML:SPHXK 0DMYF5VC9:BPCNYKMXEE1JAA/CZIK0JK1WL260X638J3-E3ND3DAJ-43 QTCPFFIJRF3O8H43HX37DUF GFE VMJJYC3SM74E5V.499TXY9KK9+OC+G9QJPNF67J6QW67KQ2G66PPM4MLJE+.PDB9L6Q2+PFQ5DB96PP5/P-59A%N+892 7J235II3NJ7PK7SLQMIPUBN9CIZI.EJJ14B2MP41AZRSEQEC5L64HX6IAS3DS2980IQ.DPUHLW\$GAHLW 70SO:GOLIROGO3T59YLQM14+OP\$I/XK\$M8CL6PZB*L8PK99Q9E\$BDZIF9J8-I\$GI0 J1ALL:F71APC9*KF6LF/NLR/FZ.COKEH-BB4OQ9OG4C5AO**HOELK2AZ7LBLEH-BHPLV5GK3DNKE\$JDVPLW1KD0KCZG.M1LUSB5BCQRJ\$DB5N9%V/GO4IHIBBJ-BI%NWRS%LR%\$KR46325NABFDDAFHD9PZP11COD5U*2KQXCA5W8HH/K51DQO8O0-SOSENFH9101U8$3"
 
-    val personBVac1Certificate = VaccinationDGCV1(
+    val personBVac1Certificate = VaccinationDccV1(
         version = "1.0.0",
-        nameData = VaccinationDGCV1.NameData(
+        nameData = Dcc.NameData(
             givenName = "Boris",
             givenNameStandardized = "BORIS",
             familyName = "Johnson Gültig",
             familyNameStandardized = "JOHNSON<GUELTIG",
         ),
         dob = "1966-11-11",
-        vaccinationDatas = listOf(
-            VaccinationDGCV1.VaccinationData(
+        payloads = listOf(
+            VaccinationDccV1.VaccinationData(
                 targetId = "840539006",
                 vaccineId = "1119305005",
                 medicalProductId = "EU/1/20/1525",
@@ -145,27 +146,27 @@ class VaccinationTestData @Inject constructor(
                 doseNumber = 1,
                 totalSeriesOfDoses = 1,
                 dt = "2021-04-20",
-                countryOfVaccination = "DE",
+                certificateCountry = "DE",
                 certificateIssuer = "Bundesministerium für Gesundheit - Test01",
                 uniqueCertificateIdentifier = "01DE/00001/1119305005/3H24U2KVOTPCSINK7N64F2OB9#S",
             )
         )
     )
 
-    val personBVac1CertificateHeader = HealthCertificateHeader(
+    val personBVac1CertificateHeader = DccHeader(
         issuer = "DE",
         issuedAt = Instant.parse("2021-05-11T09:23:03.000Z"),
         expiresAt = Instant.parse("2022-05-11T09:23:03.000Z"),
     )
 
-    val personBVac1CertificateData = VaccinationCertificateData(
+    val personBVac1CertificateData = DccData(
         certificate = personBVac1Certificate,
         header = personBVac1CertificateHeader
     )
 
     val personBVac1QRCode = VaccinationCertificateQRCode(
-        qrCodeString = personBVac1QRCodeString,
-        parsedData = personBVac1CertificateData,
+        qrCode = personBVac1QRCodeString,
+        data = personBVac1CertificateData,
     )
 
     val personBVac1Container = VaccinationContainer(
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/ValueSetTestData.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/ValueSetTestData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..732fab8d22391c94e62838b2ed913094e5814ca5
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/ValueSetTestData.kt
@@ -0,0 +1,78 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.core
+
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.DefaultValueSet
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.TestCertificateValueSets
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.VaccinationValueSets
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.ValueSetsContainer
+import java.util.Locale
+
+object ValueSetTestData {
+
+    // Shared
+    val tgItemDe = "tg" to "Ziel-Name"
+    val tgItemEn = tgItemDe.copy(second = "Target-Name")
+
+    // Vaccination
+    val vpItemDe = "1119305005" to "Impfstoff-Name"
+    val mpItemDe = "EU/1/21/1529" to "Arzneimittel-Name"
+    val maItemDe = "ORG-100001699" to "Hersteller-Name"
+
+    val vpItemEn = vpItemDe.copy(second = "Vaccine-Name")
+    val mpItemEn = mpItemDe.copy(second = "MedicalProduct-Name")
+    val maItemEn = maItemDe.copy(second = "Manufactorer-Name")
+
+    // Test certificate
+    val ttItemDe = "tt" to "Test-Typ"
+    val tcMaItemDe = "tcMa" to "RAT-Test-Name-und-Hersteller"
+    val trItemDe = "tr" to "Test-Ergebnis"
+
+    val ttItemEn = vpItemDe.copy(second = "Test-Type")
+    val tcMaItemEn = mpItemDe.copy(second = "RAT-Test-Name-and-Manufacturer")
+    val trItemEn = maItemDe.copy(second = "Test-Result")
+
+    private fun Pair<String, String>.toValueSet() = DefaultValueSet(
+        items = listOf(DefaultValueSet.DefaultItem(key = first, displayText = second))
+    )
+
+    val vaccinationValueSetsDe = VaccinationValueSets(
+        languageCode = Locale.GERMAN,
+        tg = tgItemDe.toValueSet(),
+        vp = vpItemDe.toValueSet(),
+        mp = mpItemDe.toValueSet(),
+        ma = maItemDe.toValueSet()
+    )
+
+    val vaccinationValueSetsEn = VaccinationValueSets(
+        languageCode = Locale.GERMAN,
+        tg = tgItemEn.toValueSet(),
+        vp = vpItemEn.toValueSet(),
+        mp = mpItemEn.toValueSet(),
+        ma = maItemEn.toValueSet()
+    )
+
+    val testCertificateValueSetsDe = TestCertificateValueSets(
+        languageCode = Locale.GERMAN,
+        tg = tgItemDe.toValueSet(),
+        tt = ttItemDe.toValueSet(),
+        ma = tcMaItemDe.toValueSet(),
+        tr = trItemDe.toValueSet()
+    )
+
+    val testCertificateValueSetsEn = TestCertificateValueSets(
+        languageCode = Locale.GERMAN,
+        tg = tgItemEn.toValueSet(),
+        tt = ttItemEn.toValueSet(),
+        ma = tcMaItemEn.toValueSet(),
+        tr = trItemEn.toValueSet()
+    )
+
+    val valueSetsContainerDe = ValueSetsContainer(
+        vaccinationValueSets = vaccinationValueSetsDe,
+        testCertificateValueSets = testCertificateValueSetsDe
+    )
+
+    val valueSetsContainerEn = ValueSetsContainer(
+        vaccinationValueSets = vaccinationValueSetsEn,
+        testCertificateValueSets = testCertificateValueSetsEn
+    )
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/execution/VaccinationUpdateSchedulerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/VaccinationUpdateSchedulerTest.kt
similarity index 90%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/execution/VaccinationUpdateSchedulerTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/VaccinationUpdateSchedulerTest.kt
index 4488f0b27dd0db557456c40ab0b14bb0527d6035..d3358a2c812be102861b3553ecd3682eebf5f843 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/execution/VaccinationUpdateSchedulerTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/VaccinationUpdateSchedulerTest.kt
@@ -1,16 +1,16 @@
-package de.rki.coronawarnapp.vaccination.core.execution
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.execution
 
 import androidx.work.PeriodicWorkRequest
 import androidx.work.WorkInfo
 import androidx.work.WorkManager
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.worker.VaccinationUpdateWorkerRequestBuilder
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
 import de.rki.coronawarnapp.task.TaskController
 import de.rki.coronawarnapp.task.TaskRequest
 import de.rki.coronawarnapp.util.CWADebug
 import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.device.ForegroundState
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson
-import de.rki.coronawarnapp.vaccination.core.execution.worker.VaccinationUpdateWorkerRequestBuilder
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
 import io.mockk.Called
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/execution/task/VaccinationUpdateTaskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/task/VaccinationUpdateTaskTest.kt
similarity index 84%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/execution/task/VaccinationUpdateTaskTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/task/VaccinationUpdateTaskTest.kt
index 59c1af64093c344318739a48559cbbb27884342f..918e72b86509ca245242071bb4b8bfc56a04f1f0 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/execution/task/VaccinationUpdateTaskTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/task/VaccinationUpdateTaskTest.kt
@@ -1,6 +1,6 @@
-package de.rki.coronawarnapp.vaccination.core.execution.task
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.task
 
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
 import io.mockk.coEvery
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/execution/worker/VaccinationUpdateWorkerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/worker/VaccinationUpdateWorkerTest.kt
similarity index 93%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/execution/worker/VaccinationUpdateWorkerTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/worker/VaccinationUpdateWorkerTest.kt
index 60c8a9d2558c3bd8218fa729b74a167e46af3a1d..657ee5993bdec0d28114ef3228dc626615d96f52 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/execution/worker/VaccinationUpdateWorkerTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/execution/worker/VaccinationUpdateWorkerTest.kt
@@ -1,15 +1,15 @@
-package de.rki.coronawarnapp.vaccination.core.execution.worker
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.worker
 
 import android.content.Context
 import androidx.work.ListenableWorker
 import androidx.work.WorkerParameters
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.execution.task.VaccinationUpdateTask
 import de.rki.coronawarnapp.task.TaskController
 import de.rki.coronawarnapp.task.TaskFactory
 import de.rki.coronawarnapp.task.TaskRequest
 import de.rki.coronawarnapp.task.TaskState
 import de.rki.coronawarnapp.task.common.DefaultTaskRequest
 import de.rki.coronawarnapp.task.submitBlocking
-import de.rki.coronawarnapp.vaccination.core.execution.task.VaccinationUpdateTask
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.coEvery
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt
similarity index 62%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt
index ef2d3bd05a7f431767e5bf92ce403b1a1f3b1100..de06cb9760fff4d41c49d07d7c1c5bd6078a7755 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt
@@ -1,13 +1,14 @@
-package de.rki.coronawarnapp.vaccination.core.qrcode
-
-import de.rki.coronawarnapp.vaccination.core.DaggerVaccinationTestComponent
-import de.rki.coronawarnapp.vaccination.core.VaccinationQrCodeTestData
-import de.rki.coronawarnapp.vaccination.core.VaccinationTestData
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_HC_CWT_NO_ISS
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.VC_NO_VACCINATION_ENTRY
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode
+
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_ISS
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_NO_VACCINATION_ENTRY
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.DaggerVaccinationTestComponent
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationQrCodeTestData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationTestData
 import io.kotest.assertions.throwables.shouldThrow
 import io.kotest.matchers.shouldBe
 import org.joda.time.Instant
@@ -41,13 +42,13 @@ class VaccinationQRCodeExtractorTest : BaseTest() {
     fun `happy path extraction with data`() {
         val qrCode = extractor.extract(VaccinationQrCodeTestData.validVaccinationQrCode3)
 
-        with(qrCode.parsedData.header) {
+        with(qrCode.data.header) {
             issuer shouldBe "AT"
             issuedAt shouldBe Instant.ofEpochSecond(1620392021)
             expiresAt shouldBe Instant.ofEpochSecond(1620564821)
         }
 
-        with(qrCode.parsedData.certificate) {
+        with(qrCode.data.certificate) {
             with(nameData) {
                 familyName shouldBe "Musterfrau-Gößinger"
                 familyNameStandardized shouldBe "MUSTERFRAU<GOESSINGER"
@@ -58,9 +59,9 @@ class VaccinationQRCodeExtractorTest : BaseTest() {
             dateOfBirth shouldBe LocalDate.parse("1998-02-26")
             version shouldBe "1.0.0"
 
-            with(vaccinationDatas[0]) {
+            with(payloads[0]) {
                 uniqueCertificateIdentifier shouldBe "urn:uvci:01:AT:10807843F94AEE0EE5093FBC254BD813P"
-                countryOfVaccination shouldBe "AT"
+                certificateCountry shouldBe "AT"
                 doseNumber shouldBe 1
                 dt shouldBe "2021-02-18"
                 certificateIssuer shouldBe "BMSGPK Austria"
@@ -80,29 +81,29 @@ class VaccinationQRCodeExtractorTest : BaseTest() {
     }
 
     @Test
-    fun `valid encoding but not a health certificate fails with VC_HC_CWT_NO_ISS`() {
-        shouldThrow<InvalidHealthCertificateException> {
+    fun `valid encoding but not a health certificate fails with HC_CWT_NO_ISS`() {
+        shouldThrow<InvalidVaccinationCertificateException> {
             extractor.extract(VaccinationQrCodeTestData.validEncoded)
-        }.errorCode shouldBe VC_HC_CWT_NO_ISS
+        }.errorCode shouldBe HC_CWT_NO_ISS
     }
 
     @Test
     fun `random string fails with HC_BASE45_DECODING_FAILED`() {
-        shouldThrow<InvalidHealthCertificateException> {
+        shouldThrow<InvalidVaccinationCertificateException> {
             extractor.extract("nothing here to see")
         }.errorCode shouldBe HC_BASE45_DECODING_FAILED
     }
 
     @Test
     fun `uncompressed base45 string fails with HC_ZLIB_DECOMPRESSION_FAILED`() {
-        shouldThrow<InvalidHealthCertificateException> {
+        shouldThrow<InvalidVaccinationCertificateException> {
             extractor.extract("6BFOABCDEFGHIJKLMNOPQRSTUVWXYZ %*+-./:")
         }.errorCode shouldBe HC_ZLIB_DECOMPRESSION_FAILED
     }
 
     @Test
     fun `vaccination certificate missing fails with VC_NO_VACCINATION_ENTRY`() {
-        shouldThrow<InvalidHealthCertificateException> {
+        shouldThrow<InvalidVaccinationCertificateException> {
             extractor.extract(VaccinationQrCodeTestData.certificateMissing)
         }.errorCode shouldBe VC_NO_VACCINATION_ENTRY
     }
@@ -118,4 +119,18 @@ class VaccinationQRCodeExtractorTest : BaseTest() {
         val extracted = extractor.extract(vaccinationTestData.personBVac1QRCodeString)
         extracted shouldBe vaccinationTestData.personBVac1QRCode
     }
+
+    @Test
+    fun `null values fail with JSON_SCHEMA_INVALID`() {
+        shouldThrow<InvalidVaccinationCertificateException> {
+            extractor.extract(VaccinationQrCodeTestData.qrCodeWithNullValues)
+        }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.JSON_SCHEMA_INVALID
+    }
+
+    @Test
+    fun `blank name fails with JSON_SCHEMA_INVALID`() {
+        shouldThrow<InvalidVaccinationCertificateException> {
+            extractor.extract(VaccinationQrCodeTestData.qrCodeBlankLastNameStandardized)
+        }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.JSON_SCHEMA_INVALID
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/VaccinationRepositoryTest.kt
similarity index 81%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepositoryTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/VaccinationRepositoryTest.kt
index f0703302cb0f92b034fdb75003771bfd254ef56e..1f5e4170631a3f677690f6756924f2bb15499e3f 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepositoryTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/VaccinationRepositoryTest.kt
@@ -1,14 +1,17 @@
-package de.rki.coronawarnapp.vaccination.core.repository
-
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository
+
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_ALREADY_REGISTERED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_NAME_MISMATCH
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.DaggerVaccinationTestComponent
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationTestData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.errors.VaccinationCertificateNotFoundException
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinatedPersonData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinationStorage
+import de.rki.coronawarnapp.covidcertificate.valueset.ValueSetsRepository
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.VaccinationValueSets
 import de.rki.coronawarnapp.util.TimeStamper
-import de.rki.coronawarnapp.vaccination.core.DaggerVaccinationTestComponent
-import de.rki.coronawarnapp.vaccination.core.VaccinationTestData
-import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException
-import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractor
-import de.rki.coronawarnapp.vaccination.core.repository.errors.VaccinationCertificateNotFoundException
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinatedPersonData
-import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationStorage
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet
 import io.kotest.assertions.throwables.shouldThrow
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
@@ -32,7 +35,7 @@ class VaccinationRepositoryTest : BaseTest() {
 
     @MockK lateinit var storage: VaccinationStorage
     @MockK lateinit var valueSetsRepository: ValueSetsRepository
-    @MockK lateinit var vaccinationValueSet: VaccinationValueSet
+    @MockK lateinit var vaccinationValueSet: VaccinationValueSets
     @MockK lateinit var qrCodeExtractor: VaccinationQRCodeExtractor
 
     private var testStorage: Set<VaccinatedPersonData> = emptySet()
@@ -50,7 +53,7 @@ class VaccinationRepositoryTest : BaseTest() {
 
         every { timeStamper.nowUTC } returns nowUTC
 
-        every { valueSetsRepository.latestValueSet } returns flowOf(vaccinationValueSet)
+        every { valueSetsRepository.latestVaccinationValueSets } returns flowOf(vaccinationValueSet)
 
         storage.apply {
             every { personContainers } answers { testStorage }
@@ -109,9 +112,9 @@ class VaccinationRepositoryTest : BaseTest() {
         val instance = createInstance(this)
         advanceUntilIdle()
 
-        shouldThrow<InvalidHealthCertificateException> {
+        shouldThrow<InvalidVaccinationCertificateException> {
             instance.registerVaccination(vaccinationTestData.personBVac1QRCode)
-        }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.VC_NAME_MISMATCH
+        }.errorCode shouldBe VC_NAME_MISMATCH
 
         testStorage shouldBe setOf(vaccinationTestData.personAData2Vac)
     }
@@ -127,9 +130,9 @@ class VaccinationRepositoryTest : BaseTest() {
         val instance = createInstance(this)
         advanceUntilIdle()
 
-        shouldThrow<InvalidHealthCertificateException> {
+        shouldThrow<InvalidVaccinationCertificateException> {
             instance.registerVaccination(vaccinationTestData.personAVac1QRCode)
-        }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.VC_ALREADY_REGISTERED
+        }.errorCode shouldBe VC_ALREADY_REGISTERED
 
         testStorage.first() shouldBe dataBefore
     }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainerTest.kt
similarity index 71%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainerTest.kt
index fad39f683f0e946dda8f94afb044c82a403a554d..7c9d5d97fbaabf88fb8e2f33441b956fa62a9746 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainerTest.kt
@@ -1,12 +1,11 @@
-package de.rki.coronawarnapp.vaccination.core.repository.storage
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage
 
-import de.rki.coronawarnapp.vaccination.core.DaggerVaccinationTestComponent
-import de.rki.coronawarnapp.vaccination.core.VaccinatedPersonIdentifier
-import de.rki.coronawarnapp.vaccination.core.VaccinationTestData
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.DaggerVaccinationTestComponent
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationTestData
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.DefaultValueSet
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.VaccinationValueSets
 import io.kotest.matchers.shouldBe
-import io.mockk.every
-import io.mockk.mockk
 import org.joda.time.Instant
 import org.joda.time.LocalDate
 import org.junit.jupiter.api.BeforeEach
@@ -26,7 +25,7 @@ class VaccinationContainerTest : BaseTest() {
 
     @Test
     fun `person identifier calculation`() {
-        testData.personAVac1Container.personIdentifier shouldBe VaccinatedPersonIdentifier(
+        testData.personAVac1Container.personIdentifier shouldBe CertificatePersonIdentifier(
             dateOfBirth = LocalDate.parse("1966-11-11"),
             firstNameStandardized = "ANDREAS",
             lastNameStandardized = "ASTRA<EINS"
@@ -63,6 +62,7 @@ class VaccinationContainerTest : BaseTest() {
         testData.personAVac1Container.toVaccinationCertificate(null, userLocale = Locale.GERMAN).apply {
             firstName shouldBe "Andreas"
             lastName shouldBe "Astrá Eins"
+            fullName shouldBe "Andreas Astrá Eins"
             dateOfBirth shouldBe LocalDate.parse("1966-11-11")
             vaccinatedAt shouldBe LocalDate.parse("2021-03-01")
             vaccineTypeName shouldBe "1119305005"
@@ -73,7 +73,7 @@ class VaccinationContainerTest : BaseTest() {
             certificateIssuer shouldBe "Bundesministerium für Gesundheit - Test01"
             certificateCountry shouldBe "Deutschland"
             certificateId shouldBe "01DE/00001/1119305005/7T1UG87G61Y7NRXIBQJDTYQ9#S"
-            personIdentifier shouldBe VaccinatedPersonIdentifier(
+            personIdentifier shouldBe CertificatePersonIdentifier(
                 dateOfBirth = LocalDate.parse("1966-11-11"),
                 firstNameStandardized = "ANDREAS",
                 lastNameStandardized = "ASTRA<EINS"
@@ -83,34 +83,33 @@ class VaccinationContainerTest : BaseTest() {
 
     @Test
     fun `mapping to user facing data - with valueset`() {
-        val vpItem = mockk<VaccinationValueSet.ValueSet.Item> {
-            every { key } returns "1119305005"
-            every { displayText } returns "Vaccine-Name"
-        }
-
-        val mpItem = mockk<VaccinationValueSet.ValueSet.Item> {
-            every { key } returns "EU/1/21/1529"
-            every { displayText } returns "MedicalProduct-Name"
-        }
+        val vpItem = DefaultValueSet.DefaultItem(
+            key = "1119305005",
+            displayText = "Vaccine-Name"
+        )
 
-        val maItem = mockk<VaccinationValueSet.ValueSet.Item> {
-            every { key } returns "ORG-100001699"
-            every { displayText } returns "Manufactorer-Name"
-        }
+        val mpItem = DefaultValueSet.DefaultItem(
+            key = "EU/1/21/1529",
+            displayText = "MedicalProduct-Name"
+        )
 
-        val vpMockk = mockk<VaccinationValueSet.ValueSet> {
-            every { items } returns listOf(vpItem, mpItem, maItem)
-        }
+        val maItem = DefaultValueSet.DefaultItem(
+            key = "ORG-100001699",
+            displayText = "Manufactorer-Name"
+        )
 
-        val valueSet = mockk<VaccinationValueSet> {
-            every { vp } returns vpMockk
-            every { mp } returns vpMockk
-            every { ma } returns vpMockk
-        }
+        val vaccinationValueSets = VaccinationValueSets(
+            languageCode = Locale.GERMAN,
+            tg = DefaultValueSet(),
+            vp = DefaultValueSet(items = listOf(vpItem)),
+            mp = DefaultValueSet(items = listOf(mpItem)),
+            ma = DefaultValueSet(items = listOf(maItem))
+        )
 
-        testData.personAVac1Container.toVaccinationCertificate(valueSet, userLocale = Locale.GERMAN).apply {
+        testData.personAVac1Container.toVaccinationCertificate(vaccinationValueSets, userLocale = Locale.GERMAN).apply {
             firstName shouldBe "Andreas"
             lastName shouldBe "Astrá Eins"
+            fullName shouldBe "Andreas Astrá Eins"
             dateOfBirth shouldBe LocalDate.parse("1966-11-11")
             vaccinatedAt shouldBe LocalDate.parse("2021-03-01")
             vaccineTypeName shouldBe "Vaccine-Name"
@@ -121,7 +120,7 @@ class VaccinationContainerTest : BaseTest() {
             certificateIssuer shouldBe "Bundesministerium für Gesundheit - Test01"
             certificateCountry shouldBe "Deutschland"
             certificateId shouldBe "01DE/00001/1119305005/7T1UG87G61Y7NRXIBQJDTYQ9#S"
-            personIdentifier shouldBe VaccinatedPersonIdentifier(
+            personIdentifier shouldBe CertificatePersonIdentifier(
                 dateOfBirth = LocalDate.parse("1966-11-11"),
                 firstNameStandardized = "ANDREAS",
                 lastNameStandardized = "ASTRA<EINS"
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationStorageTest.kt
similarity index 83%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorageTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationStorageTest.kt
index 9af9da65bd8172c743c89b1078d28416502a678b..4da0bfea9e53f3b7075bcb43193124031d147681 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorageTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationStorageTest.kt
@@ -1,11 +1,12 @@
-package de.rki.coronawarnapp.vaccination.core.repository.storage
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage
 
 import android.content.Context
 import androidx.core.content.edit
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.DaggerVaccinationTestComponent
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationTestData
 import de.rki.coronawarnapp.util.serialization.SerializationModule
-import de.rki.coronawarnapp.vaccination.core.DaggerVaccinationTestComponent
-import de.rki.coronawarnapp.vaccination.core.VaccinationTestData
 import io.kotest.matchers.shouldBe
+import io.kotest.matchers.shouldNotBe
 import io.mockk.MockKAnnotations
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
@@ -88,4 +89,11 @@ class VaccinationStorageTest : BaseTest() {
             )
         }
     }
+
+    @Test
+    fun `post processor injects data extractors`() {
+        createInstance().personContainers = setOf(testData.personAData2Vac)
+
+        createInstance().personContainers.single().vaccinations.first().qrCodeExtractor shouldNotBe null
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/ValueSetsStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/ValueSetsStorageTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9bddcf4c849d9f46912cf6d06f8307424db1690e
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/ValueSetsStorageTest.kt
@@ -0,0 +1,188 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage
+
+import android.content.Context
+import androidx.core.content.edit
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.ValueSetTestData.valueSetsContainerDe
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.ValueSetTestData.valueSetsContainerEn
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.ValueSetsStorage
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.emptyValueSetsContainer
+import de.rki.coronawarnapp.util.serialization.SerializationModule
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import testhelpers.extensions.toComparableJsonPretty
+import testhelpers.preferences.MockSharedPreferences
+
+class ValueSetsStorageTest : BaseTest() {
+
+    @MockK lateinit var context: Context
+    lateinit var prefs: MockSharedPreferences
+
+    private val gson = SerializationModule().baseGson()
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+        prefs = MockSharedPreferences()
+        every { context.getSharedPreferences("valuesets_localdata", Context.MODE_PRIVATE) } returns prefs
+    }
+
+    private fun createInstance() = ValueSetsStorage(
+        context = context,
+        gson = gson
+    )
+
+    @Test
+    fun `Updates values`() {
+        createInstance().run {
+            valueSetsContainer = valueSetsContainerDe
+            valueSetsContainer shouldBe valueSetsContainerDe
+
+            valueSetsContainer = valueSetsContainerEn
+            valueSetsContainer shouldBe valueSetsContainerEn
+        }
+    }
+
+    @Test
+    fun `storage inits empty without sideeffects`() {
+        createInstance()
+        prefs.dataMapPeek.isEmpty() shouldBe true
+    }
+
+    @Test
+    fun `storage format`() {
+        createInstance().valueSetsContainer = valueSetsContainerDe
+        (prefs.dataMapPeek["valuesets_container"] as String).toComparableJsonPretty() shouldBe """
+            {
+              "vaccinationValueSets": {
+                "languageCode": "de",
+                "tg": {
+                  "items": [
+                    {
+                      "key": "tg",
+                      "displayText": "Ziel-Name"
+                    }
+                  ]
+                },
+                "vp": {
+                  "items": [
+                    {
+                      "key": "1119305005",
+                      "displayText": "Impfstoff-Name"
+                    }
+                  ]
+                },
+                "mp": {
+                  "items": [
+                    {
+                      "key": "EU/1/21/1529",
+                      "displayText": "Arzneimittel-Name"
+                    }
+                  ]
+                },
+                "ma": {
+                  "items": [
+                    {
+                      "key": "ORG-100001699",
+                      "displayText": "Hersteller-Name"
+                    }
+                  ]
+                }
+              },
+              "testCertificateValueSets": {
+                "languageCode": "de",
+                "tg": {
+                  "items": [
+                    {
+                      "key": "tg",
+                      "displayText": "Ziel-Name"
+                    }
+                  ]
+                },
+                "tt": {
+                  "items": [
+                    {
+                      "key": "tt",
+                      "displayText": "Test-Typ"
+                    }
+                  ]
+                },
+                "ma": {
+                  "items": [
+                    {
+                      "key": "tcMa",
+                      "displayText": "RAT-Test-Name-und-Hersteller"
+                    }
+                  ]
+                },
+                "tr": {
+                  "items": [
+                    {
+                      "key": "tr",
+                      "displayText": "Test-Ergebnis"
+                    }
+                  ]
+                }
+              }
+            }
+        """.toComparableJsonPretty()
+
+        createInstance().apply {
+            valueSetsContainer shouldBe valueSetsContainerDe
+            valueSetsContainer = emptyValueSetsContainer
+        }
+        (prefs.dataMapPeek["valuesets_container"] as String).toComparableJsonPretty() shouldBe """
+            {
+              "vaccinationValueSets": {
+                "languageCode": "en",
+                "tg": {
+                  "items": []
+                },
+                "vp": {
+                  "items": []
+                },
+                "mp": {
+                  "items": []
+                },
+                "ma": {
+                  "items": []
+                }
+              },
+              "testCertificateValueSets": {
+                "languageCode": "en",
+                "tg": {
+                  "items": []
+                },
+                "tt": {
+                  "items": []
+                },
+                "ma": {
+                  "items": []
+                },
+                "tr": {
+                  "items": []
+                }
+              }
+            }
+        """.toComparableJsonPretty()
+
+        createInstance().valueSetsContainer shouldBe emptyValueSetsContainer
+    }
+
+    @Test
+    fun `removes leftover`() {
+        val leftover = "I'm a malicious leftover"
+        val valueSet = "valueset"
+        prefs.edit(commit = true) {
+            putString(valueSet, leftover)
+        }
+
+        prefs.dataMapPeek[valueSet] shouldBe leftover
+        createInstance().valueSetsContainer shouldBe emptyValueSetsContainer
+        prefs.dataMapPeek.isEmpty() shouldBe true
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/valueset/ValueSetsRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/valueset/ValueSetsRepositoryTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..fe97082431a3af107392e0208662b6fa2ef8f7c8
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/valueset/ValueSetsRepositoryTest.kt
@@ -0,0 +1,128 @@
+package de.rki.coronawarnapp.covidcertificate.valueset
+
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.ValueSetTestData.testCertificateValueSetsDe
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.ValueSetTestData.testCertificateValueSetsEn
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.ValueSetTestData.vaccinationValueSetsDe
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.ValueSetTestData.vaccinationValueSetsEn
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.ValueSetTestData.valueSetsContainerDe
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.ValueSetTestData.valueSetsContainerEn
+import de.rki.coronawarnapp.covidcertificate.valueset.server.CertificateValueSetServer
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.ValueSetsStorage
+import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.emptyValueSetsContainer
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.Ordering
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.just
+import io.mockk.runs
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.first
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import testhelpers.TestDispatcherProvider
+import testhelpers.coroutines.runBlockingTest2
+import java.util.Locale
+
+class ValueSetsRepositoryTest : BaseTest() {
+
+    @MockK lateinit var certificateValueSetServer: CertificateValueSetServer
+    @MockK lateinit var valueSetsStorage: ValueSetsStorage
+
+    private val testDispatcherProvider = TestDispatcherProvider()
+
+    private fun createInstance(scope: CoroutineScope) = ValueSetsRepository(
+        certificateValueSetServer = certificateValueSetServer,
+        valueSetsStorage = valueSetsStorage,
+        scope = scope,
+        dispatcherProvider = testDispatcherProvider
+    )
+
+    @BeforeEach
+    fun setUp() {
+        MockKAnnotations.init(this)
+        coEvery { certificateValueSetServer.getVaccinationValueSets(any()) } returns
+            null
+        coEvery { certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) } returns
+            valueSetsContainerEn
+        coEvery { certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.GERMAN) } returns
+            valueSetsContainerDe
+        every { certificateValueSetServer.clear() } just runs
+
+        every { valueSetsStorage.valueSetsContainer = any() } just runs
+        every { valueSetsStorage.valueSetsContainer } returns emptyValueSetsContainer
+    }
+
+    @Test
+    fun `successful update for de`() = runBlockingTest2(ignoreActive = true) {
+        createInstance(this).run {
+            triggerUpdateValueSet(languageCode = Locale.GERMAN)
+            latestVaccinationValueSets.first() shouldBe vaccinationValueSetsDe
+            latestTestCertificateValueSets.first() shouldBe testCertificateValueSetsDe
+        }
+
+        coVerify {
+            certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.GERMAN)
+            valueSetsStorage.valueSetsContainer = valueSetsContainerDe
+        }
+
+        coVerify(exactly = 0) {
+            certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.ENGLISH)
+            valueSetsStorage.valueSetsContainer = valueSetsContainerEn
+        }
+    }
+
+    @Test
+    fun `fallback to en`() = runBlockingTest2(ignoreActive = true) {
+        createInstance(this).run {
+            triggerUpdateValueSet(languageCode = Locale.FRENCH)
+            latestVaccinationValueSets.first() shouldBe vaccinationValueSetsEn
+            latestTestCertificateValueSets.first() shouldBe testCertificateValueSetsEn
+        }
+
+        coVerify(ordering = Ordering.ORDERED) {
+            certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.FRENCH)
+            certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.ENGLISH)
+            valueSetsStorage.valueSetsContainer = valueSetsContainerEn
+        }
+    }
+
+    @Test
+    fun `server returns nothing`() = runBlockingTest2(ignoreActive = true) {
+        coEvery { certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.GERMAN) } returns null
+        coEvery { certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) } returns null
+
+        createInstance(this).run {
+            triggerUpdateValueSet(languageCode = Locale.GERMAN)
+            emptyValueSetsContainer.also {
+                latestVaccinationValueSets.first() shouldBe it.vaccinationValueSets
+                latestTestCertificateValueSets.first() shouldBe it.testCertificateValueSets
+            }
+        }
+
+        coVerify(ordering = Ordering.ORDERED) {
+            certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.GERMAN)
+            certificateValueSetServer.getVaccinationValueSets(languageCode = Locale.ENGLISH)
+        }
+    }
+
+    @Test
+    fun `clear data of server and local storage`() = runBlockingTest2(ignoreActive = true) {
+        createInstance(this).run {
+            clear()
+
+            emptyValueSetsContainer.also {
+                latestVaccinationValueSets.first() shouldBe it.vaccinationValueSets
+                latestTestCertificateValueSets.first() shouldBe it.testCertificateValueSets
+            }
+
+            coVerify {
+                certificateValueSetServer.clear()
+                valueSetsStorage.valueSetsContainer = emptyValueSetsContainer
+            }
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSetServerTest.kt
similarity index 90%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServerTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSetServerTest.kt
index 1c78f8412ea1d883b5e9881b0e4b79d626959539..bd18b0305bdffb453a2d1a7d25a613f236e17116 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServerTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/valueset/server/CertificateValueSetServerTest.kt
@@ -1,9 +1,9 @@
-package de.rki.coronawarnapp.vaccination.core.server.valueset
+package de.rki.coronawarnapp.covidcertificate.valueset.server
 
 import dagger.Lazy
+import de.rki.coronawarnapp.covidcertificate.valueset.internal.ValueSetInvalidSignatureException
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.security.SignatureValidation
-import de.rki.coronawarnapp.vaccination.core.server.valueset.internal.ValueSetInvalidSignatureException
 import io.kotest.assertions.throwables.shouldThrow
 import io.kotest.matchers.shouldBe
 import io.kotest.matchers.shouldNotBe
@@ -19,7 +19,7 @@ import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 import java.io.File
 
-class VaccinationServerTest : BaseTest() {
+class CertificateValueSetServerTest : BaseTest() {
 
     /**
      * contains both binary and signature
@@ -32,7 +32,7 @@ class VaccinationServerTest : BaseTest() {
     private val invalidExportZip = File("src/test/resources/vaccination/valueset_invalid.zip")
 
     @MockK lateinit var cache: Cache
-    @MockK lateinit var apiV1: Lazy<VaccinationValueSetApiV1>
+    @MockK lateinit var apiV1: Lazy<CertificateValueSetApiV1>
     @MockK lateinit var dispatcherProvider: DispatcherProvider
     @MockK lateinit var signatureValidation: SignatureValidation
 
@@ -43,7 +43,7 @@ class VaccinationServerTest : BaseTest() {
         invalidExportZip.exists() shouldBe true
     }
 
-    private fun createInstance() = VaccinationServer(
+    private fun createInstance() = CertificateValueSetServer(
         cache,
         apiV1,
         dispatcherProvider,
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/testresult/AnalyticsRATestResultDonorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/testresult/AnalyticsRATestResultDonorTest.kt
index c2cd808c38cfc65f4d2b39d1834cfd60ae45aac0..5557a2ee486d001221de84d956d13d31a09f4d29 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/testresult/AnalyticsRATestResultDonorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/testresult/AnalyticsRATestResultDonorTest.kt
@@ -65,13 +65,13 @@ class AnalyticsRATestResultDonorTest : BaseTest() {
 
     @Test
     fun `No donation when test result is INVALID`() = runBlockingTest {
-        every { testResultSettings.testResultAtRegistration } returns mockFlowPreference(CoronaTestResult.PCR_INVALID)
+        every { testResultSettings.testResultAtRegistration } returns mockFlowPreference(CoronaTestResult.RAT_INVALID)
         testResultDonor.beginDonation(TestRequest) shouldBe AnalyticsTestResultDonor.TestResultMetadataNoContribution
     }
 
     @Test
     fun `No donation when test result is REDEEMED`() = runBlockingTest {
-        every { testResultSettings.testResultAtRegistration } returns mockFlowPreference(CoronaTestResult.PCR_REDEEMED)
+        every { testResultSettings.testResultAtRegistration } returns mockFlowPreference(CoronaTestResult.RAT_REDEEMED)
         testResultDonor.beginDonation(TestRequest) shouldBe AnalyticsTestResultDonor.TestResultMetadataNoContribution
     }
 
@@ -98,7 +98,7 @@ class AnalyticsRATestResultDonorTest : BaseTest() {
                 testResultDonor.beginDonation(TestRequest) as AnalyticsTestResultDonor.TestResultMetadataContribution
             with(donation.testResultMetadata) {
                 riskLevelAtTestRegistration shouldBe PpaData.PPARiskLevel.RISK_LEVEL_LOW
-                testResult shouldBe PpaData.PPATestResult.TEST_RESULT_PENDING
+                testResult shouldBe PpaData.PPATestResult.TEST_RESULT_RAT_PENDING
                 hoursSinceTestRegistration shouldBe 24
                 hoursSinceHighRiskWarningAtTestRegistration shouldBe 1
                 daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 1
@@ -110,14 +110,14 @@ class AnalyticsRATestResultDonorTest : BaseTest() {
     fun `Donation is collected when test result is POSITIVE`() {
         runBlockingTest {
             every { testResultSettings.testResultAtRegistration } returns
-                mockFlowPreference(CoronaTestResult.PCR_POSITIVE)
+                mockFlowPreference(CoronaTestResult.RAT_POSITIVE)
             every { testResultSettings.finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
 
             val donation =
                 testResultDonor.beginDonation(TestRequest) as AnalyticsTestResultDonor.TestResultMetadataContribution
             with(donation.testResultMetadata) {
                 riskLevelAtTestRegistration shouldBe PpaData.PPARiskLevel.RISK_LEVEL_LOW
-                testResult shouldBe PpaData.PPATestResult.TEST_RESULT_POSITIVE
+                testResult shouldBe PpaData.PPATestResult.TEST_RESULT_RAT_POSITIVE
                 hoursSinceTestRegistration shouldBe 0
                 hoursSinceHighRiskWarningAtTestRegistration shouldBe 1
                 daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 1
@@ -129,14 +129,14 @@ class AnalyticsRATestResultDonorTest : BaseTest() {
     fun `Donation is collected when test result is NEGATIVE`() {
         runBlockingTest {
             every { testResultSettings.testResultAtRegistration } returns
-                mockFlowPreference(CoronaTestResult.PCR_NEGATIVE)
+                mockFlowPreference(CoronaTestResult.RAT_NEGATIVE)
             every { testResultSettings.finalTestResultReceivedAt } returns mockFlowPreference(baseTime)
 
             val donation =
                 testResultDonor.beginDonation(TestRequest) as AnalyticsTestResultDonor.TestResultMetadataContribution
             with(donation.testResultMetadata) {
                 riskLevelAtTestRegistration shouldBe PpaData.PPARiskLevel.RISK_LEVEL_LOW
-                testResult shouldBe PpaData.PPATestResult.TEST_RESULT_NEGATIVE
+                testResult shouldBe PpaData.PPATestResult.TEST_RESULT_RAT_NEGATIVE
                 hoursSinceTestRegistration shouldBe 0
                 hoursSinceHighRiskWarningAtTestRegistration shouldBe 1
                 daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 1
@@ -147,7 +147,7 @@ class AnalyticsRATestResultDonorTest : BaseTest() {
     @Test
     fun `Scenario 1 LowRisk`() = runBlockingTest {
         with(testResultSettings) {
-            every { testResultAtRegistration } returns mockFlowPreference(CoronaTestResult.PCR_NEGATIVE)
+            every { testResultAtRegistration } returns mockFlowPreference(CoronaTestResult.RAT_NEGATIVE)
             every { finalTestResultReceivedAt } returns mockFlowPreference(
                 Instant.parse("2021-03-20T20:00:00Z")
             )
@@ -161,7 +161,7 @@ class AnalyticsRATestResultDonorTest : BaseTest() {
         val donation =
             testResultDonor.beginDonation(TestRequest) as AnalyticsTestResultDonor.TestResultMetadataContribution
         with(donation.testResultMetadata) {
-            testResult shouldBe PpaData.PPATestResult.TEST_RESULT_NEGATIVE
+            testResult shouldBe PpaData.PPATestResult.TEST_RESULT_RAT_NEGATIVE
             hoursSinceTestRegistration shouldBe 20
             riskLevelAtTestRegistration shouldBe PpaData.PPARiskLevel.RISK_LEVEL_LOW
             hoursSinceHighRiskWarningAtTestRegistration shouldBe 1
@@ -172,7 +172,7 @@ class AnalyticsRATestResultDonorTest : BaseTest() {
     @Test
     fun `Scenario 2 HighRisk`() = runBlockingTest {
         with(testResultSettings) {
-            every { testResultAtRegistration } returns mockFlowPreference(CoronaTestResult.PCR_POSITIVE)
+            every { testResultAtRegistration } returns mockFlowPreference(CoronaTestResult.RAT_POSITIVE)
             every { finalTestResultReceivedAt } returns mockFlowPreference(
                 Instant.parse("2021-03-20T20:00:00Z")
             )
@@ -187,7 +187,7 @@ class AnalyticsRATestResultDonorTest : BaseTest() {
         val donation =
             testResultDonor.beginDonation(TestRequest) as AnalyticsTestResultDonor.TestResultMetadataContribution
         with(donation.testResultMetadata) {
-            testResult shouldBe PpaData.PPATestResult.TEST_RESULT_POSITIVE
+            testResult shouldBe PpaData.PPATestResult.TEST_RESULT_RAT_POSITIVE
             hoursSinceTestRegistration shouldBe 20 // hours
             riskLevelAtTestRegistration shouldBe PpaData.PPARiskLevel.RISK_LEVEL_HIGH
             hoursSinceHighRiskWarningAtTestRegistration shouldBe 1
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt
index 12b178e9db9fd377c5eadcb406fb522a264d50e9..b1a4b64e49f5795c3d56b1ebabf26af5edcdb7c5 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt
@@ -68,6 +68,7 @@ class EnvironmentSetupTest : BaseTest() {
                 dataDonationCdnUrl shouldBe "https://datadonation-${env.rawKey}"
                 logUploadServerUrl shouldBe "https://logupload-${env.rawKey}"
                 crowdNotifierPublicKey shouldBe "123_abc-${env.rawKey}"
+                dccServerUrl shouldBe "https://dcc-${env.rawKey}"
             }
         }
     }
@@ -127,7 +128,8 @@ class EnvironmentSetupTest : BaseTest() {
         EnvironmentSetup.EnvKey.LOG_UPLOAD.rawKey shouldBe "LOG_UPLOAD_SERVER_URL"
         EnvironmentSetup.EnvKey.SAFETYNET_API_KEY.rawKey shouldBe "SAFETYNET_API_KEY"
         EnvironmentSetup.EnvKey.CROWD_NOTIFIER_PUBLIC_KEY.rawKey shouldBe "CROWD_NOTIFIER_PUBLIC_KEY"
-        EnvironmentSetup.EnvKey.values().size shouldBe 9
+        EnvironmentSetup.EnvKey.DCC.rawKey shouldBe "DCC_SERVER_URL"
+        EnvironmentSetup.EnvKey.values().size shouldBe 10
     }
 
     companion object {
@@ -152,7 +154,8 @@ class EnvironmentSetupTest : BaseTest() {
                     "VACCINATION_CDN_URL": "https://vaccination-PROD",
                     "SAFETYNET_API_KEY": "placeholder-PROD",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-PROD",
-                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-PROD"                    
+                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-PROD",
+                    "DCC_SERVER_URL": "https://dcc-PROD"
                 },
                 "DEV": {
                     "USE_EUR_KEY_PKGS" : false,
@@ -164,7 +167,8 @@ class EnvironmentSetupTest : BaseTest() {
                     "VACCINATION_CDN_URL": "https://vaccination-DEV",
                     "SAFETYNET_API_KEY": "placeholder-DEV",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-DEV",
-                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-DEV"
+                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-DEV",
+                    "DCC_SERVER_URL": "https://dcc-DEV"
                },
                 "INT": {
                     "USE_EUR_KEY_PKGS" : false,
@@ -176,7 +180,8 @@ class EnvironmentSetupTest : BaseTest() {
                     "VACCINATION_CDN_URL": "https://vaccination-INT",
                     "SAFETYNET_API_KEY": "placeholder-INT",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-INT",
-                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-INT"
+                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-INT",
+                    "DCC_SERVER_URL": "https://dcc-INT"
                 },
                 "WRU": {
                     "USE_EUR_KEY_PKGS" : false,
@@ -189,7 +194,8 @@ class EnvironmentSetupTest : BaseTest() {
                     "SAFETYNET_API_KEY": "placeholder-WRU",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU",
                     "CREATE_TRACELOCATION_URL": "https://tracelocation-WRU",
-                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU"
+                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU",
+                    "DCC_SERVER_URL": "https://dcc-WRU"
                 },
                 "WRU-XD": {
                     "USE_EUR_KEY_PKGS" : true,
@@ -201,7 +207,8 @@ class EnvironmentSetupTest : BaseTest() {
                     "VACCINATION_CDN_URL": "https://vaccination-WRU-XD",
                     "SAFETYNET_API_KEY": "placeholder-WRU-XD",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU-XD",
-                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU-XD"
+                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU-XD",
+                    "DCC_SERVER_URL": "https://dcc-WRU-XD"
                 },
                 "WRU-XA": {
                     "USE_EUR_KEY_PKGS" : true,
@@ -213,7 +220,8 @@ class EnvironmentSetupTest : BaseTest() {
                     "VACCINATION_CDN_URL": "https://vaccination-WRU-XA",
                     "SAFETYNET_API_KEY": "placeholder-WRU-XA",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU-XA",
-                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU-XA"
+                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-WRU-XA",
+                    "DCC_SERVER_URL": "https://dcc-WRU-XA"
                 },
                 "TESTER-MOCK": {
                     "USE_EUR_KEY_PKGS" : true,
@@ -225,7 +233,8 @@ class EnvironmentSetupTest : BaseTest() {
                     "VACCINATION_CDN_URL": "https://vaccination-TESTER-MOCK",
                     "SAFETYNET_API_KEY": "placeholder-TESTER-MOCK",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-TESTER-MOCK",
-                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-TESTER-MOCK"
+                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-TESTER-MOCK",
+                    "DCC_SERVER_URL": "https://dcc-TESTER-MOCK"
                 },
                 "LOCAL": {
                     "USE_EUR_KEY_PKGS" : true,
@@ -237,7 +246,8 @@ class EnvironmentSetupTest : BaseTest() {
                     "VACCINATION_CDN_URL": "https://vaccination-LOCAL",
                     "SAFETYNET_API_KEY": "placeholder-LOCAL",
                     "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-LOCAL",
-                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-LOCAL"
+                    "CROWD_NOTIFIER_PUBLIC_KEY": "123_abc-LOCAL",
+                    "DCC_SERVER_URL": "https://dcc-LOCAL"
                 }
             }
         """
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt
index 0a3643766fb3685c31d66345b3c777a2d1b90ee9..7207e5d906348755d0391d887d1ba26c67c8103e 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/MainActivityViewModelTest.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.main
 
 import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationSettings
 import de.rki.coronawarnapp.environment.EnvironmentSetup
 import de.rki.coronawarnapp.playbook.BackgroundNoise
 import de.rki.coronawarnapp.presencetracing.TraceLocationSettings
@@ -9,7 +10,6 @@ import de.rki.coronawarnapp.storage.OnboardingSettings
 import de.rki.coronawarnapp.ui.main.MainActivityViewModel
 import de.rki.coronawarnapp.util.CWADebug
 import de.rki.coronawarnapp.util.device.BackgroundModeStatus
-import de.rki.coronawarnapp.vaccination.core.VaccinationSettings
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.every
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/home/HomeFragmentViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/home/HomeFragmentViewModelTest.kt
index 7d9d96f3fa5151fff19408411c86ef342dc572ee..4ebef57b07e20691b991a50b97adb85bbede6c76 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/home/HomeFragmentViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/main/home/HomeFragmentViewModelTest.kt
@@ -3,6 +3,8 @@ package de.rki.coronawarnapp.main.home
 import android.content.Context
 import de.rki.coronawarnapp.appconfig.AppConfigProvider
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationSettings
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
 import de.rki.coronawarnapp.environment.BuildConfigWrap
 import de.rki.coronawarnapp.main.CWASettings
 import de.rki.coronawarnapp.statistics.source.StatisticsProvider
@@ -21,8 +23,6 @@ import de.rki.coronawarnapp.util.TimeStamper
 import de.rki.coronawarnapp.util.bluetooth.BluetoothSupport
 import de.rki.coronawarnapp.util.encryptionmigration.EncryptionErrorResetTool
 import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper
-import de.rki.coronawarnapp.vaccination.core.VaccinationSettings
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.coEvery
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateViewModelTest.kt
similarity index 99%
rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateViewModelTest.kt
rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateViewModelTest.kt
index bd9be00a552e0f6721b82097711e3917eb2e901f..009f839c5c79d3bfed61a95225a0f6cea8335c89 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/greencertificate/RequestCovidCertificateViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/covidcertificate/RequestCovidCertificateViewModelTest.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.ui.submission.greencertificate
+package de.rki.coronawarnapp.ui.submission.covidcertificate
 
 import androidx.lifecycle.MutableLiveData
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
@@ -20,8 +20,8 @@ import kotlinx.coroutines.flow.flowOf
 import org.joda.time.Instant
 import org.joda.time.LocalDate
 import org.joda.time.format.DateTimeFormat
-import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
 import testhelpers.BaseTest
 import testhelpers.extensions.InstantExecutorExtension
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/DataResetTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/DataResetTest.kt
index 6f8799d44b824ac8e8c98399a916ed11934e1e52..50d196f8cf8b6fc920755e1344c9f5df78b92943 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/DataResetTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/DataResetTest.kt
@@ -6,6 +6,10 @@ import de.rki.coronawarnapp.contactdiary.storage.ContactDiaryPreferences
 import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfileSettings
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationPreferences
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
+import de.rki.coronawarnapp.covidcertificate.valueset.ValueSetsRepository
 import de.rki.coronawarnapp.datadonation.analytics.Analytics
 import de.rki.coronawarnapp.datadonation.analytics.storage.AnalyticsSettings
 import de.rki.coronawarnapp.datadonation.survey.SurveySettings
@@ -24,9 +28,6 @@ import de.rki.coronawarnapp.storage.TracingSettings
 import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.submission.SubmissionSettings
 import de.rki.coronawarnapp.ui.presencetracing.TraceLocationPreferences
-import de.rki.coronawarnapp.vaccination.core.VaccinationPreferences
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
-import de.rki.coronawarnapp.vaccination.core.repository.ValueSetsRepository
 import io.mockk.MockKAnnotations
 import io.mockk.coVerify
 import io.mockk.impl.annotations.MockK
@@ -64,6 +65,7 @@ internal class DataResetTest : BaseTest() {
     @MockK lateinit var vaccinationRepository: VaccinationRepository
     @MockK lateinit var vaccinationPreferences: VaccinationPreferences
     @MockK lateinit var valueSetsRepository: ValueSetsRepository
+    @MockK lateinit var testCertificateRepository: TestCertificateRepository
 
     @BeforeEach
     fun setUp() {
@@ -97,7 +99,8 @@ internal class DataResetTest : BaseTest() {
         ratProfileSettings = ratProfileSettings,
         vaccinationPreferences = vaccinationPreferences,
         vaccinationRepository = vaccinationRepository,
-        valueSetsRepository = valueSetsRepository
+        valueSetsRepository = valueSetsRepository,
+        testCertificateRepository = testCertificateRepository,
     )
 
     @Test
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/worker/WorkerBinderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/worker/WorkerBinderTest.kt
index d5ec4edc888f4f9282dad53a14fea4e194f454fe..c04bcf04992aabd614ba0a0420a86f734e00e92a 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/worker/WorkerBinderTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/worker/WorkerBinderTest.kt
@@ -10,6 +10,8 @@ import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.coronatest.type.pcr.execution.PCRResultScheduler
 import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.execution.RAResultScheduler
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepository
 import de.rki.coronawarnapp.datadonation.analytics.Analytics
 import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsScheduler
 import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler
@@ -28,7 +30,6 @@ import de.rki.coronawarnapp.submission.SubmissionRepository
 import de.rki.coronawarnapp.task.TaskController
 import de.rki.coronawarnapp.util.di.AppContext
 import de.rki.coronawarnapp.util.serialization.BaseGson
-import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository
 import io.github.classgraph.ClassGraph
 import io.kotest.matchers.collections.shouldContainAll
 import io.mockk.mockk
@@ -172,4 +173,7 @@ class MockProvider {
 
     @Provides
     fun vaccinationRepository(): VaccinationRepository = mockk()
+
+    @Provides
+    fun testCertificateRepository(): TestCertificateRepository = mockk()
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/ValueSetTestData.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/ValueSetTestData.kt
deleted file mode 100644
index 67e7a01f66f51fee0b09e1f2ea82cdec55a1a1af..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/ValueSetTestData.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core
-
-import de.rki.coronawarnapp.vaccination.core.repository.storage.ValueSetsStorage
-import de.rki.coronawarnapp.vaccination.core.server.valueset.DefaultVaccinationValueSet
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet
-import io.kotest.matchers.shouldBe
-import java.util.Locale
-
-object ValueSetTestData {
-
-    val vpItemDe = "1119305005" to "Impfstoff-Name"
-    val mpItemDe = "EU/1/21/1529" to "Arzneimittel-Name"
-    val maItemDe = "ORG-100001699" to "Hersteller-Name"
-
-    val vpItemEn = vpItemDe.copy(second = "Vaccine-Name")
-    val mpItemEn = mpItemDe.copy(second = "MedicalProduct-Name")
-    val maItemEn = maItemDe.copy(second = "Manufactorer-Name")
-
-    val storedValueSetDe = ValueSetsStorage.StoredVaccinationValueSet(
-        languageCode = Locale.GERMAN,
-        vp = createStoredValueSet(vpItemDe),
-        mp = createStoredValueSet(mpItemDe),
-        ma = createStoredValueSet(maItemDe)
-    )
-
-    val storedValueSetEn = ValueSetsStorage.StoredVaccinationValueSet(
-        languageCode = Locale.ENGLISH,
-        vp = createStoredValueSet(vpItemEn),
-        mp = createStoredValueSet(mpItemEn),
-        ma = createStoredValueSet(maItemEn)
-    )
-
-    val emptyStoredValueSet = ValueSetsStorage.StoredVaccinationValueSet(
-        languageCode = Locale.ENGLISH,
-        vp = ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet(items = emptyList()),
-        mp = ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet(items = emptyList()),
-        ma = ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet(items = emptyList())
-    )
-
-    val valueSetDe = DefaultVaccinationValueSet(
-        languageCode = Locale.GERMAN,
-        vp = createValueSet(vpItemDe),
-        mp = createValueSet(mpItemDe),
-        ma = createValueSet(maItemDe)
-    )
-
-    val valueSetEn = DefaultVaccinationValueSet(
-        languageCode = Locale.ENGLISH,
-        vp = createValueSet(vpItemEn),
-        mp = createValueSet(mpItemEn),
-        ma = createValueSet(maItemEn)
-    )
-
-    val emptyValueSetEn = emptyStoredValueSet
-
-    fun createStoredValueSet(keyText: Pair<String, String>): ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet {
-        val item = ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet.StoredItem(
-            key = keyText.first,
-            displayText = keyText.second
-        )
-        return ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet(items = listOf(item))
-    }
-
-    fun createValueSet(keyText: Pair<String, String>): DefaultVaccinationValueSet.DefaultValueSet {
-        val item = DefaultVaccinationValueSet.DefaultValueSet.DefaultItem(
-            key = keyText.first,
-            displayText = keyText.second
-        )
-        return DefaultVaccinationValueSet.DefaultValueSet(items = listOf(item))
-    }
-}
-
-fun VaccinationValueSet.validateValues(v2: VaccinationValueSet) {
-    languageCode shouldBe v2.languageCode
-    vp.validateValues(v2.vp)
-    mp.validateValues(v2.mp)
-    ma.validateValues(v2.ma)
-}
-
-fun VaccinationValueSet.ValueSet.validateValues(v2: VaccinationValueSet.ValueSet) {
-    items.forEachIndexed { index, item1 ->
-        val item2 = v2.items[index]
-
-        item1.key shouldBe item2.key
-        item1.displayText shouldBe item2.displayText
-    }
-}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepositoryTest.kt
deleted file mode 100644
index 3ac9576d02d0740117dafee40677906c2aed214d..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepositoryTest.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.repository
-
-import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.emptyValueSetEn
-import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.valueSetDe
-import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.valueSetEn
-import de.rki.coronawarnapp.vaccination.core.repository.storage.ValueSetsStorage
-import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationServer
-import de.rki.coronawarnapp.vaccination.core.validateValues
-import io.mockk.MockKAnnotations
-import io.mockk.Ordering
-import io.mockk.coEvery
-import io.mockk.coVerify
-import io.mockk.every
-import io.mockk.impl.annotations.MockK
-import io.mockk.just
-import io.mockk.runs
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.first
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import testhelpers.BaseTest
-import testhelpers.TestDispatcherProvider
-import testhelpers.coroutines.runBlockingTest2
-import java.util.Locale
-
-class ValueSetsRepositoryTest : BaseTest() {
-
-    @MockK lateinit var vaccinationServer: VaccinationServer
-    @MockK lateinit var valueSetsStorage: ValueSetsStorage
-
-    private val testDispatcherProvider = TestDispatcherProvider()
-
-    private fun createInstance(scope: CoroutineScope) = ValueSetsRepository(
-        vaccinationServer = vaccinationServer,
-        valueSetsStorage = valueSetsStorage,
-        scope = scope,
-        dispatcherProvider = testDispatcherProvider
-    )
-
-    @BeforeEach
-    fun setUp() {
-        MockKAnnotations.init(this)
-        coEvery { vaccinationServer.getVaccinationValueSets(any()) } returns null
-        coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) } returns valueSetEn
-        coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) } returns valueSetDe
-        every { vaccinationServer.clear() } just runs
-
-        every { valueSetsStorage.vaccinationValueSet = any() } just runs
-        every { valueSetsStorage.vaccinationValueSet } returns emptyValueSetEn
-    }
-
-    @Test
-    fun `successful update for de`() = runBlockingTest2(ignoreActive = true) {
-        createInstance(this).run {
-            triggerUpdateValueSet(languageCode = Locale.GERMAN)
-            latestValueSet.first()
-        }.also { it.validateValues(valueSetDe) }
-
-        coVerify {
-            vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN)
-            valueSetsStorage.vaccinationValueSet = valueSetDe
-        }
-
-        coVerify(exactly = 0) {
-            vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH)
-            valueSetsStorage.vaccinationValueSet = valueSetEn
-        }
-    }
-
-    @Test
-    fun `fallback to en`() = runBlockingTest2(ignoreActive = true) {
-        createInstance(this).run {
-            triggerUpdateValueSet(languageCode = Locale.FRENCH)
-            latestValueSet.first()
-        }.also { it.validateValues(valueSetEn) }
-
-        coVerify(ordering = Ordering.ORDERED) {
-            vaccinationServer.getVaccinationValueSets(languageCode = Locale.FRENCH)
-            vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH)
-            valueSetsStorage.vaccinationValueSet = valueSetEn
-        }
-    }
-
-    @Test
-    fun `server returns nothing`() = runBlockingTest2(ignoreActive = true) {
-        coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) } returns null
-        coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) } returns null
-
-        createInstance(this).run {
-            triggerUpdateValueSet(languageCode = Locale.GERMAN)
-            latestValueSet.first()
-        }.also { it.validateValues(emptyValueSetEn) }
-
-        coVerify(ordering = Ordering.ORDERED) {
-            vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN)
-            vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH)
-        }
-    }
-
-    @Test
-    fun `clear data of server and local storage`() = runBlockingTest2(ignoreActive = true) {
-        createInstance(this).run {
-            clear()
-
-            latestValueSet.first().validateValues(emptyValueSetEn)
-
-            coVerify {
-                vaccinationServer.clear()
-                valueSetsStorage.vaccinationValueSet = emptyValueSetEn
-            }
-        }
-    }
-}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorageTest.kt
deleted file mode 100644
index 8b68c38cc0cd1b7424eec1a14e22858d4974e26d..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorageTest.kt
+++ /dev/null
@@ -1,142 +0,0 @@
-package de.rki.coronawarnapp.vaccination.core.repository.storage
-
-import android.content.Context
-import de.rki.coronawarnapp.util.serialization.SerializationModule
-import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.emptyStoredValueSet
-import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.emptyValueSetEn
-import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.storedValueSetDe
-import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.storedValueSetEn
-import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.valueSetDe
-import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.valueSetEn
-import de.rki.coronawarnapp.vaccination.core.validateValues
-import io.kotest.matchers.shouldBe
-import io.kotest.matchers.shouldNotBe
-import io.mockk.MockKAnnotations
-import io.mockk.every
-import io.mockk.impl.annotations.MockK
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import testhelpers.BaseTest
-import testhelpers.extensions.toComparableJsonPretty
-import testhelpers.preferences.MockSharedPreferences
-
-class ValueSetsStorageTest : BaseTest() {
-
-    @MockK lateinit var context: Context
-    lateinit var prefs: MockSharedPreferences
-
-    private val gson = SerializationModule().baseGson()
-
-    @BeforeEach
-    fun setup() {
-        MockKAnnotations.init(this)
-        prefs = MockSharedPreferences()
-        every { context.getSharedPreferences("valuesets_localdata", Context.MODE_PRIVATE) } returns prefs
-    }
-
-    private fun createInstance() = ValueSetsStorage(
-        context = context,
-        gson = gson
-    )
-
-    @Test
-    fun `Default value is an empty value set`() {
-        createInstance().vaccinationValueSet.validateValues(emptyValueSetEn)
-    }
-
-    @Test
-    fun `Updates values`() {
-        createInstance().run {
-            vaccinationValueSet = storedValueSetDe
-            vaccinationValueSet shouldBe storedValueSetDe
-
-            vaccinationValueSet = storedValueSetEn
-            vaccinationValueSet shouldBe storedValueSetEn
-        }
-    }
-
-    @Test
-    fun `Check mapping is correct`() {
-        createInstance().run {
-            storedValueSetDe.also { it.toStoredVaccinationValueSet() shouldBe it }
-
-            storedValueSetEn.also { it.toStoredVaccinationValueSet() shouldBe it }
-
-            valueSetDe.also {
-                it.toStoredVaccinationValueSet() shouldBe storedValueSetDe
-                it.toStoredVaccinationValueSet().validateValues(it)
-            }
-
-            valueSetEn.also {
-                it.toStoredVaccinationValueSet() shouldBe storedValueSetEn
-                it.toStoredVaccinationValueSet().validateValues(it)
-            }
-
-            emptyValueSetEn.also {
-                it.toStoredVaccinationValueSet() shouldBe emptyStoredValueSet
-                it.toStoredVaccinationValueSet().validateValues(it)
-            }
-        }
-    }
-
-    @Test
-    fun `storage inits empty without sideeffects`() {
-        createInstance().vaccinationValueSet shouldNotBe null
-        prefs.dataMapPeek.isEmpty() shouldBe true
-    }
-
-    @Test
-    fun `storage format`() {
-        createInstance().vaccinationValueSet = storedValueSetDe
-        (prefs.dataMapPeek["valueset"] as String).toComparableJsonPretty() shouldBe """
-            {
-              "languageCode": "de",
-              "vp": {
-                "items": [
-                  {
-                    "key": "1119305005",
-                    "displayText": "Impfstoff-Name"
-                  }
-                ]
-              },
-              "mp": {
-                "items": [
-                  {
-                    "key": "EU/1/21/1529",
-                    "displayText": "Arzneimittel-Name"
-                  }
-                ]
-              },
-              "ma": {
-                "items": [
-                  {
-                    "key": "ORG-100001699",
-                    "displayText": "Hersteller-Name"
-                  }
-                ]
-              }
-            }
-        """.toComparableJsonPretty()
-
-        createInstance().apply {
-            vaccinationValueSet shouldBe storedValueSetDe
-            vaccinationValueSet = emptyStoredValueSet
-        }
-        (prefs.dataMapPeek["valueset"] as String).toComparableJsonPretty() shouldBe """
-            {
-              "languageCode": "en",
-              "vp": {
-                "items": []
-              },
-              "mp": {
-                "items": []
-              },
-              "ma": {
-                "items": []
-              }
-            }
-        """.toComparableJsonPretty()
-
-        createInstance().vaccinationValueSet shouldBe emptyStoredValueSet
-    }
-}
diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt
index c1b802516a2f5aa590dd3cf5ba6fcbd6d23e5906..d4089a51bba7db5dcd3b5f2afe18f5dc82a6702f 100644
--- a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt
+++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt
@@ -33,13 +33,10 @@ class DebugOptionsFragmentViewModelTest : BaseTestInstrumentation() {
         every { environmentSetup.logUploadServerUrl } returns "logUploadServerUrl"
         every { environmentSetup.crowdNotifierPublicKey } returns "crowdNotifierPublicKey"
         every { environmentSetup.appConfigPublicKey } returns "appConfigPublicKey"
+        every { environmentSetup.dccServerUrl } returns "dccServerUrl"
 
-        every { environmentSetup.currentEnvironment = any() } answers {
-            currentEnvironment = arg(0)
-        }
-        every { environmentSetup.currentEnvironment } answers {
-            currentEnvironment
-        }
+        every { environmentSetup.currentEnvironment = any() } answers { currentEnvironment = arg(0) }
+        every { environmentSetup.currentEnvironment } answers { currentEnvironment }
     }
 
     private fun createViewModel(): DebugOptionsFragmentViewModel = DebugOptionsFragmentViewModel(
@@ -48,7 +45,7 @@ class DebugOptionsFragmentViewModelTest : BaseTestInstrumentation() {
     )
 
     @Test
-    fun `toggeling the env works`() {
+    fun `toggling the env works`() {
         currentEnvironment = EnvironmentSetup.Type.DEV
         val vm = createViewModel()
         vm.environmentState.getOrAwaitValue().current shouldBe EnvironmentSetup.Type.DEV
diff --git a/build.gradle b/build.gradle
index 9e108b1eec46c28d5926b0b95ea0e377c676be41..0d2649f9d90739ee876b3f77651c95d26fa55228 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,7 +3,7 @@
 buildscript {
     ext.kotlin_version = '1.5.0'
     ext.protobufVersion = '0.8.12'
-    ext.navVersion = "2.2.2"
+    ext.nav_version = "2.3.5"
 
     repositories {
         google()
@@ -16,7 +16,7 @@ buildscript {
         classpath 'com.android.tools.build:gradle:4.2.1'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
         classpath "com.google.protobuf:protobuf-gradle-plugin:$protobufVersion"
-        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navVersion"
+        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
         classpath "org.jlleitschuh.gradle:ktlint-gradle:10.0.0"
         classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.17.0"
 
diff --git a/gradle.properties b/gradle.properties
index d21f5a095e379f7f1140f76bb831b4b51da3ecd6..d98e11727136326d6d0f7342711860e6961f8f7a 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -20,4 +20,4 @@ org.gradle.dependency.verification.console=verbose
 VERSION_MAJOR=2
 VERSION_MINOR=4
 VERSION_PATCH=0
-VERSION_BUILD=5
+VERSION_BUILD=7
diff --git a/translation_v2.json b/translation_v2.json
index 286c27bb7e472ca064376dfb75f361d424b53a59..a5c864007ef79c13cfbbc071c2fb16fd65c8b0c9 100644
--- a/translation_v2.json
+++ b/translation_v2.json
@@ -12,7 +12,8 @@
             "event_registration_strings.xml",
             "antigen_strings.xml",
             "vaccination_strings.xml",
-            "green_certificate_strings.xml"
+            "green_certificate_strings.xml",
+            "green_certificate_attribute_strings.xml"
           ],
           "targetFolderPath": "../values-[langCode]"
         }