diff --git a/.circleci/config.yml b/.circleci/config.yml
index da41853c01b..ed0062ff57d 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,10 +1,12 @@
version: 2.1
orbs:
android: circleci/android@0.2.1
+ sonarcloud: sonarsource/sonarcloud@1.0.1
commands:
install-ndk: android/install-ndk
restore-build-cache: android/restore-build-cache
save-build-cache: android/save-build-cache
+ scan-sonar: sonarcloud/scan
jobs:
quickBuildReleaseWithTestsAndChecks:
executor: android/android
@@ -22,6 +24,13 @@ jobs:
environment:
JVM_OPTS: -Xmx2048m
GRADLE_OPTS: -Xmx1536m -XX:+HeapDumpOnOutOfMemoryError -Dorg.gradle.caching=true -Dorg.gradle.configureondemand=true -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false
+ - run:
+ name: JaCoCo report
+ command: ./gradlew :Corona-Warn-App:jacocoTestReportDeviceRelease
+ environment:
+ JVM_OPTS: -Xmx2048m
+ GRADLE_OPTS: -Xmx1536m -XX:+HeapDumpOnOutOfMemoryError -Dorg.gradle.caching=true -Dorg.gradle.configureondemand=true -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false
+ - scan-sonar
- save-build-cache
- save_cache:
paths:
@@ -36,4 +45,5 @@ workflows:
version: 2
workflow:
jobs:
- - quickBuildReleaseWithTestsAndChecks
+ - quickBuildReleaseWithTestsAndChecks:
+ context: SonarCloud
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index fc9b825df03..83a0e36cd75 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -11,6 +11,8 @@ Before submitting, please take the time to check the points below and provide so
* [ ] [Link your Pull Request to an issue](https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) (if applicable)
* [ ] Create Work In Progress [WIP] pull requests only if you need clarification or an explicit review before you can continue your work item.
* [ ] Make sure that your PR is not introducing _unnecessary_ reformatting (e.g., introduced by on-save hooks in your IDE)
+* [ ] Make sure that your PR does not contain changes in strings.xml (see issue #72)
+* [ ] Make sure that your PR does not contain compiled sources (already set by the default .gitignore) and / or binary files
## Description
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 210103484f0..4ad6bc590d6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -50,6 +50,8 @@ The following rule governs documentation contributions:
* Commits should be as small as possible while ensuring that each commit is correct independently (i.e., each commit should compile and pass tests).
+* Pull requests must not contain compiled sources (already set by the default .gitignore) or binary files
+
* Test your changes as thoroughly as possible before you commit them. Preferably, automate your test by unit/integration tests. If tested manually, provide information about the test scope in the PR description (e.g. “Test passed: Upgrade version from 0.42 to 0.42.23.”).
* Create _Work In Progress [WIP]_ pull requests only if you need clarification or an explicit review before you can continue your work item.
diff --git a/Corona-Warn-App/build.gradle b/Corona-Warn-App/build.gradle
index 8d2b3aa6ad8..a48d1106680 100644
--- a/Corona-Warn-App/build.gradle
+++ b/Corona-Warn-App/build.gradle
@@ -22,7 +22,6 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: "androidx.navigation.safeargs.kotlin"
-apply plugin: 'jacoco'
android {
ndkVersion "21.2.6472646"
@@ -33,8 +32,8 @@ android {
applicationId 'de.rki.coronawarnapp'
minSdkVersion 23
targetSdkVersion 29
- versionCode 12
- versionName "0.8.5"
+ versionCode 13
+ versionName "0.8.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField "String", "DOWNLOAD_CDN_URL", "\"$DOWNLOAD_CDN_URL\""
@@ -62,7 +61,12 @@ android {
def VERIFICATION_CDN_URL = properties.getProperty('VERIFICATION_CDN_URL')
if (VERIFICATION_CDN_URL)
buildConfigField "String", "VERIFICATION_CDN_URL", "\"$VERIFICATION_CDN_URL\""
+ }
+ javaCompileOptions {
+ annotationProcessorOptions {
+ arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]
+ }
}
}
@@ -78,6 +82,7 @@ android {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ testCoverageEnabled true
buildConfigField "String", "EXPORT_SIGNATURE_ID", "\"de.rki.coronawarnapp-dev\""
}
}
@@ -141,13 +146,6 @@ android {
}
-task jacocoTestReport(type: JacocoReport, dependsOn: ['testDeviceReleaseUnitTest']) {
- reports {
- xml.enabled = true
- html.enabled = true
- }
-}
-
dependencies {
// KOTLIN
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
@@ -209,7 +207,7 @@ dependencies {
implementation "androidx.room:room-ktx:$room_version"
implementation "androidx.room:room-guava:$room_version"
kapt "androidx.room:room-compiler:$room_version"
- implementation "androidx.sqlite:sqlite:2.0.1"
+ implementation "androidx.sqlite:sqlite:2.1.0"
// UTILS
implementation project(":Server-Protocol-Buffer")
diff --git a/Corona-Warn-App/schemas/de.rki.coronawarnapp.storage.AppDatabase/1.json b/Corona-Warn-App/schemas/de.rki.coronawarnapp.storage.AppDatabase/1.json
new file mode 100644
index 00000000000..006845e8274
--- /dev/null
+++ b/Corona-Warn-App/schemas/de.rki.coronawarnapp.storage.AppDatabase/1.json
@@ -0,0 +1,151 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 1,
+ "identityHash": "fc62bfe144d17a099180c8023c340138",
+ "entities": [
+ {
+ "tableName": "exposure_summary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `daysSinceLastExposure` INTEGER NOT NULL, `matchedKeyCount` INTEGER NOT NULL, `maximumRiskScore` INTEGER NOT NULL, `summationRiskScore` INTEGER NOT NULL, `attenuationDurationsInMinutes` TEXT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "daysSinceLastExposure",
+ "columnName": "daysSinceLastExposure",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "matchedKeyCount",
+ "columnName": "matchedKeyCount",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "maximumRiskScore",
+ "columnName": "maximumRiskScore",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "summationRiskScore",
+ "columnName": "summationRiskScore",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attenuationDurationsInMinutes",
+ "columnName": "attenuationDurationsInMinutes",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_exposure_summary_id",
+ "unique": false,
+ "columnNames": [
+ "id"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_exposure_summary_id` ON `${TABLE_NAME}` (`id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "date",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` TEXT NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "path",
+ "columnName": "path",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_date_id",
+ "unique": false,
+ "columnNames": [
+ "id"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_date_id` ON `${TABLE_NAME}` (`id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "tracing_interval",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`from` INTEGER NOT NULL, `to` INTEGER NOT NULL, PRIMARY KEY(`from`, `to`))",
+ "fields": [
+ {
+ "fieldPath": "from",
+ "columnName": "from",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "to",
+ "columnName": "to",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "from",
+ "to"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_tracing_interval_from_to",
+ "unique": false,
+ "columnNames": [
+ "from",
+ "to"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_tracing_interval_from_to` ON `${TABLE_NAME}` (`from`, `to`)"
+ }
+ ],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'fc62bfe144d17a099180c8023c340138')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/DBPasswordTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/DBPasswordTest.kt
index bd9025f6272..5f1267524ea 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/DBPasswordTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/DBPasswordTest.kt
@@ -20,10 +20,8 @@
package de.rki.coronawarnapp.util.security
import android.content.Context
-import android.database.sqlite.SQLiteDatabase
import androidx.test.core.app.ApplicationProvider
import de.rki.coronawarnapp.storage.AppDatabase
-import de.rki.coronawarnapp.storage.DATABASE_NAME
import de.rki.coronawarnapp.storage.keycache.KeyCacheEntity
import kotlinx.coroutines.runBlocking
import net.sqlcipher.database.SQLiteException
@@ -35,7 +33,6 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import java.io.File
import java.util.UUID
import kotlin.random.Random
diff --git a/Corona-Warn-App/src/main/assets/pins.properties b/Corona-Warn-App/src/main/assets/pins.properties
deleted file mode 100644
index 198e2e9bbfd..00000000000
--- a/Corona-Warn-App/src/main/assets/pins.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-# TODO add certificate pinning
-#
-# Intermediates will be encoded like this:
-# openssl x509 -in CERTNAME -pubkey -noout | \
-# openssl pkey -pubin -outform der | \
-# openssl dgst -sha256 -binary | \
-# openssl enc -base64
-#
-# Format is sha256/BASE64ENCODED
-# Pins are delimited by ","
-SUBMISSION_PINS=
-DISTRIBUTION_PINS=
-VERIFICATION_PINS=
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
index f1f40cb4af0..cae06737762 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
@@ -14,8 +14,8 @@ import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.localbroadcastmanager.content.LocalBroadcastManager
-import de.rki.coronawarnapp.exception.ErrorReportReceiver
-import de.rki.coronawarnapp.exception.ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL
+import de.rki.coronawarnapp.exception.reporting.ErrorReportReceiver
+import de.rki.coronawarnapp.exception.reporting.ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL
import de.rki.coronawarnapp.notification.NotificationHelper
import org.conscrypt.Conscrypt
import java.security.Security
@@ -101,7 +101,8 @@ class CoronaWarnApplication : Application(), LifecycleObserver,
}
override fun onActivityResumed(activity: Activity) {
- errorReceiver = ErrorReportReceiver(activity)
+ errorReceiver =
+ ErrorReportReceiver(activity)
LocalBroadcastManager.getInstance(this)
.registerReceiver(errorReceiver, IntentFilter(ERROR_REPORT_LOCAL_BROADCAST_CHANNEL))
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt
index d1740c85eb6..3cd4ea57daf 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt
@@ -35,7 +35,7 @@ import de.rki.coronawarnapp.databinding.FragmentTestForAPIBinding
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.ExceptionCategory.INTERNAL
import de.rki.coronawarnapp.exception.TransactionException
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper
import de.rki.coronawarnapp.receiver.ExposureStateUpdateReceiver
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt
index 3e288bd87dc..94df6e4ab1c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt
@@ -19,7 +19,7 @@ import com.google.zxing.integration.android.IntentResult
import de.rki.coronawarnapp.databinding.FragmentTestRiskLevelCalculationBinding
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.TransactionException
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.risk.RiskLevel
import de.rki.coronawarnapp.risk.TimeVariables
@@ -258,7 +258,9 @@ class TestRiskLevelCalculation : Fragment() {
"Tracing Duration: " +
"${TimeUnit.MILLISECONDS.toDays(TimeVariables.getTimeActiveTracingDuration())} days \n" +
"Tracing Duration in last 14 days: " +
- "${TimeVariables.getActiveTracingDaysInRetentionPeriod()} days"
+ "${TimeVariables.getActiveTracingDaysInRetentionPeriod()} days \n" +
+ "Last time risk level calculation ${LocalData.lastTimeRiskLevelCalculation()}"
+
binding.labelRiskScore.text = riskAsString
val lowClass =
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/CwaWebSecurityException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/CwaWebSecurityException.kt
new file mode 100644
index 00000000000..6dbbbca8d83
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/CwaWebSecurityException.kt
@@ -0,0 +1,8 @@
+package de.rki.coronawarnapp.exception
+
+import okio.IOException
+
+class CwaWebSecurityException(cause: Throwable) : IOException(
+ "an error occurred while trying to establish a secure connection to the server",
+ cause
+)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ErrorReportReceiver.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorReportReceiver.kt
similarity index 95%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ErrorReportReceiver.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorReportReceiver.kt
index 958e8a1dd95..0213635c4cc 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ErrorReportReceiver.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorReportReceiver.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.exception
+package de.rki.coronawarnapp.exception.reporting
import android.app.Activity
import android.content.BroadcastReceiver
@@ -7,6 +7,7 @@ import android.content.Intent
import android.util.Log
import de.rki.coronawarnapp.CoronaWarnApplication
import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.util.DialogHelper
class ErrorReportReceiver(private val activity: Activity) : BroadcastReceiver() {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ExceptionReporter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt
similarity index 93%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ExceptionReporter.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt
index 3c58048be14..feaa6711f16 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ExceptionReporter.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt
@@ -1,8 +1,9 @@
-package de.rki.coronawarnapp.exception
+package de.rki.coronawarnapp.exception.reporting
import android.content.Intent
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import de.rki.coronawarnapp.CoronaWarnApplication
+import de.rki.coronawarnapp.exception.ExceptionCategory
import java.io.PrintWriter
import java.io.StringWriter
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ReportingConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ReportingConstants.kt
similarity index 87%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ReportingConstants.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ReportingConstants.kt
index 22f1c2393c8..d3eb21a2eb9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ReportingConstants.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ReportingConstants.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.exception
+package de.rki.coronawarnapp.exception.reporting
object ReportingConstants {
const val ERROR_REPORT_LOCAL_BROADCAST_CHANNEL = "error-report"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/CertificatePinnerFactory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/CertificatePinnerFactory.kt
deleted file mode 100644
index 7a103bea083..00000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/CertificatePinnerFactory.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package de.rki.coronawarnapp.http
-
-import de.rki.coronawarnapp.util.PropertyLoader
-import okhttp3.CertificatePinner
-
-class CertificatePinnerFactory {
- fun getCertificatePinner(): CertificatePinner = PropertyLoader().run {
- CertificatePinner.Builder()
- .add(
- DynamicURLs.DOWNLOAD_CDN_URL.removePrefix(DynamicURLs.PATTERN_PREFIX_HTTPS),
- *this.getDistributionPins()
- )
- .add(
- DynamicURLs.SUBMISSION_CDN_URL.removePrefix(DynamicURLs.PATTERN_PREFIX_HTTPS),
- *this.getSubmissionPins()
- )
- .add(
- DynamicURLs.VERIFICATION_CDN_URL.removePrefix(DynamicURLs.PATTERN_PREFIX_HTTPS),
- *this.getVerificationPins()
- )
- .build()
- }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt
index 42604a156a5..94c3fd63c68 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt
@@ -4,15 +4,22 @@ import android.webkit.URLUtil
import de.rki.coronawarnapp.BuildConfig
import de.rki.coronawarnapp.CoronaWarnApplication
import de.rki.coronawarnapp.exception.http.ServiceFactoryException
+import de.rki.coronawarnapp.http.config.DynamicURLs
+import de.rki.coronawarnapp.http.config.HTTPVariables
+import de.rki.coronawarnapp.http.interceptor.OfflineCacheInterceptor
+import de.rki.coronawarnapp.http.interceptor.WebSecurityVerificationInterceptor
+import de.rki.coronawarnapp.http.interceptor.RetryInterceptor
import de.rki.coronawarnapp.http.service.DistributionService
import de.rki.coronawarnapp.http.service.SubmissionService
import de.rki.coronawarnapp.http.service.VerificationService
import de.rki.coronawarnapp.risk.TimeVariables
import okhttp3.Cache
+import okhttp3.CipherSuite
import okhttp3.ConnectionPool
import okhttp3.ConnectionSpec
import okhttp3.Interceptor
import okhttp3.OkHttpClient
+import okhttp3.TlsVersion
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
@@ -37,10 +44,13 @@ class ServiceFactory {
* List of interceptors, e.g. logging
*/
private val mInterceptors: List = listOf(
+ WebSecurityVerificationInterceptor(),
HttpLoggingInterceptor().also {
if (BuildConfig.DEBUG) it.setLevel(HttpLoggingInterceptor.Level.BODY)
},
- OfflineCacheInterceptor(CoronaWarnApplication.getAppContext()),
+ OfflineCacheInterceptor(
+ CoronaWarnApplication.getAppContext()
+ ),
RetryInterceptor(),
HttpErrorParser()
)
@@ -64,41 +74,98 @@ class ServiceFactory {
private val okHttpClient by lazy {
val clientBuilder = OkHttpClient.Builder()
- val timeoutMs = TimeVariables.getTransactionTimeout()
- clientBuilder.connectTimeout(timeoutMs, TimeUnit.MILLISECONDS)
- clientBuilder.readTimeout(timeoutMs, TimeUnit.MILLISECONDS)
- clientBuilder.writeTimeout(timeoutMs, TimeUnit.MILLISECONDS)
- clientBuilder.callTimeout(timeoutMs, TimeUnit.MILLISECONDS)
+ clientBuilder.connectTimeout(
+ HTTPVariables.getHTTPConnectionTimeout(),
+ TimeUnit.MILLISECONDS
+ )
+ clientBuilder.readTimeout(
+ HTTPVariables.getHTTPReadTimeout(),
+ TimeUnit.MILLISECONDS
+ )
+ clientBuilder.writeTimeout(
+ HTTPVariables.getHTTPWriteTimeout(),
+ TimeUnit.MILLISECONDS
+ )
+ clientBuilder.callTimeout(
+ TimeVariables.getTransactionTimeout(),
+ TimeUnit.MILLISECONDS
+ )
clientBuilder.connectionPool(conPool)
cache.evictAll()
clientBuilder.cache(cache)
- val spec: ConnectionSpec = ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS)
- .allEnabledCipherSuites() // TODO clarify more concrete Ciphers
- .build()
-
- clientBuilder.connectionSpecs(listOf(spec))
-
- CertificatePinnerFactory().getCertificatePinner().run {
- if (this.pins.isNotEmpty()) {
- clientBuilder.certificatePinner(this)
- }
- }
-
mInterceptors.forEach { clientBuilder.addInterceptor(it) }
clientBuilder.build()
}
+ /**
+ * For the CDN we want to ensure maximum Compatibility.
+ */
+ private fun getCDNSpecs(): List = listOf(
+ ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
+ .tlsVersions(
+ TlsVersion.TLS_1_0,
+ TlsVersion.TLS_1_1,
+ TlsVersion.TLS_1_2,
+ TlsVersion.TLS_1_3
+ )
+ .allEnabledCipherSuites()
+ .build()
+ )
+
+ /**
+ * For Submission and Verification we want to limit our specifications for TLS.
+ */
+ private fun getRestrictedSpecs(): List = listOf(
+ ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS)
+ .tlsVersions(
+ TlsVersion.TLS_1_2,
+ TlsVersion.TLS_1_3
+ )
+ .cipherSuites(
+ // TLS 1.2 with Perfect Forward Secrecy (BSI TR-02102-2)
+ CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+ // TLS 1.3 (BSI TR-02102-2)
+ CipherSuite.TLS_AES_128_GCM_SHA256,
+ CipherSuite.TLS_AES_256_GCM_SHA384,
+ CipherSuite.TLS_AES_128_CCM_SHA256
+ )
+ .build()
+ )
+
+ /**
+ * Helper function to create a new client from an existent Client with New Specs.
+ *
+ * @param specs
+ */
+ private fun OkHttpClient.buildClientWithNewSpecs(specs: List) =
+ this.newBuilder().connectionSpecs(specs).build()
+
private val downloadCdnUrl
get() = getValidUrl(DynamicURLs.DOWNLOAD_CDN_URL)
fun distributionService(): DistributionService = distributionService
private val distributionService by lazy {
Retrofit.Builder()
- .client(okHttpClient)
+ .client(okHttpClient.buildClientWithNewSpecs(getCDNSpecs()))
.baseUrl(downloadCdnUrl)
.addConverterFactory(gsonConverterFactory)
.build()
@@ -111,7 +178,7 @@ class ServiceFactory {
fun verificationService(): VerificationService = verificationService
private val verificationService by lazy {
Retrofit.Builder()
- .client(okHttpClient)
+ .client(okHttpClient.buildClientWithNewSpecs(getRestrictedSpecs()))
.baseUrl(verificationCdnUrl)
.addConverterFactory(gsonConverterFactory)
.build()
@@ -124,7 +191,7 @@ class ServiceFactory {
fun submissionService(): SubmissionService = submissionService
private val submissionService by lazy {
Retrofit.Builder()
- .client(okHttpClient)
+ .client(okHttpClient.buildClientWithNewSpecs(getRestrictedSpecs()))
.baseUrl(submissionCdnUrl)
.addConverterFactory(protoConverterFactory)
.addConverterFactory(gsonConverterFactory)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/DynamicURLs.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/config/DynamicURLs.kt
similarity index 92%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/DynamicURLs.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/config/DynamicURLs.kt
index 20dd1781424..cc05f85afe6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/DynamicURLs.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/config/DynamicURLs.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.http
+package de.rki.coronawarnapp.http.config
import de.rki.coronawarnapp.BuildConfig
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/config/HTTPVariables.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/config/HTTPVariables.kt
new file mode 100644
index 00000000000..4939bf67556
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/config/HTTPVariables.kt
@@ -0,0 +1,45 @@
+package de.rki.coronawarnapp.http.config
+
+object HTTPVariables {
+ /**
+ * The maximal runtime of a transaction
+ * In milliseconds
+ */
+ private const val HTTP_CONNECTION_TIMEOUT = 10000L
+
+ /**
+ * Getter function for [HTTP_CONNECTION_TIMEOUT]
+ *
+ * @return timeout in milliseconds
+ */
+ fun getHTTPConnectionTimeout(): Long =
+ HTTP_CONNECTION_TIMEOUT
+
+ /**
+ * The maximal runtime of a transaction
+ * In milliseconds
+ */
+ private const val HTTP_READ_TIMEOUT = 10000L
+
+ /**
+ * Getter function for [HTTP_READ_TIMEOUT]
+ *
+ * @return timeout in milliseconds
+ */
+ fun getHTTPReadTimeout(): Long =
+ HTTP_READ_TIMEOUT
+
+ /**
+ * The maximal runtime of a transaction
+ * In milliseconds
+ */
+ private const val HTTP_WRITE_TIMEOUT = 10000L
+
+ /**
+ * Getter function for [HTTP_WRITE_TIMEOUT]
+ *
+ * @return timeout in milliseconds
+ */
+ fun getHTTPWriteTimeout(): Long =
+ HTTP_WRITE_TIMEOUT
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/OfflineCacheInterceptor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/interceptor/OfflineCacheInterceptor.kt
similarity index 97%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/OfflineCacheInterceptor.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/interceptor/OfflineCacheInterceptor.kt
index 15bf62893e8..e8d14fab803 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/OfflineCacheInterceptor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/interceptor/OfflineCacheInterceptor.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.http
+package de.rki.coronawarnapp.http.interceptor
import android.content.Context
import de.rki.coronawarnapp.util.ConnectivityHelper.isNetworkEnabled
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/RetryInterceptor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/interceptor/RetryInterceptor.kt
similarity index 93%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/RetryInterceptor.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/interceptor/RetryInterceptor.kt
index c4bfa179b98..91167efe8a8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/RetryInterceptor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/interceptor/RetryInterceptor.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.http
+package de.rki.coronawarnapp.http.interceptor
import android.util.Log
import okhttp3.Interceptor
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/interceptor/WebSecurityVerificationInterceptor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/interceptor/WebSecurityVerificationInterceptor.kt
new file mode 100644
index 00000000000..2af724e76a8
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/interceptor/WebSecurityVerificationInterceptor.kt
@@ -0,0 +1,14 @@
+package de.rki.coronawarnapp.http.interceptor
+
+import de.rki.coronawarnapp.exception.CwaWebSecurityException
+import okhttp3.Interceptor
+import okhttp3.Response
+import javax.net.ssl.SSLException
+
+class WebSecurityVerificationInterceptor : Interceptor {
+ override fun intercept(chain: Interceptor.Chain): Response {
+ try { return chain.proceed(chain.request()) } catch (e: SSLException) {
+ throw CwaWebSecurityException(e)
+ }
+ }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ExposureStateUpdateWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ExposureStateUpdateWorker.kt
index bc97b2c7a0f..bf0fb12d918 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ExposureStateUpdateWorker.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ExposureStateUpdateWorker.kt
@@ -9,7 +9,7 @@ import com.google.android.gms.nearby.exposurenotification.ExposureNotificationCl
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.NoTokenException
import de.rki.coronawarnapp.exception.TransactionException
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.storage.ExposureSummaryRepository
import de.rki.coronawarnapp.transaction.RiskLevelTransaction
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelper.kt
index 61c56fa645b..7ee79021a3a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelper.kt
@@ -9,7 +9,7 @@ import com.google.android.gms.nearby.exposurenotification.ExposureNotificationSt
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
import de.rki.coronawarnapp.exception.ENPermissionException
import de.rki.coronawarnapp.exception.ExceptionCategory
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import kotlinx.coroutines.launch
/**
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiver.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiver.kt
index 9a28ffa7b51..65f13604d17 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiver.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiver.kt
@@ -10,7 +10,7 @@ import com.google.android.gms.nearby.exposurenotification.ExposureNotificationCl
import de.rki.coronawarnapp.exception.ExceptionCategory.INTERNAL
import de.rki.coronawarnapp.exception.NoTokenException
import de.rki.coronawarnapp.exception.WrongReceiverException
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.ExposureStateUpdateWorker
/**
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/TimeVariables.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/TimeVariables.kt
index 5a6537cc950..6f687165077 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/TimeVariables.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/TimeVariables.kt
@@ -3,7 +3,7 @@ package de.rki.coronawarnapp.risk
import com.google.android.gms.common.api.ApiException
import de.rki.coronawarnapp.CoronaWarnApplication
import de.rki.coronawarnapp.exception.ExceptionCategory
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.storage.tracing.TracingIntervalRepository
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/sharing/ExposureSharingService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/sharing/ExposureSharingService.kt
index 12711ab2c7d..b70a41978ce 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/sharing/ExposureSharingService.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/sharing/ExposureSharingService.kt
@@ -10,7 +10,7 @@ import com.google.zxing.BarcodeFormat
import com.google.zxing.qrcode.QRCodeWriter
import de.rki.coronawarnapp.exception.ExceptionCategory.EXPOSURENOTIFICATION
import de.rki.coronawarnapp.exception.ExceptionCategory.INTERNAL
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppDatabase.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppDatabase.kt
index 113427e38b8..632fef20885 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppDatabase.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppDatabase.kt
@@ -18,7 +18,7 @@ import java.io.File
@Database(
entities = [ExposureSummaryEntity::class, KeyCacheEntity::class, TracingIntervalEntity::class],
version = 1,
- exportSchema = false
+ exportSchema = true
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
@@ -52,6 +52,11 @@ abstract class AppDatabase : RoomDatabase() {
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
+ /**
+ * The fallback behavior is to reset the app as we only store exposure summaries
+ * and cached references that are non-critical to app operation.
+ */
+ .fallbackToDestructiveMigrationFrom()
.openHelperFactory(SupportFactory(SecurityHelper.getDBPassword()))
.build()
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt
index c6c6bba9de2..fc0d79de672 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt
@@ -276,7 +276,6 @@ object LocalData {
* @param value timestamp as Date
*/
fun lastTimeDiagnosisKeysFromServerFetch(value: Date?) {
- // TODO need this for nullable ref, shout not be goto for nullable storage
getSharedPreferenceInstance().edit(true) {
putLong(
CoronaWarnApplication.getAppContext()
@@ -286,6 +285,37 @@ object LocalData {
}
}
+ /**
+ * Gets the last time of successful risk level calculation as long
+ * from the EncryptedSharedPrefs
+ *
+ * @return Long
+ */
+ fun lastTimeRiskLevelCalculation(): Long? {
+ val time = getSharedPreferenceInstance().getLong(
+ CoronaWarnApplication.getAppContext()
+ .getString(R.string.preference_timestamp_risk_level_calculation),
+ 0L
+ )
+ return Date(time).time
+ }
+
+ /**
+ * Sets the last time of successful risk level calculation as long
+ * from the EncryptedSharedPrefs
+ *
+ * @param value timestamp as Long
+ */
+ fun lastTimeRiskLevelCalculation(value: Long?) {
+ getSharedPreferenceInstance().edit(true) {
+ putLong(
+ CoronaWarnApplication.getAppContext()
+ .getString(R.string.preference_timestamp_risk_level_calculation),
+ value ?: 0L
+ )
+ }
+ }
+
/**
* Gets the last timestamp the user manually triggered the key retrieval process
*
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
index cb84c5cc157..3beb1fb40b6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
@@ -4,7 +4,7 @@ import android.widget.Toast
import androidx.lifecycle.MutableLiveData
import de.rki.coronawarnapp.CoronaWarnApplication
import de.rki.coronawarnapp.exception.ExceptionCategory
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.risk.TimeVariables.getActiveTracingDaysInRetentionPeriod
import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt
index df32874cc60..690595b1ff9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt
@@ -32,6 +32,7 @@ import de.rki.coronawarnapp.transaction.RiskLevelTransaction.RiskLevelTransactio
import de.rki.coronawarnapp.transaction.RiskLevelTransaction.RiskLevelTransactionState.CLOSE
import de.rki.coronawarnapp.transaction.RiskLevelTransaction.RiskLevelTransactionState.RETRIEVE_APPLICATION_CONFIG
import de.rki.coronawarnapp.transaction.RiskLevelTransaction.RiskLevelTransactionState.RETRIEVE_EXPOSURE_SUMMARY
+import de.rki.coronawarnapp.transaction.RiskLevelTransaction.RiskLevelTransactionState.RISK_CALCULATION_DATE_UPDATE
import de.rki.coronawarnapp.transaction.RiskLevelTransaction.RiskLevelTransactionState.UPDATE_RISK_LEVEL
import de.rki.coronawarnapp.util.TimeAndDateExtensions.millisecondsToHours
import kotlinx.coroutines.Dispatchers
@@ -108,7 +109,8 @@ import java.util.concurrent.atomic.AtomicReference
* 6. [CHECK_INCREASED_RISK]
* 7. [CHECK_UNKNOWN_RISK_INITIAL_TRACING_DURATION]
* 8. [UPDATE_RISK_LEVEL]
- * 9. [CLOSE]
+ * 9. [RISK_CALCULATION_DATE_UPDATE]
+ * 10. [CLOSE]
*
* This transaction will queue up any start calls and executes them in the given order (unlike the other defined
* transactions (e.g. [RetrieveDiagnosisKeysTransaction]). This is necessary in order to respond to various trigger
@@ -152,6 +154,9 @@ object RiskLevelTransaction : Transaction() {
/** Update and persist the Risk Level Score with the calculated score */
UPDATE_RISK_LEVEL,
+ /** Update of the Date to reflect a complete Transaction State */
+ RISK_CALCULATION_DATE_UPDATE,
+
/** Transaction Closure */
CLOSE
}
@@ -170,6 +175,9 @@ object RiskLevelTransaction : Transaction() {
/** atomic reference for the rollback value for the last calculated risk level score */
private val lastCalculatedRiskLevelScoreForRollback = AtomicReference()
+ /** atomic reference for the rollback value for date of last risk level calculation */
+ private val lastCalculatedRiskLevelDate = AtomicReference()
+
/** initiates the transaction. This suspend function guarantees a successful transaction once completed. */
suspend fun start() = lockAndExecute {
/****************************************************
@@ -220,6 +228,7 @@ object RiskLevelTransaction : Transaction() {
if (result == UNDETERMINED) {
lastCalculatedRiskLevelScoreForRollback.set(RiskLevelRepository.getLastCalculatedScore())
executeUpdateRiskLevelScore(LOW_LEVEL_RISK)
+ executeRiskLevelCalculationDateUpdate()
executeClose()
return@lockAndExecute
} else {
@@ -233,6 +242,9 @@ object RiskLevelTransaction : Transaction() {
if (UPDATE_RISK_LEVEL.isInStateStack()) {
updateRiskLevelScore(lastCalculatedRiskLevelScoreForRollback.get())
}
+ if (RISK_CALCULATION_DATE_UPDATE.isInStateStack()) {
+ LocalData.lastTimeRiskLevelCalculation(lastCalculatedRiskLevelDate.get())
+ }
} catch (e: Exception) {
// We handle every exception through a RollbackException to make sure that a single EntryPoint
// is available for the caller.
@@ -261,7 +273,10 @@ object RiskLevelTransaction : Transaction() {
// if there was no key retrieval before, we return no calculation state
TimeVariables.getLastTimeDiagnosisKeysFromServerFetch()
?: return@executeState UNKNOWN_RISK_INITIAL.also {
- Log.v(TAG, "$transactionId - no last time diagnosis keys from server fetch timestamp was found")
+ Log.v(
+ TAG,
+ "$transactionId - no last time diagnosis keys from server fetch timestamp was found"
+ )
}
Log.v(TAG, "$transactionId - CHECK_UNKNOWN_RISK_INITIAL_NO_KEYS not applicable")
@@ -314,15 +329,16 @@ object RiskLevelTransaction : Transaction() {
/**
* Executes the [RETRIEVE_EXPOSURE_SUMMARY] Transaction State
*/
- private suspend fun executeRetrieveExposureSummary(): ExposureSummary = executeState(RETRIEVE_EXPOSURE_SUMMARY) {
- val lastExposureSummary = getLastExposureSummary() ?: getNewExposureSummary()
+ private suspend fun executeRetrieveExposureSummary(): ExposureSummary =
+ executeState(RETRIEVE_EXPOSURE_SUMMARY) {
+ val lastExposureSummary = getLastExposureSummary() ?: getNewExposureSummary()
- return@executeState lastExposureSummary.also {
- // todo remove after testing sessions
- recordedTransactionValuesForTestingOnly.exposureSummary = it
- Log.v(TAG, "$transactionId - get the exposure summary for further calculation")
+ return@executeState lastExposureSummary.also {
+ // todo remove after testing sessions
+ recordedTransactionValuesForTestingOnly.exposureSummary = it
+ Log.v(TAG, "$transactionId - get the exposure summary for further calculation")
+ }
}
- }
/**
* Executes the [CHECK_INCREASED_RISK] Transaction State
@@ -412,6 +428,7 @@ object RiskLevelTransaction : Transaction() {
private suspend fun executeClose() = executeState(CLOSE) {
Log.v(TAG, "$transactionId - transaction will close")
lastCalculatedRiskLevelScoreForRollback.set(null)
+ lastCalculatedRiskLevelDate.set(null)
}
/****************************************************
@@ -435,6 +452,8 @@ object RiskLevelTransaction : Transaction() {
)
lastCalculatedRiskLevelScoreForRollback.set(RiskLevelRepository.getLastCalculatedScore())
executeUpdateRiskLevelScore(riskLevel)
+ lastCalculatedRiskLevelDate.set(LocalData.lastTimeRiskLevelCalculation())
+ executeRiskLevelCalculationDateUpdate()
executeClose()
return true
}
@@ -522,4 +541,14 @@ object RiskLevelTransaction : Transaction() {
Log.v(TAG, "$transactionId - generated new exposure summary with $googleToken")
}
}
+
+ /**
+ * Executes the CALCULATION_DATE_UPDATE Transaction State
+ */
+ private suspend fun executeRiskLevelCalculationDateUpdate() {
+ val currentDate = System.currentTimeMillis()
+ executeState(RISK_CALCULATION_DATE_UPDATE) {
+ LocalData.lastTimeRiskLevelCalculation(currentDate)
+ }
+ }
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/LauncherActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/LauncherActivity.kt
index 7a96494ec5f..938f0c3026c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/LauncherActivity.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/LauncherActivity.kt
@@ -6,7 +6,7 @@ import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
-import de.rki.coronawarnapp.http.DynamicURLs
+import de.rki.coronawarnapp.http.config.DynamicURLs
import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.ui.main.MainActivity
import de.rki.coronawarnapp.ui.onboarding.OnboardingActivity
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt
index 95a4182275b..4fb3f4ea0a4 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt
@@ -39,7 +39,7 @@ class InformationAboutFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.informationAboutHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.informationAboutHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt
index 88f37c5fd8b..595fb2df009 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt
@@ -41,7 +41,7 @@ class InformationContactFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.informationContactHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.informationContactHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
binding.informationContactNavigationRowPhone.navigationRow.setOnClickListener {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt
index 80e7e541cd5..8e44bce61ff 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt
@@ -74,7 +74,7 @@ class InformationFragment : BaseFragment() {
InformationFragmentDirections.actionInformationFragmentToInformationTechnicalFragment()
)
}
- binding.informationHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.informationHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt
index 16abadd8c53..298e5275cdb 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt
@@ -39,7 +39,7 @@ class InformationLegalFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.informationLegalHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.informationLegalHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt
index b3ab39e4cc4..75e3d748329 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt
@@ -39,7 +39,7 @@ class InformationPrivacyFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.informationPrivacyHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.informationPrivacyHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt
index 9ce43c29ff7..d28274e6a15 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt
@@ -39,7 +39,7 @@ class InformationTechnicalFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.informationTechnicalHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.informationTechnicalHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt
index 8189f124017..1a96747418f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt
@@ -39,7 +39,7 @@ class InformationTermsFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.informationTermsHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.informationTermsHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainOverviewFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainOverviewFragment.kt
index 40502e58607..28b9c00ba30 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainOverviewFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainOverviewFragment.kt
@@ -43,7 +43,7 @@ class MainOverviewFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.mainOverviewHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.mainOverviewHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainShareFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainShareFragment.kt
index 8ba1bb2e6fc..d8cad38c46f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainShareFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainShareFragment.kt
@@ -51,7 +51,7 @@ class MainShareFragment : BaseFragment() {
binding.mainShareButton.setOnClickListener {
ShareHelper.shareText(this, getString(R.string.main_share_message), null)
}
- binding.mainShareHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.mainShareHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt
index 023b07e91f9..3ff6a0f5df3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt
@@ -6,11 +6,17 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
+import androidx.lifecycle.lifecycleScope
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentOnboardingTracingBinding
+import de.rki.coronawarnapp.exception.ExceptionCategory
+import de.rki.coronawarnapp.exception.reporting.report
+import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper
+import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.ui.BaseFragment
import de.rki.coronawarnapp.util.DialogHelper
+import kotlinx.coroutines.launch
/**
* This fragment ask the user if he wants to enable tracing.
@@ -59,6 +65,7 @@ class OnboardingTracingFragment : BaseFragment(),
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setButtonOnClickListener()
+ resetTracing()
}
private fun setButtonOnClickListener() {
@@ -100,4 +107,23 @@ class OnboardingTracingFragment : BaseFragment(),
OnboardingTracingFragmentDirections.actionOnboardingTracingFragmentToOnboardingTestFragment()
)
}
+
+ private fun resetTracing() {
+ // Reset tracing state in onboarding
+ lifecycleScope.launch {
+ if (InternalExposureNotificationClient.asyncIsEnabled()) {
+ try {
+ InternalExposureNotificationClient.asyncStop()
+ // Reset initial activation timestamp
+ LocalData.initialTracingActivationTimestamp(0L)
+ } catch (exception: Exception) {
+ exception.report(
+ ExceptionCategory.EXPOSURENOTIFICATION,
+ OnboardingTracingFragment.TAG,
+ null
+ )
+ }
+ }
+ }
+ }
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/riskdetails/RiskDetailsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/riskdetails/RiskDetailsFragment.kt
index 893a95287d2..3c753af5782 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/riskdetails/RiskDetailsFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/riskdetails/RiskDetailsFragment.kt
@@ -71,7 +71,7 @@ class RiskDetailsFragment : BaseFragment() {
RiskDetailsFragmentDirections.actionRiskDetailsFragmentToSettingsTracingFragment()
)
}
- binding.riskDetailsRiskCard.riskCardHeader.riskCardHeaderButtonBack.setOnClickListener {
+ binding.riskDetailsToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsFragment.kt
index f7aab9c197b..4f5c8b56026 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsFragment.kt
@@ -63,7 +63,7 @@ class SettingsFragment : BaseFragment() {
val tracingRow = binding.settingsTracing.settingsRow
val notificationRow = binding.settingsNotifications.settingsRow
val resetRow = binding.settingsReset
- val goBack = binding.settingsHeader.headerButtonBack.buttonIcon
+ val goBack = binding.settingsHeader.headerToolbar
resetRow.setOnClickListener {
doNavigate(
SettingsFragmentDirections.actionSettingsFragmentToSettingsResetFragment()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsNotificationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsNotificationFragment.kt
index 2344f700960..862b943ef08 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsNotificationFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsNotificationFragment.kt
@@ -68,7 +68,7 @@ class SettingsNotificationFragment : Fragment() {
// Settings
val settingsRow = binding.settingsNavigationRowSystem.navigationRow
val goBack =
- binding.settingsNotificationsHeader.headerButtonBack.buttonIcon
+ binding.settingsNotificationsHeader.headerToolbar
// Update Risk
updateRiskNotificationSwitch.setOnCheckedChangeListener { _, _ ->
// android calls this listener also on start, so it has to be verified if the user pressed the switch
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt
index 6fb673f152f..13e05292e8c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt
@@ -10,7 +10,7 @@ import androidx.lifecycle.lifecycleScope
import com.google.android.gms.common.api.ApiException
import de.rki.coronawarnapp.databinding.FragmentSettingsResetBinding
import de.rki.coronawarnapp.exception.ExceptionCategory
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.ui.BaseFragment
import de.rki.coronawarnapp.ui.main.MainActivity
@@ -55,7 +55,7 @@ class SettingsResetFragment : BaseFragment() {
binding.settingsResetButtonCancel.setOnClickListener {
(activity as MainActivity).goBack()
}
- binding.settingsResetHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.settingsResetHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt
index 382d34f0557..0c97c73a4f9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt
@@ -8,16 +8,19 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
+import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentSettingsTracingBinding
import de.rki.coronawarnapp.exception.ExceptionCategory
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper
+import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.ui.BaseFragment
import de.rki.coronawarnapp.ui.ViewBlocker
import de.rki.coronawarnapp.ui.main.MainActivity
import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel
import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
+import de.rki.coronawarnapp.util.DialogHelper
import de.rki.coronawarnapp.util.SettingsNavigationHelper
import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
import kotlinx.coroutines.launch
@@ -108,7 +111,7 @@ class SettingsTracingFragment : BaseFragment(),
}
}
}
- binding.settingsTracingHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.settingsTracingHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
binding.settingsTracingStatusBluetooth.tracingStatusCardButton.setOnClickListener {
@@ -142,8 +145,32 @@ class SettingsTracingFragment : BaseFragment(),
tracingViewModel.refreshIsTracingEnabled()
BackgroundWorkScheduler.stopWorkScheduler()
} else {
- internalExposureNotificationPermissionHelper.requestPermissionToStartTracing()
+ // tracing was already activated
+ if (LocalData.initialTracingActivationTimestamp() != null) {
+ internalExposureNotificationPermissionHelper.requestPermissionToStartTracing()
+ } else {
+ // tracing was never activated
+ // ask for consent via dialog for initial tracing activation when tracing was not
+ // activated during onboarding
+ showConsentDialog()
+ }
}
}
}
+
+ private fun showConsentDialog() {
+ val dialog = DialogHelper.DialogInstance(
+ requireActivity(),
+ R.string.onboarding_tracing_headline_consent,
+ R.string.onboarding_tracing_body_consent,
+ R.string.onboarding_button_enable,
+ R.string.onboarding_button_cancel,
+ true,
+ {
+ internalExposureNotificationPermissionHelper.requestPermissionToStartTracing()
+ }, {
+ tracingViewModel.refreshIsTracingEnabled()
+ })
+ DialogHelper.showDialog(dialog)
+ }
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionContactFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionContactFragment.kt
index 0d1693898f5..93bd99e04da 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionContactFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionContactFragment.kt
@@ -39,7 +39,7 @@ class SubmissionContactFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.submissionContactHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.submissionContactHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
binding.submissionContactButtonCall.setOnClickListener {
@@ -51,7 +51,7 @@ class SubmissionContactFragment : BaseFragment() {
}
private fun dial() = context?.let {
- val number = getString(R.string.submission_contact_number)
+ val number = getString(R.string.submission_contact_number_dial)
CallHelper.call(this, "tel:$number")
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDispatcherFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDispatcherFragment.kt
index 4178eea3bd4..73bf2aa3534 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDispatcherFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDispatcherFragment.kt
@@ -40,7 +40,7 @@ class SubmissionDispatcherFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.submissionDispatcherHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.submissionDispatcherHeader.headerToolbar.setNavigationOnClickListener {
(activity as MainActivity).goBack()
}
binding.submissionDispatcherQr.dispatcherCard.setOnClickListener {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDoneFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDoneFragment.kt
index 330c86d79ff..60c9300d935 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDoneFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDoneFragment.kt
@@ -36,7 +36,7 @@ class SubmissionDoneFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.submissionDoneHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.submissionDoneHeader.headerToolbar.setNavigationOnClickListener {
doNavigate(
SubmissionDoneFragmentDirections.actionSubmissionDoneFragmentToMainFragment()
)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionIntroFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionIntroFragment.kt
index 219457cb2e0..0dc26e99bb9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionIntroFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionIntroFragment.kt
@@ -36,7 +36,7 @@ class SubmissionIntroFragment : BaseFragment() {
}
private fun setButtonOnClickListener() {
- binding.submissionIntroHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.submissionIntroHeader.headerToolbar.setNavigationOnClickListener {
doNavigate(SubmissionIntroFragmentDirections.actionSubmissionIntroFragmentToMainFragment())
}
binding.submissionIntroButtonNext.setOnClickListener {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt
index 02872234709..401edf1528a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt
@@ -148,7 +148,7 @@ class SubmissionResultPositiveOtherWarningFragment : BaseFragment(),
binding.submissionPositiveOtherWarningButtonNext.setOnClickListener {
initiateWarningOthers()
}
- binding.submissionPositiveOtherWarningHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.submissionPositiveOtherWarningHeader.headerToolbar.setNavigationOnClickListener {
navigateToSubmissionResultFragment()
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt
index 62877109447..7a6036caaff 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt
@@ -95,7 +95,7 @@ class SubmissionTanFragment : BaseFragment() {
binding.submissionTanInput.listener = { tan -> viewModel.tan.value = tan }
binding.submissionTanButtonEnter.setOnClickListener { storeTanAndContinue() }
- binding.submissionTanHeader.headerButtonBack.buttonIcon.setOnClickListener { navigateToDispatchScreen() }
+ binding.submissionTanHeader.headerToolbar.setNavigationOnClickListener { navigateToDispatchScreen() }
submissionViewModel.registrationState.observeEvent(viewLifecycleOwner, {
if (ApiRequestState.SUCCESS == it) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt
index c18d49a0153..cae07743b57 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt
@@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import de.rki.coronawarnapp.storage.SubmissionRepository
+import de.rki.coronawarnapp.util.TanHelper
class SubmissionTanViewModel : ViewModel() {
@@ -16,7 +17,21 @@ class SubmissionTanViewModel : ViewModel() {
val isValidTanFormat =
Transformations.map(tan) {
- it != null && it.length == TanConstants.MAX_LENGTH
+ it != null &&
+ it.length == TanConstants.MAX_LENGTH &&
+ TanHelper.isChecksumValid(it) &&
+ TanHelper.allCharactersValid(it)
+ }
+
+ val tanChecksumValid =
+ Transformations.map(tan) {
+ ((it !== null && it.trim().length == TanConstants.MAX_LENGTH) &&
+ TanHelper.isChecksumValid(it).not()).not()
+ }
+
+ val tanCharactersValid =
+ Transformations.map(tan) {
+ !((it != null) && TanHelper.allCharactersValid(it).not())
}
fun storeTeletan() {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt
index 3037b5b61e0..85c53feadad 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt
@@ -1,5 +1,6 @@
package de.rki.coronawarnapp.ui.submission
+import android.app.AlertDialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -110,17 +111,11 @@ class SubmissionTestResultFragment : BaseFragment() {
}
binding.submissionTestResultButtonPendingRemoveTest.setOnClickListener {
- submissionViewModel.deregisterTestFromDevice()
- doNavigate(
- SubmissionTestResultFragmentDirections.actionSubmissionResultFragmentToMainFragment()
- )
+ removeTestAfterConfirmation()
}
binding.submissionTestResultButtonNegativeRemoveTest.setOnClickListener {
- submissionViewModel.deregisterTestFromDevice()
- doNavigate(
- SubmissionTestResultFragmentDirections.actionSubmissionResultFragmentToMainFragment()
- )
+ removeTestAfterConfirmation()
}
binding.submissionTestResultButtonPositiveContinue.setOnClickListener {
@@ -128,13 +123,10 @@ class SubmissionTestResultFragment : BaseFragment() {
}
binding.submissionTestResultButtonInvalidRemoveTest.setOnClickListener {
- submissionViewModel.deregisterTestFromDevice()
- doNavigate(
- SubmissionTestResultFragmentDirections.actionSubmissionResultFragmentToMainFragment()
- )
+ removeTestAfterConfirmation()
}
- binding.submissionTestResultHeader.headerButtonBack.buttonIcon.setOnClickListener {
+ binding.submissionTestResultHeader.headerToolbar.setNavigationOnClickListener {
doNavigate(
SubmissionTestResultFragmentDirections.actionSubmissionResultFragmentToMainFragment()
)
@@ -158,4 +150,23 @@ class SubmissionTestResultFragment : BaseFragment() {
.actionSubmissionResultFragmentToSubmissionResultPositiveOtherWarningFragment()
)
}
+
+ private fun removeTestAfterConfirmation() {
+ val removeTestDialog = DialogHelper.DialogInstance(
+ requireActivity(),
+ R.string.submission_test_result_dialog_remove_test_title,
+ R.string.submission_test_result_dialog_remove_test_message,
+ R.string.submission_test_result_dialog_remove_test_button_positive,
+ R.string.submission_test_result_dialog_remove_test_button_negative,
+ positiveButtonFunction = {
+ submissionViewModel.deregisterTestFromDevice()
+ doNavigate(
+ SubmissionTestResultFragmentDirections.actionSubmissionResultFragmentToMainFragment()
+ )
+ }
+ )
+ DialogHelper.showDialog(removeTestDialog).apply {
+ getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(context.getColor(R.color.colorTextSemanticRed))
+ }
+ }
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt
index b6be13be81d..644cf1ee0f3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt
@@ -1,6 +1,6 @@
package de.rki.coronawarnapp.ui.submission
object TanConstants {
- const val MAX_LENGTH = 7
+ const val MAX_LENGTH = 10
val ALPHA_NUMERIC_CHARS = ('a'..'z').plus('A'..'Z').plus('0'..'9')
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt
index 70cc48b6833..f95bafeb917 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt
@@ -8,6 +8,9 @@ import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout
import androidx.core.widget.doOnTextChanged
import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.ui.submission.TanConstants.MAX_LENGTH
+import de.rki.coronawarnapp.util.TanHelper
+import java.util.Locale
import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_edittext
import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_1
import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_2
@@ -16,6 +19,11 @@ import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_4
import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_5
import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_6
import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_7
+import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_8
+import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_9
+import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_10
+import kotlinx.android.synthetic.main.view_tan_input.view.dash_view_1
+import kotlinx.android.synthetic.main.view_tan_input.view.dash_view_2
class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) {
@@ -30,7 +38,7 @@ class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, att
TanConstants.ALPHA_NUMERIC_CHARS.contains(it)
}
}
- private val lengthFilter = InputFilter.LengthFilter(TanConstants.MAX_LENGTH)
+ private var lengthFilter = InputFilter.LengthFilter(MAX_LENGTH)
var listener: ((String?) -> Unit)? = null
@@ -41,6 +49,9 @@ class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, att
tan_input_edittext.filters = arrayOf(whitespaceFilter, alphaNumericFilter, lengthFilter)
+ dash_view_1.text = "-"
+ dash_view_2.text = "-"
+
// register listener
tan_input_edittext.doOnTextChanged { text, _, _, _ -> updateTan(text) }
setOnClickListener { showKeyboard() }
@@ -56,9 +67,20 @@ class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, att
}
}
+ private fun limitLength(length: Int?) {
+ lengthFilter = InputFilter.LengthFilter(if (length != null) length else MAX_LENGTH)
+ tan_input_edittext.filters = arrayOf(whitespaceFilter, alphaNumericFilter, lengthFilter)
+ }
+
private fun updateTan(text: CharSequence?) {
- this.tan = text?.toString()
+ this.tan = text?.toString()?.toUpperCase(Locale.getDefault())
updateDigits()
+ tan?.let {
+ limitLength(
+ if (TanHelper.allCharactersValid(it)) null
+ else it.length
+ )
+ }
notifyListener()
}
@@ -71,9 +93,24 @@ class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, att
tan_input_textview_4,
tan_input_textview_5,
tan_input_textview_6,
- tan_input_textview_7
+ tan_input_textview_7,
+ tan_input_textview_8,
+ tan_input_textview_9,
+ tan_input_textview_10
).forEachIndexed { i, tanDigit ->
tanDigit.text = digitAtIndex(i)
+ tanDigit.background =
+ if (digitAtIndex(i) == "")
+ resources.getDrawable(R.drawable.tan_input_digit, null)
+ else if (TanHelper.isTanCharacterValid(digitAtIndex(i)))
+ resources.getDrawable(R.drawable.tan_input_digit_entered, null)
+ else resources.getDrawable(R.drawable.tan_input_digit_error, null)
+
+ tanDigit.setTextColor(
+ if (TanHelper.isTanCharacterValid(digitAtIndex(i)))
+ resources.getColor(R.color.colorTextSemanticNeutral, null)
+ else resources.getColor(R.color.colorTextSemanticRed, null)
+ )
}
private fun digitAtIndex(index: Int): String = tan?.getOrNull(index)?.toString() ?: ""
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
index 60ab8b5cdc4..60376083e32 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
@@ -6,7 +6,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.http.CwaWebException
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.service.submission.SubmissionService
import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.storage.SubmissionRepository
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/TracingViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/TracingViewModel.kt
index ad8a5d362fc..4bccd807c69 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/TracingViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/TracingViewModel.kt
@@ -6,7 +6,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import de.rki.coronawarnapp.exception.ExceptionCategory.INTERNAL
import de.rki.coronawarnapp.exception.TransactionException
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.storage.ExposureSummaryRepository
import de.rki.coronawarnapp.storage.RiskLevelRepository
import de.rki.coronawarnapp.storage.TracingRepository
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/update/UpdateChecker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/update/UpdateChecker.kt
index 2644430f991..3d56617f253 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/update/UpdateChecker.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/update/UpdateChecker.kt
@@ -14,6 +14,7 @@ import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.UpdateAvailability
import de.rki.coronawarnapp.BuildConfig
import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.exception.CwaSecurityException
import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass
import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService
import de.rki.coronawarnapp.ui.LauncherActivity
@@ -31,12 +32,13 @@ class UpdateChecker(private val activity: LauncherActivity) {
suspend fun checkForUpdate() {
// check if an update is needed based on server config
- // TODO replace with signature exception
val updateNeededFromServer: Boolean = try {
checkIfUpdatesNeededFromServer()
+ } catch (exception: CwaSecurityException) {
+ Log.e(TAG, "CwaSecurityException caught:" + exception.localizedMessage)
+ true
} catch (exception: Exception) {
- Log.e(TAG, exception.localizedMessage ?: "unknown error")
- exception.printStackTrace()
+ Log.e(TAG, "Exception caught:" + exception.localizedMessage)
false
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt
index 7cd591d3bbe..aba5ccaa6a5 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt
@@ -13,7 +13,7 @@ import android.net.NetworkRequest
import android.os.Build
import android.util.Log
import de.rki.coronawarnapp.exception.ExceptionCategory
-import de.rki.coronawarnapp.exception.report
+import de.rki.coronawarnapp.exception.reporting.report
/**
* Helper for connectivity statuses.
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/IndexHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/IndexHelper.kt
deleted file mode 100644
index 1ea82db6601..00000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/IndexHelper.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/******************************************************************************
- * Corona-Warn-App *
- * *
- * SAP SE and all other contributors / *
- * copyright owners license this file to you under the Apache *
- * License, Version 2.0 (the "License"); you may not use this *
- * file except in compliance with the License. *
- * You may obtain a copy of the License at *
- * *
- * http://www.apache.org/licenses/LICENSE-2.0 *
- * *
- * Unless required by applicable law or agreed to in writing, *
- * software distributed under the License is distributed on an *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
- * KIND, either express or implied. See the License for the *
- * specific language governing permissions and limitations *
- * under the License. *
- ******************************************************************************/
-
-package de.rki.coronawarnapp.util
-
-import android.util.Log
-import com.google.common.base.Splitter
-import de.rki.coronawarnapp.BuildConfig
-import java.util.regex.Pattern
-
-@Suppress("ComplexCondition", "TooGenericExceptionThrown")
-object IndexHelper {
- private val TAG: String? = IndexHelper::class.simpleName
- private val WHITESPACE_SPLITTER: Splitter =
- Splitter.onPattern("\\s+").trimResults().omitEmptyStrings()
-
- private val INDEX_ELEMENT_PATTERN: Pattern = Pattern.compile("Cwa-([A-Z]{2})/([0-9]{10})-([0-9]+).zip")
-
- private const val GROUP_COUNT = 3
- private const val COUNTRY_CODE_GROUP = 1
- private const val TIMESTAMP_GROUP = 2
- private const val BATCH_NUMBER_GROUP = 3
-
- /**
- * Converts a String to an index according to the Delimiter defined in [WHITESPACE_SPLITTER] and the
- * Regular Expression of an index element defined in [INDEX_ELEMENT_PATTERN]. The Pattern has to define
- * 3 Groups.
- * 1. Country Code Information
- * 2. Creation Epoch of the Batch
- * 3. Batch Number
- *
- * @return Map of Batch Number to File Names (from the Index)
- */
- fun String.convertToIndex(): Map = WHITESPACE_SPLITTER.splitToList(this).also {
- if (BuildConfig.DEBUG) Log.d(TAG, "Index(${it.size} Elements):$it")
- }.associateBy { indexElement ->
- val matcher = INDEX_ELEMENT_PATTERN.matcher(indexElement)
- if (
- !matcher.matches() ||
- matcher.groupCount() != GROUP_COUNT ||
- matcher.group(COUNTRY_CODE_GROUP) != null ||
- matcher.group(TIMESTAMP_GROUP) != null ||
- matcher.group(BATCH_NUMBER_GROUP) != null
- ) throw RuntimeException("Failed to parse batch from $indexElement")
- val isoCountryCode =
- matcher.group(COUNTRY_CODE_GROUP)
- ?: throw NullPointerException("Batch Regex Group 1 (Country Code) must not be null")
- val timestampString =
- matcher.group(TIMESTAMP_GROUP)
- ?: throw NullPointerException("Batch Regex Group 2 (Timestamp) must not be null")
- val batchNumberString =
- matcher.group(BATCH_NUMBER_GROUP)
- ?: throw NullPointerException("Batch Regex Group 3 (Batch Number) must not be null")
-
- if (BuildConfig.DEBUG) Log.d(
- TAG, "index element " +
- "$indexElement=(Timestamp:$timestampString, BatchNum:$batchNumberString, " +
- "ISOCountryCode:$isoCountryCode"
- )
-
- timestampString.toLong()
- }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/PropertyLoader.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/PropertyLoader.kt
deleted file mode 100644
index c162ac72f29..00000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/PropertyLoader.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package de.rki.coronawarnapp.util
-
-import android.util.Log
-import de.rki.coronawarnapp.CoronaWarnApplication
-import java.util.Properties
-
-class PropertyLoader {
- companion object {
- private const val PIN_PROPERTIES_FILE_NAME = "pins.properties"
- private const val PIN_FILE_DELIMITER = ","
- private const val DISTRIBUTION_PIN_PROPERTY_NAME = "DISTRIBUTION_PINS"
- private const val SUBMISSION_PINS_PROPERTY_NAME = "SUBMISSION_PINS"
- private const val VERIFICATION_PINS_PROPERTY_NAME = "VERIFICATION_PINS"
- }
-
- fun getDistributionPins() = getCertificatePins(DISTRIBUTION_PIN_PROPERTY_NAME)
- fun getSubmissionPins() = getCertificatePins(SUBMISSION_PINS_PROPERTY_NAME)
- fun getVerificationPins() = getCertificatePins(VERIFICATION_PINS_PROPERTY_NAME)
-
- private fun getCertificatePins(key: String): Array = Properties().run {
- this.load(CoronaWarnApplication.getAppContext().assets.open(PIN_PROPERTIES_FILE_NAME))
- this.getProperty(key)
- .split(PIN_FILE_DELIMITER)
- .filter { it.isNotEmpty() }
- .also { Log.v(key, it.toString()) }
- .toTypedArray()
- }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TanHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TanHelper.kt
new file mode 100644
index 00000000000..9693fab69ac
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TanHelper.kt
@@ -0,0 +1,33 @@
+package de.rki.coronawarnapp.util
+
+import de.rki.coronawarnapp.ui.submission.TanConstants.MAX_LENGTH
+import java.security.MessageDigest
+import java.util.Locale
+
+object TanHelper {
+ private const val VALID_CHARACTERS = "23456789ABCDEFGHJKMNPQRSTUVWXYZ"
+
+ fun isChecksumValid(tan: String): Boolean {
+ if (tan.trim().length != MAX_LENGTH)
+ return false
+ val subTan = tan.substring(0, MAX_LENGTH - 1).toUpperCase(Locale.getDefault())
+ val tanDigest = MessageDigest.getInstance("SHA-256").digest(subTan.toByteArray())
+ var checkChar = "%02x".format(tanDigest[0])[0]
+ if (checkChar == '0') checkChar = 'G'
+ if (checkChar == '1') checkChar = 'H'
+
+ return checkChar.toUpperCase() == tan.last().toUpperCase()
+ }
+
+ fun allCharactersValid(tan: String): Boolean {
+ for (character in tan) {
+ if (!isTanCharacterValid(character.toString()))
+ return false
+ }
+ return true
+ }
+
+ fun isTanCharacterValid(character: String): Boolean {
+ return VALID_CHARACTERS.contains(character)
+ }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt
index 743c2af9459..9b0914336fa 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt
@@ -352,12 +352,12 @@ fun formatStableIconColor(riskLevelScore: Int?): Int =
* @param riskLevelScore
* @return
*/
-fun formatStableBackButtonColor(riskLevelScore: Int?): ColorStateList? {
+fun formatStableBackButtonIcon(riskLevelScore: Int?): Drawable? {
val appContext = CoronaWarnApplication.getAppContext()
- return if (!isTracingOffRiskLevel(riskLevelScore)) {
- appContext.getColorStateList(R.color.button_back)
+ return if (isTracingOffRiskLevel(riskLevelScore)) {
+ appContext.getDrawable(R.drawable.ic_close_dark)
} else {
- appContext.getColorStateList(R.color.button_back_stable)
+ appContext.getDrawable(R.drawable.ic_close_light)
}
}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt
index dbe3e29ed71..c9502ce5d27 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt
@@ -193,3 +193,8 @@ fun formatShowRiskStatusCard(deviceUiState: DeviceUIState?): Int =
deviceUiState != DeviceUIState.PAIRED_POSITIVE_TELETAN &&
deviceUiState != DeviceUIState.SUBMITTED_FINAL
)
+
+fun formatShowTanCharacterError(
+ charactersValid: Boolean,
+ checksumValid: Boolean
+): Int = formatVisibility(checksumValid && !charactersValid)
diff --git a/Corona-Warn-App/src/main/res/drawable/ic_close_dark.xml b/Corona-Warn-App/src/main/res/drawable/ic_close_dark.xml
new file mode 100644
index 00000000000..6b3c8307a45
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/ic_close_dark.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/Corona-Warn-App/src/main/res/drawable/ic_close_light.xml b/Corona-Warn-App/src/main/res/drawable/ic_close_light.xml
new file mode 100644
index 00000000000..a0fd695b693
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/ic_close_light.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml b/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml
index d06cdb9200e..48e3d0c51a8 100644
--- a/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml
+++ b/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml
@@ -1,11 +1,20 @@
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable/tan_input_digit_entered.xml b/Corona-Warn-App/src/main/res/drawable/tan_input_digit_entered.xml
new file mode 100644
index 00000000000..0550164c034
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/tan_input_digit_entered.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable/tan_input_digit_error.xml b/Corona-Warn-App/src/main/res/drawable/tan_input_digit_error.xml
new file mode 100644
index 00000000000..01780eeb09b
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable/tan_input_digit_error.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_information.xml b/Corona-Warn-App/src/main/res/layout/fragment_information.xml
index da08ae6e6ea..931078c802b 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_information.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_information.xml
@@ -25,7 +25,6 @@
app:title="@{@string/information_title}" />
+ app:subtitle="@{@string/information_about_title}" />
+ app:subtitle="@{@string/information_help_title}" />
+ app:subtitle="@{@string/information_terms_title}" />
+ app:subtitle="@{@string/information_privacy_title}" />
+ app:subtitle="@{@string/information_technical_title}" />
+ app:subtitle="@{@string/information_contact_title}" />
+ app:subtitle="@{@string/information_legal_title}" />
-
+ app:layout_constraintTop_toBottomOf="@+id/information_legal_header_details" />
+
+
+
+
+
+
+
+
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_information_privacy.xml b/Corona-Warn-App/src/main/res/layout/fragment_information_privacy.xml
index 056e50cc3ee..637c7cee80d 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_information_privacy.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_information_privacy.xml
@@ -26,7 +26,6 @@
app:title="@{@string/information_privacy_title}" />
-
+ app:layout_constraintTop_toBottomOf="@+id/information_privacy_header_details" />
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_information_technical.xml b/Corona-Warn-App/src/main/res/layout/fragment_information_technical.xml
index 19c05927253..50b2021336c 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_information_technical.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_information_technical.xml
@@ -26,7 +26,6 @@
app:title="@{@string/information_technical_title}" />
-
+ app:layout_constraintTop_toBottomOf="@+id/information_technical_header_details" />
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_information_terms.xml b/Corona-Warn-App/src/main/res/layout/fragment_information_terms.xml
index 4fdffed28f0..17885b9567d 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_information_terms.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_information_terms.xml
@@ -2,6 +2,14 @@
+
+
+
+
+
+
+
+
@@ -19,7 +27,6 @@
app:title="@{@string/information_terms_title}" />
-
-
-
-
+ app:layout_constraintTop_toTopOf="parent">
@@ -117,9 +111,9 @@
@@ -128,7 +122,7 @@
layout="@layout/include_risk_card"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/spacing_normal"
+ android:layout_marginTop="@dimen/spacing_small"
android:visibility="@{FormatterSubmissionHelper.formatShowRiskStatusCard(submissionViewModel.deviceUiState)}"
app:layout_constraintEnd_toStartOf="@+id/guideline_end"
app:layout_constraintStart_toStartOf="@+id/guideline_start"
@@ -140,7 +134,7 @@
+ app:constraint_referenced_ids="main_test, main_test_done, main_test_positive, main_risk" />
+ app:layout_constraintGuide_begin="@dimen/spacing_small" />
+ app:layout_constraintGuide_end="@dimen/spacing_small" />
+ app:layout_constraintGuide_end="@dimen/spacing_small" />
+ app:layout_constraintGuide_begin="@dimen/spacing_small" />
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_main_overview.xml b/Corona-Warn-App/src/main/res/layout/fragment_main_overview.xml
index ea311e0253a..a2d3826e64a 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_main_overview.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_main_overview.xml
@@ -19,7 +19,6 @@
app:title="@{@string/main_overview_title}" />
+ app:subtitle="@{@string/main_overview_subtitle_increased_risk}" />
+ app:subtitle="@{@string/main_overview_subtitle_low_risk}" />
+ app:subtitle="@{@string/main_overview_subtitle_unknown_risk}" />
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_risk_details.xml b/Corona-Warn-App/src/main/res/layout/fragment_risk_details.xml
index 72b5d8ce565..3e5f3ad200d 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_risk_details.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_risk_details.xml
@@ -24,8 +24,30 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
+
+
+
+
+
+
+ app:layout_constraintTop_toBottomOf="@+id/risk_details_app_bar_layout">
+
+
+
+
+
+
diff --git a/Corona-Warn-App/src/main/res/values-de/strings.xml b/Corona-Warn-App/src/main/res/values-de/strings.xml
new file mode 100644
index 00000000000..2daec59e50e
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/values-de/strings.xml
@@ -0,0 +1,823 @@
+
+
+
+
+
+
+ "shared_preferences_cwa"
+
+ "preference_onboarding_completed"
+
+ "preference_onboarding_completed_timestamp"
+
+ "preference_reset_app"
+
+ "preference_only_wifi"
+
+ "preference_tracing"
+
+ "preference_timestamp_diagnosis_keys_fetch"
+
+ "preference_timestamp_manual_diagnosis_keys_retrieval"
+
+ "preference_m_string_google_api_token"
+
+ "preference_notifications_enabled"
+
+ "preference_notifications_risk_enabled"
+
+ "preference_notifications_test_enabled"
+
+ "preference_background_job_enabled"
+
+ "preference_mobile_data_enabled"
+
+ "preference_registration_token"
+ "preference_device_pairing_successful_time"
+
+ "preference_initial_tracing_activation_time"
+
+ "preference_initial_result_received_time"
+
+ "preference_risk_level_score"
+
+ "preference_risk_level_score_successful"
+
+ "preference_test_guid"
+
+ "preference_is_allowed_to_submit_diagnosis_keys"
+
+ "preference_auth_code"
+
+ "preference_database_password"
+
+ "preference_total_non_active_tracing"
+
+ "preference_last_non_active_tracing_timestamp"
+
+ "preference_number_successful_submissions"
+
+ "preference_teletan"
+
+ "preference_last_three_hours_from_server"
+
+
+
+
+
+
+ "Überblick"
+
+ "App-Informationen"
+
+ "Einstellungen"
+
+
+
+ "de.rki.coronawarnapp.notification.exposureNotificationChannelId"
+
+ "1"
+ "Corona-Warn-App"
+ "Benachrichtigungen aus der Corona-Warn-App"
+ "Corona-Warn-App"
+ "Es gibt Neuigkeiten von Ihrer Corona-Warn-App."
+
+
+
+
+ "Bisher keine Risiko-Begegnungen"
+
+ "%1$s Risiko-Begegnung"
+ "%1$s Risiko-Begegnungen"
+
+
+ "%1$s von 14 Tagen gespeichert"
+ "Begegnungen wurden noch nicht überprüft."
+ "Aktualisiert: %1$s"
+ "Tägliche Aktualisierung"
+
+ "Aktualisieren"
+ "Aktualisierung in %1$s"
+
+ "Risiko-Ermittlung einschalten"
+
+ "Aktivieren Sie die Risiko-Ermittlung, um Ihre heutige Risikostatus zu berechnen."
+
+ "Niedriges Risiko"
+
+ "Erhöhtes Risiko"
+
+ "%1$s Tag seit der letzten Begegnung"
+ "%1$s Tage seit der letzten Begegnung"
+
+
+ "Unbekanntes Risiko"
+
+ "Da Sie die Risiko-Ermittlung noch nicht lange genug aktiviert haben, konnten wir für Sie kein Infektionsrisiko berechnen."
+
+ "Risiko-Ermittlung gestoppt"
+ "Letzte Risiko-Ermittlung:""\n""%1$s"
+
+ "Risiko-Ermittlung nicht möglich"
+
+ "Ihre Risiko-Ermittlung konnte seit mehr als 24 Stunden nicht aktualisiert werden."
+
+ "Prüfung läuft…"
+
+ "Es werden aktuelle Daten heruntergeladen und geprüft. Dies kann mehrere Minuten dauern."
+
+
+
+
+ "Häufige Fragen"
+
+ "Hier finden Sie Antworten auf häufig gestellte Fragen rund um die Corona-Warn-App."
+
+ "https://www.bundesregierung.de/corona-warn-app-faq"
+
+
+
+
+ "Corona-Warn-App teilen"
+
+ "Gemeinsam Corona bekämpfen"
+
+ "Je mehr Menschen mitmachen, desto besser durchbrechen wir Infektionsketten. Laden Sie Familie, Freunde und Bekannte ein!"
+
+ "Download-Link versenden"
+
+ "Gemeinsam Corona bekämpfen""\n""Ich bin dabei. Du auch?""\n""https://www.coronawarn.app/""\n"
+
+ "Ein Mann teilt die Corona-Warn-App mit vier anderen Personen."
+
+
+
+
+ "Überblick"
+
+ "Risiko-Ermittlung"
+
+ "Die Risiko-Ermittlung ist eine der drei zentralen Funktionen der App. Ist sie aktiv, werden Begegnungen aufgezeichnet. Sie brauchen sich um nichts mehr zu kümmern."
+
+ "Infektionsrisiko"
+
+ "Sind Sie innerhalb der letzten 14 Tage einer Corona-positiv getesteten Person begegnet, berechnet die App Ihr persönliches Infektionsrisiko. Als Grundlage dafür misst sie, über welche Dauer und mit welchem Abstand eine Begegnung stattfand."
+
+ "Folgende Risikostufen können angezeigt werden:"
+
+ "Erhöhtes Risiko"
+
+ "Niedriges Risiko"
+
+ "Unbekanntes Risiko"
+
+ "Benachrichtigung anderer"
+
+ "Eine weitere zentrale Funktion. Hier können Sie Ihren Test registrieren und seinen Status abfragen. Bei einem positiven Test können Sie andere warnen und damit Infektionsketten unterbrechen."
+
+ "Wichtige Begriffe:"
+
+ "Begegnungs-Aufzeichnung"
+
+ "Liste der empfangenen und vorübergehend im Betriebssystemspeicher abgelegten kurzlebigen Zufallscodes. Diese Liste wird bei der Risiko-Überprüfung gelesen. Alle Zufallscodes werden nach 14 Tagen automatisch gelöscht."
+
+ "Risiko-Überprüfung"
+
+ "Abfrage der Begegnungs-Aufzeichnung und Abgleich mit den gemeldeten Infektionen anderer Nutzerinnen und Nutzer. Die Risiko-Überprüfung erfolgt automatisch ungefähr alle zwei Stunden."
+
+ "Risiko-Begegnungen"
+
+ "Jene Begegnungen mit einer Corona-positiv getesteten Person, die über einen längeren Zeitraum und in geringer Distanz stattfanden."
+
+ "Risiko-Benachrichtigung"
+
+ "Die Anzeige von Risiko-Begegnungen in der Corona-Warn-App."
+
+ "Zufallscode"
+
+ "Die Zufallscodes sind zufällig erzeugte Zahlen- und Buchstabenkombinationen. Sie werden zwischen benachbarten Smartphones ausgetauscht. Zufallskennungen lassen sich nicht einer bestimmten Person zuordnen und werden nach 14 Tagen automatisch gelöscht. Eine Corona-positiv getestete Person kann ihre Zufallscodes der letzten bis zu 14 Tage freiwillig mit anderen CWA-Nutzern teilen."
+
+ "Ein Smartphone zeigt unterschiedliche Inhalte, die von eins bis drei nummeriert sind."
+
+
+
+
+ "Verhalten"
+
+ "So verhalten Sie sich richtig"
+
+ "Begeben Sie sich umgehend nach Hause bzw. bleiben Sie zu Hause."
+
+ "Für Fragen zu auftretenden Symptomen, Testmöglichkeiten und weiteren Absonderungsmaßnahmen, wenden Sie sich bitte an eine der folgenden Stellen:"
+
+ "Waschen Sie Ihre Hände regelmäßig."
+
+ "Tragen Sie einen Mundschutz bei Kontakt mit anderen Personen."
+
+ "Halten Sie mindestens 1,5 Meter Abstand zu anderen Personen."
+
+ "Niesen oder husten Sie in die Armbeuge oder in ein Taschentuch."
+
+ "Ihre Hausärztin/Ihren Hausarzt"
+
+ "Den Kassenärztlichen Notdienst unter der Telefonnummer: 116117"
+
+ "Ihr Gesundheitsamt"
+
+ "Infektionsrisiko"
+
+ "So wurde Ihr Risiko ermittelt"
+
+ "So wird Ihr Risiko ermittelt"
+
+ "Da Sie die Risiko-Ermittlung noch nicht lange genug aktiviert haben, konnten wir für Sie kein Infektionsrisiko berechnen."
+
+ "Ihre Risiko-Ermittlung konnte seit mehr als 24 Stunden nicht aktualisiert werden."
+ "Sie haben ein niedriges Infektionsrisiko, da keine Begegnung mit nachweislich Corona-positiv getesteten Personen aufgezeichnet wurde oder sich Ihre Begegnung auf kurze Zeit und einen größeren Abstand beschränkt hat."
+
+ "Sie haben ein erhöhtes Infektionsrisiko, da Sie zuletzt vor %1$s Tag mindestens einer Corona-positiv getesteten Person über einen längeren Zeitraum und mit einem geringen Abstand begegnet sind."
+ "Sie haben ein erhöhtes Infektionsrisiko, da Sie zuletzt vor %1$s Tagen mindestens einer Corona-positiv getesteten Person über einen längeren Zeitraum und mit einem geringen Abstand begegnet sind."
+
+ "Das Infektionsrisiko wird anhand der Daten der Risiko-Ermittlung unter Berücksichtigung von Abstand und Dauer lokal auf Ihrem Smartphone berechnet. Ihr Infektionsrisiko ist für niemanden einsehbar und wird nicht weitergegeben."
+ @string/risk_card_button_update
+ @string/risk_card_button_enable_tracing
+
+
+
+ "IS MISSING"
+ "Nicht aktivieren"
+
+ "Weiter"
+
+ "Los geht’s"
+
+ "Zurück"
+
+ "Gemeinsam Corona bekämpfen"
+
+ "Mehr Schutz für Sie und uns alle. Mit der Corona-Warn-App durchbrechen wir Infektionsketten schneller."
+
+ "Machen Sie Ihr Smartphone zum Corona-Warn-System. Überblicken Sie Ihren Risikostatus und erfahren Sie, ob in den letzten 14 Tagen Corona-positiv getestete Personen in ihrer Nähe waren."
+
+ "Die App merkt sich Begegnungen zwischen Menschen, indem ihre Smartphones verschlüsselte Zufallscodes austauschen. Und zwar ohne dabei auf persönliche Daten zuzugreifen."
+
+ "Eine vielfältige Gruppe in einer Stadt benutzt Smartphones."
+ @string/lorem_ipsum
+
+ "Eine Frau mit einem Handy benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten."
+
+ "Wie Sie die Risiko-Ermittlung ermöglichen"
+
+ "Um zu erkennen, ob für Sie ein Ansteckungsrisiko vorliegt, müssen Sie die Risiko-Ermittlung aktivieren."
+
+ "Die Risiko-Ermittlung funktioniert, indem Ihr Handy per Bluetooth verschlüsselte Zufallscodes anderer Nutzerinnen und Nutzer empfängt und Ihren eigenen Zufallscode an deren Smartphones weitergibt. Die Funktion lässt sich jederzeit wieder deaktivieren."
+
+ "Die verschlüsselten Zufallscodes geben nur Auskunft über das Datum, die Dauer und die anhand der Signalstärke berechnete Entfernung zu Ihren Mitmenschen. Persönliche Daten wie Name, Adresse oder Aufenthaltsort werden zu keiner Zeit erfasst. Konkrete Rückschlüsse auf Personen sind nicht möglich."
+
+ "Berechtigung"
+
+ "Corona-Warn-App kann dadurch keine Benachrichtigungen zum COVID-19 Risikostatus versenden und empfangen. Sie können die Funktion jederzeit ausschalten."
+
+ "Nicht aktivieren"
+
+ "Zurück"
+
+ "Drei Personen haben die Risiko-Erkennung auf ihren Smartphones aktiviert, ihre Begegnung wird daher aufgezeichnet."
+
+ "Falls Sie Corona-positiv getestet werden ..."
+
+ "... teilen Sie es bitte über die Corona-Warn-App mit. Freiwillig und sicher. Für die Gesundheit aller."
+
+ "Ihre Mitteilung wird zuverlässig verschlüsselt über einen sicheren Server weiterverarbeitet. Die Personen, deren verschlüsselte Zufallscodes Sie gesammelt haben, erhalten nun eine Warnung und Informationen darüber, wie sie weiter vorgehen sollen."
+
+ "Ein positiver Testbefund wird verschlüsselt ins System übermittelt, das nun andere Nutzerinnen und Nutzer warnt."
+
+ "Warnungen erhalten, Risiken kennen"
+
+ "Die App kann Sie automatisch über Ihren Risikostatus informieren und bei Neuinfektionen von Menschen, denen Sie begegnet sind, warnen. Erlauben Sie der App jetzt, Sie zu benachrichtigen."
+
+ "Auf diese Weise können Sie sich zum Schutz Ihrer Mitmenschen in Isolation begeben und sich nach entsprechender Abklärung testen lassen."
+
+ "Eine Frau erhält eine Mitteilung von ihrer Corona-Warn-App."
+
+
+
+
+ "Einstellungen"
+
+ "An"
+
+ "Aus"
+
+ "Risiko-Ermittlung"
+
+ "So funktioniert die Begegnungs-Aufzeichnung"
+
+ "Erlauben Sie Erfassung und Weitergabe von Covid-19 Zufallscodes."
+
+ "Risiko-Ermittlung aktiv"
+
+ "Risiko-Ermittlung gestoppt"
+
+ "Um zu erkennen, ob für Sie ein Ansteckungsrisiko vorliegt, müssen Sie die Risiko-Ermittlung aktivieren. Die Risiko-Ermittlung funktioniert, indem Ihr Handy per Bluetooth verschlüsselte Zufallscodes anderer Nutzerinnen und Nutzer empfängt und Ihren eigenen Zufallscode an deren Smartphones weitergibt. Die Funktion lässt sich jederzeit wieder deaktivieren.""\n""\n""Die verschlüsselten Zufallscodes geben nur Auskunft über das Datum, die Dauer und die anhand der Signalstärke berechnete Entfernung zu Ihren Mitmenschen. Persönliche Daten wie Name, Adresse oder Aufenthaltsort werden zu keiner Zeit erfasst. Konkrete Rückschlüsse auf Personen sind nicht möglich."
+
+ "Aktiv"
+
+ "Gestoppt"
+
+ "Eingeschränkt"
+
+ "Keine Internetverbindung"
+
+ "Bluetooth deaktiviert"
+
+ "Bluetooth aktivieren"
+
+ "Die Risiko-Ermittlung benötigt aktiviertes Bluetooth, um Begegnungen aufzuzeichnen. Bitte aktivieren Sie Bluetooth in Ihren Geräte-Einstellungen."
+
+ "Geräte-Einstellungen öffnen"
+
+ "Internetverbindung herstellen"
+
+ "Die Risiko-Ermittlung benötigt eine Internetverbindung, um Risiko-Begegnungen berechnen zu können. Bitte aktivieren Sie WLAN oder mobile Daten in Ihren Geräte-Einstellungen."
+
+ "Geräte-Einstellungen öffnen"
+
+
+ "Die Risiko-Ermittlung ist seit insgesamt einem Tag aktiv. Eine verlässliche Risiko-Überprüfung kann nur mit einer dauerhaft aktivierten Risiko-Ermittlung erfolgen."
+ "Die Risiko-Ermittlung ist seit insgesamt %1$s Tagen aktiv. Eine verlässliche Risiko-Überprüfung kann nur mit einer dauerhaft aktivierten Risiko-Ermittlung erfolgen."
+
+
+ "Drei Personen haben die Risiko-Erkennung auf ihren Smartphones aktiviert, ihre Begegnung wird daher aufgezeichnet."
+
+ "Eine Person hat die Risiko-Erkennung auf ihrem Smartphone ausgeschaltet, eine Begegnung mit zwei weiteren Personen wird daher nicht aufgezeichnet."
+
+ "Eine Person hat Bluetooth auf ihrem Smartphone ausgeschaltet, eine Begegnung mit zwei weiteren Personen wird daher nicht aufgezeichnet."
+
+ "Eine Person hat die Risiko-Erkennung auf ihrem Smartphone ausgeschaltet, eine Begegnung mit zwei weiteren Personen wird daher nicht aufgezeichnet."
+
+
+ "Mitteilungen"
+
+ "Möchten Sie Mitteilungen zu Ihrem Covid-19-Risikostatus aktivieren?"
+
+ "Mitteilungen sind deaktiviert"
+
+ "Erlauben Sie automatische Mitteilungen zu Covid-19-Risikostatus."
+ "Legen Sie fest, zu welchen Themen Sie informiert beiben möchten."
+
+ "Um Mitteilungen zu aktivieren, müssen Sie Mitteilungen für die Corona-Warn-App in Ihren Telefoneinstellungen zulassen."
+
+ "Mitteilungen"
+
+ "Ändern Ihres Infektionsrisikos"
+
+ "Status Ihres COVID-19 Tests"
+
+ "Geräte-Einstellungen öffnen"
+
+ "Eine Frau erhält eine Mitteilung von ihrer Corona-Warn-App."
+
+ "Eine Frau hat die Mitteilungen ihrer Corona-Warn-App ausgeschaltet."
+
+ "Anwendung zurücksetzen"
+
+ "Löschen Sie alle Ihre Daten in der App."
+
+ "Sind Sie sicher, dass Sie die Anwendung zurücksetzen wollen?"
+
+ "Sie werden nicht mehr über Ihre Risiko-Begegnungen informiert und können andere Nutzerinnen und Nutzer nicht mehr warnen."
+
+ "Begegnungs-""\n""Aufzeichnungen löschen"
+
+ "Die Begegnungs-Aufzeichnung muss separat in den Geräte-Einstellungen gelöscht werden."
+
+ "Anwendung zurücksetzen"
+
+ "Abbrechen"
+
+ "Eine Hand hält ein Smartphone, auf dem das Zurücksetzen der Anwendung symbolisiert wird."
+
+
+
+
+
+ "App-Informationen"
+
+ "Version: %1s"
+
+ "Über die App"
+
+ "Gemeinsam Corona bekämpfen"
+
+ "Das Robert Koch-Institut (RKI) als zentrale Einrichtung des Bundes im Bereich der Öffentlichen Gesundheit und als nationales Public-Health-Institut veröffentlicht die Corona-Warn-App für die gesamte Bundesregierung. Die App ist die digitale Ergänzung zu Abstandhalten, Hygiene und Alltagsmaske."
+
+ "Wer sie nutzt, hilft, Infektionsketten schnell nachzuverfolgen und zu durchbrechen. Die App speichert dezentral – auf Ihrem Smartphone – Begegnungen mit anderen. Sie werden informiert, wenn Sie Kontakt mit nachweislich infizierten Personen hatten. Ihre Privatsphäre bleibt dabei bestens geschützt."
+
+ "Eine vielfältige Gruppe in einer Stadt benutzt Smartphones."
+
+ "Datenschutzinformation"
+
+ "Eine Frau mit einem Handy benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten."
+
+ "Nutzungsbedingungen"
+ @string/lorem_ipsum
+
+ "Eine Hand hält ein Smartphone mit viel Text, daneben ist ein Haken als Symbol für akzeptierte Nutzungsbedingungen."
+
+ "Technische Hotline"
+
+ "Wie können wir Ihnen helfen?"
+
+ "Für technische Fragen rund um die Corona-Warn-App können Sie sich direkt an unsere technische Hotline wenden."
+
+ "Technische Hotline:"
+
+ "+49 (0)800 7540001"
+
+ "Tel:+49 800 7540001"
+
+ "Unser Kundenservice ist für Sie da."
+
+ "Unsere Öffnungszeiten:""\n""Mo – Fr: 08:00 – 22:00 Uhr""\n""Sa – So: 10:00 – 22:00 Uhr""\n""Es gelten die Preise Ihres Telefonanbieters."
+
+ "Für gesundheitliche Fragen, wenden Sie sich bitte an Ihre Hausarztpraxis oder die Hotline des ärztlichen Bereitschaftsdienstes 116 117."
+
+ "Ein Mann nutzt ein Headset zum Telefonieren."
+
+ "Häufige Fragen"
+
+ "Rechtliche Hinweise"
+
+ "Eine Hand hält ein Smartphone mit viel Text, daneben ist eine Balkenwaage als Symbol für rechtliche Hinweise."
+
+ "Impressum"
+
+ "Eine Hand hält ein Smartphone mit viel Text, daneben ist ein Paragraphenzeichen als Symbol für das Impressum."
+
+
+
+
+
+ "Fehler"
+
+ "Es ist ein Verbindungsfehler aufgetreten (%1$d). Bitte versuchen Sie es erneut."
+
+ "Es ist ein Verbindungsfehler aufgetreten. Bitte versuchen Sie es erneut."
+
+ "Zurück"
+
+
+ "Fehler"
+
+ "Der QR-Code / Die TAN ist ungültig oder wurde schon verwendet. Bitte versuchen Sie es erneut oder kontaktieren Sie die technische Hotline über App-InfoInformationen → Technische Hotline."
+
+ "Zurück"
+
+
+ "Fehler"
+
+ "Es konnte keine Übermittlungs-TAN erstellt werden. Bitte kontaktieren Sie die technische Hotline über App-Informationen → Technische Hotline."
+
+ "Zurück"
+
+
+ "Fehler"
+
+ "Es konnte keine Übermittlungs-TAN erstellt werden. Bitte kontaktieren Sie die technische Hotline über App-Informationen → Technische Hotline."
+
+ "Zurück"
+
+
+ "Kamera-Berechtigung benötigt"
+ "Bitte erlauben Sie die Autorisierung der Kamera für das Scannen von QR-Codes."
+ "Erlauben"
+ "Nicht erlauben"
+
+
+ "Scan erfolgreich"
+ "Der QR-Code wurde erfolgreich gescannt."
+ "Registrieren"
+ "Abbrechen"
+
+
+ "Falscher QR-Code"
+ "Es scheint, dass der falsche QR-Code gescannt wurde."
+ "Erneut versuchen"
+ "Abbrechen"
+
+
+
+ "Positionieren Sie den QR-Code in den Rahmen"
+
+
+ "Gerät registrieren"
+ @string/lorem_ipsum
+
+
+
+ "Test-Ergebnis"
+
+ "Info zum Ablauf:"
+
+ "Abschließen"
+
+ "Test erfolgreich hinzugefügt"
+
+ "Ihr Test wurde in der Corona-Warn-App registriert."
+
+ "Test-Ergebnis noch nicht verfügbar"
+
+ "Ihr Test-Ergebnis steht noch nicht zur Verfügung."
+
+ "Aktualisieren"
+
+ "Test entfernen"
+
+ "Ihr Test-Ergebnis"
+
+ "Der Labortest hat keinen Nachweis für das Coronavirus SARS-CoV-2 bei Ihnen ergeben. \n\nBitte entfernen Sie den Test wieder aus der Corona-Warn-App, damit Sie bei Bedarf einen neuen Test hinterlegen können."
+
+ "Test entfernen"
+
+ "Ihr Test-Ergebnis"
+
+ "Ihr Test-Ergebnis wurde als “positiv” verifiziert."
+
+ "Andere warnen"
+
+ "Ihre Zufallscodes der letzten 14 Tage teilen, um andere zu schützen und die Infektionskette zu unterbrechen."
+
+ "Weiter"
+
+ "Ihr Test-Ergebnis"
+
+ "Es gab ein Problem bei der Auswertung Ihres Tests. Bitte kontaktieren Sie das Gesundheitsamt um Information zum weiteren Vorgehen zu erhalten.\n\nBitte entfernen Sie den Test wieder aus der Corona-Warn-App, damit Sie bei Bedarf einen neuen Test hinterlegen können."
+
+ "Test entfernen"
+
+ "Risiko-Ermittlung erforderlich"
+
+ "Bitte aktivieren Sie die Risiko-Ermittlung, um andere zu warnen."
+
+ "Ok"
+
+
+
+ "TAN-Eingabe"
+
+ "Die TAN ist 7-stellig und Groß- und Kleinschreibung muss nicht beachtet werden.\n\nGeben Sie bitte die Ihnen mitgeteilte TAN ein:"
+
+ "Weiter"
+
+
+
+ "Wurden Sie getestet?"
+
+ "So funktioniert das Corona-Warn-System"
+
+ "Damit die Corona-Warn-App funktioniert, sind wir auf die Mithilfe von Corona-positiven Personen angewiesen.\n\nDa nur verschlüsselte Zufallscodes ausgetauscht werden, bleiben Sie unerkannt. Sie können jetzt wie folgt vorgehen:\n"
+
+
"Wenn Sie positiv getestet wurden, können Sie andere warnen."
"\n\n"
"Wenn Ihnen für einen positiven Test eine TAN mitgeteilt wurde, können Sie diese für die Registrierung des Tests nutzen."
"\n\n"
"Wenn Sie keine TAN haben, können Sie diese telefonisch anfragen."
+
+ "Weiter"
+
+
+
+ "Danke für die Mithilfe!"
+
+ "Ihr verifizierter Befund wurde anonym übertragen."
+
+
+
+ "Auswahl"
+
+ "Welche Informationen liegen Ihnen vor?"
+
+ "Dokument mit QR-Code"
+
+ "Registrieren Sie Ihren Test, indem Sie den QR-Code ihres Test-Dokuments scannen."
+
+ "Datenschutz"
+ @string/lorem_ipsum
+
+ "Erlauben"
+
+ "Nicht erlauben"
+
+ "TAN"
+
+ "Registrieren Sie Ihren Test per manueller TAN-Eingabe."
+
+ "Noch keine TAN?"
+
+ "Bitte rufen Sie uns an, falls Sie Corona-positiv getestet wurden."
+
+
+
+ "Andere warnen"
+
+ "Helfen Sie mit!"
+
+ "Als Nächstes können Sie dafür sorgen, dass das Corona-Warn-System Ihre lokal gespeicherten Zufallscodes der letzten 14 Tage an andere verteilt. So können Sie Ihre Mitmenschen warnen und helfen, die Infektionskette zu unterbrechen.\n\nDa nur unpersönliche Zufallscodes übertragen werden, bleibt Ihre Identität unbekannt."
+
+ "Datenschutz"
+
+ "Ich willige hiermit ein, dass mein positiver Corona-Befund an das Tracing Backend übermittelt und dazu genutzt wird, andere App Nutzer auf ein mögliches Infektionsrisiko hinzuweisen. Dabei werden die auf meinem Gerät gespeicherten Temporary Exposure Keys an das Tracing Backend übermittelt und dort anderen Nutzern der App zur Verfügung gestellt. Ich kann meine Einwilligung jederzeit mit Wirkung für die Zukunft widerrufen. Ein Widerruf lässt die Rechtmäßigkeit der Verarbeitung bis zum Widerruf unberührt.\n\nWeitere Informationen finden Sie in unserer Datenschutzhinweisen."
+
+ "Weiter"
+
+ "Zufallscodes mit der Corona-Warn-App teilen?"
+
+ "Ihre Zufallscodes der letzten 14 Tage werden dazu genutzt, andere darüber zu informieren, dass Sie in ihrer Nähe gewesen sind und sie daher möglicherweise in Kontakt mit COVID-19 gekommen sind."
+
+ "Erlauben"
+
+ "Nicht erlauben"
+
+ "Ein Smartphone übermittelt einen positiven Testbefund verschlüsselt ins System."
+
+
+
+
+ "Vielen Dank!"
+
+ "Sie haben einen wichtigen Beitrag geleistet!"
+
+ "Sie haben einen wichtigen Beitrag geleistet! Dank Ihrer Mithilfe können Andere gewarnt werden und entsprechend reagieren."
+
+ "Bitte beachten Sie:"
+
+ "Sie sind ansteckend."
+
+ "Bitte isolieren Sie sich von anderen Personen."
+
+ "Weitere Infos:"
+
+
"Ihre Quarantänezeit beträgt im Regelfall 14 Tage. Beobachten und erfassen Sie genau, wie sich ihre Krankheitszeichen entwickeln."
"\n\n"
"Sie werden von Ihrem Gesundheitsamt gebeten, eine Liste Ihrer Kontaktpersonen zu erstellen. Dabei sollen alle Personen erfasst werden, mit denen Sie in den zwei Tagen vor Erkrankungsbeginn engen Kontakt (unter 2 Meter, direktes Gespräch) über insgesamt 15 Minuten hatten."
"\n\n"
"Bitte denken Sie hier auch besonders an Personen, die nicht automatisch durch die App informiert werden, da sie kein Smartphone habe oder die App nicht installiert haben."
"\n\n"
"Auch wenn Sie keine Krankheitszeichen mehr haben und sich wieder gesund fühlen, könnten Sie noch ansteckend sein."
+
+ "Fertig"
+
+ "Eine vielfältige Gruppe begrüßt durch Jubel, dass jemand sein Testergebnis mit anderen geteilt hat."
+
+
+
+ "TAN anfragen"
+
+ "Info zum Ablauf:"
+
+ "Wir teilen Ihnen Ihren TAN-Code gerne per Telefon mit."
+
+ "Anrufen"
+
+ "TAN eingeben"
+
+ "Hotline anrufen & TAN erfragen:"
+
+ "Test per TAN-Eingabe in der App registrieren"
+
+ "Unsere Öffnungszeiten:\nMo - Fr: 08:00 - 22:00 Uhr\nSa - So: 10:00 - 22:00 Uhr\nEs gelten die Preise Ihres Telefonanbieters."
+
+
+
+
+ "Datenabruf…"
+
+ "Wurden Sie getestet?"
+
+ "Ergebnis liegt noch nicht vor"
+
+ "Ihr Ergebnis liegt vor"
+
+ "Das Ergebnis wird aktualisiert"
+
+ "Helfen Sie mit, die Infektionskette zu durchbrechen und warnen Sie Andere."
+
+ "Die Auswertung dauert zwischen 1–3 Tagen."
+
+ "Ihr Test konnte nicht ausgewertet werden."
+
+ "Sie wurden positiv auf SARS-CoV-2 getestet."
+
+ "Sie wurden negativ auf SARS-CoV-2 getestet."
+
+ "Informieren & mitmachen"
+
+ "Ergebnis anzeigen"
+
+ "Details anzeigen"
+
+ "Positives Ergebnis"
+
+ "Bitte beachten Sie:"
+
+ "Testergebnis anzeigen"
+
+ @string/submission_done_contagious
+
+ "Teilen Sie Ihre Zufallskennungen, damit andere gewarnt werden können."
+
+
+ "Ihr Befund:"
+
+ "SARS-CoV-2"
+
+ "Registriert am %tF"
+
+ "Negativ"
+
+ "Positiv"
+
+ "Auswertung nicht möglich"
+
+ "Ergebnis liegt noch nicht vor"
+
+
+ "Ok"
+
+
+ "Etwas ist schief gelaufen."
+ "Ursache"
+ "Okay"
+ "Details"
+ "Ein unbekannter Fehler ist aufgetreten."
+
+
+
+ "Lorem ipsum..."
+
+
+ "Test API"
+
+ "Test Risk Level"
+
+ "Test Notification"
+
+ "Android API Test(Manual Test)"
+
+ "Start (Broadcast/Receive Bluetooth)"
+
+ "Get Exposure keys (my keys history from api)"
+
+ "Share my keys via Email"
+
+ "Submit Exposure Key"
+
+ "Show QR Code"
+
+ "Submit keys to Server"
+
+ "Scan Exposure Key"
+
+ "Last 3 Hours Mode"
+
+ "Check Exposure Summary"
+
+ "Exposure summary"
+
+ "Days since last exposure: %1$s"
+
+ "Attenuation Durations in Minutes: %1$s"
+
+ "Summation Risk Score: %1$s"
+
+ "Matched key count: %1$s"
+
+ "Maximum risk score %1$s"
+
+ "My keys (count: %1$d)"
+
+ "Other key"
+
+ "Calculate Risk Level"
+
+
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-en/strings.xml b/Corona-Warn-App/src/main/res/values-en/strings.xml
new file mode 100644
index 00000000000..5c3e95b0d48
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/values-en/strings.xml
@@ -0,0 +1,825 @@
+
+
+
+
+
+
+ "shared_preferences_cwa"
+
+ "preference_onboarding_completed"
+
+ "preference_onboarding_completed_timestamp"
+
+ "preference_reset_app"
+
+ "preference_only_wifi"
+
+ "preference_tracing"
+
+ "preference_timestamp_diagnosis_keys_fetch"
+
+ "preference_timestamp_manual_diagnosis_keys_retrieval"
+
+ "preference_m_string_google_api_token"
+
+ "preference_notifications_enabled"
+
+ "preference_notifications_risk_enabled"
+
+ "preference_notifications_test_enabled"
+
+ "preference_background_job_enabled"
+
+ "preference_mobile_data_enabled"
+
+ "preference_registration_token"
+ "preference_device_pairing_successful_time"
+
+ "preference_initial_tracing_activation_time"
+
+ "preference_initial_result_received_time"
+
+ "preference_risk_level_score"
+
+ "preference_risk_level_score_successful"
+
+ "preference_test_guid"
+
+ "preference_is_allowed_to_submit_diagnosis_keys"
+
+ "preference_auth_code"
+
+ "preference_database_password"
+
+ "preference_total_non_active_tracing"
+
+ "preference_last_non_active_tracing_timestamp"
+
+ "preference_number_successful_submissions"
+
+ "preference_teletan"
+
+ "preference_last_three_hours_from_server"
+
+
+
+
+
+
+ "Overview"
+
+ "App Information"
+
+ "Settings"
+
+
+
+ "de.rki.coronawarnapp.notification.exposureNotificationChannelId"
+
+ "1"
+ "Corona-Warn-App"
+ "Notifications from the Corona-Warn-App"
+ "Corona-Warn-App"
+ "You have new messages from your Corona-Warn-App."
+
+
+
+
+ "No exposures up to now."
+
+ "%1$s exposure"
+ "%1$s exposures"
+
+
+ "%1$s of 14 days saved"
+ "Encounters have not yet been checked."
+ "Updated: %1$s"
+ "Updated daily"
+
+ "Update"
+ "Update in %1$s"
+
+ "Activate Risk Identification"
+
+ "Activate risk identification to evaluate your risk level today."
+
+ "Low Risk"
+
+ "Higher Risk"
+
+ "%1$s day since the last encounter"
+ "%1$s days since the last encounter"
+
+
+ "Risk Unknown"
+
+ "Since you have not activated risk identification for long enough, we could not calculate your risk of infection."
+
+ "Risk identification stopped"
+ "Last risk identification ""\n""%1$s"
+
+ "Risk Identification is not possible"
+
+ "Your Risk identification could not be updated for more than 24 hours."
+
+ "Check is running..."
+
+ "Current data is beinfgdownloaded and checked. This can take several minutes."
+
+
+
+
+ "FAQ"
+
+ "Here you can find answers to frequently asked questions about the Corona-Warn-App."
+
+ "https://www.bundesregierung.de/corona-warn-app-faq"
+
+
+
+
+ "Share the Corona-Warn-App"
+
+ "Let\'s fight coronavirus together."
+
+ "The more people who use the app, the faster we can break the infection chain. Please invite your family and friends to download the app."
+
+ "Send Download Link"
+
+ "Fighting coronavirus together""\n""I\'m in on this, you too?""\n""https://www.coronawarn.app/""\n"
+
+ "One man is sharing the Corona-Warn-App with four other people."
+
+
+
+
+ "Overview"
+
+ "Risk Identification"
+
+ "Risk identification is one of the three central features of the app. When you activate it, encounters with peoples\' devices are logged. You don\'t have to do anything else."
+
+ "Risk of Infection"
+
+ "If you have had contact within the last 14 days with a person who was diagnosed with COVID-19, the app calculates your peronal risk of infection. It does this by measuring duration and proximity of the exposure."
+
+ "The following risk levels can be shown:"
+
+ "Higher Risk"
+
+ "Low Risk"
+
+ "Risk Unknown"
+
+ "Notifying Other Users"
+
+ "Another central feature is registering your test and retrieving the result. If you are diagnosed with COVID-19, you can warn others and break the chain of infection."
+
+ "Definition of Terms:"
+
+ "Exposure Logging"
+
+ "List of received and temporary random IDs saved temporarily in the operating system storage. This list is read when the exposures are checked. All random IDs are automatically deleted after 14 days."
+
+ "Exposure Check"
+
+ "Exposure logging data is retrieved and synchronized with reported infections of other users. The exposure check is performed automatically about every two hours."
+
+ "Exposures"
+
+ "Encounters over a longer duration and close proximity to people diagnosed with COVID-19."
+
+ "Exposure Notification"
+
+ "Display exposures in the Corona-Warn-App."
+
+ "Random ID"
+
+ "Random IDs are combinations of digits and letters generated randomly. They are exhanged between devices in close proximity. Random IDs cannot be assigned to a specific person and are automatically deleted after 14 days. People diagnosed with COVID-19 can opt to share their random IDs of up to the last 14 days with other app users."
+
+ "One device shows different content numbered from 1 to 3."
+
+
+
+
+ "Behavioral Recommendations"
+
+ "This is what you should do:"
+
+ "Go home immediately and stay at home."
+
+ "If you have questions about symptoms, testing availability, or self-isolation, please contact one of the following:"
+
+ "Wash your hands regularly."
+
+ "Wear a face mask when you are close to other people."
+
+ "Keep at least 1.5 metres distance from other people."
+
+ "Sneeze or cough into your elbow or a tissue."
+
+ "Your general practitioner"
+
+ "General medical emergency service on telephone number 116117"
+
+ "Your public health authority"
+
+ "Risk of Infection"
+
+ "This is how your risk was calculated"
+
+ "This is how your risk is calculated"
+
+ "Since you have not activated risk identification for long enough, we could not calculate your risk of infection."
+
+ "Your risk identification could not be updated for more than 24 hours."
+ "You have a low risk of infection because no exposure to people later diagnosed with COVID-19 was logged, or because your encounters were only for a short time and at a greater distance."
+
+ "You have a higher risk of infection because you were last exposed %1$s day ago over a longer period of time and in close proximity to at least one person diagnosed with COVID-19."
+ "You have a higher risk of infection because you were last exposed %1$s days ago over a longer period of time and in close proximity to at least one person diagnosed with COVID-19."
+
+ "Your risk of infection is calculated from the risk identification data (duration and proximity) locally on your device. Your risk of infection cannot be seen by, or passed on to, anyone else."
+ @string/risk_card_button_update
+ @string/risk_card_button_enable_tracing
+
+
+
+ "IS MISSING"
+ "Do Not Activate"
+
+ "Next"
+
+ "Let’s Get Started"
+
+ "Back"
+
+ "Let\'s fight coronavirus together."
+
+ "More protection for you and for us all. By using the Corona-Warn-App we can break infection chains much quicker."
+
+ "Turn your device into a coronavirus warning system. Get an overview of your risk status and find out whether you\'ve had close contact with anyone diagnosed with COVID-19 in the last 14 days."
+
+ "The app logs exposures between individuals by exchanging encrypted, random IDs between their devices, whereby no personal data whatsoever is accessed."
+
+ "A group of people are all using their devices in town."
+ "Data Privacy"
+ @string/lorem_ipsum
+
+ "One of the women is using the Corona-Warn-App on her device. The padlock on the shield is the symbol for encrypted data."
+
+ "How to Enable Risk Identification"
+
+ "To identify whether you are at risk of infection, you have to activate the risk identification feature."
+
+ "Risk identification works by your device receiving, via Bluetooth, encrypted random IDs of other users and passing your own random ID to their devices. This feature can be deactivated at any time."
+
+ "The encrypted random IDs only pass information about date, duration and proximity (using signal strength) to other people. Personal data such as name, address, location is never recorded. Individuals cannot be identified."
+
+ "Authorization"
+
+ "This means the Corona-Warn-App cannot send or receive notifications about your COVID-19 risk status. You can deactivate this feature at any time."
+
+ "Do Not Activate"
+
+ "Back"
+
+ "Three people have activated exposure logging on their devices, which will log their encounters with each other."
+
+ "If you are diagnosed with COVID-19..."
+
+ "...please notify this in the Corona-Warn-App. This is voluntary and secure. Do it for the sake of everyone\'s health."
+
+ "Your notification is encrypted securely and processed on a secure server. People whose encrypted random IDs your device has collected, will now receive a warning along with information about what they should now do."
+
+ "An encrypted positive test diagnosis is transmitted to the system, which will now warn other users."
+
+ "Receive Warnings and Identify Risks"
+
+ "The app can notify you automatically about your risk status and warn you about new infections of people you have been exposed to. Allow the app now to notify you."
+
+ "You can then self-isolate to protect others and find out where you can get tested."
+
+ "One woman receives a notification from her Corona-Warn-App."
+
+
+
+
+ "Settings"
+
+ "On"
+
+ "Off"
+
+ "Risk Identification"
+
+ "This is how exposure logging works"
+
+ "Allow COVID-19 random IDs to be generated and shared."
+
+ "Risk identification active"
+
+ "Risk identification stopped"
+
+ "Risk identification works by your device receiving, via Bluetooth, encrypted random IDs of other users and passing your random ID to their devices. This feature can be deactivated at any time. ""\n""\n"" Encrypted random IDs only pass information about date, duration and proximity (calculated using signal strength) to other people. Personal data such as name, address, location is never recorded. Individuals cannot be identified."
+
+ "Active"
+
+ "Stopped"
+
+ "Restricted"
+
+ "No Internet connection"
+
+ "Bluetooth turned off"
+
+ "Turn on Bluetooth"
+
+ "Bluetooth must be turned on for risk identification in order to log encounters. Please turn on Bluetooth in your device settings."
+
+ "Open Device Settings"
+
+ "Open Internet connection"
+
+ "Risk identification requires an Internet connection to calculate exposures. Please turn on wifi or mobile data in your device settings."
+
+ "Open Device Settings"
+
+
+ "Risk identification has been active for less than one day.\nAn exposure check can only be reliable if risk identification is permanently activated."
+ "Risk identification has been active for less than %1$s days.\nAn exposure check can only be reliable if risk identification is permanently activated."
+ "Risk identification has been active for %1$s days.\nAn exposure check can only be reliable if risk identification is permanently activated."
+
+
+ "Three people have activated exposure logging on their devices, which will log their encounters with each other."
+
+ "One person has deactivated exposure logging on their device, so an encounter with two other people is not logged."
+
+ "One person has deactivated Bluetooth on the device, so an encounter with two other people is not logged."
+
+ "One person has deactivated exposure logging on their device, so an encounter with two other people is not logged."
+
+
+ "Notifications"
+
+ "Do you want to activate notifications of your COVID-19 risk status?"
+
+ "Notifications are deactivated."
+
+ "Allow automatic notifications of COVID-19 risk status"
+ "Specify which areas you want to continue to receive notifications for."
+
+ "To activate notifications, you have to allow notifications for the Corona-Warn-App in your device settings."
+
+ "Notifications"
+
+ "Your risk of infection changed"
+
+ "Status of your COVID-19 test"
+
+ "Open Device Settings"
+
+ "One woman receives a notification from her Corona-Warn-App."
+
+ "One woman has deactivated notifications for her Corona-Warn-App."
+
+ "Reset App"
+
+ "Delete all your data in the app."
+
+ "Are you sure you want to reset the app?"
+
+ "You will no longer be notified of your exposures and you will no longer be able to warn other users."
+
+ "Delete Exposure ""\n""Loggings"
+
+ "Exposure logging has to be deleted separately in your device settings."
+
+ "Reset App"
+
+ "Cancel"
+
+ "One person is holding a device displaying a symbol indicating that the app is being reset."
+
+
+
+
+
+ "App Information"
+
+ "Version: %1s"
+
+ "About the App"
+
+ "Let\'s fight coronavirus together"
+
+ "The Robert Koch Institute (RKI) is the central body for the federal state of Germany in the field of public health. The RKI is publishing the Corona-Warn-App for the federal government. The app represents the digital extension to the public health measures already introduced: social distancing, hygiene behavior, and face masks."
+
+ "Whoever uses the app helps to trace and break chains of infection. The app saves encounters with other people locally on your device. You are notified if you have encountered people who were later diagnosed with COVID-19. Your identity and privacy is always protected."
+
+ "A group of people are all using their devices in town."
+
+ "Data protection information"
+
+ "One of the women is using the Corona-Warn-App on her device. The padlock on the shield is the symbol for encrypted data."
+
+ "Terms of Use"
+ @string/lorem_ipsum
+
+ "One person is holding a device with a lot of text on the screen. Next to the text is a tick, which is the symbol for accepting the terms of use."
+
+ "Technical hotline"
+
+ "How can we help you?"
+
+ "For technical questions about the Corona-Warn-App, please contact our hotline."
+
+ "Technical hotline:"
+
+ "+49 (0)800 7540001"
+
+ "Phone: +49 800 7540001"
+
+ "Our customer service is here to help."
+
+ "Business hours:""\n""Monday to Friday: 8am - 10pm""\n""Saturday and Sunday: 10am - 10pm""\n""The standard charges of your telephone provider apply."
+
+ "If you have any health-related questions, please contact your general practitioner or the hotline for the medical emergency service, telephone: +49 6251 / 708-1082, telefax: +49 116 / 78117."
+
+ "One man is wearing a headset while he is telephoning."
+
+ "FAQ"
+
+ "Legal Notes"
+
+ "One person is holding a device with a lot of text on the screen. Next to the text is a balance scale, which is the symbol for legal notices"
+
+ "Publication Details"
+
+ "One person is holding a device with a lot of text on the screen. Next to the text is a paragraph symbol for the publication details."
+
+
+
+
+
+ "Error"
+
+ "Connection could not be established (%1$d). Please try again."
+
+ "Connection could not be established. Please try again. "
+
+ "Back"
+
+
+ "Error"
+
+ "The QR code/TAN is invalid or has been used already. The TAN is invalid or has been used already. Please try again or contact the technical hotline via App Information -> Technical hotline."
+
+ "Back"
+
+
+ "Error"
+
+ "A TAN for submission could not be generated. Please contact the technical hotline via App Information → Technical hotline."
+
+ "Back"
+
+
+ "Error"
+
+ "A TAN for submission could not be generated. Please contact the technical hotline via App Information → Technical hotline."
+
+ "Back"
+
+
+ "Camera authorization required"
+ "Allow the app to use the camera to scan the QR code."
+ "Allow"
+ "Do Not Allow"
+
+
+ "Scan successful"
+ "The QR code has been scanned successfully."
+ "Register"
+ "Cancel"
+
+
+ "Incorrect QR code"
+ "It appears that an incorrect QR code was scanned."
+ "Please try again."
+ "Cancel"
+
+
+
+ "Position the QR code in the frame."
+
+
+ "Register device"
+ @string/lorem_ipsum
+
+
+
+ "Test result"
+
+ "How this works:"
+
+ "Finish"
+
+ "Test added successfully"
+
+ "Your test has been registered in the Corona-Warn-App."
+
+ "Test result is not yet available."
+
+ "Your test result is not yet available."
+
+ "Update"
+
+ "Delete Test"
+
+ "Your Test Result"
+
+ "The laboratory result indicates no verification that you have coronavirus SARS-CoV-2.\n\nPlease delete the test from the Corona-Warn-App, so that you can save a new test code here if necessary."
+
+ "Delete Test"
+
+ "Your Test Result"
+
+ "Your test result was verified as positive."
+
+ "Warning Others"
+
+ "Share your random IDs of the last 14 days in order to protect others and break the chain of infection."
+
+ "Next"
+
+ "Your Test Result"
+
+ "There was a problem evaluating your test. Please contact the public health authority to find out how to proceed. Please delete the test from your Corona-Warn-App so that you will be able to save a new test code there if necessary."
+
+ "Delete Test"
+
+ "Risk Identification Required"
+
+ "Please activate risk identification to warn other people."
+
+ "OK"
+
+
+
+ "TAN entry"
+
+ "The TAN has 7 characters and is case-insensitive.\n\nPlease enter the TAN you were given:"
+
+ "Next"
+
+
+
+ "Have you been tested?"
+
+ "This is how the Corona-Warn-App works"
+
+ "For the app to work well, we are relying on the support of people who have tested positive. Since only encrypted random IDs are exchanged, you remain anonymous. You can now proceed as follows:\n"
+
+ "If you tested positive, you can warn others. If you were given a TAN for a positive result, you can use this to register the test. If you do not have a TAN, you can request one by telephone."
+
+ "Next"
+
+
+
+ "Thank you for your support."
+
+ "Your verified test diagnosis was transmitted anonymously."
+
+
+
+ "Selection"
+
+ "What information is here for you?"
+
+ "Document with QR code"
+
+ "Register your test by scanning the QR code of your test document."
+
+ "Data Privacy"
+ @string/lorem_ipsum
+
+ "Allow"
+
+ "Do Not Allow"
+
+ "TAN"
+
+ "Register your test by entering your TAN manually."
+
+ "Still no TAN?"
+
+ "Please call us if you have been diagnosed with COVID-19."
+
+
+
+ "Warning others"
+
+ "Please help all of us!"
+
+ "Next ,you can make sure that the Corona-Warn-App shares your random IDs of the last 14 days with others. By doing this, you can warn other people and help to break the infection chain.\n\nSince only impersonal random IDs are transmitted, your identity remains anonymous."
+
+ "Data Protection"
+
+ "Yes, I consent to the use of my tracing function in my Corona-Warn-App. In doing so, I would Iike to make an important contribution to helping break infection chains, and containing the spread of corona virus in Germany. With exposure logging, contacts can be traced in order to identify contacts that are later diagnosed with COVID-19.\n\nI can revoke my consent at any time with effect for the future.\nFor more information, see the data protection notes."
+
+ "Next"
+
+ "Share random IDs with the Corona-Warn-App?"
+
+ "Your random IDs over the last 14 days are used to notify others that you were in close proximity to them, and therefore that you may have been exposed to COVID-19."
+
+ "Allow"
+
+ "Do Not Allow"
+
+ "A device is transmitting an encrypted positive test diagnosis to the system."
+
+
+
+
+ "Thank you"
+
+ "You have made a valuable contribution."
+
+ "You have made a valuable contribution. Thanks to your support, other people can now be warned and can react appropriately."
+
+ "Please remember:"
+
+ "You are infectious."
+
+ "Please isolate yourself from other people."
+
+ "Other information:"
+
+ "Your quarantine period is usually 14 days. Please observe your symptoms and monitor how they develop. You will be asked by your public health authority to create a list of people you have had contact with. This should include all people with whom you have had close contact with (less than 2 meters, face-to-face conversation) for over 15 minutes in the two days before you developed symptoms. Please think especially about the people that will not be notified directly by the app since they don\'t have a device, or haven\'t installed the app."
+
+ "Done"
+
+ "The diverse group of people are all cheering because someone has shared their test result."
+
+
+
+ "Request TAN"
+
+ "How this works:"
+
+ "We can tell you your TAN code by telephone."
+
+ "Call"
+
+ "Enter TAN"
+
+ "Call the hotline and request a TAN:\n"
+
+ "Register the test by entering the TAN in the app."
+
+ "Business hours:\nMonday to Friday: 8am - 10pm\nSaturday and Sunday: 10am - 10pm\nThe standard charges of your telephone provider apply."
+
+
+
+
+ "Data being retrieved...."
+
+ "Have you been tested?"
+
+ "Your result is not yet available"
+
+ "Your result is available"
+
+ "You result is being updated"
+
+ "Help to break the infection chain by warning others."
+
+ "The evaluation takes between one and three days."
+
+ "Your test could not be evaluated."
+
+ "You have been tested positive for SARS-CoV-2."
+
+ "You have been tested negative for SARS-CoV-2."
+
+ "Notify and Help"
+
+ "Display Result"
+
+ "Display Details"
+
+ "Positive Result"
+
+ "Please Note:"
+
+ "Display Test Result"
+
+ @string/submission_done_contagious
+
+ "Share your random IDs so that others can be warned."
+
+
+ "Your diagnosis:"
+
+ "SARS-CoV-2"
+
+ "Registered on %tF"
+
+ "Negative"
+
+ "Positive"
+
+ "Evaluation is not possible"
+
+ "Your result is not available"
+
+
+ "OK"
+
+
+ "Something went wrong."
+ "Cause"
+ "OK"
+ "Details"
+ "An unknown error occurred."
+
+
+
+ "Lorem Ipsum..."
+
+
+ "Test API"
+
+ "Test Risk Level"
+
+ "Test Notification"
+
+ "Android API Test(Manual Test)"
+
+ "Start (Broadcast/Receive Bluetooth)"
+
+ "Get Exposure keys (my keys history from api)"
+
+ "Share my keys via Email"
+
+ "Submit Exposure Key"
+
+ "Show QR Code"
+
+ "Submit keys to Server"
+
+ "Scan Exposure Key"
+
+ "Last 3 Hours Mode"
+
+ "Check Exposure Summary"
+
+ "Exposure summary"
+
+ "Days since last exposure: %1$s"
+
+ "Attenuation Durations in Minutes: %1$s"
+
+ "Summation Risk Score: %1$s"
+
+ "Matched key count: %1$s"
+
+ "Maximum risk score %1$s"
+
+ "My keys (count: %1$d)"
+
+ "Other key"
+
+ "Calculate Risk Level"
+
+
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values/dimens.xml b/Corona-Warn-App/src/main/res/values/dimens.xml
index b7a0fb6555c..5b4e9fd4b08 100644
--- a/Corona-Warn-App/src/main/res/values/dimens.xml
+++ b/Corona-Warn-App/src/main/res/values/dimens.xml
@@ -3,7 +3,7 @@
48dp24dp16dp
- 6dp
+ 8dp3dp
@@ -19,7 +19,7 @@
4sp
- 50dp
+ 40dp10dp
@@ -54,7 +54,7 @@
@dimen/spacing_tiny4dp20dp
- 35dp
+ 40dp35dp35dp40dp
@@ -81,8 +81,10 @@
1dp2dp
- 24dp
- 32dp
+ 22dp
+ 40dp
+ 11dp
+ 40dp240dp
diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml
index 229669dc8ba..d920ef01abd 100644
--- a/Corona-Warn-App/src/main/res/values/strings.xml
+++ b/Corona-Warn-App/src/main/res/values/strings.xml
@@ -1,4 +1,5 @@
-
+
+
+
+ preference_timestamp_risk_level_calculation
+
+
preference_test_guid
@@ -145,10 +150,14 @@
1
- Corona Warn App
- Benachrichtigungen aus der Corona Warn App.
- Corona-Warn App
- Es gibt Neuigkeiten von Ihrer Corona-Warn-App
+
+ Corona-Warn-App
+
+ Benachrichtigungen aus der Corona-Warn-App.
+
+ Corona-Warn-App
+
+ Es gibt Neuigkeiten von ihrer Corona-Warn-AppHier finden Sie Antworten auf häufig gestellte Fragen rund um die Corona-Warn-App.
-
- http://www.bundesregierung.de/corona-warn-app-faq
+
+ https://www.bundesregierung.de/corona-warn-app-faq
+
+ Ihr RisikostatusVerhalten
@@ -336,7 +347,12 @@
###################################### -->
IS MISSING
+
Nicht aktivieren
+
+ Aktivieren
+
+ AbbrechenWeiter
@@ -367,6 +383,12 @@
Die Risiko-Ermittlung funktioniert, indem Ihr Handy per Bluetooth verschlüsselte Zufallscodes anderer Nutzerinnen und Nutzer empfängt und Ihren eigenen Zufallscode an deren Smartphones weitergibt. Die Funktion lässt sich jederzeit wieder deaktivieren.Die verschlüsselten Zufallscodes geben nur Auskunft über das Datum, die Dauer und die anhand der Signalstärke berechnete Entfernung zu Ihren Mitmenschen. Persönliche Daten wie Name, Adresse oder Aufenthaltsort werden zu keiner Zeit erfasst. Konkrete Rückschlüsse auf Personen sind nicht möglich.
+
+ Einwilligungserklärung
+
+ Um zu erfahren, ob Sie Kontakt mit einer infizierten Person hatten und für Sie ein Infektionsrisiko besteht, müssen Sie die Funktion Risiko-Ermittlung in der App aktivieren. Der Aktivierung der Risiko-Ermittlung und der damit im Zusammenhang stehenden Datenverarbeitung stimmen Sie mit Antippen des Buttons: Risiko-Ermittlung aktivieren zu.\n\nUm die Risiko-Ermittlung nutzen zu können müssen Sie zudem auf Ihrem Smartphone die von Google bereitgestellte Kontaktaufzeichnungs-Funktion „Benachrichtigungen zu möglicher Begegnung mit COVID-19-Infizierten“ aktivieren und für die Corona-Warn-App freigeben.\n\nIhr Smartphone erzeugt und versendet bei aktivierter Kontaktaufzeichnung kontinuierlich Zufalls-IDs per Bluetooth, die von anderen Apple- und Android-Smartphones mit ebenfalls aktivierter Kontaktaufzeichnung in Ihrer Umgebung empfangen werden können. Umgekehrt empfängt Ihr Smartphone die Zufalls-IDs der anderen Smartphones. Die eigenen und die von anderen Smartphones empfangenen Zufalls-IDs werden im Kontaktprotokoll der Kontaktaufzeichnungs-Funktion aufgezeichnet und dort für 14 Tage gespeichert.\n\nZur Ermittlung Ihres Infektionsrisikos lädt die App mehrmals täglich oder auf Abfrage eine Liste mit den Zufalls-IDs aller Nutzer, die Ihre Infektion mit dem Corona-Virus in der App geteilt haben. Diese Liste wird dann mit den im Kontaktprotokoll der Kontaktaufzeichnungs-Funktion gespeicherten Zufalls-IDs verglichen. Wenn die App dabei feststellt, dass Sie möglicherweise Kontakt zu einem infizierten Nutzer gehabt haben, werden Sie von der App informiert, dass Sie mit einer infizierten Person in Kontakt waren und insoweit ein Infektionsrisiko besteht. In diesem Fall erhält die App außerdem Zugriff auf weitere im Kontaktprotokoll der Kontaktaufzeichnungs-Funktion Ihres Smartphones gespeicherte Daten (Datum und Dauer sowie Bluetooth-Signalstärke des Kontakts).\n\nAus der Bluetooth-Signalstärke wird der räumliche Abstand abgeleitet (je stärker das Signal, desto geringer der Abstand). Diese Angaben werden von der App ausgewertet, um Ihr Gesundheitsrisiko durch eine Infektion mit dem Corona-Virus abzuschätzen und Ihnen Empfehlungen für die nächsten Schritte zu geben. Diese Auswertung wird ausschließlich lokal auf Ihrem Smartphone durchgeführt. Außer Ihnen erfährt niemand (auch nicht das RKI), ob Sie mit einer infizierten Person Kontakt hatten und welches Risiko für Sie ermittelt wird.\n\nZum Widerruf Ihrer Einwilligung in die Risiko-Ermittlung können Sie die Funktion über den Schieberegler innerhalb der App deaktivieren oder die App löschen. Wenn Sie die Risiko-Ermittlung wieder nutzen möchten, können Sie den Schieberegler erneut aktivieren oder die App erneut installieren. Wenn Sie die Risiko-Ermittlung deaktivieren, prüft die App nicht mehr, ob Sie Kontakt zu einem infizierten Nutzer gehabt haben. Um auch die Aussendung und den Empfang der Zufalls-IDs anzuhalten, müssen Sie das Kontaktprotokoll der Kontaktaufzeichnungs-Funktion in den Einstellungen Ihres Smartphones deaktivieren. Bitte beachten Sie, dass die im Kontaktprotokoll aufgezeichneten fremden und eigenen Zufalls-Kennungen nicht in der App gelöscht werden. Die im Kontaktprotokoll gespeicherten Daten können Sie nur in den Einstellungen Ihres Smartphones dauerhaft löschen.\n\nDie Datenschutzhinweise der App (einschließlich Informationen zur Datenverarbeitung für die Risiko-Ermittlung) finden Sie unter dem Menüpunkt „Datenschutzinformation“.
+
+ Risiko-Ermittlung aktivierenBerechtigung
@@ -708,9 +730,7 @@ ist das Robert Koch-Institut, Nordufer 20, 13353 Berlin (im Folgenden „
Weitere Informationen zu der Kontaktaufzeichnungs-Funktion von
Android-Smartphones finden Sie unter:
-
https://support.google.com/android/answer/9888358?hl=de
-
.
@@ -1265,10 +1285,7 @@ ist das Robert Koch-Institut, Nordufer 20, 13353 Berlin (im Folgenden „
@@ -1300,12 +1317,821 @@ ist das Robert Koch-Institut, Nordufer 20, 13353 Berlin (im Folgenden „
Stand: 05.06.2020
]]>
- @string/lorem_ipsumEine Frau mit einem Handy benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten.Nutzungsbedingungen
- @string/lorem_ipsum
+
+ Inhalt
+
+
+
+ 1...... Welche Funktionen hat die APP?
+
+
+ 2...... Was bedeutet niedriges oder erhöhtes Risiko?.
+
+
+ 3...... Risiko-Begegnung – was tun?.
+
+
+ 4...... Kein Infektionsschutz durch die App.
+
+
+ 5...... Abrufen von Testergebnissen.
+
+
+ 6...... Auslösen einer Warnung.
+
+
+ 7...... Voraussetzungen für die Nutzung der App.
+
+
+ 8...... Grenzen der App.
+
+
+ 9...... Nutzungsrechte.
+
+
+ 10.... Wichtige Hinweise zu Verfügbarkeit und Änderungen.
+
+
+ 11.... Keine Gewährleistung.
+
+
+ 12.... Besondere Bedingungen für die iOS-Version der App.
+
+
+ 13.... Schlussbestimmungen.
+
+
+ Herausgeber der App ist das
+
+
+ Robert Koch-Institut
+
+
+ Nordufer 20
+
+
+ 13353 Berlin ("RKI")
+
+
+ vertreten durch den Präsidenten. Für Fragen, Beschwerden und Ansprüche im
+ Zusammenhang mit diesen Nutzungsbedingungen können Sie das RKI telefonisch
+ unter +49 30 18754-5100 und per E-Mail unter CoronaWarnApp@rki.de
+ erreichen.
+
+
+ Bitte lesen Sie diese Nutzungsbedingungen sorgfältig. Diese
+ Nutzungsbedingungen regeln Ihre Nutzung der Corona Warn App einschließlich
+der Nutzung zukünftiger Versionen (Patches, Updates und Upgrades) ("App") und der Nutzung weiterer Dienste (" CWA-Dienste"), die derzeit oder
+ zukünftig vom RKI im Zusammenhang mit der App bereitgestellt werden. Die
+ separate Datenschutzerklärung (siehe [Link]) ist
+ Bestandteil dieser Nutzungsbedingungen. Bitte lesen Sie auch die
+ Datenschutzerklärung sorgfältig.
+
+
+ Die App ist für die Nutzung auf iOS-Geräten im Apple App Store verfügbar
+ und für die Nutzung auf Android-Geräten bei Google Play. Allgemeine
+ Nutzungsbedingungen für Applikationen von Apple oder Google finden im
+ Verhältnis zum RKI keine Anwendung. Das RKI ist allein verantwortlich für
+ die Inhalte der App sowie deren Wartung und Pflege und für Ansprüche, die
+ Sie ggf. in Bezug auf die App haben.
+
+
+ Mit der Installation und Nutzung der App erklären Sie sich mit diesen
+ Nutzungsbedingungen einverstanden. Sollten Sie mit den Nutzungsbedingungen
+ nicht einverstanden sein, dürfen Sie die App nicht installieren oder nutzen
+ (bzw. müssen diese wieder löschen) und dürfen auch die die damit
+ verbundenen Dienste und Systeme nicht nutzen. Etwaige Rechte unter Open
+ Source-Lizenzen in Bezug auf den Quellcode der App bleiben hiervon
+ unberührt.
+
+
+ Sie sind für die Einhaltung dieser Nutzungsbedingungen auch dann
+ verantwortlich, wenn Sie das Endgerät, auf dem Sie die App installiert
+ haben, Dritten überlassen und diese die App verwenden.
+
+
+ Die App richtet sich an Personen, die mindestens 16 Jahre alt sind.
+ Personen unter 16 Jahren dürfen die App nur mit Zustimmung ihres/ihrer
+ Sorgeberechtigten verwenden.
+
+ Ziel der Corona Warn App ist es, SARS-CoV-2-Infektionsketten frühzeitig zu
+ durchbrechen. Personen sollen möglichst zuverlässig und schnell über
+ Begegnungen mit infizierten Personen und damit mögliche Übertragungen des
+ Virus informiert werden, damit sie sich freiwillig isolieren können, um
+ damit zu einer Eindämmung der SARS-CoV-2-Pandemie beizutragen.
+
+
+ Die wesentlichen Funktionen der App sind nachstehend beschrieben. Hierbei
+ handelt es sich um eine Beschreibung zu Ihrer Information und nicht um eine
+ Beschaffenheitsvereinbarung oder die Vereinbarung bestimmter Funktionen,
+ bitte beachten Sie die diesbezüglichen Hinweise und Vorbehalte unter Ziffer
+ 10.
+
+
+ Hintergrund
+
+
+ Die App läuft auf dem Endgerät im Hintergrund und speichert automatisiert
+ und verschlüsselt die Zufallscodes (rolling proximity identifier)
+ anderer in der Nähe befindlicher Endgeräte. In regelmäßigen Abständen holt
+sich die App über die CWA-Dienste eine Liste der Zufallscodes (temporary exposure keys) der Personen, die sich freiwillig
+ infiziert gemeldet haben, und vergleicht diese mit den gespeicherten
+ Zufallscodes im Gerät, um eine Risiko-Begegnung zu ermitteln.
+
+
+ Die App kann nur Begegnungen mit Personen registrieren, die ihrerseits ein
+ Endgerät mit installierter App bei sich führen und alle Voraussetzungen für
+ die Nutzung der App erfüllen (siehe unten Ziffer 7). Begegnungen mit
+ anderen Personen kann die App nicht registrieren.
+
+
+ Risikobenachrichtigung
+
+
+ Bei einer festgestellten Risiko-Begegnung zu positiv getesteten Personen
+ erhalten Sie eine Benachrichtigung und verhaltensbezogene Empfehlungen.
+ Hier kann zum Beispiel die Kontaktaufnahme mit ärztlichem Fachpersonal, mit
+ dem zuständigen Gesundheitsamt und/oder die freiwillige häusliche Isolation
+ empfohlen werden.
+
+
+ Benachrichtigung über Testergebnisse
+
+
+ Ab dem Zeitpunkt der Probenabgabe für einen Test auf eine
+ SARS-CoV-2-Infektion können Sie über die App den digitalen
+ Testinformationsprozess starten und damit über das Testergebnis
+ benachrichtigt werden. Die App übermittelt lediglich das vom jeweiligen
+ Labor mitgeteilte Testergebnis. Das RKI ist weder für die Durchführung des
+ Tests noch für den Inhalt des Testergebnisses verantwortlich.
+
+
+ Infektfall
+
+
+ Im Fall eines positiven SARS-CoV-2-Befunds können Sie freiwillig die in der
+ App gespeicherten eigenen Zufallscodes der letzten 14 Tage als
+ Positivkennungen (diagnosis keys) veröffentlichen, damit andere
+ Personen, die die App nutzen, auf ihrem eigenen Endgerät abgleichen können,
+ ob sie mit Ihnen eine Risiko-Begegnung hatten.
+
+
+ Technische Beschreibung der App
+
+
+ Die technischen Funktionen der App sowie der damit verbundenen Dienste und
+ Systeme sind unter folgendem Link detailliert beschrieben:
+
+
+ https://github.com/Corona-Warn-App
+
+
+ Diese technische Beschreibung dient lediglich der Erläuterung und ist nicht
+ Bestandteil dieser Nutzungsbedingungen. Sie stellt auch keine
+ Beschaffenheitsvereinbarung in Bezug auf die App dar.
+
+
+ Weiterführende Informationen
+
+
+Weiterführende Informationen zur App finden Sie unter folgendem Link: [Link]
+
+
+ Weiterführende Informationen zur SARS-CoV-2-Pandemie finden Sie unter
+ folgendem Link:
+ https://www.zusammengegencorona.de/
+
+
+ Diese weiterführenden Informationen dienen lediglich der Erläuterung und
+ sind nicht Bestandteil dieser Nutzungsbedingungen.
+
+ Die App berechnet auf Basis der festgestellten Begegnungen ein indikatives
+ individuelles Risiko. Hierbei werden Faktoren wie der Zeitraum seit der
+Begegnung (days since exposure), die Dauer der Begegnung ( exposure duration), die ungefähre Nähe zur infizierten Person,
+basierend auf der gemessenen Dämpfung des Bluetooth-Signals (signal attenuation) sowie ggf. Übertragungsrisiken ( transmission risk berücksichtigt. Auf dieser Basis wird Ihnen in
+ der App entweder ein "niedriges Risiko" oder ein "erhöhtes Risiko"
+ angezeigt. Es handelt sich hierbei um einen rein indikativen Wert auf der
+ Grundlage der erfassten Daten.
+
+ Eine Aussage über das Vorliegen einer tatsächlichen Infektion mit
+ SARS-CoV-2 ist hiermit nicht verbunden.
+
+ Auch bei der Angabe eines "niedrigen Risikos" kann eine Infektion
+ vorliegen, während auch bei Angabe eines "erhöhten Risikos" eine Infektion
+ nicht gegeben sein kann.
+
+
+
+ Andere Faktoren können Ihr persönliches Infektionsrisiko erheblich
+ beeinflussen. Diese werden von der App nicht berücksichtigt.
+
+ Das sind insbesondere Ihre persönlichen Umstände, die äußeren Umstände
+ einer Risiko-Begegnung mit einer infizierten Person, Ihr persönliches
+ Verhalten sowie Begegnungen mit Dritten, die von der App nicht erfasst
+ wurden. Bitte beachten Sie die Hinweise in Ziffer 4.
+
+ Wenn Sie über die App eine Benachrichtigung über eine festgestellte
+ Risiko-Begegnung mit infizierten Personen erhalten, erhalten Sie
+ verhaltensbezogene Empfehlungen in der Benachrichtigung. Diese Empfehlungen
+ sind rechtlich nicht verbindlich, ihre Befolgung wird aber vom RKI
+ empfohlen. Gesetzliche und vertragliche Pflichten sowie behördliche
+ Anordnungen für den Fall einer Risiko-Begegnung mit infizierten Personen
+ bleiben unberührt und müssen von Ihnen unabhängig von diesen Empfehlungen
+ befolgt werden.
+
+
+
+ Innerhalb oder über die App erfolgt keinerlei medizinische Diagnose.
+
+
+
+
+ Die Benachrichtigung bedeutet nicht, dass Sie sich mit SARS-CoV-2
+ infiziert haben.
+
+ Sie besagt lediglich, dass sie während der letzten 14 Tage eine
+ Risiko-Begegnung mit einer anderen Person hatten, bei der eine
+ SARS-CoV-2-Infektion positiv festgestellt wurde. Hieraus ergibt sich für
+ Sie zunächst nur eine Möglichkeit, dass Sie sich ebenfalls infiziert haben
+ könnten. Die Einstufung des diesbezüglichen Risikos als "niedrig" oder
+ "erhöht" erfolgt allein auf der Basis der ermittelten Daten und lässt keine
+ Aussage über das tatsächliche Vorliegen einer Infektion zu.
+
+
+
+ Die Benachrichtigung über eine Risiko-Begegnung kann unzutreffend sein.
+
+ Die Risiko-Begegnung kann von Ihrem Endgerät beispielsweise zu einem
+ Zeitpunkt registriert worden sein, zu dem Sie sich nicht in der Nähe Ihres
+ Endgeräts aufgehalten haben oder während eine andere Person Ihr Endgerät
+ verwendet hat. Die Risiko-Begegnung kann auch aufgrund bestehender Grenzen
+ bei der Kontaktmessung fälschlicherweise registriert worden sein (siehe
+ unten Ziffer 8).
+
+ Die App dient der Unterbrechung von Infektionsketten.
+
+
+
+
+ Die App schützt Sie nicht vor einer SARS-CoV-2-Infektion.
+
+
+
+
+ Die App reduziert Ihr persönliches Infektionsrisiko nicht.
+
+
+
+
+ Sie können sich auch mit SARS-CoV-2 infizieren, ohne dass die App
+ Sie über die Risiko-Begegnung mit der Person benachrichtigt, die
+ Sie infiziert hat:
+
+
+
+
+ o Die App registriert nicht alle Ihre Begegnungen mit anderen Personen,
+ z.B. weil andere Personen die App nicht verwenden, Sie Ihr Endgerät nicht
+ immer bei sich tragen oder die App nicht immer in Betrieb haben oder weil
+ die Kontaktmessung gewissen Grenzen unterliegt (siehe unten Ziffer 8).
+
+
+ o Die App informiert Sie nur über festgestellte Risiko-Begegnungen mit
+ infizierten Personen. Das setzt voraus, dass die App die Begegnung mit der
+ infizierten Person registriert hat und die infizierte Person eine
+ Warnung über die App auslöst. Das Auslösen der Warnung ist freiwillig und
+ erfolgt möglicherweise nicht durch alle infizierten Personen.
+
+
+ Bitte halten Sie auch bei Verwendung der App die sonstigen
+ Vorsichtsmaßnahmen und behördlichen Anordnungen ein. Verlässliche
+ Informationen über die SARS-CoV-2-Pandemie und Vorsichtsmaßnahmen finden
+ Sie unter anderem auf:
+
+
+ www.infektionsschutz.de/coronavirus
+
+
+ www.zusammengegencorona.de
+
+
+ www.rki.de/covid-19
+
+
+ Diese weiterführenden Informationen dienen lediglich Ihrer Information und
+ sind nicht Bestandteil dieser Nutzungsbedingungen.
+
+
+Halten Sie sich auch bei Verwendung der App an die AHA-Regeln:
+
+
+ A
+ ✋ - Halten Sie mindestens 1,5m Abstand zu Ihren Mitmenschen
+
+
+ H
+ � - Waschen Sie sich regelmäßig für mindestens 20 Sekunden die Hände
+
+
+ A
+ � - Tragen Sie beim Einkauf und in öffentlichen Verkehrsmitteln eine
+ Alltagsmaske
+
+
+ So schützen Sie sich selbst und andere vor dem Virus.
+
+ Sie dürfen über die App ausschließlich Ihre eigenen Testergebnisse abrufen.
+
+
+ Wenn Sie auf Testergebnisse warten und die CWA-Dienste nicht zur Verfügung
+ stehen oder der Abruf der Testergebnisse über die App aus sonstigen Gründen
+ nicht funktioniert, dann informieren Sie sich bitte über andere Kontaktwege
+ über das Testergebnis, z.B. über die jeweilige Teststelle wie Ihren
+ Hausarzt oder das örtliche Gesundheitsamt. Warten Sie nicht darauf, dass
+ die App wieder zur Verfügung steht.
+
+ Sie können über die App andere Kontaktpersonen warnen, wenn Sie mit
+SARS-CoV-2 infiziert wurden. Sie dürfen diese Warnung nur auslösen, wenn
+
+ die Infektion durch einen Test in einem zugelassenen Testlabor positiv
+ bestätigt wurde.
+
+
+
+ Falls das zugelassene Testlabor noch nicht an die CWA-Dienste angeschlossen
+ ist, erfolgt eine Überprüfung Ihres Infektionsstatus über eine vom RKI
+ eingerichtete Verifikations-Hotline. Das Auslösen einer Warnung über die
+ App auf der Grundlage einer bloßen Risiko-Mitteilung ist nicht zulässig.
+
+
+ Bei Unsicherheit: erst Hausarzt oder Gesundheitsamt kontaktieren
+
+
+ Wenn Sie nicht sicher sind, ob Sie sich infiziert haben oder nicht, dann
+ kontaktieren Sie bitte Ihren Hausarzt oder das zuständige Gesundheitsamt,
+ bevor Sie eine Warnung auslösen. Hier erhalten Sie weitere Beratung und
+ können sich erforderlichenfalls auf eine Infektion testen lassen. In der
+ Zwischenzeit befolgen Sie die allgemein gültigen Empfehlungen für das
+ Verhalten bei dem Verdacht einer SARS-CoV-2-Infektion.
+
+
+ Missbrauchsverbot
+
+
+
+ Das missbräuchliche Auslösen einer Warnung ist untersagt und kann
+ schwerwiegende Konsequenzen nach sich ziehen.
+
+ Insbesondere können Sie sich eventuell gegenüber anderen betroffenen
+ Personen schadenersatzpflichtig machen.
+
+
+ Das RKI behält sich vor, Sie bei Feststellung eines missbräuchlichen
+ Verhaltens von der weiteren Nutzung der App und der CWA-Dienste
+ auszuschließen.
+
+ Folgende technische Voraussetzungen sind für die Nutzung der App
+ erforderlich:
+
+
+ Sie benötigen eine Datenverbindung
+
+
+ Bestimmte Funktionen der App setzen auf zentrale Dienste und Systeme auf,
+ die über die CWA-Dienste zur Verfügung gestellt werden. Diese Funktionen
+ stehen daher nur zur Verfügung, wenn Ihr Endgerät über eine Datenverbindung
+ mit dem Internet verfügt, z.B. über UMTS, LTE oder WLAN, um hierüber auf
+ die CWA-Dienste zugreifen zu können. Ohne Datenverbindung stehen einige
+ oder alle Funktionen der App nicht zur Verfügung. Dies gilt auch, wenn Sie
+ Ihr Endgerät in den Flugmodus versetzen oder ausschalten.
+
+
+ Die App muss auf dem Endgerät laufen und eingeschaltet sein
+
+
+ Die App muss auf Ihrem Endgerät im Vorder- oder Hintergrund laufen und
+ eingeschaltet sein. Hierzu müssen Sie die App starten. Wenn Sie die App
+ nicht starten, ausschalten oder beenden, speichert die App keine
+ Begegnungen mit anderen Personen und erzeugt keine Zufallscodes zur
+ Speicherung durch andere Personen. Wenn Sie das Endgerät neu starten (z.B.
+ nach dem Ausschalten, nachdem die Batterie leer war oder nach einem Update
+ des Betriebssystems), müssen Sie auch die App neu starten.
+
+
+ Einstellungen im Endgerät
+
+
+ Für die Nutzung der App müssen Sie ferner die Bluetooth (BLE)-Funktionen
+ auf Ihrem Endgerät aktivieren und ggf. zur Verwendung durch die App
+ freigegeben.
+
+
+ Für die Nutzung der App empfiehlt das RKI ferner folgende Funktionen auf
+ Ihrem Endgerät zu aktivieren und ggf. zur Verwendung durch die App
+ freizugegeben, auch wenn diese nicht Voraussetzung für die Nutzung der
+ grundlegenden Funktionen der App sind:
+
+
+
+ Benachrichtigungen
+
+
+ Kamerafunktion
+
+
+
+ Bitte prüfen Sie in den Einstellungen ihres Endgeräts, ob diese Funktionen
+ aktiviert und für die Verwendung der App freigegeben sind.
+
+
+ Eine ausführliche Anleitung zur Einrichtung der App unter iOS und Android
+ finden Sie unter [Link]. Die Anleitung dient lediglich der
+ Erläuterung und ist nicht Teil dieser Nutzungsbedingungen.
+
+
+ Sie müssen immer die aktuelle Version der App verwenden
+
+
+ Das RKI wird von Zeit zu Zeit Updates der App zur Verfügung stellen. Sie
+ müssen diese Updates unverzüglich installieren und immer die neueste
+ verfügbare Version der App verwenden. Beim Verwenden älterer Versionen kann
+ es zu Fehlfunktionen und Störungen kommen.
+
+
+
+ Sie benötigen aktuelle Versionen von iOS bzw. Android
+
+
+
+ Die App verwendet eigens von Apple in iOS und Google in Android
+ implementierte Funktionen (sog. Exposure Notification). Diese
+stehen in iOS erst ab Version 13.5 und in Android erst ab Version [x]zur Verfügung. Die App funktioniert
+ daher leider nicht mit früheren Versionen der beiden Betriebssysteme.
+
+ Die App kann Sie dabei unterstützen, Risiko-Begegnungen mit Personen zu
+ erkennen, die später positiv getestet wurden. Die App hat aber auch
+ Grenzen, die berücksichtigt werden müssen.
+
+
+Eine dieser Grenzen ist, dass die App zwar laufend eigene Zufallscodes ( Rolling Proximity Identifiers) aussendet, aber andere Zufallscodes
+ nur in bestimmten Intervallen empfängt. Diese Empfangsfenster liegen
+ derzeit noch bis zu fünf Minuten auseinander und sind nur als sehr kurz
+ spezifiziert. In der App sind die Empfangsfenster vier Sekunden lang.
+
+
+ Für die Entfernungsmessung wird die Dämpfung des Bluetooth-Signals
+ verwendet. Eine geringere Dämpfung bedeutet dabei grundsätzlich, dass das
+ andere Endgerät näher ist. Eine höhere Dämpfung kann entweder bedeuten,
+ dass das andere Endgerät weiter entfernt ist (also eine Entfernung von mehr
+ als zwei Metern) oder dass sich zwischen den beiden Endgeräten etwas
+ befindet, was das Signal blockiert. Das können Objekte wie eine Wand oder
+ eine Tasche, in der sich das Endgerät befindet, sein, aber genauso Personen
+ oder Tiere.
+
+ Hiermit wird Ihnen eine eingeschränkte, nicht ausschließliche, nicht
+ übertragbare, nicht unterlizenzierbare, widerrufliche Lizenz zur Nutzung
+ der App für Ihre persönlichen, nicht kommerziellen Zwecke gewährt.
+
+
+ Die Lizenz für die iOS-Version der App umfasst die Nutzung auf jedem
+ Apple-Gerät, an dem Sie Eigentum haben oder über das Sie Kontrolle ausüben,
+ im Rahmen der geltenden Nutzungsbedingungen des App Stores, wobei auch über
+ andere Apple Accounts, die mit Ihrem Apple Account via Family Sharing oder
+ Volumenkauf verbunden sind, auf die App zugegriffen und diese genutzt
+ werden kann.
+
+
+ Sie dürfen im Rahmen von Datensicherungen Kopien der App anfertigen.
+ Darüberhinausgehende Rechte an der App werden Ihnen nicht eingeräumt.
+
+
+ Eigentum an der App
+
+
+ Die App (einschließlich des Quellcodes) ist das alleinige und
+ ausschließliche Eigentum von SAP SE, Dietmar Hopp Allee 16, 69190 Walldorf
+ („SAP“) oder deren Lizenzgebern, vorbehaltlich der Ihnen
+ nach Ziffer 9 eingeräumten Rechte sowie sonstiger Rechte an der App, die
+ SAP der Bundesrepublik Deutschland vertraglich eingeräumt hat.
+
+
+ Open Source-Lizenzhinweise
+
+
+ Information über die Verwendung von Drittkomponenten in der App und die
+ anwendbaren Lizenzbestimmungen finden Sie in den Open
+ Source-Lizenzhinweisen in der App.
+
+
+ Der Quellcode der App ist unter den Lizenzbedingungen der "Apache 2.0
+ License" veröffentlicht und kann unter "
+ https://github.com/corona-warn-app
+ " heruntergeladen werden. Die Lizenzbedingungen der "Apache 2.0 License"
+ sind unter "
+ https://www.apache.org/licenses/LICENSE-2.0
+ " abrufbar.
+
+
+ Die auf den Quellcode der App sowie auf in der App enthaltene
+ Drittkomponenten jeweils anwendbaren Lizenzbestimmungen bleiben von der
+ Rechteeinräumung nach dieser Ziffer 9 unberührt.
+
+
+ Was nicht erlaubt ist
+
+
+ Sie dürfen die App nicht manipulieren oder verändern.
+
+
+ Sie dürfen die App und die Schnittstellen zu den CWA-Diensten nicht
+ missbräuchlich verwenden. Sie dürfen die CWA-Dienste nicht für andere
+ Zwecke nutzen als den bestimmungsgemäßen Betrieb der App auf Ihrem
+ Endgerät. Sie dürfen auf die CWA-Dienste ausschließlich über die App
+ zugreifen.
+
+ Die App wird Ihnen so zur Verfügung gestellt, wie sie vom RKI herausgegeben
+ wird. Das RKI übernimmt keine Gewähr für die Funktionsfähigkeit der App
+ oder der CWA-Dienste und vereinbart mit Ihnen keine bestimmte
+ Beschaffenheit. Sie haben keinen Anspruch auf eine bestimmte Funktionalität
+ oder anderweitige Beschaffenheit der App oder der CWA-Dienste. Das RKI kann
+ die App jederzeit ändern und Funktionen ganz oder teilweise entfernen oder
+ die App um zusätzliche Funktionen erweitern.
+
+
+ Keine Verfügbarkeitszusage
+
+
+ Das RKI kann den Betrieb der App und der CWA-Dienste jederzeit einschränken
+ oder einstellen. Es besteht Ihrerseits kein Anspruch auf die weitergehende
+ Verfügbarkeit der App oder der damit verbundenen Dienste und Systeme
+ einschließlich der CWA-Dienste, weder in Bezug auf einzelne Funktionen noch
+ in Bezug auf das System als Ganzes.
+
+
+ Das RKI macht keine Zusagen über die Verfügbarkeit oder Leistungsfähigkeit
+ der CWA-Dienste. Diese können aufgrund von Wartungsarbeiten oder Störungen
+ vorübergehend und ggf. auch für längere Zeiträume nicht zur Verfügung
+ stehen. In diesen Fällen ist die Funktionalität der App ganz oder teilweise
+ eingeschränkt.
+
+
+ Änderung der Nutzungsbedingungen
+
+
+ Das RKI behält sich vor, diese Nutzungsbedingungen zu ändern. In diesem
+ Fall werden Sie beim Start der App aufgefordert, den geänderten
+ Nutzungsbedingungen zuzustimmen. Wenn Sie den geänderten
+ Nutzungsbedingungen nicht zustimmen, können Sie die App und die CWA-
+ Dienste nicht mehr nutzen und müssen die App von Ihrem Endgerät löschen.
+
+
+ Risk Score
+
+
+Das RKI behält sich ferner vor, die im Rahmen der Risikobewertung ( risk score) verwendeten Parameter jederzeit zu ändern, um dadurch
+ jeweils aktuellen Forschungsergebnissen zur Virusübertragung zu
+ entsprechen. Das RKI bestimmt die verwendeten Parameter jeweils nach seinem
+ Ermessen.
+
+ Das RKI bestimmt die Funktionen der App und der CWA-Dienste sowie deren
+ Ausgestaltung. Das RKI vereinbart mit Ihnen keine bestimmte Beschaffenheit
+ und Sie haben keinen Anspruch darauf, dass die App bestimmte Funktionen hat
+ oder diese in bestimmter Weise ausgestaltet sind. Die App wird in dem
+ Zustand und mit den Funktionen zur Verfügung gestellt, wie sie beim
+ Veröffentlichen der App im Apple App Store oder bei Google Play durch das
+ RKI implementiert sind.
+
+
+ Das RKI wird die App mit angemessener Sorgfalt zur Verfügung stellen und
+ angemessene Sorgfalt hinsichtlich der CWA-Dienste anwenden. Das RKI gibt
+ keine sonstigen Versprechen oder Zusicherungen im Hinblick auf die App oder
+ die CWA-Dienste ab und gewährleistet insbesondere nicht, dass:
+
+
+ · Ihre Nutzung der App oder der CWA-Dienste ohne Unterbrechung möglich oder
+ fehlerfrei sein wird,
+
+
+ · die App oder die CWA-Dienste frei von Verlusten, Korruption, Angriffen,
+ Viren, Eingriffen, Hacking oder anderen sicherheitsrelevanten Störungen
+ sein werden.
+
+
+ Für die Datensicherung Ihres Endgeräts sowie ggf. damit verbundener Systeme
+ sind Sie verantwortlich, inklusive der Datensicherung sämtlicher anderer
+ Apps, welche auf Ihrem Endgerät gespeichert sind.
+
+ Die folgenden Bedingungen gelten für den Bezug der App über den Apple App
+ Store und die Nutzung der App unter dem Betriebssystem iOS.
+
+
+ Einwilligung zur Nutzung von Daten
+
+
+ Sie erklären sich damit einverstanden, dass das RKI technische Daten und
+ zugehörige Informationen – insbesondere technische Informationen über Ihr
+ Gerät, System und Ihre Anwendungssoftware sowie Peripheriegeräte – erheben
+ und nutzen darf, die in regelmäßigen Abständen erfasst werden, um die
+ Bereitstellung von Software-Aktualisierungen, Produkt-Support und anderen
+ im Zusammenhang mit der App gegenüber Ihnen erbrachten Dienstleistungen
+ (soweit gegeben) zu erleichtern. Das RKI darf diese Informationen nutzen,
+ um seine Produkte zu verbessern oder Ihnen Dienstleistungen oder
+ Technologien zur Verfügung zu stellen, solange dies in einer Form erfolgt,
+ die Ihre Identität nicht preisgibt.
+
+
+ Wartung und Support
+
+
+ Das RKI ist als Herausgeber der App allein verantwortlich für Wartung und
+ Support der App nach Maßgabe dieser Nutzungsbedingungen. Apple übernimmt
+ keinerlei Verpflichtung zur Erbringung irgendwelcher Wartungs- und
+ Supportleistungen in Bezug auf die App.
+
+
+ Keine Haftung von Apple für Störungen
+
+
+ Im Fall von Störungen der App steht es Ihnen frei, Apple hierüber zu
+ informieren. Soweit gesetzlich zulässig hat Apple keine weitergehenden
+ Pflichten wegen Störungen der App.
+
+
+ Produkthaftung
+
+
+ Apple ist nicht verantwortlich für etwaige Ansprüche Ihrerseits oder von
+ Dritten in Bezug auf die App oder deren Besitz oder Verwendung
+ einschließlich
+
+
+
+ Ansprüchen wegen Produkthaftung,
+
+
+
+ · Ansprüchen auf der Basis, dass die App anwendbare gesetzliche oder
+ regulatorische Anforderungen nicht erfüllt und
+
+
+ · Ansprüchen unter Verbrauchschutz- und Datenschutzgesetzen oder ähnlichen
+ Gesetzen,
+
+
+ einschließlich im Zusammenhang mit der Nutzung der HealthKit und
+ HomeKit-Frameworks.
+
+
+ Verletzung von Schutzrechten Dritter
+
+
+ Für den Fall, dass Dritte Ansprüche wegen der Verletzung von Schutzrechten
+ durch die App oder den Besitz oder die Verwendung der App durch Sie geltend
+ machen, ist Apple nicht verantwortlich für Untersuchungen, Verteidigung,
+ Beilegung oder Erfüllung solcher Ansprüche wegen der Verletzung von
+ Schutzrechten.
+
+
+ US Embargos und Sanktionen
+
+
+ Mit Anerkennen dieser Nutzungsbedingungen bestätigten Sie,
+
+
+ · dass Sie sich nicht in einem Land aufhalten, das einem Embargo der
+ Regierung der Vereinigten Staaten von Amerika unterliegt oder von der
+ Regierung der Vereinigten Staaten von Amerika als Unterstützer von
+ Terroristen ("terrorist supporting" country) designiert wurde und
+
+
+ · dass Sie nicht auf einer Liste der Regierung der Vereinigten Staaten von
+ Amerika als sog. Prohibited or Restricted Party geführt werden.
+
+
+ Drittbegünstigung von Apple
+
+
+ Sie erkennen an und erklären sich damit einverstanden, dass Apple ein
+ Drittbegünstigter unter diesen Nutzungsbedingungen ist und Apple daher
+ diese Nutzungsbedingungen Ihnen gegenüber durchsetzen kann. Die Änderung
+ und Aufhebung dieser Nutzungsbedingungen einschließlich der Rechte von
+ Apple hierunter bleibt den Vertragsparteien vorbehalten und bedarf nicht
+ der Zustimmung von Apple.
+
+ Bestimmungsgemäße Nutzung / Sperrung bei missbräuchlicher Verwendung
+
+
+ Sie dürfen die App und die CWA-Dienste nur bestimmungsgemäß nutzen. Das RKI
+ behält sich vor, Sie bei missbräuchlicher Verwendung der App oder nicht
+ bestimmungsgemäßem Zugriff auf die CWA-Dienste von der Nutzung der App und
+ der CWA-Dienste auszuschließen.
+
+
+ Dienste Dritter
+
+
+ Sofern Sie im Zusammenhang mit der Nutzung der App Dienste Dritter in
+ Anspruch nehmen, insbesondere die Dienste von
+ Telekommunikationsdienstleistern für die Bereitstellung einer
+ Datenverbindung, sind Sie für damit im Zusammenhang stehenden Kosten und
+ die Einhaltung der jeweiligen Vertragsbedingungen selbst verantwortlich.
+
+
+ Anwendbares Recht
+
+
+ Diese Nutzungsbedingungen unterliegen dem Recht der Bundesrepublik
+ Deutschland. Das Übereinkommen der Vereinten Nationen über Verträge über
+ den internationalen Warenkauf findet keine Anwendung. Die gesetzlichen
+ Vorschriften zur Beschränkung der Rechtswahl und zur Anwendbarkeit
+ zwingender Vorschriften insbesondere des Staates, in dem Sie als
+ Verbraucher Ihren gewöhnlichen Aufenthalt haben, bleiben unberührt.
+
+
+ Teilunwirksamkeit
+
+
+ Diese Nutzungsbedingungen bleiben auch bei rechtlicher Unwirksamkeit
+ einzelner Punkte in ihren übrigen Teilen verbindlich. Anstelle der
+ unwirksamen Punkte treten, soweit vorhanden, die gesetzlichen Vorschriften.
+ Soweit dies für eine Vertragspartei eine unzumutbare Härte darstellen
+ würde, werden die Nutzungsbedingungen jedoch im Ganzen unwirksam.
+
+
+ * * *
+
+]]>Eine Hand hält ein Smartphone mit viel Text, daneben ist ein Haken als Symbol für akzeptierte Nutzungsbedingungen.
@@ -1344,75 +2170,75 @@ ist das Robert Koch-Institut, Nordufer 20, 13353 Berlin (im Folgenden „Components:
Component: JUnit 4
Licensor: The JUnit Team
- Website: https://junit.org/junit4/
+ Website: https://junit.org/junit4/
License: Eclipse Public License 1.0
Component: Robolectric
Licensor: Xtreme Labs, Pivotal Labs and Google Inc.
- Website: http://robolectric.org/
+ Website: https://robolectric.org/
License: MIT
Component: RootBeer
Licensor: Scott Alexander-Bown, Mat Rollings
- Website: https://github.com/scottyab/rootbeer
+ Website: https://github.com/scottyab/rootbeer
License: Apache 2.0
Copyright (c) 2008-2020 Zetetic LLC
All rights reserved.
@@ -1687,30 +2513,20 @@ as modifying the License.
Eine Hand hält ein Smartphone mit viel Text, daneben ist eine Balkenwaage als Symbol für rechtliche Hinweise.Impressum
-
-
- Herausgeber
- (verantwortlich nach § 5 Abs. 1 TMG, § 55 Abs. 1 RStV, DS-GVO, BDSG)
-
-
- Robert Koch-Institut
- Nordufer 20
- 13353 Berlin
-
- Umsatzsteueridentifikationsnummer
- DE 165 893 430
-
-]]>
+
+ Herausgeber
+
+ (verantwortlich nach § 5 Abs. 1 TMG, § 55 Abs. 1 RStV, DS-GVO, BDSG)
+
+ Robert Koch-Institut\nNordufer 20\n13353 Berlin\n\nvertreten durch den Präsidenten
+
+ Kontakt
+
+ E-Mail: CoronaWarnApp@rki.de\nTelefon: 030 18754 – 5100
+
+ Umsatzsteueridentifikationsnummer
+
+ DE 165 893 430Eine Hand hält ein Smartphone mit viel Text, daneben ist ein Paragraphenzeichen als Symbol für das Impressum.
@@ -1831,6 +2647,14 @@ as modifying the License.
Bitte aktivieren Sie die Risiko-Ermittlung um andere zu warnen.OK
+
+ Test entfernen?
+
+ Der Test wird endgültig aus der Corona-Warn-App entfernt und kann nicht wieder hinzugefügt werden. Dieser Vorgang kann nicht widerrufen werden.
+
+ Entfernen
+
+ AbbrechenSARS-CoV-2 Positiv
@@ -1840,9 +2664,13 @@ as modifying the License.
TAN Eingabe
- Die TAN ist 7-stellig und Groß- und Kleinschreibung muss beachtet werden.\n\nGeben Sie bitte die Ihnen mitgeteilte TAN ein:
+ Geben Sie bitte die 10 Stellen der TAN ein, die Ihnen mitgeteilt wurde.Weiter
+
+ Ungültige TAN, bitte überprüfen Sie Ihre Eingabe.
+
+ Ungültige Eingabe, bitte überprüfen Sie das Zeichen.
@@ -1950,7 +2778,9 @@ as modifying the License.
- +49 (0) 800 7540002
+ +49 (0) 800 7540002
+
+ +49 800 7540002Test per TAN-Eingabe in der App registrieren
diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml
index 44d3f74ccf1..28523970dfd 100644
--- a/Corona-Warn-App/src/main/res/values/styles.xml
+++ b/Corona-Warn-App/src/main/res/values/styles.xml
@@ -65,10 +65,10 @@
@color/colorTextPrimary1@drawable/rectangle@color/button_main_tracing
- @dimen/button_padding_start_end
- @dimen/button_padding_top_bottom
- @dimen/button_padding_start_end
- @dimen/button_padding_top_bottom
+ @dimen/spacing_small
+ @dimen/spacing_tiny
+ @dimen/spacing_small
+ @dimen/spacing_tiny
+
+