From 41d3c1bcf90b45bdf3469ba07de070a8919c165b Mon Sep 17 00:00:00 2001
From: Mohamed <mohamed.metwalli@sap.com>
Date: Mon, 12 Apr 2021 10:14:36 +0200
Subject: [PATCH] Extend poster testability (EXPOSUREAPP-6308) (#2792)

* Rename

* Support  positioning configurations

* Connect sliders values

* Change color

* Polishing

* ViewModel test - resize qr-code

* Font size

* lint

* Polishing

* Add tooltip

* lint

Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com>
---
 .../test/menu/ui/TestMenuFragmentViewModel.kt |   4 +-
 .../ui/PresenceTracingTestFragment.kt}        |  24 +-
 .../ui/PresenceTracingTestFragmentModule.kt}  |  10 +-
 .../ui/PresenceTracingTestViewModel.kt}       |   6 +-
 .../ui/poster/QrCodePosterTestFragment.kt     | 298 ++++++++++++++++++
 .../poster/QrCodePosterTestFragmentModule.kt  |  18 ++
 .../ui/poster/QrCodePosterTestViewModel.kt    | 138 ++++++++
 .../ui/main/MainActivityTestModule.kt         |  16 +-
 ...xml => fragment_test_presence_tracing.xml} |   0
 .../layout/fragment_test_qr_code_poster.xml   | 277 ++++++++++++++++
 .../res/navigation/test_nav_graph.xml         |  24 +-
 .../EventRegistrationUIModule.kt              |   5 +
 12 files changed, 778 insertions(+), 42 deletions(-)
 rename Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/{eventregistration/ui/EventRegistrationTestFragment.kt => presencetracing/ui/PresenceTracingTestFragment.kt} (84%)
 rename Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/{eventregistration/ui/EventRegistrationTestFragmentModule.kt => presencetracing/ui/PresenceTracingTestFragmentModule.kt} (53%)
 rename Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/{eventregistration/ui/EventRegistrationTestFragmentViewModel.kt => presencetracing/ui/PresenceTracingTestViewModel.kt} (96%)
 create mode 100644 Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragment.kt
 create mode 100644 Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragmentModule.kt
 create mode 100644 Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestViewModel.kt
 rename Corona-Warn-App/src/deviceForTesters/res/layout/{fragment_test_eventregistration.xml => fragment_test_presence_tracing.xml} (100%)
 create mode 100644 Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_qr_code_poster.xml

diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt
index e631969b4..b4200bc33 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt
@@ -10,7 +10,7 @@ import de.rki.coronawarnapp.test.crash.ui.SettingsCrashReportFragment
 import de.rki.coronawarnapp.test.datadonation.ui.DataDonationTestFragment
 import de.rki.coronawarnapp.test.debugoptions.ui.DebugOptionsFragment
 import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaonboardingFragment
-import de.rki.coronawarnapp.test.eventregistration.ui.EventRegistrationTestFragment
+import de.rki.coronawarnapp.test.presencetracing.ui.PresenceTracingTestFragment
 import de.rki.coronawarnapp.test.keydownload.ui.KeyDownloadTestFragment
 import de.rki.coronawarnapp.test.playground.ui.PlaygroundFragment
 import de.rki.coronawarnapp.test.risklevel.ui.TestRiskLevelCalculationFragment
@@ -36,7 +36,7 @@ class TestMenuFragmentViewModel @AssistedInject constructor() : CWAViewModel() {
             PlaygroundFragment.MENU_ITEM,
             DataDonationTestFragment.MENU_ITEM,
             DeltaonboardingFragment.MENU_ITEM,
-            EventRegistrationTestFragment.MENU_ITEM,
+            PresenceTracingTestFragment.MENU_ITEM,
         ).let { MutableLiveData(it) }
     }
     val showTestScreenEvent = SingleLiveEvent<TestMenuItem>()
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/presencetracing/ui/PresenceTracingTestFragment.kt
similarity index 84%
rename from Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragment.kt
rename to Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestFragment.kt
index 95d522e04..8e54311d1 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/presencetracing/ui/PresenceTracingTestFragment.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.test.eventregistration.ui
+package de.rki.coronawarnapp.test.presencetracing.ui
 
 import android.annotation.SuppressLint
 import android.os.Bundle
@@ -11,7 +11,7 @@ import androidx.core.text.scale
 import androidx.core.view.isVisible
 import androidx.fragment.app.Fragment
 import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.databinding.FragmentTestEventregistrationBinding
+import de.rki.coronawarnapp.databinding.FragmentTestPresenceTracingBinding
 import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
 import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
 import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat
@@ -24,12 +24,12 @@ import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
 import javax.inject.Inject
 
 @SuppressLint("SetTextI18n")
-class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregistration), AutoInject {
+class PresenceTracingTestFragment : Fragment(R.layout.fragment_test_presence_tracing), AutoInject {
 
     @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
-    private val viewModel: EventRegistrationTestFragmentViewModel by cwaViewModels { viewModelFactory }
+    private val viewModel: PresenceTracingTestViewModel by cwaViewModels { viewModelFactory }
 
-    private val binding: FragmentTestEventregistrationBinding by viewBindingLazy()
+    private val binding: FragmentTestPresenceTracingBinding by viewBindingLazy()
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
@@ -71,8 +71,8 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis
                     lastOrganiserLocationUrl.text = styleText("URL", traceLocation.locationUrl)
                     qrcodeButton.setOnClickListener {
                         doNavigate(
-                            EventRegistrationTestFragmentDirections
-                                .actionEventRegistrationTestFragmentToQrCodePosterFragmentTest(traceLocation.id)
+                            PresenceTracingTestFragmentDirections
+                                .actionPresenceTracingTestFragmentToQrCodePosterTestFragment(traceLocation.id)
                         )
                     }
                 }
@@ -112,7 +112,7 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis
         buildSpannedString {
             bold {
                 color(requireContext().getColorCompat(R.color.colorAccent)) {
-                    append("$key=")
+                    append("$key = ")
                 }
             }
 
@@ -121,14 +121,14 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis
                     append(value.toString())
                 }
             }
-            append("\n")
+            appendLine()
         }
 
     companion object {
         val MENU_ITEM = TestMenuItem(
-            title = "Event Registration",
-            description = "View & Control the event registration.",
-            targetId = R.id.eventRegistrationTestFragment
+            title = "Presence Tracing",
+            description = "View & Control presence tracing",
+            targetId = R.id.presenceTracingTestFragment
         )
     }
 }
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragmentModule.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestFragmentModule.kt
similarity index 53%
rename from Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragmentModule.kt
rename to Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestFragmentModule.kt
index 3c95a0a4a..db41dfdf6 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragmentModule.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestFragmentModule.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.test.eventregistration.ui
+package de.rki.coronawarnapp.test.presencetracing.ui
 
 import dagger.Binds
 import dagger.Module
@@ -8,11 +8,11 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
 
 @Module
-abstract class EventRegistrationTestFragmentModule {
+abstract class PresenceTracingTestFragmentModule {
     @Binds
     @IntoMap
-    @CWAViewModelKey(EventRegistrationTestFragmentViewModel::class)
-    abstract fun testEventRegistrationFragment(
-        factory: EventRegistrationTestFragmentViewModel.Factory
+    @CWAViewModelKey(PresenceTracingTestViewModel::class)
+    abstract fun testPresenceTracingFragment(
+        factory: PresenceTracingTestViewModel.Factory
     ): CWAViewModelFactory<out CWAViewModel>
 }
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/presencetracing/ui/PresenceTracingTestViewModel.kt
similarity index 96%
rename from Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/eventregistration/ui/EventRegistrationTestFragmentViewModel.kt
rename to Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestViewModel.kt
index 3913503fe..7e0e674bc 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/presencetracing/ui/PresenceTracingTestViewModel.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.test.eventregistration.ui
+package de.rki.coronawarnapp.test.presencetracing.ui
 
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
@@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.map
 import timber.log.Timber
 import kotlin.system.measureTimeMillis
 
-class EventRegistrationTestFragmentViewModel @AssistedInject constructor(
+class PresenceTracingTestViewModel @AssistedInject constructor(
     dispatcherProvider: DispatcherProvider,
     traceLocationRepository: TraceLocationRepository,
     checkInRepository: CheckInRepository,
@@ -144,5 +144,5 @@ class EventRegistrationTestFragmentViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory : SimpleCWAViewModelFactory<EventRegistrationTestFragmentViewModel>
+    interface Factory : SimpleCWAViewModelFactory<PresenceTracingTestViewModel>
 }
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragment.kt
new file mode 100644
index 000000000..c4aa4a257
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragment.kt
@@ -0,0 +1,298 @@
+package de.rki.coronawarnapp.test.presencetracing.ui.poster
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.print.PrintAttributes
+import android.print.PrintManager
+import android.text.SpannedString
+import android.util.TypedValue
+import android.view.View
+import android.widget.Toast
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.content.getSystemService
+import androidx.core.text.bold
+import androidx.core.text.buildSpannedString
+import androidx.core.text.color
+import androidx.core.view.isVisible
+import androidx.core.widget.TextViewCompat
+import androidx.core.widget.doOnTextChanged
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.navArgs
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.databinding.FragmentTestQrCodePosterBinding
+import de.rki.coronawarnapp.exception.ExceptionCategory
+import de.rki.coronawarnapp.exception.reporting.report
+import de.rki.coronawarnapp.server.protocols.internal.pt.QrCodePosterTemplate
+import de.rki.coronawarnapp.ui.color.parseColor
+import de.rki.coronawarnapp.ui.print.PrintingAdapter
+import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat
+import de.rki.coronawarnapp.util.di.AutoInject
+import de.rki.coronawarnapp.util.ui.popBackStack
+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.io.File
+import javax.inject.Inject
+
+@SuppressLint("SetTextI18n")
+class QrCodePosterTestFragment : Fragment(R.layout.fragment_test_qr_code_poster), AutoInject {
+
+    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
+
+    private val args by navArgs<QrCodePosterTestFragmentArgs>()
+    private val viewModel: QrCodePosterTestViewModel by cwaViewModelsAssisted(
+        factoryProducer = { viewModelFactory },
+        constructorCall = { factory, _ ->
+            factory as QrCodePosterTestViewModel.Factory
+            factory.create(args.traceLocationId)
+        }
+    )
+
+    private var itemId = -1
+
+    private val binding: FragmentTestQrCodePosterBinding by viewBindingLazy()
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        with(binding) {
+            toolbar.setNavigationOnClickListener { popBackStack() }
+            viewModel.poster.observe(viewLifecycleOwner) { poster ->
+                bindPoster(poster)
+                bindToolbar()
+            }
+        }
+
+        viewModel.sharingIntent.observe(viewLifecycleOwner) { fileIntent ->
+            when (itemId) {
+                R.id.action_print -> printFile(fileIntent.file)
+                R.id.action_share -> startActivity(fileIntent.intent(requireActivity()))
+            }
+        }
+
+        viewModel.qrCodeBitmap.observe(viewLifecycleOwner) {
+            binding.qrCodeImage.setImageBitmap(it)
+        }
+    }
+
+    private fun FragmentTestQrCodePosterBinding.bindPoster(poster: QrCodePosterTestViewModel.Poster) {
+        Timber.d("poster=$poster")
+        progressBar.hide()
+
+        val template = poster.template ?: return // Exit early
+        Timber.d("template=$template")
+
+        // Adjust poster image dimensions ratio to have a proper printing preview
+        val posterLayoutParam = posterImage.layoutParams as ConstraintLayout.LayoutParams
+        val dimensionRatio = template.run { "$width:$height" } // W:H
+        Timber.d("dimensionRatio=$dimensionRatio")
+        posterLayoutParam.dimensionRatio = dimensionRatio
+
+        // Display images
+        qrCodeImage.setImageBitmap(poster.qrCode)
+        posterImage.setImageBitmap(template.bitmap)
+
+        // Position QR Code image based on data provided by server
+        topGuideline.setGuidelinePercent(template.offsetY)
+        startGuideline.setGuidelinePercent(template.offsetX)
+        endGuideline.setGuidelinePercent(1 - template.offsetX)
+
+        // Qr Code positioning
+        qrOffsetXSlider.apply {
+            value = template.offsetX.sliderValue
+            addOnChangeListener { _, value, fromUser ->
+                if (fromUser) {
+                    val offset = value.percentage
+                    startGuideline.setGuidelinePercent(offset)
+                    endGuideline.setGuidelinePercent(1 - offset)
+                    updateQrCodeOffsetText()
+                }
+            }
+        }
+        qrOffsetYSlider.apply {
+            value = template.offsetY.sliderValue
+            addOnChangeListener { _, value, fromUser ->
+                if (fromUser) {
+                    topGuideline.setGuidelinePercent(value.percentage)
+                    updateQrCodeOffsetText()
+                }
+            }
+        }
+        updateQrCodeOffsetText()
+
+        qrLengthSlider.apply {
+            value = poster.template.qrCodeLength.toFloat()
+            addOnChangeListener { _, value, _ ->
+                updateQrCodeLengthText()
+                viewModel.generateQrCode(value.toInt())
+            }
+        }
+        updateQrCodeLengthText()
+
+        // Bind text info
+        bindTextBox(poster.infoText, poster.template.textBox)
+        offsetsPanel.isVisible = true
+        tooltip.setOnClickListener {
+            Toast.makeText(requireContext(), toastText(), Toast.LENGTH_LONG).show()
+        }
+    }
+
+    private fun toastText(): SpannedString =
+        buildSpannedString {
+            bold {
+                append("Tips:")
+            }
+            color(requireContext().getColorCompat(R.color.colorAccent)) {
+                appendLine()
+                appendLine()
+                append(
+                    "- Qr-Code Length defines Qr-Code bitmap length and not" +
+                        "\nthe displayed Qr-Code ImageView where its length is flexible per screen size" +
+                        "\nIn a way it defines the bitmap quality." +
+                        "\nThe more the length the more the bitmaps's sharpness."
+                )
+
+                appendLine()
+                appendLine()
+                append(
+                    "- Text below Qr-Code has max 2 lines and has a uniform auto scaling down to `fontSize - 6`." +
+                        "\nIf the size is way larger than it fits in two lines, it will be cut."
+                )
+
+                appendLine()
+                appendLine()
+                append(
+                    "- OffsetX defines the position of two guidelines left and right for the edges." +
+                        "\n If the offset is increasing, the space in between the guidelines is decreasing." +
+                        "\n Which means less width of the respective view. -> | -> view_width <- | <- "
+                )
+            }
+        }
+
+    private fun updateQrCodeLengthText() {
+        val value = binding.qrLengthSlider.value
+        binding.qrCodeLength.text = "Qr Code length:%d".format(value.toInt())
+    }
+
+    private fun FragmentTestQrCodePosterBinding.bindTextBox(
+        infoText: String,
+        textBox: QrCodePosterTemplate.QRCodePosterTemplateAndroid.QRCodeTextBoxAndroid
+    ) = with(infoTextView) {
+        text = infoText
+        setFontSize(textBox.fontSize)
+        setTextColor(textBox.fontColor.parseColor())
+        textEndGuideline.setGuidelinePercent(1 - textBox.offsetX)
+        textStartGuideline.setGuidelinePercent(textBox.offsetX)
+        textTopGuideline.setGuidelinePercent(textBox.offsetY)
+
+        // Text Position
+        txtOffsetXSlider.apply {
+            value = textBox.offsetX.sliderValue
+            addOnChangeListener { _, value, fromUser ->
+                if (fromUser) {
+                    val offset = value.percentage
+                    textEndGuideline.setGuidelinePercent(1 - offset)
+                    textStartGuideline.setGuidelinePercent(offset)
+                    updateInfoOffsetText()
+                }
+            }
+        }
+        txtOffsetYSlider.apply {
+            value = textBox.offsetY.sliderValue
+            addOnChangeListener { _, value, fromUser ->
+                if (fromUser) {
+                    textTopGuideline.setGuidelinePercent(value.percentage)
+                    updateInfoOffsetText()
+                }
+            }
+        }
+        updateInfoOffsetText()
+
+        // Text Size
+        infoTextSizeSlider.apply {
+            value = textBox.fontSize.toFloat()
+            addOnChangeListener { _, value, _ ->
+                updateFontSizeText()
+                setFontSize(value.toInt())
+            }
+        }
+        updateFontSizeText()
+
+        // Text Color
+        infoTextColorValue.doOnTextChanged { color, _, _, _ ->
+            infoTextView.setTextColor(color.toString().parseColor())
+        }
+    }
+
+    private fun updateFontSizeText() {
+        binding.infoTextSize.text =
+            "Font size: %s sp".format(binding.infoTextSizeSlider.value)
+    }
+
+    private fun FragmentTestQrCodePosterBinding.setFontSize(maxFontSize: Int) {
+        val minFontSize = maxFontSize - 6
+        TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(
+            infoTextView,
+            minFontSize,
+            maxFontSize,
+            1,
+            TypedValue.COMPLEX_UNIT_SP
+        )
+        infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, maxFontSize.toFloat())
+    }
+
+    private fun FragmentTestQrCodePosterBinding.bindToolbar() {
+        toolbar.setOnMenuItemClickListener {
+            itemId = it.itemId
+            viewModel.createPDF(binding.qrCodePoster)
+            true
+        }
+    }
+
+    private fun printFile(file: File) {
+        val printingManger = context?.getSystemService<PrintManager>()
+        Timber.i("PrintingManager=$printingManger")
+        if (printingManger == null) {
+            Toast.makeText(requireContext(), R.string.errors_generic_headline, Toast.LENGTH_LONG).show()
+            return
+        }
+
+        try {
+            val job = printingManger.print(
+                getString(R.string.app_name),
+                PrintingAdapter(file),
+                PrintAttributes.Builder()
+                    .setMediaSize(PrintAttributes.MediaSize.ISO_A3)
+                    .build()
+            )
+
+            Timber.d("JobState=%s", job.info.state)
+        } catch (e: Exception) {
+            Timber.d(e, "Printing job failed")
+            e.report(ExceptionCategory.INTERNAL)
+        }
+    }
+
+    private fun updateQrCodeOffsetText() {
+        with(binding) {
+            qrCodeOffsets.text = "Qr Code offsets: X=%.3f, Y=%.3f".format(
+                qrOffsetXSlider.value.percentage,
+                qrOffsetYSlider.value.percentage
+            )
+        }
+    }
+
+    private fun updateInfoOffsetText() {
+        with(binding) {
+            infoTextOffsets.text = "Text offsets: X=%.3f, Y=%.3f".format(
+                txtOffsetXSlider.value.percentage,
+                txtOffsetYSlider.value.percentage
+            )
+        }
+    }
+
+    private val Float.percentage get() = this / 1000
+
+    private val Float.sliderValue get() = this * 1000
+}
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragmentModule.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragmentModule.kt
new file mode 100644
index 000000000..871e9145d
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragmentModule.kt
@@ -0,0 +1,18 @@
+package de.rki.coronawarnapp.test.presencetracing.ui.poster
+
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoMap
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
+
+@Module
+abstract class QrCodePosterTestFragmentModule {
+    @Binds
+    @IntoMap
+    @CWAViewModelKey(QrCodePosterTestViewModel::class)
+    abstract fun qrCodePosterTestFragmentModule(
+        factory: QrCodePosterTestViewModel.Factory
+    ): CWAViewModelFactory<out CWAViewModel>
+}
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestViewModel.kt
new file mode 100644
index 000000000..f4cf799fa
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestViewModel.kt
@@ -0,0 +1,138 @@
+package de.rki.coronawarnapp.test.presencetracing.ui.poster
+
+import android.graphics.Bitmap
+import android.graphics.pdf.PdfDocument
+import android.view.View
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.PosterTemplateProvider
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.QrCodeGenerator
+import de.rki.coronawarnapp.eventregistration.checkins.qrcode.Template
+import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
+import de.rki.coronawarnapp.exception.ExceptionCategory
+import de.rki.coronawarnapp.exception.reporting.report
+import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
+import de.rki.coronawarnapp.util.files.FileSharing
+import de.rki.coronawarnapp.util.ui.SingleLiveEvent
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
+import timber.log.Timber
+import java.io.File
+import java.io.FileOutputStream
+import java.lang.ref.WeakReference
+
+class QrCodePosterTestViewModel @AssistedInject constructor(
+    @Assisted private val traceLocationId: Long,
+    private val dispatcher: DispatcherProvider,
+    private val qrCodeGenerator: QrCodeGenerator,
+    private val posterTemplateProvider: PosterTemplateProvider,
+    private val traceLocationRepository: TraceLocationRepository,
+    private val fileSharing: FileSharing
+) : CWAViewModel(dispatcher) {
+
+    private val posterLiveData = MutableLiveData<Poster>()
+    val poster: LiveData<Poster> = posterLiveData
+    val sharingIntent = SingleLiveEvent<FileSharing.FileIntentProvider>()
+    val qrCodeBitmap = SingleLiveEvent<Bitmap>()
+    private var isRunning = false
+
+    init {
+        generatePoster()
+    }
+
+    /**
+     * Create a new PDF file and result is delivered by [sharingIntent]
+     * as a sharing [FileSharing.ShareIntentProvider]
+     */
+    @Suppress("BlockingMethodInNonBlockingContext")
+    fun createPDF(view: View) = launch(context = dispatcher.IO) {
+        try {
+            val weakViewRef = WeakReference(view) // Accessing view in background thread
+            val directory = File(view.context.cacheDir, "poster").apply { if (!exists()) mkdirs() }
+            val file = File(directory, "cwa-qr-code.pdf")
+
+            val weakView = weakViewRef.get() ?: return@launch // View is not existing anymore
+            val pageInfo = PdfDocument.PageInfo.Builder(weakView.width, weakView.height, 1).create()
+
+            PdfDocument().apply {
+                startPage(pageInfo).apply {
+                    weakView.draw(canvas)
+                    finishPage(this)
+                }
+
+                FileOutputStream(file).use {
+                    writeTo(it)
+                    close()
+                }
+            }
+
+            sharingIntent.postValue(fileSharing.getFileIntentProvider(file, traceLocation().description))
+        } catch (e: Exception) {
+            Timber.d(e, "Creating pdf failed")
+            e.report(ExceptionCategory.INTERNAL)
+        }
+    }
+
+    fun generateQrCode(length: Int) = launch(context = dispatcher.IO) {
+        try {
+            if (isRunning) return@launch
+            isRunning = true
+            val traceLocation = traceLocation()
+            val qrCode = qrCodeGenerator.createQrCode(
+                input = traceLocation.locationUrl,
+                length = length,
+                margin = 0
+            )
+            qrCodeBitmap.postValue(qrCode)
+        } catch (e: Exception) {
+            Timber.e(e)
+            e.report(ExceptionCategory.INTERNAL)
+        } finally {
+            isRunning = false
+        }
+    }
+
+    private fun generatePoster() = launch(context = dispatcher.IO) {
+        try {
+            val traceLocation = traceLocation()
+            val template = posterTemplateProvider.template()
+            Timber.d("template=$template")
+            val qrCode = qrCodeGenerator.createQrCode(
+                input = traceLocation.locationUrl,
+                length = template.qrCodeLength,
+                margin = 0
+            )
+
+            val textInfo = buildString {
+                append(traceLocation.description)
+                appendLine()
+                append(traceLocation.address)
+            }
+            posterLiveData.postValue(
+                Poster(qrCode, template, textInfo)
+            )
+        } catch (e: Exception) {
+            Timber.d(e, "Generating poster failed")
+            posterLiveData.postValue(Poster())
+            e.report(ExceptionCategory.INTERNAL)
+        }
+    }
+
+    private suspend fun traceLocation() = traceLocationRepository.traceLocationForId(traceLocationId)
+
+    @AssistedFactory
+    interface Factory : CWAViewModelFactory<QrCodePosterTestViewModel> {
+        fun create(
+            traceLocationId: Long
+        ): QrCodePosterTestViewModel
+    }
+
+    data class Poster(
+        val qrCode: Bitmap? = null,
+        val template: Template? = null,
+        val infoText: String = ""
+    )
+}
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt
index 9728bc8fd..e4a3ea0af 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt
@@ -14,22 +14,22 @@ import de.rki.coronawarnapp.test.debugoptions.ui.DebugOptionsFragment
 import de.rki.coronawarnapp.test.debugoptions.ui.DebugOptionsFragmentModule
 import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaOnboardingFragmentModule
 import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaonboardingFragment
-import de.rki.coronawarnapp.test.eventregistration.ui.EventRegistrationTestFragment
-import de.rki.coronawarnapp.test.eventregistration.ui.EventRegistrationTestFragmentModule
+import de.rki.coronawarnapp.test.presencetracing.ui.PresenceTracingTestFragment
+import de.rki.coronawarnapp.test.presencetracing.ui.PresenceTracingTestFragmentModule
 import de.rki.coronawarnapp.test.keydownload.ui.KeyDownloadTestFragment
 import de.rki.coronawarnapp.test.keydownload.ui.KeyDownloadTestFragmentModule
 import de.rki.coronawarnapp.test.menu.ui.TestMenuFragment
 import de.rki.coronawarnapp.test.menu.ui.TestMenuFragmentModule
 import de.rki.coronawarnapp.test.playground.ui.PlaygroundFragment
 import de.rki.coronawarnapp.test.playground.ui.PlaygroundModule
+import de.rki.coronawarnapp.test.presencetracing.ui.poster.QrCodePosterTestFragment
+import de.rki.coronawarnapp.test.presencetracing.ui.poster.QrCodePosterTestFragmentModule
 import de.rki.coronawarnapp.test.risklevel.ui.TestRiskLevelCalculationFragment
 import de.rki.coronawarnapp.test.risklevel.ui.TestRiskLevelCalculationFragmentModule
 import de.rki.coronawarnapp.test.submission.ui.SubmissionTestFragment
 import de.rki.coronawarnapp.test.submission.ui.SubmissionTestFragmentModule
 import de.rki.coronawarnapp.test.tasks.ui.TestTaskControllerFragment
 import de.rki.coronawarnapp.test.tasks.ui.TestTaskControllerFragmentModule
-import de.rki.coronawarnapp.ui.eventregistration.organizer.details.QrCodeDetailFragment
-import de.rki.coronawarnapp.ui.eventregistration.organizer.details.QrCodeDetailFragmentModule
 
 @Module
 abstract class MainActivityTestModule {
@@ -70,9 +70,9 @@ abstract class MainActivityTestModule {
     @ContributesAndroidInjector(modules = [DeltaOnboardingFragmentModule::class])
     abstract fun deltaOnboarding(): DeltaonboardingFragment
 
-    @ContributesAndroidInjector(modules = [EventRegistrationTestFragmentModule::class])
-    abstract fun eventRegistration(): EventRegistrationTestFragment
+    @ContributesAndroidInjector(modules = [PresenceTracingTestFragmentModule::class])
+    abstract fun eventRegistration(): PresenceTracingTestFragment
 
-    @ContributesAndroidInjector(modules = [QrCodeDetailFragmentModule::class])
-    abstract fun showEventDetail(): QrCodeDetailFragment
+    @ContributesAndroidInjector(modules = [QrCodePosterTestFragmentModule::class])
+    abstract fun showEventDetail(): QrCodePosterTestFragment
 }
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_eventregistration.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_presence_tracing.xml
similarity index 100%
rename from Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_eventregistration.xml
rename to Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_presence_tracing.xml
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_qr_code_poster.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_qr_code_poster.xml
new file mode 100644
index 000000000..590b0a48c
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_qr_code_poster.xml
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:ignore="HardcodedText">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@android:color/white">
+
+        <com.google.android.material.appbar.MaterialToolbar
+            android:id="@+id/toolbar"
+            style="@style/CWAToolbar.BackArrow"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:elevation="2dp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:menu="@menu/menu_trace_location_qr_code_poster"
+            app:title="@string/trace_location_organiser_poster_title" />
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/qr_code_poster"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/toolbar">
+
+            <ImageView
+                android:id="@+id/poster_image"
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:adjustViewBounds="true"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                tools:layout_constraintDimensionRatio="595:841" />
+
+            <ImageView
+                android:id="@+id/qr_code_image"
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:scaleType="fitXY"
+                app:layout_constraintDimensionRatio="1:1"
+                app:layout_constraintEnd_toEndOf="@id/end_guideline"
+                app:layout_constraintStart_toStartOf="@id/start_guideline"
+                app:layout_constraintTop_toTopOf="@id/top_guideline"
+                tools:src="@drawable/ic_qrcode"
+                tools:tint="@android:color/black" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/start_guideline"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                app:layout_constraintGuide_percent="0.16" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/end_guideline"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                app:layout_constraintGuide_percent="0.84" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/top_guideline"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                app:layout_constraintGuide_percent="0.095" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/text_start_guideline"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                app:layout_constraintGuide_percent="0.132" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/text_end_guideline"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                app:layout_constraintGuide_percent="0.87" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/text_top_guideline"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                app:layout_constraintGuide_percent="0.61" />
+
+            <TextView
+                android:id="@+id/info_text_view"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:maxLines="2"
+                app:layout_constraintEnd_toEndOf="@id/text_end_guideline"
+                app:layout_constraintStart_toStartOf="@id/text_start_guideline"
+                app:layout_constraintTop_toTopOf="@id/text_top_guideline"
+                tools:ignore="SmallSp"
+                tools:text="Vereinsaktivität: Jahrestreffen der deutschen SAP Anwendergruppe\nHauptstr 3, 69115 Heidelberg"
+                tools:textColor="#000000"
+                tools:textSize="10sp" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <com.google.android.material.progressindicator.LinearProgressIndicator
+            android:id="@+id/progress_bar"
+            android:layout_width="150dp"
+            android:layout_height="wrap_content"
+            android:indeterminate="true"
+            app:hideAnimationBehavior="inward"
+            app:indicatorColor="@color/colorAccent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <ScrollView
+        android:id="@+id/offsets_panel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        app:behavior_peekHeight="60dp"
+        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
+
+        <LinearLayout
+            style="@style/Card"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <FrameLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="10dp"
+                android:orientation="horizontal"
+                android:paddingBottom="20dp">
+
+                <ImageView
+                    android:id="@+id/tooltip"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="end|center"
+                    android:background="?selectableItemBackgroundBorderless"
+                    app:srcCompat="@drawable/ic_info" />
+
+                <View
+                    android:layout_width="100dp"
+                    android:layout_height="5dp"
+                    android:layout_gravity="center"
+                    android:background="@color/colorAccent" />
+
+            </FrameLayout>
+
+            <TextView
+                android:id="@+id/qr_code_offsets"
+                style="@style/body2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="QR Code offsets" />
+
+            <com.google.android.material.slider.Slider
+                android:id="@+id/qrOffsetXSlider"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="5dp"
+                android:stepSize="1"
+                android:valueFrom="0"
+                android:valueTo="1000"
+                app:labelBehavior="gone" />
+
+            <com.google.android.material.slider.Slider
+                android:id="@+id/qrOffsetYSlider"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="5dp"
+                android:stepSize="1"
+                android:valueFrom="0"
+                android:valueTo="1000"
+                app:labelBehavior="gone" />
+
+            <TextView
+                android:id="@+id/qr_code_length"
+                style="@style/body2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                android:text="Qr Code length" />
+
+            <com.google.android.material.slider.Slider
+                android:id="@+id/qrLengthSlider"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="5dp"
+                android:stepSize="100"
+                android:valueFrom="500"
+                android:valueTo="2000"
+                app:labelBehavior="gone" />
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="5dp"
+                android:layout_marginVertical="10dp"
+                android:background="#BE818181" />
+
+            <TextView
+                android:id="@+id/info_text_offsets"
+                style="@style/body2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                android:text="Text offsets" />
+
+            <com.google.android.material.slider.Slider
+                android:id="@+id/txtOffsetXSlider"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="5dp"
+                android:stepSize="1"
+                android:valueFrom="0"
+                android:valueTo="1000"
+                app:labelBehavior="gone" />
+
+            <com.google.android.material.slider.Slider
+                android:id="@+id/txtOffsetYSlider"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="5dp"
+                android:stepSize="1"
+                android:valueFrom="0"
+                android:valueTo="1000"
+                app:labelBehavior="gone" />
+
+            <TextView
+                android:id="@+id/info_text_size"
+                style="@style/body2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                android:text="Font size" />
+
+            <com.google.android.material.slider.Slider
+                android:id="@+id/infoTextSizeSlider"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="5dp"
+                android:stepSize="1"
+                android:valueFrom="10"
+                android:valueTo="30"
+                app:labelBehavior="gone" />
+
+            <TextView
+                style="@style/body2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                android:text="Font Color" />
+
+            <com.google.android.material.textfield.TextInputEditText
+                android:id="@+id/info_text_color_value"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="5dp"
+                android:hint="#000000 - FallbackColor=#000000" />
+        </LinearLayout>
+    </ScrollView>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml b/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml
index 1586ca697..a8cdc52cf 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml
@@ -47,8 +47,8 @@
             android:id="@+id/action_test_menu_fragment_to_deltaonboardingFragment"
             app:destination="@id/test_deltaonboarding_fragment" />
         <action
-            android:id="@+id/action_test_menu_fragment_to_eventRegistrationTestFragment"
-            app:destination="@id/eventRegistrationTestFragment" />
+            android:id="@+id/action_test_menu_fragment_to_presenceTracingTestFragment"
+            app:destination="@id/presenceTracingTestFragment" />
     </fragment>
 
     <fragment
@@ -128,19 +128,19 @@
         android:label="DeltaonboardingFragment"
         tools:layout="@layout/fragment_test_deltaonboarding" />
     <fragment
-        android:id="@+id/eventRegistrationTestFragment"
-        android:name="de.rki.coronawarnapp.test.eventregistration.ui.EventRegistrationTestFragment"
-        android:label="EventRegistrationTestFragment"
-        tools:layout="@layout/fragment_test_eventregistration">
+        android:id="@+id/presenceTracingTestFragment"
+        android:name="de.rki.coronawarnapp.test.presencetracing.ui.PresenceTracingTestFragment"
+        android:label="PresenceTracingTestFragment"
+        tools:layout="@layout/fragment_test_presence_tracing">
         <action
-            android:id="@+id/action_eventRegistrationTestFragment_to_qrCodePosterFragmentTest"
-            app:destination="@id/qrCodePosterFragmentTest" />
+            android:id="@+id/action_presenceTracingTestFragment_to_qrCodePosterTestFragment"
+            app:destination="@id/qrCodePosterTestFragment" />
     </fragment>
     <fragment
-        android:id="@+id/qrCodePosterFragmentTest"
-        android:name="de.rki.coronawarnapp.ui.eventregistration.organizer.poster.QrCodePosterFragment"
-        android:label="qr_code_poster_fragment"
-        tools:layout="@layout/qr_code_poster_fragment">
+        android:id="@+id/qrCodePosterTestFragment"
+        android:name="de.rki.coronawarnapp.test.presencetracing.ui.poster.QrCodePosterTestFragment"
+        android:label="QrCodePosterTestFragment"
+        tools:layout="@layout/fragment_test_qr_code_poster">
 
         <argument
             android:name="traceLocationId"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt
index e6f0123e6..07b90907c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt
@@ -16,6 +16,8 @@ import de.rki.coronawarnapp.ui.eventregistration.organizer.category.TraceLocatio
 import de.rki.coronawarnapp.ui.eventregistration.organizer.category.TraceLocationCategoryFragmentModule
 import de.rki.coronawarnapp.ui.eventregistration.organizer.create.TraceLocationCreateFragment
 import de.rki.coronawarnapp.ui.eventregistration.organizer.create.TraceLocationCreateFragmentModule
+import de.rki.coronawarnapp.ui.eventregistration.organizer.details.QrCodeDetailFragment
+import de.rki.coronawarnapp.ui.eventregistration.organizer.details.QrCodeDetailFragmentModule
 import de.rki.coronawarnapp.ui.eventregistration.organizer.list.TraceLocationsFragment
 import de.rki.coronawarnapp.ui.eventregistration.organizer.list.TraceLocationsFragmentModule
 import de.rki.coronawarnapp.ui.eventregistration.organizer.poster.QrCodePosterFragment
@@ -55,4 +57,7 @@ internal abstract class EventRegistrationUIModule {
 
     @ContributesAndroidInjector(modules = [QrCodePosterFragmentModule::class])
     abstract fun qrCodePosterFragment(): QrCodePosterFragment
+
+    @ContributesAndroidInjector(modules = [QrCodeDetailFragmentModule::class])
+    abstract fun showEventDetail(): QrCodeDetailFragment
 }
-- 
GitLab