From beaa8c93f0defb51f6d5145659785a78ace858d1 Mon Sep 17 00:00:00 2001
From: Alex Paulescu <alex.paulescu@gmail.com>
Date: Wed, 10 Mar 2021 16:29:56 +0200
Subject: [PATCH] Replace active tracing days with days since installation
 (EXPOSUREAPP-5170) (#2522)

* Added new strings.

* Implemented first install time logic.

* Adapted screens to first install time.

* Fixed layout issues in tracing settings.

* Instrumentation test fix.

* Addressed PR comments.

* Removed mstodays transformation.

* Added missing daysSinceInstallation value.

* Removed unnecessary constraint layouts.

* Fixed constraints.

* Unified text styles to subtitles.

* Over 14 days text displayed from 14 days onwards.

* Minor UI adjustments.

* Risk card not showing days since install when lowe risk encountered.

Co-authored-by: Ralf Gehrer <ralfgehrer@users.noreply.github.com>
Co-authored-by: Juraj Kusnier <jurajkusnier@users.noreply.github.com>
---
 .../coronawarnapp/ui/main/home/HomeData.kt    |   6 +-
 .../coronawarnapp/ui/tracing/TracingData.kt   |   8 +
 .../installTime/InstallTimeProvider.kt        |  19 ++
 .../tracing/states/TracingState.kt            |  11 +-
 .../tracing/states/TracingStateProvider.kt    |   8 +-
 .../ui/details/TracingDetailsItemProvider.kt  |   3 +
 .../items/periodlogged/PeriodLoggedBox.kt     |  16 +-
 .../SettingsTracingFragmentViewModel.kt       |   9 +-
 .../coronawarnapp/ui/view/CircleProgress.kt   | 168 ------------------
 .../src/main/res/drawable/ic_download.xml     |  13 ++
 .../res/layout/fragment_settings_tracing.xml  |  56 ++++--
 .../layout/tracing_content_increased_view.xml |  10 +-
 .../res/layout/tracing_content_low_view.xml   |  24 ++-
 ...tracing_details_item_periodlogged_view.xml |  79 ++++----
 .../tracing/states/LowRiskTest.kt             |   1 +
 .../details/TracingDetailsItemProviderTest.kt |  24 ++-
 16 files changed, 211 insertions(+), 244 deletions(-)
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/installTime/InstallTimeProvider.kt
 delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CircleProgress.kt
 create mode 100644 Corona-Warn-App/src/main/res/drawable/ic_download.xml

diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt
index 4839c083c..b3ee5d135 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt
@@ -42,7 +42,8 @@ object HomeData {
                 lastExposureDetectionTime = Instant.now(),
                 lastEncounterAt = null,
                 allowManualUpdate = false,
-                daysWithEncounters = 0
+                daysWithEncounters = 0,
+                daysSinceInstallation = 4,
             ),
             onCardClick = {},
             onUpdateClick = {}
@@ -55,7 +56,8 @@ object HomeData {
                 lastExposureDetectionTime = Instant.now(),
                 lastEncounterAt = Instant.now(),
                 allowManualUpdate = false,
-                daysWithEncounters = 1
+                daysWithEncounters = 1,
+                daysSinceInstallation = 4
             ),
             onCardClick = {},
             onUpdateClick = {}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingData.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingData.kt
index b5dcdc27b..a076477cb 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingData.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingData.kt
@@ -41,6 +41,7 @@ object TracingData {
             ),
 
             PeriodLoggedBox.Item(
+                daysSinceInstallation = 4,
                 tracingStatus = GeneralTracingStatus.Status.TRACING_INACTIVE
             ),
             DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
@@ -61,6 +62,7 @@ object TracingData {
                     lastExposureDetectionTime = Instant.now(),
                     allowManualUpdate = false,
                     daysWithEncounters = 0,
+                    daysSinceInstallation = 4,
                     lastEncounterAt = Instant.now()
                 )
             ),
@@ -70,6 +72,7 @@ object TracingData {
             ),
 
             PeriodLoggedBox.Item(
+                daysSinceInstallation = 4,
                 tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
             ),
             DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
@@ -90,6 +93,7 @@ object TracingData {
                     lastExposureDetectionTime = Instant.now(),
                     allowManualUpdate = false,
                     daysWithEncounters = 1,
+                    daysSinceInstallation = 4,
                     lastEncounterAt = Instant.now()
                 )
             ),
@@ -99,6 +103,7 @@ object TracingData {
             ),
 
             PeriodLoggedBox.Item(
+                daysSinceInstallation = 4,
                 tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
             ),
             DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
@@ -119,6 +124,7 @@ object TracingData {
                     lastExposureDetectionTime = Instant.now(),
                     allowManualUpdate = false,
                     daysWithEncounters = 2,
+                    daysSinceInstallation = 4,
                     lastEncounterAt = Instant.now()
                 )
             ),
@@ -128,6 +134,7 @@ object TracingData {
             ),
 
             PeriodLoggedBox.Item(
+                daysSinceInstallation = 4,
                 tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
             ),
             DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
@@ -153,6 +160,7 @@ object TracingData {
             ),
             BehaviorIncreasedRiskBox.Item,
             PeriodLoggedBox.Item(
+                daysSinceInstallation = 5,
                 tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
             ),
             DetailsIncreasedRiskBox.Item(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/installTime/InstallTimeProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/installTime/InstallTimeProvider.kt
new file mode 100644
index 000000000..9aa763874
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/installTime/InstallTimeProvider.kt
@@ -0,0 +1,19 @@
+package de.rki.coronawarnapp.installTime
+
+import android.content.Context
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.roundUpMsToDays
+import de.rki.coronawarnapp.util.di.AppContext
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class InstallTimeProvider @Inject constructor(
+    @AppContext private val context: Context
+) {
+    private val installTime: Long = context
+        .packageManager
+        .getPackageInfo(context.packageName, 0)
+        .firstInstallTime
+
+    val daysSinceInstallation: Long get() = (System.currentTimeMillis() - installTime).roundUpMsToDays()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingState.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingState.kt
index 35b60f17d..0c5b12843 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingState.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingState.kt
@@ -84,8 +84,6 @@ data class IncreasedRisk(
             lastEncounterAt.toLocalDate().toString(DateTimeFormat.mediumDate())
         )
     }
-
-    fun getProgressColorHighRisk(context: Context) = context.getColorCompat(R.color.colorStableLight)
 }
 
 // tracing_content_low_view
@@ -95,7 +93,8 @@ data class LowRisk(
     val lastExposureDetectionTime: Instant?,
     val lastEncounterAt: Instant?,
     val allowManualUpdate: Boolean,
-    val daysWithEncounters: Int
+    val daysWithEncounters: Int,
+    val daysSinceInstallation: Long
 ) : TracingState() {
 
     val showUpdateButton: Boolean = allowManualUpdate && !isInDetailsMode
@@ -131,6 +130,12 @@ data class LowRisk(
         )
     }
 
+    fun getDaysSinceInstall(context: Context): String =
+        context.getString(R.string.risk_card_body_days_since_installation)
+            .format(daysSinceInstallation)
+
+    fun appInstalledForOverTwoWeeks(): Boolean = daysSinceInstallation < 14 && lastEncounterAt == null
+
     fun getRiskContactLast(context: Context): String? {
         if (lastEncounterAt == null) return null
         // caution! lastEncounterAt is null after migration from 1.7.x -> 1.8.x
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingStateProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingStateProvider.kt
index 2e7017757..c5168a647 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingStateProvider.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingStateProvider.kt
@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.tracing.states
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import de.rki.coronawarnapp.installTime.InstallTimeProvider
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.latestSubmission
 import de.rki.coronawarnapp.risk.RiskState
@@ -25,9 +26,9 @@ class TracingStateProvider @AssistedInject constructor(
     backgroundModeStatus: BackgroundModeStatus,
     tracingRepository: TracingRepository,
     riskLevelStorage: RiskLevelStorage,
-    exposureDetectionTracker: ExposureDetectionTracker
+    exposureDetectionTracker: ExposureDetectionTracker,
+    installTimeProvider: InstallTimeProvider
 ) {
-
     val state: Flow<TracingState> = combine(
         tracingStatus.generalStatus.onEach {
             Timber.v("tracingStatus: $it")
@@ -72,7 +73,8 @@ class TracingStateProvider @AssistedInject constructor(
                 lastExposureDetectionTime = latestSubmission?.startedAt,
                 lastEncounterAt = latestCalc.lastRiskEncounterAt,
                 daysWithEncounters = latestCalc.daysWithEncounters,
-                allowManualUpdate = !isBackgroundJobEnabled
+                allowManualUpdate = !isBackgroundJobEnabled,
+                daysSinceInstallation = installTimeProvider.daysSinceInstallation
             )
             latestCalc.riskState == RiskState.INCREASED_RISK -> IncreasedRisk(
                 isInDetailsMode = isDetailsMode,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProvider.kt
index 68ffdbac5..41de9b928 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProvider.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProvider.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.tracing.ui.details
 
 import dagger.Reusable
 import de.rki.coronawarnapp.datadonation.survey.Surveys
+import de.rki.coronawarnapp.installTime.InstallTimeProvider
 import de.rki.coronawarnapp.risk.RiskState
 import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
 import de.rki.coronawarnapp.risk.tryLatestResultsWithDefaults
@@ -29,6 +30,7 @@ import javax.inject.Inject
 class TracingDetailsItemProvider @Inject constructor(
     tracingStatus: GeneralTracingStatus,
     riskLevelStorage: RiskLevelStorage,
+    installTimeProvider: InstallTimeProvider,
     surveys: Surveys
 ) {
 
@@ -68,6 +70,7 @@ class TracingDetailsItemProvider @Inject constructor(
 
             if (latestCalc.riskState != RiskState.CALCULATION_FAILED && status != Status.TRACING_INACTIVE) {
                 PeriodLoggedBox.Item(
+                    daysSinceInstallation = installTimeProvider.daysSinceInstallation,
                     tracingStatus = status
                 ).also { add(it) }
             }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/periodlogged/PeriodLoggedBox.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/periodlogged/PeriodLoggedBox.kt
index 985a26953..beb754001 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/periodlogged/PeriodLoggedBox.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/periodlogged/PeriodLoggedBox.kt
@@ -8,7 +8,6 @@ import de.rki.coronawarnapp.databinding.TracingDetailsItemPeriodloggedViewBindin
 import de.rki.coronawarnapp.tracing.GeneralTracingStatus
 import de.rki.coronawarnapp.tracing.ui.details.TracingDetailsAdapter
 import de.rki.coronawarnapp.tracing.ui.details.items.DetailsItem
-import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat
 
 class PeriodLoggedBox(
     parent: ViewGroup,
@@ -34,15 +33,18 @@ class PeriodLoggedBox(
     }
 
     data class Item(
+        val daysSinceInstallation: Long,
         val tracingStatus: GeneralTracingStatus.Status
     ) : DetailsItem {
 
-        fun getProgressColor(context: Context) = when (tracingStatus) {
-            GeneralTracingStatus.Status.TRACING_INACTIVE,
-            GeneralTracingStatus.Status.BLUETOOTH_DISABLED,
-            GeneralTracingStatus.Status.LOCATION_DISABLED -> R.color.colorTextPrimary2
-            GeneralTracingStatus.Status.TRACING_ACTIVE -> R.color.colorAccentTintIcon
-        }.let { context.getColorCompat(it) }
+        fun getInstallTimePeriodLogged(context: Context): String =
+            if (daysSinceInstallation < 14L) {
+                context.getString(
+                    R.string.risk_details_information_body_period_logged_assessment_under_14_days
+                ).format(daysSinceInstallation)
+            } else context.getString(
+                R.string.risk_details_information_body_period_logged_assessment_over_14_days
+            )
 
         override val stableId: Long
             get() = Item::class.java.name.hashCode().toLong()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragmentViewModel.kt
index 37a9cdd1e..76af2958e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragmentViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragmentViewModel.kt
@@ -10,6 +10,7 @@ import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.reporting.report
+import de.rki.coronawarnapp.installTime.InstallTimeProvider
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.nearby.TracingPermissionHelper
 import de.rki.coronawarnapp.tracing.GeneralTracingStatus
@@ -31,12 +32,18 @@ import timber.log.Timber
 class SettingsTracingFragmentViewModel @AssistedInject constructor(
     dispatcherProvider: DispatcherProvider,
     tracingStatus: GeneralTracingStatus,
+    installTimeProvider: InstallTimeProvider,
     private val backgroundStatus: BackgroundModeStatus,
     tracingPermissionHelperFactory: TracingPermissionHelper.Factory
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
     val loggingPeriod: LiveData<PeriodLoggedBox.Item> =
-        tracingStatus.generalStatus.map { PeriodLoggedBox.Item(it) }
+        tracingStatus.generalStatus.map {
+            PeriodLoggedBox.Item(
+                daysSinceInstallation = installTimeProvider.daysSinceInstallation,
+                tracingStatus = it
+            )
+        }
             .onEach { Timber.v("logginPeriod onEach") }
             .asLiveData(dispatcherProvider.Main)
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CircleProgress.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CircleProgress.kt
deleted file mode 100644
index 455b50499..000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CircleProgress.kt
+++ /dev/null
@@ -1,168 +0,0 @@
-package de.rki.coronawarnapp.ui.view
-
-import android.content.Context
-import android.graphics.Canvas
-import android.graphics.Color
-import android.graphics.Paint
-import android.graphics.RectF
-import android.util.AttributeSet
-import android.view.LayoutInflater
-import android.view.View
-import android.widget.FrameLayout
-import androidx.core.content.ContextCompat
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.databinding.ViewCircleProgressBinding
-import de.rki.coronawarnapp.risk.TimeVariables
-
-/**
- * Used on the tracing details fragment without text and also on the risk card with the progress
- * number in the circle.
- *
- * @param context
- * @param attrs
- * @param defStyleAttr
- */
-class CircleProgress @JvmOverloads constructor(
-    context: Context,
-    attrs: AttributeSet? = null,
-    defStyleAttr: Int = 0
-) : FrameLayout(context, attrs, defStyleAttr) {
-    companion object {
-        private const val START_ANGLE = 270f
-        private const val FULL_CIRCLE = 360f
-        private const val DEFAULT_WIDTH = 10f
-        private val DEFAULT_MAX_PROGRESS = TimeVariables.getDefaultRetentionPeriodInDays().toFloat()
-    }
-
-    private val circlePaint: Paint
-    private var progressPaint: Paint
-    private val rect = RectF()
-    private var binding: ViewCircleProgressBinding
-    private var centerX: Float = 0f
-    private var centerY: Float = 0f
-    private var radius: Float = 0f
-    private var progressWidth: Float = 0f
-    private var disableText: Boolean = false
-
-    /**
-     * Setter for progress. Text and icon depend on the progress value.
-     * The visibility is also influenced by the disableText attribute.
-     */
-    var progress: Float = 0F
-        set(value) {
-            field = value
-            val body = binding.circleProgressBody
-            val icon = binding.circleProgressIcon
-            // text visibility
-            if (disableText || value == DEFAULT_MAX_PROGRESS) {
-                body.visibility = View.GONE
-            } else {
-                body.visibility = View.VISIBLE
-                body.text = context.getString(R.string.risk_details_information_active_tracing_days_circle_progress)
-                    .format(value.toInt())
-            }
-            // icon visibility
-            if (value == DEFAULT_MAX_PROGRESS) {
-                icon.visibility = View.VISIBLE
-            } else {
-                icon.visibility = View.GONE
-            }
-            invalidate()
-        }
-
-    /**
-     * Setter for the progress circle color.
-     * The progress bar also needs to be repainted when the
-     * color changes (ex: when the risk calculation gets turned on/off)
-     */
-    var progressColor: Int = Color.TRANSPARENT
-        set(value) {
-            field = value
-            binding.circleProgressIcon.setColorFilter(value, android.graphics.PorterDuff.Mode.SRC_IN)
-            progressPaint = paintProgressCircle()
-            invalidate()
-        }
-
-    /**
-     * Initialise the view with the following attributes or some default values:
-     * - circleColor
-     * - textColor
-     * - disableText
-     * - progressWidth
-     */
-    init {
-        setWillNotDraw(false)
-        binding = ViewCircleProgressBinding.inflate(LayoutInflater.from(context), this)
-        val styleAttrs = context.obtainStyledAttributes(attrs, R.styleable.CircleProgress)
-        val circleColor = styleAttrs.getColor(
-            R.styleable.CircleProgress_circleColor,
-            ContextCompat.getColor(context, R.color.colorSurface2)
-        )
-        // attribute progressColor; default = colorAccentTintIcon
-        val progressColor = styleAttrs.getColor(
-            R.styleable.CircleProgress_progressColor,
-            ContextCompat.getColor(context, R.color.colorAccentTintIcon)
-        )
-        // attribute textColor; default = colorTextPrimary2
-        val textColor = styleAttrs.getColor(
-            R.styleable.CircleProgress_textColor,
-            ContextCompat.getColor(context, R.color.colorTextPrimary2)
-        )
-        // attribute disableText; default = true
-        disableText = styleAttrs.getBoolean(R.styleable.CircleProgress_disableText, false)
-        // attribute progressWidth; default = DEFAULT_WIDTH
-        progressWidth = styleAttrs.getFloat(R.styleable.CircleProgress_circleWidth, DEFAULT_WIDTH)
-        // attribute progress; default = 0
-        progress = styleAttrs.getFloat(R.styleable.CircleProgress_progress, 0F)
-        // set textColor
-        val body = binding.circleProgressBody
-        body.setTextColor(textColor)
-        // set icon color
-        val icon = binding.circleProgressIcon
-        icon.setColorFilter(progressColor, android.graphics.PorterDuff.Mode.SRC_IN)
-        // circlePaint based on the attributes and default value
-        circlePaint = Paint().apply {
-            color = circleColor
-            style = Paint.Style.STROKE
-            strokeWidth = progressWidth
-            isAntiAlias = true
-        }
-        // progressPaint based on the attributes and default value
-        progressPaint = paintProgressCircle()
-        styleAttrs.recycle()
-    }
-
-    private fun paintProgressCircle() =
-        Paint().apply {
-            color = progressColor
-            style = Paint.Style.STROKE
-            strokeWidth = progressWidth
-            isAntiAlias = true
-            strokeCap = Paint.Cap.ROUND
-        }
-
-    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
-        centerX = w.toFloat().div(2)
-        centerY = h.toFloat().div(2)
-        radius = w.toFloat().div(2).minus(progressWidth)
-        rect.set(
-            centerX.minus(radius),
-            centerY.minus(radius),
-            centerX.plus(radius),
-            centerY.plus(radius)
-        )
-        super.onSizeChanged(w, h, oldw, oldh)
-    }
-
-    override fun onDraw(canvas: Canvas?) {
-        super.onDraw(canvas)
-        canvas?.drawCircle(centerX, centerY, radius, circlePaint)
-        canvas?.drawArc(
-            rect,
-            START_ANGLE,
-            FULL_CIRCLE.times(progress).div(DEFAULT_MAX_PROGRESS),
-            false,
-            progressPaint
-        )
-    }
-}
diff --git a/Corona-Warn-App/src/main/res/drawable/ic_download.xml b/Corona-Warn-App/src/main/res/drawable/ic_download.xml
new file mode 100644
index 000000000..17573ee7c
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/ic_download.xml
@@ -0,0 +1,13 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="40dp"
+    android:height="42dp"
+    android:viewportWidth="37"
+    android:viewportHeight="39">
+    <group
+        android:translateX="8.5"
+        android:translateY="8.5">
+        <path
+            android:fillColor="#ffffff"
+            android:pathData="M10,2.0132C14.41,2.0132 18,5.6032 18,10.0132C18,14.4232 14.41,18.0132 10,18.0132C5.59,18.0132 2,14.4232 2,10.0132C2,5.6032 5.59,2.0132 10,2.0132ZM10,0.0132C4.48,0.0132 0,4.4932 0,10.0132C0,15.5332 4.48,20.0132 10,20.0132C15.52,20.0132 20,15.5332 20,10.0132C20,4.4932 15.52,0.0132 10,0.0132ZM11,10.0132V6.0132H9V10.0132H6L10,14.0132L14,10.0132H11Z" />
+    </group>
+</vector>
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml b/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml
index 617cb80e2..de95af036 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml
@@ -169,8 +169,8 @@
                         app:buttonText="@{@string/settings_tracing_status_location_button}"
                         app:headline="@{@string/settings_tracing_status_location_headline}"
                         app:icon="@{@drawable/ic_location}"
-                        app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
-                        app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
+                        app:layout_constraintEnd_toStartOf="@id/guideline_card_end"
+                        app:layout_constraintStart_toStartOf="@id/guideline_card_start"
                         app:layout_constraintTop_toTopOf="parent" />
 
                     <include
@@ -183,22 +183,58 @@
                         app:buttonText="@{@string/settings_tracing_status_bluetooth_button}"
                         app:headline="@{@string/settings_tracing_status_bluetooth_headline}"
                         app:icon="@{@drawable/ic_settings_tracing_bluetooth}"
-                        app:layout_constraintEnd_toStartOf="@+id/guideline_card_end"
-                        app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
+                        app:layout_constraintEnd_toStartOf="@id/guideline_card_end"
+                        app:layout_constraintStart_toStartOf="@id/guideline_card_start"
                         app:layout_constraintTop_toTopOf="parent" />
 
                     <TextView
-                        android:id="@+id/risk_details_period_logged_body_notice"
-                        style="@style/subtitleMedium"
-                        gone="@{!settingsTracingState.isTracingStatusTextVisible()}"
+                        android:id="@+id/risk_details_period_logged_headline"
+                        style="@style/headline5"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:focusable="false"
+                        android:text="@string/risk_details_headline_period_logged"
+                        app:layout_constraintEnd_toStartOf="@id/guideline_end"
+                        app:layout_constraintStart_toStartOf="@id/guideline_start"
+                        app:layout_constraintTop_toBottomOf="@id/settings_tracing_status_bluetooth" />
+
+                    <TextView
+                        android:id="@+id/risk_details_period_logged_subtitle"
+                        style="@style/subtitle"
                         android:layout_width="0dp"
                         android:layout_height="wrap_content"
                         android:layout_marginTop="@dimen/spacing_tiny"
+                        android:focusable="false"
+                        android:text="@string/risk_details_subtitle_period_logged"
+                        app:layout_constraintEnd_toStartOf="@id/guideline_end"
+                        app:layout_constraintStart_toStartOf="@id/guideline_start"
+                        app:layout_constraintTop_toBottomOf="@id/risk_details_period_logged_headline" />
+
+                    <TextView
+                        android:id="@id/risk_details_period_logged_body_notice"
+                        style="@style/subtitle"
+                        gone="@{!settingsTracingState.isTracingStatusTextVisible()}"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_marginTop="@dimen/spacing_normal"
                         android:focusable="true"
                         android:text="@string/risk_details_information_body_period_logged"
-                        app:layout_constraintEnd_toStartOf="@+id/guideline_end"
-                        app:layout_constraintStart_toStartOf="@+id/guideline_start"
-                        app:layout_constraintTop_toBottomOf="@+id/settings_tracing_status_bluetooth" />
+                        app:layout_constraintEnd_toStartOf="@id/guideline_end"
+                        app:layout_constraintStart_toStartOf="@id/guideline_start"
+                        app:layout_constraintTop_toBottomOf="@id/risk_details_period_logged_subtitle" />
+
+                    <TextView
+                        android:id="@+id/risk_details_period_logged_days"
+                        style="@style/subtitle"
+                        gone="@{!settingsTracingState.isTracingStatusTextVisible()}"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_marginTop="@dimen/spacing_normal"
+                        android:focusable="true"
+                        android:text="@{loggedPeriod.getInstallTimePeriodLogged(context)}"
+                        app:layout_constraintEnd_toStartOf="@id/guideline_end"
+                        app:layout_constraintStart_toStartOf="@id/guideline_start"
+                        app:layout_constraintTop_toBottomOf="@id/risk_details_period_logged_body_notice" />
 
                     <include layout="@layout/merge_guidelines_card" />
 
diff --git a/Corona-Warn-App/src/main/res/layout/tracing_content_increased_view.xml b/Corona-Warn-App/src/main/res/layout/tracing_content_increased_view.xml
index 2d2c4b51f..12af62996 100644
--- a/Corona-Warn-App/src/main/res/layout/tracing_content_increased_view.xml
+++ b/Corona-Warn-App/src/main/res/layout/tracing_content_increased_view.xml
@@ -24,7 +24,7 @@
             android:accessibilityHeading="true"
             android:text="@string/risk_card_increased_risk_headline"
             android:textColor="@color/colorTextPrimary1InvertedStable"
-            app:layout_constraintEnd_toStartOf="@+id/details_icon"
+            app:layout_constraintEnd_toStartOf="@id/details_icon"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent"
             app:layout_goneMarginEnd="0dp" />
@@ -52,7 +52,7 @@
             app:compatIconTint="@color/colorStableLight"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/headline"
+            app:layout_constraintTop_toBottomOf="@id/headline"
             tools:text="@plurals/risk_card_high_risk_encounter_days_body" />
 
         <de.rki.coronawarnapp.ui.view.TracingCardInfoRow
@@ -66,7 +66,7 @@
             app:compatIconTint="@color/colorStableLight"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/row_contact"
+            app:layout_constraintTop_toBottomOf="@id/row_contact"
             tools:text="@string/risk_card_high_risk_most_recent_body_encounters_on_more_than_one_day" />
 
         <androidx.constraintlayout.widget.ConstraintLayout
@@ -90,7 +90,7 @@
             app:compatIconTint="@color/colorStableLight"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/row_tracing_days"
+            app:layout_constraintTop_toBottomOf="@id/row_contact_last"
             tools:text="@string/risk_card_body_not_yet_fetched" />
 
         <Button
@@ -103,7 +103,7 @@
             android:text="@string/risk_card_button_update"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/row_time_fetched" />
+            app:layout_constraintTop_toBottomOf="@id/row_time_fetched" />
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 </layout>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/layout/tracing_content_low_view.xml b/Corona-Warn-App/src/main/res/layout/tracing_content_low_view.xml
index 048ee99fe..1fbb229ef 100644
--- a/Corona-Warn-App/src/main/res/layout/tracing_content_low_view.xml
+++ b/Corona-Warn-App/src/main/res/layout/tracing_content_low_view.xml
@@ -24,7 +24,7 @@
             android:accessibilityHeading="true"
             android:text="@string/risk_card_low_risk_headline"
             android:textColor="@color/colorTextPrimary1InvertedStable"
-            app:layout_constraintEnd_toStartOf="@+id/details_icon"
+            app:layout_constraintEnd_toStartOf="@id/details_icon"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent"
             app:layout_goneMarginEnd="0dp"
@@ -55,7 +55,7 @@
             app:compatIconTint="@color/colorStableLight"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/headline"
+            app:layout_constraintTop_toBottomOf="@id/headline"
             tools:text="@plurals/risk_card_low_risk_encounter_days_body" />
 
         <de.rki.coronawarnapp.ui.view.TracingCardInfoRow
@@ -69,9 +69,23 @@
             app:compatIconTint="@color/colorStableLight"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/row_contact"
+            app:layout_constraintTop_toBottomOf="@id/row_contact"
             tools:text="@string/risk_card_low_risk_most_recent_body_encounters_on_more_than_one_day" />
 
+        <de.rki.coronawarnapp.ui.view.TracingCardInfoRow
+            android:id="@+id/row_days_since_installation"
+            gone="@{!state.appInstalledForOverTwoWeeks()}"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:icon="@drawable/ic_download"
+            android:text="@{state.getDaysSinceInstall(context)}"
+            android:textColor="@color/colorTextPrimary1InvertedStable"
+            app:compatIconTint="@color/colorStableLight"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/row_contact_last"
+            tools:text="@string/risk_card_body_days_since_installation" />
+
         <de.rki.coronawarnapp.ui.view.TracingCardInfoRow
             android:id="@+id/row_time_fetched"
             android:layout_width="0dp"
@@ -82,7 +96,7 @@
             app:compatIconTint="@color/colorStableLight"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/row_contact_last"
+            app:layout_constraintTop_toBottomOf="@id/row_days_since_installation"
             tools:text="@string/risk_card_body_not_yet_fetched" />
 
         <Button
@@ -95,7 +109,7 @@
             android:text="@string/risk_card_button_update"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/row_time_fetched" />
+            app:layout_constraintTop_toBottomOf="@id/row_time_fetched" />
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 </layout>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/layout/tracing_details_item_periodlogged_view.xml b/Corona-Warn-App/src/main/res/layout/tracing_details_item_periodlogged_view.xml
index d89197811..b6a1b70d3 100644
--- a/Corona-Warn-App/src/main/res/layout/tracing_details_item_periodlogged_view.xml
+++ b/Corona-Warn-App/src/main/res/layout/tracing_details_item_periodlogged_view.xml
@@ -15,50 +15,51 @@
         android:focusable="true"
         android:padding="@dimen/card_padding">
 
-        <androidx.constraintlayout.widget.ConstraintLayout
-            android:id="@+id/risk_details_period_logged_layout"
-            android:layout_width="match_parent"
+        <TextView
+            android:id="@+id/risk_details_period_logged_headline"
+            style="@style/headline5"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:focusable="true"
+            android:focusable="false"
+            android:text="@string/risk_details_headline_period_logged"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="parent">
+            app:layout_constraintTop_toTopOf="parent" />
 
-            <TextView
-                android:id="@+id/risk_details_period_logged_headline"
-                style="@style/headline5"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:focusable="false"
-                android:text="@string/risk_details_headline_period_logged"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toTopOf="parent" />
+        <TextView
+            android:id="@+id/risk_details_period_logged_subtitle"
+            style="@style/subtitle"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/spacing_tiny"
+            android:focusable="false"
+            android:text="@string/risk_details_subtitle_period_logged"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/risk_details_period_logged_headline" />
 
-            <TextView
-                android:id="@+id/risk_details_period_logged_subtitle"
-                style="@style/subtitle"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="@dimen/spacing_tiny"
-                android:focusable="false"
-                android:text="@string/risk_details_subtitle_period_logged"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toBottomOf="@id/risk_details_period_logged_headline" />
+        <TextView
+            android:id="@+id/risk_details_period_logged_body_notice"
+            style="@style/subtitle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/spacing_normal"
+            android:focusable="true"
+            android:text="@string/risk_details_information_body_period_logged"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/risk_details_period_logged_subtitle" />
 
-            <TextView
-                android:id="@+id/risk_details_period_logged_body_notice"
-                style="@style/body1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="@dimen/spacing_normal"
-                android:focusable="true"
-                android:text="@string/risk_details_information_body_period_logged"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toBottomOf="@id/risk_details_period_logged_subtitle" />
-        </androidx.constraintlayout.widget.ConstraintLayout>
+        <TextView
+            style="@style/subtitle"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/spacing_normal"
+            android:text="@{loggedPeriod.getInstallTimePeriodLogged(context)}"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/risk_details_period_logged_body_notice"
+            tools:text="@string/risk_details_information_body_period_logged_assessment_under_14_days" />
 
     </androidx.constraintlayout.widget.ConstraintLayout>
-</layout>
\ No newline at end of file
+</layout>
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/states/LowRiskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/states/LowRiskTest.kt
index 8fb93b6e4..3bc2c760b 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/states/LowRiskTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/states/LowRiskTest.kt
@@ -32,6 +32,7 @@ internal class LowRiskTest {
         lastExposureDetectionTime = Instant.now(),
         allowManualUpdate = false,
         daysWithEncounters = 0,
+        daysSinceInstallation = 4,
         lastEncounterAt = null
     )
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProviderTest.kt
index 73be55667..4cc268ca6 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProviderTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProviderTest.kt
@@ -4,6 +4,7 @@ import android.content.Context
 import android.content.res.Resources
 import com.google.android.gms.nearby.exposurenotification.ExposureWindow
 import de.rki.coronawarnapp.datadonation.survey.Surveys
+import de.rki.coronawarnapp.installTime.InstallTimeProvider
 import de.rki.coronawarnapp.risk.ProtoRiskLevel
 import de.rki.coronawarnapp.risk.RiskLevelTaskResult
 import de.rki.coronawarnapp.risk.result.AggregatedRiskResult
@@ -17,6 +18,7 @@ import de.rki.coronawarnapp.tracing.ui.details.items.riskdetails.DetailsFailedCa
 import de.rki.coronawarnapp.tracing.ui.details.items.riskdetails.DetailsIncreasedRiskBox
 import de.rki.coronawarnapp.tracing.ui.details.items.riskdetails.DetailsLowRiskBox
 import de.rki.coronawarnapp.tracing.ui.details.items.survey.UserSurveyBox
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.daysToMilliseconds
 import io.kotest.matchers.ints.shouldBeGreaterThan
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
@@ -39,6 +41,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
 
     @MockK lateinit var tracingStatus: GeneralTracingStatus
     @MockK lateinit var riskLevelStorage: RiskLevelStorage
+    @MockK lateinit var installTimeProvider: InstallTimeProvider
     @MockK lateinit var surveys: Surveys
 
     @BeforeEach
@@ -50,6 +53,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
     private fun createInstance() = TracingDetailsItemProvider(
         tracingStatus = tracingStatus,
         riskLevelStorage = riskLevelStorage,
+        installTimeProvider = installTimeProvider,
         surveys = surveys
     )
 
@@ -57,10 +61,12 @@ class TracingDetailsItemProviderTest : BaseTest() {
         status: GeneralTracingStatus.Status,
         riskLevel: ProtoRiskLevel,
         matchedKeyCount: Int,
+        daysSinceInstallation: Long,
         availableSurveys: List<Surveys.Type> = emptyList()
     ) {
         every { tracingStatus.generalStatus } returns flowOf(status)
         every { aggregatedRiskResult.totalRiskLevel } returns riskLevel
+        every { installTimeProvider.daysSinceInstallation } returns daysSinceInstallation
         every { surveys.availableSurveys } returns flowOf(availableSurveys)
 
         if (riskLevel == ProtoRiskLevel.LOW) {
@@ -86,6 +92,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.LOW,
+            daysSinceInstallation = 4,
             matchedKeyCount = 1
         )
 
@@ -102,6 +109,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.LOW,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -118,6 +126,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.HIGH,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -134,6 +143,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.HIGH,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -152,6 +162,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.LOW,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -170,7 +181,8 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.LOW,
-            matchedKeyCount = 0
+            daysSinceInstallation = 4,
+            matchedKeyCount = 0,
         )
 
         val instance = createInstance()
@@ -189,6 +201,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.HIGH,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -208,6 +221,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.UNRECOGNIZED,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -227,6 +241,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_INACTIVE,
             riskLevel = ProtoRiskLevel.LOW,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -246,6 +261,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_INACTIVE,
             riskLevel = ProtoRiskLevel.LOW,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -268,6 +284,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.UNRECOGNIZED,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -290,6 +307,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.LOW,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -312,6 +330,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
         prepare(
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.HIGH,
+            daysSinceInstallation = 4,
             matchedKeyCount = 0
         )
 
@@ -335,6 +354,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.LOW,
             matchedKeyCount = 0,
+            daysSinceInstallation = 4,
             availableSurveys = listOf(Surveys.Type.HIGH_RISK_ENCOUNTER)
         )
 
@@ -355,6 +375,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.HIGH,
             matchedKeyCount = 0,
+            daysSinceInstallation = 4,
             availableSurveys = emptyList()
         )
 
@@ -375,6 +396,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
             status = GeneralTracingStatus.Status.TRACING_ACTIVE,
             riskLevel = ProtoRiskLevel.HIGH,
             matchedKeyCount = 0,
+            daysSinceInstallation = 4,
             availableSurveys = listOf(Surveys.Type.HIGH_RISK_ENCOUNTER)
         )
 
-- 
GitLab