diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/VerifiedTraceLocationTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/VerifiedTraceLocationTest.kt
index 838f409bdb9bc1c4308d1db22993d2fc90e19238..2e78d0912c047be24b4ab9c53a46da693f0deaf7 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/VerifiedTraceLocationTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/VerifiedTraceLocationTest.kt
@@ -1,13 +1,10 @@
 package de.rki.coronawarnapp.eventregistration.checkins.qrcode
 
-import de.rki.coronawarnapp.environment.EnvironmentSetup
+import android.os.Bundle
+import android.os.Parcel
 import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
 import io.kotest.matchers.shouldBe
-import io.mockk.MockKAnnotations
-import io.mockk.every
-import io.mockk.impl.annotations.MockK
 import okio.ByteString.Companion.decodeBase64
-import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -15,254 +12,68 @@ import testhelpers.BaseTestInstrumentation
 
 @RunWith(JUnit4::class)
 class VerifiedTraceLocationTest : BaseTestInstrumentation() {
-
-    @MockK lateinit var environmentSetup: EnvironmentSetup
-
-    @Before
-    fun setUp() {
-        MockKAnnotations.init(this)
-        every { environmentSetup.appConfigPublicKey } returns PUB_KEY
-    }
-
-    // TODO: Ugly but kinda works
     @Test
-    fun verifyTraceLocationIdGenerationHash1() {
-        val base64Payload = "CAESLAgBEhFNeSBCaXJ0aGRheSBQYXJ0eRoLYXQgbXkgcGxhY2Uo04ekAT" +
-            "D3h6QBGmUIARJbMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEst" +
-            "cUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3" +
-            "cAfQmxeuFMZAIX2+6A5XhoEMTIzNCIECAEQAg=="
-        val base64LocationID = "jNcJTCajd9Sen6Tbexl2Yb7O3J7ps47b6k4+QMT4xS0="
-
-        val qrCodePayload =
-            TraceLocationOuterClass.QRCodePayload.parseFrom(base64Payload.decodeBase64()!!.toByteArray())
-        val instance = VerifiedTraceLocation(qrCodePayload)
+    fun verifyTraceLocationMapping1() {
+        val qrCodePayload = TraceLocationOuterClass.QRCodePayload.parseFrom(
+            BASE64_PAYLOAD_1.decodeBase64()!!.toByteArray()
+        )
 
-        instance.traceLocationID.sha256().base64() shouldBe base64LocationID
+        VerifiedTraceLocation(qrCodePayload).traceLocation
+            .apply {
+                locationId.base64() shouldBe "jNcJTCajd9Sen6Tbexl2Yb7O3J7ps47b6k4+QMT4xS0="
+                qrCodePayload() shouldBe qrCodePayload
+            }
     }
 
     @Test
-    fun verifyTraceLocationIdGenerationHash2() {
-        val base64Payload = "CAESIAgBEg1JY2VjcmVhbSBTaG9wGg1NYWluIFN0cmVldCAxGmUIARJ" +
-            "bMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT" +
-            "0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5XhoEMTIzNCIGCAEQARgK"
-        val base64LocationID = "GMuCjqNmOdYyrFhyvFNTVEeLaZh+uShgUoY0LYJo4YQ="
-
-        val qrCodePayload =
-            TraceLocationOuterClass.QRCodePayload.parseFrom(base64Payload.decodeBase64()!!.toByteArray())
-        val instance = VerifiedTraceLocation(qrCodePayload)
-
-        instance.traceLocationID.sha256().base64() shouldBe base64LocationID
-    }
-
-    /* disabled because of incompatibilities due to latest tech spec changes... needs to be re-written anyway
-
-@Test
-fun verifyEventSuccess() = runBlockingTest {
-    val instant = Instant.ofEpochMilli(2687960 * 1_000L)
-    shouldNotThrowAny {
-        val verifyResult = traceLocationQRCodeVerifier.verify(ENCODED_EVENT1.decodeBase32().toByteArray())
-        verifyResult.apply {
-            traceLocation.description shouldBe "My Birthday Party"
-            traceLocation.isBeforeStartTime(instant) shouldBe false
-            traceLocation.isAfterEndTime(instant) shouldBe false
-        }
-    }
-}
-
-@Test
-fun verifyParcelization() = runBlockingTest {
-    val verifyResult = traceLocationQRCodeVerifier.verify(ENCODED_EVENT1.decodeBase32().toByteArray())
-
-    val expectedTraceLocation = TraceLocation(
-        guid = "3055331c-2306-43f3-9742-6d8fab54e848",
-        version = 1,
-        type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
-        description = "My Birthday Party",
-        address = "at my place",
-        startDate = Instant.ofEpochSecond(2687955),
-        endDate = Instant.ofEpochSecond(2687991),
-        defaultCheckInLengthInMinutes = 0,
-        byteRepresentation = verifyResult.traceLocationBytes,
-        signature = verifyResult.signature.toByteArray().toByteString(),
-    )
-
-    verifyResult.traceLocation shouldBe expectedTraceLocation
-
-    val bundle = Bundle().apply {
-        putParcelable("test", verifyResult.traceLocation)
-    }
-
-    val parcelRaw = Parcel.obtain().apply {
-        writeBundle(bundle)
-    }.marshall()
-
-    val restoredParcel = Parcel.obtain().apply {
-        unmarshall(parcelRaw, 0, parcelRaw.size)
-        setDataPosition(0)
-    }
-
-    val restoredData = restoredParcel.readBundle()!!.run {
-        classLoader = TraceLocation::class.java.classLoader
-        getParcelable<TraceLocation>("test")
-    }
-    restoredData shouldBe expectedTraceLocation
-}
-
-@Test
-fun verifyEventStartTimeWaning() = runBlockingTest {
-    val instant = Instant.ofEpochMilli(2687940 * 1_000L)
-    shouldNotThrowAny {
-        val verifyResult = traceLocationQRCodeVerifier.verify(ENCODED_EVENT1.decodeBase32().toByteArray())
-        verifyResult.apply {
-            traceLocation.description shouldBe "My Birthday Party"
-            traceLocation.isBeforeStartTime(instant) shouldBe true
-            traceLocation.isAfterEndTime(instant) shouldBe false
-        }
-    }
-}
+    fun verifyTraceLocationMapping2() {
+        val qrCodePayload = TraceLocationOuterClass.QRCodePayload.parseFrom(
+            BASE64_PAYLOAD_2.decodeBase64()!!.toByteArray()
+        )
 
-@Test
-fun verifyEventEndTimeWarning() = runBlockingTest {
-    val instant = Instant.now()
-    shouldNotThrowAny {
-        val verifyResult = traceLocationQRCodeVerifier.verify(ENCODED_EVENT1.decodeBase32().toByteArray())
-        verifyResult.apply {
-            traceLocation.description shouldBe "My Birthday Party"
-            traceLocation.isBeforeStartTime(instant) shouldBe false
-            traceLocation.isAfterEndTime(instant) shouldBe true
-        }
+        VerifiedTraceLocation(qrCodePayload).traceLocation
+            .apply {
+                locationId.base64() shouldBe "GMuCjqNmOdYyrFhyvFNTVEeLaZh+uShgUoY0LYJo4YQ="
+                qrCodePayload() shouldBe qrCodePayload
+            }
     }
-}
 
-@Test
-fun verifyEventWithInvalidKey() = runBlockingTest {
-    every { environmentSetup.appConfigVerificationKey } returns INVALID_PUB_KEY
-    shouldThrow<InvalidQRCodeSignatureException> {
-        traceLocationQRCodeVerifier.verify(ENCODED_EVENT1.decodeBase32().toByteArray())
-    }
-}
-
-@Test
-fun eventHasMalformedData() = runBlockingTest {
-    shouldThrow<InvalidQRCodeDataException> {
-        traceLocationQRCodeVerifier.verify(
-            INVALID_ENCODED_EVENT.decodeBase32().toByteArray()
+    @Test
+    fun parcelization() {
+        val qrCodePayload = TraceLocationOuterClass.QRCodePayload.parseFrom(
+            BASE64_PAYLOAD_2.decodeBase64()!!.toByteArray()
         )
-    }
-}
 
-@Test
-fun decodingTest1() = runBlockingTest {
-    val signedTraceLocation = TraceLocationOuterClass.SignedTraceLocation.parseFrom(
-        ENCODED_EVENT1.decodeBase32().toByteArray()
-    )
-    val expectedSignature =
-        "MEQCIGVKfqPF2851IrEyDeVMazlRnIzLX16H6r1TB37PRzjbAiBGP13ADQcbQZsztKUCZMRcvnv5Mgdo0LY/v3qFMnrUkQ=="
+        val expectedVerifiedLocation = VerifiedTraceLocation(qrCodePayload)
 
-    val base32 = signedTraceLocation.toByteArray().toByteString().base32()
-
-    shouldNotThrowAny {
-        val verifyResult = traceLocationQRCodeVerifier.verify(base32.decodeBase32().toByteArray())
-
-        verifyResult.apply {
-            traceLocation.description shouldBe "My Birthday Party"
-            signedTraceLocation.signature.toByteArray().toByteString().base64() shouldBe expectedSignature
+        val bundle = Bundle().apply {
+            putParcelable("verifiedTraceLocation", expectedVerifiedLocation)
         }
-    }
-}
 
-@Test
-fun decodingTest2() = runBlockingTest {
-    val signedTraceLocation = TraceLocationOuterClass.SignedTraceLocation.parseFrom(
-        ENCODED_EVENT2.decodeBase32().toByteArray()
-    )
-    val expectedSignature =
-        "MEQCIDWRTM4ujn1GFPuHlgpUnQIWwwzwI8abxSrF5Er2I5HaAiAbucxg+6d3nC/Iwzo7AXehJAS20TRX1S2rl0LO8kcYxA=="
+        val parcelRaw = Parcel.obtain().apply {
+            writeBundle(bundle)
+        }.marshall()
 
-    val base32 = signedTraceLocation.toByteArray().toByteString().base32()
-
-    shouldNotThrowAny {
-        val verifyResult = traceLocationQRCodeVerifier.verify(base32.decodeBase32().toByteArray())
-
-        verifyResult.apply {
-            traceLocation.description shouldBe "Icecream Shop"
-            signedTraceLocation.signature.toByteArray().toByteString().base64() shouldBe expectedSignature
+        val restoredParcel = Parcel.obtain().apply {
+            unmarshall(parcelRaw, 0, parcelRaw.size)
+            setDataPosition(0)
         }
-    }
-}
 
-@Test
-fun testVerifiedTraceLocationMapping() {
-    shouldNotThrowAny {
-        val signedTraceLocation = TraceLocationOuterClass.SignedTraceLocation.parseFrom(
-            ENCODED_EVENT1.decodeBase32().toByteArray()
-        )
-
-        val traceLocation = TraceLocationOuterClass.TraceLocation.parseFrom(
-            ENCODED_EVENT1_LOCATION.decodeBase32().toByteArray()
-        )
-        val verifiedTraceLocation = VerifiedTraceLocation(
-            protoSignedTraceLocation = signedTraceLocation,
-            protoTraceLocation = traceLocation
-        ).traceLocation
-
-        verifiedTraceLocation shouldBe TraceLocation(
-            guid = "3055331c-2306-43f3-9742-6d8fab54e848",
-            version = 1,
-            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
-            description = "My Birthday Party",
-            address = "at my place",
-            startDate = Instant.ofEpochSecond(2687955),
-            endDate = Instant.ofEpochSecond(2687991),
-            defaultCheckInLengthInMinutes = 0,
-            byteRepresentation = signedTraceLocation.location.toByteArray().toByteString(),
-            signature = signedTraceLocation.signature.toByteArray().toByteString()
-        )
+        val restoredData = restoredParcel.readBundle()!!.run {
+            classLoader = VerifiedTraceLocation::class.java.classLoader
+            getParcelable<VerifiedTraceLocation>("verifiedTraceLocation")
+        }
+        restoredData shouldBe expectedVerifiedLocation
     }
-}
-
-*/
 
     companion object {
+        private const val BASE64_PAYLOAD_1 = "CAESLAgBEhFNeSBCaXJ0aGRheSBQYXJ0eRoLYXQgbXkgcGxhY2Uo04ekAT" +
+            "D3h6QBGmUIARJbMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEst" +
+            "cUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3" +
+            "cAfQmxeuFMZAIX2+6A5XhoEMTIzNCIECAEQAg=="
 
-        //   "signedLocation": {
-        //    "location": {
-        //      "guid": "3055331c-2306-43f3-9742-6d8fab54e848",
-        //      "version": 1,
-        //      "type": 2,
-        //      "description": "My Birthday Party",
-        //      "address": "at my place",
-        //      "startTimestamp": 2687955,
-        //      "endTimestamp": 2687991,
-        //      "defaultCheckInLengthInMinutes": 0
-        //    },
-        //    "signature": "MEQCIGVKfqPF2851IrEyDeVMazlRnIzLX16H6r1TB37PRzjbAiBGP13ADQcbQZsztKUCZMRcvnv5Mgdo0LY/v3qFMnrUkQ=="
-        private const val ENCODED_EVENT1 =
-            "BJLAUJBTGA2TKMZTGFRS2MRTGA3C2NBTMYZS2OJXGQZC2NTEHBTGCYRVGRSTQNBYCAARQARCCFGXSICCNFZHI2DEMF4SAUDBOJ2HSKQLMF2CA3LZEBYGYYLDMUYNHB5EAE4PPB5EAFAAAESGGBCAEIDFJJ7KHRO3ZZ2SFMJSBXSUY2ZZKGOIZS27L2D6VPKTA57M6RZY3MBCARR7LXAA2BY3IGNTHNFFAJSMIXF6PP4TEB3I2C3D7P32QUZHVVER"
-        private const val ENCODED_EVENT1_LOCATION =
-            "BISDGMBVGUZTGMLDFUZDGMBWFU2DGZRTFU4TONBSFU3GIODGMFRDKNDFHA2DQEABDABCEEKNPEQEE2LSORUGIYLZEBIGC4TUPEVAWYLUEBWXSIDQNRQWGZJQ2OD2IAJY66D2IAKAAA"
-
-        //   "signedLocation": {
-        //    "location": {
-        //      "guid": "fca84b37-61c0-4a7c-b2f8-825cadd506cf",
-        //      "version": 1,
-        //      "type": 1,
-        //      "description": "Icecream Shop",
-        //      "address": "Main Street 1",
-        //      "startTimestamp": 0,
-        //      "endTimestamp": 0,
-        //      "defaultCheckInLengthInMinutes": 10
-        //    },
-        //    "signature": "MEQCIDWRTM4ujn1GFPuHlgpUnQIWwwzwI8abxSrF5Er2I5HaAiAbucxg+6d3nC/Iwzo7AXehJAS20TRX1S2rl0LO8kcYxA=="
-        private const val ENCODED_EVENT2 =
-            "BJHAUJDGMNQTQNDCGM3S2NRRMMYC2NDBG5RS2YRSMY4C2OBSGVRWCZDEGUYDMY3GCAARQAJCBVEWGZLDOJSWC3JAKNUG64BKBVGWC2LOEBJXI4TFMV2CAMJQAA4AAQAKCJDDARACEA2ZCTGOF2HH2RQU7ODZMCSUTUBBNQYM6AR4NG6FFLC6ISXWEOI5UARADO44YYH3U53ZYL6IYM5DWALXUESAJNWRGRL5KLNLS5BM54SHDDCA"
-
-        private const val INVALID_ENCODED_EVENT =
-            "NB2HI4DTHIXS653XO4XHK4TCMFXGI2LDORUW63TBOJ4S4Y3PNUXWIZLGNFXGKLTQNBYD65DFOJWT2VDIMUSTEMCDN53GSZBFGIYDCOI="
-
-        private const val PUB_KEY =
-            "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEafIKZOiRPuJWjKOUmKv7OTJWTyii4oCQLcGn3FgYoLQaJIvAM3Pl7anFDPPY/jxfqqrLyGc0f6hWQ9JPR3QjBw=="
-        private const val INVALID_PUB_KEY =
-            "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg=="
+        private const val BASE64_PAYLOAD_2 = "CAESIAgBEg1JY2VjcmVhbSBTaG9wGg1NYWluIFN0cmVldCAxGmUIARJ" +
+            "bMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT" +
+            "0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5XhoEMTIzNCIGCAEQARgK"
     }
 }
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragment.kt
index beb72df52a2358f5258e42221e0db7f1237d8737..dc916befbe2d774a71a2ed10890e714b35d6b59f 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragment.kt
@@ -2,13 +2,21 @@ package de.rki.coronawarnapp.test.eventregistration.ui
 
 import android.annotation.SuppressLint
 import android.os.Bundle
+import android.text.SpannedString
 import android.view.View
 import android.widget.Toast
+import androidx.core.text.bold
+import androidx.core.text.buildSpannedString
+import androidx.core.text.color
+import androidx.core.text.scale
+import androidx.core.view.isVisible
 import androidx.fragment.app.Fragment
 import androidx.navigation.fragment.findNavController
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentTestEventregistrationBinding
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
 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.doNavigate
 import de.rki.coronawarnapp.util.ui.observe2
@@ -50,10 +58,6 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis
             showEventsButton.setOnClickListener {
                 findNavController().navigate(R.id.showStoredEventsTestFragment)
             }
-
-            generateTestTraceLocations.setOnClickListener {
-                viewModel.generateTestTraceLocations()
-            }
         }
         binding.runMatcher.setOnClickListener {
             viewModel.runMatcher()
@@ -82,8 +86,63 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis
         viewModel.riskCalculationRuntime.observe2(this) {
             binding.riskCalculationRuntimeText.text = "Risk calculation runtime in millis: $it"
         }
+
+        viewModel.lastOrganiserLocation.observe(viewLifecycleOwner) {
+            binding.lastOrganiserLocationCard.isVisible = it != null
+            it?.let { traceLocation ->
+                with(binding) {
+                    lastOrganiserLocation.text = traceLocationText(traceLocation)
+                    lastOrganiserLocationId.text = styleText("ID", traceLocation.locationId.base64())
+                    lastOrganiserLocationUrl.text = styleText("URL", traceLocation.locationUrl)
+                }
+            }
+        }
+
+        viewModel.lastAttendeeLocation.observe(viewLifecycleOwner) {
+            binding.lastAttendeeLocationCard.isVisible = it != null
+            it?.let { traceLocation ->
+                with(binding) {
+                    lastAttendeeLocation.text = traceLocationText(traceLocation)
+                    lastAttendeeLocationId.text = styleText("ID", traceLocation.locationId.base64())
+                    lastAttendeeLocationUrl.text = styleText("URL", traceLocation.locationUrl)
+                }
+            }
+        }
     }
 
+    private fun traceLocationText(traceLocation: TraceLocation): SpannedString = with(traceLocation) {
+        buildSpannedString {
+            append("TraceLocation [\n")
+            append(styleText("Id", id))
+            append(styleText("type", type))
+            append(styleText("version", version))
+            append(styleText("address", address))
+            append(styleText("description", description))
+            append(styleText("startDate", startDate))
+            append(styleText("endDate", endDate))
+            append(styleText("defaultCheckInLengthInMinutes", defaultCheckInLengthInMinutes))
+            append(styleText("cnPublicKey", cnPublicKey))
+            append(styleText("cryptographicSeed", cryptographicSeed.base64()))
+            append("]")
+        }
+    }
+
+    private fun styleText(key: String, value: Any?): SpannedString =
+        buildSpannedString {
+            bold {
+                color(requireContext().getColorCompat(R.color.colorAccent)) {
+                    append("$key=")
+                }
+            }
+
+            scale(0.85f) {
+                color(requireContext().getColorCompat(R.color.colorTextPrimary1)) {
+                    append(value.toString())
+                }
+            }
+            append("\n")
+        }
+
     companion object {
         val MENU_ITEM = TestMenuItem(
             title = "Event Registration",
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragmentViewModel.kt
index a87c13dc9c2aadbd6399aad83b2add45605cad64..a44796fb2128582cd6c2ab517e875eeea6818d96 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragmentViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragmentViewModel.kt
@@ -1,8 +1,12 @@
 package de.rki.coronawarnapp.test.eventregistration.ui
 
+import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.asLiveData
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.eventregistration.checkins.CheckIn
+import de.rki.coronawarnapp.eventregistration.checkins.CheckInRepository
 import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
 import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
 import de.rki.coronawarnapp.presencetracing.risk.CheckInWarningMatcher
@@ -13,17 +17,27 @@ import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.debug.measureTime
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
-import okio.ByteString.Companion.encode
-import org.joda.time.DateTime
+import kotlinx.coroutines.flow.map
 import timber.log.Timber
 
 class EventRegistrationTestFragmentViewModel @AssistedInject constructor(
-    private val dispatcherProvider: DispatcherProvider,
-    private val traceLocationRepository: TraceLocationRepository,
+    dispatcherProvider: DispatcherProvider,
+    traceLocationRepository: TraceLocationRepository,
+    checkInRepository: CheckInRepository,
     private val checkInWarningMatcher: CheckInWarningMatcher,
     private val presenceTracingRiskCalculator: PresenceTracingRiskCalculator
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
+    val lastOrganiserLocation: LiveData<TraceLocation?> =
+        traceLocationRepository.allTraceLocations
+            .map { lastLocationData(it) }
+            .asLiveData(dispatcherProvider.Default)
+
+    val lastAttendeeLocation: LiveData<TraceLocation?> =
+        checkInRepository.allCheckIns
+            .map { lastAttendeeLocationData(it) }
+            .asLiveData(dispatcherProvider.Default)
+
     private val checkInWarningOverlaps = mutableListOf<CheckInWarningOverlap>()
     val checkInOverlapsText = MutableLiveData<String>()
     val matchingRuntime = MutableLiveData<Long>()
@@ -93,92 +107,24 @@ class EventRegistrationTestFragmentViewModel @AssistedInject constructor(
         }
     }
 
-    fun generateTestTraceLocations() {
-        launch {
-            val permanent = TraceLocation(
-                type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_FOOD_SERVICE,
-                description = "SAP Kantine WDF20",
-                address = "Hauptstr. 3, 69115 Heidelberg",
-                startDate = null,
-                endDate = null,
-                defaultCheckInLengthInMinutes = 60,
-                cryptographicSeed = "".encode(),
-                cnPublicKey = ""
-            )
-            traceLocationRepository.addTraceLocation(permanent)
-
-            val oneDayEvent = TraceLocation(
-                type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT,
-                description = "Jahrestreffen der deutschen SAP Anwendergruppe (one day)",
-                address = "Hauptstr. 3, 69115 Heidelberg",
-                startDate = DateTime.now().plusHours(2).toInstant(),
-                endDate = DateTime.now().plusHours(3).toInstant(),
-                defaultCheckInLengthInMinutes = 60,
-                cryptographicSeed = "".encode(),
-                cnPublicKey = ""
-            )
-            traceLocationRepository.addTraceLocation(oneDayEvent)
-
-            val partyHardEvent = TraceLocation(
-                type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CLUB_ACTIVITY,
-                description = "Jahrestreffen der deutschen SAP Anwendergruppe (many days)",
-                address = "Hauptstr. 3, 69115 Heidelberg",
-                startDate = DateTime.now().plusHours(2).toInstant(),
-                endDate = DateTime.now().plusDays(5).plusHours(2).toInstant(),
-                defaultCheckInLengthInMinutes = 60,
-                cryptographicSeed = "".encode(),
-                cnPublicKey = ""
-            )
-            traceLocationRepository.addTraceLocation(partyHardEvent)
-
-            val oldPermanent = TraceLocation(
-                type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_FOOD_SERVICE,
-                description = "SAP Kantine MOW07",
-                address = "Moscow, Kosmodomianskaya 52/7",
-                startDate = null,
-                endDate = null,
-                defaultCheckInLengthInMinutes = 60,
-                cryptographicSeed = "".encode(),
-                cnPublicKey = ""
-            )
-            traceLocationRepository.addTraceLocation(oldPermanent)
-
-            val oldTemporaryOne = TraceLocation(
-                type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CLUB_ACTIVITY,
-                description = "Old temporary 1",
-                address = "Hauptstr. 3, 69115 Heidelberg",
-                startDate = DateTime.now().minusSeconds(16 * 86400).toInstant(),
-                endDate = DateTime.now().minusSeconds(15 * 86400 - 10).toInstant(),
-                defaultCheckInLengthInMinutes = 60,
-                cryptographicSeed = "".encode(),
-                cnPublicKey = ""
-            )
-            traceLocationRepository.addTraceLocation(oldTemporaryOne)
-
-            val oldTemporaryTwo = TraceLocation(
-                type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CLUB_ACTIVITY,
-                description = "Old temporary 2",
-                address = "Hauptstr. 3, 69115 Heidelberg",
-                startDate = DateTime.now().minusSeconds(16 * 86400).toInstant(),
-                endDate = DateTime.now().minusSeconds(15 * 86400).toInstant(),
-                defaultCheckInLengthInMinutes = 60,
-                cryptographicSeed = "".encode(),
-                cnPublicKey = ""
-            )
-            traceLocationRepository.addTraceLocation(oldTemporaryTwo)
-
-            val oldTemporaryThree = TraceLocation(
-                type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CLUB_ACTIVITY,
-                description = "Old temporary 3",
-                address = "Hauptstr. 3, 69115 Heidelberg",
-                startDate = DateTime.now().minusSeconds(16 * 86400).toInstant(),
-                endDate = DateTime.now().minusSeconds(15 * 86400 + 10).toInstant(),
-                defaultCheckInLengthInMinutes = 60,
-                cryptographicSeed = "".encode(),
-                cnPublicKey = ""
-            )
-            traceLocationRepository.addTraceLocation(oldTemporaryThree)
-        }
+    private fun lastLocationData(it: List<TraceLocation>): TraceLocation? =
+        it.maxByOrNull { traceLocation -> traceLocation.id }
+
+    private fun lastAttendeeLocationData(it: List<CheckIn>): TraceLocation? {
+        val checkIn = it.maxByOrNull { checkIn -> checkIn.id } ?: return null
+
+        return TraceLocation(
+            id = checkIn.id,
+            type = TraceLocationOuterClass.TraceLocationType.forNumber(checkIn.type),
+            description = checkIn.description,
+            address = checkIn.address,
+            startDate = checkIn.traceLocationStart,
+            endDate = checkIn.traceLocationEnd,
+            defaultCheckInLengthInMinutes = checkIn.defaultCheckInLengthInMinutes,
+            cryptographicSeed = checkIn.cryptographicSeed,
+            cnPublicKey = checkIn.cnPublicKey,
+            version = checkIn.version
+        )
     }
 
     @AssistedFactory
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_eventregistration.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_eventregistration.xml
index 7cde04273f12098aaf69f92af3986360c3ae31cf..d35124a53e2e67e5a91cb543d6de32d1dcb9922b 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_eventregistration.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_eventregistration.xml
@@ -118,6 +118,82 @@
 
         </LinearLayout>
 
+        <LinearLayout
+            android:id="@+id/lastOrganiserLocationCard"
+            style="@style/Card"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginHorizontal="@dimen/spacing_tiny"
+            android:layout_marginTop="10dp"
+            android:orientation="vertical">
+
+            <TextView
+                style="@style/headline6"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="Last organiser location" />
+
+            <TextView
+                android:id="@+id/lastOrganiserLocation"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:textIsSelectable="true" />
+
+            <TextView
+                android:id="@+id/lastOrganiserLocationUrl"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:autoLink="web"
+                android:textIsSelectable="true" />
+
+            <TextView
+                android:id="@+id/lastOrganiserLocationId"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:textIsSelectable="true" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/lastAttendeeLocationCard"
+            style="@style/Card"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginHorizontal="@dimen/spacing_tiny"
+            android:layout_marginTop="10dp"
+            android:orientation="vertical">
+
+            <TextView
+                style="@style/headline6"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="Last attendee location" />
+
+            <TextView
+                android:id="@+id/lastAttendeeLocation"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:textIsSelectable="true" />
+
+            <TextView
+                android:id="@+id/lastAttendeeLocationUrl"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:autoLink="web"
+                android:textIsSelectable="true" />
+
+            <TextView
+                android:id="@+id/lastAttendeeLocationId"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:textIsSelectable="true" />
+        </LinearLayout>
+
         <androidx.constraintlayout.widget.ConstraintLayout
             android:id="@+id/event_container"
             style="@style/Card"
diff --git a/Corona-Warn-App/src/main/AndroidManifest.xml b/Corona-Warn-App/src/main/AndroidManifest.xml
index d0ebbbe7886e8262f3367976a3aa836bf26d0f93..2cefbd599e3a740713e55a733c3b04b38949d234 100644
--- a/Corona-Warn-App/src/main/AndroidManifest.xml
+++ b/Corona-Warn-App/src/main/AndroidManifest.xml
@@ -85,7 +85,6 @@
 
                 <data
                     android:host="e.coronawarn.app"
-                    android:pathPrefix="/"
                     android:scheme="https" />
             </intent-filter>
         </activity>
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/PresenceTracingConfig.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/PresenceTracingConfig.kt
index 7b73dbd495e8be74db6c1ad731ecf06d760e0c7a..699e95b6fd724340c2819eba9140ecc0c6071424 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/PresenceTracingConfig.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/PresenceTracingConfig.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.appconfig
 
 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
 import de.rki.coronawarnapp.appconfig.mapping.ConfigMapper
+import de.rki.coronawarnapp.server.protocols.internal.v2.PresenceTracingParametersOuterClass.PresenceTracingQRCodeDescriptorOrBuilder
 
 interface PresenceTracingConfig {
     val qrCodeErrorCorrectionLevel: ErrorCorrectionLevel
@@ -9,6 +10,7 @@ interface PresenceTracingConfig {
     val riskCalculationParameters: PresenceTracingRiskCalculationParamContainer
     val submissionParameters: PresenceTracingSubmissionParamContainer
     val plausibleDeniabilityParameters: PlausibleDeniabilityParametersContainer
+    val qrCodeDescriptors: List<PresenceTracingQRCodeDescriptorOrBuilder>
 
     interface Mapper : ConfigMapper<PresenceTracingConfig>
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/PresenceTracingConfigContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/PresenceTracingConfigContainer.kt
index 91e17852764dea900fcb19f5ce569f0730ef6c93..5957fcdd91063e0ddeef7020db73994aa2f6367a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/PresenceTracingConfigContainer.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/PresenceTracingConfigContainer.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.appconfig
 
 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
+import de.rki.coronawarnapp.server.protocols.internal.v2.PresenceTracingParametersOuterClass.PresenceTracingQRCodeDescriptorOrBuilder
 
 data class PresenceTracingConfigContainer(
     override val qrCodeErrorCorrectionLevel: ErrorCorrectionLevel = ErrorCorrectionLevel.H,
@@ -10,5 +11,6 @@ data class PresenceTracingConfigContainer(
     override val submissionParameters: PresenceTracingSubmissionParamContainer =
         PresenceTracingSubmissionParamContainer(),
     override val plausibleDeniabilityParameters: PlausibleDeniabilityParametersContainer =
-        PlausibleDeniabilityParametersContainer()
+        PlausibleDeniabilityParametersContainer(),
+    override val qrCodeDescriptors: List<PresenceTracingQRCodeDescriptorOrBuilder> = emptyList()
 ) : PresenceTracingConfig
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/PresenceTracingConfigMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/PresenceTracingConfigMapper.kt
index bdba0734eca097fa3d2cbbf037a13c4762aef169..739a0e6fd00d27db3cd02e7f396e076eefeaa0dd 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/PresenceTracingConfigMapper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/PresenceTracingConfigMapper.kt
@@ -8,14 +8,10 @@ import de.rki.coronawarnapp.appconfig.PresenceTracingConfigContainer
 import de.rki.coronawarnapp.appconfig.PresenceTracingRiskCalculationParamContainer
 import de.rki.coronawarnapp.appconfig.PresenceTracingSubmissionParamContainer
 import de.rki.coronawarnapp.server.protocols.internal.v2.AppConfigAndroid
-import de.rki.coronawarnapp.server.protocols.internal.v2
-    .PresenceTracingParametersOuterClass.PresenceTracingSubmissionParameters
-import de.rki.coronawarnapp.server.protocols.internal.v2
-    .PresenceTracingParametersOuterClass.PresenceTracingRiskCalculationParameters
-import de.rki.coronawarnapp.server.protocols.internal.v2
-    .PresenceTracingParametersOuterClass.PresenceTracingParameters.QRCodeErrorCorrectionLevel
-import de.rki.coronawarnapp.server.protocols.internal.v2
-    .PresenceTracingParametersOuterClass.PresenceTracingPlausibleDeniabilityParameters
+import de.rki.coronawarnapp.server.protocols.internal.v2.PresenceTracingParametersOuterClass.PresenceTracingSubmissionParameters
+import de.rki.coronawarnapp.server.protocols.internal.v2.PresenceTracingParametersOuterClass.PresenceTracingRiskCalculationParameters
+import de.rki.coronawarnapp.server.protocols.internal.v2.PresenceTracingParametersOuterClass.PresenceTracingParameters.QRCodeErrorCorrectionLevel
+import de.rki.coronawarnapp.server.protocols.internal.v2.PresenceTracingParametersOuterClass.PresenceTracingPlausibleDeniabilityParameters
 
 import timber.log.Timber
 import javax.inject.Inject
@@ -95,7 +91,8 @@ class PresenceTracingConfigMapper @Inject constructor() : PresenceTracingConfig.
                 revokedTraceLocationVersions = revokedTraceLocationVersionsList.orEmpty(),
                 riskCalculationParameters = riskCalculationParameters,
                 submissionParameters = submissionParameters,
-                plausibleDeniabilityParameters = plausibleDeniabilityParameters
+                plausibleDeniabilityParameters = plausibleDeniabilityParameters,
+                qrCodeDescriptors = qrCodeDescriptorsOrBuilderList
             )
         }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/CheckInsTransformer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/CheckInsTransformer.kt
index 6f76b0b04c1c86b8894e7ec7182343b834dbb2ab..68c52400c7bdcd9d559b1885d5bd84b4c3fe8636 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/CheckInsTransformer.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/CheckInsTransformer.kt
@@ -1,6 +1,5 @@
 package de.rki.coronawarnapp.eventregistration.checkins
 
-import com.google.protobuf.ByteString
 import de.rki.coronawarnapp.appconfig.AppConfigProvider
 import de.rki.coronawarnapp.eventregistration.checkins.derivetime.deriveTime
 import de.rki.coronawarnapp.eventregistration.checkins.split.splitByMidnightUTC
@@ -107,5 +106,3 @@ fun CheckIn.determineRiskTransmission(now: Instant, transmissionVector: Transmis
     val ageInDays = Days.daysBetween(startMidnight, nowMidnight).days
     return transmissionVector.raw.getOrElse(ageInDays) { 1 } // Default value
 }
-
-private fun okio.ByteString.toProtoByteString() = ByteString.copyFrom(toByteArray())
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeDataException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeDataException.kt
deleted file mode 100644
index 935e86b319ff3fc5ca3d685371c417fe706bf64a..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeDataException.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package de.rki.coronawarnapp.eventregistration.checkins.qrcode
-
-class InvalidQRCodeDataException constructor(
-    message: String? = null,
-    cause: Throwable? = null
-) : QRCodeException(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeSignatureException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeSignatureException.kt
deleted file mode 100644
index eae77689d0aab837f5527c2682e72f55078c70ab..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/InvalidQRCodeSignatureException.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package de.rki.coronawarnapp.eventregistration.checkins.qrcode
-
-class InvalidQRCodeSignatureException constructor(
-    message: String? = null,
-    cause: Throwable? = null
-) : QRCodeException(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeException.kt
index 1fb4c881a81819cd76149537923ad3956f8d942a..3df60ea22ecbc0d8683f5d5987475eb287373e7a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeException.kt
@@ -1,6 +1,21 @@
 package de.rki.coronawarnapp.eventregistration.checkins.qrcode
 
-open class QRCodeException constructor(
+sealed class QRCodeException constructor(
     message: String? = null,
     cause: Throwable? = null
 ) : Exception(message, cause)
+
+class InvalidQrCodeUriException constructor(
+    message: String? = null,
+    cause: Throwable? = null
+) : QRCodeException(message, cause)
+
+class InvalidQrCodePayloadException constructor(
+    message: String? = null,
+    cause: Throwable? = null
+) : QRCodeException(message, cause)
+
+class InvalidQrCodeDataException constructor(
+    message: String? = null,
+    cause: Throwable? = null
+) : QRCodeException(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeUriParser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeUriParser.kt
index 7d622c3425e2e986c9117edf50e179940ea1ecde..493d2bdb667c846e7189099574c2018b63fd5a57 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeUriParser.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeUriParser.kt
@@ -1,46 +1,86 @@
 package de.rki.coronawarnapp.eventregistration.checkins.qrcode
 
+import com.google.common.io.BaseEncoding
 import dagger.Reusable
+import de.rki.coronawarnapp.appconfig.AppConfigProvider
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.QRCodePayload
+import de.rki.coronawarnapp.server.protocols.internal.v2.PresenceTracingParametersOuterClass.PresenceTracingQRCodeDescriptorOrBuilder
+import de.rki.coronawarnapp.server.protocols.internal.v2.PresenceTracingParametersOuterClass.PresenceTracingQRCodeDescriptor.PayloadEncoding
 import de.rki.coronawarnapp.util.decodeBase32
-import okio.ByteString
+import okio.ByteString.Companion.toByteString
 import timber.log.Timber
 import java.net.URI
 import javax.inject.Inject
 
 @Reusable
-class QRCodeUriParser @Inject constructor() {
+class QRCodeUriParser @Inject constructor(
+    private val configProvider: AppConfigProvider
+) {
 
     /**
-     * Validate that QRCode scanned uri matches the following formulas:
-     * https://e.coronawarn.app/c1/SIGNED_TRACE_LOCATION_BASE32
-     * HTTPS://E.CORONAWARN.APP/C1/SIGNED_TRACE_LOCATION_BASE32
+     * Parse [QRCodePayload] from [input]
+     *
+     * @throws [Exception] such as [QRCodeException],
+     * exceptions from [URI.create]
+     * and possible decoding exceptions
      */
-    fun getQrCodePayload(maybeUri: String): ByteString? = URI.create(maybeUri).run {
-        if (!scheme.equals(SCHEME, true)) return@run null
-        if (!authority.equals(AUTHORITY, true)) return@run null
+    @Suppress("BlockingMethodInNonBlockingContext")
+    suspend fun getQrCodePayload(input: String): QRCodePayload {
+        Timber.d("input=$input")
+        try {
+            URI.create(input) // Verify it is a valid uri
+        } catch (e: Exception) {
+            Timber.d(e, "Invalid URI")
+            throw InvalidQrCodeUriException("Invalid URI", e)
+        }
 
-        if (!path.substringBeforeLast("/").equals(PATH_PREFIX, true)) return@run null
+        val descriptor = descriptor(input)
+        val groups = descriptor.matchedGroups(input)
 
-        val rawData = path.substringAfterLast("/")
-        val paddingDiff = 8 - (rawData.length % 8)
-        val maybeBase32 = rawData + createPadding(paddingDiff)
+        val payload = groups[descriptor.encodedPayloadGroupIndex]
+        Timber.d("payload=$payload")
 
-        if (!maybeBase32.matches(BASE32_REGEX)) return@run null
+        val encoding = PayloadEncoding.forNumber(descriptor.payloadEncoding.number)
+        Timber.d("encoding=$encoding")
 
-        return@run try {
-            maybeBase32.decodeBase32()
+        val rawPayload = try {
+            when (encoding) {
+                PayloadEncoding.BASE32 -> payload.decodeBase32()
+                PayloadEncoding.BASE64 -> BaseEncoding.base64Url().decode(payload).toByteString()
+                else -> null
+            }
         } catch (e: Exception) {
-            Timber.w(e, "Data wasn't base32: %s", maybeBase32)
+            Timber.d(e, "Payload decoding failed")
             null
+        } ?: throw InvalidQrCodeDataException("Payload decoding failed")
+
+        return QRCodePayload.parseFrom(rawPayload.toByteArray())
+    }
+
+    private suspend fun descriptor(input: String): PresenceTracingQRCodeDescriptorOrBuilder {
+        val descriptors = configProvider.getAppConfig().presenceTracing.qrCodeDescriptors
+        Timber.d("descriptors=$descriptors")
+        val descriptor = descriptors.find { it.regexPattern.toRegex(RegexOption.IGNORE_CASE).matches(input) }
+        if (descriptor == null) {
+            Timber.d("Invalid URI - no matchedDescriptor")
+            throw InvalidQrCodeUriException("Invalid URI - no matchedDescriptor")
         }
+        Timber.d("descriptor=$descriptor")
+        return descriptor
     }
 
-    companion object {
-        private fun createPadding(length: Int) = (0 until length).joinToString(separator = "") { "=" }
+    private fun PresenceTracingQRCodeDescriptorOrBuilder.matchedGroups(
+        input: String
+    ): List<String> {
+        val groups = regexPattern
+            .toRegex(RegexOption.IGNORE_CASE).find(input) // Find matched result [MatchResult]
+            ?.destructured?.toList().orEmpty() // Destructured groups - excluding the zeroth group (Whole String)
+        Timber.d("groups=$groups")
 
-        private const val SCHEME = "https"
-        private const val AUTHORITY = "e.coronawarn.app"
-        private const val PATH_PREFIX = "/c1"
-        private val BASE32_REGEX = "^([A-Z2-7=]{8})+$".toRegex(RegexOption.IGNORE_CASE)
+        if (encodedPayloadGroupIndex !in groups.indices) {
+            Timber.d("Invalid payload - group index is out of bounds")
+            throw InvalidQrCodePayloadException("Invalid payload - group index is out of bounds")
+        }
+        return groups
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QrCodePayload.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QrCodePayload.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7ac7412993b6bea0ea8e9c666d013bb41dac2dbe
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QrCodePayload.kt
@@ -0,0 +1,57 @@
+package de.rki.coronawarnapp.eventregistration.checkins.qrcode
+
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.CWALocationData
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.CrowdNotifierData
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.QRCodePayload
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.secondsToInstant
+import de.rki.coronawarnapp.util.toOkioByteString
+import de.rki.coronawarnapp.util.toProtoByteString
+import okio.ByteString.Companion.decodeBase64
+import org.joda.time.Instant
+
+fun TraceLocation.qrCodePayload(): QRCodePayload {
+    val vendorData = CWALocationData.newBuilder()
+        .setType(type)
+        .setDefaultCheckInLengthInMinutes(defaultCheckInLengthInMinutes ?: 0)
+        .setVersion(TraceLocation.VERSION)
+        .build()
+
+    val crowdNotifierData = CrowdNotifierData.newBuilder()
+        .setCryptographicSeed(cryptographicSeed.toProtoByteString())
+        .setPublicKey(cnPublicKey.decodeBase64()!!.toProtoByteString())
+        .setVersion(TraceLocation.VERSION)
+
+    val locationData = TraceLocationOuterClass.TraceLocation.newBuilder()
+        .setDescription(description)
+        .setAddress(address)
+        .setStartTimestamp(startDate?.seconds ?: 0)
+        .setEndTimestamp(endDate?.seconds ?: 0)
+        .setVersion(TraceLocation.VERSION)
+        .build()
+
+    return QRCodePayload.newBuilder()
+        .setVendorData(vendorData.toByteString())
+        .setCrowdNotifierData(crowdNotifierData)
+        .setLocationData(locationData)
+        .setVersion(TraceLocation.VERSION)
+        .build()
+}
+
+fun QRCodePayload.traceLocation(): TraceLocation {
+    val cwaLocationData = CWALocationData.parseFrom(vendorData)
+    return TraceLocation(
+        version = version,
+        type = cwaLocationData.type,
+        defaultCheckInLengthInMinutes = cwaLocationData.defaultCheckInLengthInMinutes,
+        description = locationData.description,
+        address = locationData.address,
+        startDate = locationData.startTimestamp.instant(),
+        endDate = locationData.endTimestamp.instant(),
+        cryptographicSeed = crowdNotifierData.cryptographicSeed.toOkioByteString(),
+        cnPublicKey = crowdNotifierData.publicKey.toOkioByteString().base64()
+    )
+}
+
+private fun Long.instant(): Instant? = if (this == 0L) null else secondsToInstant()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocation.kt
index 92409f9bf5c1ad34c00b28d063b9be8a17f03edd..0669968f006c3b01ee1216189356717be540ed77 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocation.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/TraceLocation.kt
@@ -1,15 +1,17 @@
 package de.rki.coronawarnapp.eventregistration.checkins.qrcode
 
 import android.os.Parcelable
+import com.google.common.io.BaseEncoding
 import de.rki.coronawarnapp.eventregistration.storage.entity.TraceLocationEntity
 import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.ui.eventregistration.organizer.details.QrCodeGenerator
+import kotlinx.parcelize.IgnoredOnParcel
 import kotlinx.parcelize.Parcelize
 import okio.ByteString
 import okio.ByteString.Companion.decodeBase64
+import okio.ByteString.Companion.toByteString
 import org.joda.time.Instant
 
-const val TRACE_LOCATION_VERSION = 1
-
 @Parcelize
 data class TraceLocation(
     val id: Long = 0L,
@@ -21,12 +23,53 @@ data class TraceLocation(
     val defaultCheckInLengthInMinutes: Int?,
     val cryptographicSeed: ByteString,
     val cnPublicKey: String,
-    val version: Int = TRACE_LOCATION_VERSION,
+    val version: Int = VERSION,
 ) : Parcelable {
 
+    /**
+     * Return a url for [TraceLocation] to be used as an input for [QrCodeGenerator]
+     * URL format https://e.coronawarn.app?v=1#QR_CODE_PAYLOAD_BASE64URL
+     */
+    @IgnoredOnParcel
+    val locationUrl: String by lazy {
+        val payloadBytes = qrCodePayload().toByteArray()
+        val base64Url = BaseEncoding.base64Url().omitPadding().encode(payloadBytes)
+        AUTHORITY.plus(base64Url)
+    }
+
+    /**
+     *  Returns a byte sequence that serves as an identifier for the trace location.
+     *  The ID is the byte representation of SHA-256 hash.
+     */
+    @IgnoredOnParcel
+    val locationId: ByteString by lazy {
+        val cwaDomain = CWA_GUID.toByteArray()
+        val payloadBytes = qrCodePayload().toByteArray()
+        val totalByteSequence = cwaDomain + payloadBytes
+        totalByteSequence.toByteString().sha256()
+    }
+
+    /**
+     *  Returns SHA-256 hash of [locationId] which itself is SHA-256 hash
+     */
+    @IgnoredOnParcel
+    val locationIdHash: ByteString by lazy {
+        locationId.sha256()
+    }
+
     fun isBeforeStartTime(now: Instant): Boolean = startDate?.isAfter(now) ?: false
 
     fun isAfterEndTime(now: Instant): Boolean = endDate?.isBefore(now) ?: false
+
+    companion object {
+        /**
+         * Trace location version. This is a static data and not calculated from [TraceLocation]
+         */
+        const val VERSION = 1
+
+        private const val AUTHORITY = "https://e.coronawarn.app?v=$VERSION#"
+        private const val CWA_GUID = "CWA-GUID"
+    }
 }
 
 fun List<TraceLocationEntity>.toTraceLocations() = this.map { it.toTraceLocation() }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/VerifiedTraceLocation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/VerifiedTraceLocation.kt
index 6eb4f36452e936ca31e30161c025c074eb3a9948..b524577b5626e51801189188cb5a4db447ff6f69 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/VerifiedTraceLocation.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/VerifiedTraceLocation.kt
@@ -7,12 +7,6 @@ import kotlinx.parcelize.IgnoredOnParcel
 import kotlinx.parcelize.Parceler
 import kotlinx.parcelize.Parcelize
 import kotlinx.parcelize.TypeParceler
-import okio.Buffer
-import okio.ByteString
-import okio.ByteString.Companion.encode
-import okio.ByteString.Companion.toByteString
-import org.joda.time.Instant
-import java.util.concurrent.TimeUnit
 
 @Parcelize
 @TypeParceler<TraceLocationOuterClass.TraceLocation, TraceLocationParceler>()
@@ -20,42 +14,7 @@ import java.util.concurrent.TimeUnit
 data class VerifiedTraceLocation(
     private val protoQrCodePayload: TraceLocationOuterClass.QRCodePayload
 ) : Parcelable {
-
-    @IgnoredOnParcel private val vendorData by lazy {
-        TraceLocationOuterClass.CWALocationData.parseFrom(protoQrCodePayload.vendorData)
-    }
-
-    @IgnoredOnParcel val traceLocation: TraceLocation by lazy {
-
-        TraceLocation(
-            version = protoQrCodePayload.version,
-            type = vendorData.type,
-            description = protoQrCodePayload.locationData.description,
-            address = protoQrCodePayload.locationData.address,
-            startDate = protoQrCodePayload.locationData.startTimestamp.toInstant(),
-            endDate = protoQrCodePayload.locationData.endTimestamp.toInstant(),
-            defaultCheckInLengthInMinutes = vendorData.defaultCheckInLengthInMinutes,
-            cryptographicSeed = protoQrCodePayload.crowdNotifierData.cryptographicSeed.toByteArray().toByteString(),
-            cnPublicKey = protoQrCodePayload.crowdNotifierData.publicKey.toStringUtf8()
-        )
-    }
-
-    @IgnoredOnParcel private val traceLocationHeader: ByteString by lazy {
-        "CWA-GUID".encode(Charsets.UTF_8)
-    }
-
-    @IgnoredOnParcel val traceLocationID: ByteString by lazy {
-        Buffer()
-            .write(traceLocationHeader)
-            .write(protoQrCodePayload.toByteArray())
-            .readByteString()
-    }
-
-    /**
-     * Converts time in seconds into [Instant]
-     */
-    private fun Long.toInstant() =
-        if (this == 0L) null else Instant.ofEpochMilli(TimeUnit.SECONDS.toMillis(this))
+    @IgnoredOnParcel val traceLocation: TraceLocation = protoQrCodePayload.traceLocation()
 }
 
 private object TraceLocationParceler : Parceler<TraceLocationOuterClass.TraceLocation> {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt
index eaa1800739549ee6f5c44a1a7331dc3e6d91a371..b39c06703c9b30c4dd27fd5f0a4802e59f545375 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt
@@ -12,7 +12,6 @@ import androidx.appcompat.widget.Toolbar
 import androidx.core.net.toUri
 import androidx.core.view.isGone
 import androidx.fragment.app.Fragment
-import androidx.navigation.NavOptions
 import androidx.navigation.fragment.FragmentNavigatorExtras
 import androidx.navigation.fragment.findNavController
 import androidx.navigation.fragment.navArgs
@@ -24,7 +23,6 @@ import de.rki.coronawarnapp.databinding.TraceLocationAttendeeCheckinsFragmentBin
 import de.rki.coronawarnapp.eventregistration.checkins.CheckIn
 import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.CameraPermissionVH
 import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.CheckInsItem
-import de.rki.coronawarnapp.util.CWADebug
 import de.rki.coronawarnapp.util.di.AutoInject
 import de.rki.coronawarnapp.util.list.isSwipeable
 import de.rki.coronawarnapp.util.list.onSwipeItem
@@ -38,6 +36,8 @@ import de.rki.coronawarnapp.util.ui.viewBindingLazy
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted
 import timber.log.Timber
+import java.lang.Exception
+import java.net.URLEncoder
 import javax.inject.Inject
 
 class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_fragment), AutoInject {
@@ -149,18 +149,6 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag
                     FragmentNavigatorExtras(this to transitionName)
                 )
             }
-            // TODO Remove once feature is done
-            if (CWADebug.isDeviceForTestersBuild) {
-                setOnLongClickListener {
-                    findNavController().navigate(
-                        createCheckInUri(DEBUG_CHECKINS.random()),
-                        NavOptions.Builder().apply {
-                            setLaunchSingleTop(true)
-                        }.build()
-                    )
-                    true
-                }
-            }
         }
     }
 
@@ -224,15 +212,14 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag
     }
 
     companion object {
-        fun createCheckInUri(rootUri: String): Uri = "coronawarnapp://check-ins/$rootUri".toUri()
-
-        @Suppress("MaxLineLength")
-        private val DEBUG_CHECKINS = listOf(
-            "HTTPS://E.CORONAWARN.APP/C1/BJHAUJDFMNSTKMJYGY3S2NJYHA4S2NBRG5QS2YLGMM3C2ZDDHFRTSNRSGZTGIYZWCAARQAJCBVEWGZLDOJSWC3JAKNUG64BKBVGWC2LOEBJXI4TFMV2CAMJQAA4AAQAKCJDTARICEBFRIDICXSP4QTNMBRDF7EOJ3EIJD6AWT24YDOWWXQI22KCUD7R7WARBAC7ONBRPJDB2KK6QKZLF4RE3PXU7PMON4IOZVIHCYPJGBZ27FF5S4",
-            "HTTPS://E.CORONAWARN.APP/C1/BJHAUJDEMVRDGZTGMU2C2MZUGQ2C2NBWGZQS2YLCHEYC2NJQHBRDCMBRMVTDIZBTCAARQAJCBVEWGZLDOJSWC3JAKNUG64BKBVGWC2LOEBJXI4TFMV2CAMJQAA4AAQAKCJDTARICEEAJRWAYJARF3V4AS5OVBODPLPX2V3IJFMFU4O2CAKRH6HGHHWCDMJYCEBH7BO2IU2EEGRKEXBZT2DAOFIMXES5ETUT45QIWDCX64APY7C2ME",
-            "HTTPS://E.CORONAWARN.APP/C1/BJHAUJDBMNQWIMLFHA3S2NZQGVTC2NDDGY3C2ODGGBTC2ZBWGQYDCZJUMRTDEN3FCAARQAJCBVEWGZLDOJSWC3JAKNUG64BKBVGWC2LOEBJXI4TFMV2CAMJQAA4AAQAKCJDTARICEEAKJM3RPYMM2VVCE2GLVK6OKY36F64FRNSI6DWYV7WW6MGESFCDNNQCEA44UHS2GEWHJYHTIJ3AJYM6BC3HEIYHY2HRMPIP7ZF62YBAUKOIY",
-            "HTTPS://E.CORONAWARN.APP/C1/BJHAUJBQGZRDOMJXHEYC2NBRG44C2NBWGZRC2YRQGA4S2MJTGRRDQOJZMU4DMMRQCAARQAJCBVEWGZLDOJSWC3JAKNUG64BKBVGWC2LOEBJXI4TFMV2CAMJQAA4AAQAKCJDTARICEB365TX5SEWICC3JUOAZCQX5YUK2LZZA7RGRTNBXTSEBXTD2766CAARBADXEYUJHQSE7QRQOIPEMSSPLCVC5D4I3FOBDRX64NASE47XKKK5EY",
-            "HTTPS://E.CORONAWARN.APP/C1/BJHAUJDGGE4WKMTEMQZC2OJRMUYC2NBQGNTC2OJZMZRC2MTEG4ZWGMJTGA3GEOBTCAARQAJCBVEWGZLDOJSWC3JAKNUG64BKBVGWC2LOEBJXI4TFMV2CAMJQAA4AAQAKCJDTARICEEANT4HDNB7V5DWCKKUV22YQ7NYOBCTOZ2QUFBOUDZS6V5J2VRVLVSICEBU2YHAEBPQSLWTR75VFC6OEFIS22V6KU4NRDYZHTIBMHS4FDADG6",
-        )
+        fun createCheckInUri(rootUri: String): Uri {
+            val encodedUrl = try {
+                URLEncoder.encode(rootUri, Charsets.UTF_8.name())
+            } catch (e: Exception) {
+                Timber.d(e, "URL Encoding failed url($rootUri)")
+                rootUri // Pass original
+            }
+            return "coronawarnapp://check-ins/$encodedUrl".toUri()
+        }
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModel.kt
index dbfafa23aac8f2e6410cc218b13eceb6d12170c5..e78ae163bec10c1d32b585fc1482ed5ea204597f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModel.kt
@@ -8,13 +8,11 @@ import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.eventregistration.checkins.CheckIn
 import de.rki.coronawarnapp.eventregistration.checkins.CheckInRepository
-import de.rki.coronawarnapp.eventregistration.checkins.qrcode.InvalidQRCodeDataException
 import de.rki.coronawarnapp.eventregistration.checkins.qrcode.QRCodeUriParser
 import de.rki.coronawarnapp.eventregistration.checkins.qrcode.VerifiedTraceLocation
 import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.presencetracing.checkins.checkout.CheckOutHandler
-import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
 import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.ActiveCheckInVH
 import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.CameraPermissionVH
 import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.CheckInsItem
@@ -138,15 +136,7 @@ class CheckInsViewModel @AssistedInject constructor(
     private fun verifyUri(uri: String) = launch {
         try {
             Timber.i("uri: $uri")
-            val qrCodePayloadRaw = qrCodeUriParser.getQrCodePayload(uri)?.toByteArray()
-                ?: throw IllegalArgumentException("Invalid uri: $uri")
-
-            val qrCodePayload = try {
-                TraceLocationOuterClass.QRCodePayload.parseFrom(qrCodePayloadRaw)
-            } catch (e: Exception) {
-                throw InvalidQRCodeDataException(cause = e, message = "QR-code data could not be parsed.")
-            }
-
+            val qrCodePayload = qrCodeUriParser.getQrCodePayload(uri)
             val verifiedTraceLocation = VerifiedTraceLocation(qrCodePayload)
             events.postValue(CheckInEvent.ConfirmCheckIn(verifiedTraceLocation))
         } catch (e: Exception) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInViewModel.kt
index bd50ffcbe58afd1376da965d07776a3d8d8d0864..685f2f245ba266202fac9d439482f8c249a37baa 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInViewModel.kt
@@ -88,23 +88,26 @@ class ConfirmCheckInViewModel @AssistedInject constructor(
         ),
         completed: Boolean = false,
         createJournalEntry: Boolean = true
-    ): CheckIn = CheckIn(
-        traceLocationId = verifiedTraceLocation.traceLocationID,
-        traceLocationIdHash = verifiedTraceLocation.traceLocationID.sha256(),
-        version = traceLocation.version,
-        type = traceLocation.type.number,
-        description = traceLocation.description,
-        address = traceLocation.address,
-        traceLocationStart = traceLocation.startDate,
-        traceLocationEnd = traceLocation.endDate,
-        defaultCheckInLengthInMinutes = traceLocation.defaultCheckInLengthInMinutes,
-        cryptographicSeed = traceLocation.cryptographicSeed,
-        cnPublicKey = traceLocation.cnPublicKey,
-        checkInStart = checkInStart,
-        checkInEnd = checkInEnd,
-        completed = completed,
-        createJournalEntry = createJournalEntry,
-    )
+    ): CheckIn {
+        val traceLocation = verifiedTraceLocation.traceLocation
+        return CheckIn(
+            traceLocationId = traceLocation.locationId,
+            traceLocationIdHash = traceLocation.locationIdHash,
+            version = traceLocation.version,
+            type = traceLocation.type.number,
+            description = traceLocation.description,
+            address = traceLocation.address,
+            traceLocationStart = traceLocation.startDate,
+            traceLocationEnd = traceLocation.endDate,
+            defaultCheckInLengthInMinutes = traceLocation.defaultCheckInLengthInMinutes,
+            cryptographicSeed = traceLocation.cryptographicSeed,
+            cnPublicKey = traceLocation.cnPublicKey,
+            checkInStart = checkInStart,
+            checkInEnd = checkInEnd,
+            completed = completed,
+            createJournalEntry = createJournalEntry,
+        )
+    }
 
     @AssistedFactory
     interface Factory : CWAViewModelFactory<ConfirmCheckInViewModel> {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailViewModel.kt
index d9a58e3871a4c6ce7db771476f2ca273b5683b00..863daf7a12bae805bcd69bdea3da15f443174f13 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailViewModel.kt
@@ -53,11 +53,7 @@ class QrCodeDetailViewModel @AssistedInject constructor(
 
             traceLocationFlow.value = traceLocation
 
-            createQrCode(
-                "HTTPS://E.CORONAWARN.APP/C1/BIYAUEDBZY6EIWF7QX6JOKSRPAGEB3H7CIIEGV2BEBGGC5LOMNUCAUD" +
-                    "BOJ2HSGGTQ6SACIHXQ6SACKA6CJEDARQCEEAPHGEZ5JI2K2T422L5U3SMZY5DGCPUZ2RQACAYEJ3HQYMAFF" +
-                    "BU2SQCEEAJAUCJSQJ7WDM675MCMOD3L2UL7ECJU7TYERH23B746RQTABO3CTI="
-            )
+            createQrCode(traceLocation)
         }
     }
 
@@ -91,9 +87,10 @@ class QrCodeDetailViewModel @AssistedInject constructor(
     /**
      * Creates a QR Code [Bitmap] ,result is delivered by [qrCodeBitmap]
      */
-    private fun createQrCode(input: String) = launch(context = dispatcher.IO) {
-
+    private fun createQrCode(traceLocation: TraceLocation) = launch(context = dispatcher.IO) {
         try {
+            val input = traceLocation.locationUrl
+            Timber.d("input=$input")
             qrCodeBitmap.postValue(qrCodeGenerator.createQrCode(input))
         } catch (e: Exception) {
             Timber.d(e, "Qr code creation failed")
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoBuf.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoBuf.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c0a185307df427ba46134ef4d13afadf0c7c3816
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoBuf.kt
@@ -0,0 +1,7 @@
+package de.rki.coronawarnapp.util
+
+import com.google.protobuf.ByteString
+import okio.ByteString.Companion.toByteString
+
+fun okio.ByteString.toProtoByteString(): ByteString = ByteString.copyFrom(toByteArray())
+fun ByteString.toOkioByteString() = toByteArray().toByteString()
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/attendee/confirm/ConfirmCheckInViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/attendee/confirm/ConfirmCheckInViewModelTest.kt
index 054e7b9473651d136d6f07c03b5a4c5f5f244652..aee24dd7643b2551114c25038649cc427269aad3 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/attendee/confirm/ConfirmCheckInViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/attendee/confirm/ConfirmCheckInViewModelTest.kt
@@ -3,13 +3,18 @@ package de.rki.coronawarnapp.eventregistration.attendee.confirm
 import de.rki.coronawarnapp.eventregistration.checkins.CheckInRepository
 import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
 import de.rki.coronawarnapp.eventregistration.checkins.qrcode.VerifiedTraceLocation
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
 import de.rki.coronawarnapp.ui.eventregistration.attendee.confirm.ConfirmCheckInNavigation
 import de.rki.coronawarnapp.ui.eventregistration.attendee.confirm.ConfirmCheckInViewModel
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.secondsToInstant
 import de.rki.coronawarnapp.util.TimeStamper
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
+import io.mockk.coEvery
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
+import okio.ByteString.Companion.decodeBase64
+import org.joda.time.Instant
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
@@ -20,19 +25,32 @@ import testhelpers.extensions.getOrAwaitValue
 @ExtendWith(InstantExecutorExtension::class)
 class ConfirmCheckInViewModelTest : BaseTest() {
 
-    @MockK lateinit var traceLocation: TraceLocation
     @MockK lateinit var verifiedTraceLocation: VerifiedTraceLocation
     @MockK lateinit var checkInRepository: CheckInRepository
     @MockK lateinit var timeStamper: TimeStamper
 
     private lateinit var viewModel: ConfirmCheckInViewModel
 
+    private val traceLocation = TraceLocation(
+        id = 1,
+        type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
+        description = "My Birthday Party",
+        address = "at my place",
+        startDate = 2687955L.secondsToInstant(),
+        endDate = 2687991L.secondsToInstant(),
+        defaultCheckInLengthInMinutes = null,
+        cryptographicSeed = "CRYPTOGRAPHIC_SEED".decodeBase64()!!,
+        cnPublicKey = "PUB_KEY",
+        version = TraceLocation.VERSION
+    )
+
     @BeforeEach
     fun setUp() {
         MockKAnnotations.init(this)
 
+        coEvery { checkInRepository.addCheckIn(any()) } returns 1L
         every { verifiedTraceLocation.traceLocation } returns traceLocation
-        every { traceLocation.defaultCheckInLengthInMinutes } returns 10
+        every { timeStamper.nowUTC } returns Instant.parse("2021-03-04T10:30:00Z")
 
         viewModel = ConfirmCheckInViewModel(
             verifiedTraceLocation = verifiedTraceLocation,
@@ -49,8 +67,7 @@ class ConfirmCheckInViewModelTest : BaseTest() {
 
     @Test
     fun onConfirmEvent() {
-        // TODO
-//        viewModel.onConfirmTraceLocation()
-//        viewModel.events.getOrAwaitValue() shouldBe ConfirmCheckInNavigation.ConfirmNavigation
+        viewModel.onConfirmTraceLocation()
+        viewModel.events.getOrAwaitValue() shouldBe ConfirmCheckInNavigation.ConfirmNavigation
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/Base32UrlProvider.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/Base32UrlProvider.kt
new file mode 100644
index 0000000000000000000000000000000000000000..036343e6dcf6c681a7f35f89809b365b11da401e
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/Base32UrlProvider.kt
@@ -0,0 +1,81 @@
+package de.rki.coronawarnapp.eventregistration.checkins.qrcode
+
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.CWALocationData
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocation
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.QRCodePayload
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.CrowdNotifierData
+import de.rki.coronawarnapp.util.toProtoByteString
+import okio.ByteString.Companion.decodeBase64
+import org.junit.jupiter.api.extension.ExtensionContext
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.ArgumentsProvider
+import java.util.stream.Stream
+
+class Base32UrlProvider : ArgumentsProvider {
+    override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> {
+        return Stream.of(
+            Arguments.of(
+                "https://e.coronawarn.app?v=1#BAARELAIAEJBCTLZEBBGS4TUNBSGC6JAKBQXE5DZDIFWC5BANV4SA4DMMFRWKKGTQ6SA" +
+                    "CMHXQ6SACGTFBAAREWZQLEYBGBQHFKDERTR5AIAQMCBKQZEM4PIDAEDQGQQAARZ3BRFS24KCCFZSSN7E4YBSPXT7QU4DO" +
+                    "UKYNRUDLSSPJTFOZWCHHV5DFTRKISOOU5Y3ENLQ2WS2HYW5YAPUE3C6XBJRSAEF6352AOK6DICDCMRTGQRAICABCABA",
+                QRCodePayload.newBuilder()
+                    .setVersion(1)
+                    .setCrowdNotifierData(
+                        CrowdNotifierData.newBuilder()
+                            .setCryptographicSeed(CRYPTOGRAPHIC_SEED.decodeBase64()!!.toProtoByteString())
+                            .setPublicKey(PUB_KEY.decodeBase64()!!.toProtoByteString())
+                            .setVersion(1)
+                    )
+                    .setVendorData("CAEQAg==".decodeBase64()!!.toProtoByteString())
+                    .setLocationData(
+                        TraceLocation.newBuilder()
+                            .setDescription("My Birthday Party")
+                            .setAddress("at my place")
+                            .setStartTimestamp(2687955)
+                            .setEndTimestamp(2687991)
+                            .setVersion(1)
+                            .build()
+                    )
+                    .build(),
+                CWALocationData.newBuilder()
+                    .setType(TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER)
+                    .setVersion(1)
+                    .build()
+            ),
+            Arguments.of(
+                "https://e.coronawarn.app?v=1#BAAREIAIAEJA2SLDMVRXEZLBNUQFG2DPOANA2TLBNFXCAU3UOJSWK5BAGENGKCABCJNTA" +
+                    "WJQCMDAOKUGJDHD2AQBAYECVBSIZY6QGAIHANBAABDTWDCLFVYUEELTFE36JZQDE7PH7BJYG5IVQ3DIGXFE6TGK5TMEOPL" +
+                    "2GLHCURE45J3RWI2XBVNFUPRN3QA7IJWF5OCTDEAIL5X3UA4V4GQEGEZDGNBCAYEACEABDAFA",
+                QRCodePayload.newBuilder()
+                    .setVersion(1)
+                    .setCrowdNotifierData(
+                        CrowdNotifierData.newBuilder()
+                            .setCryptographicSeed(CRYPTOGRAPHIC_SEED.decodeBase64()!!.toProtoByteString())
+                            .setPublicKey(PUB_KEY.decodeBase64()!!.toProtoByteString())
+                            .setVersion(1)
+                    )
+                    .setVendorData("CAEQARgK".decodeBase64()!!.toProtoByteString())
+                    .setLocationData(
+                        TraceLocation.newBuilder()
+                            .setDescription("Icecream Shop")
+                            .setAddress("Main Street 1")
+                            .setVersion(1)
+                            .build()
+                    )
+                    .build(),
+                CWALocationData.newBuilder()
+                    .setType(TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER)
+                    .setVersion(1)
+                    .setDefaultCheckInLengthInMinutes(10)
+                    .build()
+            )
+        )
+    }
+
+    companion object {
+        const val CRYPTOGRAPHIC_SEED = "MTIzNA=="
+        const val PUB_KEY =
+            "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg=="
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/Base64UrlProvider.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/Base64UrlProvider.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2d92ae6bc967dc070b483590991c231b79295626
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/Base64UrlProvider.kt
@@ -0,0 +1,82 @@
+package de.rki.coronawarnapp.eventregistration.checkins.qrcode
+
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.CWALocationData
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.TraceLocation
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.QRCodePayload
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.CrowdNotifierData
+import de.rki.coronawarnapp.util.toProtoByteString
+import okio.ByteString.Companion.decodeBase64
+import org.junit.jupiter.api.extension.ExtensionContext
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.ArgumentsProvider
+import java.util.stream.Stream
+
+class Base64UrlProvider : ArgumentsProvider {
+    override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> {
+        return Stream.of(
+            Arguments.of(
+                "https://e.coronawarn.app?v=1#CAESLAgBEhFNeSBCaXJ0aGRheSBQYXJ0eRoLYXQgbXkgcGxhY2Uo04ekATD3h6QBGmoIARJgO" +
+                    "MTa6eYSiaDv8lW13xdYEvGHOZ1EYTiFSxt51HEoPCD7CNnvCUiIYPhax1MpkN0UfNClCm9ZWYy0JH01CDVD9eq-vox" +
+                    "Q1EcFJQkEIujVwoCNK0MNGuDK1ayjGxeDc4UDGgQxMjM0IgQIARAC",
+                QRCodePayload.newBuilder()
+                    .setVersion(1)
+                    .setCrowdNotifierData(
+                        CrowdNotifierData.newBuilder()
+                            .setCryptographicSeed(CRYPTOGRAPHIC_SEED.decodeBase64()!!.toProtoByteString())
+                            .setPublicKey(PUB_KEY.decodeBase64()!!.toProtoByteString())
+                            .setVersion(1)
+                    )
+                    .setVendorData("CAEQAg==".decodeBase64()!!.toProtoByteString())
+                    .setLocationData(
+                        TraceLocation.newBuilder()
+                            .setDescription("My Birthday Party")
+                            .setAddress("at my place")
+                            .setStartTimestamp(2687955)
+                            .setEndTimestamp(2687991)
+                            .setVersion(1)
+                            .build()
+                    )
+                    .build(),
+                CWALocationData.newBuilder()
+                    .setType(TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER)
+                    .setVersion(1)
+                    .build()
+            ),
+            Arguments.of(
+                "https://e.coronawarn.app?v=1#CAESIAgBEg1JY2VjcmVhbSBTaG9wGg1NYWluIFN0cmVldCAxGmoIARJgOMTa6eYSiaDv8lW1" +
+                    "3xdYEvGHOZ1EYTiFSxt51HEoPCD7CNnvCUiIYPhax1MpkN0UfNClCm9ZWYy0JH01CDVD9eq-voxQ" +
+                    "1EcFJQkEIujVwoCNK0MNGuDK1ayjGxeDc4UDGgQxMjM0IgYIARABGAo",
+                QRCodePayload.newBuilder()
+                    .setVersion(1)
+                    .setCrowdNotifierData(
+                        CrowdNotifierData.newBuilder()
+                            .setCryptographicSeed(CRYPTOGRAPHIC_SEED.decodeBase64()!!.toProtoByteString())
+                            .setPublicKey(PUB_KEY.decodeBase64()!!.toProtoByteString())
+                            .setVersion(1)
+                    )
+                    .setVendorData("CAEQARgK".decodeBase64()!!.toProtoByteString())
+                    .setLocationData(
+                        TraceLocation.newBuilder()
+                            .setDescription("Icecream Shop")
+                            .setAddress("Main Street 1")
+                            .setVersion(1)
+                            .build()
+                    )
+                    .build(),
+                CWALocationData.newBuilder()
+                    .setType(TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER)
+                    .setVersion(1)
+                    .setDefaultCheckInLengthInMinutes(10)
+                    .build()
+            )
+        )
+    }
+
+    companion object {
+        const val CRYPTOGRAPHIC_SEED = "MTIzNA=="
+        const val PUB_KEY =
+            "OMTa6eYSiaDv8lW13xdYEvGHOZ1EYTiFSxt51HEoPCD7CNnvCUiIYPhax1MpkN0UfNClCm9ZWYy0JH01CDVD9" +
+                "eq+voxQ1EcFJQkEIujVwoCNK0MNGuDK1ayjGxeDc4UD"
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifierTest2.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifierTest2.kt
deleted file mode 100644
index 5a767d467dcc7696076c8e28082bf2f79dee8074..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/DefaultQRCodeVerifierTest2.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-package de.rki.coronawarnapp.eventregistration.checkins.qrcode
-
-import testhelpers.BaseTest
-
-class DefaultQRCodeVerifierTest2 : BaseTest() {
-
-    /* Disabled, because new protobuf doesn't include signed traceLocation, we should write tests for the parsing of
-    QrCodePayload protobuf ...
-
-    @Test
-    fun `protobuf decoding 1`() {
-        val signedTraceLocation =
-            TraceLocationOuterClass.SignedTraceLocation.parseFrom(
-                "BJLAUJBTGA2TKMZTGFRS2MRTGA3C2NBTMYZS2OJXGQZC2NTEHBTGCYRVGRSTQNBYCAARQARCCFGXSICCNFZHI2DEMF4SAUDBOJ2HSKQLMF2CA3LZEBYGYYLDMUYNHB5EAE4PPB5EAFAAAESGGBCAEIDFJJ7KHRO3ZZ2SFMJSBXSUY2ZZKGOIZS27L2D6VPKTA57M6RZY3MBCARR7LXAA2BY3IGNTHNFFAJSMIXF6PP4TEB3I2C3D7P32QUZHVVER"
-                    .decodeBase32().toByteArray()
-            )
-
-        signedTraceLocation.apply {
-            TraceLocationOuterClass.TraceLocation.parseFrom(location).apply {
-                guid shouldBe "3055331c-2306-43f3-9742-6d8fab54e848"
-                version shouldBe 1
-                typeValue shouldBe 2
-                description shouldBe "My Birthday Party"
-                address shouldBe "at my place"
-                startTimestamp shouldBe 2687955
-                endTimestamp shouldBe 2687991
-                defaultCheckInLengthInMinutes shouldBe 0
-            }
-            signature.toByteArray().toByteString()
-                .base64() shouldBe "MEQCIGVKfqPF2851IrEyDeVMazlRnIzLX16H6r1TB37PRzjbAiBGP13ADQcbQZsztKUCZMRcvnv5Mgdo0LY/v3qFMnrUkQ=="
-        }
-
-        signedTraceLocation.location.toByteArray().toByteString()
-            .base64() shouldBe "CiQzMDU1MzMxYy0yMzA2LTQzZjMtOTc0Mi02ZDhmYWI1NGU4NDgQARgCIhFNeSBCaXJ0aGRheSBQYXJ0eSoLYXQgbXkgcGxhY2Uw04ekATj3h6QBQAA="
-    }
-
-    @Test
-    fun `protobuf decoding 2`() {
-        val signedTraceLocation = TraceLocationOuterClass.SignedTraceLocation.parseFrom(
-            "BJHAUJDGMNQTQNDCGM3S2NRRMMYC2NDBG5RS2YRSMY4C2OBSGVRWCZDEGUYDMY3GCAARQAJCBVEWGZLDOJSWC3JAKNUG64BKBVGWC2LOEBJXI4TFMV2CAMJQAA4AAQAKCJDDARACEA2ZCTGOF2HH2RQU7ODZMCSUTUBBNQYM6AR4NG6FFLC6ISXWEOI5UARADO44YYH3U53ZYL6IYM5DWALXUESAJNWRGRL5KLNLS5BM54SHDDCA"
-                .decodeBase32().toByteArray()
-        )
-
-        signedTraceLocation.apply {
-            TraceLocationOuterClass.TraceLocation.parseFrom(location).apply {
-                guid shouldBe "fca84b37-61c0-4a7c-b2f8-825cadd506cf"
-                version shouldBe 1
-                typeValue shouldBe 1
-                description shouldBe "Icecream Shop"
-                address shouldBe "Main Street 1"
-                startTimestamp shouldBe 0
-                endTimestamp shouldBe 0
-                defaultCheckInLengthInMinutes shouldBe 10
-            }
-            signature.toByteArray().toByteString()
-                .base64() shouldBe "MEQCIDWRTM4ujn1GFPuHlgpUnQIWwwzwI8abxSrF5Er2I5HaAiAbucxg+6d3nC/Iwzo7AXehJAS20TRX1S2rl0LO8kcYxA=="
-        }
-
-        signedTraceLocation.location.toByteArray().toByteString()
-            .base64() shouldBe "CiRmY2E4NGIzNy02MWMwLTRhN2MtYjJmOC04MjVjYWRkNTA2Y2YQARgBIg1JY2VjcmVhbSBTaG9wKg1NYWluIFN0cmVldCAxMAA4AEAK"
-    }
-
-     */
-}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeUriParserTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeUriParserTest.kt
index 71a1c8722df6ebbcae83bb335bebdd1176f56d30..c01a15b2b532b8da63ff40271b1c22e9ed49910f 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeUriParserTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/QRCodeUriParserTest.kt
@@ -1,24 +1,91 @@
 package de.rki.coronawarnapp.eventregistration.checkins.qrcode
 
+import de.rki.coronawarnapp.appconfig.AppConfigProvider
+import de.rki.coronawarnapp.appconfig.ConfigData
+import de.rki.coronawarnapp.appconfig.PresenceTracingConfigContainer
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.CWALocationData
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass.QRCodePayload
+import de.rki.coronawarnapp.server.protocols.internal.v2.PresenceTracingParametersOuterClass.PresenceTracingQRCodeDescriptor
+import de.rki.coronawarnapp.server.protocols.internal.v2.PresenceTracingParametersOuterClass.PresenceTracingQRCodeDescriptor.PayloadEncoding
+import io.kotest.assertions.throwables.shouldThrow
 import io.kotest.matchers.shouldBe
-import io.kotest.matchers.shouldNotBe
+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.test.runBlockingTest
+import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.params.ParameterizedTest
 import org.junit.jupiter.params.provider.ArgumentsSource
 import testhelpers.BaseTest
 
+@Suppress("BlockingMethodInNonBlockingContext")
 class QRCodeUriParserTest : BaseTest() {
 
-    fun createInstance() = QRCodeUriParser()
+    @MockK lateinit var configProvider: AppConfigProvider
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+        coEvery { configProvider.getAppConfig() } returns mockk<ConfigData>().apply {
+            every { presenceTracing } returns PresenceTracingConfigContainer(
+                qrCodeDescriptors = listOf(
+                    PresenceTracingQRCodeDescriptor.newBuilder()
+                        .setVersionGroupIndex(0)
+                        .setEncodedPayloadGroupIndex(1)
+                        .setPayloadEncoding(PayloadEncoding.BASE64)
+                        .setRegexPattern("https://e\\.coronawarn\\.app\\?v=(\\d+)\\#(.+)")
+                        .build()
+                )
+            )
+        }
+    }
+
+    fun createInstance() = QRCodeUriParser(configProvider)
 
     @ParameterizedTest
-    @ArgumentsSource(ValidUrlProvider::class)
-    fun `Valid URLs`(input: String) {
-        createInstance().getQrCodePayload(input) shouldNotBe null
+    @ArgumentsSource(Base64UrlProvider::class)
+    fun `Base64 Valid URLs`(
+        input: String,
+        expectedPayload: QRCodePayload,
+        expectedVendorData: CWALocationData
+    ) = runBlockingTest {
+        val qrCodePayload = createInstance().getQrCodePayload(input)
+        qrCodePayload shouldBe expectedPayload
+        CWALocationData.parseFrom(qrCodePayload.vendorData) shouldBe expectedVendorData
+    }
+
+    @ParameterizedTest
+    @ArgumentsSource(Base32UrlProvider::class)
+    fun `Base32 Valid URLs`(
+        input: String,
+        expectedPayload: QRCodePayload,
+        expectedVendorData: CWALocationData
+    ) = runBlockingTest {
+        coEvery { configProvider.getAppConfig() } returns mockk<ConfigData>().apply {
+            every { presenceTracing } returns PresenceTracingConfigContainer(
+                qrCodeDescriptors = listOf(
+                    PresenceTracingQRCodeDescriptor.newBuilder()
+                        .setVersionGroupIndex(0)
+                        .setEncodedPayloadGroupIndex(1)
+                        .setPayloadEncoding(PayloadEncoding.BASE32)
+                        .setRegexPattern("https://e\\.coronawarn\\.app\\?v=(\\d+)\\#(.+)")
+                        .build()
+                )
+            )
+        }
+
+        val qrCodePayload = createInstance().getQrCodePayload(input)
+        qrCodePayload shouldBe expectedPayload
+        CWALocationData.parseFrom(qrCodePayload.vendorData) shouldBe expectedVendorData
     }
 
     @ParameterizedTest
     @ArgumentsSource(InvalidUrlProvider::class)
-    fun `Invalid URLs`(input: String) {
-        createInstance().getQrCodePayload(input) shouldBe null
+    fun `Invalid URLs`(input: String) = runBlockingTest {
+        shouldThrow<InvalidQrCodeUriException> {
+            createInstance().getQrCodePayload(input)
+        }
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/ValidUrlProvider.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/ValidUrlProvider.kt
deleted file mode 100644
index f7e0bf42fae6a0c6d362ad86c1ffdb14bf97fc9f..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/checkins/qrcode/ValidUrlProvider.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package de.rki.coronawarnapp.eventregistration.checkins.qrcode
-
-import org.junit.jupiter.api.extension.ExtensionContext
-import org.junit.jupiter.params.provider.Arguments
-import org.junit.jupiter.params.provider.ArgumentsProvider
-import java.util.stream.Stream
-
-class ValidUrlProvider : ArgumentsProvider {
-    override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> {
-        return Stream.of(
-            Arguments.of(
-                "HTTPS://E.CORONAWARN.APP/C1/BIYAUEDBZY6EIWF7QX6JOKSRPAGEB3H7CIIEGV2BEBGGC5LOMNUCAUDBO" +
-                    "J2HSGGTQ6SACIHXQ6SACKA6CJEDARQCEEAPHGEZ5JI2K2T422L5U3SMZY5DGCPUZ2RQACAYEJ3HQYMAFFBU2" +
-                    "SQCEEAJAUCJSQJ7WDM675MCMOD3L2UL7ECJU7TYERH23B746RQTABO3CTI="
-            ),
-            Arguments.of(
-                "https://e.coronawarn.app/c1/BIYAUEDBZY6EIWF7QX6JOKSRPAGEB3H7CIIEGV2BEBGGC5LOMNUCAUDBO" +
-                    "J2HSGGTQ6SACIHXQ6SACKA6CJEDARQCEEAPHGEZ5JI2K2T422L5U3SMZY5DGCPUZ2RQACAYEJ3HQYMAFFBU2" +
-                    "SQCEEAJAUCJSQJ7WDM675MCMOD3L2UL7ECJU7TYERH23B746RQTABO3CTI="
-            ),
-            Arguments.of(
-                "https://e.coronawarn.app/c1/BJLAUJBTGA2TKMZTGFRS2MRTGA3C2NBTMYZS2OJXGQZC2NTEHBTGCYRVG" +
-                    "RSTQNBYCAARQARCCFGXSICCNFZHI2DEMF4SAUDBOJ2HSKQLMF2CA3LZEBYGYYLDMUYNHB5EAE4PPB5EAF" +
-                    "AAAESIGBDAEIIARVENF6QT6XZATJ5GSDHL77BCAGR6QKDEUJRP2RDCTKTS7QECWMFAEIIA47MT2EA7MQK" +
-                    "GNQU2XCY3Y2ZOZXCILDPC65PBUO4JJHT5LQQWDQSA"
-            ),
-            Arguments.of(
-                "https://e.coronawarn.app/c1/BJHAUJDGMNQTQNDCGM3S2NRRMMYC2NDBG5RS2YRSMY4C2OBSGVRWCZDEG" +
-                    "UYDMY3GCAARQAJCBVEWGZLDOJSWC3JAKNUG64BKBVGWC2LOEBJXI4TFMV2CAMJQAA4AAQAKCJDTARICEB" +
-                    "NEPPKKTAAIH5BSV45EPOINHOASARJLYYSHNTUUHLNGVYUZXZEBWARBACD53WYEGYXYQS3STOFLSOVM3XX" +
-                    "D5A5HKMFQR7WYYARKKVOFGYGHO"
-            ),
-            Arguments.of("https://e.coronawarn.app/c1/JBSWY3DPEBLW64TMMQQQ===="),
-            Arguments.of("https://e.coronawarn.app/c1/JBSWY3DPEBLW64TMMQQQ"),
-            Arguments.of("https://e.coronawarn.app/c1/JBSWY3DPEBLW64TMMQQQ========"),
-        )
-    }
-}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/QrCodePayloadTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/QrCodePayloadTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..683a645639868de09b9607ee724e21801bfac02c
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/QrCodePayloadTest.kt
@@ -0,0 +1,67 @@
+package de.rki.coronawarnapp.eventregistration.events
+
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.qrCodePayload
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.secondsToInstant
+import io.kotest.matchers.shouldBe
+import okio.ByteString.Companion.decodeBase64
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class QrCodePayloadTest : BaseTest() {
+
+    @Test
+    fun `Trace location to QrCodePayload 1`() {
+        val traceLocation = TraceLocation(
+            id = 1,
+            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
+            description = "My Birthday Party",
+            address = "at my place",
+            startDate = 2687955L.secondsToInstant(),
+            endDate = 2687991L.secondsToInstant(),
+            defaultCheckInLengthInMinutes = null,
+            cryptographicSeed = CRYPTOGRAPHIC_SEED.decodeBase64()!!,
+            cnPublicKey = PUB_KEY,
+            version = TraceLocation.VERSION
+        )
+
+        traceLocation.qrCodePayload() shouldBe
+            TraceLocationOuterClass.QRCodePayload.parseFrom(PAYLOAD_1.decodeBase64()!!.toByteArray())
+    }
+
+    @Test
+    fun `Trace location to QrCodePayload 2`() {
+        val traceLocation = TraceLocation(
+            id = 2,
+            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER,
+            description = "Icecream Shop",
+            address = "Main Street 1",
+            startDate = null,
+            endDate = null,
+            defaultCheckInLengthInMinutes = 10,
+            cryptographicSeed = CRYPTOGRAPHIC_SEED.decodeBase64()!!,
+            cnPublicKey = PUB_KEY,
+            version = TraceLocation.VERSION
+        )
+
+        traceLocation.qrCodePayload() shouldBe
+            TraceLocationOuterClass.QRCodePayload.parseFrom(PAYLOAD_2.decodeBase64()!!.toByteArray())
+    }
+
+    companion object {
+        private const val PAYLOAD_1 =
+            "CAESLAgBEhFNeSBCaXJ0aGRheSBQYXJ0eRoLYXQgbXkgcGxhY2Uo04ekATD3h6QBGmUIARJbMFkwEwYHKoZIzj0CAQYIKo" +
+                "ZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxe" +
+                "uFMZAIX2+6A5XhoEMTIzNCIECAEQAg=="
+
+        private const val PAYLOAD_2 =
+            "CAESIAgBEg1JY2VjcmVhbSBTaG9wGg1NYWluIFN0cmVldCAxGmUIARJbMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIR" +
+                "cyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5XhoEMTIzNCIGCAEQARgK"
+
+        private const val CRYPTOGRAPHIC_SEED = "MTIzNA=="
+        private const val PUB_KEY =
+            "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0z" +
+                "K7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg=="
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationIdTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationIdTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bc1c62af21a381de2212a6650f6ad47ccf36e2c6
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationIdTest.kt
@@ -0,0 +1,77 @@
+package de.rki.coronawarnapp.eventregistration.events
+
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.traceLocation
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.secondsToInstant
+import io.kotest.matchers.shouldBe
+import okio.ByteString.Companion.decodeBase64
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class TraceLocationIdTest : BaseTest() {
+    @Test
+    fun `locationId from qrCodePayloadBase64 - 1`() {
+        val qrCodePayloadBase64 =
+            "CAESLAgBEhFNeSBCaXJ0aGRheSBQYXJ0eRoLYXQgbXkgcGxhY2Uo04ekATD3h6QBGmUIARJbMFkwEwYHKoZIzj0CAQYIKo" +
+                "ZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxe" +
+                "uFMZAIX2+6A5XhoEMTIzNCIECAEQAg=="
+        val qrCodePayload = TraceLocationOuterClass.QRCodePayload.parseFrom(
+            qrCodePayloadBase64.decodeBase64()!!.toByteArray()
+        )
+        qrCodePayload.traceLocation().locationId.base64() shouldBe "jNcJTCajd9Sen6Tbexl2Yb7O3J7ps47b6k4+QMT4xS0="
+    }
+
+    @Test
+    fun `locationId from qrCodePayloadBase64 - 2`() {
+        val qrCodePayloadBase64 =
+            "CAESIAgBEg1JY2VjcmVhbSBTaG9wGg1NYWluIFN0cmVldCAxGmUIARJbMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIR" +
+                "cyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5XhoEMTIzNCIGCAEQARgK"
+        val qrCodePayload = TraceLocationOuterClass.QRCodePayload.parseFrom(
+            qrCodePayloadBase64.decodeBase64()!!.toByteArray()
+        )
+        qrCodePayload.traceLocation().locationId.base64() shouldBe "GMuCjqNmOdYyrFhyvFNTVEeLaZh+uShgUoY0LYJo4YQ="
+    }
+
+    @Test
+    fun `locationId from traceLocation - 1`() {
+        val traceLocation = TraceLocation(
+            id = 1,
+            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
+            description = "My Birthday Party",
+            address = "at my place",
+            startDate = 2687955L.secondsToInstant(),
+            endDate = 2687991L.secondsToInstant(),
+            defaultCheckInLengthInMinutes = null,
+            cryptographicSeed = CRYPTOGRAPHIC_SEED.decodeBase64()!!,
+            cnPublicKey = PUB_KEY,
+            version = TraceLocation.VERSION
+        )
+        traceLocation.locationId.base64() shouldBe "jNcJTCajd9Sen6Tbexl2Yb7O3J7ps47b6k4+QMT4xS0="
+    }
+
+    @Test
+    fun `locationId from traceLocation - 2`() {
+        val traceLocation = TraceLocation(
+            id = 2,
+            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER,
+            description = "Icecream Shop",
+            address = "Main Street 1",
+            startDate = null,
+            endDate = null,
+            defaultCheckInLengthInMinutes = 10,
+            cryptographicSeed = CRYPTOGRAPHIC_SEED.decodeBase64()!!,
+            cnPublicKey = PUB_KEY,
+            version = TraceLocation.VERSION
+        )
+
+        traceLocation.locationId.base64() shouldBe "GMuCjqNmOdYyrFhyvFNTVEeLaZh+uShgUoY0LYJo4YQ="
+    }
+
+    companion object {
+        private const val CRYPTOGRAPHIC_SEED = "MTIzNA=="
+        private const val PUB_KEY =
+            "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0z" +
+                "K7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg=="
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationUrlTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationUrlTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..aee6965e78df1ed7e771ec7b6bb041c3fbaa6ec6
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/events/TraceLocationUrlTest.kt
@@ -0,0 +1,62 @@
+package de.rki.coronawarnapp.eventregistration.events
+
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.secondsToInstant
+import io.kotest.matchers.shouldBe
+import kotlinx.coroutines.test.runBlockingTest
+import okio.ByteString.Companion.decodeBase64
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class TraceLocationUrlTest : BaseTest() {
+
+    @Test
+    fun `locationUrl 1`() = runBlockingTest {
+        val traceLocation = TraceLocation(
+            id = 1,
+            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
+            description = "My Birthday Party",
+            address = "at my place",
+            startDate = 2687955L.secondsToInstant(),
+            endDate = 2687991L.secondsToInstant(),
+            defaultCheckInLengthInMinutes = null,
+            cryptographicSeed = CRYPTOGRAPHIC_SEED.decodeBase64()!!,
+            cnPublicKey = PUB_KEY,
+            version = TraceLocation.VERSION
+        )
+
+        traceLocation.locationUrl shouldBe
+            "https://e.coronawarn.app?v=1#CAESLAgBEhFNeSBCaXJ0aGRheSBQYXJ0eRoLYXQgbXkgcGxhY2Uo04ekATD3h6QBGmoIAR" +
+            "JgOMTa6eYSiaDv8lW13xdYEvGHOZ1EYTiFSxt51HEoPCD7CNnvCUiIYPhax1MpkN0UfNClCm9ZWYy0JH01CDVD9eq-voxQ1EcFJ" +
+            "QkEIujVwoCNK0MNGuDK1ayjGxeDc4UDGgQxMjM0IgQIARAC"
+    }
+
+    @Test
+    fun `locationUrl 2`() = runBlockingTest {
+        val traceLocation = TraceLocation(
+            id = 2,
+            type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_OTHER,
+            description = "Icecream Shop",
+            address = "Main Street 1",
+            startDate = null,
+            endDate = null,
+            defaultCheckInLengthInMinutes = 10,
+            cryptographicSeed = CRYPTOGRAPHIC_SEED.decodeBase64()!!,
+            cnPublicKey = PUB_KEY,
+            version = TraceLocation.VERSION
+        )
+
+        traceLocation.locationUrl shouldBe
+            "https://e.coronawarn.app?v=1#CAESIAgBEg1JY2VjcmVhbSBTaG9wGg1NYWluIFN0cmVldCAxGmoIARJgOMTa6eYSiaDv8l" +
+            "W13xdYEvGHOZ1EYTiFSxt51HEoPCD7CNnvCUiIYPhax1MpkN0UfNClCm9ZWYy0JH01CDVD9eq-voxQ1EcFJQkEIujVwoCNK0MNG" +
+            "uDK1ayjGxeDc4UDGgQxMjM0IgYIARABGAo"
+    }
+
+    companion object {
+        private const val CRYPTOGRAPHIC_SEED = "MTIzNA=="
+        private const val PUB_KEY =
+            "OMTa6eYSiaDv8lW13xdYEvGHOZ1EYTiFSxt51HEoPCD7CNnvCUiIYPhax1MpkN0UfNClCm9ZWYy0JH01CDVD9" +
+                "eq+voxQ1EcFJQkEIujVwoCNK0MNGuDK1ayjGxeDc4UD"
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModelTest.kt
index 77d37b6285bcc0b9d4981ce580d366e7440d0ed8..bfbd074700697d48cbfc6eebf01d6c887164530c 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsViewModelTest.kt
@@ -5,6 +5,7 @@ import de.rki.coronawarnapp.eventregistration.checkins.CheckIn
 import de.rki.coronawarnapp.eventregistration.checkins.CheckInRepository
 import de.rki.coronawarnapp.eventregistration.checkins.qrcode.QRCodeUriParser
 import de.rki.coronawarnapp.presencetracing.checkins.checkout.CheckOutHandler
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
 import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.ActiveCheckInVH
 import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.CameraPermissionVH
 import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.PastCheckInVH
@@ -23,7 +24,6 @@ import io.mockk.verify
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runBlockingTest
-import okio.ByteString
 import org.joda.time.Instant
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
@@ -80,11 +80,12 @@ class CheckInsViewModelTest : BaseTest() {
     @Test
     fun `DeepLink verification`() = runBlockingTest {
         every { savedState.get<String>(any()) } returns null
-        every { qrCodeUriParser.getQrCodePayload(any()) } returns ByteString.EMPTY
+        coEvery { qrCodeUriParser.getQrCodePayload(any()) } returns
+            TraceLocationOuterClass.QRCodePayload.newBuilder().build()
 
         createInstance(deepLink = DEEP_LINK, scope = this).apply {
             events.getOrAwaitValue().shouldBeInstanceOf<CheckInEvent.ConfirmCheckIn>()
-            verify {
+            coVerify {
                 savedState.get<String>(any())
                 qrCodeUriParser.getQrCodePayload(any())
                 savedState.set(any(), any<String>())
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ProtoBufKtTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ProtoBufKtTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b1678a5b59974ee94f11483bd2965ec4fc1c0008
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ProtoBufKtTest.kt
@@ -0,0 +1,28 @@
+package de.rki.coronawarnapp.util
+
+import com.google.protobuf.ByteString
+import io.kotest.matchers.shouldBe
+import okio.ByteString.Companion.toByteString
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class ProtoBufKtTest : BaseTest() {
+
+    @Test
+    fun toProtoByteString() {
+        val okioByteString = KEY.toByteArray().toByteString()
+
+        okioByteString.toProtoByteString() shouldBe ByteString.copyFromUtf8(KEY)
+    }
+
+    @Test
+    fun toOkioByteString() {
+        val protoByteString = ByteString.copyFromUtf8(KEY)
+
+        protoByteString.toOkioByteString() shouldBe KEY.toByteArray().toByteString()
+    }
+
+    companion object {
+        private const val KEY = "No generated key"
+    }
+}