diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/DefaultExposureWindowProvider.kt b/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/DefaultExposureWindowProvider.kt
similarity index 100%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/DefaultExposureWindowProvider.kt
rename to Corona-Warn-App/src/device/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/DefaultExposureWindowProvider.kt
diff --git a/Corona-Warn-App/src/deviceForTesters/assets/exposure-windows-increased-risk-random.json b/Corona-Warn-App/src/deviceForTesters/assets/exposure-windows-increased-risk-random.json
new file mode 100644
index 0000000000000000000000000000000000000000..544b74346319309e35780eccde28274cb969fd73
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/assets/exposure-windows-increased-risk-random.json
@@ -0,0 +1,690 @@
+[
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 2,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 299,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 2,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 2,
+    "scanInstances": [
+      {
+        "minAttenuation": 73,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 73,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 2,
+    "scanInstances": [
+      {
+        "minAttenuation": 72,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 72,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 2,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 1,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 299,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 1,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 3,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 2,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 4,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 1,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 2,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 3,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 2,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 4,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 1,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 2,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 2,
+    "calibrationConfidence": 0,
+    "infectiousness": 1,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 4,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 420,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 2,
+    "scanInstances": []
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 0,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 70,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  },
+  {
+    "ageInDays": 1,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 3,
+    "scanInstances": [
+      {
+        "minAttenuation": 70,
+        "secondsSinceLastScan": 0,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 70,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 70,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/Corona-Warn-App/src/deviceForTesters/assets/exposure-windows-lowrisk-random.json b/Corona-Warn-App/src/deviceForTesters/assets/exposure-windows-lowrisk-random.json
new file mode 100644
index 0000000000000000000000000000000000000000..675781ac432d5542f2d43c257997c715d78f3f6d
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/assets/exposure-windows-lowrisk-random.json
@@ -0,0 +1,38 @@
+[
+  {
+    "ageInDays": 1,
+    "reportType": 2,
+    "infectiousness": 2,
+    "calibrationConfidence": 0,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "typicalAttenuation": 25,
+        "secondsSinceLastScan": 300
+      },
+      {
+        "minAttenuation": 30,
+        "typicalAttenuation": 25,
+        "secondsSinceLastScan": 300
+      }
+    ]
+  },
+  {
+    "ageInDays": 4,
+    "calibrationConfidence": 0,
+    "infectiousness": 2,
+    "reportType": 1,
+    "scanInstances": [
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      },
+      {
+        "minAttenuation": 30,
+        "secondsSinceLastScan": 300,
+        "typicalAttenuation": 25
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/DefaultExposureWindowProvider.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/DefaultExposureWindowProvider.kt
new file mode 100644
index 0000000000000000000000000000000000000000..dd7306b0b1f347ba356fbbbca101f5abd95dc827
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/DefaultExposureWindowProvider.kt
@@ -0,0 +1,31 @@
+package de.rki.coronawarnapp.nearby.modules.exposurewindow
+
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import com.google.android.gms.nearby.exposurenotification.ExposureWindow
+import de.rki.coronawarnapp.storage.TestSettings
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlin.coroutines.suspendCoroutine
+
+@Singleton
+class DefaultExposureWindowProvider @Inject constructor(
+    private val client: ExposureNotificationClient,
+    private val testSettings: TestSettings,
+    private val fakeExposureWindowProvider: FakeExposureWindowProvider
+) : ExposureWindowProvider {
+
+    override suspend fun exposureWindows(): List<ExposureWindow> = suspendCoroutine { cont ->
+        when (val fakeSetting = testSettings.fakeExposureWindows.value) {
+            TestSettings.FakeExposureWindowTypes.DISABLED -> {
+                client.exposureWindows
+                    .addOnSuccessListener { cont.resume(it) }
+                    .addOnFailureListener { cont.resumeWithException(it) }
+            }
+            else -> {
+                fakeExposureWindowProvider.getExposureWindows(fakeSetting).let { cont.resume(it) }
+            }
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/FakeExposureWindowProvider.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/FakeExposureWindowProvider.kt
new file mode 100644
index 0000000000000000000000000000000000000000..086b6b5f9418d0e314743d8b07c8379a6522c5ae
--- /dev/null
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/FakeExposureWindowProvider.kt
@@ -0,0 +1,62 @@
+package de.rki.coronawarnapp.nearby.modules.exposurewindow
+
+import android.content.Context
+import com.google.android.gms.nearby.exposurenotification.ExposureWindow
+import com.google.android.gms.nearby.exposurenotification.ScanInstance
+import com.google.gson.Gson
+import com.google.gson.annotations.SerializedName
+import dagger.Reusable
+import de.rki.coronawarnapp.storage.TestSettings.FakeExposureWindowTypes
+import de.rki.coronawarnapp.util.di.AppContext
+import de.rki.coronawarnapp.util.serialization.fromJson
+import org.joda.time.Duration
+import org.joda.time.Instant
+import javax.inject.Inject
+
+@Reusable
+class FakeExposureWindowProvider @Inject constructor(
+    @AppContext val context: Context
+) {
+
+    fun getExposureWindows(testSettings: FakeExposureWindowTypes): List<ExposureWindow> {
+        val jsonInput = when (testSettings) {
+            FakeExposureWindowTypes.INCREASED_RISK_DEFAULT -> "exposure-windows-increased-risk-random.json"
+            FakeExposureWindowTypes.LOW_RISK_DEFAULT -> "exposure-windows-lowrisk-random.json"
+            else -> throw NotImplementedError()
+        }.let { context.assets.open(it) }.readBytes().toString(Charsets.UTF_8)
+        val jsonWindows: List<JsonWindow> = Gson().fromJson(jsonInput)
+
+        return jsonWindows.map { jWindow ->
+            ExposureWindow.Builder().apply {
+                setDateMillisSinceEpoch(
+                    Instant.now().minus(Duration.standardDays(jWindow.ageInDays.toLong())).millis
+                )
+                setCalibrationConfidence(jWindow.calibrationConfidence)
+                setInfectiousness(jWindow.infectiousness)
+                setReportType(jWindow.reportType)
+
+                jWindow.scanInstances.map { jScanInstance ->
+                    ScanInstance.Builder().apply {
+                        setMinAttenuationDb(jScanInstance.minAttenuation)
+                        setSecondsSinceLastScan(jScanInstance.secondsSinceLastScan)
+                        setTypicalAttenuationDb(jScanInstance.typicalAttenuation)
+                    }.build()
+                }.let { setScanInstances(it) }
+            }.build()
+        }
+    }
+}
+
+private data class JsonScanInstance(
+    @SerializedName("minAttenuation") val minAttenuation: Int,
+    @SerializedName("secondsSinceLastScan") val secondsSinceLastScan: Int,
+    @SerializedName("typicalAttenuation") val typicalAttenuation: Int
+)
+
+private data class JsonWindow(
+    @SerializedName("ageInDays") val ageInDays: Int,
+    @SerializedName("calibrationConfidence") val calibrationConfidence: Int,
+    @SerializedName("infectiousness") val infectiousness: Int,
+    @SerializedName("reportType") val reportType: Int,
+    @SerializedName("scanInstances") val scanInstances: List<JsonScanInstance>
+)
diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt
index b0e40407ce9b0895cc283865456e43f7303882d0..7087a044d87e8f1341a2ec5b785883fa78d8bc5e 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt
@@ -2,12 +2,17 @@ package de.rki.coronawarnapp.test.risklevel.ui
 
 import android.os.Bundle
 import android.view.View
+import android.widget.RadioButton
+import android.widget.RadioGroup
 import android.widget.Toast
+import androidx.core.view.ViewCompat
+import androidx.core.view.children
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
 import androidx.navigation.fragment.navArgs
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentTestRiskLevelCalculationBinding
+import de.rki.coronawarnapp.storage.TestSettings
 import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
 import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel
 import de.rki.coronawarnapp.util.di.AutoInject
@@ -79,6 +84,37 @@ class TestRiskLevelCalculationFragment : Fragment(R.layout.fragment_test_risk_le
         vm.backendParameters.observe2(this) {
             binding.labelBackendParameters.text = it
         }
+
+        vm.fakeWindowsState.observe2(this) { currentType ->
+            binding.apply {
+                if (fakeWindowsToggleGroup.childCount != TestSettings.FakeExposureWindowTypes.values().size) {
+                    fakeWindowsToggleGroup.removeAllViews()
+                    TestSettings.FakeExposureWindowTypes.values().forEach { type ->
+                        RadioButton(requireContext()).apply {
+                            id = ViewCompat.generateViewId()
+                            text = type.name
+                            layoutParams = RadioGroup.LayoutParams(
+                                RadioGroup.LayoutParams.MATCH_PARENT,
+                                RadioGroup.LayoutParams.WRAP_CONTENT
+                            )
+                            fakeWindowsToggleGroup.addView(this)
+                        }
+                    }
+                }
+
+                fakeWindowsToggleGroup.children.forEach {
+                    it as RadioButton
+                    it.isChecked = it.text == currentType.name
+                }
+            }
+        }
+        binding.fakeWindowsToggleGroup.apply {
+            setOnCheckedChangeListener { group, checkedId ->
+                val chip = group.findViewById<RadioButton>(checkedId)
+                if (!chip.isPressed) return@setOnCheckedChangeListener
+                vm.selectFakeExposureWindowMode(TestSettings.FakeExposureWindowTypes.valueOf(chip.text.toString()))
+            }
+        }
     }
 
     companion object {
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 35c5e63f9b8c3f63e4c06d605c7b1ec59e867b08..dd93a0e154d8e7ece32be12a0984a78c197c3560 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
@@ -21,6 +21,7 @@ import de.rki.coronawarnapp.storage.AppDatabase
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.storage.RiskLevelRepository
 import de.rki.coronawarnapp.storage.SubmissionRepository
+import de.rki.coronawarnapp.storage.TestSettings
 import de.rki.coronawarnapp.task.TaskController
 import de.rki.coronawarnapp.task.common.DefaultTaskRequest
 import de.rki.coronawarnapp.task.submitBlocking
@@ -51,11 +52,14 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
     private val keyCacheRepository: KeyCacheRepository,
     private val appConfigProvider: AppConfigProvider,
     tracingCardStateProvider: TracingCardStateProvider,
-    private val exposureResultStore: ExposureResultStore
+    private val exposureResultStore: ExposureResultStore,
+    private val testSettings: TestSettings
 ) : CWAViewModel(
     dispatcherProvider = dispatcherProvider
 ) {
 
+    val fakeWindowsState = testSettings.fakeExposureWindows.flow.asLiveData()
+
     init {
         Timber.d("CWAViewModel: %s", this)
         Timber.d("SavedStateHandle: %s", handle)
@@ -219,6 +223,10 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
         launch { keyCacheRepository.clear() }
     }
 
+    fun selectFakeExposureWindowMode(newMode: TestSettings.FakeExposureWindowTypes) {
+        testSettings.fakeExposureWindows.update { newMode }
+    }
+
     @AssistedInject.Factory
     interface Factory : CWAViewModelFactory<TestRiskLevelCalculationFragmentCWAViewModel> {
         fun create(
diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_risk_level_calculation.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_risk_level_calculation.xml
index 7d94e7c3dca3a8e044acb4aac523109b7266aa7c..905ec558113eefa6b4b968a4abe5aec506b7b7b4 100644
--- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_risk_level_calculation.xml
+++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_risk_level_calculation.xml
@@ -34,23 +34,44 @@
             android:layout_height="wrap_content"
             android:orientation="vertical">
 
-            <TextView
-                style="@style/headline6"
-                android:accessibilityHeading="true"
+            <androidx.constraintlayout.widget.ConstraintLayout
+                android:id="@+id/environment_container"
+                style="@style/card"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:text="Preview (no interaction possible)" />
+                android:layout_height="wrap_content">
+
+                <TextView
+                    android:id="@+id/fake_windows_title"
+                    style="@style/headline6"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="Fake exposure windows"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+                <RadioGroup
+                    android:id="@+id/fake_windows_toggle_group"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/spacing_tiny"
+                    android:orientation="vertical"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toBottomOf="@+id/fake_windows_title" />
+            </androidx.constraintlayout.widget.ConstraintLayout>
 
             <FrameLayout
                 android:id="@+id/test_risk_card"
                 style="@style/card"
+                gone="@{showRiskStatusCard == null || !showRiskStatusCard}"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginTop="@dimen/spacing_normal"
-                gone="@{showRiskStatusCard == null || !showRiskStatusCard}"
-                android:focusable="true"
                 android:backgroundTint="@{tracingCard.getRiskInfoContainerBackgroundTint(context)}"
-                android:backgroundTintMode="src_over">
+                android:backgroundTintMode="src_over"
+                android:focusable="true">
 
                 <include
                     android:id="@+id/risk_card_content"
@@ -94,10 +115,10 @@
             <TextView
                 android:id="@+id/label_aggregated_risk_result_title"
                 style="@style/headline6"
-                android:accessibilityHeading="true"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginTop="@dimen/spacing_normal"
+                android:accessibilityHeading="true"
                 android:text="Aggregated Risk Result" />
 
             <TextView
@@ -109,9 +130,9 @@
             <TextView
                 android:id="@+id/label_risk_additional_info_title"
                 style="@style/headline6"
-                android:accessibilityHeading="true"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:accessibilityHeading="true"
                 android:text="Risk Calculation Additional Information" />
 
             <TextView
@@ -123,9 +144,9 @@
             <TextView
                 android:id="@+id/label_backend_parameters_title"
                 style="@style/headline6"
-                android:accessibilityHeading="true"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:accessibilityHeading="true"
                 android:text="Backend Parameters" />
 
             <TextView
@@ -137,9 +158,9 @@
             <TextView
                 android:id="@+id/label_exposure_window_title"
                 style="@style/headline6"
-                android:accessibilityHeading="true"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:accessibilityHeading="true"
                 android:text="Exposure Windows" />
 
             <TextView
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TestSettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TestSettings.kt
index 261fd5fcacf20a08176f1db87dbc42bb1e44b8a1..5f9b38fcb3cf3949be5d8fbd5af640560911d62c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TestSettings.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TestSettings.kt
@@ -1,14 +1,19 @@
 package de.rki.coronawarnapp.storage
 
 import android.content.Context
+import com.google.gson.Gson
+import com.google.gson.annotations.SerializedName
 import de.rki.coronawarnapp.util.di.AppContext
+import de.rki.coronawarnapp.util.preferences.FlowPreference
 import de.rki.coronawarnapp.util.preferences.createFlowPreference
+import de.rki.coronawarnapp.util.serialization.BaseGson
 import javax.inject.Inject
 import javax.inject.Singleton
 
 @Singleton
 class TestSettings @Inject constructor(
-    @AppContext private val context: Context
+    @AppContext private val context: Context,
+    @BaseGson private val gson: Gson
 ) {
     private val prefs by lazy {
         context.getSharedPreferences("test_settings", Context.MODE_PRIVATE)
@@ -18,4 +23,22 @@ class TestSettings @Inject constructor(
         key = "connections.metered.fake",
         defaultValue = false
     )
+
+    val fakeExposureWindows = FlowPreference(
+        preferences = prefs,
+        key = "riskleve.exposurewindows.fake",
+        reader = FlowPreference.gsonReader<FakeExposureWindowTypes>(gson, FakeExposureWindowTypes.DISABLED),
+        writer = FlowPreference.gsonWriter(gson)
+    )
+
+    enum class FakeExposureWindowTypes {
+        @SerializedName("DISABLED")
+        DISABLED,
+
+        @SerializedName("INCREASED_RISK_DEFAULT")
+        INCREASED_RISK_DEFAULT,
+
+        @SerializedName("LOW_RISK_DEFAULT")
+        LOW_RISK_DEFAULT
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/TestSettingsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/TestSettingsTest.kt
index f904964bfddde385950bac6c95efad7247fda59b..75dd982d0f4a0bc20c580e3bdc0bd08bf693e334 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/TestSettingsTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/TestSettingsTest.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.storage
 
 import android.content.Context
+import com.google.gson.Gson
 import de.rki.coronawarnapp.util.CWADebug
 import io.mockk.MockKAnnotations
 import io.mockk.clearAllMocks
@@ -16,6 +17,7 @@ class TestSettingsTest : BaseTest() {
 
     @MockK lateinit var context: Context
     private lateinit var mockPreferences: MockSharedPreferences
+    private val gson = Gson()
 
     @BeforeEach
     fun setup() {
@@ -35,6 +37,7 @@ class TestSettingsTest : BaseTest() {
     }
 
     private fun buildInstance(): TestSettings = TestSettings(
-        context = context
+        context = context,
+        gson = gson
     )
 }
diff --git a/Corona-Warn-App/src/testDevice/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/ExposureWindowProviderTest.kt b/Corona-Warn-App/src/testDevice/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/ExposureWindowProviderTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9d495c8c22e32f7ad4fcaa7548c38ac13ebda676
--- /dev/null
+++ b/Corona-Warn-App/src/testDevice/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/ExposureWindowProviderTest.kt
@@ -0,0 +1,43 @@
+package de.rki.coronawarnapp.nearby.modules.exposurewindow
+
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import de.rki.coronawarnapp.util.CWADebug
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.clearAllMocks
+import io.mockk.coEvery
+import io.mockk.impl.annotations.MockK
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import testhelpers.gms.MockGMSTask
+import java.io.File
+
+class ExposureWindowProviderTest : BaseTest() {
+    @MockK lateinit var googleENFClient: ExposureNotificationClient
+
+    private val exampleKeyFiles = listOf(File("file1"), File("file2"))
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        coEvery { googleENFClient.exposureWindows } returns MockGMSTask.forValue(emptyList())
+    }
+
+    @AfterEach
+    fun teardown() {
+        clearAllMocks()
+    }
+
+    private fun createProvider() = DefaultExposureWindowProvider(
+        client = googleENFClient
+    )
+
+    @Test
+    fun `fake exposure windows only in tester builds`() {
+        val instance = createProvider()
+        CWADebug.isDeviceForTestersBuild shouldBe false
+    }
+}
diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/ExposureWindowProviderTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/ExposureWindowProviderTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f9b77f2560de2a6f1a7d0e0f84642cd3a9085468
--- /dev/null
+++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/ExposureWindowProviderTest.kt
@@ -0,0 +1,48 @@
+package de.rki.coronawarnapp.nearby.modules.exposurewindow
+
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import de.rki.coronawarnapp.storage.TestSettings
+import de.rki.coronawarnapp.util.CWADebug
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.clearAllMocks
+import io.mockk.coEvery
+import io.mockk.impl.annotations.MockK
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import testhelpers.gms.MockGMSTask
+import java.io.File
+
+class ExposureWindowProviderTest : BaseTest() {
+    @MockK lateinit var googleENFClient: ExposureNotificationClient
+    @MockK lateinit var testSettings: TestSettings
+    @MockK lateinit var fakeExposureWindowProvider: FakeExposureWindowProvider
+
+    private val exampleKeyFiles = listOf(File("file1"), File("file2"))
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+
+        coEvery { googleENFClient.exposureWindows } returns MockGMSTask.forValue(emptyList())
+    }
+
+    @AfterEach
+    fun teardown() {
+        clearAllMocks()
+    }
+
+    private fun createProvider() = DefaultExposureWindowProvider(
+        client = googleENFClient,
+        testSettings = testSettings,
+        fakeExposureWindowProvider = fakeExposureWindowProvider
+    )
+
+    @Test
+    fun `fake exposure windows only in tester builds`() {
+        val instance = createProvider()
+        CWADebug.isDeviceForTestersBuild shouldBe true
+    }
+}