From 2838e743d89c21aaeb29597733d77726ecff7dd8 Mon Sep 17 00:00:00 2001
From: Kolya Opahle <k.opahle@sap.com>
Date: Mon, 14 Jun 2021 16:14:21 +0200
Subject: [PATCH] Missing text for test certificate on negative test result
 screen (EXPOSUREAPP-7753) (#3424)

* Added Ability to check registrationToken to TestCertificateWrapper RATResultNegativeFragment now displays if a certificate is assigned to the test and if it is pending the icon and is final state for StepEntry's can now be set via code added new strings for RATResultNegativeFragment

* SubmissionTestResultNegativeFragment now displays if a certificate is assigned to the test and if it is pending moved some strings around

* linting

* Fixed Integration tests

Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com>
Co-authored-by: Mohamed Metwalli <mohamed.metwalli@sap.com>
---
 ...ubmissionTestResultNegativeFragmentTest.kt | 10 +++--
 .../test/core/TestCertificateWrapper.kt       |  2 +
 .../negative/RATResultNegativeFragment.kt     | 42 +++++++++++++++----
 .../negative/RATResultNegativeViewModel.kt    | 39 +++++++++++++----
 .../SubmissionTestResultNegativeFragment.kt   | 35 +++++++++++++++-
 .../SubmissionTestResultNegativeViewModel.kt  | 41 ++++++++++++++----
 .../de/rki/coronawarnapp/ui/view/StepEntry.kt | 26 +++++++++---
 ...ubmission_antigen_test_result_negative.xml | 17 +++++++-
 ...agment_submission_test_result_negative.xml | 17 +++++++-
 .../main/res/values-de/antigen_strings.xml    |  4 ++
 .../src/main/res/values/antigen_strings.xml   |  4 ++
 11 files changed, 201 insertions(+), 36 deletions(-)

diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNegativeFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNegativeFragmentTest.kt
index 9efe83450..628b6cd79 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNegativeFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultNegativeFragmentTest.kt
@@ -7,8 +7,8 @@ import dagger.android.ContributesAndroidInjector
 import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
 import de.rki.coronawarnapp.submission.SubmissionRepository
-import de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState
 import de.rki.coronawarnapp.ui.submission.testresult.negative.SubmissionTestResultNegativeFragment
 import de.rki.coronawarnapp.ui.submission.testresult.negative.SubmissionTestResultNegativeViewModel
 import de.rki.coronawarnapp.ui.submission.testresult.positive.SubmissionTestResultConsentGivenFragmentArgs
@@ -34,6 +34,7 @@ class SubmissionTestResultNegativeFragmentTest : BaseUITest() {
 
     lateinit var viewModel: SubmissionTestResultNegativeViewModel
     @MockK lateinit var submissionRepository: SubmissionRepository
+    @MockK lateinit var certificateRepository: TestCertificateRepository
     @MockK lateinit var testResultAvailableNotificationService: PCRTestResultAvailableNotificationService
     @MockK lateinit var testType: CoronaTest.Type
     private val resultNegativeFragmentArgs =
@@ -44,11 +45,13 @@ class SubmissionTestResultNegativeFragmentTest : BaseUITest() {
         MockKAnnotations.init(this, relaxed = true)
 
         every { submissionRepository.testForType(any()) } returns flowOf()
+        every { certificateRepository.certificates } returns flowOf()
 
         viewModel = spyk(
             SubmissionTestResultNegativeViewModel(
                 TestDispatcherProvider(),
                 submissionRepository,
+                certificateRepository,
                 testResultAvailableNotificationService,
                 testType
             )
@@ -70,12 +73,13 @@ class SubmissionTestResultNegativeFragmentTest : BaseUITest() {
     @Screenshot
     fun capture_fragment() {
         every { viewModel.testResult } returns MutableLiveData(
-            TestResultUIState(
+            SubmissionTestResultNegativeViewModel.UIState(
                 coronaTest = mockk<CoronaTest>().apply {
                     every { testResult } returns CoronaTestResult.PCR_NEGATIVE
                     every { registeredAt } returns Instant.now()
                     every { type } returns CoronaTest.Type.PCR
-                }
+                },
+                certificateState = SubmissionTestResultNegativeViewModel.CertificateState.AVAILABLE
             )
         )
         launchFragmentInContainer2<SubmissionTestResultNegativeFragment>(fragmentArgs = resultNegativeFragmentArgs)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateWrapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateWrapper.kt
index 2be76074c..403f2b34d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateWrapper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateWrapper.kt
@@ -20,4 +20,6 @@ data class TestCertificateWrapper(
     val testCertificate: TestCertificate? by lazy {
         container.toTestCertificate(valueSets)
     }
+
+    val registrationToken = container.registrationToken
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeFragment.kt
index 790a2cbca..3076ce098 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeFragment.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.submission.ui.testresults.negative
 
 import android.os.Bundle
 import android.view.View
+import androidx.appcompat.content.res.AppCompatResources.getDrawable
 import androidx.core.text.bold
 import androidx.core.text.buildSpannedString
 import androidx.core.view.isGone
@@ -58,21 +59,21 @@ class RATResultNegativeFragment : Fragment(R.layout.fragment_submission_antigen_
         }
 
     private fun FragmentSubmissionAntigenTestResultNegativeBinding.bindView(
-        testAge: RATResultNegativeViewModel.TestAge
+        uiState: RATResultNegativeViewModel.UIState
     ) {
-        resultReceivedCounter.chronometer.text = testAge.ageText
+        resultReceivedCounter.chronometer.text = uiState.ageText
 
         val patientName = getString(
             R.string.submission_test_result_antigen_patient_name_placeholder,
-            testAge.test.firstName ?: "",
-            testAge.test.lastName ?: ""
+            uiState.test.firstName ?: "",
+            uiState.test.lastName ?: ""
         )
 
         rapidTestCardPatientInfo.text = buildSpannedString {
             bold {
                 if (patientName.isNotBlank()) append(patientName)
             }
-            testAge.test.dateOfBirth?.let {
+            uiState.test.dateOfBirth?.let {
                 val birthDate = getString(
                     R.string.submission_test_result_antigen_patient_birth_date_placeholder,
                     it.toString(DATE_FORMAT)
@@ -82,14 +83,14 @@ class RATResultNegativeFragment : Fragment(R.layout.fragment_submission_antigen_
             }
         }
 
-        val localTime = testAge.test.testTakenAt.toUserTimeZone()
+        val localTime = uiState.test.testTakenAt.toUserTimeZone()
         resultReceivedTimeAndDate.text = getString(
             R.string.coronatest_negative_antigen_result_time_date_placeholder,
             localTime.toString(DATE_FORMAT),
             localTime.toString(shortTime)
         )
 
-        val isAnonymousTest = with(testAge.test) {
+        val isAnonymousTest = with(uiState.test) {
             firstName == null && lastName == null && dateOfBirth == null
         }
 
@@ -108,6 +109,33 @@ class RATResultNegativeFragment : Fragment(R.layout.fragment_submission_antigen_
         negativeTestProofBody.text = getString(proofBodyString)
 
         negativeTestProofAdditionalInformation.isGone = isAnonymousTest
+
+        when (uiState.certificateState) {
+            RATResultNegativeViewModel.CertificateState.NOT_REQUESTED -> {
+                coronatestNegativeAntigenResultThirdInfo.setIsFinal(true)
+                coronatestNegativeAntigenResultFourthInfo.isGone = true
+            }
+            RATResultNegativeViewModel.CertificateState.PENDING -> {
+                coronatestNegativeAntigenResultThirdInfo.setIsFinal(false)
+                coronatestNegativeAntigenResultFourthInfo.isGone = false
+                coronatestNegativeAntigenResultFourthInfo.setEntryText(
+                    getText(R.string.submission_test_result_pending_steps_test_certificate_not_available_yet_body)
+                )
+                coronatestNegativeAntigenResultFourthInfo.setIcon(
+                    getDrawable(requireContext(), R.drawable.ic_result_pending_certificate_info)
+                )
+            }
+            RATResultNegativeViewModel.CertificateState.AVAILABLE -> {
+                coronatestNegativeAntigenResultThirdInfo.setIsFinal(false)
+                coronatestNegativeAntigenResultFourthInfo.isGone = false
+                coronatestNegativeAntigenResultFourthInfo.setEntryText(
+                    getText(R.string.coronatest_negative_result_certificate_info_body)
+                )
+                coronatestNegativeAntigenResultFourthInfo.setIcon(
+                    getDrawable(requireContext(), R.drawable.ic_qr_code_illustration)
+                )
+            }
+        }
     }
 
     companion object {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeViewModel.kt
index 70990f8e1..763476722 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeViewModel.kt
@@ -6,6 +6,8 @@ import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateWrapper
 import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.submission.SubmissionRepository
@@ -25,22 +27,28 @@ class RATResultNegativeViewModel @AssistedInject constructor(
     dispatcherProvider: DispatcherProvider,
     private val timeStamper: TimeStamper,
     private val submissionRepository: SubmissionRepository,
-    coronaTestRepository: CoronaTestRepository
+    coronaTestRepository: CoronaTestRepository,
+    certificateRepository: TestCertificateRepository
 ) : CWAViewModel(dispatcherProvider) {
 
     val events = SingleLiveEvent<RATResultNegativeNavigation>()
     val testAge = combine(
         intervalFlow(1),
-        coronaTestRepository.coronaTests
-    ) { _, tests ->
+        coronaTestRepository.coronaTests,
+        certificateRepository.certificates
+    ) { _, tests, certs ->
         val rapidTest = tests.firstOrNull {
             it.type == CoronaTest.Type.RAPID_ANTIGEN
         }
 
-        rapidTest?.testAge()
+        val certificate = certs.firstOrNull {
+            it.registrationToken == rapidTest?.registrationToken
+        }
+
+        rapidTest?.uiState(certificate)
     }.asLiveData(context = dispatcherProvider.Default)
 
-    private fun CoronaTest.testAge(): TestAge? {
+    private fun CoronaTest.uiState(certificate: TestCertificateWrapper?): UIState? {
         if (this !is RACoronaTest) {
             Timber.d("Rapid test is missing")
             return null
@@ -50,7 +58,17 @@ class RATResultNegativeViewModel @AssistedInject constructor(
         val age = nowUTC.millis - testTakenAt.millis
         val ageText = formatter.print(Duration(age).toPeriod())
 
-        return TestAge(test = this, ageText)
+        val certificateState: CertificateState = when (certificate?.isCertificateRetrievalPending) {
+            true -> CertificateState.PENDING
+            false -> CertificateState.AVAILABLE
+            else -> CertificateState.NOT_REQUESTED
+        }
+
+        return UIState(
+            test = this,
+            ageText = ageText,
+            certificateState = certificateState
+        )
     }
 
     fun onDeleteTestConfirmed() {
@@ -75,9 +93,16 @@ class RATResultNegativeViewModel @AssistedInject constructor(
     @AssistedFactory
     interface Factory : SimpleCWAViewModelFactory<RATResultNegativeViewModel>
 
-    data class TestAge(
+    enum class CertificateState {
+        NOT_REQUESTED,
+        PENDING,
+        AVAILABLE
+    }
+
+    data class UIState(
         val test: RACoronaTest,
         val ageText: String,
+        val certificateState: CertificateState
     )
 
     companion object {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeFragment.kt
index b3eb8f9bb..b3e8bdd3c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeFragment.kt
@@ -4,6 +4,8 @@ import android.content.DialogInterface
 import android.os.Bundle
 import android.view.View
 import android.view.accessibility.AccessibilityEvent
+import androidx.appcompat.content.res.AppCompatResources.getDrawable
+import androidx.core.view.isGone
 import androidx.fragment.app.Fragment
 import androidx.navigation.fragment.navArgs
 import de.rki.coronawarnapp.R
@@ -45,7 +47,38 @@ class SubmissionTestResultNegativeFragment : Fragment(R.layout.fragment_submissi
         }
 
         viewModel.testResult.observe2(this) {
-            binding.submissionTestResultSection.setTestResultSection(it.coronaTest)
+            binding.apply {
+                submissionTestResultSection.setTestResultSection(it.coronaTest)
+
+                when (it.certificateState) {
+                    SubmissionTestResultNegativeViewModel.CertificateState.NOT_REQUESTED -> {
+                        testResultNegativeStepsNegativeResult.setIsFinal(true)
+                        testResultNegativeStepsCertificate.isGone = true
+                    }
+                    SubmissionTestResultNegativeViewModel.CertificateState.PENDING -> {
+                        testResultNegativeStepsNegativeResult.setIsFinal(false)
+                        testResultNegativeStepsCertificate.isGone = false
+                        testResultNegativeStepsCertificate.setEntryText(
+                            getText(
+                                R.string.submission_test_result_pending_steps_test_certificate_not_available_yet_body
+                            )
+                        )
+                        testResultNegativeStepsCertificate.setIcon(
+                            getDrawable(requireContext(), R.drawable.ic_result_pending_certificate_info)
+                        )
+                    }
+                    SubmissionTestResultNegativeViewModel.CertificateState.AVAILABLE -> {
+                        testResultNegativeStepsNegativeResult.setIsFinal(false)
+                        testResultNegativeStepsCertificate.isGone = false
+                        testResultNegativeStepsCertificate.setEntryText(
+                            getText(R.string.coronatest_negative_result_certificate_info_body)
+                        )
+                        testResultNegativeStepsCertificate.setIcon(
+                            getDrawable(requireContext(), R.drawable.ic_qr_code_illustration)
+                        )
+                    }
+                }
+            }
         }
 
         viewModel.routeToScreen.observe2(this) { navDirections ->
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeViewModel.kt
index 98ed23aee..b9f774254 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeViewModel.kt
@@ -1,6 +1,5 @@
 package de.rki.coronawarnapp.ui.submission.testresult.negative
 
-import androidx.lifecycle.LiveData
 import androidx.lifecycle.asLiveData
 import androidx.navigation.NavDirections
 import dagger.assisted.Assisted
@@ -8,19 +7,20 @@ import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import de.rki.coronawarnapp.coronatest.type.pcr.notification.PCRTestResultAvailableNotificationService
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
 import de.rki.coronawarnapp.submission.SubmissionRepository
-import de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filterNotNull
-import kotlinx.coroutines.flow.map
 import timber.log.Timber
 
 class SubmissionTestResultNegativeViewModel @AssistedInject constructor(
     dispatcherProvider: DispatcherProvider,
     private val submissionRepository: SubmissionRepository,
+    certificateRepository: TestCertificateRepository,
     private val testResultAvailableNotificationService: PCRTestResultAvailableNotificationService,
     @Assisted private val testType: CoronaTest.Type
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
@@ -30,11 +30,25 @@ class SubmissionTestResultNegativeViewModel @AssistedInject constructor(
     }
 
     val routeToScreen = SingleLiveEvent<NavDirections?>()
-    val testResult: LiveData<TestResultUIState> = submissionRepository.testForType(type = testType)
-        .filterNotNull()
-        .map { test ->
-            TestResultUIState(coronaTest = test)
-        }.asLiveData(context = dispatcherProvider.Default)
+    val testResult = combine(
+        submissionRepository.testForType(type = testType).filterNotNull(),
+        certificateRepository.certificates
+    ) { test, certs ->
+        val cert = certs.firstOrNull {
+            it.registrationToken == test.registrationToken
+        }
+
+        val certificateState: CertificateState = when (cert?.isCertificateRetrievalPending) {
+            true -> CertificateState.PENDING
+            false -> CertificateState.AVAILABLE
+            else -> CertificateState.NOT_REQUESTED
+        }
+
+        UIState(
+            coronaTest = test,
+            certificateState = certificateState
+        )
+    }.asLiveData(context = dispatcherProvider.Default)
 
     fun deregisterTestFromDevice() = launch {
         Timber.tag(TAG).d("deregisterTestFromDevice()")
@@ -49,6 +63,17 @@ class SubmissionTestResultNegativeViewModel @AssistedInject constructor(
         testResultAvailableNotificationService.cancelTestResultAvailableNotification()
     }
 
+    enum class CertificateState {
+        NOT_REQUESTED,
+        PENDING,
+        AVAILABLE
+    }
+
+    data class UIState(
+        val coronaTest: CoronaTest,
+        val certificateState: CertificateState
+    )
+
     @AssistedFactory
     interface Factory : CWAViewModelFactory<SubmissionTestResultNegativeViewModel> {
         fun create(testType: CoronaTest.Type): SubmissionTestResultNegativeViewModel
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/StepEntry.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/StepEntry.kt
index f8c117a56..d6f50ad58 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/StepEntry.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/StepEntry.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.ui.view
 
 import android.content.Context
+import android.graphics.drawable.Drawable
 import android.util.AttributeSet
 import android.view.View
 import android.view.ViewGroup
@@ -20,6 +21,9 @@ open class StepEntry @JvmOverloads constructor(
 
     val body: FrameLayout?
 
+    private lateinit var entryLine: View
+    private lateinit var entryIcon: ImageView
+
     init {
         inflate(context, R.layout.view_step_entry, this)
 
@@ -27,14 +31,24 @@ open class StepEntry @JvmOverloads constructor(
 
         context.withStyledAttributes(attrs, R.styleable.StepEntry) {
             val icon = getDrawable(R.styleable.StepEntry_step_entry_icon)
-            findViewById<ImageView>(R.id.step_entry_icon).setImageDrawable(icon)
+            entryIcon = findViewById(R.id.step_entry_icon)
+            setIcon(icon)
 
             val isFinal = getBoolean(R.styleable.StepEntry_step_entry_final, false)
-            findViewById<View>(R.id.step_entry_line).visibility = if (isFinal) {
-                View.INVISIBLE
-            } else {
-                View.VISIBLE
-            }
+            entryLine = findViewById(R.id.step_entry_line)
+            setIsFinal(isFinal)
+        }
+    }
+
+    fun setIcon(icon: Drawable?) {
+        entryIcon.setImageDrawable(icon)
+    }
+
+    fun setIsFinal(isFinal: Boolean) {
+        entryLine.visibility = if (isFinal) {
+            View.INVISIBLE
+        } else {
+            View.VISIBLE
         }
     }
 
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_antigen_test_result_negative.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_antigen_test_result_negative.xml
index 0a623944c..1f89e6589 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_submission_antigen_test_result_negative.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_antigen_test_result_negative.xml
@@ -226,9 +226,22 @@
                 app:layout_constraintTop_toBottomOf="@+id/test_result_negative_steps_negative_result"
                 app:simple_step_entry_text="@string/coronatest_negative_antigen_restul_third_info_body"
                 app:simple_step_entry_title="@string/coronatest_negative_antigen_result_third_info_title"
-                app:step_entry_final="true"
+                app:step_entry_final="false"
                 app:step_entry_icon="@drawable/ic_test_result_delete_test" />
 
+            <de.rki.coronawarnapp.ui.view.SimpleStepEntry
+                android:id="@+id/coronatest_negative_antigen_result_fourth_info"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="@dimen/spacing_normal"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="@id/coronatest_negative_antigen_result_third_info"
+                app:layout_constraintTop_toBottomOf="@+id/coronatest_negative_antigen_result_third_info"
+                app:simple_step_entry_text="@string/coronatest_negative_result_certificate_info_body"
+                app:simple_step_entry_title="@string/coronatest_negative_result_certificate_info_title"
+                app:step_entry_final="true"
+                app:step_entry_icon="@drawable/ic_qr_code_illustration" />
+
             <LinearLayout
                 android:id="@+id/further_info"
                 android:layout_width="match_parent"
@@ -236,7 +249,7 @@
                 android:background="@color/colorSurface2"
                 android:orientation="vertical"
                 android:padding="@dimen/spacing_normal"
-                app:layout_constraintTop_toBottomOf="@id/coronatest_negative_antigen_result_third_info">
+                app:layout_constraintTop_toBottomOf="@id/coronatest_negative_antigen_result_fourth_info">
 
                 <TextView
                     android:id="@+id/further_info_title"
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_negative.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_negative.xml
index 49d5aab4c..bba45502a 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_negative.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_negative.xml
@@ -88,9 +88,22 @@
                     app:layout_constraintTop_toBottomOf="@+id/test_result_negative_steps_added"
                     app:simple_step_entry_text="@string/submission_test_result_negative_steps_negative_body"
                     app:simple_step_entry_title="@string/submission_test_result_negative_steps_negative_heading"
-                    app:step_entry_final="true"
+                    app:step_entry_final="false"
                     app:step_entry_icon="@drawable/ic_test_result_step_done" />
 
+                <de.rki.coronawarnapp.ui.view.SimpleStepEntry
+                    android:id="@+id/test_result_negative_steps_certificate"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_marginEnd="@dimen/spacing_normal"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintStart_toStartOf="@+id/test_result_negative_steps_negative_result"
+                    app:layout_constraintTop_toBottomOf="@+id/test_result_negative_steps_negative_result"
+                    app:simple_step_entry_text="@string/coronatest_negative_result_certificate_info_body"
+                    app:simple_step_entry_title="@string/coronatest_negative_result_certificate_info_title"
+                    app:step_entry_final="true"
+                    app:step_entry_icon="@drawable/ic_qr_code_illustration" />
+
                 <LinearLayout
                     android:id="@+id/further_info"
                     android:layout_width="match_parent"
@@ -98,7 +111,7 @@
                     android:background="@color/colorSurface2"
                     android:orientation="vertical"
                     android:padding="@dimen/spacing_normal"
-                    app:layout_constraintTop_toBottomOf="@id/test_result_negative_steps_negative_result">
+                    app:layout_constraintTop_toBottomOf="@id/test_result_negative_steps_certificate">
 
                     <TextView
                         android:id="@+id/further_info_title"
diff --git a/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml
index 3eb70a980..d43011a41 100644
--- a/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml
@@ -141,6 +141,10 @@
     <string name="coronatest_negative_antigen_result_third_info_title">"Test entfernen"</string>
     <!-- XTXT: coronatest negative antigen result third info body -->
     <string name="coronatest_negative_antigen_restul_third_info_body">"Bitte entfernen Sie den Test wieder aus der Corona-Warn-App, damit Sie bei Bedarf einen neuen Test hinterlegen können."</string>
+    <!-- XTXT: coronatest negative result certificate info title -->
+    <string name="coronatest_negative_result_certificate_info_title">"Testzertifikat"</string>
+    <!-- XTXT: coronatest negative result certificate info body -->
+    <string name="coronatest_negative_result_certificate_info_body">"Das Testzertifikat liegt im Tab „Zertifikate“ vor."</string>
 
     <!-- ####################################
      Rapid Antigen Test Profile
diff --git a/Corona-Warn-App/src/main/res/values/antigen_strings.xml b/Corona-Warn-App/src/main/res/values/antigen_strings.xml
index 525e59370..4a8d7401c 100644
--- a/Corona-Warn-App/src/main/res/values/antigen_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/antigen_strings.xml
@@ -141,6 +141,10 @@
     <string name="coronatest_negative_antigen_result_third_info_title">"Remove Test"</string>
     <!-- XTXT: coronatest negative antigen result third info body -->
     <string name="coronatest_negative_antigen_restul_third_info_body">"Please delete the test from the Corona-Warn-App, so that you can save a new test code here if necessary."</string>
+    <!-- XTXT: coronatest negative result certificate info title -->
+    <string name="coronatest_negative_result_certificate_info_title"></string>
+    <!-- XTXT: coronatest negative result certificate info body -->
+    <string name="coronatest_negative_result_certificate_info_body"></string>
 
     <!-- ####################################
      Rapid Antigen Test Profile
-- 
GitLab