diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/RiskLevelAndKeyRetrievalBenchmark.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/RiskLevelAndKeyRetrievalBenchmark.kt
deleted file mode 100644
index 6771827fa9cab7f2cc67ea55cdb6a0c537a6f3ec..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/RiskLevelAndKeyRetrievalBenchmark.kt
+++ /dev/null
@@ -1,163 +0,0 @@
-package de.rki.coronawarnapp.test
-
-import android.content.Context
-import android.text.format.Formatter
-import de.rki.coronawarnapp.diagnosiskeys.download.DownloadDiagnosisKeysTask
-import de.rki.coronawarnapp.diagnosiskeys.download.DownloadDiagnosisKeysTask.Progress.ApiSubmissionFinished
-import de.rki.coronawarnapp.diagnosiskeys.download.DownloadDiagnosisKeysTask.Progress.ApiSubmissionStarted
-import de.rki.coronawarnapp.diagnosiskeys.download.DownloadDiagnosisKeysTask.Progress.KeyFilesDownloadFinished
-import de.rki.coronawarnapp.diagnosiskeys.download.DownloadDiagnosisKeysTask.Progress.KeyFilesDownloadStarted
-import de.rki.coronawarnapp.risk.RiskLevelTask
-import de.rki.coronawarnapp.task.Task
-import de.rki.coronawarnapp.task.common.DefaultTaskRequest
-import de.rki.coronawarnapp.task.submitAndListen
-import de.rki.coronawarnapp.util.di.AppInjector
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.flow.map
-import timber.log.Timber
-import java.util.UUID
-
-class RiskLevelAndKeyRetrievalBenchmark(
-    private val context: Context,
-    private val countries: List<String>
-) {
-
-    /**
-     * the key cache instance used to store queried dates and hours
-     */
-    private val keyCache = AppInjector.component.keyCacheRepository
-
-    /**
-     * Calls the RetrieveDiagnosisKeysTransaction and RiskLevelTransaction and measures them.
-     * Results are displayed using a label
-     * @param callCount defines how often the transactions should be called (each call will be
-     * measured separately)
-     */
-    suspend fun start(
-        callCount: Int,
-        onBenchmarkCompletedListener: OnBenchmarkCompletedListener
-    ) {
-
-        var resultInfo = StringBuilder()
-            .append(
-                "MEASUREMENT Running for Countries:\n " +
-                    "${countries.joinToString(", ")}\n\n"
-            )
-            .append("Result: \n\n")
-            .append("#\t Combined \t Download \t Sub \t Risk \t File # \t  F. size\n")
-
-        onBenchmarkCompletedListener(resultInfo.toString())
-
-        repeat(callCount) { index ->
-
-            keyCache.clear()
-
-            var keyRetrievalError = ""
-            var keyFileCount: Int = -1
-            var keyFileDownloadDuration: Long = -1
-            var keyFilesSize: Long = -1
-            var apiSubmissionDuration: Long = -1
-
-            measureDiagnosticKeyRetrieval(
-                label = "#$index",
-                countries = countries,
-                downloadFinished = { duration, keyCount, totalFileSize ->
-                    keyFileCount = keyCount
-                    keyFileDownloadDuration = duration
-                    keyFilesSize = totalFileSize
-                }, apiSubmissionFinished = { duration ->
-                    apiSubmissionDuration = duration
-                })
-
-            var calculationDuration: Long = -1
-            var calculationError = ""
-
-            measureKeyCalculation("#$index") {
-                if (it != null) calculationDuration = it
-
-                // build result entry for current iteration with all gathered data
-                resultInfo.append(
-                    "${index + 1}. \t ${calculationDuration + keyFileDownloadDuration + apiSubmissionDuration} ms \t " +
-                        "$keyFileDownloadDuration ms " + "\t $apiSubmissionDuration ms" +
-                        "\t $calculationDuration ms \t $keyFileCount \t " +
-                        "${Formatter.formatFileSize(context, keyFilesSize)}\n"
-                )
-
-                if (keyRetrievalError.isNotEmpty()) {
-                    resultInfo.append("Key Retrieval Error: $keyRetrievalError\n")
-                }
-
-                if (calculationError.isNotEmpty()) {
-                    resultInfo.append("Calculation Error: $calculationError\n")
-                }
-
-                onBenchmarkCompletedListener(resultInfo.toString())
-            }
-        }
-    }
-
-    private suspend fun measureKeyCalculation(label: String, callback: (Long?) -> Unit) {
-        val uuid = UUID.randomUUID()
-        val t0 = System.currentTimeMillis()
-        AppInjector.component.taskController.tasks
-            .map {
-                it
-                    .map { taskInfo -> taskInfo.taskState }
-                    .filter { taskState -> taskState.request.id == uuid && taskState.isFinished }
-            }
-            .collect {
-                it.firstOrNull()?.also { state ->
-                    Timber.v("MEASURE [Risk Level Calculation] $label finished")
-                    callback.invoke(
-                        if (state.error != null)
-                            null
-                        else
-                            System.currentTimeMillis() - t0
-                    )
-                }
-            }
-        Timber.v("MEASURE [Risk Level Calculation] $label started")
-        AppInjector.component.taskController.submit(
-            DefaultTaskRequest(
-                RiskLevelTask::class,
-                object : Task.Arguments {},
-                uuid
-            )
-        )
-    }
-
-    private suspend fun measureDiagnosticKeyRetrieval(
-        label: String,
-        countries: List<String>,
-        downloadFinished: (duration: Long, keyCount: Int, fileSize: Long) -> Unit,
-        apiSubmissionFinished: (duration: Long) -> Unit
-    ) {
-        var keyFileDownloadStart: Long = -1
-        var apiSubmissionStarted: Long = -1
-
-        AppInjector.component.taskController.submitAndListen(
-            DefaultTaskRequest(DownloadDiagnosisKeysTask::class, DownloadDiagnosisKeysTask.Arguments(countries))
-        ).collect { progress: Task.Progress ->
-            when (progress) {
-                is KeyFilesDownloadStarted -> {
-                    Timber.v("MEASURE [Diagnostic Key Files] $label started")
-                    keyFileDownloadStart = System.currentTimeMillis()
-                }
-                is KeyFilesDownloadFinished -> {
-                    Timber.v("MEASURE [Diagnostic Key Files] $label finished")
-                    val duration = System.currentTimeMillis() - keyFileDownloadStart
-                    downloadFinished(duration, progress.keyCount, progress.fileSize)
-                }
-                is ApiSubmissionStarted -> {
-                    apiSubmissionStarted = System.currentTimeMillis()
-                }
-                is ApiSubmissionFinished -> {
-                    val duration = System.currentTimeMillis() - apiSubmissionStarted
-                    apiSubmissionFinished(duration)
-                }
-            }
-        }
-    }
-}
-
-typealias OnBenchmarkCompletedListener = (resultInfo: String) -> Unit
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt
index f2ebfd26e4c413d2b3c80cb8cce605669310ee03..d277c9b961d19aa3ab2eba3c8eb262c0fe71fe51 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt
@@ -18,7 +18,7 @@ class TestForApiFragmentViewModel @AssistedInject constructor(
 ) : CWAViewModel() {
 
     fun calculateRiskLevelClicked() {
-        taskController.submit(DefaultTaskRequest(RiskLevelTask::class))
+        taskController.submit(DefaultTaskRequest(RiskLevelTask::class, originTag = "TestForApiFragmentViewModel"))
     }
 
     val gmsState by smartLiveData {
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt
index f521a36ac7ad1e978682fbd77bd24f0f63b8606a..8d3d50bef73f1b4ed81fd3287f76d39bdd889ee5 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt
@@ -80,14 +80,23 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
     fun retrieveDiagnosisKeys() {
         launch {
             taskController.submitBlocking(
-                DefaultTaskRequest(DownloadDiagnosisKeysTask::class, DownloadDiagnosisKeysTask.Arguments())
+                DefaultTaskRequest(
+                    DownloadDiagnosisKeysTask::class,
+                    DownloadDiagnosisKeysTask.Arguments(),
+                    originTag = "TestRiskLevelCalculationFragmentCWAViewModel.retrieveDiagnosisKeys()"
+                )
             )
             calculateRiskLevel()
         }
     }
 
     fun calculateRiskLevel() {
-        taskController.submit(DefaultTaskRequest(RiskLevelTask::class))
+        taskController.submit(
+            DefaultTaskRequest(
+                RiskLevelTask::class,
+                originTag = "TestRiskLevelCalculationFragmentCWAViewModel.calculateRiskLevel()"
+            )
+        )
     }
 
     fun resetRiskLevel() {
diff --git a/Corona-Warn-App/src/main/assets/privacy_de.html b/Corona-Warn-App/src/main/assets/privacy_de.html
index 8bea0c0161487c05071636b59b12f45a01908d3c..eb3a024ed1a780760397c4a5df80ed208e0e8b42 100644
--- a/Corona-Warn-App/src/main/assets/privacy_de.html
+++ b/Corona-Warn-App/src/main/assets/privacy_de.html
@@ -1,10 +1,6 @@
 <p>
     Datenschutzerklärung
 </p>
-<p>
-    Stand: 15.11.2020, Version 1.8 (frühere Versionen abrufbar unter:
-    https://www.coronawarn.app/de/privacy)
-</p>
 <p>
     In dieser Datenschutzerklärung erfahren Sie, wie Ihre Daten verarbeitet
     werden und welche Datenschutzrechte Sie haben, wenn Sie die offizielle
@@ -463,8 +459,8 @@
     d. Informatorische Nutzung der App
 </h2>
 <p>
-    <u>Die täglichen Statistiken, die in der App erscheinen, erhält die App 
-    automatisch über das Serversystem. Dabei fallen Zugriffsdaten an.</u>
+    Die täglichen Statistiken, die in der App erscheinen, erhält die App 
+    automatisch über das Serversystem. Dabei fallen Zugriffsdaten an.
     In der App verlinkte Webseiten, z. B.: www.bundesregierung.de, werden im
     Standard-Browser (Android-Smartphones) oder in der App (iPhones) geöffnet und angezeigt.
     Welche Daten dabei verarbeitet werden, wird von den jeweiligen Anbietern der aufgerufenen Webseite festgelegt.
@@ -795,3 +791,6 @@
     Datenschutzbeauftragten, Nordufer 20, 13353 Berlin oder per E-Mail an:
     datenschutz@rki.de.
 </p>
+<p>
+    Stand: 15.11.2020
+</p>
diff --git a/Corona-Warn-App/src/main/assets/privacy_en.html b/Corona-Warn-App/src/main/assets/privacy_en.html
index e6914d659fecbe82976e73750595d7c945c5e6ac..411f8c5accb2a0ed0ad356308fcdea5d8ac0d5ec 100644
--- a/Corona-Warn-App/src/main/assets/privacy_en.html
+++ b/Corona-Warn-App/src/main/assets/privacy_en.html
@@ -1,9 +1,7 @@
 <p>
     Privacy notice
 </p>
-<p>
-    Last amended: 15 November 2020. Valid from app version 1.8 (earlier versions available at: https://www.coronawarn.app/en/privacy) 
-</p>
+
 <p>
     This privacy notice explains how your data is processed and what data
     protection rights you have when using the German Federal Government’s
@@ -767,5 +765,5 @@
     13353 Berlin, or by emailing datenschutz@rki.de.
 </p>
 <p>
-    ***
+    Last amended: 15 November 2020 
 </p>
diff --git a/Corona-Warn-App/src/main/assets/privacy_tr.html b/Corona-Warn-App/src/main/assets/privacy_tr.html
index 55243e394d5031feef9b974a735dce3ed2b231d2..cebbc84a12a3faf296ba8a5961597b2705c86aa7 100644
--- a/Corona-Warn-App/src/main/assets/privacy_tr.html
+++ b/Corona-Warn-App/src/main/assets/privacy_tr.html
@@ -79,22 +79,25 @@
 <p>
     Uygulamanın kullanımı isteğe bağlıdır; Uygulamayı yüklemeniz, Uygulamanın
     hangi işlevlerini kullanmanız ve verileri diğer kişilerle paylaşmanız
-    noktasında yalnızca siz karar verirsiniz. Uygulamanın veri aktarımını
-    gerektiren tüm işlevleri, öncesinde sizin açık bir şekilde onay vermenizi
-    ister. Onay vermezseniz veya sonradan bu onayı geri alırsanız, bu durum
-    sizin için bir sakınca doğurmaz.
+    noktasında yalnızca siz karar verirsiniz. Maruz kalma veya sağlık verilerinizin 
+    aktarılmasını gerektiren Uygulamanın tüm işlevleri, sizden önceden açıkça rızanızı 
+    vermenizi gerektirir. Rızanızı vermezseniz veya sonradan bu rızayı geri alırsanız, 
+    bu durum sizin için bir sakınca doğurmaz.
 </p>
 <h1>
     3. Verileriniz işlenmesinde hangi yasal dayanaklar söz konusudur?
     
 </h1>
 <p>
-    Verileriniz esas itibariyle yalnızca açık bir şekilde verdiğiniz onay
+    Verileriniz esas itibariyle açık bir şekilde verdiğiniz onay
     temelinde iÅŸlenir. Bu baÄŸlamdaki yasal dayanak, GVKT (Genel Veri Koruma
     Tüzüğü) madde 6, fıkra 1, cümle 1, bent a ve sağlık verileri durumundaki
     yasal dayanak ise GVKT madde 9, fıkra 2, bent a’dır. Verdiğiniz onayı,
     istediğiniz zaman geri alabilirsiniz. Onayınız geri alma hakkı ile ilgili
-    ayrıntılı bilgileri madde 12’de bulabilirsiniz.
+    ayrıntılı bilgileri madde 12’de bulabilirsiniz. Günlük istatistiklerin alınması 
+    için erişim verilerinin işlenmesi (bkz. Madde 6 d.), GVKT madde 6, fıkra 1, cümle 1, bent 
+    e ile bağlantılı olarak BGA-NachfG (Federal Sağlık Kurumu Halef Kuruluşları 
+    hakkında Kanun) madde 4, fıkra 4 uyarınca RKI tarafından toplumun bilgilendirilmesi kapsamında gerçekleşir.
 </p>
 <h1>
     4. Uygulama kimleri hedefler?
@@ -271,14 +274,13 @@
     bilgileri temin etmektir.
 </p>
 <p>
-    Bu amaç için Uygulama, arka planda çalışarak sunucu sisteminden, Korona
-    testi pozitif çıkan ve sınır ötesi uyarı sistemine katılan ülkelerin resmi
-    Korona uygulamaları aracılığıyla gönüllü olarak bir uyarı tetikleyen
-    kullanıcılardan rastgele kimlik numaraları ve varsa semptomların
-    başlangıcına ilişkin bilgiyi içeren günlük bir liste çağırır (bundan böyle: <strong>pozitif
-    liste</strong>). Pozitif listedeki rastgele kimlik
-    numaraları, ek olarak ayrıca bir taşıma riski değeri ve tanı tipi hakkında
-    bilgi de içerir (bkz. Madde 6 c.).
+    Bu amaç doğrultusunda Uygulama, arka planda çalışarak sunucu sisteminden, 
+    Korona testi pozitif çıkan ve sınır ötesi uyarı sistemine katılan ülkelerin 
+    resmi Korona uygulamaları aracılığıyla bir uyarı tetikleyen kullanıcılardan 
+    rastgele kimlik numaraları ve varsa semptomların başlangıcına ilişkin bilgiyi 
+    içeren listeleri günde birçok kez çağırır (bundan böyle: <strong>pozitif liste</strong>).
+    Pozitif listedeki rastgele kimlik numaraları, ek olarak ayrıca bir taşıma riski 
+    değeri ve tanı tipi hakkında bilgi de içerir (bkz. Madde 6 c.).
 </p>
 <p>
     Uygulama bu rastgele kimlik numaralarını, COVID-19 bildirim sistemine
@@ -446,13 +448,11 @@
     d. Uygulamanın bilgilenme amaçlı kullanımı
 </h2>
 <p>
-    Uygulamayı yalnızca bilgi edinme amaçlı kullanıyorsanız, yani yukarıda
-    belirtilen işlevlerden hiçbirini kullanmıyorsanız, veri işleme yalnızca
-    kendi akıllı telefonunuzda gerçekleşir ve RKI tarafından hiçbir kişisel
-    veri işlenmez. Uygulamada, örneğin www.bundesregierung.de gibi
-    bağlantılı web siteleri açılır ve standart tarayıcıda (Android akıllı
-    telefonlar) veya Uygulamada (iPhone’lar) görüntülenir. Hangi verilerin
-    işleneceği, erişilen web sitesinin ilgili sağlayıcısı tarafından
+    Uygulama otomatik olarak sunucu sistemi üzerinden günlük istatistikleri alır 
+    ve bunlar Uygulamada görüntülenir. Bu sırada erişim verileri oluşur. Uygulamada, 
+    örneğin www.bundesregierung.de gibi bağlantılı web siteleri açılır ve standart 
+    tarayıcıda (Android akıllı telefonlar) veya Uygulamada (iPhone’lar) görüntülenir. 
+    Hangi verilerin işleneceği, erişilen web sitesinin ilgili sağlayıcısı tarafından
     belirlenmektedir.
 </p>
 <h1>
@@ -772,5 +772,4 @@
     veya e-posta yoluyla: datenschutz@rki.de.
 </p>
 <p>
-    Yayım tarihi: 17.10.2020
-</p>
+    Baskı: 15.11.2020
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ConfigChangeDetector.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ConfigChangeDetector.kt
index cf17b9f3e954cf2840ff98d16bb2bf45c21bc943..588451c9dec8b5393a6c55e1aaf9fbb00bc2317b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ConfigChangeDetector.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ConfigChangeDetector.kt
@@ -47,7 +47,7 @@ class ConfigChangeDetector @Inject constructor(
         if (newIdentifier != oldConfigId) {
             Timber.i("New config id ($newIdentifier) differs from last one ($oldConfigId), resetting.")
             RiskLevelRepositoryDeferrer.resetRiskLevel()
-            taskController.submit(DefaultTaskRequest(RiskLevelTask::class))
+            taskController.submit(DefaultTaskRequest(RiskLevelTask::class, originTag = "ConfigChangeDetector"))
         } else {
             Timber.v("Config identifier ($oldConfigId) didn't change, NOOP.")
         }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt
index 90b013bf159ff3d4d533b2262f71ea493805db7a..8eb886fcd046455684e89b4394190e15640cc26f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DownloadDiagnosisKeysTask.kt
@@ -63,9 +63,6 @@ class DownloadDiagnosisKeysTask @Inject constructor(
             val currentDate = Date(timeStamper.nowUTC.millis)
             Timber.tag(TAG).d("Using $currentDate as current date in task.")
 
-            /****************************************************
-             * DOWNLOAD KEYS
-             ****************************************************/
             throwIfCancelled()
 
             // RETRIEVE RISK SCORE PARAMETERS
@@ -229,8 +226,7 @@ class DownloadDiagnosisKeysTask @Inject constructor(
     }
 
     class Arguments(
-        val requestedCountries: List<String>? = null,
-        val withConstraints: Boolean = false
+        val requestedCountries: List<String>? = null
     ) : Task.Arguments
 
     data class Config(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt
index 62b1aa91462f3b54232b55f04585538497c77306..5f177f2920d7e8bc8bf9738df7e19189f9aa6f0b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt
@@ -17,8 +17,9 @@ import java.io.PrintWriter
 import java.io.StringWriter
 import java.util.concurrent.CancellationException
 
-fun Throwable.report(exceptionCategory: ExceptionCategory) =
+fun Throwable.report(exceptionCategory: ExceptionCategory) {
     this.report(exceptionCategory, null, null)
+}
 
 fun Throwable.report(
     exceptionCategory: ExceptionCategory,
@@ -32,6 +33,9 @@ fun Throwable.report(
     if (this is CancellationException) return
 
     reportProblem(tag = prefix, info = suffix)
+
+    if (CWADebug.isAUnitTest) return
+
     val context = CoronaWarnApplication.getAppContext()
 
     val intent = Intent(ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt
index b2a7d5f6a3962eadcd7d8893f86a29fcba05edfe..c965b791d0c50cb0fff69412843c6709f4277c55 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt
@@ -10,6 +10,7 @@ import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProv
 import de.rki.coronawarnapp.nearby.modules.exposurewindow.ExposureWindowProvider
 import de.rki.coronawarnapp.nearby.modules.locationless.ScanningSupport
 import de.rki.coronawarnapp.nearby.modules.tracing.TracingStatus
+import de.rki.coronawarnapp.nearby.modules.version.ENFVersion
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.map
 import org.joda.time.Instant
@@ -26,8 +27,9 @@ class ENFClient @Inject constructor(
     private val tracingStatus: TracingStatus,
     private val scanningSupport: ScanningSupport,
     private val exposureWindowProvider: ExposureWindowProvider,
-    private val exposureDetectionTracker: ExposureDetectionTracker
-) : DiagnosisKeyProvider, TracingStatus, ScanningSupport, ExposureWindowProvider {
+    private val exposureDetectionTracker: ExposureDetectionTracker,
+    private val enfVersion: ENFVersion
+) : DiagnosisKeyProvider, TracingStatus, ScanningSupport, ExposureWindowProvider, ENFVersion by enfVersion  {
 
     // TODO Remove this once we no longer need direct access to the ENF Client,
     // i.e. in **[InternalExposureNotificationClient]**
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt
index ec99ff4e77f53c5a7f777519cd01ad799f56d61c..1d4220ee0df1f0640c4d5587ddd56bfdbd669e77 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt
@@ -15,6 +15,8 @@ import de.rki.coronawarnapp.nearby.modules.locationless.DefaultScanningSupport
 import de.rki.coronawarnapp.nearby.modules.locationless.ScanningSupport
 import de.rki.coronawarnapp.nearby.modules.tracing.DefaultTracingStatus
 import de.rki.coronawarnapp.nearby.modules.tracing.TracingStatus
+import de.rki.coronawarnapp.nearby.modules.version.DefaultENFVersion
+import de.rki.coronawarnapp.nearby.modules.version.ENFVersion
 import de.rki.coronawarnapp.util.di.AppContext
 import javax.inject.Singleton
 
@@ -50,4 +52,8 @@ class ENFModule {
     @Provides
     fun calculationTracker(exposureDetectionTracker: DefaultExposureDetectionTracker): ExposureDetectionTracker =
         exposureDetectionTracker
+
+    @Singleton
+    @Provides
+    fun enfClientVersion(enfVersion: DefaultENFVersion): ENFVersion = enfVersion
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ExposureStateUpdateWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ExposureStateUpdateWorker.kt
index d5fee52d0c01b1565510170d1ba9fed1bc2ca95a..e1a84422b7ca39f9c9149ffbb77828ee77f6df33 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ExposureStateUpdateWorker.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ExposureStateUpdateWorker.kt
@@ -31,7 +31,9 @@ class ExposureStateUpdateWorker @AssistedInject constructor(
                     Timber.v("exposure summary state updated: $it")
                 }
 
-            taskController.submit(DefaultTaskRequest(RiskLevelTask::class))
+            taskController.submit(
+                DefaultTaskRequest(RiskLevelTask::class, originTag = "ExposureStateUpdateWorker")
+            )
             Timber.v("risk level calculation triggered")
         } catch (e: ApiException) {
             e.report(ExceptionCategory.EXPOSURENOTIFICATION)
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 2284f36d64cc0dd7ba523a72a403bafd99340938..3ded662b655f7aa9dc7b87cdada9cbd6425031a6 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
@@ -88,15 +88,6 @@ object InternalExposureNotificationClient {
             }
     }
 
-    suspend fun getVersion(): Long = suspendCoroutine { cont ->
-        exposureNotificationClient.version
-            .addOnSuccessListener {
-                cont.resume(it)
-            }.addOnFailureListener {
-                cont.resumeWithException(it)
-            }
-    }
-
     /**
      * Retrieves key history from the data store on the device for uploading to your
      * internet-accessible server. Calling this method prompts Google Play services to display
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt
index ebf8523d7de03944a06598d2005ba21d7ed43e6a..c612cf3f0b2ca93a726a36b919d23aa89a485ebd 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt
@@ -3,7 +3,7 @@ package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
 import com.google.android.gms.common.api.ApiException
 import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
 import de.rki.coronawarnapp.exception.reporting.ReportingConstants
-import de.rki.coronawarnapp.util.GoogleAPIVersion
+import de.rki.coronawarnapp.nearby.modules.version.ENFVersion
 import timber.log.Timber
 import java.io.File
 import javax.inject.Inject
@@ -14,7 +14,7 @@ import kotlin.coroutines.suspendCoroutine
 
 @Singleton
 class DefaultDiagnosisKeyProvider @Inject constructor(
-    private val googleAPIVersion: GoogleAPIVersion,
+    private val enfVersion: ENFVersion,
     private val submissionQuota: SubmissionQuota,
     private val enfClient: ExposureNotificationClient
 ) : DiagnosisKeyProvider {
@@ -25,7 +25,7 @@ class DefaultDiagnosisKeyProvider @Inject constructor(
             return true
         }
 
-        if (!googleAPIVersion.isAtLeast(GoogleAPIVersion.V15)) {
+        if (!enfVersion.isAtLeast(ENFVersion.V15)) {
             // Actually this shouldn't happen
             Timber.d("No key files submitted because client uses an old unsupported version")
             return false
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersion.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersion.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f1983ba68c6f080becbb1d746b66ea137e1d60f7
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersion.kt
@@ -0,0 +1,53 @@
+package de.rki.coronawarnapp.nearby.modules.version
+
+import com.google.android.gms.common.api.ApiException
+import com.google.android.gms.common.api.CommonStatusCodes
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlin.coroutines.suspendCoroutine
+import kotlin.math.abs
+
+@Singleton
+class DefaultENFVersion @Inject constructor(
+    private val client: ExposureNotificationClient
+) : ENFVersion {
+
+    override suspend fun getENFClientVersion(): Long? = try {
+        internalGetENFClientVersion()
+    } catch (e: Exception) {
+        Timber.w(e, "Failed to get ENFClient version.")
+        null
+    }
+
+    override suspend fun isAtLeast(compareVersion: Long): Boolean {
+        if (!compareVersion.isCorrectVersionLength) throw IllegalArgumentException("given version has incorrect length")
+
+        return try {
+            internalGetENFClientVersion() >= compareVersion
+        } catch (apiException: ApiException) {
+            if (apiException.statusCode != CommonStatusCodes.API_NOT_CONNECTED) {
+                throw apiException
+            } else {
+                return false
+            }
+        }
+    }
+
+    private suspend fun internalGetENFClientVersion(): Long = suspendCoroutine { cont ->
+        client.version
+            .addOnSuccessListener { cont.resume(it) }
+            .addOnFailureListener { cont.resumeWithException(it) }
+    }
+
+    // check if a raw long has the correct length to be considered an API version
+    private val Long.isCorrectVersionLength
+        get(): Boolean = abs(this).toString().length == GOOGLE_API_VERSION_FIELD_LENGTH
+
+    companion object {
+        private const val GOOGLE_API_VERSION_FIELD_LENGTH = 8
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/ENFVersion.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/ENFVersion.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e0f3fec558f0a5771f0e13d2852d17f0935be3c1
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/ENFVersion.kt
@@ -0,0 +1,16 @@
+package de.rki.coronawarnapp.nearby.modules.version
+
+interface ENFVersion {
+    suspend fun getENFClientVersion(): Long?
+
+    /**
+     * Indicates if the client runs above a certain version
+     *
+     * @return isAboveVersion, if connected to an old unsupported version, return false
+     */
+    suspend fun isAtLeast(compareVersion: Long): Boolean
+
+    companion object {
+        const val V16 = 16000000L
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiver.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiver.kt
index d58137f5eeceee48d15a7151ee2db98bc5f524cc..5fb17c90d2172fad81d2f77f21acd51be979d670 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiver.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiver.kt
@@ -15,7 +15,7 @@ import de.rki.coronawarnapp.exception.UnknownBroadcastException
 import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.nearby.ExposureStateUpdateWorker
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
-import de.rki.coronawarnapp.nearby.modules.detectiontracker.TrackedExposureDetection
+import de.rki.coronawarnapp.nearby.modules.detectiontracker.TrackedExposureDetection.Result
 import de.rki.coronawarnapp.util.coroutine.AppScope
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import kotlinx.coroutines.CoroutineScope
@@ -41,26 +41,35 @@ class ExposureStateUpdateReceiver : BroadcastReceiver() {
     @Inject @AppScope lateinit var scope: CoroutineScope
     @Inject lateinit var dispatcherProvider: DispatcherProvider
     @Inject lateinit var exposureDetectionTracker: ExposureDetectionTracker
-    lateinit var context: Context
+    @Inject lateinit var workManager: WorkManager
 
     override fun onReceive(context: Context, intent: Intent) {
         Timber.tag(TAG).d("onReceive(context=%s, intent=%s)", context, intent)
         AndroidInjection.inject(this, context)
-        this.context = context
 
         val action = intent.action
         Timber.tag(TAG).v("Looking up action: %s", action)
 
         val async = goAsync()
-        scope.launch(context = dispatcherProvider.Default) {
+
+        scope.launch(context = scope.coroutineContext) {
             try {
-                val token = intent.getStringExtra(EXTRA_TOKEN)
-                when (action) {
-                    ACTION_EXPOSURE_STATE_UPDATED -> processStateUpdates(token)
-                    ACTION_EXPOSURE_NOT_FOUND -> processNotFound(token)
-                    else -> throw UnknownBroadcastException(action)
-                }
+                val token = intent.requireToken()
+
+                trackDetection(token, action)
+
+                val data = Data
+                    .Builder()
+                    .putString(EXTRA_TOKEN, token)
+                    .build()
+
+                OneTimeWorkRequest
+                    .Builder(ExposureStateUpdateWorker::class.java)
+                    .setInputData(data)
+                    .build()
+                    .let { workManager.enqueue(it) }
             } catch (e: Exception) {
+                Timber.e(e, "Failed to process intent.")
                 e.report(INTERNAL)
             } finally {
                 Timber.tag(TAG).i("Finished processing broadcast.")
@@ -69,36 +78,16 @@ class ExposureStateUpdateReceiver : BroadcastReceiver() {
         }
     }
 
-    private fun processStateUpdates(token: String?) {
-        Timber.tag(TAG).i("Processing ACTION_EXPOSURE_STATE_UPDATED")
-
-        val workManager = WorkManager.getInstance(context)
-
-        // TODO("Remove token from ExposureStateUpdateWorker")
-        val data = Data
-            .Builder()
-            .putString(EXTRA_TOKEN, token)
-            .build()
-
-        OneTimeWorkRequest
-            .Builder(ExposureStateUpdateWorker::class.java)
-            .setInputData(data)
-            .build()
-            .let { workManager.enqueue(it) }
-
-        exposureDetectionTracker.finishExposureDetection(
-            token,
-            TrackedExposureDetection.Result.UPDATED_STATE
-        )
-    }
-
-    private fun processNotFound(token: String?) {
-        Timber.tag(TAG).i("Processing ACTION_EXPOSURE_NOT_FOUND")
-
-        exposureDetectionTracker.finishExposureDetection(
-            token,
-            TrackedExposureDetection.Result.NO_MATCHES
-        )
+    private fun trackDetection(token: String, action: String?) {
+        when (action) {
+            ACTION_EXPOSURE_STATE_UPDATED -> {
+                exposureDetectionTracker.finishExposureDetection(token, Result.UPDATED_STATE)
+            }
+            ACTION_EXPOSURE_NOT_FOUND -> {
+                exposureDetectionTracker.finishExposureDetection(token, Result.NO_MATCHES)
+            }
+            else -> throw UnknownBroadcastException(action)
+        }
     }
 
     companion object {
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 9f912cf2579fd0d1ae95fb0491bbf1e440370498..75be4b8cf6503bb73bdf1a9dbda5c92e1fad2206 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
@@ -69,6 +69,7 @@ class TracingRepository @Inject constructor(
     private fun List<TaskInfo>.isRiskLevelTaskRunning() = any {
         it.taskState.isActive && it.taskState.request.type == RiskLevelTask::class
     }
+
     private fun List<TaskInfo>.isDownloadDiagnosisKeysTaskRunning() = any {
         it.taskState.isActive && it.taskState.request.type == DownloadDiagnosisKeysTask::class
     }
@@ -85,10 +86,15 @@ class TracingRepository @Inject constructor(
             taskController.submitBlocking(
                 DefaultTaskRequest(
                     DownloadDiagnosisKeysTask::class,
-                    DownloadDiagnosisKeysTask.Arguments()
+                    DownloadDiagnosisKeysTask.Arguments(),
+                    originTag = "TracingRepository.refreshDiagnosisKeys()"
+                )
+            )
+            taskController.submit(
+                DefaultTaskRequest(
+                    RiskLevelTask::class, originTag = "TracingRepository.refreshDiagnosisKeys()"
                 )
             )
-            taskController.submit(DefaultTaskRequest(RiskLevelTask::class))
             TimerHelper.startManualKeyRetrievalTimer()
         }
     }
@@ -133,12 +139,15 @@ class TracingRepository @Inject constructor(
                     taskController.submitBlocking(
                         DefaultTaskRequest(
                             DownloadDiagnosisKeysTask::class,
-                            DownloadDiagnosisKeysTask.Arguments()
+                            DownloadDiagnosisKeysTask.Arguments(),
+                            originTag = "TracingRepository.refreshRisklevel()"
                         )
                     )
                     TimerHelper.checkManualKeyRetrievalTimer()
 
-                    taskController.submit(DefaultTaskRequest(RiskLevelTask::class))
+                    taskController.submit(
+                        DefaultTaskRequest(RiskLevelTask::class, originTag = "TracingRepository.refreshRiskLevel()")
+                    )
                 }
             }
         }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/common/DefaultTaskRequest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/common/DefaultTaskRequest.kt
index df111a364ba660bc00759312bd44578ea3c371b0..e34681d7755b32565a6865a90c69a688e2184391 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/common/DefaultTaskRequest.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/common/DefaultTaskRequest.kt
@@ -8,7 +8,8 @@ import kotlin.reflect.KClass
 data class DefaultTaskRequest(
     override val type: KClass<out Task<Task.Progress, Task.Result>>,
     override val arguments: Task.Arguments = object : Task.Arguments {},
-    override val id: UUID = UUID.randomUUID()
+    override val id: UUID = UUID.randomUUID(),
+    val originTag: String? = null
 ) : TaskRequest {
 
     fun toNewTask(): DefaultTaskRequest = copy(id = UUID.randomUUID())
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt
index e6b1683ce430f4073e569959a96785f79ae6eec2..caac006b32562d2d7ccffa0881ad81d6eb3eec9a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt
@@ -1,27 +1,58 @@
 package de.rki.coronawarnapp.ui.information
 
+import android.content.Intent
 import android.os.Bundle
 import android.view.View
 import android.view.accessibility.AccessibilityEvent
 import android.view.accessibility.AccessibilityNodeInfo
 import androidx.fragment.app.Fragment
 import androidx.navigation.fragment.findNavController
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentInformationBinding
 import de.rki.coronawarnapp.ui.doNavigate
 import de.rki.coronawarnapp.ui.main.MainActivity
 import de.rki.coronawarnapp.util.ExternalActionHelper
+import de.rki.coronawarnapp.util.di.AutoInject
+import de.rki.coronawarnapp.util.ui.observe2
+import de.rki.coronawarnapp.util.ui.setGone
 import de.rki.coronawarnapp.util.ui.viewBindingLazy
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
+import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
+import timber.log.Timber
+import javax.inject.Inject
 
 /**
  * Basic Fragment which links to static and web content.
  */
-class InformationFragment : Fragment(R.layout.fragment_information) {
+class InformationFragment : Fragment(R.layout.fragment_information), AutoInject {
+
+    @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
+    private val vm: InformationFragmentViewModel by cwaViewModels { viewModelFactory }
 
     private val binding: FragmentInformationBinding by viewBindingLazy()
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
+
+        vm.currentENFVersion.observe2(this) {
+            binding.informationEnfVersion.apply {
+                setGone(it == null)
+                text = it
+            }
+        }
+        vm.appVersion.observe2(this) {
+            binding.informationVersion.text = it
+        }
+
+        binding.informationEnfVersion.setOnClickListener {
+            try {
+                startActivity(Intent(ExposureNotificationClient.ACTION_EXPOSURE_NOTIFICATION_SETTINGS))
+            } catch (e: Exception) {
+                Timber.e(e, "Can't open ENF settings.")
+            }
+        }
+
         setButtonOnClickListener()
         setAccessibilityDelegate()
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragmentModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7b7473491c6c067a89555f75535491ffbdd81b27
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragmentModule.kt
@@ -0,0 +1,22 @@
+package de.rki.coronawarnapp.ui.information
+
+import dagger.Binds
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import dagger.multibindings.IntoMap
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
+
+@Module
+abstract class InformationFragmentModule {
+    @Binds
+    @IntoMap
+    @CWAViewModelKey(InformationFragmentViewModel::class)
+    abstract fun informationFragmentViewModel(
+        factory: InformationFragmentViewModel.Factory
+    ): CWAViewModelFactory<out CWAViewModel>
+
+    @ContributesAndroidInjector
+    abstract fun informationFragment(): InformationFragment
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragmentViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..27f53ae57b79ddf2ea0c09a62fed833f2125a3b4
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragmentViewModel.kt
@@ -0,0 +1,34 @@
+package de.rki.coronawarnapp.ui.information
+
+import android.content.Context
+import androidx.lifecycle.asLiveData
+import com.squareup.inject.assisted.AssistedInject
+import de.rki.coronawarnapp.BuildConfig
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.nearby.ENFClient
+import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
+import de.rki.coronawarnapp.util.di.AppContext
+import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
+import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOf
+
+class InformationFragmentViewModel @AssistedInject constructor(
+    dispatcherProvider: DispatcherProvider,
+    enfClient: ENFClient,
+    @AppContext private val context: Context
+) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
+
+    val currentENFVersion = flow {
+        val enfVersion = enfClient.getENFClientVersion()
+            ?.let { "ENF ${context.getString(R.string.information_version).format(it)}" }
+        emit(enfVersion)
+    }.asLiveData(context = dispatcherProvider.Default)
+
+    val appVersion = flowOf(
+        context.getString(R.string.information_version).format(BuildConfig.VERSION_NAME)
+    ).asLiveData(context = dispatcherProvider.Default)
+
+    @AssistedInject.Factory
+    interface Factory : SimpleCWAViewModelFactory<InformationFragmentViewModel>
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt
index efb78a5cbf81f040fe8b6cac1c78e64785a86303..fd0e01406f0c89425fac3b81ffb0a5bc0bbcbc8e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt
@@ -10,13 +10,11 @@ import androidx.appcompat.app.AppCompatActivity
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentManager
 import androidx.lifecycle.ViewModelProviders
-import androidx.lifecycle.lifecycleScope
 import dagger.android.AndroidInjector
 import dagger.android.DispatchingAndroidInjector
 import dagger.android.HasAndroidInjector
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.deadman.DeadmanNotificationScheduler
-import de.rki.coronawarnapp.playbook.BackgroundNoise
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.ui.base.startActivitySafely
 import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel
@@ -30,7 +28,6 @@ import de.rki.coronawarnapp.util.ui.observe2
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
 import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
-import kotlinx.coroutines.launch
 import javax.inject.Inject
 
 /**
@@ -105,16 +102,10 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector {
         settingsViewModel.updateBackgroundJobEnabled(ConnectivityHelper.autoModeEnabled(this))
         scheduleWork()
         checkShouldDisplayBackgroundWarning()
-        doBackgroundNoiseCheck()
+        vm.doBackgroundNoiseCheck()
         deadmanScheduler.schedulePeriodic()
     }
 
-    private fun doBackgroundNoiseCheck() {
-        lifecycleScope.launch {
-            BackgroundNoise.getInstance().foregroundScheduleCheck()
-        }
-    }
-
     private fun showEnergyOptimizedEnabledForBackground() {
         val dialog = DialogHelper.DialogInstance(
             this,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt
index 7a596bfc0666c156fe94d05749be586282b531e7..998c4e89dd36104eba97220c65164608a4961f36 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt
@@ -4,6 +4,7 @@ import dagger.Binds
 import dagger.Module
 import dagger.android.ContributesAndroidInjector
 import dagger.multibindings.IntoMap
+import de.rki.coronawarnapp.ui.information.InformationFragmentModule
 import de.rki.coronawarnapp.ui.interoperability.InteroperabilityConfigurationFragment
 import de.rki.coronawarnapp.ui.interoperability.InteroperabilityConfigurationFragmentModule
 import de.rki.coronawarnapp.ui.main.home.HomeFragmentModule
@@ -23,7 +24,8 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
         HomeFragmentModule::class,
         RiskDetailsFragmentModule::class,
         SettingFragmentsModule::class,
-        SubmissionFragmentModule::class
+        SubmissionFragmentModule::class,
+        InformationFragmentModule::class
     ]
 )
 abstract class MainActivityModule {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt
index 8345f33c5aafac4b55a784fd5090d4ebb8a6779d..02dbea80d6c3e99fe272b5c8980600a2a8f35a70 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityViewModel.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.ui.main
 
 import com.squareup.inject.assisted.AssistedInject
 import de.rki.coronawarnapp.environment.EnvironmentSetup
+import de.rki.coronawarnapp.playbook.BackgroundNoise
 import de.rki.coronawarnapp.util.CWADebug
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
@@ -28,6 +29,12 @@ class MainActivityViewModel @AssistedInject constructor(
         }
     }
 
+    fun doBackgroundNoiseCheck() {
+        launch {
+            BackgroundNoise.getInstance().foregroundScheduleCheck()
+        }
+    }
+
     @AssistedInject.Factory
     interface Factory : SimpleCWAViewModelFactory<MainActivityViewModel>
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt
index aba0e9850f7be7eb0f6945755d7259da9ff4d1b9..af99a6380e0446e1338420c9a1e973b67b68eb96 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt
@@ -5,7 +5,6 @@ import android.os.Bundle
 import android.view.View
 import android.view.accessibility.AccessibilityEvent
 import androidx.fragment.app.Fragment
-import androidx.lifecycle.lifecycleScope
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentHomeBinding
 import de.rki.coronawarnapp.util.DialogHelper
@@ -18,7 +17,6 @@ import de.rki.coronawarnapp.util.ui.observe2
 import de.rki.coronawarnapp.util.ui.viewBindingLazy
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
-import kotlinx.coroutines.launch
 import javax.inject.Inject
 
 /**
@@ -100,7 +98,7 @@ class HomeFragment : Fragment(R.layout.fragment_home), AutoInject {
             }
         }
 
-        lifecycleScope.launch { vm.observeTestResultToSchedulePositiveTestResultReminder() }
+        vm.observeTestResultToSchedulePositiveTestResultReminder()
     }
 
     override fun onResume() {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
index 36fb7f775e1137820d510815ac191c27c78cd685..99d389d7d608dc1a9491aaa1e5c444c344da490a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt
@@ -76,10 +76,11 @@ class HomeFragmentViewModel @AssistedInject constructor(
 
     private var isLoweredRiskLevelDialogBeingShown = false
 
-    suspend fun observeTestResultToSchedulePositiveTestResultReminder() =
+    fun observeTestResultToSchedulePositiveTestResultReminder() = launch {
         submissionCardsStateProvider.state
             .first { it.isPositiveSubmissionCardVisible() }
             .also { testResultNotificationService.schedulePositiveTestResultReminder() }
+    }
 
     // TODO only lazy to keep tests going which would break because of LocalData access
     val showLoweredRiskLevelDialog: LiveData<Boolean> by lazy {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultFragment.kt
index 0de5f0efad201d2a0f065cd443291523ca65275c..86d6b9bc9c8f73aa14fee8ef1380bdde24e1dad3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultFragment.kt
@@ -6,7 +6,6 @@ import android.view.View
 import android.view.accessibility.AccessibilityEvent
 import androidx.activity.OnBackPressedCallback
 import androidx.fragment.app.Fragment
-import androidx.lifecycle.lifecycleScope
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentSubmissionTestResultBinding
 import de.rki.coronawarnapp.exception.http.CwaClientError
@@ -22,7 +21,6 @@ import de.rki.coronawarnapp.util.ui.observe2
 import de.rki.coronawarnapp.util.ui.viewBindingLazy
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
-import kotlinx.coroutines.launch
 import javax.inject.Inject
 
 class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_result),
@@ -136,7 +134,7 @@ class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_
             }
         }
 
-        lifecycleScope.launch { viewModel.observeTestResultToSchedulePositiveTestResultReminder() }
+        viewModel.observeTestResultToSchedulePositiveTestResultReminder()
     }
 
     override fun onResume() {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultViewModel.kt
index 370ecbf292818116417636008439820aeb2a02e7..ff12359c1b6403092b4b8ac318ca6f2e2412e0cf 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/SubmissionTestResultViewModel.kt
@@ -57,7 +57,7 @@ class SubmissionTestResultViewModel @AssistedInject constructor(
         ).let { emit(it) }
     }.asLiveData(context = dispatcherProvider.Default)
 
-    suspend fun observeTestResultToSchedulePositiveTestResultReminder() =
+    fun observeTestResultToSchedulePositiveTestResultReminder() = launch {
         SubmissionRepository.deviceUIStateFlow
             .first { request ->
                 request.withSuccess(false) {
@@ -65,6 +65,7 @@ class SubmissionTestResultViewModel @AssistedInject constructor(
                 }
             }
             .also { testResultNotificationService.schedulePositiveTestResultReminder() }
+    }
 
     fun onBackPressed() {
         routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragment.kt
index 56ef3c2d2747d7f329aa3a1eb04e769ed12f9ece..489f83c59a0bbe31475fd18214d8637bd4cb2752 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragment.kt
@@ -5,17 +5,14 @@ import android.os.Bundle
 import android.view.View
 import android.view.accessibility.AccessibilityEvent
 import androidx.fragment.app.Fragment
-import androidx.lifecycle.lifecycleScope
 import androidx.navigation.fragment.findNavController
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentSettingsTracingBinding
-import de.rki.coronawarnapp.exception.ExceptionCategory
-import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper
-import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.ui.doNavigate
 import de.rki.coronawarnapp.ui.main.MainActivity
+import de.rki.coronawarnapp.ui.tracing.settings.SettingsTracingFragmentViewModel.Event
 import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel
 import de.rki.coronawarnapp.util.DialogHelper
 import de.rki.coronawarnapp.util.ExternalActionHelper
@@ -25,7 +22,6 @@ import de.rki.coronawarnapp.util.ui.viewBindingLazy
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
 import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
-import kotlinx.coroutines.launch
 import timber.log.Timber
 import javax.inject.Inject
 
@@ -47,7 +43,7 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing),
 
     private val binding: FragmentSettingsTracingBinding by viewBindingLazy()
 
-    private lateinit var internalExposureNotificationPermissionHelper: InternalExposureNotificationPermissionHelper
+    private lateinit var exposureNotificationPermissionHelper: InternalExposureNotificationPermissionHelper
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
@@ -63,11 +59,21 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing),
                     TracingSettingsState.BluetoothDisabled,
                     TracingSettingsState.LocationDisabled -> setOnClickListener(null)
                     TracingSettingsState.TracingInActive,
-                    TracingSettingsState.TracingActive -> setOnClickListener { startStopTracing() }
+                    TracingSettingsState.TracingActive -> setOnClickListener { vm.startStopTracing() }
                 }
             }
         }
 
+        exposureNotificationPermissionHelper = InternalExposureNotificationPermissionHelper(this, this)
+
+        vm.events.observe2(this) {
+            when (it) {
+                Event.RequestPermissions -> exposureNotificationPermissionHelper.requestPermissionToStartTracing()
+                Event.ShowConsentDialog -> showConsentDialog()
+                Event.ManualCheckingDialog -> showManualCheckingRequiredDialog()
+            }
+        }
+
         setButtonOnClickListener()
     }
 
@@ -77,7 +83,7 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing),
     }
 
     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
-        internalExposureNotificationPermissionHelper.onResolutionComplete(
+        exposureNotificationPermissionHelper.onResolutionComplete(
             requestCode,
             resultCode
         )
@@ -98,13 +104,10 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing),
         val location = binding.settingsTracingStatusLocation.tracingStatusCardButton
         val interoperability = binding.settingsInteroperabilityRow.settingsPlainRow
 
-        internalExposureNotificationPermissionHelper =
-            InternalExposureNotificationPermissionHelper(this, this)
         switch.setOnCheckedChangeListener { view, _ ->
-
             // Make sure that listener is called by user interaction
             if (view.isPressed) {
-                startStopTracing()
+                vm.startStopTracing()
                 // Focus on the body text after to announce the tracing status for accessibility reasons
                 binding.settingsTracingSwitchRow.settingsSwitchRowHeaderBody
                     .sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED)
@@ -131,39 +134,6 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing),
             )
     }
 
-    private fun startStopTracing() {
-        // if tracing is enabled when listener is activated it should be disabled
-        lifecycleScope.launch {
-            try {
-                if (InternalExposureNotificationClient.asyncIsEnabled()) {
-                    InternalExposureNotificationClient.asyncStop()
-                    BackgroundWorkScheduler.stopWorkScheduler()
-                } else {
-                    // tracing was already activated
-                    if (LocalData.initialTracingActivationTimestamp() != null) {
-                        internalExposureNotificationPermissionHelper.requestPermissionToStartTracing()
-                    } else {
-                        // tracing was never activated
-                        // ask for consent via dialog for initial tracing activation when tracing was not
-                        // activated during onboarding
-                        showConsentDialog()
-                        // check if background processing is switched off, if it is, show the manual calculation dialog explanation before turning on.
-                        val activity = requireActivity() as MainActivity
-                        if (!activity.backgroundPrioritization.isBackgroundActivityPrioritized) {
-                            showManualCheckingRequiredDialog()
-                        }
-                    }
-                }
-            } catch (exception: Exception) {
-                exception.report(
-                    ExceptionCategory.EXPOSURENOTIFICATION,
-                    TAG,
-                    null
-                )
-            }
-        }
-    }
-
     private fun showManualCheckingRequiredDialog() {
         val dialog = DialogHelper.DialogInstance(
             requireActivity(),
@@ -186,7 +156,7 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing),
             R.string.onboarding_button_enable,
             R.string.onboarding_button_cancel,
             true, {
-                internalExposureNotificationPermissionHelper.requestPermissionToStartTracing()
+                exposureNotificationPermissionHelper.requestPermissionToStartTracing()
             }, {
                 // Declined
             })
@@ -194,6 +164,6 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing),
     }
 
     companion object {
-        private val TAG: String? = SettingsTracingFragment::class.simpleName
+        internal val TAG: String? = SettingsTracingFragment::class.simpleName
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragmentViewModel.kt
index c9a5462932dcd507732537d002b785f6a7b659fe..6b2e57dfa22ec73593740d62705248d4ce98e6fe 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragmentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/tracing/settings/SettingsTracingFragmentViewModel.kt
@@ -4,13 +4,20 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.asLiveData
 import androidx.lifecycle.viewModelScope
 import com.squareup.inject.assisted.AssistedInject
+import de.rki.coronawarnapp.exception.ExceptionCategory
+import de.rki.coronawarnapp.exception.reporting.report
+import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
+import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.tracing.GeneralTracingStatus
 import de.rki.coronawarnapp.ui.tracing.details.TracingDetailsState
 import de.rki.coronawarnapp.ui.tracing.details.TracingDetailsStateProvider
+import de.rki.coronawarnapp.util.BackgroundPrioritization
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.flow.shareLatest
+import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
+import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
@@ -20,7 +27,8 @@ import timber.log.Timber
 class SettingsTracingFragmentViewModel @AssistedInject constructor(
     dispatcherProvider: DispatcherProvider,
     tracingDetailsStateProvider: TracingDetailsStateProvider,
-    tracingStatus: GeneralTracingStatus
+    tracingStatus: GeneralTracingStatus,
+    private val backgroundPrioritization: BackgroundPrioritization
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
     val tracingDetailsState: LiveData<TracingDetailsState> = tracingDetailsStateProvider.state
@@ -36,6 +44,47 @@ class SettingsTracingFragmentViewModel @AssistedInject constructor(
         )
         .asLiveData(dispatcherProvider.Main)
 
+    val events = SingleLiveEvent<Event>()
+
+    fun startStopTracing() {
+        // if tracing is enabled when listener is activated it should be disabled
+        launch {
+            try {
+                if (InternalExposureNotificationClient.asyncIsEnabled()) {
+                    InternalExposureNotificationClient.asyncStop()
+                    BackgroundWorkScheduler.stopWorkScheduler()
+                } else {
+                    // tracing was already activated
+                    if (LocalData.initialTracingActivationTimestamp() != null) {
+                        events.postValue(Event.RequestPermissions)
+                    } else {
+                        // tracing was never activated
+                        // ask for consent via dialog for initial tracing activation when tracing was not
+                        // activated during onboarding
+                        events.postValue(Event.ShowConsentDialog)
+                        // check if background processing is switched off,
+                        // if it is, show the manual calculation dialog explanation before turning on.
+                        if (!backgroundPrioritization.isBackgroundActivityPrioritized) {
+                            events.postValue(Event.ManualCheckingDialog)
+                        }
+                    }
+                }
+            } catch (exception: Exception) {
+                exception.report(
+                    ExceptionCategory.EXPOSURENOTIFICATION,
+                    SettingsTracingFragment.TAG,
+                    null
+                )
+            }
+        }
+    }
+
+    sealed class Event {
+        object RequestPermissions : Event()
+        object ShowConsentDialog : Event()
+        object ManualCheckingDialog : Event()
+    }
+
     @AssistedInject.Factory
     interface Factory : SimpleCWAViewModelFactory<SettingsTracingFragmentViewModel>
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DefaultBackgroundPrioritization.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DefaultBackgroundPrioritization.kt
index 7cfd0d07b2c5fbbc01e76b1002709c5bc06b92ca..eab3573bc450f2792c8ed8fa085f16cdd13f0ce6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DefaultBackgroundPrioritization.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DefaultBackgroundPrioritization.kt
@@ -1,8 +1,10 @@
 package de.rki.coronawarnapp.util
 
+import dagger.Reusable
 import de.rki.coronawarnapp.util.device.PowerManagement
 import javax.inject.Inject
 
+@Reusable
 class DefaultBackgroundPrioritization @Inject constructor(
     private val powerManagement: PowerManagement
 ) : BackgroundPrioritization {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/GoogleAPIVersion.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/GoogleAPIVersion.kt
deleted file mode 100644
index 8119586bcbab639d1634a4a2b92e9544d8aaa02f..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/GoogleAPIVersion.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package de.rki.coronawarnapp.util
-
-import com.google.android.gms.common.api.ApiException
-import com.google.android.gms.common.api.CommonStatusCodes
-import dagger.Reusable
-import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
-import javax.inject.Inject
-import kotlin.math.abs
-
-@Reusable
-class GoogleAPIVersion @Inject constructor() {
-    /**
-     * Indicates if the client runs above a certain version
-     *
-     * @return isAboveVersion, if connected to an old unsupported version, return false
-     */
-    suspend fun isAtLeast(compareVersion: Long): Boolean {
-        if (!compareVersion.isCorrectVersionLength) {
-            throw IllegalArgumentException("given version has incorrect length")
-        }
-        return try {
-            val currentVersion = InternalExposureNotificationClient.getVersion()
-            currentVersion >= compareVersion
-        } catch (apiException: ApiException) {
-            if (apiException.statusCode != CommonStatusCodes.API_NOT_CONNECTED) {
-                throw apiException
-            }
-            return false
-        }
-    }
-
-    // check if a raw long has the correct length to be considered an API version
-    private val Long.isCorrectVersionLength
-        get(): Boolean = abs(this).toString().length == GOOGLE_API_VERSION_FIELD_LENGTH
-
-    companion object {
-        private const val GOOGLE_API_VERSION_FIELD_LENGTH = 8
-        const val V16 = 16000000L
-        const val V15 = 15000000L
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt
index 00d62d17067f43ef080520518ba36bf2d4ee5d8f..cd3eccf6fce55cb8dc4bcdd7f1df52c544f3a8f3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt
@@ -51,7 +51,8 @@ class WatchdogService @Inject constructor(
             val state = taskController.submitBlocking(
                 DefaultTaskRequest(
                     DownloadDiagnosisKeysTask::class,
-                    DownloadDiagnosisKeysTask.Arguments(null, true)
+                    DownloadDiagnosisKeysTask.Arguments(),
+                    originTag = "WatchdogService"
                 )
             )
             if (state.isFailed) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterInformationHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterInformationHelper.kt
deleted file mode 100644
index 913424b0671ddfef1a1a9a00e79304ab5b6486f7..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterInformationHelper.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-@file:JvmName("FormatterInformationHelper")
-
-package de.rki.coronawarnapp.util.formatter
-
-import de.rki.coronawarnapp.BuildConfig
-import de.rki.coronawarnapp.CoronaWarnApplication
-import de.rki.coronawarnapp.R
-
-fun formatVersion(): String {
-    val appContext = CoronaWarnApplication.getAppContext()
-    val versionName: String = BuildConfig.VERSION_NAME
-    return appContext.getString(R.string.information_version).format(versionName)
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt
index ef5f51077634e914630f793378753b17336e4432..421d8d872b385bdb76c2b786fc30456053bab6de 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt
@@ -40,12 +40,11 @@ class DiagnosisKeyRetrievalOneTimeWorker @AssistedInject constructor(
         taskController.submitBlocking(
             DefaultTaskRequest(
                 DownloadDiagnosisKeysTask::class,
-                DownloadDiagnosisKeysTask.Arguments(null, true)
+                DownloadDiagnosisKeysTask.Arguments(),
+                originTag = "DiagnosisKeyRetrievalOneTimeWorker"
             )
         ).error?.also { error: Throwable ->
-            Timber.w(
-                error, "$id: Error during startWithConstraints()."
-            )
+            Timber.w(error, "$id: Error when submitting DownloadDiagnosisKeysTask.")
 
             if (runAttemptCount > BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD) {
                 Timber.w(error, "$id: Retry attempts exceeded.")
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_information.xml b/Corona-Warn-App/src/main/res/layout/fragment_information.xml
index d51c313a9172fd2dba61cbbcdfa0a807b3e55a57..b18582525731b852608527024c79dc44b8c39503 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_information.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_information.xml
@@ -1,12 +1,7 @@
 <?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">
-
-    <data>
-
-        <import type="de.rki.coronawarnapp.util.formatter.FormatterInformationHelper" />
-
-    </data>
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/information_container"
@@ -117,11 +112,27 @@
                     android:layout_height="wrap_content"
                     android:layout_marginTop="@dimen/spacing_small"
                     android:focusable="true"
-                    android:text="@{FormatterInformationHelper.formatVersion()}"
+                    tools:text="v1.8.0-RC1"
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintStart_toStartOf="@+id/guideline_body"
                     app:layout_constraintTop_toBottomOf="@+id/information_legal" />
 
+                <TextView
+                    android:id="@+id/information_enf_version"
+                    style="@style/body2Medium"
+                    android:visibility="gone"
+                    tools:visibility="visible"
+                    android:layout_width="@dimen/match_constraint"
+                    android:paddingTop="@dimen/spacing_tiny"
+                    android:paddingBottom="@dimen/spacing_tiny"
+                    android:layout_height="wrap_content"
+                    android:focusable="true"
+                    android:background="?selectableItemBackground"
+                    tools:text="16000000"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintStart_toStartOf="@+id/guideline_body"
+                    app:layout_constraintTop_toBottomOf="@+id/information_version" />
+
                 <androidx.constraintlayout.widget.Guideline
                     android:id="@+id/guideline_body"
                     android:layout_width="wrap_content"
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt
index 624df3ea1a0afe8819a4637d929c4f02c8de93ad..b24f8fc8964adf921e00389250ed379eb54ea4d1 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt
@@ -8,12 +8,14 @@ import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProv
 import de.rki.coronawarnapp.nearby.modules.exposurewindow.ExposureWindowProvider
 import de.rki.coronawarnapp.nearby.modules.locationless.ScanningSupport
 import de.rki.coronawarnapp.nearby.modules.tracing.TracingStatus
+import de.rki.coronawarnapp.nearby.modules.version.ENFVersion
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.Runs
 import io.mockk.clearAllMocks
 import io.mockk.coEvery
 import io.mockk.coVerify
+import io.mockk.coVerifySequence
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
 import io.mockk.just
@@ -38,6 +40,7 @@ class ENFClientTest : BaseTest() {
     @MockK lateinit var scanningSupport: ScanningSupport
     @MockK lateinit var exposureWindowProvider: ExposureWindowProvider
     @MockK lateinit var exposureDetectionTracker: ExposureDetectionTracker
+    @MockK lateinit var enfVersion: ENFVersion
 
     @BeforeEach
     fun setup() {
@@ -56,7 +59,7 @@ class ENFClientTest : BaseTest() {
         diagnosisKeyProvider = diagnosisKeyProvider,
         tracingStatus = tracingStatus,
         scanningSupport = scanningSupport,
-
+        enfVersion = enfVersion,
         exposureWindowProvider = exposureWindowProvider,
         exposureDetectionTracker = exposureDetectionTracker
     )
@@ -274,4 +277,13 @@ class ENFClientTest : BaseTest() {
             exposureWindowProvider.exposureWindows()
         }
     }
+
+    @Test
+    fun `enf version check is forwaded to the right module`() = runBlocking {
+        coEvery { enfVersion.getENFClientVersion() } returns Long.MAX_VALUE
+
+        createClient().getENFClientVersion() shouldBe Long.MAX_VALUE
+
+        coVerifySequence { enfVersion.getENFClientVersion() }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt
index 6ef70a9cddd0ffca0e67ede59a0d8dffb56805b9..d4e8aa99150773a347cd9152363176a69e97513f 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt
@@ -1,7 +1,7 @@
 package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
 
 import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
-import de.rki.coronawarnapp.util.GoogleAPIVersion
+import de.rki.coronawarnapp.nearby.modules.version.ENFVersion
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.clearAllMocks
@@ -17,11 +17,9 @@ import testhelpers.gms.MockGMSTask
 import java.io.File
 
 class DefaultDiagnosisKeyProviderTest : BaseTest() {
-    @MockK
-    lateinit var googleENFClient: ExposureNotificationClient
-
-    @MockK
-    lateinit var googleAPIVersion: GoogleAPIVersion
+    @MockK lateinit var googleENFClient: ExposureNotificationClient
+    @MockK lateinit var enfVersion: ENFVersion
+    @MockK lateinit var submissionQuota: SubmissionQuota
 
     @MockK
     lateinit var submissionQuota: SubmissionQuota
@@ -36,7 +34,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
 
         coEvery { googleENFClient.provideDiagnosisKeys(any<List<File>>()) } returns MockGMSTask.forValue(null)
 
-        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V15) } returns true
+        coEvery { enfVersion.isAtLeast(ENFVersion.V16) } returns true
     }
 
     @AfterEach
@@ -45,14 +43,14 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
     }
 
     private fun createProvider() = DefaultDiagnosisKeyProvider(
-        googleAPIVersion = googleAPIVersion,
+        enfVersion = enfVersion,
         submissionQuota = submissionQuota,
         enfClient = googleENFClient
     )
 
     @Test
     fun `key provision is used on older ENF versions`() {
-        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V15) } returns false
+        coEvery { enfVersion.isAtLeast(ENFVersion.V15) } returns false
 
         val provider = createProvider()
 
@@ -68,7 +66,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
 
     @Test
     fun `key provision is used on newer ENF versions`() {
-        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V15) } returns true
+        coEvery { enfVersion.isAtLeast(ENFVersion.V15) } returns true
 
         val provider = createProvider()
 
@@ -83,7 +81,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
 
     @Test
     fun `quota is consumed silently`() {
-        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V15) } returns true
+        coEvery { enfVersion.isAtLeast(ENFVersion.V15) } returns true
         coEvery { submissionQuota.consumeQuota(any()) } returns false
 
         val provider = createProvider()
@@ -100,7 +98,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
 
     @Test
     fun `provide empty key list`() {
-        coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V15) } returns true
+        coEvery { enfVersion.isAtLeast(ENFVersion.V15) } returns true
 
         val provider = createProvider()
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0a8ebf8773183208c180051eb08dff547f9994d3
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt
@@ -0,0 +1,77 @@
+package de.rki.coronawarnapp.nearby.modules.version
+
+import com.google.android.gms.common.api.ApiException
+import com.google.android.gms.common.api.CommonStatusCodes.API_NOT_CONNECTED
+import com.google.android.gms.common.api.Status
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import io.kotest.matchers.shouldBe
+import io.mockk.Called
+import io.mockk.MockKAnnotations
+import io.mockk.clearAllMocks
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.verify
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runBlockingTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertThrows
+import testhelpers.gms.MockGMSTask
+
+@ExperimentalCoroutinesApi
+internal class DefaultENFVersionTest {
+
+    @MockK lateinit var client: ExposureNotificationClient
+
+    @BeforeEach
+    fun setUp() {
+        MockKAnnotations.init(this)
+    }
+
+    @AfterEach
+    fun tearDown() {
+        clearAllMocks()
+    }
+
+    fun createInstance() = DefaultENFVersion(
+        client = client
+    )
+
+    @Test
+    fun `isAbove API v16 is true for v17`() {
+        every { client.version } returns MockGMSTask.forValue(17000000L)
+
+        runBlockingTest {
+            createInstance().isAtLeast(ENFVersion.V16) shouldBe true
+        }
+    }
+
+    @Test
+    fun `isAbove API v16 is false for v15`() {
+        every { client.version } returns MockGMSTask.forValue(15000000L)
+
+        runBlockingTest {
+            createInstance().isAtLeast(ENFVersion.V16) shouldBe false
+        }
+    }
+
+    @Test
+    fun `isAbove API v16 throws IllegalArgument for invalid version`() {
+        assertThrows<IllegalArgumentException> {
+            runBlockingTest {
+                createInstance().isAtLeast(1L)
+            }
+            verify { client.version wasNot Called }
+        }
+    }
+
+    @Test
+    fun `isAbove API v16 false when APIException for too low version`() {
+        every { client.version } returns MockGMSTask.forError(ApiException(Status(API_NOT_CONNECTED)))
+
+        runBlockingTest {
+            createInstance().isAtLeast(ENFVersion.V16) shouldBe false
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt
index fbc170105e025901200d40c8dc3e40d92a95e3c8..9a703be68780ffe862e47172cb454a6c5a4d9c26 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt
@@ -12,12 +12,13 @@ import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTra
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.TrackedExposureDetection
 import de.rki.coronawarnapp.util.di.AppInjector
 import io.mockk.MockKAnnotations
+import io.mockk.Runs
 import io.mockk.clearAllMocks
 import io.mockk.every
 import io.mockk.impl.annotations.MockK
+import io.mockk.just
 import io.mockk.mockk
 import io.mockk.mockkObject
-import io.mockk.mockkStatic
 import io.mockk.verifySequence
 import kotlinx.coroutines.test.TestCoroutineScope
 import org.junit.jupiter.api.AfterEach
@@ -36,6 +37,7 @@ class ExposureStateUpdateReceiverTest : BaseTest() {
     @MockK private lateinit var intent: Intent
     @MockK private lateinit var workManager: WorkManager
     @MockK private lateinit var exposureDetectionTracker: ExposureDetectionTracker
+
     private val scope = TestCoroutineScope()
 
     class TestApp : Application(), HasAndroidInjector {
@@ -48,23 +50,25 @@ class ExposureStateUpdateReceiverTest : BaseTest() {
     @BeforeEach
     fun setUp() {
         MockKAnnotations.init(this)
-        mockkStatic(WorkManager::class)
         every { intent.getStringExtra(ExposureNotificationClient.EXTRA_TOKEN) } returns "token"
 
         mockkObject(AppInjector)
 
+        every { workManager.enqueue(any<WorkRequest>()) } answers { mockk() }
+
         val application = mockk<TestApp>()
         every { context.applicationContext } returns application
+
         val broadcastReceiverInjector = AndroidInjector<Any> {
             it as ExposureStateUpdateReceiver
             it.exposureDetectionTracker = exposureDetectionTracker
             it.dispatcherProvider = TestDispatcherProvider
             it.scope = scope
+            it.workManager = workManager
         }
         every { application.androidInjector() } returns broadcastReceiverInjector
 
-        every { WorkManager.getInstance(context) } returns workManager
-        every { workManager.enqueue(any<WorkRequest>()) } answers { mockk() }
+        every { exposureDetectionTracker.finishExposureDetection(any(), any()) } just Runs
     }
 
     @AfterEach
@@ -77,9 +81,11 @@ class ExposureStateUpdateReceiverTest : BaseTest() {
         every { intent.action } returns ExposureNotificationClient.ACTION_EXPOSURE_STATE_UPDATED
         ExposureStateUpdateReceiver().onReceive(context, intent)
 
+        scope.advanceUntilIdle()
+
         verifySequence {
-            workManager.enqueue(any<WorkRequest>())
             exposureDetectionTracker.finishExposureDetection("token", TrackedExposureDetection.Result.UPDATED_STATE)
+            workManager.enqueue(any<WorkRequest>())
         }
     }
 
@@ -88,8 +94,11 @@ class ExposureStateUpdateReceiverTest : BaseTest() {
         every { intent.action } returns ExposureNotificationClient.ACTION_EXPOSURE_NOT_FOUND
         ExposureStateUpdateReceiver().onReceive(context, intent)
 
+        scope.advanceUntilIdle()
+
         verifySequence {
             exposureDetectionTracker.finishExposureDetection("token", TrackedExposureDetection.Result.NO_MATCHES)
+            workManager.enqueue(any<WorkRequest>())
         }
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleAPIVersionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleAPIVersionTest.kt
deleted file mode 100644
index 110d8cbeed2aef3b469c0355c3a848025f1faadf..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleAPIVersionTest.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-package de.rki.coronawarnapp.util
-
-import com.google.android.gms.common.api.ApiException
-import com.google.android.gms.common.api.CommonStatusCodes.API_NOT_CONNECTED
-import com.google.android.gms.common.api.Status
-import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
-import io.kotest.matchers.shouldBe
-import io.mockk.Called
-import io.mockk.coEvery
-import io.mockk.coVerify
-import io.mockk.mockkObject
-import io.mockk.unmockkObject
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.runBlockingTest
-import org.junit.jupiter.api.AfterEach
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-
-@ExperimentalCoroutinesApi
-internal class GoogleAPIVersionTest {
-
-    private lateinit var classUnderTest: GoogleAPIVersion
-
-    @BeforeEach
-    fun setUp() {
-        mockkObject(InternalExposureNotificationClient)
-        classUnderTest = GoogleAPIVersion()
-    }
-
-    @AfterEach
-    fun tearDown() {
-        unmockkObject(InternalExposureNotificationClient)
-    }
-
-    @Test
-    fun `isAbove API v16 is true for v17`() {
-        coEvery { InternalExposureNotificationClient.getVersion() } returns 17000000L
-
-        runBlockingTest {
-            classUnderTest.isAtLeast(GoogleAPIVersion.V16) shouldBe true
-        }
-    }
-
-    @Test
-    fun `isAbove API v16 is false for v15`() {
-        coEvery { InternalExposureNotificationClient.getVersion() } returns 15000000L
-
-        runBlockingTest {
-            classUnderTest.isAtLeast(GoogleAPIVersion.V16) shouldBe false
-        }
-    }
-
-    @Test
-    fun `isAbove API v16 throws IllegalArgument for invalid version`() {
-        assertThrows<IllegalArgumentException> {
-            runBlockingTest {
-                classUnderTest.isAtLeast(1L)
-            }
-            coVerify {
-                InternalExposureNotificationClient.getVersion() wasNot Called
-            }
-        }
-    }
-
-    @Test
-    fun `isAbove API v16 false when APIException for too low version`() {
-        coEvery { InternalExposureNotificationClient.getVersion() } throws
-                ApiException(Status(API_NOT_CONNECTED))
-
-        runBlockingTest {
-            classUnderTest.isAtLeast(GoogleAPIVersion.V16) shouldBe false
-        }
-    }
-}
diff --git a/Corona-Warn-App/src/test/java/testhelpers/gms/MockGMSTask.kt b/Corona-Warn-App/src/test/java/testhelpers/gms/MockGMSTask.kt
index d0ed11f4ec929f0ba4ec6ff7e89bfc832fef9f01..321a733ae210c6fa0dd2600912032fdbb4d08159 100644
--- a/Corona-Warn-App/src/test/java/testhelpers/gms/MockGMSTask.kt
+++ b/Corona-Warn-App/src/test/java/testhelpers/gms/MockGMSTask.kt
@@ -8,12 +8,12 @@ import io.mockk.mockk
 
 object MockGMSTask {
     fun <T> forError(error: Exception): Task<T> = mockk<Task<T>>().apply {
-        every { addOnSuccessListener(any()) } answers {
+        every { addOnFailureListener(any()) } answers {
             val listener = arg<OnFailureListener>(0)
             listener.onFailure(error)
             this@apply
         }
-        every { addOnFailureListener(any()) } returns this
+        every { addOnSuccessListener(any()) } returns this
     }
 
     fun <T> forValue(value: T): Task<T> = mockk<Task<T>>().apply {
diff --git a/gradle.properties b/gradle.properties
index 94936bbe11127030181ed8fc471cffd28322536d..3802281e4f1879b6ddca5ff34f9f5b3376baaee3 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -20,4 +20,4 @@ org.gradle.dependency.verification.console=verbose
 VERSION_MAJOR=1
 VERSION_MINOR=8
 VERSION_PATCH=0
-VERSION_BUILD=5
+VERSION_BUILD=7