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 c3de7abd0615b66f64d5eb6255c6d1c255e571e8..38d4f40b1d415d97d246263ea0ce715826ec582d 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
@@ -4,9 +4,11 @@ package de.rki.coronawarnapp.nearby
 
 import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
 import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import com.google.android.gms.nearby.exposurenotification.ExposureWindow
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.TrackedExposureDetection
 import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider
+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 kotlinx.coroutines.flow.Flow
@@ -23,8 +25,10 @@ class ENFClient @Inject constructor(
     private val diagnosisKeyProvider: DiagnosisKeyProvider,
     private val tracingStatus: TracingStatus,
     private val scanningSupport: ScanningSupport,
+    private val exposureWindowProvider: ExposureWindowProvider,
+
     private val exposureDetectionTracker: ExposureDetectionTracker
-) : DiagnosisKeyProvider, TracingStatus, ScanningSupport {
+) : DiagnosisKeyProvider, TracingStatus, ScanningSupport, ExposureWindowProvider {
 
     // TODO Remove this once we no longer need direct access to the ENF Client,
     // i.e. in **[InternalExposureNotificationClient]**
@@ -51,6 +55,19 @@ class ENFClient @Inject constructor(
         }
     }
 
+    override suspend fun provideDiagnosisKeys(keyFiles: Collection<File>): Boolean {
+        Timber.d("asyncProvideDiagnosisKeys(keyFiles=$keyFiles)")
+
+        return if (keyFiles.isEmpty()) {
+            Timber.d("No key files submitted, returning early.")
+            true
+        } else {
+            Timber.d("Forwarding %d key files to our DiagnosisKeyProvider.", keyFiles.size)
+            TODO("Call calculationTracker.trackNewCalaculation with an UUID as replacement for token?")
+            diagnosisKeyProvider.provideDiagnosisKeys(keyFiles)
+        }
+    }
+
     override val isLocationLessScanningSupported: Flow<Boolean>
         get() = scanningSupport.isLocationLessScanningSupported
 
@@ -72,4 +89,6 @@ class ENFClient @Inject constructor(
                 .filter { !it.isCalculating && it.isSuccessful }
                 .maxByOrNull { it.finishedAt ?: Instant.EPOCH }
         }
+
+    override suspend fun exposureWindows(): List<ExposureWindow> = exposureWindowProvider.exposureWindows()
 }
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 9d98d5b33bf809dbc19995310857d2cda775fcb6..ec99ff4e77f53c5a7f777519cd01ad799f56d61c 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
@@ -9,6 +9,8 @@ import de.rki.coronawarnapp.nearby.modules.detectiontracker.DefaultExposureDetec
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
 import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DefaultDiagnosisKeyProvider
 import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider
+import de.rki.coronawarnapp.nearby.modules.exposurewindow.DefaultExposureWindowProvider
+import de.rki.coronawarnapp.nearby.modules.exposurewindow.ExposureWindowProvider
 import de.rki.coronawarnapp.nearby.modules.locationless.DefaultScanningSupport
 import de.rki.coronawarnapp.nearby.modules.locationless.ScanningSupport
 import de.rki.coronawarnapp.nearby.modules.tracing.DefaultTracingStatus
@@ -39,6 +41,11 @@ class ENFModule {
     fun scanningSupport(scanningSupport: DefaultScanningSupport): ScanningSupport =
         scanningSupport
 
+    @Singleton
+    @Provides
+    fun exposureWindowProvider(exposureWindowProvider: DefaultExposureWindowProvider): ExposureWindowProvider =
+        exposureWindowProvider
+
     @Singleton
     @Provides
     fun calculationTracker(exposureDetectionTracker: DefaultExposureDetectionTracker): ExposureDetectionTracker =
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 59114d58d4c0bab4709d0568ffb39c052923913d..a0cbf8b53d1f2d6b5a1dce3c515e16f60508a9b9 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
@@ -54,6 +54,31 @@ class DefaultDiagnosisKeyProvider @Inject constructor(
         }
     }
 
+    override suspend fun provideDiagnosisKeys(keyFiles: Collection<File>): Boolean {
+        if (keyFiles.isEmpty()) {
+            Timber.d("No key files submitted, returning early.")
+            return true
+        }
+
+        if (!googleAPIVersion.isAtLeast(GoogleAPIVersion.V15)) {
+            // Actually this shouldn't happen
+            Timber.d("No key files submitted because client uses an old unsupported version")
+            return false
+        }
+
+        if (!submissionQuota.consumeQuota(1)) {
+            Timber.w("No key files submitted because not enough quota available.")
+        }
+
+        return suspendCoroutine { cont ->
+            Timber.d("Performing key submission.")
+            enfClient
+                .provideDiagnosisKeys(keyFiles.toList())
+                .addOnSuccessListener { cont.resume(true) }
+                .addOnFailureListener { cont.resumeWithException(it) }
+        }
+    }
+
     private suspend fun provideKeys(
         files: Collection<File>,
         configuration: ExposureConfiguration,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt
index accedeed05ba0a7be5e2259326da4960db3ab3b7..d4a2f00fa1a99bf4d26b5511b9e32787e99f812c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt
@@ -17,9 +17,12 @@ interface DiagnosisKeyProvider {
      * @param token
      * @return
      */
+    @Deprecated("Use provideDiagnosisKeys with only keyFiles as param to activate WindowExposure mode")
     suspend fun provideDiagnosisKeys(
         keyFiles: Collection<File>,
         configuration: ExposureConfiguration?,
         token: String
     ): Boolean
+
+    suspend fun provideDiagnosisKeys(keyFiles: Collection<File>): Boolean
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuota.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuota.kt
index d9bd53506983a3d65e700bd694c21e6ca8d2a618..bf5ff885a0c194492cc122e266e34ddb5d3ee019 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuota.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuota.kt
@@ -86,6 +86,10 @@ class SubmissionQuota @Inject constructor(
 
     companion object {
         @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+        /**
+         * This quota changes when using ExposureWindow mode from 20 to 6 per day
+         * See: https://developers.google.com/android/exposure-notifications/release-notes
+         */
         internal const val DEFAULT_QUOTA = 20
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/DefaultExposureWindowProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/DefaultExposureWindowProvider.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5f83c9bba28645b8e7e2e6b1cbb298dbdc71dd00
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/DefaultExposureWindowProvider.kt
@@ -0,0 +1,20 @@
+package de.rki.coronawarnapp.nearby.modules.exposurewindow
+
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import com.google.android.gms.nearby.exposurenotification.ExposureWindow
+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
+) : ExposureWindowProvider {
+    override suspend fun exposureWindows(): List<ExposureWindow> = suspendCoroutine { cont ->
+        client.exposureWindows
+            .addOnSuccessListener { cont.resume(it) }
+            .addOnFailureListener { cont.resumeWithException(it) }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/ExposureWindowProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/ExposureWindowProvider.kt
new file mode 100644
index 0000000000000000000000000000000000000000..713715c879f0f75746ff3503d4d1116875d7fca7
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/exposurewindow/ExposureWindowProvider.kt
@@ -0,0 +1,7 @@
+package de.rki.coronawarnapp.nearby.modules.exposurewindow
+
+import com.google.android.gms.nearby.exposurenotification.ExposureWindow
+
+interface ExposureWindowProvider {
+    suspend fun exposureWindows(): List<ExposureWindow>
+}
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
index 6af00068b370a93acc562d74cf16b23d8819617c..8119586bcbab639d1634a4a2b92e9544d8aaa02f 100644
--- 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
@@ -36,5 +36,6 @@ class GoogleAPIVersion @Inject constructor() {
     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/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt
index 4880b66aa8e79d52d909cc7e2ecdc9fc47a5ea96..1f242c4c2c35c8cef7e31c4f87b62401489a6b6f 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
@@ -2,9 +2,11 @@ package de.rki.coronawarnapp.nearby
 
 import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
 import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import com.google.android.gms.nearby.exposurenotification.ExposureWindow
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.TrackedExposureDetection
 import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider
+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 io.kotest.matchers.shouldBe
@@ -37,6 +39,7 @@ class ENFClientTest : BaseTest() {
     @MockK lateinit var diagnosisKeyProvider: DiagnosisKeyProvider
     @MockK lateinit var tracingStatus: TracingStatus
     @MockK lateinit var scanningSupport: ScanningSupport
+    @MockK lateinit var exposureWindowProvider: ExposureWindowProvider
     @MockK lateinit var exposureDetectionTracker: ExposureDetectionTracker
 
     @BeforeEach
@@ -56,6 +59,8 @@ class ENFClientTest : BaseTest() {
         diagnosisKeyProvider = diagnosisKeyProvider,
         tracingStatus = tracingStatus,
         scanningSupport = scanningSupport,
+
+        exposureWindowProvider = exposureWindowProvider,
         exposureDetectionTracker = exposureDetectionTracker
     )
 
@@ -265,4 +270,17 @@ class ENFClientTest : BaseTest() {
             createClient().lastSuccessfulTrackedExposureDetection().first()!!.identifier shouldBe "1"
         }
     }
+
+    @Test
+    fun `exposure windows check is forwarded to the right module`() = runBlocking {
+        val exposureWindowList = emptyList<ExposureWindow>()
+        coEvery { exposureWindowProvider.exposureWindows() } returns exposureWindowList
+
+        val client = createClient()
+        client.exposureWindows() shouldBe exposureWindowList
+
+        coVerify(exactly = 1) {
+            exposureWindowProvider.exposureWindows()
+        }
+    }
 }