From eca15f2964eb83b2f83d12bd0c499cd899673c0c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakob=20M=C3=B6ller?= <jakob.moeller@sap.com>
Date: Thu, 11 Jun 2020 15:09:31 +0200
Subject: [PATCH] Compile Strip for Test Coding (#348)

* First Setup of Compile Strip

Signed-off-by: d067928 <jakob.moeller@sap.com>

* First Setup of Compile Strip

Signed-off-by: d067928 <jakob.moeller@sap.com>

* First Setup of Compile Strip

Signed-off-by: d067928 <jakob.moeller@sap.com>

* First Setup of Compile Strip

Signed-off-by: d067928 <jakob.moeller@sap.com>

* First Setup of Compile Strip

Signed-off-by: d067928 <jakob.moeller@sap.com>

* remove notification

Signed-off-by: d067928 <jakob.moeller@sap.com>

* fixed risk level test fragment

* Log to Timber

Signed-off-by: d067928 <jakob.moeller@sap.com>

* Log to Timber

Signed-off-by: d067928 <jakob.moeller@sap.com>

* Environment Variables only drawn for TestRelease

Signed-off-by: d067928 <jakob.moeller@sap.com>

* remove toasts from productive code

* fix wildcard import

* Adjust Fragment

Signed-off-by: d067928 <jakob.moeller@sap.com>

* Adaptions to Test Coding

Signed-off-by: d067928 <jakob.moeller@sap.com>

* added exception handling for Test Risk Level fragment

Co-authored-by: Philipp Woessner <philipp.woessner@sap.com>
Co-authored-by: Ooi, Hee Tatt <hee.tatt.ooi@sap.com>
---
 Corona-Warn-App/build.gradle                  |  68 ++--
 .../ui/main/MainFragment.kt                   | 177 ++++++++++
 .../TestForAPIFragment.kt                     |  48 +--
 .../TestRiskLevelCalculation.kt               | 215 +++++++------
 .../ui/main/MainFragment.kt                   |  19 --
 .../res/layout/fragment_main.xml              | 231 +++++++++++++
 .../res/layout/fragment_test_for_a_p_i.xml    |   0
 .../fragment_test_risk_level_calculation.xml  |   0
 .../deviceForTesters/res/menu/menu_main.xml   |  18 ++
 .../res/navigation/nav_graph.xml              | 303 ++++++++++++++++++
 .../InternalExposureNotificationClient.kt     |  12 -
 .../storage/TracingRepository.kt              |  10 +-
 .../transaction/RiskLevelTransaction.kt       |  32 +-
 .../ui/settings/SettingsResetFragment.kt      |   6 -
 .../ui/settings/SettingsTracingFragment.kt    |  15 -
 .../coronawarnapp/util/CachedKeyFileHolder.kt |   3 +-
 .../src/main/res/menu/menu_main.xml           |  10 -
 .../src/main/res/navigation/nav_graph.xml     |   9 -
 build.gradle                                  |   8 +
 19 files changed, 933 insertions(+), 251 deletions(-)
 create mode 100644 Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt
 rename Corona-Warn-App/src/{main/java/de/rki/coronawarnapp => deviceForTesters/java/de.rki.coronawarnapp}/TestForAPIFragment.kt (88%)
 rename Corona-Warn-App/src/{main/java/de/rki/coronawarnapp => deviceForTesters/java/de.rki.coronawarnapp}/TestRiskLevelCalculation.kt (57%)
 rename Corona-Warn-App/src/{main/java/de/rki/coronawarnapp => deviceForTesters/java/de.rki.coronawarnapp}/ui/main/MainFragment.kt (89%)
 create mode 100644 Corona-Warn-App/src/deviceForTesters/res/layout/fragment_main.xml
 rename Corona-Warn-App/src/{main => deviceForTesters}/res/layout/fragment_test_for_a_p_i.xml (100%)
 rename Corona-Warn-App/src/{main => deviceForTesters}/res/layout/fragment_test_risk_level_calculation.xml (100%)
 create mode 100644 Corona-Warn-App/src/deviceForTesters/res/menu/menu_main.xml
 create mode 100644 Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml

diff --git a/Corona-Warn-App/build.gradle b/Corona-Warn-App/build.gradle
index 8210fbdb8..910799534 100644
--- a/Corona-Warn-App/build.gradle
+++ b/Corona-Warn-App/build.gradle
@@ -44,24 +44,12 @@ android {
         //override URLs. Use local.properties if exist.
         // If environment.properties also exist, override local.properties
         def propertiesFile = project.rootProject.file('local.properties')
-        def environmentPropertiesFile = project.rootProject.file('environment.properties')
 
-        Properties overridingProperties
 
         if (propertiesFile.exists()) {
-            overridingProperties = new Properties()
+            Properties overridingProperties = new Properties()
             overridingProperties.load(propertiesFile.newDataInputStream())
-        }
-
-        if (environmentPropertiesFile.exists()) {
-            overridingProperties = new Properties()
-            overridingProperties.load(environmentPropertiesFile.newDataInputStream())
-        }else if (propertiesFile.exists()) {
-            overridingProperties = new Properties()
-            overridingProperties.load(propertiesFile.newDataInputStream())
-        }
 
-        if(overridingProperties){
             def DOWNLOAD_CDN_URL = overridingProperties.getProperty('DOWNLOAD_CDN_URL')
             if (DOWNLOAD_CDN_URL)
                 buildConfigField "String", "DOWNLOAD_CDN_URL", "\"$DOWNLOAD_CDN_URL\""
@@ -92,17 +80,9 @@ android {
             shrinkResources true
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
-        releaseForTest {
-            applicationIdSuffix '.dev'
-            minifyEnabled true
-            shrinkResources true
-            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
-        }
     }
 
-    // https://developer.android.com/studio/build/build-variants
-    // We use flavors to build different versions of the app. One version which uses
-    // the mock ExposureNotification API and one for the real Google API
+    // One version contains our Test Fragments
     flavorDimensions "version"
     productFlavors {
         device {
@@ -110,6 +90,34 @@ android {
             buildConfigField "String", "BUILD_VARIANT", "\"device\""
             resValue "string", "app_name", "Corona-Warn"
         }
+        deviceForTesters {
+            dimension "version"
+            buildConfigField "String", "BUILD_VARIANT", "\"deviceForTesters\""
+            resValue "string", "app_name", "CWA TEST"
+            applicationIdSuffix '.dev'
+
+            def environmentPropertiesFile = project.rootProject.file('environment.properties')
+            if (environmentPropertiesFile.exists()) {
+                Properties overridingProperties = new Properties()
+                overridingProperties.load(environmentPropertiesFile.newDataInputStream())
+
+                def DOWNLOAD_CDN_URL = overridingProperties.getProperty('DOWNLOAD_CDN_URL')
+                if (DOWNLOAD_CDN_URL)
+                    buildConfigField "String", "DOWNLOAD_CDN_URL", "\"$DOWNLOAD_CDN_URL\""
+
+                def SUBMISSION_CDN_URL = overridingProperties.getProperty('SUBMISSION_CDN_URL')
+                if (SUBMISSION_CDN_URL)
+                    buildConfigField "String", "SUBMISSION_CDN_URL", "\"$SUBMISSION_CDN_URL\""
+
+                def VERIFICATION_CDN_URL = overridingProperties.getProperty('VERIFICATION_CDN_URL')
+                if (VERIFICATION_CDN_URL)
+                    buildConfigField "String", "VERIFICATION_CDN_URL", "\"$VERIFICATION_CDN_URL\""
+
+                def PUB_KEYS_SIGNATURE_VERIFICATION = overridingProperties.getProperty('PUB_KEYS_SIGNATURE_VERIFICATION')
+                if (PUB_KEYS_SIGNATURE_VERIFICATION)
+                    buildConfigField "String", "PUB_KEYS_SIGNATURE_VERIFICATION", "\"$PUB_KEYS_SIGNATURE_VERIFICATION\""
+            }
+        }
     }
 
     buildFeatures {
@@ -157,6 +165,22 @@ android {
         exclude 'CODE_OF_CONDUCT.md'
     }
 
+    sourceSets {
+        deviceForTesters {
+            kotlin {
+                srcDirs = ['src/deviceForTesters']
+            }
+            res {
+                srcDirs 'src/deviceForTesters/res', 'src/deviceForTesters/res/navigation'
+            }
+        }
+        device {
+            kotlin {
+                srcDirs = ['src/device']
+            }
+        }
+    }
+
 }
 
 dependencies {
diff --git a/Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt b/Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt
new file mode 100644
index 000000000..b3b01c57a
--- /dev/null
+++ b/Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt
@@ -0,0 +1,177 @@
+package de.rki.coronawarnapp.ui.main
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.accessibility.AccessibilityEvent
+import android.widget.PopupMenu
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.navigation.fragment.findNavController
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.databinding.FragmentMainBinding
+import de.rki.coronawarnapp.timer.TimerHelper
+import de.rki.coronawarnapp.ui.doNavigate
+import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel
+import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
+import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
+import de.rki.coronawarnapp.util.ExternalActionHelper
+
+/**
+ * After the user has finished the onboarding this fragment will be the heart of the application.
+ * Three ViewModels are needed that this fragment shows all relevant information to the user.
+ * Also the Menu is set here.
+ *
+ * @see tracingViewModel
+ * @see settingsViewModel
+ * @see submissionViewModel
+ * @see PopupMenu
+ */
+class MainFragment : Fragment() {
+
+    companion object {
+        private val TAG: String? = MainFragment::class.simpleName
+    }
+
+    private val tracingViewModel: TracingViewModel by activityViewModels()
+    private val settingsViewModel: SettingsViewModel by activityViewModels()
+    private val submissionViewModel: SubmissionViewModel by activityViewModels()
+    private var _binding: FragmentMainBinding? = null
+    private val binding: FragmentMainBinding get() = _binding!!
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        _binding = FragmentMainBinding.inflate(inflater)
+        binding.tracingViewModel = tracingViewModel
+        binding.settingsViewModel = settingsViewModel
+        binding.submissionViewModel = submissionViewModel
+        binding.lifecycleOwner = this
+        return binding.root
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        setButtonOnClickListener()
+        setContentDescription()
+    }
+
+    override fun onResume() {
+        super.onResume()
+        // refresh required data
+        tracingViewModel.refreshRiskLevel()
+        tracingViewModel.refreshExposureSummary()
+        tracingViewModel.refreshLastTimeDiagnosisKeysFetchedDate()
+        tracingViewModel.refreshIsTracingEnabled()
+        tracingViewModel.refreshActiveTracingDaysInRetentionPeriod()
+        TimerHelper.checkManualKeyRetrievalTimer()
+        submissionViewModel.refreshDeviceUIState()
+        tracingViewModel.refreshLastSuccessfullyCalculatedScore()
+        binding.mainScrollview.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
+    }
+
+    override fun onStart() {
+        super.onStart()
+        binding.mainScrollview.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
+    }
+
+    private fun setContentDescription() {
+        val shareButtonString: String = getString(R.string.button_share)
+        val menuButtonString: String = getString(R.string.button_menu)
+        val mainCardString: String = getString(R.string.hint_external_webpage)
+        binding.mainHeaderShare.buttonIcon.contentDescription = shareButtonString
+        binding.mainHeaderOptionsMenu.buttonIcon.contentDescription = menuButtonString
+        binding.mainAbout.mainCard.contentDescription = mainCardString
+    }
+
+    private fun setButtonOnClickListener() {
+        binding.mainTestUnregistered.submissionStatusCardUnregistered.setOnClickListener {
+            toSubmissionIntro()
+        }
+        binding.mainTestUnregistered.submissionStatusCardUnregisteredButton.setOnClickListener {
+            toSubmissionIntro()
+        }
+        binding.mainTestDone.submissionStatusCardDone.setOnClickListener {
+            findNavController().doNavigate(
+                MainFragmentDirections.actionMainFragmentToSubmissionDoneFragment()
+            )
+        }
+        binding.mainTestResult.submissionStatusCardContent.setOnClickListener {
+            toSubmissionResult()
+        }
+        binding.mainTestResult.submissionStatusCardContentButton.setOnClickListener {
+            toSubmissionResult()
+        }
+        binding.mainTestPositive.submissionStatusCardPositive.setOnClickListener {
+            toSubmissionResult()
+        }
+        binding.mainTestPositive.submissionStatusCardPositiveButton.setOnClickListener {
+            toSubmissionResult()
+        }
+        binding.mainTracing.setOnClickListener {
+            findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToSettingsTracingFragment())
+        }
+        binding.mainRisk.riskCard.setOnClickListener {
+            findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToRiskDetailsFragment())
+        }
+        binding.mainRisk.riskCardButtonUpdate.setOnClickListener {
+            tracingViewModel.refreshDiagnosisKeys()
+            settingsViewModel.updateManualKeyRetrievalEnabled(false)
+        }
+        binding.mainRisk.riskCardButtonEnableTracing.setOnClickListener {
+            findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToSettingsTracingFragment())
+        }
+        binding.mainAbout.mainCard.setOnClickListener {
+            ExternalActionHelper.openUrl(this, requireContext().getString(R.string.main_about_link))
+        }
+        binding.mainHeaderShare.buttonIcon.setOnClickListener {
+            findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToMainSharingFragment())
+        }
+        binding.mainHeaderOptionsMenu.buttonIcon.setOnClickListener {
+            showPopup(it)
+        }
+    }
+
+    private fun toSubmissionResult() {
+        findNavController().doNavigate(
+            MainFragmentDirections.actionMainFragmentToSubmissionResultFragment()
+        )
+    }
+
+    private fun toSubmissionIntro() {
+        findNavController().doNavigate(
+            MainFragmentDirections.actionMainFragmentToSubmissionIntroFragment()
+        )
+    }
+
+    private fun showPopup(view: View) {
+        val popup = PopupMenu(requireContext(), view)
+        popup.inflate(R.menu.menu_main)
+        popup.setOnMenuItemClickListener {
+            return@setOnMenuItemClickListener when (it.itemId) {
+                R.id.menu_help -> {
+                    findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToMainOverviewFragment())
+                    true
+                }
+                R.id.menu_information -> {
+                    findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToInformationFragment())
+                    true
+                }
+                R.id.menu_settings -> {
+                    findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToSettingsFragment())
+                    true
+                }
+                else -> super.onOptionsItemSelected(it)
+            }
+        }
+        popup.show()
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestForAPIFragment.kt
similarity index 88%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt
rename to Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestForAPIFragment.kt
index 4b7c14b70..950664416 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestForAPIFragment.kt
@@ -49,30 +49,30 @@ import de.rki.coronawarnapp.storage.tracing.TracingIntervalRepository
 import de.rki.coronawarnapp.transaction.RiskLevelTransaction
 import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
 import de.rki.coronawarnapp.util.KeyFileHelper
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_api_enter_other_keys
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_api_get_check_exposure
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_api_get_exposure_keys
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_api_scan_qr_code
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_api_share_my_keys
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_api_submit_keys
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_api_test_start
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_calculate_risk_level
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_clear_db
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_insert_exposure_summary
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_retrieve_exposure_summary
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_tracing_duration_in_retention_period
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_tracing_intervals
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_exposure_summary_attenuation
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_exposure_summary_daysSinceLastExposure
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_exposure_summary_matchedKeyCount
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_exposure_summary_maximumRiskScore
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_exposure_summary_summationRiskScore
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_googlePlayServices_version
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_my_keys
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.qr_code_viewpager
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.test_api_switch_last_three_hours_from_server
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.text_my_keys
-import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.text_scanned_key
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_api_enter_other_keys
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_api_get_check_exposure
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_api_get_exposure_keys
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_api_scan_qr_code
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_api_share_my_keys
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_api_submit_keys
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_api_test_start
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_calculate_risk_level
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_clear_db
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_insert_exposure_summary
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_retrieve_exposure_summary
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_tracing_duration_in_retention_period
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.button_tracing_intervals
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.label_exposure_summary_attenuation
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.label_exposure_summary_daysSinceLastExposure
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.label_exposure_summary_matchedKeyCount
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.label_exposure_summary_maximumRiskScore
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.label_exposure_summary_summationRiskScore
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.label_googlePlayServices_version
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.label_my_keys
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.qr_code_viewpager
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.test_api_switch_last_three_hours_from_server
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.text_my_keys
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.text_scanned_key
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt b/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestRiskLevelCalculation.kt
similarity index 57%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt
rename to Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestRiskLevelCalculation.kt
index f44da266a..a81b12c96 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestRiskLevelCalculation.kt
@@ -9,10 +9,10 @@ import android.widget.EditText
 import android.widget.Toast
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.viewModelScope
-import com.google.android.gms.nearby.exposurenotification.ExposureSummary
+import com.google.android.gms.nearby.Nearby
+import com.google.android.gms.nearby.exposurenotification.ExposureInformation
 import com.google.zxing.integration.android.IntentIntegrator
 import com.google.zxing.integration.android.IntentResult
 import de.rki.coronawarnapp.databinding.FragmentTestRiskLevelCalculationBinding
@@ -21,14 +21,15 @@ import de.rki.coronawarnapp.exception.TransactionException
 import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.risk.RiskLevel
+import de.rki.coronawarnapp.risk.RiskLevelCalculation
 import de.rki.coronawarnapp.risk.TimeVariables
 import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange
-import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass
 import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService
 import de.rki.coronawarnapp.sharing.ExposureSharingService
 import de.rki.coronawarnapp.storage.AppDatabase
 import de.rki.coronawarnapp.storage.FileStorageHelper
 import de.rki.coronawarnapp.storage.LocalData
+import de.rki.coronawarnapp.storage.RiskLevelRepository
 import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction
 import de.rki.coronawarnapp.transaction.RiskLevelTransaction
 import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel
@@ -36,7 +37,7 @@ import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
 import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
 import de.rki.coronawarnapp.util.KeyFileHelper
 import de.rki.coronawarnapp.util.security.SecurityHelper
-import kotlinx.android.synthetic.main.fragment_test_risk_level_calculation.transmission_number
+import kotlinx.android.synthetic.deviceForTesters.fragment_test_risk_level_calculation.transmission_number
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
@@ -44,6 +45,9 @@ import timber.log.Timber
 import java.io.File
 import java.util.UUID
 import java.util.concurrent.TimeUnit
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlin.coroutines.suspendCoroutine
 
 @Suppress("MagicNumber", "LongMethod")
 class TestRiskLevelCalculation : Fragment() {
@@ -51,19 +55,17 @@ class TestRiskLevelCalculation : Fragment() {
         val TAG: String? = TestRiskLevelCalculation::class.simpleName
     }
 
-    data class TransactionValues(
-        var appConfig: ApplicationConfigurationOuterClass.ApplicationConfiguration? = null,
-        var exposureSummary: ExposureSummary? = null,
-        var riskScore: Double? = null,
-        var riskLevel: RiskLevel? = null
-    )
-
     private val tracingViewModel: TracingViewModel by activityViewModels()
     private val settingsViewModel: SettingsViewModel by activityViewModels()
     private val submissionViewModel: SubmissionViewModel by activityViewModels()
     private var _binding: FragmentTestRiskLevelCalculationBinding? = null
     private val binding: FragmentTestRiskLevelCalculationBinding get() = _binding!!
 
+    // reference to the client from the Google framework with the given application context
+    private val exposureNotificationClient by lazy {
+        Nearby.getExposureNotificationClient(CoronaWarnApplication.getAppContext())
+    }
+
     override fun onCreateView(
         inflater: LayoutInflater,
         container: ViewGroup?,
@@ -128,13 +130,14 @@ class TestRiskLevelCalculation : Fragment() {
             }
         }
 
+
         startObserving()
+
     }
 
     override fun onResume() {
         super.onResume()
         tracingViewModel.viewModelScope.launch {
-            RiskLevelTransaction.recordedTransactionValuesForTestingOnly = TransactionValues()
             calculateRiskLevel()
         }
     }
@@ -243,90 +246,112 @@ class TestRiskLevelCalculation : Fragment() {
     }
 
     private fun startObserving() {
-        RiskLevelTransaction.tempExposedTransactionValuesForTestingOnly.observe(
-            viewLifecycleOwner,
-            Observer {
-                tracingViewModel.viewModelScope.launch {
-                    val riskAsString = "Level: ${it.riskLevel}\n" +
-                            "Last successful Level: " +
-                            "${LocalData.lastSuccessfullyCalculatedRiskLevel()}\n" +
-                            "Calculated Score: ${it.riskScore}\n" +
-                            "Last Time Server Fetch: ${LocalData.lastTimeDiagnosisKeysFromServerFetch()}\n" +
-                            "Tracing Duration: " +
-                            "${TimeUnit.MILLISECONDS.toDays(TimeVariables.getTimeActiveTracingDuration())} days \n" +
-                            "Tracing Duration in last 14 days: " +
-                            "${TimeVariables.getActiveTracingDaysInRetentionPeriod()} days \n" +
-                            "Last time risk level calculation ${LocalData.lastTimeRiskLevelCalculation()}"
-
-                    binding.labelRiskScore.text = riskAsString
-
-                    val lowClass =
-                        it.appConfig?.riskScoreClasses?.riskClassesList?.find { low -> low.label == "LOW" }
-                    val highClass =
-                        it.appConfig?.riskScoreClasses?.riskClassesList?.find { high -> high.label == "HIGH" }
-
-                    val configAsString =
-                        "Attenuation Weight Low: ${it.appConfig?.attenuationDuration?.weights?.low}\n" +
-                                "Attenuation Weight Mid: ${it.appConfig?.attenuationDuration?.weights?.mid}\n" +
-                                "Attenuation Weight High: ${it.appConfig?.attenuationDuration?.weights?.high}\n\n" +
-                                "Attenuation Offset: ${it.appConfig?.attenuationDuration?.defaultBucketOffset}\n" +
-                                "Attenuation Normalization: " +
-                                "${it.appConfig?.attenuationDuration?.riskScoreNormalizationDivisor}\n\n" +
-                                "Risk Score Low Class: ${lowClass?.min ?: 0} - ${lowClass?.max ?: 0}\n" +
-                                "Risk Score High Class: ${highClass?.min ?: 0} - ${highClass?.max ?: 0}"
-
-                    binding.labelBackendParameters.text = configAsString
-
-                    val summaryAsString =
-                        "Days Since Last Exposure: ${it.exposureSummary?.daysSinceLastExposure}\n" +
-                                "Matched Key Count: ${it.exposureSummary?.matchedKeyCount}\n" +
-                                "Maximum Risk Score: ${it.exposureSummary?.maximumRiskScore}\n" +
-                                "Attenuation Durations: [${it.exposureSummary?.attenuationDurationsInMinutes?.get(
-                                    0
-                                )}," +
-                                "${it.exposureSummary?.attenuationDurationsInMinutes?.get(1)}," +
-                                "${it.exposureSummary?.attenuationDurationsInMinutes?.get(2)}]\n" +
-                                "Summation Risk Score: ${it.exposureSummary?.summationRiskScore}"
-
-                    binding.labelExposureSummary.text = summaryAsString
-
-                    val maxRisk = it.exposureSummary?.maximumRiskScore
-                    val atWeights = it.appConfig?.attenuationDuration?.weights
-                    val attenuationDurationInMin =
-                        it.exposureSummary?.attenuationDurationsInMinutes
-                    val attenuationConfig = it.appConfig?.attenuationDuration
-                    val formulaString =
-                        "($maxRisk / ${attenuationConfig?.riskScoreNormalizationDivisor}) * " +
-                                "(${attenuationDurationInMin?.get(0)} * ${atWeights?.low} " +
-                                "+ ${attenuationDurationInMin?.get(1)} * ${atWeights?.mid} " +
-                                "+ ${attenuationDurationInMin?.get(2)} * ${atWeights?.high} " +
-                                "+ ${attenuationConfig?.defaultBucketOffset})"
-
-                    binding.labelFormula.text = formulaString
-
-                    binding.labelFullConfig.text = it.appConfig?.toString()
-
-                    val token = LocalData.googleApiToken()
-                    if (token != null) {
-                        val exposureInformation =
-                            InternalExposureNotificationClient.asyncGetExposureInformation(token)
-
-                        var infoString = ""
-                        exposureInformation.forEach {
-                            infoString += "Attenuation duration in min.: " +
-                                    "[${it.attenuationDurationsInMinutes?.get(0)}, " +
-                                    "${it.attenuationDurationsInMinutes?.get(1)}," +
-                                    "${it.attenuationDurationsInMinutes?.get(2)}]\n" +
-                                    "Attenuation value: ${it.attenuationValue}\n" +
-                                    "Duration in min.: ${it.durationMinutes}\n" +
-                                    "Risk Score: ${it.totalRiskScore}\n" +
-                                    "Transmission Risk Level: ${it.transmissionRiskLevel}\n" +
-                                    "Date Millis Since Epoch: ${it.dateMillisSinceEpoch}\n\n"
-                        }
-
-                        binding.labelExposureInfo.text = infoString
+        tracingViewModel.viewModelScope.launch {
+            try {
+                val googleToken = LocalData.googleApiToken() ?: UUID.randomUUID().toString()
+                val exposureSummary =
+                    InternalExposureNotificationClient.asyncGetExposureSummary(googleToken)
+
+                val appConfig =
+                    ApplicationConfigurationService.asyncRetrieveApplicationConfiguration()
+
+                val riskLevelScore = RiskLevelCalculation.calculateRiskScore(
+                    appConfig.attenuationDuration,
+                    exposureSummary
+                )
+
+                val riskAsString = "Level: ${RiskLevelRepository.getLastCalculatedScore()}\n" +
+                        "Last successful Level: " +
+                        "${LocalData.lastSuccessfullyCalculatedRiskLevel()}\n" +
+                        "Calculated Score: ${riskLevelScore}\n" +
+                        "Last Time Server Fetch: ${LocalData.lastTimeDiagnosisKeysFromServerFetch()}\n" +
+                        "Tracing Duration: " +
+                        "${TimeUnit.MILLISECONDS.toDays(TimeVariables.getTimeActiveTracingDuration())} days \n" +
+                        "Tracing Duration in last 14 days: " +
+                        "${TimeVariables.getActiveTracingDaysInRetentionPeriod()} days \n" +
+                        "Last time risk level calculation ${LocalData.lastTimeRiskLevelCalculation()}"
+
+                binding.labelRiskScore.text = riskAsString
+
+                val lowClass =
+                    appConfig.riskScoreClasses?.riskClassesList?.find { low -> low.label == "LOW" }
+                val highClass =
+                    appConfig.riskScoreClasses?.riskClassesList?.find { high -> high.label == "HIGH" }
+
+                val configAsString =
+                    "Attenuation Weight Low: ${appConfig.attenuationDuration?.weights?.low}\n" +
+                            "Attenuation Weight Mid: ${appConfig.attenuationDuration?.weights?.mid}\n" +
+                            "Attenuation Weight High: ${appConfig.attenuationDuration?.weights?.high}\n\n" +
+                            "Attenuation Offset: ${appConfig.attenuationDuration?.defaultBucketOffset}\n" +
+                            "Attenuation Normalization: " +
+                            "${appConfig.attenuationDuration?.riskScoreNormalizationDivisor}\n\n" +
+                            "Risk Score Low Class: ${lowClass?.min ?: 0} - ${lowClass?.max ?: 0}\n" +
+                            "Risk Score High Class: ${highClass?.min ?: 0} - ${highClass?.max ?: 0}"
+
+                binding.labelBackendParameters.text = configAsString
+
+                val summaryAsString =
+                    "Days Since Last Exposure: ${exposureSummary.daysSinceLastExposure}\n" +
+                            "Matched Key Count: ${exposureSummary.matchedKeyCount}\n" +
+                            "Maximum Risk Score: ${exposureSummary.maximumRiskScore}\n" +
+                            "Attenuation Durations: [${exposureSummary.attenuationDurationsInMinutes?.get(
+                                0
+                            )}," +
+                            "${exposureSummary.attenuationDurationsInMinutes?.get(1)}," +
+                            "${exposureSummary.attenuationDurationsInMinutes?.get(2)}]\n" +
+                            "Summation Risk Score: ${exposureSummary.summationRiskScore}"
+
+                binding.labelExposureSummary.text = summaryAsString
+
+                val maxRisk = exposureSummary.maximumRiskScore
+                val atWeights = appConfig.attenuationDuration?.weights
+                val attenuationDurationInMin =
+                    exposureSummary.attenuationDurationsInMinutes
+                val attenuationConfig = appConfig.attenuationDuration
+                val formulaString =
+                    "($maxRisk / ${attenuationConfig?.riskScoreNormalizationDivisor}) * " +
+                            "(${attenuationDurationInMin?.get(0)} * ${atWeights?.low} " +
+                            "+ ${attenuationDurationInMin?.get(1)} * ${atWeights?.mid} " +
+                            "+ ${attenuationDurationInMin?.get(2)} * ${atWeights?.high} " +
+                            "+ ${attenuationConfig?.defaultBucketOffset})"
+
+                binding.labelFormula.text = formulaString
+
+                binding.labelFullConfig.text = appConfig.toString()
+
+                val token = LocalData.googleApiToken()
+                if (token != null) {
+                    val exposureInformation = asyncGetExposureInformation(token)
+
+                    var infoString = ""
+                    exposureInformation.forEach {
+                        infoString += "Attenuation duration in min.: " +
+                                "[${it.attenuationDurationsInMinutes?.get(0)}, " +
+                                "${it.attenuationDurationsInMinutes?.get(1)}," +
+                                "${it.attenuationDurationsInMinutes?.get(2)}]\n" +
+                                "Attenuation value: ${it.attenuationValue}\n" +
+                                "Duration in min.: ${it.durationMinutes}\n" +
+                                "Risk Score: ${it.totalRiskScore}\n" +
+                                "Transmission Risk Level: ${it.transmissionRiskLevel}\n" +
+                                "Date Millis Since Epoch: ${it.dateMillisSinceEpoch}\n\n"
                     }
+
+                    binding.labelExposureInfo.text = infoString
                 }
-            })
+            } catch (e: Exception) {
+                e.report(ExceptionCategory.EXPOSURENOTIFICATION)
+            }
+        }
     }
+
+    // todo remove before release - not used in prod setup - only for testing
+    suspend fun asyncGetExposureInformation(token: String): List<ExposureInformation> =
+        suspendCoroutine { cont ->
+            exposureNotificationClient.getExposureInformation(token)
+                .addOnSuccessListener {
+                    cont.resume(it)
+                }.addOnFailureListener {
+                    cont.resumeWithException(it)
+                }
+        }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/ui/main/MainFragment.kt
similarity index 89%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainFragment.kt
rename to Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/ui/main/MainFragment.kt
index 44c1104f1..502ba7fe7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/ui/main/MainFragment.kt
@@ -6,21 +6,17 @@ import android.view.View
 import android.view.ViewGroup
 import android.view.accessibility.AccessibilityEvent
 import android.widget.PopupMenu
-import androidx.core.app.NotificationCompat
-import androidx.core.app.NotificationManagerCompat
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
 import androidx.navigation.fragment.findNavController
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentMainBinding
-import de.rki.coronawarnapp.notification.NotificationHelper
 import de.rki.coronawarnapp.timer.TimerHelper
 import de.rki.coronawarnapp.ui.doNavigate
 import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel
 import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
 import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
 import de.rki.coronawarnapp.util.ExternalActionHelper
-import timber.log.Timber
 
 /**
  * After the user has finished the onboarding this fragment will be the heart of the application.
@@ -173,31 +169,16 @@ class MainFragment : Fragment() {
                     findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToSettingsFragment())
                     true
                 }
-                // todo remove only for testing
                 R.id.menu_test_api -> {
                     findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToTestForAPIFragment())
                     true
                 }
-                // todo remove only for testing
                 R.id.menu_test_risk_level -> {
                     findNavController().doNavigate(
                         MainFragmentDirections.actionMainFragmentToTestRiskLevelCalculation()
                     )
                     true
                 }
-                // todo remove only for testing
-                R.id.menu_notification_test -> {
-                    Timber.i("calling notification")
-                    Timber.i(
-                        NotificationManagerCompat.from(requireContext()).areNotificationsEnabled()
-                            .toString()
-                    )
-                    NotificationHelper.sendNotification(
-                        getString(R.string.notification_body),
-                        NotificationCompat.PRIORITY_HIGH
-                    )
-                    true
-                }
                 else -> super.onOptionsItemSelected(it)
             }
         }
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_main.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_main.xml
new file mode 100644
index 000000000..6a9bd45d4
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_main.xml
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <data>
+
+        <import type="de.rki.coronawarnapp.util.formatter.FormatterSettingsHelper" />
+
+        <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" />
+
+        <variable
+            name="submissionViewModel"
+            type="de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel" />
+
+        <variable
+            name="tracingViewModel"
+            type="de.rki.coronawarnapp.ui.viewmodel.TracingViewModel" />
+
+        <variable
+            name="settingsViewModel"
+            type="de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel" />
+    </data>
+
+    <ScrollView
+        android:id="@+id/main_scrollview"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:contentDescription="@string/main_title"
+        android:fillViewport="true"
+        tools:context="de.rki.coronawarnapp.ui.main.MainFragment">
+
+        <!-- todo apply merge tags through xml when applicable (eod) -->
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <androidx.constraintlayout.widget.ConstraintLayout
+                android:id="@+id/main_header"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="@dimen/header_main"
+                android:layout_margin="@dimen/spacing_small"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent">
+
+                <ImageView
+                    android:id="@+id/main_header_logo"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:importantForAccessibility="no"
+                    android:scaleType="fitStart"
+                    android:src="@drawable/ic_main_header"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintEnd_toStartOf="@+id/main_header_share"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+                <include
+                    android:id="@+id/main_header_share"
+                    layout="@layout/include_button_icon"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    app:icon="@{@drawable/ic_main_share}"
+                    app:iconDescription="@{@string/main_share_title}"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintEnd_toStartOf="@+id/main_header_options_menu"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+                <include
+                    android:id="@+id/main_header_options_menu"
+                    layout="@layout/include_button_icon"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    app:icon="@{@drawable/ic_main_settings}"
+                    app:iconDescription="@{@string/accessibility_menu}"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+            </androidx.constraintlayout.widget.ConstraintLayout>
+
+            <androidx.constraintlayout.widget.ConstraintLayout
+                android:id="@+id/main_tracing"
+                style="@style/buttonTracing"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:focusable="true"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintHorizontal_bias="0.0"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/main_header">
+
+                <TextView
+                    android:id="@+id/main_tracing_headline"
+                    style="@style/bodyButton"
+                    android:layout_width="@dimen/match_constraint"
+                    android:layout_height="wrap_content"
+                    android:focusable="false"
+                    android:text="@{FormatterSettingsHelper.formatTracingDescription(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled())}"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+                <ImageView
+                    android:id="@+id/main_tracing_icon"
+                    android:layout_width="@dimen/icon_size_main_card"
+                    android:layout_height="@dimen/icon_size_main_card"
+                    android:importantForAccessibility="no"
+                    android:src="@{FormatterSettingsHelper.formatTracingIcon(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled())}"
+                    android:tint="@{FormatterSettingsHelper.formatTracingIconColor(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled())}"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+            </androidx.constraintlayout.widget.ConstraintLayout>
+
+            <include
+                android:id="@+id/main_tracing_divider"
+                layout="@layout/include_divider"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/main_tracing" />
+
+            <include
+                android:id="@+id/main_risk"
+                layout="@layout/include_risk_card"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_small"
+                android:visibility="@{FormatterSubmissionHelper.formatShowRiskStatusCard(submissionViewModel.deviceUiState)}"
+                app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
+                app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
+                app:layout_constraintTop_toBottomOf="@+id/main_tracing_divider"
+                app:settingsViewModel="@{settingsViewModel}"
+                app:showDetails="@{false}"
+                app:tracingViewModel="@{tracingViewModel}" />
+
+            <!-- submission status cards -->
+            <include
+                android:id="@+id/main_test_unregistered"
+                layout="@layout/include_submission_status_card_unregistered"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_small"
+                android:visibility="@{FormatterSubmissionHelper.formatSubmissionStatusCardUnregisteredVisible(submissionViewModel.deviceRegistered)}"
+                app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
+                app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
+                app:layout_constraintTop_toBottomOf="@id/main_risk" />
+
+            <include
+                android:id="@+id/main_test_result"
+                layout="@layout/include_submission_status_card_content"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_small"
+                android:visibility="@{FormatterSubmissionHelper.formatSubmissionStatusCardContentVisible(submissionViewModel.deviceUiState)}"
+                app:deviceUIState="@{submissionViewModel.deviceUiState}"
+                app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
+                app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
+                app:layout_constraintTop_toBottomOf="@id/main_test_unregistered" />
+
+            <include
+                android:id="@+id/main_test_fetching"
+                layout="@layout/include_submission_status_card_fetching"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_small"
+                android:visibility="@{FormatterSubmissionHelper.formatSubmissionStatusCardFetchingVisible(submissionViewModel.deviceRegistered, submissionViewModel.uiStateState)}"
+                app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
+                app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
+                app:layout_constraintTop_toBottomOf="@id/main_test_result" />
+
+            <include
+                android:id="@+id/main_test_positive"
+                layout="@layout/include_submission_status_card_positive"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_small"
+                android:visibility="@{FormatterSubmissionHelper.formatShowSubmissionStatusPositiveCard(submissionViewModel.deviceUiState)}"
+                app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
+                app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
+                app:layout_constraintTop_toBottomOf="@+id/main_test_fetching"
+                app:registerDate="@{submissionViewModel.testResultReceivedDate}" />
+
+            <include
+                android:id="@+id/main_test_done"
+                layout="@layout/include_submission_status_card_done"
+                android:layout_width="@dimen/match_constraint"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_small"
+                android:visibility="@{FormatterSubmissionHelper.formatShowSubmissionDoneCard(submissionViewModel.deviceUiState)}"
+                app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
+                app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
+                app:layout_constraintTop_toBottomOf="@+id/main_test_positive" />
+
+            <androidx.constraintlayout.widget.Barrier
+                android:id="@+id/main_barrier"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                app:barrierDirection="bottom"
+                app:constraint_referenced_ids="main_test_done, main_risk" />
+
+            <include
+                android:id="@+id/main_about"
+                layout="@layout/include_main_faq_card"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/spacing_small"
+                app:layout_constraintBottom_toTopOf="@+id/guideline_bottom"
+                app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
+                app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
+                app:layout_constraintTop_toBottomOf="@+id/main_barrier" />
+
+            <include layout="@layout/merge_guidelines_side" />
+
+            <androidx.constraintlayout.widget.Guideline
+                android:id="@+id/guideline_bottom"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                app:layout_constraintGuide_end="@dimen/spacing_small" />
+
+            <include layout="@layout/merge_guidelines_card" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+    </ScrollView>
+</layout>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_test_for_a_p_i.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_for_a_p_i.xml
similarity index 100%
rename from Corona-Warn-App/src/main/res/layout/fragment_test_for_a_p_i.xml
rename to Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_for_a_p_i.xml
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_test_risk_level_calculation.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_risk_level_calculation.xml
similarity index 100%
rename from Corona-Warn-App/src/main/res/layout/fragment_test_risk_level_calculation.xml
rename to Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_risk_level_calculation.xml
diff --git a/Corona-Warn-App/src/deviceForTesters/res/menu/menu_main.xml b/Corona-Warn-App/src/deviceForTesters/res/menu/menu_main.xml
new file mode 100644
index 000000000..95688307e
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/res/menu/menu_main.xml
@@ -0,0 +1,18 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/menu_help"
+        android:title="@string/menu_help" />
+    <item
+        android:id="@+id/menu_information"
+        android:title="@string/menu_information" />
+    <item
+        android:id="@+id/menu_settings"
+        android:title="@string/menu_settings" />
+    <!-- Todo throwaway code only for testing -->
+    <item
+        android:id="@+id/menu_test_api"
+        android:title="@string/menu_test_api" />
+    <item
+        android:id="@+id/menu_test_risk_level"
+        android:title="@string/menu_test_risk_level" />
+</menu>
diff --git a/Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml b/Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml
new file mode 100644
index 000000000..178330347
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml
@@ -0,0 +1,303 @@
+<?xml version="1.0" encoding="utf-8"?>
+<navigation 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:id="@+id/nav_graph"
+    app:startDestination="@id/mainFragment">
+
+    <!-- Main -->
+    <fragment
+        android:id="@+id/mainFragment"
+        android:name="de.rki.coronawarnapp.ui.main.MainFragment"
+        android:label="MainFragment"
+        tools:layout="@layout/fragment_main">
+        <action
+            android:id="@+id/action_mainFragment_to_settingsTracingFragment"
+            app:destination="@id/settingsTracingFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_riskDetailsFragment"
+            app:destination="@id/riskDetailsFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_settingsFragment"
+            app:destination="@id/settingsFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_testForAPIFragment"
+            app:destination="@id/testForAPIFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_informationFragment"
+            app:destination="@id/informationFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_mainSharingFragment"
+            app:destination="@id/mainSharingFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_submissionIntroFragment"
+            app:destination="@id/submissionIntroFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_submissionResultFragment"
+            app:destination="@id/submissionResultFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_submissionDoneFragment"
+            app:destination="@id/submissionDoneFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_mainOverviewFragment"
+            app:destination="@id/mainOverviewFragment" />
+        <action
+            android:id="@+id/action_mainFragment_to_testRiskLevelCalculation"
+            app:destination="@id/testRiskLevelCalculation" />
+    </fragment>
+
+    <fragment
+        android:id="@+id/mainSharingFragment"
+        android:name="de.rki.coronawarnapp.ui.main.MainShareFragment"
+        android:label="@layout/fragment_main_share"
+        tools:layout="@layout/fragment_main_share" />
+
+    <fragment
+        android:id="@+id/mainOverviewFragment"
+        android:name="de.rki.coronawarnapp.ui.main.MainOverviewFragment"
+        android:label="@layout/fragment_main_overview"
+        tools:layout="@layout/fragment_main_overview" />
+
+    <!-- Settings -->
+    <fragment
+        android:id="@+id/settingsFragment"
+        android:name="de.rki.coronawarnapp.ui.settings.SettingsFragment"
+        android:label="@layout/fragment_settings"
+        tools:layout="@layout/fragment_settings">
+        <action
+            android:id="@+id/action_settingsFragment_to_settingsResetFragment"
+            app:destination="@id/settingsResetFragment" />
+        <action
+            android:id="@+id/action_settingsFragment_to_settingsTracingFragment"
+            app:destination="@id/settingsTracingFragment" />
+        <action
+            android:id="@+id/action_settingsFragment_self"
+            app:destination="@id/settingsFragment" />
+        <action
+            android:id="@+id/action_settingsFragment_to_settingsNotificationFragment"
+            app:destination="@id/settingsNotificationFragment" />
+    </fragment>
+
+    <fragment
+        android:id="@+id/settingsTracingFragment"
+        android:name="de.rki.coronawarnapp.ui.settings.SettingsTracingFragment"
+        android:label="@layout/fragment_settings_tracing"
+        tools:layout="@layout/fragment_settings_tracing" />
+
+    <fragment
+        android:id="@+id/settingsNotificationFragment"
+        android:name="de.rki.coronawarnapp.ui.settings.SettingsNotificationFragment"
+        android:label="SettingsNotificationFragment"
+        tools:layout="@layout/fragment_settings_notifications" />
+
+    <fragment
+        android:id="@+id/settingsResetFragment"
+        android:name="de.rki.coronawarnapp.ui.settings.SettingsResetFragment"
+        android:label="@layout/fragment_settings_reset"
+        tools:layout="@layout/fragment_settings_reset">
+        <action
+            android:id="@+id/action_settingsResetFragment_to_mainFragment"
+            app:destination="@id/mainFragment" />
+    </fragment>
+
+    <!-- Information -->
+    <fragment
+        android:id="@+id/informationFragment"
+        android:name="de.rki.coronawarnapp.ui.information.InformationFragment"
+        android:label="@layout/fragment_information"
+        tools:layout="@layout/fragment_information">
+        <action
+            android:id="@+id/action_informationFragment_to_informationLegalFragment"
+            app:destination="@id/informationLegalFragment" />
+        <action
+            android:id="@+id/action_informationFragment_to_informationTermsFragment"
+            app:destination="@id/informationTermsFragment" />
+        <action
+            android:id="@+id/action_informationFragment_to_informationPrivacyFragment"
+            app:destination="@id/informationPrivacyFragment" />
+        <action
+            android:id="@+id/action_informationFragment_to_informationAboutFragment"
+            app:destination="@id/informationAboutFragment" />
+        <action
+            android:id="@+id/action_informationFragment_to_informationContactFragment"
+            app:destination="@id/informationContactFragment" />
+        <action
+            android:id="@+id/action_informationFragment_to_informationTechnicalFragment"
+            app:destination="@id/informationTechnicalFragment" />
+    </fragment>
+
+    <fragment
+        android:id="@+id/informationAboutFragment"
+        android:name="de.rki.coronawarnapp.ui.information.InformationAboutFragment"
+        android:label="@layout/fragment_information_about"
+        tools:layout="@layout/fragment_information_about" />
+
+    <fragment
+        android:id="@+id/informationPrivacyFragment"
+        android:name="de.rki.coronawarnapp.ui.information.InformationPrivacyFragment"
+        android:label="@layout/fragment_information_privacy"
+        tools:layout="@layout/fragment_information_privacy" />
+
+    <fragment
+        android:id="@+id/informationTermsFragment"
+        android:name="de.rki.coronawarnapp.ui.information.InformationTermsFragment"
+        android:label="@layout/fragment_information_terms"
+        tools:layout="@layout/fragment_information_terms" />
+
+    <fragment
+        android:id="@+id/informationContactFragment"
+        android:name="de.rki.coronawarnapp.ui.information.InformationContactFragment"
+        android:label="@layout/fragment_information_contact"
+        tools:layout="@layout/fragment_information_contact" />
+
+    <fragment
+        android:id="@+id/informationLegalFragment"
+        android:name="de.rki.coronawarnapp.ui.information.InformationLegalFragment"
+        android:label="@layout/fragment_information_legal"
+        tools:layout="@layout/fragment_information_legal" />
+
+    <fragment
+        android:id="@+id/informationTechnicalFragment"
+        android:name="de.rki.coronawarnapp.ui.information.InformationTechnicalFragment"
+        android:label="InformationTechnicalFragment"
+        tools:layout="@layout/fragment_information_technical" />
+
+    <!-- Submission -->
+    <fragment
+        android:id="@+id/testForAPIFragment"
+        android:name="de.rki.coronawarnapp.TestForAPIFragment"
+        android:label="@layout/fragment_test_for_a_p_i"
+        tools:layout="@layout/fragment_test_for_a_p_i" />
+
+    <fragment
+        android:id="@+id/riskDetailsFragment"
+        android:name="de.rki.coronawarnapp.ui.riskdetails.RiskDetailsFragment"
+        android:label="@layout/fragment_risk_details"
+        tools:layout="@layout/fragment_risk_details">
+        <action
+            android:id="@+id/action_riskDetailsFragment_to_settingsTracingFragment"
+            app:destination="@id/settingsTracingFragment" />
+    </fragment>
+
+    <fragment
+        android:id="@+id/submissionDispatcherFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionDispatcherFragment"
+        android:label="fragment_submission_dispatcher"
+        tools:layout="@layout/fragment_submission_dispatcher">
+        <action
+            android:id="@+id/action_submissionDispatcherFragment_to_submissionTanFragment"
+            app:destination="@id/submissionTanFragment" />
+        <action
+            android:id="@+id/action_submissionDispatcherFragment_to_submissionQRCodeScanFragment"
+            app:destination="@id/submissionQRCodeScanFragment" />
+        <action
+            android:id="@+id/action_submissionDispatcherFragment_to_submissionContactFragment"
+            app:destination="@id/submissionContactFragment" />
+    </fragment>
+    <fragment
+        android:id="@+id/submissionResultPositiveOtherWarningFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionResultPositiveOtherWarningFragment"
+        android:label="fragment_submission_result_positive_other_warning"
+        tools:layout="@layout/fragment_submission_positive_other_warning">
+        <action
+            android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionResultFragment"
+            app:destination="@id/submissionResultFragment"
+            app:popUpTo="@id/submissionResultFragment"
+            app:popUpToInclusive="true" />
+        <action
+            android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionDoneFragment"
+            app:destination="@id/submissionDoneFragment"
+            app:popUpTo="@id/submissionDoneFragment"
+            app:popUpToInclusive="true" />
+    </fragment>
+    <fragment
+        android:id="@+id/submissionResultFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionTestResultFragment"
+        android:label="fragment_submission_result"
+        tools:layout="@layout/fragment_submission_test_result">
+        <action
+            android:id="@+id/action_submissionResultFragment_to_mainFragment"
+            app:destination="@id/mainFragment"
+            app:popUpTo="@id/mainFragment"
+            app:popUpToInclusive="true" />
+        <action
+            android:id="@+id/action_submissionResultFragment_to_submissionResultPositiveOtherWarningFragment"
+            app:destination="@id/submissionResultPositiveOtherWarningFragment" />
+    </fragment>
+
+    <fragment
+        android:id="@+id/submissionTanFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionTanFragment"
+        android:label="fragment_submission_tan"
+        tools:layout="@layout/fragment_submission_tan">
+        <action
+            android:id="@+id/action_submissionTanFragment_to_submissionDispatcherFragment"
+            app:destination="@id/submissionDispatcherFragment"
+            app:popUpTo="@id/submissionDispatcherFragment"
+            app:popUpToInclusive="true" />
+        <action
+            android:id="@+id/action_submissionTanFragment_to_submissionResultFragment"
+            app:destination="@id/submissionResultFragment"
+            app:popUpTo="@id/submissionResultFragment"
+            app:popUpToInclusive="true" />
+    </fragment>
+
+    <fragment
+        android:id="@+id/submissionIntroFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionIntroFragment"
+        android:label="SubmissionIntroFragment">
+        <action
+            android:id="@+id/action_submissionIntroFragment_to_mainFragment"
+            app:destination="@id/mainFragment"
+            app:popUpTo="@+id/mainFragment"
+            app:popUpToInclusive="true" />
+        <action
+            android:id="@+id/action_submissionIntroFragment_to_submissionDispatcherFragment"
+            app:destination="@id/submissionDispatcherFragment" />
+    </fragment>
+    <activity
+        android:id="@+id/launcherActivity"
+        android:name="de.rki.coronawarnapp.ui.LauncherActivity"
+        android:label="LauncherActivity">
+        <deepLink
+            android:id="@+id/deepLink"
+            app:uri="coronawarnapp://launch" />
+    </activity>
+    <fragment
+        android:id="@+id/submissionQRCodeScanFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionQRCodeScanFragment"
+        android:label="SubmissionQRCodeScanFragment">
+        <action
+            android:id="@+id/action_submissionQRCodeScanFragment_to_submissionDispatcherFragment"
+            app:destination="@id/submissionDispatcherFragment"
+            app:popUpTo="@id/submissionDispatcherFragment"
+            app:popUpToInclusive="true" />
+        <action
+            android:id="@+id/action_submissionQRCodeScanFragment_to_submissionResultFragment"
+            app:destination="@id/submissionResultFragment"
+            app:popUpTo="@id/submissionResultFragment" />
+    </fragment>
+    <fragment
+        android:id="@+id/submissionDoneFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionDoneFragment"
+        android:label="SubmissionDoneFragment">
+        <action
+            android:id="@+id/action_submissionDoneFragment_to_mainFragment"
+            app:destination="@id/mainFragment"
+            app:popUpTo="@id/mainFragment"
+            app:popUpToInclusive="true" />
+    </fragment>
+    <fragment
+        android:id="@+id/submissionContactFragment"
+        android:name="de.rki.coronawarnapp.ui.submission.SubmissionContactFragment"
+        android:label="SubmissionContactFragment">
+        <action
+            android:id="@+id/action_submissionContactFragment_to_submissionTanFragment"
+            app:destination="@id/submissionTanFragment" />
+    </fragment>
+    <fragment
+        android:id="@+id/testRiskLevelCalculation"
+        android:name="de.rki.coronawarnapp.TestRiskLevelCalculation"
+        android:label="fragment_test_risk_level_calculation"
+        tools:layout="@layout/fragment_test_risk_level_calculation" />
+</navigation>
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt
index b22f24191..efa21ac87 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt
@@ -3,7 +3,6 @@ package de.rki.coronawarnapp.nearby
 import com.google.android.gms.nearby.Nearby
 import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
 import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration.ExposureConfigurationBuilder
-import com.google.android.gms.nearby.exposurenotification.ExposureInformation
 import com.google.android.gms.nearby.exposurenotification.ExposureSummary
 import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
 import de.rki.coronawarnapp.CoronaWarnApplication
@@ -161,15 +160,4 @@ object InternalExposureNotificationClient {
                     cont.resumeWithException(it)
                 }
         }
-
-    // todo remove before release - not used in prod setup - only for testing
-    suspend fun asyncGetExposureInformation(token: String): List<ExposureInformation> =
-        suspendCoroutine { cont ->
-            exposureNotificationClient.getExposureInformation(token)
-                .addOnSuccessListener {
-                    cont.resume(it)
-                }.addOnFailureListener {
-                    cont.resumeWithException(it)
-                }
-        }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
index 966f104dc..c94cc8347 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
@@ -1,8 +1,6 @@
 package de.rki.coronawarnapp.storage
 
-import android.widget.Toast
 import androidx.lifecycle.MutableLiveData
-import de.rki.coronawarnapp.CoronaWarnApplication
 import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
@@ -54,12 +52,6 @@ object TracingRepository {
         try {
             RetrieveDiagnosisKeysTransaction.start()
             RiskLevelTransaction.start()
-            // TODO remove after testing
-            Toast.makeText(
-                CoronaWarnApplication.getAppContext(),
-                "transaction completed",
-                Toast.LENGTH_SHORT
-            ).show()
         } catch (e: Exception) {
             e.report(ExceptionCategory.EXPOSURENOTIFICATION)
         }
@@ -91,7 +83,7 @@ object TracingRepository {
     /**
      * Refresh the activeTracingDaysInRetentionPeriod calculation.
      *
-     * @see TimeVariables
+     * @see de.rki.coronawarnapp.risk.TimeVariables
      */
     suspend fun refreshActiveTracingDaysInRetentionPeriod() {
         activeTracingDaysInRetentionPeriod.postValue(getActiveTracingDaysInRetentionPeriod())
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt
index 076cfe228..e0043fa81 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt
@@ -1,11 +1,9 @@
 package de.rki.coronawarnapp.transaction
 
 import androidx.core.app.NotificationCompat
-import androidx.lifecycle.MutableLiveData
 import com.google.android.gms.nearby.exposurenotification.ExposureSummary
 import de.rki.coronawarnapp.CoronaWarnApplication
 import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.TestRiskLevelCalculation
 import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.NoNetworkException
 import de.rki.coronawarnapp.exception.RiskLevelCalculationException
@@ -170,17 +168,6 @@ object RiskLevelTransaction : Transaction() {
         CLOSE
     }
 
-    /** TESTING ONLY
-     *
-     * TODO remove asap, only used to display the used values for risk level calculation
-     */
-
-    val tempExposedTransactionValuesForTestingOnly =
-        MutableLiveData<TestRiskLevelCalculation.TransactionValues>()
-
-    var recordedTransactionValuesForTestingOnly =
-        TestRiskLevelCalculation.TransactionValues()
-
     /** atomic reference for the rollback value for the last calculated risk level score */
     private val lastCalculatedRiskLevelScoreForRollback = AtomicReference<RiskLevel>()
 
@@ -358,9 +345,7 @@ object RiskLevelTransaction : Transaction() {
         executeState(RETRIEVE_APPLICATION_CONFIG) {
             return@executeState getApplicationConfiguration()
                 .also {
-                    // todo remove after testing sessions
-                    recordedTransactionValuesForTestingOnly.appConfig = it
-                    Timber.v("$transactionId - retrieved configuration from backend")
+                    Timber.v(TAG, "$transactionId - retrieved configuration from backend")
                 }
         }
 
@@ -372,9 +357,7 @@ object RiskLevelTransaction : Transaction() {
             val lastExposureSummary = getLastExposureSummary() ?: getNewExposureSummary()
 
             return@executeState lastExposureSummary.also {
-                // todo remove after testing sessions
-                recordedTransactionValuesForTestingOnly.exposureSummary = it
-                Timber.v("$transactionId - get the exposure summary for further calculation")
+                Timber.v(TAG, "$transactionId - get the exposure summary for further calculation")
             }
         }
 
@@ -397,9 +380,7 @@ object RiskLevelTransaction : Transaction() {
                 attenuationParameters,
                 exposureSummary
             ).also {
-                // todo remove after testing sessions
-                recordedTransactionValuesForTestingOnly.riskScore = it
-                Timber.v("calculated risk with the given config: $it")
+                Timber.v(TAG, "calculated risk with the given config: $it")
             }
 
             // these are the defined risk classes. They will divide the calculated
@@ -448,13 +429,6 @@ object RiskLevelTransaction : Transaction() {
         executeState(UPDATE_RISK_LEVEL) {
             Timber.v("$transactionId - update the risk level with $riskLevel")
             updateRiskLevelScore(riskLevel)
-                .also {
-                    // todo remove after testing sessions
-                    recordedTransactionValuesForTestingOnly.riskLevel = riskLevel
-                    tempExposedTransactionValuesForTestingOnly.postValue(
-                        recordedTransactionValuesForTestingOnly
-                    )
-                }
         }
 
     /**
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt
index a0f6f4b3b..88c3d33e8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt
@@ -5,7 +5,6 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import android.widget.Toast
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.lifecycleScope
 import com.google.android.gms.common.api.ApiException
@@ -75,11 +74,6 @@ class SettingsResetFragment : Fragment() {
                 apiException.report(
                     ExceptionCategory.EXPOSURENOTIFICATION, TAG, null
                 )
-                Toast.makeText(
-                    this@SettingsResetFragment.context,
-                    "Could not stop tracing. ${apiException.localizedMessage}",
-                    Toast.LENGTH_LONG
-                ).show()
             }
             withContext(Dispatchers.IO) {
                 deleteLocalAppContent()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt
index 72cb7f518..a1842b998 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt
@@ -5,7 +5,6 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import android.widget.Toast
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
 import androidx.lifecycle.lifecycleScope
@@ -85,18 +84,11 @@ class SettingsTracingFragment : Fragment(),
     override fun onStartPermissionGranted() {
         tracingViewModel.refreshIsTracingEnabled()
         BackgroundWorkScheduler.startWorkScheduler()
-        Toast.makeText(requireContext(), "Tracing started successfully", Toast.LENGTH_SHORT).show()
     }
 
     override fun onFailure(exception: Exception?) {
         tracingViewModel.refreshIsTracingEnabled()
         exception?.report(ExceptionCategory.EXPOSURENOTIFICATION)
-        // TODO
-        Toast.makeText(
-            requireContext(),
-            exception?.localizedMessage ?: "Unknown Error",
-            Toast.LENGTH_SHORT
-        ).show()
     }
 
     private fun setButtonOnClickListener() {
@@ -127,13 +119,6 @@ class SettingsTracingFragment : Fragment(),
         lifecycleScope.launch {
             try {
                 if (InternalExposureNotificationClient.asyncIsEnabled()) {
-                    Toast.makeText(
-                        requireContext(),
-                        "Tracing stopped successfully",
-                        Toast.LENGTH_SHORT
-                    )
-                        .show()
-
                     InternalExposureNotificationClient.asyncStop()
                     tracingViewModel.refreshIsTracingEnabled()
                     BackgroundWorkScheduler.stopWorkScheduler()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt
index 78a5bb2d0..883d0d03e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt
@@ -19,6 +19,7 @@
 
 package de.rki.coronawarnapp.util
 
+import de.rki.coronawarnapp.BuildConfig
 import de.rki.coronawarnapp.CoronaWarnApplication
 import de.rki.coronawarnapp.http.WebRequestBuilder
 import de.rki.coronawarnapp.service.diagnosiskey.DiagnosisKeyConstants
@@ -68,7 +69,7 @@ object CachedKeyFileHolder {
     suspend fun asyncFetchFiles(currentDate: Date): List<File> = withContext(Dispatchers.IO) {
         val serverDates = getDatesFromServer()
         // TODO remove last3HourFetch before Release
-        if (isLast3HourFetchEnabled()) {
+        if (BuildConfig.FLAVOR != "device" && isLast3HourFetchEnabled()) {
             Timber.v("Last 3 Hours will be Fetched. Only use for Debugging!")
             val currentDateServerFormat = currentDate.toServerFormat()
             // just fetch the hours if the date is available
diff --git a/Corona-Warn-App/src/main/res/menu/menu_main.xml b/Corona-Warn-App/src/main/res/menu/menu_main.xml
index 35ebff47b..73c8756d9 100644
--- a/Corona-Warn-App/src/main/res/menu/menu_main.xml
+++ b/Corona-Warn-App/src/main/res/menu/menu_main.xml
@@ -8,14 +8,4 @@
     <item
         android:id="@+id/menu_settings"
         android:title="@string/menu_settings" />
-    <!-- Todo throwaway code only for testing -->
-    <item
-        android:id="@+id/menu_test_api"
-        android:title="@string/menu_test_api" />
-    <item
-        android:id="@+id/menu_test_risk_level"
-        android:title="@string/menu_test_risk_level" />
-    <item
-        android:id="@+id/menu_notification_test"
-        android:title="@string/menu_test_notification" />
 </menu>
diff --git a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml
index 2c77e7881..da14ba42c 100644
--- a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml
+++ b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml
@@ -20,9 +20,6 @@
         <action
             android:id="@+id/action_mainFragment_to_settingsFragment"
             app:destination="@id/settingsFragment" />
-        <action
-            android:id="@+id/action_mainFragment_to_testForAPIFragment"
-            app:destination="@id/testForAPIFragment" />
         <action
             android:id="@+id/action_mainFragment_to_informationFragment"
             app:destination="@id/informationFragment" />
@@ -163,12 +160,6 @@
         tools:layout="@layout/fragment_information_technical" />
 
     <!-- Submission -->
-    <fragment
-        android:id="@+id/testForAPIFragment"
-        android:name="de.rki.coronawarnapp.TestForAPIFragment"
-        android:label="@layout/fragment_test_for_a_p_i"
-        tools:layout="@layout/fragment_test_for_a_p_i" />
-
     <fragment
         android:id="@+id/riskDetailsFragment"
         android:name="de.rki.coronawarnapp.ui.riskdetails.RiskDetailsFragment"
diff --git a/build.gradle b/build.gradle
index 4f313e7af..785ef6608 100644
--- a/build.gradle
+++ b/build.gradle
@@ -79,6 +79,14 @@ task quickBuild {
     dependsOn ':Corona-Warn-App:detekt'
 }
 
+task quickBuildTest {
+    dependsOn ':Corona-Warn-App:assembleDeviceForTestersRelease'
+    dependsOn ':Corona-Warn-App:testDeviceForTestersReleaseUnitTest'
+    dependsOn ':Corona-Warn-App:lintDeviceForTestersRelease'
+    dependsOn ':Corona-Warn-App:ktlintDeviceForTestersReleaseCheck'
+    dependsOn ':Corona-Warn-App:detekt'
+}
+
 task quickBuildWithFixes {
     dependsOn ':Corona-Warn-App:assembleDeviceRelease'
     dependsOn ':Corona-Warn-App:testDeviceReleaseUnitTest'
-- 
GitLab