diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/QrCodeDetailFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/QrCodeDetailFragmentTest.kt index 9986448a35777f646a5b4b694ce54a39f8fbde0d..88fd58510e72caa29f6f538ac577647279cadedc 100644 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/QrCodeDetailFragmentTest.kt +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/QrCodeDetailFragmentTest.kt @@ -5,9 +5,13 @@ import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import dagger.Module import dagger.android.ContributesAndroidInjector import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.appconfig.AppConfigProvider +import de.rki.coronawarnapp.appconfig.ConfigData +import de.rki.coronawarnapp.appconfig.PresenceTracingConfig import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository import de.rki.coronawarnapp.ui.presencetracing.organizer.details.QrCodeDetailFragment @@ -15,7 +19,10 @@ import de.rki.coronawarnapp.ui.presencetracing.organizer.details.QrCodeDetailFra import de.rki.coronawarnapp.ui.presencetracing.organizer.details.QrCodeDetailViewModel import io.mockk.MockKAnnotations import io.mockk.coEvery +import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import kotlinx.coroutines.flow.flowOf import org.joda.time.DateTimeZone import org.junit.After import org.junit.Before @@ -30,6 +37,7 @@ import java.util.TimeZone class QrCodeDetailFragmentTest : BaseUITest() { @MockK private lateinit var qrCodeGenerator: QrCodeGenerator + @MockK private lateinit var appConfigProvider: AppConfigProvider @MockK private lateinit var traceLocationRepository: TraceLocationRepository private val timeZone = TimeZone.getTimeZone("Europe/Berlin") @@ -42,6 +50,13 @@ class QrCodeDetailFragmentTest : BaseUITest() { coEvery { traceLocationRepository.traceLocationForId(1) } returns TraceLocationData.traceLocationSameDate coEvery { traceLocationRepository.traceLocationForId(2) } returns TraceLocationData.traceLocationDifferentDate + coEvery { appConfigProvider.currentConfig } returns flowOf( + mockk<ConfigData>().apply { + every { presenceTracing } returns mockk<PresenceTracingConfig>().apply { + every { qrCodeErrorCorrectionLevel } returns ErrorCorrectionLevel.M + } + } + ) setupMockViewModel( object : QrCodeDetailViewModel.Factory { @@ -87,7 +102,8 @@ class QrCodeDetailFragmentTest : BaseUITest() { traceLocationId = traceLocationId, qrCodeGenerator = qrCodeGenerator, traceLocationRepository = traceLocationRepository, - dispatcher = TestDispatcherProvider() + dispatcher = TestDispatcherProvider(), + appConfigProvider = appConfigProvider ) } diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestViewModel.kt index 05bfd33c01dc2301b9fa3523e4e790b8ef72341f..02f7de56f669d9fee6d2d940cea27b6b476ccf25 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestViewModel.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestViewModel.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.appconfig.AppConfigProvider import de.rki.coronawarnapp.presencetracing.checkins.qrcode.PosterTemplateProvider import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator import de.rki.coronawarnapp.presencetracing.checkins.qrcode.Template @@ -30,6 +31,7 @@ class QrCodePosterTestViewModel @AssistedInject constructor( private val qrCodeGenerator: QrCodeGenerator, private val posterTemplateProvider: PosterTemplateProvider, private val traceLocationRepository: TraceLocationRepository, + private val appConfigProvider: AppConfigProvider, private val fileSharing: FileSharing ) : CWAViewModel(dispatcher) { @@ -81,10 +83,12 @@ class QrCodePosterTestViewModel @AssistedInject constructor( if (isRunning) return@launch isRunning = true val traceLocation = traceLocation() + val correctionLevel = appConfigProvider.getAppConfig().presenceTracing.qrCodeErrorCorrectionLevel val qrCode = qrCodeGenerator.createQrCode( input = traceLocation.locationUrl, length = length, - margin = 0 + margin = 0, + correctionLevel = correctionLevel ) qrCodeBitmap.postValue(qrCode) } catch (e: Exception) { @@ -99,11 +103,13 @@ class QrCodePosterTestViewModel @AssistedInject constructor( try { val traceLocation = traceLocation() val template = posterTemplateProvider.template() + val correctionLevel = appConfigProvider.getAppConfig().presenceTracing.qrCodeErrorCorrectionLevel Timber.d("template=$template") val qrCode = qrCodeGenerator.createQrCode( input = traceLocation.locationUrl, length = template.qrCodeLength, - margin = 0 + margin = 0, + correctionLevel = correctionLevel ) val textInfo = buildString { diff --git a/Corona-Warn-App/src/main/assets/privacy_de.html b/Corona-Warn-App/src/main/assets/privacy_de.html index d07e702a1e17005b76827a5865f8bb8df6011a31..34d84e3ce1d59b9210ee3fff6299de20fb1dec52 100644 --- a/Corona-Warn-App/src/main/assets/privacy_de.html +++ b/Corona-Warn-App/src/main/assets/privacy_de.html @@ -7,22 +7,22 @@ <p> Folgende Themen werden behandelt: </p> -<ol> - <li><strong>Wer ist Herausgeber der Corona-Warn-App?</strong></li> - <li><strong>Ist die Nutzung der App freiwillig?</strong></li> - <li><strong>Auf welcher Rechtsgrundlage werden Ihre Daten verarbeitet?</strong></li> - <li><strong>An wen richtet sich die App?</strong></li> - <li><strong>Welche Daten werden verarbeitet?</strong></li> - <li><strong>Wofür werden Ihre Daten verarbeitet?</strong></li> - <li><strong>Wie funktioniert das länderübergreifende Warnsystem?</strong></li> - <li><strong>Welche Berechtigungen benötigt die App?</strong></li> - <li><strong>Wann werden Ihre Daten gelöscht?</strong></li> - <li><strong>An wen werden Ihre Daten weitergegeben?</strong></li> - <li><strong>Werden Ihre Daten in Länder außerhalb der EU übermittelt?</strong></li> - <li><strong>Wie können Sie Ihr Einverständnis zurücknehmen?</strong></li> - <li><strong>Welche weiteren Datenschutzrechte haben Sie?</strong></li> - <li><strong>Datenschutzbeauftragter und Kontakt</strong></li> -</ol> +<ul> + <li><strong>1. Wer ist Herausgeber der Corona-Warn-App?</strong></li> + <li><strong>2. Ist die Nutzung der App freiwillig?</strong></li> + <li><strong>3. Auf welcher Rechtsgrundlage werden Ihre Daten verarbeitet?</strong></li> + <li><strong>4. An wen richtet sich die App?</strong></li> + <li><strong>5. Welche Daten werden verarbeitet?</strong></li> + <li><strong>6. Wofür werden Ihre Daten verarbeitet?</strong></li> + <li><strong>7. Wie funktioniert das länderübergreifende Warnsystem?</strong></li> + <li><strong>8. Welche Berechtigungen benötigt die App?</strong></li> + <li><strong>9. Wann werden Ihre Daten gelöscht?</strong></li> + <li><strong>10. An wen werden Ihre Daten weitergegeben?</strong></li> + <li><strong>11. Werden Ihre Daten in Länder außerhalb der EU übermittelt?</strong></li> + <li><strong>12. Wie können Sie Ihr Einverständnis zurücknehmen?</strong></li> + <li><strong>13. Welche weiteren Datenschutzrechte haben Sie?</strong></li> + <li><strong>14. Datenschutzbeauftragter und Kontakt</strong></li> +</ul> <p> Damit dieser Text für alle Nutzer verständlich ist, bemühen wir uns um eine einfache und möglichst untechnische Darstellung. diff --git a/Corona-Warn-App/src/main/assets/privacy_en.html b/Corona-Warn-App/src/main/assets/privacy_en.html index 3cab6eaf586af2ed48b5f696178842a32787b41b..2d69b43027d732d97a4ecafbda1b0875d7634323 100644 --- a/Corona-Warn-App/src/main/assets/privacy_en.html +++ b/Corona-Warn-App/src/main/assets/privacy_en.html @@ -6,22 +6,22 @@ <p> It covers the following topics: </p> -<ol> - <li><strong>Who is the Corona-Warn-App published by?</strong></li> - <li><strong>Is using the app voluntary?</strong></li> - <li><strong>On what legal basis is your data processed?</strong></li> - <li><strong>Who is the app aimed at?</strong></li> - <li><strong>What data is processed?</strong></li> - <li><strong>Why is your data processed?</strong></li> - <li><strong>How does the transnational warning system work?</strong></li> - <li><strong>What permissions does the app require?</strong></li> - <li><strong>When will your data be deleted?</strong></li> - <li><strong>Who will receive your data?</strong></li> - <li><strong>Is your data transferred to countries outside the EU?</strong></li> - <li><strong>How can you withdraw your consent?</strong></li> - <li><strong>What other rights do you have under data protection law?</strong></li> - <li><strong>Data protection officer and contact</strong></li> -</ol> +<ul> + <li><strong>1. Who is the Corona-Warn-App published by?</strong></li> + <li><strong>2. Is using the app voluntary?</strong></li> + <li><strong>3. On what legal basis is your data processed?</strong></li> + <li><strong>4. Who is the app aimed at?</strong></li> + <li><strong>5. What data is processed?</strong></li> + <li><strong>6. Why is your data processed?</strong></li> + <li><strong>7. How does the transnational warning system work?</strong></li> + <li><strong>8. What permissions does the app require?</strong></li> + <li><strong>9. When will your data be deleted?</strong></li> + <li><strong>10. Who will receive your data?</strong></li> + <li><strong>11. Is your data transferred to countries outside the EU?</strong></li> + <li><strong>12. How can you withdraw your consent?</strong></li> + <li><strong>13. What other rights do you have under data protection law?</strong></li> + <li><strong>14. Data protection officer and contact</strong></li> +</ul> <p> To make sure that this text can be understood by all users, we have made every effort to make it simple and as non-technical as possible. diff --git a/Corona-Warn-App/src/main/assets/privacy_tr.html b/Corona-Warn-App/src/main/assets/privacy_tr.html index e8ea93be63cf2ea3f718825d721fc9d8181c4773..1bf1c47d818fef8153a98ab5305c240b96401ef8 100644 --- a/Corona-Warn-App/src/main/assets/privacy_tr.html +++ b/Corona-Warn-App/src/main/assets/privacy_tr.html @@ -7,22 +7,22 @@ <p> Burada aÅŸağıdaki konular ele alınmaktadır: </p> -<ol> - <li><strong>Corona-Warn-App’ın yayımcısı kimdir?</strong></li> - <li><strong>Uygulamanın kullanılması isteÄŸe baÄŸlı mı?</strong></li> - <li><strong>Verileriniz iÅŸlenmesinde hangi yasal dayanaklar söz konusudur?</strong></li> - <li><strong>Uygulama kimleri hedefler?</strong></li> - <li><strong>Hangi veriler iÅŸlenir?</strong></li> - <li><strong>Verileriniz niçin iÅŸleniyor?</strong></li> - <li><strong>Sınır ötesi uyarı sistemi nasıl çalışır?</strong></li> - <li><strong>Uygulamanın hangi izinlere gerek duyar?</strong></li> - <li><strong>Verileriniz ne zaman silinir?</strong></li> - <li><strong>Verileriniz kime aktarılır?</strong></li> - <li><strong>Verileriniz AB dışındaki ülkelere aktarılacak mı?</strong></li> - <li><strong>VerdiÄŸiniz rıza beyanını nasıl geri alabilirsiniz?</strong></li> - <li><strong>BaÅŸka hangi veri koruma haklarına sahipsiniz?</strong></li> - <li><strong>Veri koruma görevlisi ve iletiÅŸim</strong></li> -</ol> +<ul> + <li><strong>1. Corona-Warn-App’ın yayımcısı kimdir?</strong></li> + <li><strong>2. Uygulamanın kullanılması isteÄŸe baÄŸlı mı?</strong></li> + <li><strong>3. Verileriniz iÅŸlenmesinde hangi yasal dayanaklar söz konusudur?</strong></li> + <li><strong>4. Uygulama kimleri hedefler?</strong></li> + <li><strong>5. Hangi veriler iÅŸlenir?</strong></li> + <li><strong>6. Verileriniz niçin iÅŸleniyor?</strong></li> + <li><strong>7. Sınır ötesi uyarı sistemi nasıl çalışır?</strong></li> + <li><strong>8. Uygulamanın hangi izinlere gerek duyar?</strong></li> + <li><strong>9. Verileriniz ne zaman silinir?</strong></li> + <li><strong>10. Verileriniz kime aktarılır?</strong></li> + <li><strong>11. Verileriniz AB dışındaki ülkelere aktarılacak mı?</strong></li> + <li><strong>12. VerdiÄŸiniz rıza beyanını nasıl geri alabilirsiniz?</strong></li> + <li><strong>13. BaÅŸka hangi veri koruma haklarına sahipsiniz?</strong></li> + <li><strong>14. Veri koruma görevlisi ve iletiÅŸim</strong></li> +</ul> <p> Bu metnin tüm kullanıcılar için anlaşılabilir olması amacıyla, mümkün olduÄŸunca basit ve teknik terimler içermeyen bir metin hazırladık. diff --git a/Corona-Warn-App/src/main/assets/terms_de.html b/Corona-Warn-App/src/main/assets/terms_de.html index f0fac924b935e53842914600aa34a50e440e7d75..36de702c330e2a02048a18d3ee56afc97b637921 100644 --- a/Corona-Warn-App/src/main/assets/terms_de.html +++ b/Corona-Warn-App/src/main/assets/terms_de.html @@ -67,7 +67,7 @@ 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) („<strong>App</strong>“) und - der Nutzung weiterer Dienste („<a name="_Hlk41947003"><strong>CWA-Dienste</strong>“), die + der Nutzung weiterer Dienste („<strong>CWA-Dienste</strong>“), die derzeit oder zukünftig vom RKI im Zusammenhang mit der App bereitgestellt werden. Sie können diese Nutzungsbedingungen jederzeit in der App unter diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/BugCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/BugCensor.kt index 48c13a4a73e9de887be0621f210e447c91dd8759..57cf1c85a0c790057a9d3e42facd9ac3a955004d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/BugCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/BugCensor.kt @@ -1,15 +1,47 @@ package de.rki.coronawarnapp.bugreporting.censors -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import kotlin.math.max +import kotlin.math.min interface BugCensor { /** * If there is something to censor a new log line is returned, otherwise returns null */ - suspend fun checkLog(entry: LogLine): LogLine? + suspend fun checkLog(message: String): CensoredString? + + data class CensoredString( + // The censored version of the string + val string: String, + // The range that we censored + // If there is a collision, this range in the original needs to be removed. + val range: IntRange? = null + ) companion object { + operator fun CensoredString.plus(newer: CensoredString?): CensoredString { + if (newer == null) return this + + val range = when { + newer.range == null -> this.range + this.range == null -> newer.range + else -> min(this.range.first, newer.range.first)..max(this.range.last, newer.range.last) + } + + return CensoredString(string = newer.string, range = range) + } + + fun CensoredString.censor(orig: String, replacement: String): CensoredString? { + val start = this.string.indexOf(orig) + if (start == -1) return null + + val end = start + orig.length + return CensoredString( + string = this.string.replace(orig, replacement), + range = start..end + ) + } + fun withValidName(name: String?, action: (String) -> Unit): Boolean { if (name.isNullOrBlank()) return false if (name.length < 3) return false @@ -66,8 +98,8 @@ interface BugCensor { return true } - fun LogLine.toNewLogLineIfDifferent(newMessage: String): LogLine? { - return if (newMessage != message) copy(message = newMessage) else null + fun CensoredString.toNullIfUnmodified(): CensoredString? { + return if (range == null) null else this } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryEncounterCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryEncounterCensor.kt index 9c75a723f8df9d5ff4cc8caa8c6efd13e75ecb3b..63c6cfc428590001c989c606794e555ffab87f9f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryEncounterCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryEncounterCensor.kt @@ -2,16 +2,19 @@ package de.rki.coronawarnapp.bugreporting.censors.contactdiary import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidComment -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPersonEncounter import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable @@ -20,29 +23,31 @@ class DiaryEncounterCensor @Inject constructor( diary: ContactDiaryRepository ) : BugCensor { - private val encounters by lazy { - diary.personEncounters.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() + // We keep a history of all encounters so that we can censor them even after they got deleted + private val encounterHistory = mutableSetOf<ContactDiaryPersonEncounter>() + + val mutex = Mutex() + + init { + diary.personEncounters + .onEach { mutex.withLock { encounterHistory.addAll(it) } } + .launchIn(debugScope) } - override suspend fun checkLog(entry: LogLine): LogLine? { - val encountersNow = encounters.first().filter { !it.circumstances.isNullOrBlank() } + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - if (encountersNow.isEmpty()) return null + if (encounterHistory.isEmpty()) return null - val newMessage = encountersNow.fold(entry.message) { orig, encounter -> + val newMessage = encounterHistory.fold(CensoredString(message)) { orig, encounter -> var wip = orig withValidComment(encounter.circumstances) { - wip = wip.replace(it, "Encounter#${encounter.id}/Circumstances") + wip += wip.censor(it, "Encounter#${encounter.id}/Circumstances") } wip } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryLocationCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryLocationCensor.kt index 70628444cbaa4ed279be2e03adc54bb37bbc6c1e..e1439a50c1469658f2c81a10b3252a274ffe32eb 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryLocationCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryLocationCensor.kt @@ -2,18 +2,21 @@ package de.rki.coronawarnapp.bugreporting.censors.contactdiary import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidEmail import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidPhoneNumber -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocation import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable @@ -22,35 +25,36 @@ class DiaryLocationCensor @Inject constructor( diary: ContactDiaryRepository ) : BugCensor { - private val locations by lazy { - diary.locations.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() + private val mutex = Mutex() + + private var locationHistory = mutableSetOf<ContactDiaryLocation>() + + init { + diary.locations + .onEach { mutex.withLock { locationHistory.addAll(it) } } + .launchIn(debugScope) } - override suspend fun checkLog(entry: LogLine): LogLine? { - val locationsNow = locations.first() + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - if (locationsNow.isEmpty()) return null + if (locationHistory.isEmpty()) return null - val newMessage = locationsNow.fold(entry.message) { orig, location -> + val newMessage = locationHistory.fold(CensoredString(message)) { orig, location -> var wip = orig withValidName(location.locationName) { - wip = wip.replace(it, "Location#${location.locationId}/Name") + wip += wip.censor(it, "Location#${location.locationId}/Name") } withValidEmail(location.emailAddress) { - wip = wip.replace(it, "Location#${location.locationId}/EMail") + wip += wip.censor(it, "Location#${location.locationId}/EMail") } withValidPhoneNumber(location.phoneNumber) { - wip = wip.replace(it, "Location#${location.locationId}/PhoneNumber") + wip += wip.censor(it, "Location#${location.locationId}/PhoneNumber") } wip } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryPersonCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryPersonCensor.kt index a8a0056d95bc5027c1f79e3d4d3e0451cd0b41a7..52f542fc4350aa8bf218879148294e4134b3a250 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryPersonCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryPersonCensor.kt @@ -2,18 +2,21 @@ package de.rki.coronawarnapp.bugreporting.censors.contactdiary import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidEmail import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidPhoneNumber -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPerson import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable @@ -22,35 +25,37 @@ class DiaryPersonCensor @Inject constructor( diary: ContactDiaryRepository ) : BugCensor { - private val persons by lazy { - diary.people.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() + private val mutex = Mutex() + + // We keep a history of all persons so that we can censor them even after they got deleted + private val personHistory = mutableSetOf<ContactDiaryPerson>() + + init { + diary.people + .onEach { mutex.withLock { personHistory.addAll(it) } } + .launchIn(debugScope) } - override suspend fun checkLog(entry: LogLine): LogLine? { - val personsNow = persons.first() + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - if (personsNow.isEmpty()) return null + if (personHistory.isEmpty()) return null - val newMessage = personsNow.fold(entry.message) { orig, person -> + val newMessage = personHistory.fold(CensoredString(message)) { orig, person -> var wip = orig withValidName(person.fullName) { - wip = wip.replace(it, "Person#${person.personId}/Name") + wip += wip.censor(it, "Person#${person.personId}/Name") } withValidEmail(person.emailAddress) { - wip = wip.replace(it, "Person#${person.personId}/EMail") + wip += wip.censor(it, "Person#${person.personId}/EMail") } withValidPhoneNumber(person.phoneNumber) { - wip = wip.replace(it, "Person#${person.personId}/PhoneNumber") + wip += wip.censor(it, "Person#${person.personId}/PhoneNumber") } wip } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryVisitCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryVisitCensor.kt index f060c0fd2d49e2e415664e3dac90ad56937bbef5..f08bfc69db37440967acd31172e5ce0c4f7275bc 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryVisitCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryVisitCensor.kt @@ -2,15 +2,18 @@ package de.rki.coronawarnapp.bugreporting.censors.contactdiary import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocationVisit import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable @@ -19,29 +22,35 @@ class DiaryVisitCensor @Inject constructor( diary: ContactDiaryRepository ) : BugCensor { - private val visits by lazy { - diary.locationVisits.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() + private val mutex = Mutex() + + private val visitsHistory = mutableSetOf<ContactDiaryLocationVisit>() + + init { + diary.locationVisits + .onEach { locationVisitList -> + val visitsWithCircumstances = locationVisitList.filterNot { it.circumstances.isNullOrBlank() } + mutex.withLock { + visitsHistory.addAll(visitsWithCircumstances) + } + } + .launchIn(debugScope) } - override suspend fun checkLog(entry: LogLine): LogLine? { - val visitsNow = visits.first().filter { !it.circumstances.isNullOrBlank() } + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - if (visitsNow.isEmpty()) return null + if (visitsHistory.isEmpty()) return null - val newMessage = visitsNow.fold(entry.message) { orig, visit -> + val newMessage = visitsHistory.fold(CensoredString(message)) { orig, visit -> var wip = orig BugCensor.withValidComment(visit.circumstances) { - wip = wip.replace(it, "Visit#${visit.id}/Circumstances") + wip += wip.censor(it, "Visit#${visit.id}/Circumstances") } wip } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/CheckInsCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/CheckInsCensor.kt index a5f10d81cb24ca19dbf32068e6e878b557ac84e0..7cbede14a180730ca3d2f45efe804039bb737dbf 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/CheckInsCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/CheckInsCensor.kt @@ -2,54 +2,57 @@ package de.rki.coronawarnapp.bugreporting.censors.presencetracing import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidAddress import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidDescription -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.presencetracing.checkins.CheckIn import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable class CheckInsCensor @Inject constructor( @DebuggerScope debugScope: CoroutineScope, - private val checkInRepository: CheckInRepository + checkInRepository: CheckInRepository ) : BugCensor { - private val checkInsFlow by lazy { - checkInRepository.allCheckIns.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() - } + private val mutex = Mutex() + + private val checkInsHistory = mutableSetOf<CheckIn>() - override suspend fun checkLog(entry: LogLine): LogLine? { + init { + checkInRepository.allCheckIns + .onEach { mutex.withLock { checkInsHistory.addAll(it) } } + .launchIn(debugScope) + } - val checkIns = checkInsFlow.first() + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - if (checkIns.isEmpty()) return null + if (checkInsHistory.isEmpty()) return null - val newLogMsg = checkIns.fold(entry.message) { initial, checkIn -> + val newLogMsg = checkInsHistory.fold(CensoredString(message)) { initial, checkIn -> var acc = initial withValidDescription(checkIn.description) { description -> - acc = acc.replace(description, "CheckIn#${checkIn.id}/Description") + acc += acc.censor(description, "CheckIn#${checkIn.id}/Description") } withValidAddress(checkIn.address) { address -> - acc = acc.replace(address, "CheckIn#${checkIn.id}/Address") + acc += acc.censor(address, "CheckIn#${checkIn.id}/Address") } acc } - return entry.toNewLogLineIfDifferent(newLogMsg) + return newLogMsg.toNullIfUnmodified() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/TraceLocationCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/TraceLocationCensor.kt index 6d3f60ffb8bf2bc8dc61612b9722a9fc67fac64b..cae77e40731e632bc380e509a64293bfd028006c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/TraceLocationCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/TraceLocationCensor.kt @@ -2,24 +2,27 @@ package de.rki.coronawarnapp.bugreporting.censors.presencetracing import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidAddress import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidDescription -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.presencetracing.locations.TraceLocationUserInput import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject /** * Censors Trace Location Data * - * The information about which data to censor comes from two places + * The information about what data to censor comes from two places * - traceLocationRepository, for traceLocations that are already stored * - dataToCensor, which is set before a traceLocation is created; this is needed in cases when the app crashes between * data input and storing @@ -27,32 +30,32 @@ import javax.inject.Inject @Reusable class TraceLocationCensor @Inject constructor( @DebuggerScope debugScope: CoroutineScope, - private val traceLocationRepository: TraceLocationRepository + traceLocationRepository: TraceLocationRepository ) : BugCensor { - private val traceLocationsFlow by lazy { - traceLocationRepository.allTraceLocations.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() - } + private val mutex = Mutex() + + private val traceLocationHistory = mutableSetOf<TraceLocation>() - override suspend fun checkLog(entry: LogLine): LogLine? { + init { + traceLocationRepository.allTraceLocations + .onEach { mutex.withLock { traceLocationHistory.addAll(it) } } + .launchIn(debugScope) + } - val traceLocations = traceLocationsFlow.first() + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - var newLogMsg = traceLocations.fold(entry.message) { initial, traceLocation -> + var newLogMsg = traceLocationHistory.fold(CensoredString(message)) { initial, traceLocation -> var acc = initial - acc = acc.replace(traceLocation.type.name, "TraceLocation#${traceLocation.id}/Type") + acc += acc.censor(traceLocation.type.name, "TraceLocation#${traceLocation.id}/Type") withValidDescription(traceLocation.description) { description -> - acc = acc.replace(description, "TraceLocation#${traceLocation.id}/Description") + acc += acc.censor(description, "TraceLocation#${traceLocation.id}/Description") } withValidAddress(traceLocation.address) { address -> - acc = acc.replace(address, "TraceLocation#${traceLocation.id}/Address") + acc += acc.censor(address, "TraceLocation#${traceLocation.id}/Address") } acc @@ -60,18 +63,18 @@ class TraceLocationCensor @Inject constructor( val inputDataToCensor = dataToCensor if (inputDataToCensor != null) { - newLogMsg = newLogMsg.replace(inputDataToCensor.type.name, "TraceLocationUserInput#Type") + newLogMsg += newLogMsg.censor(inputDataToCensor.type.name, "TraceLocationUserInput#Type") withValidDescription(inputDataToCensor.description) { - newLogMsg = newLogMsg.replace(inputDataToCensor.description, "TraceLocationUserInput#Description") + newLogMsg += newLogMsg.censor(inputDataToCensor.description, "TraceLocationUserInput#Description") } withValidAddress(inputDataToCensor.address) { - newLogMsg = newLogMsg.replace(inputDataToCensor.address, "TraceLocationUserInput#Address") + newLogMsg += newLogMsg.censor(inputDataToCensor.address, "TraceLocationUserInput#Address") } } - return entry.toNewLogLineIfDifferent(newLogMsg) + return newLogMsg.toNullIfUnmodified() } companion object { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/CoronaTestCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/CoronaTestCensor.kt index 8958fe2908a31347a0f318fe3f968051c337e231..ea9d31a4fc46d6a0d37b76ab9c6e97721d9fc676 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/CoronaTestCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/CoronaTestCensor.kt @@ -2,44 +2,61 @@ package de.rki.coronawarnapp.bugreporting.censors.submission import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified +import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.coronatest.CoronaTestRepository -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable class CoronaTestCensor @Inject constructor( - private val coronaTestRepository: CoronaTestRepository, + @DebuggerScope debugScope: CoroutineScope, + coronaTestRepository: CoronaTestRepository, ) : BugCensor { + private val mutex = Mutex() + // Keep a history to have references even after the user deletes a test private val tokenHistory = mutableSetOf<String>() private val identifierHistory = mutableSetOf<String>() - override suspend fun checkLog(entry: LogLine): LogLine? { + init { + coronaTestRepository.coronaTests + .filterNotNull() + .onEach { tests -> + mutex.withLock { + // The Registration Token is received after registration of PCR and RAT tests. It is required to poll the test result. + tokenHistory.addAll(tests.map { it.registrationToken }) + identifierHistory.addAll(tests.map { it.identifier }) + } + }.launchIn(debugScope) + } - // The Registration Token is received after registration of PCR and RAT tests. It is required to poll the test result. - val tokens = coronaTestRepository.coronaTests.first().map { it.registrationToken } - tokenHistory.addAll(tokens) + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - val identifiers = coronaTestRepository.coronaTests.first().map { it.identifier } - identifierHistory.addAll(identifiers) + var newMessage = CensoredString(message) - var newMessage = entry.message for (token in tokenHistory) { - if (!entry.message.contains(token)) continue + if (!message.contains(token)) continue - newMessage = newMessage.replace(token, PLACEHOLDER + token.takeLast(4)) + newMessage += newMessage.censor(token, PLACEHOLDER + token.takeLast(4)) } identifierHistory - .filter { entry.message.contains(it) } + .filter { message.contains(it) } .forEach { - newMessage = newMessage.replace(it, "${it.take(11)}CoronaTest/Identifier") + newMessage += newMessage.censor(it, "${it.take(11)}CoronaTest/Identifier") } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } companion object { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrQrCodeCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrQrCodeCensor.kt index 881a5396fd56cbac04e76333bd07e74a8c139ce5..0c61dd0ca84a9d834f5d03e7d704b909464f41be 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrQrCodeCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrQrCodeCensor.kt @@ -2,21 +2,18 @@ package de.rki.coronawarnapp.bugreporting.censors.submission import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor import javax.inject.Inject @Reusable class PcrQrCodeCensor @Inject constructor() : BugCensor { - override suspend fun checkLog(entry: LogLine): LogLine? { - + override suspend fun checkLog(message: String): CensoredString? { val guid = lastGUID ?: return null - if (!entry.message.contains(guid)) return null - - val newMessage = entry.message.replace(guid, PLACEHOLDER + guid.takeLast(4)) + if (!message.contains(guid)) return null - return entry.toNewLogLineIfDifferent(newMessage) + return CensoredString(message).censor(guid, PLACEHOLDER + guid.takeLast(4)) } companion object { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RACoronaTestCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RACoronaTestCensor.kt index 38c06dca4ae6ed269f293e30b47948baeae28467..b2eff318663524e5953a18989ece304814901b87 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RACoronaTestCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RACoronaTestCensor.kt @@ -1,57 +1,61 @@ package de.rki.coronawarnapp.bugreporting.censors.submission import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.coronatest.CoronaTestRepository import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.joda.time.format.DateTimeFormat import javax.inject.Inject class RACoronaTestCensor @Inject constructor( @DebuggerScope debugScope: CoroutineScope, - private val coronaTestRepository: CoronaTestRepository + coronaTestRepository: CoronaTestRepository ) : BugCensor { + private val mutex = Mutex() + private val dayOfBirthFormatter = DateTimeFormat.forPattern("yyyy-MM-dd") - private val coronaTestFlow by lazy { - coronaTestRepository.coronaTests.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() - } + // We keep a history of rat corona test so that we are able to censor even after they got deleted + private val ratCoronaTestHistory = mutableSetOf<RACoronaTest>() - override suspend fun checkLog(entry: LogLine): LogLine? { + init { + coronaTestRepository + .coronaTests + .map { it.filterIsInstance<RACoronaTest>() } + .onEach { mutex.withLock { ratCoronaTestHistory.addAll(it) } } + .launchIn(debugScope) + } - val raCoronaTestFlow = coronaTestFlow.map { tests -> tests.filterIsInstance<RACoronaTest>() }.first() - val raCoronaTest = raCoronaTestFlow.firstOrNull() ?: return null + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - var newMessage = entry.message + var newMessage = CensoredString(message) - with(raCoronaTest) { - withValidName(firstName) { firstName -> - newMessage = newMessage.replace(firstName, "RATest/FirstName") + ratCoronaTestHistory.forEach { ratCoronaTest -> + withValidName(ratCoronaTest.firstName) { firstName -> + newMessage += newMessage.censor(firstName, "RATest/FirstName") } - withValidName(lastName) { lastName -> - newMessage = newMessage.replace(lastName, "RATest/LastName") + withValidName(ratCoronaTest.lastName) { lastName -> + newMessage += newMessage.censor(lastName, "RATest/LastName") } - val dateOfBirthString = dateOfBirth?.toString(dayOfBirthFormatter) ?: return@with - - newMessage = newMessage.replace(dateOfBirthString, "RATest/DateOfBirth") + ratCoronaTest.dateOfBirth?.toString(dayOfBirthFormatter)?.let { dateOfBirthString -> + newMessage += newMessage.censor(dateOfBirthString, "RATest/DateOfBirth") + } } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensor.kt index fa1e919bbeeccadfded6038b795001cee462cf34..b33838de51adbb046dd41a1e8b562279bd933e4c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensor.kt @@ -1,16 +1,20 @@ package de.rki.coronawarnapp.bugreporting.censors.submission import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidAddress import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidCity import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidPhoneNumber import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidZipCode -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfile import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfileSettings import kotlinx.coroutines.flow.first +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.joda.time.format.DateTimeFormat import javax.inject.Inject @@ -18,10 +22,11 @@ class RatProfileCensor @Inject constructor( private val ratProfileSettings: RATProfileSettings ) : BugCensor { + private val mutex = Mutex() private val dayOfBirthFormatter = DateTimeFormat.forPattern("yyyy-MM-dd") private val ratProfileHistory = mutableSetOf<RATProfile>() - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { val ratProfile = ratProfileSettings.profile.flow.first() // store the profile in a property so we still have a reference after it was deleted by the user @@ -29,46 +34,46 @@ class RatProfileCensor @Inject constructor( ratProfileHistory.add(ratProfile) } - var newMessage = entry.message + var newMessage = CensoredString(message) ratProfileHistory.forEach { profile -> with(profile) { withValidName(firstName) { firstName -> - newMessage = newMessage.replace(firstName, "RAT-Profile/FirstName") + newMessage += newMessage.censor(firstName, "RAT-Profile/FirstName") } withValidName(lastName) { lastName -> - newMessage = newMessage.replace(lastName, "RAT-Profile/LastName") + newMessage += newMessage.censor(lastName, "RAT-Profile/LastName") } val dateOfBirthString = birthDate?.toString(dayOfBirthFormatter) if (dateOfBirthString != null) { - newMessage = newMessage.replace(dateOfBirthString, "RAT-Profile/DateOfBirth") + newMessage += newMessage.censor(dateOfBirthString, "RAT-Profile/DateOfBirth") } withValidAddress(street) { street -> - newMessage = newMessage.replace(street, "RAT-Profile/Street") + newMessage += newMessage.censor(street, "RAT-Profile/Street") } withValidCity(city) { city -> - newMessage = newMessage.replace(city, "RAT-Profile/City") + newMessage += newMessage.censor(city, "RAT-Profile/City") } withValidZipCode(zipCode) { zipCode -> - newMessage = newMessage.replace(zipCode, "RAT-Profile/Zip-Code") + newMessage += newMessage.censor(zipCode, "RAT-Profile/Zip-Code") } withValidPhoneNumber(phone) { phone -> - newMessage = newMessage.replace(phone, "RAT-Profile/Phone") + newMessage += newMessage.censor(phone, "RAT-Profile/Phone") } withValidPhoneNumber(email) { phone -> - newMessage = newMessage.replace(phone, "RAT-Profile/eMail") + newMessage += newMessage.censor(phone, "RAT-Profile/eMail") } } } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatQrCodeCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatQrCodeCensor.kt index 29a9c1fa5ee6fbcefa2170f568939e061b367745..f7537dc8d751be536cbe5c142729b7ac92be9e04 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatQrCodeCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatQrCodeCensor.kt @@ -2,9 +2,11 @@ package de.rki.coronawarnapp.bugreporting.censors.submission import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.coronatest.qrcode.RapidAntigenHash import org.joda.time.LocalDate import org.joda.time.format.DateTimeFormat @@ -15,31 +17,31 @@ class RatQrCodeCensor @Inject constructor() : BugCensor { private val dayOfBirthFormatter = DateTimeFormat.forPattern("yyyy-MM-dd") - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? { val dataToCensor = dataToCensor ?: return null - var newMessage = entry.message + var newMessage = CensoredString(message) with(dataToCensor) { - newMessage = newMessage.replace(rawString, "RatQrCode/ScannedRawString") + newMessage += newMessage.censor(rawString, "RatQrCode/ScannedRawString") - newMessage = newMessage.replace(hash, PLACEHOLDER + hash.takeLast(4)) + newMessage += newMessage.censor(hash, PLACEHOLDER + hash.takeLast(4)) withValidName(firstName) { firstName -> - newMessage = newMessage.replace(firstName, "RATest/FirstName") + newMessage += newMessage.censor(firstName, "RATest/FirstName") } withValidName(lastName) { lastName -> - newMessage = newMessage.replace(lastName, "RATest/LastName") + newMessage += newMessage.censor(lastName, "RATest/LastName") } val dateOfBirthString = dateOfBirth?.toString(dayOfBirthFormatter) ?: return@with - newMessage = newMessage.replace(dateOfBirthString, "RATest/DateOfBirth") + newMessage += newMessage.censor(dateOfBirthString, "RATest/DateOfBirth") } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } companion object { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt index b3de1ea4f938ebcb8e7b4f2287702d5a50a4072c..3b1dbda24086b9ab568cc128e2d36c44ce7b9ea6 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt @@ -2,8 +2,10 @@ package de.rki.coronawarnapp.bugreporting.censors.vaccination import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1 import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData import java.util.LinkedList @@ -12,86 +14,83 @@ import javax.inject.Inject @Reusable class CertificateQrCodeCensor @Inject constructor() : BugCensor { - override suspend fun checkLog(entry: LogLine): LogLine? { - var newMessage = entry.message + override suspend fun checkLog(message: String): CensoredString? { + var newMessage = CensoredString(message) synchronized(qrCodeStringsToCensor) { qrCodeStringsToCensor.toList() }.forEach { - newMessage = newMessage.replace( - it, - PLACEHOLDER + it.takeLast(4) - ) + newMessage += newMessage.censor(it, PLACEHOLDER + it.takeLast(4)) } synchronized(certsToCensor) { certsToCensor.toList() }.forEach { it.certificate.apply { - newMessage = newMessage.replace( + newMessage += newMessage.censor( dob, "vaccinationCertificate/dob" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( dateOfBirth.toString(), "vaccinationCertificate/dateOfBirth" ) - newMessage = censorNameData(nameData, newMessage) + newMessage += censorNameData(nameData, newMessage) vaccinationDatas.forEach { data -> - newMessage = censorVaccinationData(data, newMessage) + newMessage += censorVaccinationData(data, newMessage) } } } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } private fun censorVaccinationData( vaccinationData: VaccinationDGCV1.VaccinationData, - message: String - ): String { + message: CensoredString + ): CensoredString { var newMessage = message - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.dt, "vaccinationData/dt" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.marketAuthorizationHolderId, "vaccinationData/marketAuthorizationHolderId" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.medicalProductId, "vaccinationData/medicalProductId" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.targetId, "vaccinationData/targetId" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.certificateIssuer, "vaccinationData/certificateIssuer" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.uniqueCertificateIdentifier, "vaccinationData/uniqueCertificateIdentifier" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.countryOfVaccination, "vaccinationData/countryOfVaccination" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.vaccineId, "vaccinationData/vaccineId" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.vaccinatedAt.toString(), "vaccinationData/vaccinatedAt" ) @@ -99,30 +98,30 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor { return newMessage } - private fun censorNameData(nameData: VaccinationDGCV1.NameData, message: String): String { + private fun censorNameData(nameData: VaccinationDGCV1.NameData, message: CensoredString): CensoredString { var newMessage = message nameData.familyName?.let { fName -> - newMessage = newMessage.replace( + newMessage += newMessage.censor( fName, "nameData/familyName" ) } - newMessage = newMessage.replace( + newMessage += newMessage.censor( nameData.familyNameStandardized, "nameData/familyNameStandardized" ) nameData.givenName?.let { gName -> - newMessage = newMessage.replace( + newMessage += newMessage.censor( gName, "nameData/givenName" ) } nameData.givenNameStandardized?.let { gName -> - newMessage = newMessage.replace( + newMessage += newMessage.censor( gName, "nameData/givenNameStandardized" ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt index 698f5b68c658e6a27e39089550f8c42b1997ab8b..5fe3b904e97c3f904edd6370aca2ddd76a2f9619 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt @@ -3,6 +3,7 @@ package de.rki.coronawarnapp.bugreporting.debuglog import android.annotation.SuppressLint import android.content.Context import android.util.Log +import de.rki.coronawarnapp.bugreporting.censors.BugCensor import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLogStorageCheck import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLogTree import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLoggerScope @@ -12,6 +13,8 @@ import de.rki.coronawarnapp.util.di.ApplicationComponent import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -160,10 +163,28 @@ class DebugLogger( launch { // Censor data sources need a moment to know what to censor delay(1000) - val censoredLine = bugCensors.get().fold(rawLine) { prev, censor -> - censor.checkLog(prev) ?: prev + + val formattedMessage = rawLine.format() + val censored: Collection<BugCensor.CensoredString> = bugCensors.get() + .map { + async { + it.checkLog(formattedMessage) + } + } + .awaitAll() + .filterNotNull() + .filter { it.range != null } + + val toWrite: String = when (censored.size) { + 0 -> formattedMessage + 1 -> censored.single().string + else -> { + val minMin = censored.minOf { it.range!!.first } + val maxMax = censored.maxOf { it.range!!.last } + formattedMessage.replaceRange(minMin, maxMax, CENSOR_COLLISION_PLACERHOLDER) + } } - logWriter.write(censoredLine) + logWriter.write(toWrite) } } } catch (e: CancellationException) { @@ -174,6 +195,7 @@ class DebugLogger( } companion object { + private const val CENSOR_COLLISION_PLACERHOLDER = "<censoring-collision>" internal const val TAG = "DebugLogger" } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLine.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLine.kt index defe6c2c2c9adb8ea2ab8ab01c6983a59ecc730d..67664ffba0c2b20d6837378e1a6825252817953d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLine.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLine.kt @@ -2,6 +2,8 @@ package de.rki.coronawarnapp.bugreporting.debuglog import android.util.Log import org.joda.time.Instant +import java.io.PrintWriter +import java.io.StringWriter data class LogLine( val timestamp: Long, @@ -13,15 +15,33 @@ data class LogLine( fun format(): String { val time = Instant.ofEpochMilli(timestamp) - return "$time ${priorityLabel(priority)}/$tag: $message\n" + + val baseLine = "$time ${priorityLabel(priority)}/$tag: $message" + + return if (throwable != null) { + baseLine + "\n" + getStackTraceString(throwable) + } else { + baseLine + } } - private fun priorityLabel(priority: Int): String = when (priority) { - Log.ERROR -> "E" - Log.WARN -> "W" - Log.INFO -> "I" - Log.DEBUG -> "D" - Log.VERBOSE -> "V" - else -> priority.toString() + companion object { + // Based on Timber.Tree.getStackTraceString() + internal fun getStackTraceString(t: Throwable): String { + val sw = StringWriter(256) + val pw = PrintWriter(sw, false) + t.printStackTrace(pw) + pw.flush() + return sw.toString() + } + + internal fun priorityLabel(priority: Int): String = when (priority) { + Log.ERROR -> "E" + Log.WARN -> "W" + Log.INFO -> "I" + Log.DEBUG -> "D" + Log.VERBOSE -> "V" + else -> priority.toString() + } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheck.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheck.kt index 113ffeb5b92334209ae19aff6930deaf75e63c9b..1b9298774aca0547cee15424122400728053aa00 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheck.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheck.kt @@ -30,7 +30,7 @@ class DebugLogStorageCheck @Inject constructor( return eval.usableSpace } - fun isLowStorage(forceCheck: Boolean = false): Boolean { + suspend fun isLowStorage(forceCheck: Boolean = false): Boolean { val now = timeProvider() if (!forceCheck && now - lastCheckAt < 5_000) return isLowStorage.value @@ -64,23 +64,23 @@ class DebugLogStorageCheck @Inject constructor( companion object { private const val TAG = DebugLogger.TAG - private val createStorageCheckErrorLine: (Throwable) -> LogLine = { + private val createStorageCheckErrorLine: (Throwable) -> String = { LogLine( timestamp = System.currentTimeMillis(), priority = Log.ERROR, tag = TAG, message = "Low storage check failed.", throwable = it - ) + ).format() } - private val createLowStorageLogLine: () -> LogLine = { + private val createLowStorageLogLine: () -> String = { LogLine( timestamp = System.currentTimeMillis(), priority = Log.WARN, tag = TAG, message = "Low storage, debug logger halted.", throwable = null - ) + ).format() } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLoggerScope.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLoggerScope.kt index 9e60dc67be1c4e384fe51ab05f5b545aabd8625b..77c72ec18a05f9871d62aa3bdb2b73641ae6a22e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLoggerScope.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLoggerScope.kt @@ -9,7 +9,8 @@ import javax.inject.Qualifier import kotlin.coroutines.CoroutineContext object DebugLoggerScope : CoroutineScope { - val dispatcher = Executors.newSingleThreadExecutor( + val dispatcher = Executors.newFixedThreadPool( + 4, NamedThreadFactory("DebugLogger") ).asCoroutineDispatcher() override val coroutineContext: CoroutineContext = SupervisorJob() + dispatcher diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriter.kt index ebb188567e11bf2a885afb9d35f2018ce6cbb09d..992f86be6ca9818e85c56c32d437a08a22ca0f81 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriter.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriter.kt @@ -1,20 +1,27 @@ package de.rki.coronawarnapp.bugreporting.debuglog.internal -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import android.annotation.SuppressLint +import android.util.Log import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import timber.log.Timber import java.io.File +import java.io.FileNotFoundException import javax.inject.Inject +@Suppress("BlockingMethodInNonBlockingContext") +@SuppressLint("LogNotTimber") class LogWriter @Inject constructor(val logFile: File) { private var ioLimiter = 0 + private val mutex = Mutex() val logSize = MutableStateFlow(logFile.length()) private fun updateLogSize() { logSize.value = logFile.length() } - fun setup() { + suspend fun setup() = mutex.withLock { if (!logFile.exists()) { logFile.parentFile?.mkdirs() if (logFile.createNewFile()) { @@ -24,16 +31,36 @@ class LogWriter @Inject constructor(val logFile: File) { updateLogSize() } - fun teardown() { + suspend fun teardown() = mutex.withLock { if (logFile.exists() && logFile.delete()) { Timber.d("Log file was deleted.") } updateLogSize() } - fun write(line: LogLine) { - val formattedLine = line.format() - logFile.appendText(formattedLine, Charsets.UTF_8) + suspend fun write(formattedLine: String): Unit = mutex.withLock { + val performWrite = { + logFile.appendText(formattedLine + "\n", Charsets.UTF_8) + } + + try { + performWrite() + } catch (e: FileNotFoundException) { + Log.e(TAG, "Log file didn't exist when we tried to write, retry.") + + try { + logFile.parentFile?.mkdirs() + logFile.createNewFile() + logFile.writeText("Logfile was deleted.\n") + + performWrite() + + updateLogSize() + } catch (e: Exception) { + Log.e(TAG, "LogWrite retry failed, something is just wrong...", e) + return@withLock + } + } if (ioLimiter % 10 == 0) { updateLogSize() @@ -41,4 +68,8 @@ class LogWriter @Inject constructor(val logFile: File) { } ioLimiter++ } + + companion object { + private const val TAG = "LogWriter" + } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deadman/DeadmanNotificationTimeCalculation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deadman/DeadmanNotificationTimeCalculation.kt index a7820554419bb452b385378f8df864c85bdd6c74..de21b1095ef5aff1db73aca0b8f31abd7b3ebcc5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deadman/DeadmanNotificationTimeCalculation.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/deadman/DeadmanNotificationTimeCalculation.kt @@ -1,7 +1,8 @@ package de.rki.coronawarnapp.deadman import dagger.Reusable -import de.rki.coronawarnapp.nearby.ENFClient +import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository +import de.rki.coronawarnapp.diagnosiskeys.storage.pkgDateTime import de.rki.coronawarnapp.util.TimeStamper import kotlinx.coroutines.flow.first import org.joda.time.DateTimeConstants @@ -12,8 +13,8 @@ import javax.inject.Inject @Reusable class DeadmanNotificationTimeCalculation @Inject constructor( - val timeStamper: TimeStamper, - val enfClient: ENFClient + private val timeStamper: TimeStamper, + private val keyCacheRepository: KeyCacheRepository, ) { /** @@ -29,10 +30,15 @@ class DeadmanNotificationTimeCalculation @Inject constructor( * If last success date time is null (eg: on application first start) - return [DEADMAN_NOTIFICATION_DELAY] */ suspend fun getDelay(): Long { - val lastSuccess = enfClient.lastSuccessfulTrackedExposureDetection().first()?.finishedAt - Timber.d("enfClient.lastSuccessfulTrackedExposureDetection: $lastSuccess") + val lastSuccess = keyCacheRepository.allCachedKeys() + .first() + .filter { it.info.isDownloadComplete } + .maxByOrNull { it.info.pkgDateTime } + ?.info + + Timber.d("Last successful diagnosis key package download: $lastSuccess") return if (lastSuccess != null) { - getHoursDiff(lastSuccess).toLong() + getHoursDiff(lastSuccess.pkgDateTime.toInstant()).toLong() } else { (DEADMAN_NOTIFICATION_DELAY * DateTimeConstants.MINUTES_PER_HOUR).toLong() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DayPackageSyncTool.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DayPackageSyncTool.kt index 7598c00a60494d6a1aa01302570dd8a55df0691e..6744d5a6ab88955b2c2ce24a317bd6b1729cc575 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DayPackageSyncTool.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/DayPackageSyncTool.kt @@ -9,6 +9,7 @@ import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKey import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo.Type import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository +import de.rki.coronawarnapp.diagnosiskeys.storage.pkgDateTime import de.rki.coronawarnapp.exception.http.CwaUnknownHostException import de.rki.coronawarnapp.storage.DeviceStorage import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc @@ -81,7 +82,7 @@ class DayPackageSyncTool @Inject constructor( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal fun expectNewDayPackages(cachedDays: List<CachedKey>): Boolean { val yesterday = timeStamper.nowUTC.toLocalDateUtc().minusDays(1) - val newestDay = cachedDays.map { it.info.toDateTime() }.maxOrNull()?.toLocalDate() + val newestDay = cachedDays.map { it.info.pkgDateTime }.maxOrNull()?.toLocalDate() return yesterday != newestDay } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/HourPackageSyncTool.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/HourPackageSyncTool.kt index caa3143bc4f03a53ba486f072c18d00f0fa2e42a..6a2c012621d604be3c5358a43e8467abf4ba5d77 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/HourPackageSyncTool.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/HourPackageSyncTool.kt @@ -9,6 +9,7 @@ import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKey import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo.Type import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository +import de.rki.coronawarnapp.diagnosiskeys.storage.pkgDateTime import de.rki.coronawarnapp.exception.http.CwaServerError import de.rki.coronawarnapp.exception.http.CwaUnknownHostException import de.rki.coronawarnapp.exception.http.NetworkConnectTimeoutException @@ -126,7 +127,7 @@ class HourPackageSyncTool @Inject constructor( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal fun expectNewHourPackages(cachedHours: List<CachedKey>, now: Instant): Boolean { val today = now.toDateTime(DateTimeZone.UTC) - val newestHour = cachedHours.map { it.info.toDateTime() }.maxOrNull() + val newestHour = cachedHours.map { it.info.pkgDateTime }.maxOrNull() return today.minusHours(1).hourOfDay != newestHour?.hourOfDay || today.toLocalDate() != newestHour.toLocalDate() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/CachedKeyInfo.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/CachedKeyInfo.kt index ada80369ada5f758a9748016f9439df216402f35..b7d7f395442ba80aa6e997f96c5403af01f19078 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/CachedKeyInfo.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/CachedKeyInfo.kt @@ -50,11 +50,6 @@ data class CachedKeyInfo( isDownloadComplete = true ) - fun toDateTime(): DateTime = when (type) { - Type.LOCATION_DAY -> day.toDateTimeAtStartOfDay(DateTimeZone.UTC) - Type.LOCATION_HOUR -> day.toDateTime(hour, DateTimeZone.UTC) - } - companion object { fun calcluateId( location: LocationCode, @@ -89,3 +84,9 @@ data class CachedKeyInfo( @ColumnInfo(name = "completed") val isDownloadComplete: Boolean ) } + +val CachedKeyInfo.pkgDateTime: DateTime + get() = when (type) { + CachedKeyInfo.Type.LOCATION_DAY -> day.toDateTimeAtStartOfDay(DateTimeZone.UTC) + CachedKeyInfo.Type.LOCATION_HOUR -> day.toDateTime(hour, DateTimeZone.UTC) + } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/TracingPermissionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/TracingPermissionHelper.kt index 1c3ad7c8c64bb948aa51c69a4c3123f1922673a4..02d31943e6f8e42ce586fea956bfcbef93414471 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/TracingPermissionHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/TracingPermissionHelper.kt @@ -54,7 +54,7 @@ class TracingPermissionHelper @AssistedInject constructor( fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { Timber.v( - "handleActivityResult(requesutCode=%d, resultCode=%d, data=%s)", + "handleActivityResult(requestCode=%d, resultCode=%d, data=%s)", requestCode, resultCode, data diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/qrcode/QrCodeGenerator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/qrcode/QrCodeGenerator.kt index d4645b71f6decac284bc3720cb37070a12ac63b6..bb024a2b955640bce47235c8105bc001b153d4e3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/qrcode/QrCodeGenerator.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/qrcode/QrCodeGenerator.kt @@ -8,15 +8,17 @@ import com.google.zxing.EncodeHintType import com.google.zxing.MultiFormatWriter import com.google.zxing.WriterException import com.google.zxing.common.BitMatrix +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import dagger.Reusable -import de.rki.coronawarnapp.appconfig.AppConfigProvider +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider import de.rki.coronawarnapp.util.di.AppContext +import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject @Reusable class QrCodeGenerator @Inject constructor( - private val appConfigProvider: AppConfigProvider, + private val dispatcherProvider: DispatcherProvider, @AppContext private val context: Context, ) { @@ -25,25 +27,29 @@ class QrCodeGenerator @Inject constructor( * @param input [String] * @param length [Int] QR Code side length * @param margin [Int] QR Code side's margin + * @param correctionLevel [ErrorCorrectionLevel] + * + * Note: we cannot use Charsets.UTF_8 as zxing calls toString internally and some android version + * return the class name and not the charset name + * @param characterSet [String] * * @throws [Exception] it could throw [IllegalArgumentException] , [WriterException] * or exception while creating the bitmap */ - suspend fun createQrCode(input: String, length: Int = 1000, margin: Int = 1): Bitmap { - val correctionLevel = appConfigProvider - .getAppConfig() - .presenceTracing - .qrCodeErrorCorrectionLevel + suspend fun createQrCode( + input: String, + length: Int = 1000, + margin: Int = 1, + correctionLevel: ErrorCorrectionLevel = ErrorCorrectionLevel.Q, + characterSet: String = Charsets.UTF_8.name() + ): Bitmap = withContext(dispatcherProvider.Default) { Timber.i("correctionLevel=$correctionLevel") - val hints = mapOf( EncodeHintType.ERROR_CORRECTION to correctionLevel, EncodeHintType.MARGIN to margin, - // we cannot use Charsets.UTF_8 as zxing calls toString internally and some android version - // return the class name and not the charset name - EncodeHintType.CHARACTER_SET to Charsets.UTF_8.name() + EncodeHintType.CHARACTER_SET to characterSet ) - return MultiFormatWriter().encode( + MultiFormatWriter().encode( input, BarcodeFormat.QR_CODE, length, diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt index 29b46a9ce6a242921afb35ad2a8d338b0f0ff577..086e9628888fab7c36afc2e48f7c4ddc29272fb2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelTask.kt @@ -7,6 +7,7 @@ import de.rki.coronawarnapp.appconfig.ExposureWindowRiskCalculationConfig import de.rki.coronawarnapp.coronatest.CoronaTestRepository import de.rki.coronawarnapp.datadonation.analytics.modules.exposurewindows.AnalyticsExposureWindowCollector import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository +import de.rki.coronawarnapp.diagnosiskeys.storage.pkgDateTime import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.reporting.report import de.rki.coronawarnapp.nearby.ENFClient @@ -125,14 +126,14 @@ class RiskLevelTask @Inject constructor( Timber.tag(TAG).d("Evaluating areKeyPkgsOutDated(nowUTC=%s)", nowUTC) val latestDownload = keyCacheRepository.getAllCachedKeys().maxByOrNull { - it.info.toDateTime() + it.info.pkgDateTime } if (latestDownload == null) { Timber.w("areKeyPkgsOutDated(): No downloads available, why is the RiskLevelTask running? Aborting!") return true } - val downloadAge = Duration(latestDownload.info.toDateTime(), nowUTC).also { + val downloadAge = Duration(latestDownload.info.pkgDateTime, nowUTC).also { Timber.d("areKeyPkgsOutDated(): Age is %dh for latest key package: %s", it.standardHours, latestDownload) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailFragment.kt index ee6f9e9bdcb47392f40db32fbeb99a23b408d74f..70758a13500e55607c746fe7347edd75573491c1 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailFragment.kt @@ -104,7 +104,7 @@ class QrCodeDetailFragment : Fragment(R.layout.trace_location_organizer_qr_code_ ) is QrCodeDetailNavigationEvents.NavigateToFullScreenQrCode -> findNavController().navigate( R.id.action_global_qrCodeFullScreenFragment, - QrCodeFullScreenFragmentArgs(it.qrcodeText).toBundle(), + QrCodeFullScreenFragmentArgs(it.qrcodeText, it.correctionLevel).toBundle(), null, FragmentNavigatorExtras(binding.qrCodeImage to binding.qrCodeImage.transitionName) ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailNavigationEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailNavigationEvents.kt index d2eafc3815ad1b80f656f5fcfd21c441fbac2efc..55dfb3917d29598c885bb32c455f10b12bffdb57 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailNavigationEvents.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailNavigationEvents.kt @@ -1,5 +1,6 @@ package de.rki.coronawarnapp.ui.presencetracing.organizer.details +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.ui.presencetracing.organizer.category.adapter.category.TraceLocationCategory @@ -9,5 +10,8 @@ sealed class QrCodeDetailNavigationEvents { data class NavigateToDuplicateFragment(val traceLocation: TraceLocation, val category: TraceLocationCategory) : QrCodeDetailNavigationEvents() - data class NavigateToFullScreenQrCode(val qrcodeText: String) : QrCodeDetailNavigationEvents() + data class NavigateToFullScreenQrCode( + val qrcodeText: String, + val correctionLevel: ErrorCorrectionLevel + ) : QrCodeDetailNavigationEvents() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailViewModel.kt index 50ac1f175e67ac785270d6b5b3d846a442e0f16f..747679e4f9ef387e99db6ba592e43344bb781e2e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.MutableLiveData import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.appconfig.AppConfigProvider import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository @@ -16,6 +17,7 @@ import de.rki.coronawarnapp.util.coroutine.DispatcherProvider import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import kotlinx.coroutines.flow.first import org.joda.time.Instant import timber.log.Timber import java.lang.Exception @@ -24,6 +26,7 @@ class QrCodeDetailViewModel @AssistedInject constructor( @Assisted private val traceLocationId: Long, private val dispatcher: DispatcherProvider, private val qrCodeGenerator: QrCodeGenerator, + private val appConfigProvider: AppConfigProvider, private val traceLocationRepository: TraceLocationRepository ) : CWAViewModel() { @@ -57,8 +60,17 @@ class QrCodeDetailViewModel @AssistedInject constructor( private fun createQrCode(traceLocation: TraceLocation) = launch(context = dispatcher.IO) { try { val input = traceLocation.locationUrl + val correctionLevel = appConfigProvider.currentConfig.first().presenceTracing.qrCodeErrorCorrectionLevel Timber.d("input=$input") - mutableUiState.postValue(UiState(traceLocation, qrCodeGenerator.createQrCode(input))) + mutableUiState.postValue( + UiState( + traceLocation, + qrCodeGenerator.createQrCode( + input = input, + correctionLevel = correctionLevel + ) + ) + ) } catch (e: Exception) { Timber.d(e, "Qr code creation failed") e.report(ExceptionCategory.INTERNAL) @@ -86,9 +98,15 @@ class QrCodeDetailViewModel @AssistedInject constructor( } } - fun openFullScreen() { + fun openFullScreen() = launch { traceLocation?.let { - routeToScreen.postValue(QrCodeDetailNavigationEvents.NavigateToFullScreenQrCode(it.locationUrl)) + val correctionLevel = appConfigProvider.currentConfig.first().presenceTracing.qrCodeErrorCorrectionLevel + routeToScreen.postValue( + QrCodeDetailNavigationEvents.NavigateToFullScreenQrCode( + it.locationUrl, + correctionLevel + ) + ) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterViewModel.kt index 4f903050f79ca8c91daa2885f382f8ff21f1fd2e..0c9f19cd9ad8a0448aef2469cc34a4f31dc1a917 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterViewModel.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.appconfig.AppConfigProvider import de.rki.coronawarnapp.presencetracing.checkins.qrcode.PosterTemplateProvider import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator import de.rki.coronawarnapp.presencetracing.checkins.qrcode.Template @@ -19,6 +20,7 @@ import de.rki.coronawarnapp.util.files.FileSharing import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import kotlinx.coroutines.flow.first import timber.log.Timber import java.io.File import java.io.FileOutputStream @@ -30,6 +32,7 @@ class QrCodePosterViewModel @AssistedInject constructor( private val qrCodeGenerator: QrCodeGenerator, private val posterTemplateProvider: PosterTemplateProvider, private val traceLocationRepository: TraceLocationRepository, + private val appConfigProvider: AppConfigProvider, private val fileSharing: FileSharing ) : CWAViewModel(dispatcher) { @@ -80,11 +83,13 @@ class QrCodePosterViewModel @AssistedInject constructor( try { val traceLocation = traceLocation() val template = posterTemplateProvider.template() + val correctionLevel = appConfigProvider.currentConfig.first().presenceTracing.qrCodeErrorCorrectionLevel Timber.d("template=$template") val qrCode = qrCodeGenerator.createQrCode( input = traceLocation.locationUrl, length = template.qrCodeLength, - margin = 0 + margin = 0, + correctionLevel = correctionLevel ) val textInfo = buildString { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenFragment.kt index 0f4420cc9b091306c0098b01842e93a780cf6cd3..ec0a46a97a49c1f6cb37eaac07da72297751c10e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenFragment.kt @@ -37,7 +37,8 @@ class QrCodeFullScreenFragment : Fragment(R.layout.fragment_qr_code_full_screen) constructorCall = { factory, _ -> factory as QrCodeFullScreenViewModel.Factory factory.create( - qrcodeText = args.qrCodeText + qrcodeText = args.qrCodeText, + correctionLevel = args.correctionLevel ) } ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenViewModel.kt index 7427c998be1a03c2f76a8621e4e65c33bf0cfc15..1cfc2635a2d06246468016f3ec92e69c437a9c6a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenViewModel.kt @@ -3,6 +3,7 @@ package de.rki.coronawarnapp.ui.qrcode.fullscreen import android.graphics.Bitmap import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -15,6 +16,7 @@ import timber.log.Timber class QrCodeFullScreenViewModel @AssistedInject constructor( @Assisted private val qrcodeText: String, + @Assisted private val correctionLevel: ErrorCorrectionLevel, private val qrCodeGenerator: QrCodeGenerator, dispatcherProvider: DispatcherProvider ) : CWAViewModel(dispatcherProvider) { @@ -29,7 +31,9 @@ class QrCodeFullScreenViewModel @AssistedInject constructor( private fun generateQrCode() = launch { try { - qrCodeBitmap.postValue(qrCodeGenerator.createQrCode(qrcodeText)) + qrCodeBitmap.postValue( + qrCodeGenerator.createQrCode(input = qrcodeText, correctionLevel = correctionLevel) + ) } catch (e: Exception) { Timber.d(e, "generateQrCode failed") } @@ -40,7 +44,8 @@ class QrCodeFullScreenViewModel @AssistedInject constructor( @AssistedFactory interface Factory : CWAViewModelFactory<QrCodeFullScreenViewModel> { fun create( - qrcodeText: String + qrcodeText: String, + correctionLevel: ErrorCorrectionLevel ): QrCodeFullScreenViewModel } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt index f77d17f363e3e104a40230fa53be8f44266578c3..8f0a5a788dfdcb1d145b3919a4cd9efa9663c8af 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt @@ -82,9 +82,13 @@ class SubmissionQRCodeScanFragment : Fragment(R.layout.fragment_submission_qr_co viewModel.qrCodeValidationState.observe2(this) { if (QrCodeRegistrationStateProcessor.ValidationState.INVALID == it) { - showInvalidScanDialog() + DialogHelper.showDialog(createInvalidScanDialog()) } } + + viewModel.registrationError.observe2(this) { + DialogHelper.showDialog(buildErrorDialog(it)) + } viewModel.showRedeemedTokenWarning.observe2(this) { val dialog = DialogHelper.DialogInstance( requireActivity(), @@ -128,10 +132,6 @@ class SubmissionQRCodeScanFragment : Fragment(R.layout.fragment_submission_qr_co } }.run { doNavigate(this) } } - - viewModel.registrationError.observe2(this) { - DialogHelper.showDialog(buildErrorDialog(it)) - } } private fun startDecode() { @@ -142,16 +142,7 @@ class SubmissionQRCodeScanFragment : Fragment(R.layout.fragment_submission_qr_co private fun buildErrorDialog(exception: CwaWebException): DialogHelper.DialogInstance { return when (exception) { - is BadRequestException -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_qr_code_scan_invalid_dialog_headline, - R.string.submission_qr_code_scan_invalid_dialog_body, - R.string.submission_qr_code_scan_invalid_dialog_button_positive, - R.string.submission_qr_code_scan_invalid_dialog_button_negative, - true, - { startDecode() }, - ::navigateToDispatchScreen - ) + is BadRequestException -> createInvalidScanDialog() is CwaClientError, is CwaServerError -> DialogHelper.DialogInstance( requireActivity(), R.string.submission_error_dialog_web_generic_error_title, @@ -177,20 +168,17 @@ class SubmissionQRCodeScanFragment : Fragment(R.layout.fragment_submission_qr_co SubmissionQRCodeScanFragmentDirections.actionSubmissionQRCodeScanFragmentToSubmissionDispatcherFragment() ) - private fun showInvalidScanDialog() { - val invalidScanDialogInstance = DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_qr_code_scan_invalid_dialog_headline, - R.string.submission_qr_code_scan_invalid_dialog_body, - R.string.submission_qr_code_scan_invalid_dialog_button_positive, - R.string.submission_qr_code_scan_invalid_dialog_button_negative, - true, - ::startDecode, - ::navigateToDispatchScreen - ) - - DialogHelper.showDialog(invalidScanDialogInstance) - } + private fun createInvalidScanDialog() = DialogHelper.DialogInstance( + requireActivity(), + R.string.submission_qr_code_scan_invalid_dialog_headline, + R.string.submission_qr_code_scan_invalid_dialog_body, + R.string.submission_qr_code_scan_invalid_dialog_button_positive, + R.string.submission_qr_code_scan_invalid_dialog_button_negative, + true, + { startDecode() }, + { viewModel.onBackPressed() }, + { viewModel.onBackPressed() } + ) override fun onRequestPermissionsResult( requestCode: Int, 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 dd664afaed6e8b74e869a4114b6b25bd6b27f761..41761985896813ea285f5af0fd9dfd3f126d6804 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 @@ -8,6 +8,7 @@ import de.rki.coronawarnapp.appconfig.AppConfigProvider import de.rki.coronawarnapp.appconfig.CWAConfig import de.rki.coronawarnapp.appconfig.internal.ApplicationConfigurationCorruptException import de.rki.coronawarnapp.environment.BuildConfigWrap +import kotlinx.coroutines.withTimeout import timber.log.Timber import javax.inject.Inject @@ -29,13 +30,15 @@ class UpdateChecker @Inject constructor( ) Result(isUpdateNeeded = true, updateIntent = createUpdateAction()) - } catch (exception: Exception) { - Timber.tag(TAG).e("Exception caught:%s", exception.localizedMessage) + } catch (e: Exception) { + Timber.tag(TAG).e(e, "Update check failed, network connection?") Result(isUpdateNeeded = false) } private suspend fun isUpdateNeeded(): Boolean { - val cwaAppConfig: CWAConfig = appConfigProvider.getAppConfig() + val cwaAppConfig: CWAConfig = withTimeout(UPDATE_CHECK_TIMEOUT) { + appConfigProvider.getAppConfig() + } val minVersionFromServer = cwaAppConfig.minVersionCode @@ -43,7 +46,6 @@ class UpdateChecker @Inject constructor( Timber.tag(TAG).d("minVersionFromServer:%s", minVersionFromServer) Timber.tag(TAG).d("Current app version:%s", currentVersion) - val needsImmediateUpdate = VersionComparator.isVersionOlder( currentVersion, minVersionFromServer @@ -67,7 +69,7 @@ class UpdateChecker @Inject constructor( companion object { private const val TAG: String = "UpdateChecker" - + private const val UPDATE_CHECK_TIMEOUT = 5_000L private const val STORE_PREFIX = "https://play.google.com/store/apps/details?id=" private const val COM_ANDROID_VENDING = "com.android.vending" } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DialogHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DialogHelper.kt index e8bdab771a746f50b9c37301ae43828863625ede..8fb8629f214d4b516ce281128428d64f2e416cf1 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DialogHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DialogHelper.kt @@ -23,7 +23,8 @@ object DialogHelper { val cancelable: Boolean? = true, val isTextSelectable: Boolean = false, val positiveButtonFunction: () -> Unit? = {}, - val negativeButtonFunction: () -> Unit? = {} + val negativeButtonFunction: () -> Unit? = {}, + val cancelFunction: () -> Unit? = {} ) { constructor( context: Context, @@ -33,7 +34,8 @@ object DialogHelper { negativeButton: Int? = null, cancelable: Boolean? = true, positiveButtonFunction: () -> Unit? = {}, - negativeButtonFunction: () -> Unit? = {} + negativeButtonFunction: () -> Unit? = {}, + cancelFunction: () -> Unit? = {} ) : this( context = context, title = context.resources.getString(title), @@ -42,7 +44,8 @@ object DialogHelper { negativeButton = negativeButton?.let { context.resources.getString(it) }, cancelable = cancelable, positiveButtonFunction = positiveButtonFunction, - negativeButtonFunction = negativeButtonFunction + negativeButtonFunction = negativeButtonFunction, + cancelFunction = cancelFunction ) constructor( @@ -53,7 +56,8 @@ object DialogHelper { negativeButton: Int? = null, cancelable: Boolean? = true, positiveButtonFunction: () -> Unit? = {}, - negativeButtonFunction: () -> Unit? = {} + negativeButtonFunction: () -> Unit? = {}, + cancelFunction: () -> Unit? = {} ) : this( context = context, title = context.resources.getString(title), @@ -62,7 +66,8 @@ object DialogHelper { negativeButton = negativeButton?.let { context.resources.getString(it) }, cancelable = cancelable, positiveButtonFunction = positiveButtonFunction, - negativeButtonFunction = negativeButtonFunction + negativeButtonFunction = negativeButtonFunction, + cancelFunction = cancelFunction ) } @@ -93,6 +98,7 @@ object DialogHelper { dialogInstance.negativeButtonFunction() } } + setOnCancelListener { dialogInstance.cancelFunction() } } builder.create() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt index 9b0a15fd8dd03a5b47cab7299e3932a5b2930406..240b35bf342a849ffd0762b2bb6ebb3651373df6 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt @@ -1,5 +1,6 @@ package de.rki.coronawarnapp.vaccination.core +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinatedPersonData import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet import org.joda.time.Duration @@ -43,15 +44,10 @@ data class VaccinatedPerson( ) fun getVaccinationStatus(nowUTC: Instant = Instant.now()): Status { - val newestFullDose = vaccinationCertificates - .filter { it.doseNumber == it.totalSeriesOfDoses } - .maxByOrNull { it.vaccinatedAt } - ?: return Status.INCOMPLETE - - val daysAgo = Duration(newestFullDose.vaccinatedAt.toDateTimeAtStartOfDay(), nowUTC).standardDays + val daysToImmunity = getTimeUntilImmunity(nowUTC)?.standardDays ?: return Status.INCOMPLETE return when { - daysAgo >= IMMUNITY_WAITING_PERIOD.standardDays -> Status.IMMUNITY + daysToImmunity <= 0 -> Status.IMMUNITY else -> Status.COMPLETE } } @@ -64,7 +60,7 @@ data class VaccinatedPerson( val immunityAt = newestFullDose.vaccinatedAt.toDateTimeAtStartOfDay().plus(IMMUNITY_WAITING_PERIOD) - return Duration(nowUTC, immunityAt) + return Duration(nowUTC.toLocalDateUtc().toDateTimeAtStartOfDay(), immunityAt) } enum class Status { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt index 27de6bffab3d6d14dd588f322d370025b3efdb51..3c51b6df3aff83058514b6825a8497d602190d8e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt @@ -1,16 +1,23 @@ package de.rki.coronawarnapp.vaccination.core.repository -import androidx.annotation.VisibleForTesting import dagger.Reusable import de.rki.coronawarnapp.util.coroutine.AppScope +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.flow.HotDataFlow import de.rki.coronawarnapp.vaccination.core.repository.storage.ValueSetsStorage import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationServer import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet +import de.rki.coronawarnapp.vaccination.core.server.valueset.emptyVaccinationValueSet import de.rki.coronawarnapp.vaccination.core.server.valueset.isEmpty import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.plus import timber.log.Timber import java.util.Locale import javax.inject.Inject @@ -19,55 +26,65 @@ import javax.inject.Inject class ValueSetsRepository @Inject constructor( private val vaccinationServer: VaccinationServer, private val valueSetsStorage: ValueSetsStorage, - @AppScope private val scope: CoroutineScope + @AppScope private val scope: CoroutineScope, + dispatcherProvider: DispatcherProvider ) { - val latestValueSet: Flow<VaccinationValueSet> = valueSetsStorage.valueSet.flow.distinctUntilChanged() + private fun Flow<VaccinationValueSet>.distinctUntilChangedByHash() = distinctUntilChangedBy { it.hashCode() } - fun triggerUpdateValueSet(languageCode: Locale) = scope.launch { + private val internalData: HotDataFlow<VaccinationValueSet> = HotDataFlow( + loggingTag = TAG, + scope = scope, + coroutineContext = dispatcherProvider.IO, + sharingBehavior = SharingStarted.Lazily, + startValueProvider = { + valueSetsStorage.vaccinationValueSet.also { Timber.v("Loaded initial value set %s", it) } + } + ) + + init { + internalData.data + .distinctUntilChangedByHash() + .onStart { Timber.d("Observing value set") } + .onEach { valueSetsStorage.vaccinationValueSet = it } + .catch { Timber.e(it, "Storing new value set failed.") } + .launchIn(scope + dispatcherProvider.IO) + } + + val latestValueSet: Flow<VaccinationValueSet> = internalData.data.distinctUntilChangedByHash() + + fun triggerUpdateValueSet(languageCode: Locale) { Timber.d("triggerUpdateValueSet(languageCode=%s)", languageCode) + internalData.updateAsync( + onUpdate = { getValueSetFromServer(languageCode = languageCode) ?: this }, + onError = { Timber.e(it, "Updating value set failed") } + ) + } + + private suspend fun getValueSetFromServer(languageCode: Locale): VaccinationValueSet? { + Timber.v("getValueSetFromServer(languageCode=%s)", languageCode) var valueSet = vaccinationServer.getVaccinationValueSets(languageCode = languageCode) - if (valueSet == null && valueSetsStorage.valueSet.value.isEmpty()) { + if (valueSet.isEmpty()) { Timber.d( - "Got no value set from server for %s and local value set is empty... " + - "Try fallback to value set for en", + "Got no value set from server for %s and local value set is empty... Try fallback to value set for en", languageCode.language ) valueSet = vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) } - valueSet - .also { Timber.d("Value set is %s", it) } - ?.let { newValueSet -> valueSetsStorage.valueSet.update { newValueSet.toStoredVaccinationValueSet() } } + return valueSet + .also { Timber.v("New value set %s", it) } } - fun clear() { + suspend fun clear() { Timber.d("Clearing value sets") vaccinationServer.clear() - valueSetsStorage.clear() + internalData.updateBlocking { + Timber.v("Resetting value set to an empty value set") + emptyVaccinationValueSet + } } } -@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) -fun VaccinationValueSet.toStoredVaccinationValueSet(): ValueSetsStorage.StoredVaccinationValueSet = - ValueSetsStorage.StoredVaccinationValueSet( - languageCode = languageCode, - vp = vp.toStoredValueSet(), - mp = mp.toStoredValueSet(), - ma = ma.toStoredValueSet() - ) - -@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) -fun VaccinationValueSet.ValueSet.toStoredValueSet(): ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet = - ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet( - items = items.map { it.toStoredItem() } - ) - -@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) -fun VaccinationValueSet.ValueSet.Item.toStoredItem(): - ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet.StoredItem = - ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet.StoredItem( - key = key, - displayText = displayText - ) +private const val TAG = "ValueSetsRepository" diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt index b76916194b49ab4bcb1090bedb3cea556db50694..e1f4174618247df92441f4195b932e580b508d64 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt @@ -51,7 +51,10 @@ data class VaccinationContainer internal constructor( val personIdentifier: VaccinatedPersonIdentifier get() = certificate.personIdentifier - fun toVaccinationCertificate(valueSet: VaccinationValueSet?) = object : VaccinationCertificate { + fun toVaccinationCertificate( + valueSet: VaccinationValueSet?, + userLocale: Locale = Locale.getDefault(), + ) = object : VaccinationCertificate { override val personIdentifier: VaccinatedPersonIdentifier get() = certificate.personIdentifier @@ -83,9 +86,10 @@ data class VaccinationContainer internal constructor( get() = vaccination.certificateIssuer override val certificateCountry: String get() = Locale( - Locale.getDefault().language, + userLocale.language, vaccination.countryOfVaccination.uppercase() - ).displayCountry + ).getDisplayCountry(userLocale) + override val certificateId: String get() = vaccination.uniqueCertificateIdentifier diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorage.kt index bb81b8a8261a55e8bfa6cdcba1ed2f20ecb86064..63c2246e457b96b251dae2590186c4b5e108a214 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorage.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorage.kt @@ -3,15 +3,15 @@ package de.rki.coronawarnapp.vaccination.core.repository.storage import android.content.Context import android.content.SharedPreferences import androidx.annotation.Keep +import androidx.annotation.VisibleForTesting +import androidx.core.content.edit import com.google.gson.Gson import com.google.gson.annotations.SerializedName import dagger.Reusable import de.rki.coronawarnapp.util.di.AppContext -import de.rki.coronawarnapp.util.preferences.FlowPreference -import de.rki.coronawarnapp.util.preferences.clearAndNotify -import de.rki.coronawarnapp.util.preferences.createFlowPreference import de.rki.coronawarnapp.util.serialization.BaseGson import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet +import de.rki.coronawarnapp.vaccination.core.server.valueset.emptyVaccinationValueSet import timber.log.Timber import java.util.Locale import javax.inject.Inject @@ -26,25 +26,52 @@ class ValueSetsStorage @Inject constructor( context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) } - var valueSet: FlowPreference<StoredVaccinationValueSet> = prefs.createFlowPreference( - key = PKEY_VALUE_SETS_PREFIX, - reader = FlowPreference.gsonReader(gson = gson, createEmptyValueSet()), - writer = FlowPreference.gsonWriter(gson = gson) - ) + var vaccinationValueSet: VaccinationValueSet + get() = getValueSet() + set(value) = setValueSet(value) - fun clear() { - Timber.d("Clearing local storage") - prefs.clearAndNotify() + private fun getValueSet(): VaccinationValueSet { + Timber.v("Loading value set") + val valueSetString = prefs.getString(PKEY_VALUE_SETS_PREFIX, null) + return when (valueSetString != null) { + true -> gson.fromJson(valueSetString, StoredVaccinationValueSet::class.java) + else -> emptyVaccinationValueSet + }.also { loaded -> Timber.v("Loaded value set %s", loaded) } } - private fun createEmptyValueSet() = StoredVaccinationValueSet( - languageCode = Locale.ENGLISH, - vp = StoredVaccinationValueSet.StoredValueSet(items = emptyList()), - mp = StoredVaccinationValueSet.StoredValueSet(items = emptyList()), - ma = StoredVaccinationValueSet.StoredValueSet(items = emptyList()) - ) + private fun setValueSet(value: VaccinationValueSet) { + Timber.v("Saving value set %s", value) + prefs.edit { + val json = gson.toJson(value.toStoredVaccinationValueSet(), StoredVaccinationValueSet::class.java) + Timber.v("Writing %s to prefs", json) + putString(PKEY_VALUE_SETS_PREFIX, json) + } + } + + @VisibleForTesting + fun VaccinationValueSet.toStoredVaccinationValueSet(): StoredVaccinationValueSet = + StoredVaccinationValueSet( + languageCode = languageCode, + vp = vp.toStoredValueSet(), + mp = mp.toStoredValueSet(), + ma = ma.toStoredValueSet() + ) + + @VisibleForTesting + fun VaccinationValueSet.ValueSet.toStoredValueSet(): StoredVaccinationValueSet.StoredValueSet = + StoredVaccinationValueSet.StoredValueSet( + items = items.map { it.toStoredItem() } + ) + + @VisibleForTesting + fun VaccinationValueSet.ValueSet.Item.toStoredItem(): + StoredVaccinationValueSet.StoredValueSet.StoredItem = + StoredVaccinationValueSet.StoredValueSet.StoredItem( + key = key, + displayText = displayText + ) - @Keep + @VisibleForTesting data class StoredVaccinationValueSet( @SerializedName("languageCode") override val languageCode: Locale, @SerializedName("vp") override val vp: StoredValueSet, diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/DefaultVaccinationValueSet.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/DefaultVaccinationValueSet.kt index 1962cf330dbe26a192497bc4eeaeeb0e052b00d9..c7635321913b9267d867927ad2359afb41f7968d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/DefaultVaccinationValueSet.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/DefaultVaccinationValueSet.kt @@ -19,3 +19,12 @@ data class DefaultVaccinationValueSet( ) : VaccinationValueSet.ValueSet.Item } } + +internal val emptyVaccinationValueSet: VaccinationValueSet by lazy { + DefaultVaccinationValueSet( + languageCode = Locale.ENGLISH, + vp = DefaultVaccinationValueSet.DefaultValueSet(items = emptyList()), + mp = DefaultVaccinationValueSet.DefaultValueSet(items = emptyList()), + ma = DefaultVaccinationValueSet.DefaultValueSet(items = emptyList()) + ) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt index 08618fc008c487cd471b334a15fe6df1d039a348..23d5350fad4c4018dd2691784541febcb8ff42ad 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt @@ -24,6 +24,6 @@ fun VaccinationValueSet.getDisplayText(key: String): String? = fun VaccinationValueSet.ValueSet.getDisplayText(key: String): String? = items.find { key == it.key }?.displayText -fun VaccinationValueSet.isEmpty(): Boolean = vp.isEmpty() && mp.isEmpty() && ma.isEmpty() +fun VaccinationValueSet?.isEmpty(): Boolean = (this == null) || (vp.isEmpty() && mp.isEmpty() && ma.isEmpty()) fun VaccinationValueSet.ValueSet.isEmpty(): Boolean = items.isEmpty() diff --git a/Corona-Warn-App/src/main/res/drawable-night/ic_hourglass.xml b/Corona-Warn-App/src/main/res/drawable-night/ic_hourglass.xml new file mode 100644 index 0000000000000000000000000000000000000000..dc7162747e71e41486fe4e9a4f1b422d1b6ee1ad --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable-night/ic_hourglass.xml @@ -0,0 +1,13 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportWidth="40" + android:viewportHeight="40"> + <path + android:pathData="M20,20m-20,0a20,20 0,1 1,40 0a20,20 0,1 1,-40 0" + android:fillColor="#434445"/> + <path + android:pathData="M14,10V16H14.01L14,16.01L18,20L14,24L14.01,24.01H14V30H26V24.01H25.99L26,24L22,20L26,16.01L25.99,16H26V10H14ZM24,24.5V28H16V24.5L20,20.5L24,24.5ZM16,12V15.5L20,19.5L24,15.5V12H16Z" + android:fillColor="#83D2F2" + android:fillType="evenOdd"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable-night/ic_test_result_step_deletion.xml b/Corona-Warn-App/src/main/res/drawable-night/ic_test_result_step_deletion.xml new file mode 100644 index 0000000000000000000000000000000000000000..340dae96b75ddd3903549ba4bcf0ccc2e4ee6819 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable-night/ic_test_result_step_deletion.xml @@ -0,0 +1,12 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportWidth="40" + android:viewportHeight="40"> + <path + android:pathData="M20,20m-20,0a20,20 0,1 1,40 0a20,20 0,1 1,-40 0" + android:fillColor="#434445"/> + <path + android:pathData="M24,17V27H16V17H24ZM22.5,11H17.5L16.5,12H13V14H27V12H23.5L22.5,11ZM26,15H14V27C14,28.1 14.9,29 16,29H24C25.1,29 26,28.1 26,27V15Z" + android:fillColor="#83D2F2"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_onboarding.xml b/Corona-Warn-App/src/main/res/layout/fragment_onboarding.xml index 7723129e1f0043eb2067f5a1ef7fc31ca2ea2550..f03590fabf37b17f9b544137148d093863cd85d1 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_onboarding.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_onboarding.xml @@ -126,6 +126,20 @@ app:layout_constraintTop_toBottomOf="@id/onboarding_body_4" tools:text="@string/onboarding_body_5" /> + <TextView + android:id="@+id/onboarding_body_6" + style="@style/subtitle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_normal" + android:focusable="true" + android:text="@string/onboarding_body_6" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/onboarding_body_5" + tools:text="@string/onboarding_body_6" /> + <TextView android:id="@+id/onboarding_easy_language" style="@style/subtitle" @@ -140,7 +154,7 @@ android:textColorLink="@color/colorTextTint" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/onboarding_body_5" + app:layout_constraintTop_toBottomOf="@id/onboarding_body_6" tools:text="@string/onboarding_tracing_easy_language_explanation" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml b/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml index 51317118fb1efa3c0b7f0a6b2daa256269cf6e85..d5be7b0a3b24368bfe07a8d32907e6181e4a0402 100644 --- a/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml +++ b/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml @@ -15,7 +15,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:title="@string/vaccination_consent_title" /> + app:title="@string/vaccination_consent_headline" /> <ScrollView android:id="@+id/scrollview" @@ -35,46 +35,34 @@ android:id="@+id/vaccination_consent_info_graphic" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_huge" - android:layout_marginEnd="@dimen/spacing_normal" + android:layout_marginTop="32dp" android:importantForAccessibility="no" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/ic_vaccination_consent" /> - <TextView - android:id="@+id/vaccination_consent_headline" - style="@style/headline5" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/spacing_normal" - android:layout_marginTop="@dimen/spacing_huge" - android:layout_marginEnd="@dimen/spacing_normal" - android:text="@string/vaccination_consent_headline" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/vaccination_consent_info_graphic" /> - <TextView android:id="@+id/vaccination_consent_info_subtitle" style="@style/subtitleMedium" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/spacing_normal" - android:layout_marginTop="@dimen/spacing_normal" + android:layout_marginTop="48dp" android:layout_marginEnd="@dimen/spacing_normal" android:text="@string/vaccination_consent_info_subtitle_text" android:textColorLink="@color/colorAccent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/vaccination_consent_headline" /> + app:layout_constraintTop_toBottomOf="@id/vaccination_consent_info_graphic" + tools:text="@string/vaccination_consent_info_subtitle_text" + /> <ImageView android:id="@+id/vaccination_consent_info_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_large" + android:layout_marginTop="32dp" android:importantForAccessibility="no" app:layout_constraintStart_toStartOf="@id/vaccination_consent_info_subtitle" app:layout_constraintTop_toBottomOf="@id/vaccination_consent_info_subtitle" diff --git a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml index 6966786eac8380ae27a2810af9f5ee6f5cfcc53d..3b7b70124ea8c4dd175329cd2c23698d9a353058 100644 --- a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml +++ b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml @@ -807,6 +807,10 @@ <argument android:name="qrCodeText" app:argType="string" /> + <argument + android:name="correctionLevel" + app:argType="com.google.zxing.qrcode.decoder.ErrorCorrectionLevel" + android:defaultValue="Q" /> </fragment> <action android:id="@+id/action_global_qrCodeFullScreenFragment" diff --git a/Corona-Warn-App/src/main/res/values-bg/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-bg/antigen_strings.xml index 3144dd73f17dc45a2bc7ac9ff3561008b4b66660..06cc536543af05f208024d6243bdcb92ee453207 100644 --- a/Corona-Warn-App/src/main/res/values-bg/antigen_strings.xml +++ b/Corona-Warn-App/src/main/res/values-bg/antigen_strings.xml @@ -6,7 +6,7 @@ <!-- XHED: Register test homescreen card: title --> <string name="ag_homescreen_card_test_register_title">"РегиÑтрирайте ÑÐ²Ð¾Ñ Ñ‚ÐµÑÑ‚"</string> <!-- XTXT: Register test homescreen card: body --> - <string name="ag_homescreen_card_test_register_body">"Използвайте приложението, за да извлечете резултатите от теÑта и да предупредите оÑтаналите по-бързо."</string> + <string name="ag_homescreen_card_test_register_body">"Използвайте приложението, за да региÑтрирате теÑтовете Ñи и да извлечете резултатите от Ñ‚ÑÑ…, за да можете предупредите оÑтаналите по-бързо."</string> <!-- #################################### Homescreen cards - common buttons @@ -142,7 +142,7 @@ <!-- XHED: Create RAT profile card title --> <string name="rat_profile_create_card_title">"Създаване на профил за бързи теÑтове"</string> <!-- XTXT: Create RAT profile card subtitle --> - <string name="rat_profile_create_card_subtitle">"Можете да Ñъздадете профил Ñ Ð»Ð¸Ñ‡Ð½Ð¸Ñ‚Ðµ Ñи данни, който да предÑтавÑте под формата на QR код при вÑеки бърз теÑÑ‚."</string> + <string name="rat_profile_create_card_subtitle">"Можете да Ñъздадете профил Ñ Ð»Ð¸Ñ‡Ð½Ð¸Ñ‚Ðµ Ñи данни, който да предÑтавÑте чрез QR код във вÑеки включен пункт за теÑтване."</string> <!-- XHED: Open RAT profile card title --> <string name="rat_profile_open_card_title">"Профил за бързи теÑтове"</string> <!-- XTXT: Open RAT profile card subtitle --> @@ -158,7 +158,7 @@ <!-- XBUT: Create RAT profile save button --> <string name="rat_profile_create_button">"Запазване"</string> <!-- XTXT: Create RAT profile description --> - <string name="rat_profile_create_description">"Запазете личните Ñи данни като QR код, за да уÑкорите региÑтрациÑта в пунктовете за теÑтване."</string> + <string name="rat_profile_create_description">"Можете да Ñъздадете профил Ñ Ð»Ð¸Ñ‡Ð½Ð¸Ñ‚Ðµ Ñи данни, който да предÑтавÑте чрез QR код във вÑеки включен пункт за теÑтване."</string> <!-- XTXT: Create RAT profile street hint --> <string name="rat_profile_create_street_hint">"Улица и номер"</string> <!-- XTXT: Create RAT profile post code hint --> @@ -173,7 +173,7 @@ <!--RAT profile onboarding--> <string name="rat_profile_onboarding_image_content_description">"Жена ÑÑŠÑ Ñмартфон в ръката Ñтои пред Ñграда. QR кодът Ñимволизира профила за бързи теÑтове, който Ñ‚Ñ€Ñбва да Ñе Ñканира."</string> <!-- XTXT: Create RAT profile onboarding title --> - <string name="rat_profile_onboarding_title">"Запазете личните Ñи данни като QR код, за да уÑкорите региÑтрациÑта в пунктовете за теÑтване."</string> + <string name="rat_profile_onboarding_title">"Можете да Ñъздадете профил Ñ Ð»Ð¸Ñ‡Ð½Ð¸Ñ‚Ðµ Ñи данни, който да предÑтавÑте чрез QR код във вÑеки включен пункт за теÑтване."</string> <!-- XTXT: Create RAT profile onboarding subtitle --> <string name="rat_profile_onboarding_subtitle">"Ðко Ñи Ñъздадете профил за бързи теÑтове, нÑма да Ñе налага да попълвате личните Ñи данни наново при вÑеки антигенен теÑÑ‚."</string> <!-- XTXT: Create RAT profile onboarding next button --> diff --git a/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml index b3079ef9d7a5dff1c548e034dc68d049a34d8522..fb165acc4816cc19117521807662ccf0fc0ecfd0 100644 --- a/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml +++ b/Corona-Warn-App/src/main/res/values-bg/contact_diary_strings.xml @@ -31,7 +31,7 @@ <!-- XTXT: Title for the contact diary onboarding screen --> <string name="contact_diary_information_card_title">"ОтбелÑзвайте Вашите контакти."</string> <!-- XTXT: Contact diary onboarding screen --> - <string name="contact_diary_onboarding_body">"Ðаправете ÑпиÑък на Вашите контакти през поÑледните 14 дни. Ще имате бърз доÑтъп до него в Ñлучай на необходимоÑÑ‚."</string> + <string name="contact_diary_onboarding_body">"Ðаправете ÑпиÑък на Вашите контакти през поÑледните 14 дни. Ще имате бърз доÑтъп до него в Ñлучай на необходимоÑÑ‚. Вашите Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк Ñъщо ще Ñе показват в него."</string> <!-- XTXT: Contact diary onboarding screen first functionality --> <string name="contact_diary_onboarding_functionality_first_section">"Отбележете хората, които Ñте Ñрещнали."</string> <!-- XTXT: Contact diary onboarding screen second functionality --> diff --git a/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml index bf594250652e02fbd751c788e07a7cfca7331544..c36ffbe1836a1a5f7bbe701ea251a8f2810d7e63 100644 --- a/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml +++ b/Corona-Warn-App/src/main/res/values-bg/release_info_strings.xml @@ -16,26 +16,22 @@ <!-- XHED: Titles for the release info screen bullet points --> <string-array name="new_release_title"> - <item>"Водене на журнали за анализ на грешки"</item> - <item>"Създаване на профили за бързи теÑтове"</item> + <item>"Електронно доказателÑтво за вакÑиниране"</item> </string-array> <!-- XTXT: Text bodies for the release info screen bullet points --> <string-array name="new_release_body"> - <item>"Вече можете да генерирате отчети за грешките чрез функциÑта за техничеÑка поддръжка. Ð’ Ñ‚ÑÑ… Ñе запиÑват дейÑтвиÑта Ви в приложението, за да можем по-леÑно да анализираме евентуални проблеми и да ги отÑтраним по-бързо."</item> - <item>"Вече можете да Ñи Ñъздадете профил Ñ Ð»Ð¸Ñ‡Ð½Ð¸Ñ‚Ðµ данни, необходими при бързи теÑтове. ИнформациÑта Ñе преобразува в QR код, който леÑно и бързо Ñе Ñканира в пунктовете за теÑтване."</item> + <item>"Вече можете да добавите в приложението Ñертификатите Ñи за вакÑиниране и да ги предÑтавите чрез QR код. Приложението ще покаже пълна защита от вакÑиниране 14 дни Ñлед крайната вакÑинациÑ."</item> </string-array> <!-- XTXT: Text labels that will be converted to Links --> <string-array name="new_release_linkified_labels"> <item/> - <item/> </string-array> <!-- XTXT: URL destinations for the lables in new_release_linkified_labels --> <string-array name="new_release_target_urls"> <item/> - <item/> </string-array> </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-bg/strings.xml b/Corona-Warn-App/src/main/res/values-bg/strings.xml index d97472c1022d357349130ec32cbadc4849102ec1..9f392a30db6e2f798aaf9f265e735983dde4d7b9 100644 --- a/Corona-Warn-App/src/main/res/values-bg/strings.xml +++ b/Corona-Warn-App/src/main/res/values-bg/strings.xml @@ -411,7 +411,9 @@ <!-- YTXT: onboarding(together) - paragraph --> <string name="onboarding_body_4">"Ðко желаете, може да използвате приложението за доказване на Ð»Ð¸Ñ‡Ð½Ð¸Ñ Ð²Ð¸ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð½Ð° заразÑване (например отрицателен бърз теÑÑ‚). Ðо имайте предвид, че по никакъв начин не Ñте задължени да използвате приложението за тази цел. Може да докажете ÑтатуÑа Ñи и по друг начин, Ñъобразен Ñ Ð¿Ñ€Ð°Ð²Ð½Ð¸Ñ‚Ðµ разпоредби на вашето мÑÑто на пребиваване."</string> <!-- YTXT: onboarding(together) - paragraph --> - <string name="onboarding_body_5">"Приложението региÑтрира контакти на лица поÑредÑтвом обмÑна на криптирани Ñлучайни ИД кодове между уÑтройÑтвата им, без да оÑъщеÑтвÑва доÑтъп до каквито и да било лични данни."</string> + <string name="onboarding_body_5">"Можете Ñъщо да потвърдите Ð»Ð¸Ñ‡Ð½Ð¸Ñ Ñи вакÑинационен ÑтатуÑ."</string> + <!-- YTXT: onboarding(together) - paragraph --> + <string name="onboarding_body_6">"Приложението региÑтрира контакти на лица поÑредÑтвом обмÑна на криптирани Ñлучайни ИД кодове между уÑтройÑтвата им, без да оÑъщеÑтвÑва доÑтъп до каквито и да било лични данни."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"Група лица използват Ñмартфоните Ñи, придвижвайки Ñе из града."</string> <!-- XACT: Onboarding (privacy) page title --> @@ -747,7 +749,7 @@ <string name="settings_privacy_preserving_analytics_title">"СподелÑне на данни"</string> <!-- XTXT: privacy preserving analytics settings switch subtitle --> - <string name="settings_analytics_switch_subtitle">"СподелÑне на потребителÑки данни"</string> + <string name="settings_analytics_switch_subtitle">"СподелÑне на данни"</string> <!-- #################################### App Information @@ -1063,13 +1065,17 @@ <!-- XHED: Page subheadline for test result --> <string name="submission_test_result_subtitle">"Как работи:"</string> <!-- XHED: Page headline for results next steps --> - <string name="submission_test_result_steps_added_heading">"ТеÑÑ‚ÑŠÑ‚ е добавен уÑпешно"</string> + <string name="submission_test_result_steps_added_heading">"PCR теÑÑ‚ÑŠÑ‚ Ви е добавен уÑпешно."</string> <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"ВашиÑÑ‚ теÑÑ‚ е запазен в приложението Corona-Warn-App."</string> <!-- XHED: Page headline for pending test result next steps --> <string name="submission_test_result_pending_steps_waiting_heading">"Ð’Ñе още нÑма резултат от теÑта Ви."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> <string name="submission_test_result_pending_steps_waiting_body">"Резултатът от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ ще Ñе покаже в приложението веднага щом бъде готов.\n\nТой ще Ви бъде изпратен Ñъщо и извън приложението. Службата за общеÑтвено здравеопазване ще Ви уведоми, ако е положителен.\n\nÐко получите такова уведомление, Ð¼Ð¾Ð»Ñ Ð¸Ð·Ñ‚Ñ€Ð¸Ð¹Ñ‚Ðµ теÑта, който в момента е региÑтриран в приложението. Позвънете на номера, показан под „ЗаÑвка за ТÐРкод“, за да получите ТÐÐ. Използвайте кода, за да региÑтрирате ÑÐ²Ð¾Ñ Ñ€ÐµÐ·ÑƒÐ»Ñ‚Ð°Ñ‚ в приложението и да предупредите оÑтаналите потребители."</string> + <!-- XHED: Page headline for pending test result next steps --> + <string name="submission_test_result_pending_steps_waiting_pcr_heading">"Ð’Ñе още нÑма резултат от теÑта Ви."</string> + <!-- YTXT: Body text for next steps section of waiting test result page --> + <string name="submission_test_result_pending_steps_waiting_pcr_body">"Резултатът от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ ще Ñе покаже в приложението веднага щом бъде готов.\n\nТой ще Ви бъде изпратен Ñъщо и извън приложението. Службата за общеÑтвено здравеопазване ще Ви уведоми, ако е положителен.\n\nÐко получите такова уведомление, Ð¼Ð¾Ð»Ñ Ð¸Ð·Ñ‚Ñ€Ð¸Ð¹Ñ‚Ðµ теÑта, който в момента е региÑтриран в приложението. Позвънете на номера, показан под „ЗаÑвка за ТÐРкод“, за да получите ТÐÐ. Използвайте кода, за да региÑтрирате ÑÐ²Ð¾Ñ Ñ€ÐµÐ·ÑƒÐ»Ñ‚Ð°Ñ‚ в приложението и да предупредите оÑтаналите потребители."</string> <!-- XHED: Page headline for results next steps --> <string name="submission_test_result_steps_added_rat_heading">"БързиÑÑ‚ Ви теÑÑ‚ е добавен."</string> <!-- XHED: Page headline for pending test result next steps --> @@ -1101,12 +1107,21 @@ <string name="submission_test_result_positive_continue_button_with_symptoms">"Въведете Ñимптоми"</string> <!-- XBUT: positive test result : continue button without symptoms --> <string name="submission_test_result_positive_continue_button_wo_symptoms">"Ðе въвеждайте Ñимптоми"</string> + + <!-- XHED: Page headline for invalid test result screen --> - <string name="submission_test_result_invalid_steps_invalid_heading">"Резултатът от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚"</string> + <string name="submission_test_result_invalid_steps_invalid_heading">"Ðе може да бъде определен резултат от теÑта Ви"</string> + + <!-- XHED: Page headline for invalid test result screen --> + <string name="submission_test_result_delete_steps_invalid_heading">"Изтриване на теÑÑ‚"</string> + <!-- YTXT: Body text for next steps section of invalid test result--> - <string name="submission_test_result_invalid_steps_invalid_body">"Възникна проблем при определÑнето на резултата от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚. МолÑ, Ñвържете Ñе ÑÑŠÑ ÑÑŠÐ¾Ñ‚Ð²ÐµÑ‚Ð½Ð¸Ñ Ñ†ÐµÐ½Ñ‚ÑŠÑ€ за теÑтване или лабораториÑ, за да получите Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ ÐºÐ°ÐºÐ²Ð¾ Ñ‚Ñ€Ñбва да направите.\n\nМолÑ, изтрийте теÑта от Вашето Corona-Warn-App приложение, за да можете да запазите нов код на теÑÑ‚, ако е необходимо."</string> + <string name="submission_test_result_invalid_steps_invalid_body">"Възникна проблем при определÑнето на резултата от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚. МолÑ, Ñвържете Ñе ÑÑŠÑ ÑÑŠÐ¾Ñ‚Ð²ÐµÑ‚Ð½Ð¸Ñ Ñ†ÐµÐ½Ñ‚ÑŠÑ€ за теÑтване или лабораториÑ, за да получите Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ ÐºÐ°ÐºÐ²Ð¾ можете да направите."</string> + <!-- YTXT: Body text for next steps section of invalid test result--> + <string name="submission_test_result_delete_steps_invalid_body">"МолÑ, изтрийте теÑта от приложението Corona-Warn-App, за да можете да запазите нов код на теÑÑ‚, ако е необходимо."</string> + <!-- XBUT: invalid test result : remove the test button --> - <string name="submission_test_result_invalid_remove_test_button">"Изтриване на теÑта"</string> + <string name="submission_test_result_invalid_remove_test_button">"Изтриване на теÑÑ‚"</string> <!-- XHED: Dialog title for tracing required dailog --> <string name="submission_test_result_dialog_tracing_required_title">"ИзиÑква Ñе региÑтриране на излаганиÑта на риÑк"</string> <!-- YTXT: Dialog text for tracing required dialog--> @@ -1158,17 +1173,13 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Извличане на резултат от теÑÑ‚"</string> - <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"Получете резултата от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚ чрез приложението и предупредете оÑтаналите. По този начин предпазвате Ñебе Ñи и помагате да Ñе Ñпре разпроÑтранението на коронавируÑа."</string> - <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">"Правили ли Ñте Ñи теÑÑ‚?"</string> + <string name="submission_dispatcher_headline">"РегиÑтрирайте ÑÐ²Ð¾Ñ Ñ‚ÐµÑÑ‚"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> <string name="submission_dispatcher_already_positive_subheadline">"Положителен ли е ВашиÑÑ‚ резултат от PCR теÑта?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"ТеÑÑ‚ Ñ QR код"</string> + <string name="submission_dispatcher_card_qr">"Сканиране на QR код"</string> <!-- YTXT: Body text for QR code dispatcher option --> - <string name="submission_dispatcher_qr_card_text">"РегиÑтрирайте теÑта Ñи, като Ñканирате QR кода на документа."</string> + <string name="submission_dispatcher_qr_card_text">"Получете резултата Ñи в приложението и предупредете оÑтаналите."</string> <!-- YTXT: Dispatcher text for TAN code option --> <string name="submission_dispatcher_card_tan_code">"Въведете ТÐРкод за PCR теÑÑ‚"</string> <!-- YTXT: Body text for TAN code dispatcher option --> @@ -1236,9 +1247,9 @@ <!-- YTXT: text after submission: pcr validation --> <string name="submission_done_share_keys">"Споделете Ñвоите Ñлучайни ИД кодове, за да предупредите оÑтаналите потребители."</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"От Ñлужбата за общеÑтвено здравеопазване (Gesundheitsamt) ще Ñе Ñвържат Ñ Ð’Ð°Ñ Ð² Ñледващите нÑколко дни."</string> + <string name="submission_done_contagious">"От Ñлужбата за общеÑтвено здравеопазване (Gesundheitsamt) може да Ñе Ñвържат Ñ Ð’Ð°Ñ Ð¿Ñ€ÐµÐ· Ñледващите нÑколко дни."</string> <!-- YTXT: text after submission: isolate --> - <string name="submission_done_isolate">"Вие Ñте ноÑител на заразата. Ðеобходимо е да Ñе Ñамоизолирате."</string> + <string name="submission_done_isolate">"Има голÑма вероÑтноÑÑ‚ да Ñте ноÑител на заразата. Изолирайте Ñе от другите хора."</string> <!-- XHED: Title for further info --> <string name="submission_done_further_info_title">"Още информациÑ:"</string> @@ -1247,7 +1258,7 @@ <item>"Периодът, в който Ñ‚Ñ€Ñбва да Ñте под карантина, обикновено е 14 дни. Ðаблюдавайте внимателно развитието на Вашите Ñимптоми."</item> <item>"Службата за общеÑтвено здравеопазване ще изиÑка от Ð’Ð°Ñ Ð´Ð° ÑÑŠÑтавите ÑпиÑък на хората, Ñ ÐºÐ¾Ð¸Ñ‚Ð¾ Ñте били в близък контакт (на разÑтоÑние под 2 метра или при разговор лице в лице) в продължение на повече от 15 минути през поÑледните два дни, преди да Ñе разболеете. Може да използвате Ð’Ð°ÑˆÐ¸Ñ Ð´Ð½ÐµÐ²Ð½Ð¸Ðº на контактите – проÑто екÑпортирайте запиÑите и Ñлед това ги разпечатайте или ги изпратете по имейл."</item> <item>"МолÑ, обърнете оÑобено внимание на хората, които нÑма да бъдат уведомени директно чрез приложението, тъй като нÑмат Ñмартфон или не Ñа инÑталирали приложението."</item> - <item>"Може вÑе още да Ñте ноÑител на заразата дори ако вече не проÑвÑвате Ñимптоми и отново Ñе чувÑтвате добре. По тази причина, молÑ, не нарушавайте ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð¿ÐµÑ€Ð¸Ð¾Ð´ на карантина."</item> + <item>"Може вÑе още да Ñте ноÑител на заразата дори ако вече не проÑвÑвате Ñимптоми и отново Ñе чувÑтвате добре. По тази причина, молÑ, не нарушавайте ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð¿ÐµÑ€Ð¸Ð¾Ð´ на изолациÑ."</item> </string-array> <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Готово"</string> @@ -1395,9 +1406,9 @@ <!-- XHED: submission status card positive result subtitle --> <string name="submission_status_card_positive_result_subtitle">"МолÑ, не забравÑйте:"</string> <!-- YTXT: text for contagious card --> - <string name="submission_status_card_positive_result_contagious">"Вие Ñте ноÑител на заразата. Ðеобходимо е да Ñе Ñамоизолирате."</string> + <string name="submission_status_card_positive_result_contagious">"Има голÑма вероÑтноÑÑ‚ да Ñте ноÑител на заразата. Изолирайте Ñе от другите хора."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"От Ñлужбата за общеÑтвено здравеопазване (Gesundheitsamt) ще Ñе Ñвържат Ñ Ð’Ð°Ñ Ð² Ñледващите нÑколко дни."</string> + <string name="submission_status_card_positive_result_contact">"От Ñлужбата за общеÑтвено здравеопазване (Gesundheitsamt) може да Ñе Ñвържат Ñ Ð’Ð°Ñ Ð¿Ñ€ÐµÐ· Ñледващите нÑколко дни."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"Споделете Ñвоите Ñлучайни ИД кодове, за да предупредите оÑтаналите потребители."</string> @@ -1991,7 +2002,7 @@ <!-- XHED: Trace location poster title --> <string name="trace_location_organiser_poster_title">"ВерÑÐ¸Ñ Ð·Ð° печат"</string> <!-- XHED: Trace location check-ins consent screen title --> - <string name="trace_location_attendee_consent_title">"Ще Ñподелите ли Ñвоите региÑтрации от локациите, които Ñте поÑетили?"</string> + <string name="trace_location_attendee_consent_title">"Ще Ñподелите ли Ñвоите региÑтрации?"</string> <!-- XTXT: Trace location check-ins consent screen header description --> <string name="trace_location_attendee_consent_header_description">"Предупредете оÑтаналите, които Ñъщо Ñа Ñе региÑтрирали Ñ Ð²Ð°Ñ. Вашите лични данни нÑма да бъдат Ñподелени."</string> <!-- XBUT: Trace location check-ins consent screen header button --> @@ -2025,9 +2036,9 @@ <!-- XHED: Incompitability card title --> <string name="incompatible_headline">"Предупреждение за неÑъвмеÑтимоÑÑ‚"</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_advertising_not_supported">"Вашето мобилно уÑтройÑтво може да поучава извеÑÑ‚Ð¸Ñ Ð·Ð° COVID-19 чрез Bluetooth, но не може да изпраща такива. Това означава, че Вие ще получавате предупреждениÑ, но без да извеÑÑ‚Ñвате околните, че Ñа били в контакт Ñ Ð²Ð°Ñ. Можете както да получавате, така и да изпращате Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð² ÑледÑтвие на региÑтрации в дадена локациÑ."</string> + <string name="incompatible_advertising_not_supported">"Вашето мобилно уÑтройÑтво може да поучава извеÑÑ‚Ð¸Ñ Ð·Ð° излагане на COVID-19 чрез Bluetooth, но не може да изпраща такива. Това означава, че може да получавате Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð·Ð° такова излагане през този интерфейÑ, но нÑма да можете да извеÑÑ‚Ñвате околните, че Ñа били в контакт Ñ Ð²Ð°Ñ. Можете както да получавате, така и да изпращате Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð²ÑледÑтвие на региÑтрации на дадена локациÑ."</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_scanning_not_supported">"Вашето мобилно уÑтройÑтво не може нито да изпраща, нито да получава извеÑÑ‚Ð¸Ñ Ð·Ð° COVID-19 чрез Bluetooth. Можете както да получавате, така и да изпращате Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð² ÑледÑтвие на региÑтрации в дадена локациÑ."</string> + <string name="incompatible_scanning_not_supported">"ВашиÑÑ‚ Ñмартфон не може нито да изпраща, нито да получава извеÑÑ‚Ð¸Ñ Ð·Ð° излагане на COVID-19 чрез Bluetooth. Можете както да получавате, така и да изпращате Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð²ÑледÑтвие на региÑтрации на дадена локациÑ."</string> <!-- XTXT: Incompitability faq link for partial incompatibility --> <string name="incompatible_link_advertising_not_supported">"https://www.coronawarn.app/en/faq/#part_incompat"</string> <!-- XTXT: Incompitability faq link for full incompatibility --> diff --git a/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..4bbb3a06eefc2357b8f880867554afdb1e18a179 --- /dev/null +++ b/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools"> + <!-- XTXT: Vaccination Details birth date --> + <string name="vaccination_details_birth_date">"Дата на раждане %1$s"</string> + <!-- XTXT: Vaccination Details certificate date --> + <string name="vaccination_details_certificate_date">"Дата на вакÑиниране"</string> + <!-- XTXT: Vaccination Details vaccine name --> + <string name="vaccination_details_vaccine_name">"ВакÑина"</string> + <!-- XTXT: Vaccination Details vaccine manufacturer --> + <string name="vaccination_details_vaccine_manufacturer">"Производител"</string> + <!-- XTXT: Vaccination Details vaccine type --> + <string name="vaccination_details_vaccine_medical_product_name">"Вид вакÑина"</string> + <!-- XTXT: Vaccination Details certificate issuer --> + <string name="vaccination_details_certificate_issuer">"Издадено от"</string> + <!-- XTXT: Vaccination Details certificate country --> + <string name="vaccination_details_certificate_country">"Държава"</string> + <!-- XTXT: Vaccination Details certificate id --> + <string name="vaccination_details_certificate_id">"Сертификационен номер"</string> + <!-- XTXT: Vaccination Details subtitle--> + <string name="vaccination_details_subtitle">"ВакÑинационен Ñертификат"</string> + <!-- XTXT: Vaccination Details title--> + <string name="vaccination_details_title">"ВакÑиниране %1$d от %2$d"</string> + <!-- XTXT: Vaccination Qr Code card title--> + <string name="vaccination_qrcode_card_title">"ВакÑинационен Ñертификат %1$d от %2$d"</string> + <!-- XTXT: Vaccination Qr Code card subtitle--> + <string name="vaccination_qrcode_card_subtitle">"ВакÑиниране %1$s - валидноÑÑ‚ до %2$s"</string> + + <!-- XTXT: Vaccination List title--> + <string name="vaccination_list_title">"Електронно доказателÑтво за вакÑиниране"</string> + <!-- XTXT: Vaccination List complete vaccination subtitle--> + <string name="vaccination_list_complete_vaccination_subtitle">"ВакÑинационна защита Ñрещу SARS-CoV-2"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_name_card_subtitle">"Дата на раждане %1$s"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_title">"ВакÑиниране %1$d от %2$d"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_subtitle">"Извършено на %1$s"</string> + <!-- XTXT: Vaccination List immunity information card body--> + <plurals name="vaccination_list_immunity_card_body"> + <item quantity="one">"Получихте вÑички планирани за момента вакÑинации, но защитата ви от вакÑиниране ще е пълна едва Ñлед %1$d ден."</item> + <item quantity="other">"Получихте вÑички планирани за момента вакÑинации, но защитата ви от вакÑиниране ще е пълна едва Ñлед %1$d дни."</item> + <item quantity="zero">"Получихте вÑички планирани за момента вакÑинации, но защитата ви от вакÑиниране ще е пълна едва Ñлед %1$d дни."</item> + <item quantity="two">"Получихте вÑички планирани за момента вакÑинации, но защитата ви от вакÑиниране ще е пълна едва Ñлед %1$d дни."</item> + <item quantity="few">"Получихте вÑички планирани за момента вакÑинации, но защитата ви от вакÑиниране ще е пълна едва Ñлед %1$d дни."</item> + <item quantity="many">"Получихте вÑички планирани за момента вакÑинации, но защитата ви от вакÑиниране ще е пълна едва Ñлед %1$d дни."</item> + </plurals> + <!-- XBUT: Vaccination List register additional vaccination button --> + <string name="vaccination_list_register_new_vaccination_button">"РегиÑтрирайте друго вакÑиниране"</string> + <!-- XBUT: Vaccination List delete button --> + <string name="vaccination_list_delete_button">"Изтриване"</string> + <!-- XTXT: Vaccination List deletion dialog title--> + <string name="vaccination_list_deletion_dialog_title">"Желаете ли да изтриете Ñертификата за вакÑиниране?"</string> + <!-- XTXT: Vaccination List deletion dialog message--> + <string name="vaccination_list_deletion_dialog_message">"Ðко изтриете Ñертификата за вакÑиниране, приложението вече нÑма да може да използва вакÑинациÑта за удоÑтоверÑване на Ð²Ð°ÑˆÐ¸Ñ Ð²Ð°ÐºÑинационен ÑтатуÑ."</string> + <!-- XBUT: Vaccination List deletion dialog positive button--> + <string name="vaccination_list_deletion_dialog_positive_button">"Изтриване"</string> + <!-- XBUT: Vaccination List deletion dialog negative button--> + <string name="vaccination_list_deletion_dialog_negative_button">"Отказ"</string> + <!-- XACT: Vaccination List Qr-Code for screen readers --> + <string name="vaccination_list_qr_code_accessibility">"QR код"</string> + + <!-- #################################### + Homescreen cards + ###################################### --> + <!-- XHED: Title for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_registration_title">"Добавете Ñертификат за вакÑиниране"</string> + <!-- YTXT: Body text for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_registration_body">"Добавете вакÑинационни Ñертификати в приложението, за да Ñа винаги Ñ Ð²Ð°Ñ. За да направите това, Ñканирайте QR кода от Ð²Ð°ÑˆÐ¸Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚."</string> + <!-- XBUT: button for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_register">"ДобавÑне"</string> + <!-- XHED: Homescreen vaccination status card title --> + <string name="vaccination_card_status_title">"Електронно доказателÑтво за вакÑиниране"</string> + <!-- XHED: Homescreen vaccination status card vaccination name --> + <string name="vaccination_card_status_vaccination_name">"ВакÑиниране Ñрещу SARS-CoV-2"</string> + <!-- XTXT: Homescreen card incomplete vaccination status label --> + <string name="vaccination_card_status_vaccination_incomplete">"ВакÑинирането не е пълно"</string> + <!-- XTXT: Homescreen card complete vaccination status label --> + <plurals name="vaccination_card_status_vaccination_complete" tools:ignore="UnusedQuantity"> + <item quantity="one">"Пълна защита от вакÑиниране Ñлед %1$d ден"</item> + <item quantity="other">"Пълна защита от вакÑиниране Ñлед %1$d дни"</item> + <item quantity="zero">"Пълна защита от вакÑиниране Ñлед %1$d дни"</item> + <item quantity="two">"Пълна защита от вакÑиниране Ñлед %1$d дни"</item> + <item quantity="few">"Пълна защита от вакÑиниране Ñлед %1$d дни"</item> + <item quantity="many">"Пълна защита от вакÑиниране Ñлед %1$d дни"</item> + </plurals> + + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_invalid">"Този QR код не е валиден Ñертификат за вакÑиниране."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_not_yet_supported">"Този Ñертификат за вакÑиниране вÑе още не Ñе поддържа във верÑиÑта на вашето приложение. МолÑ, актуализирайте приложението Ñи или Ñе Ñвържете Ñ Ð³Ð¾Ñ€ÐµÑ‰Ð°Ñ‚Ð° Ð»Ð¸Ð½Ð¸Ñ Ð·Ð° техничеÑки проблеми от â€œÐ˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° приложениетоâ€."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_scan_again">"Сертификатът за вакÑиниране не може да бъде запазен на Ñмартфона ви. МолÑ, опитайте отново по-къÑно или Ñе Ñвържете Ñ Ð³Ð¾Ñ€ÐµÑ‰Ð°Ñ‚Ð° Ð»Ð¸Ð½Ð¸Ñ Ð·Ð° техничеÑки проблеми от â€œÐ˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° приложениетоâ€."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_already_registered">"Сертификатът за вакÑиниране вече е региÑтриран в приложението ви."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_different_person">"Личната Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð² този Ñертификат за вакÑиниране не ÑъответÑтва на тази във вече региÑтрираните Ñертификати. Ð’ приложението можете да региÑтрирате Ñертификати Ñамо за едно лице."</string> + + <!-- XTXT: Vaccination Consent title--> + <string name="vaccination_consent_title">"Вашето ÑъглаÑие"</string> + <!-- XTXT: Vaccination Consent subtitle--> + <string name="vaccination_consent_headline">"Добавете Ñертификат за вакÑиниране"</string> + <!-- XTXT: Vaccination Consent subtitle of qr info --> + <string name="vaccination_consent_info_subtitle_text">"Добавете ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¸Ñ Ñи Ñертификат за вакÑиниране. Когато вакÑинационната ви защита бъде завършена, можете да предÑтавÑте QR кода в приложението Ñи като доказателÑтво за вакÑиниране."</string> + <!-- XTXT: Vaccination Consent text of qr info --> + <string name="vaccination_consent_qr_info_text">"За да добавите Ñертификат за вакÑиниране в приложението, Ñканирайте QR кода, който Ñте получили по време на вакÑинирането."</string> + <!-- XTXT: Vaccination Consent qr code text --> + <string name="vaccination_consent_qr_info_qr_code_text">"Приложението чете информациÑта от QR кода и го запазва в защитена облаÑÑ‚ в Ñмартфона ви."</string> + <!-- XTXT: Vaccination Consent time text --> + <string name="vaccination_consent_qr_info_time_text">"Данните ще оÑтанат в Ñмартфона. Те ще бъдат предадени на другите Ñамо ако предÑтавите вакÑÐ¸Ð½Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¸Ñ Ñи Ñертификат за проверка."</string> + <!-- XTXT: Text for vaccination consent legal information button --> + <string name="vaccination_consent_onboarding_legal_information">"За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¾Ñ‡ÐµÑ‚ÐµÑ‚Ðµ декларациÑта за поверителноÑÑ‚."</string> + <!-- XBUT: Text for vaccination consent accept button --> + <string name="vaccination_consent_accept_button">"Ðапред"</string> + +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml index ee14f5eb4790c3edeb18e38e071ea6a167764370..a6b5ffce0827295c024e61a13fadf66f586c63cc 100644 --- a/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml @@ -7,7 +7,7 @@ <!-- XHED: Register test homescreen card: title --> <string name="ag_homescreen_card_test_register_title">"Test registrieren"</string> <!-- XTXT: Register test homescreen card: body --> - <string name="ag_homescreen_card_test_register_body">"Nutzen Sie die App, um Ihre Testergebnisse abrufen und schneller warnen zu können."</string> + <string name="ag_homescreen_card_test_register_body">"Nutzen Sie die App, um Ihre Tests zu registrieren und Testergebnisse abzurufen, um andere schneller warnen zu können."</string> <!-- #################################### Homescreen cards - common buttons diff --git a/Corona-Warn-App/src/main/res/values-de/strings.xml b/Corona-Warn-App/src/main/res/values-de/strings.xml index dd1ea83e090b1f44d0901bf97433629f5c5192eb..60f2884212e2a8ba436d25e62a778f40f0d618c5 100644 --- a/Corona-Warn-App/src/main/res/values-de/strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/strings.xml @@ -412,7 +412,9 @@ <!-- YTXT: onboarding(together) - paragraph --> <string name="onboarding_body_4">"Auf Wunsch können Sie mit der App Ihren persönlichen Infektionsstatus nachweisen (z.B. negativer Schnelltest). Bitte beachten Sie, dass Sie grundsätzlich nicht zum Nachweis Ihres Infektionsstatus per App verpflichtet sind. Sie können Ihren Infektionsstatus im Rahmen der rechtlichen Bestimmungen an Ihrem Aufenthaltsort auch auf andere Weise nachweisen."</string> <!-- YTXT: onboarding(together) - paragraph --> - <string name="onboarding_body_5">"Die App merkt sich Begegnungen zwischen Menschen, indem ihre Smartphones verschlüsselte Zufalls-IDs austauschen. Persönliche Daten werden dabei nicht ausgetauscht."</string> + <string name="onboarding_body_5">"Ebenso können Sie Ihren persönlichen Impfstatus nachweisen."</string> + <!-- YTXT: onboarding(together) - paragraph --> + <string name="onboarding_body_6">"Die App merkt sich Begegnungen zwischen Menschen, indem ihre Smartphones verschlüsselte Zufalls-IDs austauschen. Persönliche Daten werden dabei nicht ausgetauscht."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"Eine vielfältige Gruppe in einer Stadt benutzt Smartphones."</string> <!-- XACT: Onboarding (privacy) page title --> @@ -918,7 +920,7 @@ <!-- XBUT: Button for bugreporting share log screen --> <string name="debugging_debuglog_share_log_button">"Einverstanden und senden"</string> <!-- XHED: Title for log upload history --> - <string name="debugging_debuglog_uploadhistory_title">"ID Historie"</string> + <string name="debugging_debuglog_uploadhistory_title">"ID-Historie"</string> <!-- YTXT: Description for log upload history --> <string name="debugging_debuglog_uploadhistory_description">"Hier sehen Sie die IDs Ihrer Fehleranalyse-Protokolle."</string> @@ -1071,6 +1073,10 @@ <string name="submission_test_result_pending_steps_waiting_heading">"Ihr Testergebnis liegt noch nicht vor."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> <string name="submission_test_result_pending_steps_waiting_body">"Sobald Ihr Testergebnis vorliegt, wird es Ihnen in der App angezeigt.\n\nSie bekommen Ihr Testergebnis auch außerhalb der App mitgeteilt. Falls Ihr Test positiv ist, bekommen Sie vom Gesundheitsamt eine Mitteilung.\n\nWenn Ihnen außerhalb der App ein positives Testergebnis mitgeteilt wurde, entfernen Sie den aktuell in der App registrierten Test. Rufen Sie die unter "TAN anfragen" angegebene Nummer an, um eine TAN zu erhalten. Registrieren Sie dann Ihr Testergebnis mithilfe der TAN in der App."</string> + <!-- XHED: Page headline for pending test result next steps --> + <string name="submission_test_result_pending_steps_waiting_pcr_heading">"Ihr Testergebnis liegt noch nicht vor."</string> + <!-- YTXT: Body text for next steps section of waiting test result page --> + <string name="submission_test_result_pending_steps_waiting_pcr_body">"Sobald Ihr Testergebnis vorliegt, wird es Ihnen in der App angezeigt.\n\nSie bekommen Ihr Testergebnis auch außerhalb der App mitgeteilt. Falls Ihr Test positiv ist, bekommen Sie vom Gesundheitsamt eine Mitteilung.\n\nWenn Ihnen außerhalb der App ein positives Testergebnis mitgeteilt wurde, entfernen Sie den aktuell in der App registrierten Test. Rufen Sie die unter "TAN anfragen" angegebene Nummer an, um eine TAN zu erhalten. Registrieren Sie dann Ihr Testergebnis mithilfe der TAN in der App."</string> <!-- XHED: Page headline for results next steps --> <string name="submission_test_result_steps_added_rat_heading">"Ihr Schnelltest wurde hinzugefügt."</string> <!-- XHED: Page headline for pending test result next steps --> @@ -1172,9 +1178,9 @@ <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> <string name="submission_dispatcher_already_positive_subheadline">"Ihr PCR-Test ist positiv?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"Test mit QR-Code"</string> + <string name="submission_dispatcher_card_qr">"QR-Code scannen"</string> <!-- YTXT: Body text for QR code dispatcher option --> - <string name="submission_dispatcher_qr_card_text">"Registrieren Sie Ihren Test, indem Sie den QR-Code Ihres Testdokuments scannen."</string> + <string name="submission_dispatcher_qr_card_text">"Erhalten Sie Ihr Testergebnis in der App und warnen Sie andere."</string> <!-- YTXT: Dispatcher text for TAN code option --> <string name="submission_dispatcher_card_tan_code">"TAN für PCR-Test eingeben"</string> <!-- YTXT: Body text for TAN code dispatcher option --> diff --git a/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml index c999b32ca36f2c04f770d2f36ded9b0e26ab45f9..396a5e8edea728688b00f2ec1255afdfa2795b81 100644 --- a/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml @@ -27,6 +27,8 @@ <!-- XTXT: Vaccination List title--> <string name="vaccination_list_title">Digitaler Impfnachweis</string> + <!-- XTXT: Vaccination List complete vaccination subtitle--> + <string name="vaccination_list_complete_vaccination_subtitle">SARS-CoV-2-Impfschutz</string> <!-- XTXT: Vaccination List top card subtitle--> <string name="vaccination_list_name_card_subtitle">geboren %1$s</string> <!-- XTXT: Vaccination List top card subtitle--> diff --git a/Corona-Warn-App/src/main/res/values-en/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-en/antigen_strings.xml index f8f1e06cab846bc72146e8817815dc8e2900d89c..41e6204345ae0789126f8f380bff107c32f28afa 100644 --- a/Corona-Warn-App/src/main/res/values-en/antigen_strings.xml +++ b/Corona-Warn-App/src/main/res/values-en/antigen_strings.xml @@ -6,7 +6,7 @@ <!-- XHED: Register test homescreen card: title --> <string name="ag_homescreen_card_test_register_title">"Register Your Test"</string> <!-- XTXT: Register test homescreen card: body --> - <string name="ag_homescreen_card_test_register_body">"Use the app to retrieve your test results, so you can warn others more quickly."</string> + <string name="ag_homescreen_card_test_register_body">"Use the app to register your tests and retrieve your test results, so you can warn others more quickly."</string> <!-- #################################### Homescreen cards - common buttons @@ -142,7 +142,7 @@ <!-- XHED: Create RAT profile card title --> <string name="rat_profile_create_card_title">"Create Rapid Test Profile"</string> <!-- XTXT: Create RAT profile card subtitle --> - <string name="rat_profile_create_card_subtitle">"You can create a profile with your personal data, which you can submit via QR code during every rapid test."</string> + <string name="rat_profile_create_card_subtitle">"You can create a profile with your personal data, which you can submit via QR code to every participating testing point."</string> <!-- XHED: Open RAT profile card title --> <string name="rat_profile_open_card_title">"Rapid Test Profile"</string> <!-- XTXT: Open RAT profile card subtitle --> @@ -158,7 +158,7 @@ <!-- XBUT: Create RAT profile save button --> <string name="rat_profile_create_button">"Save"</string> <!-- XTXT: Create RAT profile description --> - <string name="rat_profile_create_description">"Save your personal data as a QR code to speed up registration at testing points."</string> + <string name="rat_profile_create_description">"You can create a profile with your personal data, which you can submit via QR code to every participating testing point."</string> <!-- XTXT: Create RAT profile street hint --> <string name="rat_profile_create_street_hint">"Street and House Number"</string> <!-- XTXT: Create RAT profile post code hint --> @@ -173,7 +173,7 @@ <!--RAT profile onboarding--> <string name="rat_profile_onboarding_image_content_description">"A woman with a smartphone in her hand is standing in front of a building. A QR code symbolizes the rapid test profile to be scanned."</string> <!-- XTXT: Create RAT profile onboarding title --> - <string name="rat_profile_onboarding_title">"Save your personal data as a QR code to speed up registration at testing points."</string> + <string name="rat_profile_onboarding_title">"You can create a profile with your personal data, which you can submit via QR code to every participating testing point."</string> <!-- XTXT: Create RAT profile onboarding subtitle --> <string name="rat_profile_onboarding_subtitle">"When you create a rapid test profile, you will not have to fill out your personal data again before every rapid test."</string> <!-- XTXT: Create RAT profile onboarding next button --> diff --git a/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml index 6d2df0cbdfe9c54d7f90bea7d579bbc439c72712..d323982a0fcdcb275c2296e8ba8af2a7a94781c1 100644 --- a/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml +++ b/Corona-Warn-App/src/main/res/values-en/contact_diary_strings.xml @@ -31,7 +31,7 @@ <!-- XTXT: Title for the contact diary onboarding screen --> <string name="contact_diary_information_card_title">"Keep track of your contacts."</string> <!-- XTXT: Contact diary onboarding screen --> - <string name="contact_diary_onboarding_body">"Create an overview of your contacts in the last 14 days, so you’ll have a complete list at hand quickly if needed."</string> + <string name="contact_diary_onboarding_body">"Create an overview of your contacts in the last 14 days, so you’ll have a complete list at hand quickly if needed. Your exposures are also displayed here."</string> <!-- XTXT: Contact diary onboarding screen first functionality --> <string name="contact_diary_onboarding_functionality_first_section">"Enter the people you have met."</string> <!-- XTXT: Contact diary onboarding screen second functionality --> diff --git a/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml index 46730e89a2f7de86a8d75d92998a4651f4d70458..5302462e1984ec8a7b1b38c1fffa68c67b1c991a 100644 --- a/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml +++ b/Corona-Warn-App/src/main/res/values-en/release_info_strings.xml @@ -16,26 +16,22 @@ <!-- XHED: Titles for the release info screen bullet points --> <string-array name="new_release_title"> - <item>"Record Troubleshooting Logs"</item> - <item>"Create Rapid Test Profiles"</item> + <item>"Digital Proof of Vaccination"</item> </string-array> <!-- XTXT: Text bodies for the release info screen bullet points --> <string-array name="new_release_body"> - <item>"You can now generate an error log in the technical support feature for the app. It records the steps that you perform in the app, to simplify the analysis of potential errors and help us correct them more quickly."</item> - <item>"You can now create a rapid test profile in your personal data. Your profile can then be scanned at testing points quickly and easily via QR code."</item> + <item>"You can now add your vaccination certificates in the app and present them via QR code. The app displays full vaccination protection 14 days after the final vaccination."</item> </string-array> <!-- XTXT: Text labels that will be converted to Links --> <string-array name="new_release_linkified_labels"> <item/> - <item/> </string-array> <!-- XTXT: URL destinations for the lables in new_release_linkified_labels --> <string-array name="new_release_target_urls"> <item/> - <item/> </string-array> </resources> \ 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 index 10c3f7c018b7ae2c581025ec93029ee05f31b48d..08e17636898a81ca4b380c7e6f3baf6a56b1a3ed 100644 --- a/Corona-Warn-App/src/main/res/values-en/strings.xml +++ b/Corona-Warn-App/src/main/res/values-en/strings.xml @@ -411,7 +411,9 @@ <!-- YTXT: onboarding(together) - paragraph --> <string name="onboarding_body_4">"If you want, you can use the app to prove your personal infection status (a negative rapid test, for example). Please note, however, that you are under no obligation to use the app to prove your infection status. You can also prove your infection status in another manner compliant with the legal regulations at your residence."</string> <!-- YTXT: onboarding(together) - paragraph --> - <string name="onboarding_body_5">"The app logs encounters between individuals by exchanging encrypted, random IDs between their smartphones, whereby no personal data whatsoever is accessed."</string> + <string name="onboarding_body_5">"You can also verify your personal vaccination status."</string> + <!-- YTXT: onboarding(together) - paragraph --> + <string name="onboarding_body_6">"The app logs encounters between individuals by exchanging encrypted, random IDs between their smartphones, whereby no personal data whatsoever is accessed."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"A group of persons use their smartphones around town."</string> <!-- XACT: Onboarding (privacy) page title --> @@ -747,7 +749,7 @@ <string name="settings_privacy_preserving_analytics_title">"Share Data"</string> <!-- XTXT: privacy preserving analytics settings switch subtitle --> - <string name="settings_analytics_switch_subtitle">"Share User Data"</string> + <string name="settings_analytics_switch_subtitle">"Share Data"</string> <!-- #################################### App Information @@ -1038,7 +1040,7 @@ <!-- YTXT: Body for consent main section second point --> <string name="submission_consent_main_second_point">"Your identity will remain secret. Other users will not find out who has shared a test result."</string> <!-- YTXT: Body for consent main section third point --> - <string name="submission_consent_main_third_point">"Under “My Check-Insâ€, you can see the events and places whose checked-in guests will be warned. You can remove individual check-ins from the list to exclude them from the warning process."</string> + <string name="submission_consent_main_third_point">"Under “My Check-Insâ€, you can see the events and places whose checked-in guests will be warned. You can delete individual check-ins from the list to exclude them from the warning process."</string> <!-- YTXT: Body for consent main section fourth point --> <string name="submission_consent_main_fourth_point">"You must be at least 16 years old to grant your consent."</string> <!-- YTXT: Body for consent main section final id consent --> @@ -1053,7 +1055,7 @@ <!-- YTXT: Body for no consent section third point --> <string name="submission_no_consent_third_point">"Your identity will remain secret. Other users will not find out who has shared a test result."</string> <!-- YTXT: Body for no consent section fourth point --> - <string name="submission_no_consent_fourth_point">"Under “My Check-Insâ€, you can see the events and places whose checked-in guests will be warned. You can remove individual check-ins from the list to exclude them from the warning process."</string> + <string name="submission_no_consent_fourth_point">"Under “My Check-Insâ€, you can see the events and places whose checked-in guests will be warned. You can delete individual check-ins from the list to exclude them from the warning process."</string> <!-- YTXT: Body for no consent section fifth point --> <string name="submission_no_consent_fifth_point">"You must be at least 16 years old to grant your consent."</string> @@ -1063,13 +1065,17 @@ <!-- XHED: Page subheadline for test result --> <string name="submission_test_result_subtitle">"How this works:"</string> <!-- XHED: Page headline for results next steps --> - <string name="submission_test_result_steps_added_heading">"Test added successfully"</string> + <string name="submission_test_result_steps_added_heading">"Your PCR test was added successfully."</string> <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Your test has been stored in the Corona-Warn-App."</string> <!-- XHED: Page headline for pending test result next steps --> <string name="submission_test_result_pending_steps_waiting_heading">"Your test result is not available yet."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> - <string name="submission_test_result_pending_steps_waiting_body">"As soon as your test result becomes available, it will be displayed in the app.\n\nYou will also receive your test result outside of the app. The public health authorities will notify you, should your test be positive.\n\nIf you are notified of a positive test result outside the app, please remove the test currently registered in the app. Call the number shown under “Request TAN†to get a TAN. You can then use this TAN to register your result in the app and warn others."</string> + <string name="submission_test_result_pending_steps_waiting_body">"As soon as your test result becomes available, it will be displayed in the app.\n\nYou will also receive your test result outside of the app. The public health authorities will notify you, should your test be positive.\n\nIf you are notified of a positive test result outside the app, please delete the test currently registered in the app. Call the number shown under “Request TAN†to get a TAN. You can then use this TAN to register your result in the app and warn others."</string> + <!-- XHED: Page headline for pending test result next steps --> + <string name="submission_test_result_pending_steps_waiting_pcr_heading">"Your test result is not available yet."</string> + <!-- YTXT: Body text for next steps section of waiting test result page --> + <string name="submission_test_result_pending_steps_waiting_pcr_body">"As soon as your test result becomes available, it will be displayed in the app.\n\nYou will also receive your test result outside of the app. The public health authorities will notify you, should your test be positive.\n\nIf you are notified of a positive test result outside the app, please delete the test currently registered in the app. Call the number shown under “Request TAN†to get a TAN. You can then use this TAN to register your result in the app and warn others."</string> <!-- XHED: Page headline for results next steps --> <string name="submission_test_result_steps_added_rat_heading">"Your rapid test was added."</string> <!-- XHED: Page headline for pending test result next steps --> @@ -1101,12 +1107,21 @@ <string name="submission_test_result_positive_continue_button_with_symptoms">"Enter Symptoms"</string> <!-- XBUT: positive test result : continue button without symptoms --> <string name="submission_test_result_positive_continue_button_wo_symptoms">"Don’t Enter Symptoms"</string> + + <!-- XHED: Page headline for invalid test result screen --> - <string name="submission_test_result_invalid_steps_invalid_heading">"Your Test Result"</string> + <string name="submission_test_result_invalid_steps_invalid_heading">"Your test cannot be evaluated"</string> + + <!-- XHED: Page headline for invalid test result screen --> + <string name="submission_test_result_delete_steps_invalid_heading">"Delete Test"</string> + <!-- YTXT: Body text for next steps section of invalid test result--> - <string name="submission_test_result_invalid_steps_invalid_body">"There was a problem evaluating your test. Please contact the test center or laboratory involved to find out how to proceed.\n\nPlease delete the test from your Corona-Warn-App so that you will be able to save a new test code there, if necessary."</string> + <string name="submission_test_result_invalid_steps_invalid_body">"There was a problem evaluating your test. Please contact the test center or laboratory involved to find out how to proceed."</string> + <!-- YTXT: Body text for next steps section of invalid test result--> + <string name="submission_test_result_delete_steps_invalid_body">"Please delete the test from the Corona-Warn-App, so that you can save a new test code here if necessary."</string> + <!-- XBUT: invalid test result : remove the test button --> - <string name="submission_test_result_invalid_remove_test_button">"Remove test"</string> + <string name="submission_test_result_invalid_remove_test_button">"Delete Test"</string> <!-- XHED: Dialog title for tracing required dailog --> <string name="submission_test_result_dialog_tracing_required_title">"Exposure Logging required"</string> <!-- YTXT: Dialog text for tracing required dialog--> @@ -1116,9 +1131,9 @@ <!-- XHED: Dialog title for test removal --> <string name="submission_test_result_dialog_remove_test_title">"The test can only be scanned once."</string> <!-- YTXT: Dialog text for test removal --> - <string name="submission_test_result_dialog_remove_test_message">"If you remove the test, you can no longer retrieve your test result. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with coronavirus, the public health authority will be notified through the legally prescribed channel and will contact you."</string> + <string name="submission_test_result_dialog_remove_test_message">"If you delete the test, you can no longer retrieve your test result. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with coronavirus, the public health authority will be notified through the legally prescribed channel and will contact you."</string> <!-- XBUT: Positive button for test removal --> - <string name="submission_test_result_dialog_remove_test_button_positive">"Remove"</string> + <string name="submission_test_result_dialog_remove_test_button_positive">"Delete"</string> <!-- XBUT: Negative button for test removal --> <string name="submission_test_result_dialog_remove_test_button_negative">"Cancel"</string> <!-- XHED: Title for test result card positive --> @@ -1158,17 +1173,13 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Retrieve Test Result"</string> - <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"Retrieve your test result through the app and then warn others. You’ll protect yourself and help to stop the spread of coronavirus."</string> - <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">"Have you been tested?"</string> + <string name="submission_dispatcher_headline">"Register Your Test"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> <string name="submission_dispatcher_already_positive_subheadline">"Was your PCR test positive?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"Test with QR Code"</string> + <string name="submission_dispatcher_card_qr">"Scan QR Code"</string> <!-- YTXT: Body text for QR code dispatcher option --> - <string name="submission_dispatcher_qr_card_text">"Register your test by scanning the QR code of your test document."</string> + <string name="submission_dispatcher_qr_card_text">"Receive your test result in the app and warn others."</string> <!-- YTXT: Dispatcher text for TAN code option --> <string name="submission_dispatcher_card_tan_code">"Enter TAN for PCR Test"</string> <!-- YTXT: Body text for TAN code dispatcher option --> @@ -1236,18 +1247,18 @@ <!-- YTXT: text after submission: pcr validation --> <string name="submission_done_share_keys">"Share your random IDs so that others can be warned."</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"The public health authority will contact you within the next few days."</string> + <string name="submission_done_contagious">"The public health authority may contact you within the next few days."</string> <!-- YTXT: text after submission: isolate --> - <string name="submission_done_isolate">"You are infectious. Isolate yourself from other people."</string> + <string name="submission_done_isolate">"There is a high probability that you are infectious. Isolate yourself from other people."</string> <!-- XHED: Title for further info --> <string name="submission_done_further_info_title">"Other information:"</string> <!-- YTXT: submission done further info bullet points --> <string-array name="submission_done_further_info_bullet_points"> - <item>"Your quarantine period is usually 14 days. Please monitor how your symptoms develop closely."</item> + <item>"Your isolation period is usually 14 days. Please monitor how your symptoms develop closely."</item> <item>"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 became ill. You can use your contact journal for this: simply export the entries and then print them out or send them via e-mail."</item> <item>"Please particularly consider people who will not be notified directly by the app since they don’t own a smartphone, or haven’t installed the app."</item> - <item>"Even when you no longer have any symptoms and you feel well again, you could still be infectious, so please follow the designated quarantine period."</item> + <item>"Even when you no longer have any symptoms and you feel well again, you could still be infectious, so please follow the designated isolation period."</item> </string-array> <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Done"</string> @@ -1395,9 +1406,9 @@ <!-- XHED: submission status card positive result subtitle --> <string name="submission_status_card_positive_result_subtitle">"Please note:"</string> <!-- YTXT: text for contagious card --> - <string name="submission_status_card_positive_result_contagious">"You are infectious. Isolate yourself from other people."</string> + <string name="submission_status_card_positive_result_contagious">"There is a high probability that you are infectious. Isolate yourself from other people."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"The public health authority will contact you within the next few days."</string> + <string name="submission_status_card_positive_result_contact">"The public health authority may contact you within the next few days."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"Share your random IDs so that others can be warned."</string> @@ -1959,7 +1970,7 @@ <!-- XACT: Button/Dialog label to cancel something--> <string name="generic_action_abort">"Cancel"</string> <!-- XACT: Button/Dialog label to remove something--> - <string name="generic_action_remove">"Remove"</string> + <string name="generic_action_remove">"Delete"</string> <!-- #################################### Trace Location @@ -1991,7 +2002,7 @@ <!-- XHED: Trace location poster title --> <string name="trace_location_organiser_poster_title">"Print Version"</string> <!-- XHED: Trace location check-ins consent screen title --> - <string name="trace_location_attendee_consent_title">"Share Location Check-Ins?"</string> + <string name="trace_location_attendee_consent_title">"Share Check-Ins?"</string> <!-- XTXT: Trace location check-ins consent screen header description --> <string name="trace_location_attendee_consent_header_description">"Warn others who checked in with you. Your personal data will not be shared."</string> <!-- XBUT: Trace location check-ins consent screen header button --> @@ -2025,9 +2036,9 @@ <!-- XHED: Incompitability card title --> <string name="incompatible_headline">"Incompatibility Warning"</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_advertising_not_supported">"Your smartphone can only receive COVID-19 notifications via Bluetooth, but not send them. This means you can be warned of exposures through this interface, but you cannot warn others of exposures yourself. You can send and receive warnings that result from check-ins."</string> + <string name="incompatible_advertising_not_supported">"Your smartphone can only receive COVID-19 exposure notifications via Bluetooth, but not send them. This means you can be warned of exposures through this interface, but you cannot warn others of exposures yourself. You can send and receive warnings that result from check-ins."</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_scanning_not_supported">"Your smartphone cannot send or receive COVID-19 notifications via Bluetooth. You can send and receive warnings that result from check-ins."</string> + <string name="incompatible_scanning_not_supported">"Your smartphone cannot send or receive COVID-19 exposure notifications via Bluetooth. You can send and receive warnings that result from check-ins."</string> <!-- XTXT: Incompitability faq link for partial incompatibility --> <string name="incompatible_link_advertising_not_supported">"https://www.coronawarn.app/en/faq/#part_incompat"</string> <!-- XTXT: Incompitability faq link for full incompatibility --> diff --git a/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..5d041f22fb1d1071da6b93095bb8cea41784e238 --- /dev/null +++ b/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools"> + <!-- XTXT: Vaccination Details birth date --> + <string name="vaccination_details_birth_date">"Born %1$s"</string> + <!-- XTXT: Vaccination Details certificate date --> + <string name="vaccination_details_certificate_date">"Vaccination Date"</string> + <!-- XTXT: Vaccination Details vaccine name --> + <string name="vaccination_details_vaccine_name">"Vaccine"</string> + <!-- XTXT: Vaccination Details vaccine manufacturer --> + <string name="vaccination_details_vaccine_manufacturer">"Manufacturer"</string> + <!-- XTXT: Vaccination Details vaccine type --> + <string name="vaccination_details_vaccine_medical_product_name">"Vaccine type"</string> + <!-- XTXT: Vaccination Details certificate issuer --> + <string name="vaccination_details_certificate_issuer">"Issuer"</string> + <!-- XTXT: Vaccination Details certificate country --> + <string name="vaccination_details_certificate_country">"Country"</string> + <!-- XTXT: Vaccination Details certificate id --> + <string name="vaccination_details_certificate_id">"Certification Number"</string> + <!-- XTXT: Vaccination Details subtitle--> + <string name="vaccination_details_subtitle">"Vaccination Certificate"</string> + <!-- XTXT: Vaccination Details title--> + <string name="vaccination_details_title">"Vaccination %1$d of %2$d"</string> + <!-- XTXT: Vaccination Qr Code card title--> + <string name="vaccination_qrcode_card_title">"Vaccination certificate %1$d of %2$d"</string> + <!-- XTXT: Vaccination Qr Code card subtitle--> + <string name="vaccination_qrcode_card_subtitle">"Vaccinated %1$s - valid to %2$s"</string> + + <!-- XTXT: Vaccination List title--> + <string name="vaccination_list_title">"Digital Proof of Vaccination"</string> + <!-- XTXT: Vaccination List complete vaccination subtitle--> + <string name="vaccination_list_complete_vaccination_subtitle">"SARS-CoV-2 Vaccination Protection"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_name_card_subtitle">"Born %1$s"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_title">"Vaccination %1$d of %2$d"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_subtitle">"Performed on %1$s"</string> + <!-- XTXT: Vaccination List immunity information card body--> + <plurals name="vaccination_list_immunity_card_body"> + <item quantity="one">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d day."</item> + <item quantity="other">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item> + <item quantity="zero">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item> + <item quantity="two">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item> + <item quantity="few">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item> + <item quantity="many">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item> + </plurals> + <!-- XBUT: Vaccination List register additional vaccination button --> + <string name="vaccination_list_register_new_vaccination_button">"Register Another Vaccination"</string> + <!-- XBUT: Vaccination List delete button --> + <string name="vaccination_list_delete_button">"Delete"</string> + <!-- XTXT: Vaccination List deletion dialog title--> + <string name="vaccination_list_deletion_dialog_title">"Do you want to delete the vaccination certificate?"</string> + <!-- XTXT: Vaccination List deletion dialog message--> + <string name="vaccination_list_deletion_dialog_message">"If you delete the vaccination certificate, the app can no longer use the vaccination for the verification of your vaccination status."</string> + <!-- XBUT: Vaccination List deletion dialog positive button--> + <string name="vaccination_list_deletion_dialog_positive_button">"Delete"</string> + <!-- XBUT: Vaccination List deletion dialog negative button--> + <string name="vaccination_list_deletion_dialog_negative_button">"Cancel"</string> + <!-- XACT: Vaccination List Qr-Code for screen readers --> + <string name="vaccination_list_qr_code_accessibility">"QR Code"</string> + + <!-- #################################### + Homescreen cards + ###################################### --> + <!-- XHED: Title for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_registration_title">"Add Vaccination Certificate"</string> + <!-- YTXT: Body text for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_registration_body">"Add vaccination certificates in the app so you always have them with you. To do so, scan the QR code on your document."</string> + <!-- XBUT: button for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_register">"Add"</string> + <!-- XHED: Homescreen vaccination status card title --> + <string name="vaccination_card_status_title">"Digital Proof of Vaccination"</string> + <!-- XHED: Homescreen vaccination status card vaccination name --> + <string name="vaccination_card_status_vaccination_name">"SARS-CoV-2 Vaccination"</string> + <!-- XTXT: Homescreen card incomplete vaccination status label --> + <string name="vaccination_card_status_vaccination_incomplete">"Vaccination incomplete"</string> + <!-- XTXT: Homescreen card complete vaccination status label --> + <plurals name="vaccination_card_status_vaccination_complete" tools:ignore="UnusedQuantity"> + <item quantity="one">"Full vaccination protection in %1$d day"</item> + <item quantity="other">"Full vaccination protection in %1$d days"</item> + <item quantity="zero">"Full vaccination protection in %1$d days"</item> + <item quantity="two">"Full vaccination protection in %1$d days"</item> + <item quantity="few">"Full vaccination protection in %1$d days"</item> + <item quantity="many">"Full vaccination protection in %1$d days"</item> + </plurals> + + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_invalid">"This QR code is not a valid vaccination certificate."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_not_yet_supported">"This vaccination certificate is not supported in your app version yet. Please update your app or contact the technical hotline under “App Informationâ€."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_scan_again">"The vaccination certificate could not be saved on your smartphone. Please try again later or contact the technical hotline under “App Informationâ€."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_already_registered">"The vaccination certificate is already registered in your app."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_different_person">"The personal information of this vaccination certificate does not match that of the certificates already registered. You can only register certificates for one person in the app."</string> + + <!-- XTXT: Vaccination Consent title--> + <string name="vaccination_consent_title">"Your Consent"</string> + <!-- XTXT: Vaccination Consent subtitle--> + <string name="vaccination_consent_headline">"Add Vaccination Certificate"</string> + <!-- XTXT: Vaccination Consent subtitle of qr info --> + <string name="vaccination_consent_info_subtitle_text">"Add your digital vaccination certificate in the app. As soon as your vaccination protection is complete, you can present the QR code in your app as proof of your vaccination."</string> + <!-- XTXT: Vaccination Consent text of qr info --> + <string name="vaccination_consent_qr_info_text">"To add a vaccination certificate in the app, scan the QR code that you received during your vaccination."</string> + <!-- XTXT: Vaccination Consent qr code text --> + <string name="vaccination_consent_qr_info_qr_code_text">"The app reads the information from the QR code and saves it in a secure area on your smartphone."</string> + <!-- XTXT: Vaccination Consent time text --> + <string name="vaccination_consent_qr_info_time_text">"The data will remain on the smartphone. It will only be transmitted to others if you present your vaccination certificate for verification."</string> + <!-- XTXT: Text for vaccination consent legal information button --> + <string name="vaccination_consent_onboarding_legal_information">"For more information, please refer to the privacy notice."</string> + <!-- XBUT: Text for vaccination consent accept button --> + <string name="vaccination_consent_accept_button">"Continue"</string> + +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-pl/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-pl/antigen_strings.xml index 6a8bc292e6f2839aae216bdd19828c011f27fd62..4ecc1f38d7c99bcc2b1ccc94e187062cd6e672a5 100644 --- a/Corona-Warn-App/src/main/res/values-pl/antigen_strings.xml +++ b/Corona-Warn-App/src/main/res/values-pl/antigen_strings.xml @@ -6,7 +6,7 @@ <!-- XHED: Register test homescreen card: title --> <string name="ag_homescreen_card_test_register_title">"Zarejestruj test"</string> <!-- XTXT: Register test homescreen card: body --> - <string name="ag_homescreen_card_test_register_body">"Korzystaj z aplikacji do pobierania wyników swoich badaÅ„, aby szybciej ostrzegać innych."</string> + <string name="ag_homescreen_card_test_register_body">"Korzystaj z aplikacji do rejestrowania swoich testów i pobierania ich wyników, aby szybciej ostrzegać innych."</string> <!-- #################################### Homescreen cards - common buttons @@ -142,7 +142,7 @@ <!-- XHED: Create RAT profile card title --> <string name="rat_profile_create_card_title">"Utwórz profil szybkiego testu"</string> <!-- XTXT: Create RAT profile card subtitle --> - <string name="rat_profile_create_card_subtitle">"Możesz utworzyć profil ze swoimi danymi osobowymi, który bÄ™dziesz przesyÅ‚ać za pomocÄ… kodu QR podczas wykonywania każdego szybkiego testu."</string> + <string name="rat_profile_create_card_subtitle">"Możesz utworzyć profil ze swoimi danymi osobowymi, który bÄ™dziesz przesyÅ‚ać za pomocÄ… kodu QR do każdego uczestniczÄ…cego punktu testowania."</string> <!-- XHED: Open RAT profile card title --> <string name="rat_profile_open_card_title">"Profil szybkiego testu"</string> <!-- XTXT: Open RAT profile card subtitle --> @@ -158,7 +158,7 @@ <!-- XBUT: Create RAT profile save button --> <string name="rat_profile_create_button">"Zapisz"</string> <!-- XTXT: Create RAT profile description --> - <string name="rat_profile_create_description">"Zapisz swoje dane osobowe w postaci kodu QR, aby przyspieszyć rejestracjÄ™ w punktach testowania."</string> + <string name="rat_profile_create_description">"Możesz utworzyć profil ze swoimi danymi osobowymi, który bÄ™dziesz przesyÅ‚ać za pomocÄ… kodu QR do każdego uczestniczÄ…cego punktu testowania."</string> <!-- XTXT: Create RAT profile street hint --> <string name="rat_profile_create_street_hint">"Ulica i numer domu"</string> <!-- XTXT: Create RAT profile post code hint --> @@ -173,7 +173,7 @@ <!--RAT profile onboarding--> <string name="rat_profile_onboarding_image_content_description">"Przed budynkiem stoi kobieta ze smartfonem w dÅ‚oni. Kod QR symbolizuje profil szybkiego testu do zeskanowania."</string> <!-- XTXT: Create RAT profile onboarding title --> - <string name="rat_profile_onboarding_title">"Zapisz swoje dane osobowe w postaci kodu QR, aby przyspieszyć rejestracjÄ™ w punktach testowania."</string> + <string name="rat_profile_onboarding_title">"Możesz utworzyć profil ze swoimi danymi osobowymi, który bÄ™dziesz przesyÅ‚ać za pomocÄ… kodu QR do każdego uczestniczÄ…cego punktu testowania."</string> <!-- XTXT: Create RAT profile onboarding subtitle --> <string name="rat_profile_onboarding_subtitle">"DziÄ™ki utworzeniu profilu szybkiego testu, nie bÄ™dziesz musiaÅ‚(a) ponownie wypeÅ‚niać swoich danych osobowych przed wykonaniem szybkiego testu."</string> <!-- XTXT: Create RAT profile onboarding next button --> diff --git a/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml index 852a7b72edfe78f8c7bee51ea27b859426410336..db68e982dfac05b2d6862c89aadd7f113c60398f 100644 --- a/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml +++ b/Corona-Warn-App/src/main/res/values-pl/release_info_strings.xml @@ -16,26 +16,22 @@ <!-- XHED: Titles for the release info screen bullet points --> <string-array name="new_release_title"> - <item>"Rejestruj dzienniki rozwiÄ…zywania problemów"</item> - <item>"Utwórz profile szybkich testów"</item> + <item>"Cyfrowy dowód szczepienia"</item> </string-array> <!-- XTXT: Text bodies for the release info screen bullet points --> <string-array name="new_release_body"> - <item>"Możesz teraz wygenerować dziennik bÅ‚Ä™dów w funkcji pomocy technicznej dla aplikacji. Rejestruje on kroki, które wykonujesz w aplikacji, aby uproÅ›cić analizÄ™ potencjalnych bÅ‚Ä™dów i pomóc nam szybciej je poprawić."</item> - <item>"Możesz teraz utworzyć profil szybkiego testu w swoich danych osobowych. Twój profil bÄ™dzie można później w szybki i Å‚atwy sposób zeskanować w punktach testowania za pomocÄ… kodu QR."</item> + <item>"Teraz możesz dodać swoje Å›wiadectwa szczepienia w aplikacji i okazywać je za pomocÄ… kodu QR. Aplikacja wyÅ›wietla peÅ‚nÄ… ochronÄ™ poszczepiennÄ… 14 dni po ostatnim szczepieniu."</item> </string-array> <!-- XTXT: Text labels that will be converted to Links --> <string-array name="new_release_linkified_labels"> <item/> - <item/> </string-array> <!-- XTXT: URL destinations for the lables in new_release_linkified_labels --> <string-array name="new_release_target_urls"> <item/> - <item/> </string-array> </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-pl/strings.xml b/Corona-Warn-App/src/main/res/values-pl/strings.xml index 84e7c66fb85d5592fac4dac5141ee167fde65e2a..0ceebd83a9b4b094d92da9609691f7ec2ddfad30 100644 --- a/Corona-Warn-App/src/main/res/values-pl/strings.xml +++ b/Corona-Warn-App/src/main/res/values-pl/strings.xml @@ -411,7 +411,9 @@ <!-- YTXT: onboarding(together) - paragraph --> <string name="onboarding_body_4">"JeÅ›li chcesz, możesz użyć aplikacji, aby udowodnić swój osobisty status dotyczÄ…cy zakażenia (na przykÅ‚ad negatywny wynik szybkiego testu). PamiÄ™taj jednak, że nie masz obowiÄ…zku korzystania z aplikacji w celu potwierdzenia swojego statusu dotyczÄ…cego zakażenia. Możesz również udowodnić swój status dotyczÄ…cy zakażenia w inny sposób, zgodny z przepisami prawnymi obowiÄ…zujÄ…cymi w Twoim miejscu zamieszkania."</string> <!-- YTXT: onboarding(together) - paragraph --> - <string name="onboarding_body_5">"Aplikacja rejestruje kontakty miÄ™dzy osobami poprzez wymianÄ™ zaszyfrowanych, losowych identyfikatorów miÄ™dzy ich smartfonami bez uzyskiwania dostÄ™pu do danych osobowych."</string> + <string name="onboarding_body_5">"Ponadto masz możliwość weryfikacji swojego osobistego statusu szczepienia."</string> + <!-- YTXT: onboarding(together) - paragraph --> + <string name="onboarding_body_6">"Aplikacja rejestruje kontakty miÄ™dzy osobami poprzez wymianÄ™ zaszyfrowanych, losowych identyfikatorów miÄ™dzy ich smartfonami bez uzyskiwania dostÄ™pu do danych osobowych."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"Grupa osób korzysta ze smartfonów na mieÅ›cie."</string> <!-- XACT: Onboarding (privacy) page title --> @@ -747,7 +749,7 @@ <string name="settings_privacy_preserving_analytics_title">"UdostÄ™pnij dane"</string> <!-- XTXT: privacy preserving analytics settings switch subtitle --> - <string name="settings_analytics_switch_subtitle">"UdostÄ™pnij dane użytkownika"</string> + <string name="settings_analytics_switch_subtitle">"UdostÄ™pnij dane"</string> <!-- #################################### App Information @@ -1063,13 +1065,17 @@ <!-- XHED: Page subheadline for test result --> <string name="submission_test_result_subtitle">"Jak to dziaÅ‚a:"</string> <!-- XHED: Page headline for results next steps --> - <string name="submission_test_result_steps_added_heading">"Test zostaÅ‚ dodany"</string> + <string name="submission_test_result_steps_added_heading">"Test PCR zostaÅ‚ dodany."</string> <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Twój test zostaÅ‚ zapisany w Corona-Warn-App."</string> <!-- XHED: Page headline for pending test result next steps --> <string name="submission_test_result_pending_steps_waiting_heading">"Twój wynik testu nie jest jeszcze dostÄ™pny."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> <string name="submission_test_result_pending_steps_waiting_body">"Wynik testu zostanie wyÅ›wietlony w aplikacji, jak tylko bÄ™dzie dostÄ™pny.\n\nWynik testu otrzymasz również poza aplikacjÄ…. Organ ds. zdrowia publicznego powiadomi CiÄ™, jeÅ›li wynik testu bÄ™dzie pozytywny.\n\nJeÅ›li otrzymasz powiadomienie o pozytywnym wyniku testu poza aplikacjÄ…, usuÅ„ test aktualnie zarejestrowany w aplikacji. ZadzwoÅ„ na numer podany w sekcji „PoproÅ› o TANâ€, aby otrzymać numer TAN. BÄ™dziesz mieć wówczas możliwość zarejestrowania swojego wyniku w aplikacji za pomocÄ… tego numeru, aby ostrzegać innych."</string> + <!-- XHED: Page headline for pending test result next steps --> + <string name="submission_test_result_pending_steps_waiting_pcr_heading">"Twój wynik testu nie jest jeszcze dostÄ™pny."</string> + <!-- YTXT: Body text for next steps section of waiting test result page --> + <string name="submission_test_result_pending_steps_waiting_pcr_body">"Wynik testu zostanie wyÅ›wietlony w aplikacji, jak tylko bÄ™dzie dostÄ™pny.\n\nWynik testu otrzymasz również poza aplikacjÄ…. Organ ds. zdrowia publicznego powiadomi CiÄ™, jeÅ›li wynik testu bÄ™dzie pozytywny.\n\nJeÅ›li otrzymasz powiadomienie o pozytywnym wyniku testu poza aplikacjÄ…, usuÅ„ test aktualnie zarejestrowany w aplikacji. ZadzwoÅ„ na numer podany w sekcji „PoproÅ› o TANâ€, aby otrzymać numer TAN. BÄ™dziesz mieć wówczas możliwość zarejestrowania swojego wyniku w aplikacji za pomocÄ… tego numeru, aby ostrzegać innych."</string> <!-- XHED: Page headline for results next steps --> <string name="submission_test_result_steps_added_rat_heading">"Twój szybki test zostaÅ‚ dodany."</string> <!-- XHED: Page headline for pending test result next steps --> @@ -1101,10 +1107,19 @@ <string name="submission_test_result_positive_continue_button_with_symptoms">"Wprowadź objawy"</string> <!-- XBUT: positive test result : continue button without symptoms --> <string name="submission_test_result_positive_continue_button_wo_symptoms">"Nie wprowadzaj objawów"</string> + + <!-- XHED: Page headline for invalid test result screen --> - <string name="submission_test_result_invalid_steps_invalid_heading">"Twój wynik testu"</string> + <string name="submission_test_result_invalid_steps_invalid_heading">"Ustalenie wyniku Twojego testu jest niemożliwe"</string> + + <!-- XHED: Page headline for invalid test result screen --> + <string name="submission_test_result_delete_steps_invalid_heading">"UsuÅ„ test"</string> + <!-- YTXT: Body text for next steps section of invalid test result--> - <string name="submission_test_result_invalid_steps_invalid_body">"WystÄ…piÅ‚ problem z ustaleniem wyniku Twojego testu. Skontaktuj siÄ™ z oÅ›rodkiem wykonujÄ…cym testy lub odpowiednim laboratorium, aby dowiedzieć siÄ™, jak dalej postÄ™pować.\n\nUsuÅ„ test z aplikacji Corona-Warn-App, aby w razie potrzeby móc zapisać w niej kod nowego testu."</string> + <string name="submission_test_result_invalid_steps_invalid_body">"WystÄ…piÅ‚ problem z ustaleniem wyniku Twojego testu. Skontaktuj siÄ™ z odpowiednim oÅ›rodkiem wykonujÄ…cym testy laboratorium, aby dowiedzieć siÄ™, jak dalej postÄ™pować."</string> + <!-- YTXT: Body text for next steps section of invalid test result--> + <string name="submission_test_result_delete_steps_invalid_body">"UsuÅ„ test z aplikacji Corona-Warn-App, aby w razie potrzeby można byÅ‚o zapisać w niej kod nowego testu."</string> + <!-- XBUT: invalid test result : remove the test button --> <string name="submission_test_result_invalid_remove_test_button">"UsuÅ„ test"</string> <!-- XHED: Dialog title for tracing required dailog --> @@ -1158,17 +1173,13 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Pobierz wynik testu"</string> - <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"Pobierz wynik testu za poÅ›rednictwem aplikacji, a nastÄ™pnie ostrzeż innych. Zadbasz o swoje bezpieczeÅ„stwo i pomożesz powstrzymać rozprzestrzenianie siÄ™ koronawirusa."</string> - <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">"Czy wykonano Ci test?"</string> + <string name="submission_dispatcher_headline">"Zarejestruj test"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> <string name="submission_dispatcher_already_positive_subheadline">"Czy wynik Twojego testu PCR byÅ‚ pozytywny?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"Test z kodem QR"</string> + <string name="submission_dispatcher_card_qr">"Skanuj kod QR"</string> <!-- YTXT: Body text for QR code dispatcher option --> - <string name="submission_dispatcher_qr_card_text">"Zarejestruj test poprzez zeskanowanie kodu QR dokumentu testu."</string> + <string name="submission_dispatcher_qr_card_text">"Odbierz wynik testu w aplikacji i ostrzegaj innych."</string> <!-- YTXT: Dispatcher text for TAN code option --> <string name="submission_dispatcher_card_tan_code">"Wpisz TAN do testu PCR"</string> <!-- YTXT: Body text for TAN code dispatcher option --> @@ -1236,18 +1247,18 @@ <!-- YTXT: text after submission: pcr validation --> <string name="submission_done_share_keys">"UdostÄ™pnij swoje losowe identyfikatory, aby umożliwić ostrzeganie innych osób."</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"Organ ds. zdrowia publicznego skontaktuje siÄ™ z TobÄ… w ciÄ…gu kilku najbliższych dni."</string> + <string name="submission_done_contagious">"Organ ds. zdrowia publicznego może skontaktować siÄ™ z TobÄ… w ciÄ…gu kilku najbliższych dni."</string> <!-- YTXT: text after submission: isolate --> - <string name="submission_done_isolate">"Możesz zarażać. Izoluj siÄ™ od innych osób."</string> + <string name="submission_done_isolate">"Istnieje duże prawdopodobieÅ„stwo, że możesz zakażać. Odizoluj siÄ™ od innych ludzi."</string> <!-- XHED: Title for further info --> <string name="submission_done_further_info_title">"Inne informacje:"</string> <!-- YTXT: submission done further info bullet points --> <string-array name="submission_done_further_info_bullet_points"> - <item>"Okres kwarantanny wynosi zazwyczaj 14 dni. Obserwuj swoje objawy i monitoruj ich rozwój."</item> + <item>"Okres izolacji wynosi zazwyczaj 14 dni. Obserwuj swoje objawy i monitoruj ich rozwój."</item> <item>"Zostaniesz poproszony(-a) przez organ ds. zdrowia publicznego o stworzenie listy osób, z którymi miaÅ‚eÅ›(-aÅ›) kontakt. Powinna ona obejmować wszystkie osoby, z którymi miaÅ‚eÅ›(-aÅ›) bliski kontakt (w odlegÅ‚oÅ›ci mniejszej niż 2 metry, rozmowa twarzÄ… w twarz) przez ponad 15 minut w ciÄ…gu dwóch dni poprzedzajÄ…cych zachorowanie. Możesz do tego celu wykorzystać swój dziennik kontaktów: po prostu wyeksportuj wpisy, a nastÄ™pnie wydrukuj je lub wyÅ›lij pocztÄ… e-mail."</item> <item>"Zwróć szczególnÄ… uwagÄ™ na osoby, które nie zostanÄ… powiadomione bezpoÅ›rednio przez aplikacjÄ™, ponieważ nie posiadajÄ… smartfonów lub nie zainstalowaÅ‚y aplikacji."</item> - <item>"Nawet jeÅ›li nie masz już żadnych objawów i znów czujesz siÄ™ dobrze, możesz nadal zarażać, dlatego prosimy o przestrzeganie wyznaczonego okresu kwarantanny."</item> + <item>"Nawet jeÅ›li nie masz już żadnych objawów i znów czujesz siÄ™ dobrze, możesz nadal zarażać, dlatego prosimy o przestrzeganie wyznaczonego okresu izolacji."</item> </string-array> <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Gotowe"</string> @@ -1395,9 +1406,9 @@ <!-- XHED: submission status card positive result subtitle --> <string name="submission_status_card_positive_result_subtitle">"Uwaga:"</string> <!-- YTXT: text for contagious card --> - <string name="submission_status_card_positive_result_contagious">"Możesz zarażać. Izoluj siÄ™ od innych osób."</string> + <string name="submission_status_card_positive_result_contagious">"Istnieje duże prawdopodobieÅ„stwo, że możesz zakażać. Odizoluj siÄ™ od innych ludzi."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"Organ ds. zdrowia publicznego skontaktuje siÄ™ z TobÄ… w ciÄ…gu kilku najbliższych dni."</string> + <string name="submission_status_card_positive_result_contact">"Organ ds. zdrowia publicznego może skontaktować siÄ™ z TobÄ… w ciÄ…gu kilku najbliższych dni."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"UdostÄ™pnij swoje losowe identyfikatory, aby umożliwić ostrzeganie innych osób."</string> @@ -1991,7 +2002,7 @@ <!-- XHED: Trace location poster title --> <string name="trace_location_organiser_poster_title">"Wersja do druku"</string> <!-- XHED: Trace location check-ins consent screen title --> - <string name="trace_location_attendee_consent_title">"UdostÄ™pnić zameldowania w lokalizacji?"</string> + <string name="trace_location_attendee_consent_title">"UdostÄ™pnić Twoje zameldowania?"</string> <!-- XTXT: Trace location check-ins consent screen header description --> <string name="trace_location_attendee_consent_header_description">"Ostrzegaj inne osoby, które siÄ™ zameldowaÅ‚y wraz z TobÄ…. Twoje dane osobowe nie bÄ™dÄ… udostÄ™pniane."</string> <!-- XBUT: Trace location check-ins consent screen header button --> @@ -2025,9 +2036,9 @@ <!-- XHED: Incompitability card title --> <string name="incompatible_headline">"Ostrzeżenie o niekompatybilnoÅ›ci"</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_advertising_not_supported">"Twój smartfon może tylko odbierać powiadomienia dotyczÄ…ce COVID-19 przez Bluetooth, ale nie może ich wysyÅ‚ać. Oznacza to, że możesz otrzymywać ostrzeżenia o narażeniach za poÅ›rednictwem tego interfejsu, ale nie możesz ostrzegać innych o narażeniach. Możesz wysyÅ‚ać i odbierać ostrzeżenia, które wynikajÄ… z zameldowaÅ„."</string> + <string name="incompatible_advertising_not_supported">"Twój smartfon może tylko odbierać powiadomienia dotyczÄ…ce narażenia na zakażenie COVID-19 przez Bluetooth, ale nie może ich wysyÅ‚ać. Oznacza to, że możesz otrzymywać ostrzeżenia o narażeniach za poÅ›rednictwem tego interfejsu, ale nie możesz ostrzegać innych o narażeniach. Możesz wysyÅ‚ać i odbierać ostrzeżenia, które wynikajÄ… z zameldowaÅ„."</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_scanning_not_supported">"Twój smartfon nie może wysyÅ‚ać ani odbierać powiadomieÅ„ dotyczÄ…cych COVID-19 przez Bluetooth. Możesz wysyÅ‚ać i odbierać ostrzeżenia wynikajÄ…ce z zameldowaÅ„."</string> + <string name="incompatible_scanning_not_supported">"Twój smartfon nie może wysyÅ‚ać ani odbierać powiadomieÅ„ dotyczÄ…cych narażenia na zakażenie COVID-19 przez Bluetooth. Możesz wysyÅ‚ać i odbierać ostrzeżenia wynikajÄ…ce z zameldowaÅ„."</string> <!-- XTXT: Incompitability faq link for partial incompatibility --> <string name="incompatible_link_advertising_not_supported">"https://www.coronawarn.app/en/faq/#part_incompat"</string> <!-- XTXT: Incompitability faq link for full incompatibility --> diff --git a/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..76aecaab12e0c09d49e9a629ca1ffda86c875118 --- /dev/null +++ b/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools"> + <!-- XTXT: Vaccination Details birth date --> + <string name="vaccination_details_birth_date">"Data urodzenia %1$s"</string> + <!-- XTXT: Vaccination Details certificate date --> + <string name="vaccination_details_certificate_date">"Data szczepienia"</string> + <!-- XTXT: Vaccination Details vaccine name --> + <string name="vaccination_details_vaccine_name">"Szczepionka"</string> + <!-- XTXT: Vaccination Details vaccine manufacturer --> + <string name="vaccination_details_vaccine_manufacturer">"Producent"</string> + <!-- XTXT: Vaccination Details vaccine type --> + <string name="vaccination_details_vaccine_medical_product_name">"Typ szczepionki"</string> + <!-- XTXT: Vaccination Details certificate issuer --> + <string name="vaccination_details_certificate_issuer">"Wystawca"</string> + <!-- XTXT: Vaccination Details certificate country --> + <string name="vaccination_details_certificate_country">"Kraj"</string> + <!-- XTXT: Vaccination Details certificate id --> + <string name="vaccination_details_certificate_id">"Numer Å›wiadectwa"</string> + <!-- XTXT: Vaccination Details subtitle--> + <string name="vaccination_details_subtitle">"Åšwiadectwo szczepienia"</string> + <!-- XTXT: Vaccination Details title--> + <string name="vaccination_details_title">"Szczepienie %1$d %2$d"</string> + <!-- XTXT: Vaccination Qr Code card title--> + <string name="vaccination_qrcode_card_title">"Åšwiadectwo szczepienia %1$d %2$d"</string> + <!-- XTXT: Vaccination Qr Code card subtitle--> + <string name="vaccination_qrcode_card_subtitle">"Zaszczepiony(-a) %1$s - ważne do %2$s"</string> + + <!-- XTXT: Vaccination List title--> + <string name="vaccination_list_title">"Cyfrowy dowód szczepienia"</string> + <!-- XTXT: Vaccination List complete vaccination subtitle--> + <string name="vaccination_list_complete_vaccination_subtitle">"Ochrona poszczepienna przed SARS-CoV-2"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_name_card_subtitle">"Data urodzenia %1$s"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_title">"Szczepienie %1$d %2$d"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_subtitle">"Wykonano dnia %1$s"</string> + <!-- XTXT: Vaccination List immunity information card body--> + <plurals name="vaccination_list_immunity_card_body"> + <item quantity="one">"OtrzymaÅ‚eÅ›(-aÅ›) już wszystkie szczepienia, jednak peÅ‚nÄ… ochronÄ™ poszczepiennÄ… uzyskasz dopiero za %1$d dzieÅ„."</item> + <item quantity="other">"OtrzymaÅ‚eÅ›(-aÅ›) już wszystkie szczepienia, jednak peÅ‚nÄ… ochronÄ™ poszczepiennÄ… uzyskasz dopiero za %1$d dni."</item> + <item quantity="zero">"OtrzymaÅ‚eÅ›(-aÅ›) już wszystkie szczepienia, jednak peÅ‚nÄ… ochronÄ™ poszczepiennÄ… uzyskasz dopiero za %1$d dni."</item> + <item quantity="two">"OtrzymaÅ‚eÅ›(-aÅ›) już wszystkie szczepienia, jednak peÅ‚nÄ… ochronÄ™ poszczepiennÄ… uzyskasz dopiero za %1$d dni."</item> + <item quantity="few">"OtrzymaÅ‚eÅ›(-aÅ›) już wszystkie szczepienia, jednak peÅ‚nÄ… ochronÄ™ poszczepiennÄ… uzyskasz dopiero za %1$d dni."</item> + <item quantity="many">"OtrzymaÅ‚eÅ›(-aÅ›) już wszystkie szczepienia, jednak peÅ‚nÄ… ochronÄ™ poszczepiennÄ… uzyskasz dopiero za %1$d dni."</item> + </plurals> + <!-- XBUT: Vaccination List register additional vaccination button --> + <string name="vaccination_list_register_new_vaccination_button">"Zarejestruj kolejne szczepienie"</string> + <!-- XBUT: Vaccination List delete button --> + <string name="vaccination_list_delete_button">"UsuÅ„"</string> + <!-- XTXT: Vaccination List deletion dialog title--> + <string name="vaccination_list_deletion_dialog_title">"Czy chcesz usunąć Å›wiadectwo szczepienia?"</string> + <!-- XTXT: Vaccination List deletion dialog message--> + <string name="vaccination_list_deletion_dialog_message">"JeÅ›li usuniesz Å›wiadectwo szczepienia, aplikacja nie bÄ™dzie już mogÅ‚a używać szczepienia do weryfikacji statusu szczepienia."</string> + <!-- XBUT: Vaccination List deletion dialog positive button--> + <string name="vaccination_list_deletion_dialog_positive_button">"UsuÅ„"</string> + <!-- XBUT: Vaccination List deletion dialog negative button--> + <string name="vaccination_list_deletion_dialog_negative_button">"Anuluj"</string> + <!-- XACT: Vaccination List Qr-Code for screen readers --> + <string name="vaccination_list_qr_code_accessibility">"Kod QR"</string> + + <!-- #################################### + Homescreen cards + ###################################### --> + <!-- XHED: Title for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_registration_title">"Dodaj Å›wiadectwo szczepienia"</string> + <!-- YTXT: Body text for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_registration_body">"Dodaj Å›wiadectwa szczepienia w aplikacji, aby mieć je zawsze przy sobie. W tym celu zeskanuj kod QR znajdujÄ…cy siÄ™ na dokumencie."</string> + <!-- XBUT: button for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_register">"Dodaj"</string> + <!-- XHED: Homescreen vaccination status card title --> + <string name="vaccination_card_status_title">"Cyfrowy dowód szczepienia"</string> + <!-- XHED: Homescreen vaccination status card vaccination name --> + <string name="vaccination_card_status_vaccination_name">"Szczepienie przeciwko SARS-CoV-2"</string> + <!-- XTXT: Homescreen card incomplete vaccination status label --> + <string name="vaccination_card_status_vaccination_incomplete">"NiepeÅ‚ne zaszczepienie"</string> + <!-- XTXT: Homescreen card complete vaccination status label --> + <plurals name="vaccination_card_status_vaccination_complete" tools:ignore="UnusedQuantity"> + <item quantity="one">"PeÅ‚na ochrona poszczepienna za %1$d dzieÅ„"</item> + <item quantity="other">"PeÅ‚na ochrona poszczepienna za %1$d dni"</item> + <item quantity="zero">"PeÅ‚na ochrona poszczepienna za %1$d dni"</item> + <item quantity="two">"PeÅ‚na ochrona poszczepienna za %1$d dni"</item> + <item quantity="few">"PeÅ‚na ochrona poszczepienna za %1$d dni"</item> + <item quantity="many">"PeÅ‚na ochrona poszczepienna za %1$d dni"</item> + </plurals> + + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_invalid">"Ten kod QR nie jest ważnym Å›wiadectwem szczepienia."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_not_yet_supported">"To Å›wiadectwo szczepienia nie jest jeszcze obsÅ‚ugiwane w Twojej wersji aplikacji. Zaktualizuj aplikacjÄ™ lub skontaktuj siÄ™ z infoliniÄ… technicznÄ… dostÄ™pnÄ… w sekcji „Informacje o aplikacjiâ€."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_scan_again">"Åšwiadectwo szczepienia nie mogÅ‚o zostać zapisane na Twoim smartfonie. Spróbuj ponownie później lub skontaktuj siÄ™ z infoliniÄ… technicznÄ… dostÄ™pnÄ… w sekcji „Informacje o aplikacjiâ€."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_already_registered">"Åšwiadectwo szczepienia jest już zarejestrowane w Twojej aplikacji."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_different_person">"Dane osobowe tego Å›wiadectwa szczepienia nie sÄ… zgodne z danymi już zarejestrowanych Å›wiadectw. W aplikacji można rejestrować Å›wiadectwa tylko dla jednej osoby."</string> + + <!-- XTXT: Vaccination Consent title--> + <string name="vaccination_consent_title">"Twoja zgoda"</string> + <!-- XTXT: Vaccination Consent subtitle--> + <string name="vaccination_consent_headline">"Dodaj Å›wiadectwo szczepienia"</string> + <!-- XTXT: Vaccination Consent subtitle of qr info --> + <string name="vaccination_consent_info_subtitle_text">"Dodaj cyfrowe Å›wiadectwo szczepienia w aplikacji. Gdy uzyskasz peÅ‚nÄ… ochronÄ™ poszczepiennÄ…, bÄ™dziesz mógÅ‚ (mogÅ‚a) okazywać kod QR z aplikacji jako dowód szczepienia."</string> + <!-- XTXT: Vaccination Consent text of qr info --> + <string name="vaccination_consent_qr_info_text">"Aby dodać Å›wiadectwo szczepienia w aplikacji, zeskanuj kod QR, który otrzymaÅ‚eÅ›(-aÅ›) podczas szczepienia."</string> + <!-- XTXT: Vaccination Consent qr code text --> + <string name="vaccination_consent_qr_info_qr_code_text">"Aplikacja odczytuje informacje z kodu QR i zapisuje je w bezpiecznym miejscu na Twoim smartfonie."</string> + <!-- XTXT: Vaccination Consent time text --> + <string name="vaccination_consent_qr_info_time_text">"Dane pozostanÄ… na smartfonie. BÄ™dÄ… one przekazywane innym osobom tylko wtedy, gdy bÄ™dziesz przedstawiać Å›wiadectwo szczepienia do weryfikacji."</string> + <!-- XTXT: Text for vaccination consent legal information button --> + <string name="vaccination_consent_onboarding_legal_information">"WiÄ™cej informacji znajduje siÄ™ w oÅ›wiadczeniu o ochronie prywatnoÅ›ci."</string> + <!-- XBUT: Text for vaccination consent accept button --> + <string name="vaccination_consent_accept_button">"Kontynuuj"</string> + +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-ro/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-ro/antigen_strings.xml index 52e545312fd352bfd4297f43f3f0f9261c408c34..392caf56b4b6ea4e74722b18fc1af9fa318d047b 100644 --- a/Corona-Warn-App/src/main/res/values-ro/antigen_strings.xml +++ b/Corona-Warn-App/src/main/res/values-ro/antigen_strings.xml @@ -6,7 +6,7 @@ <!-- XHED: Register test homescreen card: title --> <string name="ag_homescreen_card_test_register_title">"ÃŽnregistrarea testului dvs."</string> <!-- XTXT: Register test homescreen card: body --> - <string name="ag_homescreen_card_test_register_body">"UtilizaÈ›i aplicaÈ›ia pentru a afla rezultatele testului dvs. pentru a-i putea avertiza pe ceilalÈ›i mai rapid."</string> + <string name="ag_homescreen_card_test_register_body">"UtilizaÈ›i aplicaÈ›ia pentru a înregistra testele dvs. È™i a afla rezultatele testelor dvs. pentru a-i putea avertiza pe ceilalÈ›i mai rapid."</string> <!-- #################################### Homescreen cards - common buttons @@ -142,7 +142,7 @@ <!-- XHED: Create RAT profile card title --> <string name="rat_profile_create_card_title">"Crearea profilului de test rapid"</string> <!-- XTXT: Create RAT profile card subtitle --> - <string name="rat_profile_create_card_subtitle">"PuteÈ›i crea un profil cu datele dvs. personale, pe care îl puteÈ›i transmite prin intermediul codului QR la fiecare test rapid."</string> + <string name="rat_profile_create_card_subtitle">"PuteÈ›i crea un profil cu datele dvs. personale, pe care îl puteÈ›i transmite prin intermediul codului QR la fiecare punct de testare participant."</string> <!-- XHED: Open RAT profile card title --> <string name="rat_profile_open_card_title">"Profil de test rapid"</string> <!-- XTXT: Open RAT profile card subtitle --> @@ -158,7 +158,7 @@ <!-- XBUT: Create RAT profile save button --> <string name="rat_profile_create_button">"Salvare"</string> <!-- XTXT: Create RAT profile description --> - <string name="rat_profile_create_description">"SalvaÈ›i datele dvs. personale sub formă de cod QR pentru a grăbi înregistrarea în punctele de testare."</string> + <string name="rat_profile_create_description">"PuteÈ›i crea un profil cu datele dvs. personale, pe care îl puteÈ›i transmite prin intermediul codului QR la fiecare punct de testare participant."</string> <!-- XTXT: Create RAT profile street hint --> <string name="rat_profile_create_street_hint">"Strada È™i numărul"</string> <!-- XTXT: Create RAT profile post code hint --> @@ -173,7 +173,7 @@ <!--RAT profile onboarding--> <string name="rat_profile_onboarding_image_content_description">"O femeie cu un smartphone în mână stă în faÈ›a unei clădiri. Un cod QR simbolizează profilul de test rapid de scanat."</string> <!-- XTXT: Create RAT profile onboarding title --> - <string name="rat_profile_onboarding_title">"SalvaÈ›i datele dvs. personale sub formă de cod QR pentru a grăbi înregistrarea în punctele de testare."</string> + <string name="rat_profile_onboarding_title">"PuteÈ›i crea un profil cu datele dvs. personale, pe care îl puteÈ›i transmite prin intermediul codului QR la fiecare punct de testare participant."</string> <!-- XTXT: Create RAT profile onboarding subtitle --> <string name="rat_profile_onboarding_subtitle">"Când creaÈ›i un profil de test rapid nu va trebui să completaÈ›i din nou datele dvs. înainte de fiecare test rapid."</string> <!-- XTXT: Create RAT profile onboarding next button --> diff --git a/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml index 7ea5c62fb7d3b08de3f8d36025c9ae153e599d0c..74c6a300dd3ad7dd45598b880be494b962a29d81 100644 --- a/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml +++ b/Corona-Warn-App/src/main/res/values-ro/contact_diary_strings.xml @@ -31,7 +31,7 @@ <!-- XTXT: Title for the contact diary onboarding screen --> <string name="contact_diary_information_card_title">"PăstraÈ›i evidenÈ›a contactelor dvs."</string> <!-- XTXT: Contact diary onboarding screen --> - <string name="contact_diary_onboarding_body">"CreaÈ›i un sumar al contactelor din ultimele 14 zile pentru a avea rapid la îndemână o listă completă, dacă este necesar."</string> + <string name="contact_diary_onboarding_body">"CreaÈ›i un sumar al contactelor din ultimele 14 zile pentru a avea rapid la îndemână o listă completă, dacă este necesar. Expunerile dvs. sunt, de asemenea, afiÈ™ate aici."</string> <!-- XTXT: Contact diary onboarding screen first functionality --> <string name="contact_diary_onboarding_functionality_first_section">"IntroduceÈ›i persoanele pe care le-aÈ›i întâlnit."</string> <!-- XTXT: Contact diary onboarding screen second functionality --> diff --git a/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml index 7515e68be77321299607746518d64501711f990b..e9834861c1fde15d9569a64200fd224bc8d85a93 100644 --- a/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml +++ b/Corona-Warn-App/src/main/res/values-ro/release_info_strings.xml @@ -16,26 +16,22 @@ <!-- XHED: Titles for the release info screen bullet points --> <string-array name="new_release_title"> - <item>"ÃŽnregistrarea jurnalelor de depanare"</item> - <item>"Crearea profilurilor de test rapid"</item> + <item>"Dovada digitală a vaccinării"</item> </string-array> <!-- XTXT: Text bodies for the release info screen bullet points --> <string-array name="new_release_body"> - <item>"Acum puteÈ›i genera un jurnal de erori în caracteristica de suport tehnic pentru aplicaÈ›ie. Aceasta înregistrează etapele pe care le efectuaÈ›i în aplicaÈ›ie, pentru a simplifica analiza de erori potenÈ›iale È™i pentru a ne ajuta să le corectăm mai rapid."</item> - <item>"Acum puteÈ›i crea un profil de test rapid în datele dvs. personale. Apoi, profilul dvs. poate fi scanat în punctele de testare, rapid È™i uÈ™or, prin intermediul codului QR."</item> + <item>"Acum puteÈ›i adăuga certificatele dvs. de vaccinare în aplicaÈ›ie È™i le puteÈ›i prezenta prin codul QR. AplicaÈ›ia arată protecÈ›ia prin vaccinarea completă la 14 zile de la vaccinarea finală."</item> </string-array> <!-- XTXT: Text labels that will be converted to Links --> <string-array name="new_release_linkified_labels"> <item/> - <item/> </string-array> <!-- XTXT: URL destinations for the lables in new_release_linkified_labels --> <string-array name="new_release_target_urls"> <item/> - <item/> </string-array> </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-ro/strings.xml b/Corona-Warn-App/src/main/res/values-ro/strings.xml index 0d7cc64bdb45e7e2917423dace7299e5e69dd6c2..2307b28d73abd0aa099f4eb10ab33d7406464485 100644 --- a/Corona-Warn-App/src/main/res/values-ro/strings.xml +++ b/Corona-Warn-App/src/main/res/values-ro/strings.xml @@ -411,7 +411,9 @@ <!-- YTXT: onboarding(together) - paragraph --> <string name="onboarding_body_4">"Dacă doriÈ›i, puteÈ›i utiliza aplicaÈ›ia pentru a dovedi starea de infectare personală (de exemplu, un test rapid negativ). ReÈ›ineÈ›i, totuÈ™i, că nu aveÈ›i nicio obligaÈ›ie de a utiliza aplicaÈ›ia pentru a dovedi starea dvs. de infectare. De asemenea, puteÈ›i dovedi starea dvs. de infectare într-un alt mod care respectă reglementările legale din localitatea dvs. de domiciliu."</string> <!-- YTXT: onboarding(together) - paragraph --> - <string name="onboarding_body_5">"AplicaÈ›ia înregistrează în jurnal întâlnirile dintre persoane prin smartphone-urile acestora, care schimbă ID-uri aleatorii criptate, fără a accesa niciun fel de date personale."</string> + <string name="onboarding_body_5">"De asemenea, puteÈ›i verifica starea vaccinării personale."</string> + <!-- YTXT: onboarding(together) - paragraph --> + <string name="onboarding_body_6">"AplicaÈ›ia înregistrează în jurnal întâlnirile dintre persoane prin smartphone-urile acestora, care schimbă ID-uri aleatorii criptate, fără a accesa niciun fel de date personale."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"Un grup de persoane își utilizează smartphone-urile prin oraÈ™."</string> <!-- XACT: Onboarding (privacy) page title --> @@ -747,7 +749,7 @@ <string name="settings_privacy_preserving_analytics_title">"Partajare date"</string> <!-- XTXT: privacy preserving analytics settings switch subtitle --> - <string name="settings_analytics_switch_subtitle">"Partajare date de utilizator"</string> + <string name="settings_analytics_switch_subtitle">"Partajare date"</string> <!-- #################################### App Information @@ -1038,7 +1040,7 @@ <!-- YTXT: Body for consent main section second point --> <string name="submission_consent_main_second_point">"Identitatea dvs. va rămâne secretă. AlÈ›i utilizatori nu vor afla cine a partajat rezultatul testului."</string> <!-- YTXT: Body for consent main section third point --> - <string name="submission_consent_main_third_point">"La „Check-inurile meleâ€, puteÈ›i vedea evenimentele È™i locurile ale căror invitaÈ›i cu check-inul făcut vor fi avertizaÈ›i. PuteÈ›i elimina check-inuri individuale din listă pentru a le exclude din procesul de avertizare."</string> + <string name="submission_consent_main_third_point">"La „Check-inurile meleâ€, puteÈ›i vedea evenimentele È™i locurile ale căror invitaÈ›i cu check-inul făcut vor fi avertizaÈ›i. PuteÈ›i È™terge check-inuri individuale din listă pentru a le exclude din procesul de avertizare."</string> <!-- YTXT: Body for consent main section fourth point --> <string name="submission_consent_main_fourth_point">"Trebuie să aveÈ›i cel puÈ›in 16 ani pentru a vă acorda consimțământul."</string> <!-- YTXT: Body for consent main section final id consent --> @@ -1053,7 +1055,7 @@ <!-- YTXT: Body for no consent section third point --> <string name="submission_no_consent_third_point">"Identitatea dvs. va rămâne secretă. AlÈ›i utilizatori nu vor afla cine a partajat rezultatul testului."</string> <!-- YTXT: Body for no consent section fourth point --> - <string name="submission_no_consent_fourth_point">"La „Check-inurile meleâ€, puteÈ›i vedea evenimentele È™i locurile ale căror invitaÈ›i cu check-inul făcut vor fi avertizaÈ›i. PuteÈ›i elimina check-inuri individuale din listă pentru a le exclude din procesul de avertizare."</string> + <string name="submission_no_consent_fourth_point">"La „Check-inurile meleâ€, puteÈ›i vedea evenimentele È™i locurile ale căror invitaÈ›i cu check-inul făcut vor fi avertizaÈ›i. PuteÈ›i È™terge check-inuri individuale din listă pentru a le exclude din procesul de avertizare."</string> <!-- YTXT: Body for no consent section fifth point --> <string name="submission_no_consent_fifth_point">"Trebuie să aveÈ›i cel puÈ›in 16 ani pentru a vă acorda consimțământul."</string> @@ -1063,13 +1065,17 @@ <!-- XHED: Page subheadline for test result --> <string name="submission_test_result_subtitle">"Cum funcÈ›ionează:"</string> <!-- XHED: Page headline for results next steps --> - <string name="submission_test_result_steps_added_heading">"Test adăugat cu succes"</string> + <string name="submission_test_result_steps_added_heading">"Testul dvs. PCR a fost adăugat cu succes."</string> <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Testul dvs. a fost stocat în Corona-Warn-App."</string> <!-- XHED: Page headline for pending test result next steps --> <string name="submission_test_result_pending_steps_waiting_heading">"Rezultatul testului dvs. nu este încă disponibil."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> - <string name="submission_test_result_pending_steps_waiting_body">"Imediat ce devine disponibil, rezultatul testului dvs. va fi afiÈ™at în aplicaÈ›ie.\n\nDe asemenea, veÈ›i primi rezultatul testului în afara aplicaÈ›iei. Autoritățile de sănătate publică vă vor anunÈ›a dacă testul dvs. este pozitiv.\n\nDacă sunteÈ›i notificat privind un rezultat pozitiv al testului în afara aplicaÈ›iei, eliminaÈ›i testul curent înregistrat în aplicaÈ›ie. ApelaÈ›i numărul indicat la „Solicitare TAN†pentru a obÈ›ine un număr TAN. Apoi, puteÈ›i utiliza acest TAN pentru a vă înregistra rezultatul în aplicaÈ›ie È™i pentru a-i avertiza pe ceilalÈ›i."</string> + <string name="submission_test_result_pending_steps_waiting_body">"Imediat ce devine disponibil, rezultatul testului dvs. va fi afiÈ™at în aplicaÈ›ie.\n\nDe asemenea, veÈ›i primi rezultatul testului în afara aplicaÈ›iei. Autoritățile de sănătate publică vă vor anunÈ›a dacă testul dvs. este pozitiv.\n\nDacă sunteÈ›i notificat privind un rezultat pozitiv al testului în afara aplicaÈ›iei, È™tergeÈ›i testul curent înregistrat în aplicaÈ›ie. ApelaÈ›i numărul indicat la „Solicitare TAN†pentru a obÈ›ine un număr TAN. Apoi, puteÈ›i utiliza acest TAN pentru a vă înregistra rezultatul în aplicaÈ›ie È™i pentru a-i avertiza pe ceilalÈ›i."</string> + <!-- XHED: Page headline for pending test result next steps --> + <string name="submission_test_result_pending_steps_waiting_pcr_heading">"Rezultatul testului dvs. nu este încă disponibil."</string> + <!-- YTXT: Body text for next steps section of waiting test result page --> + <string name="submission_test_result_pending_steps_waiting_pcr_body">"Imediat ce devine disponibil, rezultatul testului dvs. va fi afiÈ™at în aplicaÈ›ie.\n\nDe asemenea, veÈ›i primi rezultatul testului în afara aplicaÈ›iei. Autoritățile de sănătate publică vă vor anunÈ›a dacă testul dvs. este pozitiv.\n\nDacă sunteÈ›i notificat privind un rezultat pozitiv al testului în afara aplicaÈ›iei, È™tergeÈ›i testul curent înregistrat în aplicaÈ›ie. ApelaÈ›i numărul indicat la „Solicitare TAN†pentru a obÈ›ine un număr TAN. Apoi, puteÈ›i utiliza acest TAN pentru a vă înregistra rezultatul în aplicaÈ›ie È™i pentru a-i avertiza pe ceilalÈ›i."</string> <!-- XHED: Page headline for results next steps --> <string name="submission_test_result_steps_added_rat_heading">"Testul dvs. rapid a fost adăugat."</string> <!-- XHED: Page headline for pending test result next steps --> @@ -1101,12 +1107,21 @@ <string name="submission_test_result_positive_continue_button_with_symptoms">"Introducere simptome"</string> <!-- XBUT: positive test result : continue button without symptoms --> <string name="submission_test_result_positive_continue_button_wo_symptoms">"Nu se introduc simptome"</string> + + <!-- XHED: Page headline for invalid test result screen --> - <string name="submission_test_result_invalid_steps_invalid_heading">"Rezultatul testului dvs."</string> + <string name="submission_test_result_invalid_steps_invalid_heading">"Testul dvs. nu poate fi evaluat"</string> + + <!-- XHED: Page headline for invalid test result screen --> + <string name="submission_test_result_delete_steps_invalid_heading">"Ștergere test"</string> + <!-- YTXT: Body text for next steps section of invalid test result--> - <string name="submission_test_result_invalid_steps_invalid_body">"A apărut o problemă la evaluarea testului dvs. ContactaÈ›i centrul sau laboratorul de testare implicat pentru a afla paÈ™ii următori.\n\nȘtergeÈ›i testul din Corona-Warn-App pentru a salva un nou cod de test aici, dacă este necesar."</string> + <string name="submission_test_result_invalid_steps_invalid_body">"A apărut o problemă la evaluarea testului dvs. ContactaÈ›i centrul sau laboratorul de testare implicat pentru a afla paÈ™ii următori."</string> + <!-- YTXT: Body text for next steps section of invalid test result--> + <string name="submission_test_result_delete_steps_invalid_body">"ȘtergeÈ›i testul din Corona-Warn-App pentru a salva un nou cod de test aici dacă este necesar."</string> + <!-- XBUT: invalid test result : remove the test button --> - <string name="submission_test_result_invalid_remove_test_button">"Eliminare test"</string> + <string name="submission_test_result_invalid_remove_test_button">"Ștergere test"</string> <!-- XHED: Dialog title for tracing required dailog --> <string name="submission_test_result_dialog_tracing_required_title">"Este necesară înregistrarea în jurnal a expunerilor"</string> <!-- YTXT: Dialog text for tracing required dialog--> @@ -1116,9 +1131,9 @@ <!-- XHED: Dialog title for test removal --> <string name="submission_test_result_dialog_remove_test_title">"Testul poate fi scanat o singură dată."</string> <!-- YTXT: Dialog text for test removal --> - <string name="submission_test_result_dialog_remove_test_message">"Dacă eliminaÈ›i testul, nu veÈ›i mai putea afla rezultatul testului. VeÈ›i primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteÈ›i diagnosticat cu coronavirus, autoritatea de sănătate publică va fi notificată prin canalul de comunicare prevăzut în mod legal È™i vă va contacta."</string> + <string name="submission_test_result_dialog_remove_test_message">"Dacă È™tergeÈ›i testul, nu veÈ›i mai putea afla rezultatul testului. VeÈ›i primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteÈ›i diagnosticat cu coronavirus, autoritatea de sănătate publică va fi notificată prin canalul de comunicare prevăzut în mod legal È™i vă va contacta."</string> <!-- XBUT: Positive button for test removal --> - <string name="submission_test_result_dialog_remove_test_button_positive">"Eliminare"</string> + <string name="submission_test_result_dialog_remove_test_button_positive">"Ștergere"</string> <!-- XBUT: Negative button for test removal --> <string name="submission_test_result_dialog_remove_test_button_negative">"Anulare"</string> <!-- XHED: Title for test result card positive --> @@ -1158,17 +1173,13 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Aflarea rezultatului testului"</string> - <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"AflaÈ›i rezultatul testului dvs. prin intermediul aplicaÈ›iei È™i avertizaÈ›i-i pe ceilalÈ›i. Vă veÈ›i proteja È™i veÈ›i opri răspândirea coronavirusului."</string> - <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">"AÈ›i fost testat?"</string> + <string name="submission_dispatcher_headline">"ÃŽnregistrarea testului dvs."</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> <string name="submission_dispatcher_already_positive_subheadline">"Testul dvs. PCR a fost pozitiv?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"Testarea cu cod QR"</string> + <string name="submission_dispatcher_card_qr">"Scanare cod QR"</string> <!-- YTXT: Body text for QR code dispatcher option --> - <string name="submission_dispatcher_qr_card_text">"ÃŽnregistraÈ›i-vă testul scanând codul QR al documentului de testare."</string> + <string name="submission_dispatcher_qr_card_text">"PrimiÈ›i rezultatul testului dvs. în aplicaÈ›ie È™i avertizaÈ›i-i pe ceilalÈ›i."</string> <!-- YTXT: Dispatcher text for TAN code option --> <string name="submission_dispatcher_card_tan_code">"IntroduceÈ›i codul TAN pentru testul PCR"</string> <!-- YTXT: Body text for TAN code dispatcher option --> @@ -1236,18 +1247,18 @@ <!-- YTXT: text after submission: pcr validation --> <string name="submission_done_share_keys">"TrimiteÈ›i ID-ul dvs. aleatoriu pentru a-i avertiza È™i pe alÈ›ii."</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"Autoritatea de sănătate publică vă va contacta în următoarele zile."</string> + <string name="submission_done_contagious">"Autoritatea de sănătate publică vă poate contacta în următoarele zile."</string> <!-- YTXT: text after submission: isolate --> - <string name="submission_done_isolate">"SunteÈ›i infectat. IzolaÈ›i-vă de alte persoane."</string> + <string name="submission_done_isolate">"Există o probabilitate mare să fiÈ›i contagios. IzolaÈ›i-vă de alte persoane."</string> <!-- XHED: Title for further info --> <string name="submission_done_further_info_title">"Alte informaÈ›ii:"</string> <!-- YTXT: submission done further info bullet points --> <string-array name="submission_done_further_info_bullet_points"> - <item>"Perioada de carantină este de obicei de 14 zile. MonitorizaÈ›i cu atenÈ›ie modul în care evoluează simptomele dvs."</item> + <item>"Perioada de izolare este de obicei de 14 zile. MonitorizaÈ›i cu atenÈ›ie modul în care evoluează simptomele dvs."</item> <item>"Autoritatea dvs. de sănătate publică vă va solicita să întocmiÈ›i o listă a persoanelor cu care aÈ›i intrat în contact. Aceasta trebuie să cuprindă toate persoanele cu care aÈ›i avut contact strâns (mai puÈ›in de 2 metri, conversaÈ›ii față în față) timp de peste 15 minute începând cu două zile înainte de a vă îmbolnăvi. PuteÈ›i utiliza jurnalul de contacte în acest scop: trebuie doar să exportaÈ›i intrările È™i apoi să le tipăriÈ›i sau să le expediaÈ›i pe e-mail."</item> <item>"LuaÈ›i în considerare în special persoanele care nu vor fi notificate direct de aplicaÈ›ie dacă nu au un smartphone sau dacă nu È™i-au instalat aplicaÈ›ia."</item> - <item>"Chiar È™i când nu mai aveÈ›i simptome È™i vă simÈ›iÈ›i din nou bine, tot puteÈ›i să fiÈ›i contagios. Vă rugăm să respectaÈ›i perioada de carantină indicată."</item> + <item>"Chiar È™i când nu mai aveÈ›i simptome È™i vă simÈ›iÈ›i din nou bine, tot puteÈ›i să fiÈ›i contagios. Vă rugăm să respectaÈ›i perioada de izolare indicată."</item> </string-array> <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Gata"</string> @@ -1395,9 +1406,9 @@ <!-- XHED: submission status card positive result subtitle --> <string name="submission_status_card_positive_result_subtitle">"ReÈ›ineÈ›i:"</string> <!-- YTXT: text for contagious card --> - <string name="submission_status_card_positive_result_contagious">"SunteÈ›i infectat. IzolaÈ›i-vă de alte persoane."</string> + <string name="submission_status_card_positive_result_contagious">"Există o probabilitate mare să fiÈ›i contagios. IzolaÈ›i-vă de alte persoane."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"Autoritatea de sănătate publică vă va contacta în următoarele zile."</string> + <string name="submission_status_card_positive_result_contact">"Autoritatea de sănătate publică vă poate contacta în următoarele zile."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"TrimiteÈ›i ID-ul dvs. aleatoriu pentru a-i avertiza È™i pe alÈ›ii."</string> @@ -1959,7 +1970,7 @@ <!-- XACT: Button/Dialog label to cancel something--> <string name="generic_action_abort">"Anulare"</string> <!-- XACT: Button/Dialog label to remove something--> - <string name="generic_action_remove">"Eliminare"</string> + <string name="generic_action_remove">"Ștergere"</string> <!-- #################################### Trace Location @@ -1991,7 +2002,7 @@ <!-- XHED: Trace location poster title --> <string name="trace_location_organiser_poster_title">"Versiune de tipărire"</string> <!-- XHED: Trace location check-ins consent screen title --> - <string name="trace_location_attendee_consent_title">"PartajaÈ›i check-inurile locaÈ›iei?"</string> + <string name="trace_location_attendee_consent_title">"PartajaÈ›i check-inurile?"</string> <!-- XTXT: Trace location check-ins consent screen header description --> <string name="trace_location_attendee_consent_header_description">"AvertizaÈ›i-i pe ceilalÈ›i care au făcut check-in cu dvs. Datele dvs. personale nu vor fi partajate."</string> <!-- XBUT: Trace location check-ins consent screen header button --> @@ -2025,9 +2036,9 @@ <!-- XHED: Incompitability card title --> <string name="incompatible_headline">"Avertizare de incompatibilitate"</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_advertising_not_supported">"Smartphone-ul dvs. poate doar primi notificări despre COVID-19 prin Bluetooth, dar nu le poate expedia. Aceasta înseamnă că puteÈ›i fi avertizat privind expunerile prin această interfață, dar dvs. nu îi puteÈ›i avertiza pe ceilalÈ›i de expuneri. PuteÈ›i trimite È™i primi avertizări care rezultă din check-inuri."</string> + <string name="incompatible_advertising_not_supported">"Smartphone-ul dvs. poate doar primi notificări despre expunerea la COVID-19 prin Bluetooth, dar nu le poate expedia. Aceasta înseamnă că puteÈ›i fi avertizat privind expunerile prin această interfață, dar dvs. nu îi puteÈ›i avertiza pe ceilalÈ›i de expuneri. PuteÈ›i trimite È™i primi avertizări care rezultă din check-inuri."</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_scanning_not_supported">"Smartphone-ul dvs. nu poate trimite sau primi notificări despre COVID-19 prin Bluetooth. PuteÈ›i trimite È™i primi avertizări care rezultă din check-inuri."</string> + <string name="incompatible_scanning_not_supported">"Smartphone-ul dvs. nu poate trimite sau primi notificări despre expunerea la COVID-19 prin Bluetooth. PuteÈ›i trimite È™i primi avertizări care rezultă din check-inuri."</string> <!-- XTXT: Incompitability faq link for partial incompatibility --> <string name="incompatible_link_advertising_not_supported">"https://www.coronawarn.app/en/faq/#part_incompat"</string> <!-- XTXT: Incompitability faq link for full incompatibility --> diff --git a/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..50adc9d947a69485ef7655e980e61f545bcf6621 --- /dev/null +++ b/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools"> + <!-- XTXT: Vaccination Details birth date --> + <string name="vaccination_details_birth_date">"Născut(ă) pe %1$s"</string> + <!-- XTXT: Vaccination Details certificate date --> + <string name="vaccination_details_certificate_date">"Data vaccinării"</string> + <!-- XTXT: Vaccination Details vaccine name --> + <string name="vaccination_details_vaccine_name">"Vaccin"</string> + <!-- XTXT: Vaccination Details vaccine manufacturer --> + <string name="vaccination_details_vaccine_manufacturer">"Fabricant"</string> + <!-- XTXT: Vaccination Details vaccine type --> + <string name="vaccination_details_vaccine_medical_product_name">"Tip de vaccin"</string> + <!-- XTXT: Vaccination Details certificate issuer --> + <string name="vaccination_details_certificate_issuer">"Emitent"</string> + <!-- XTXT: Vaccination Details certificate country --> + <string name="vaccination_details_certificate_country">"Èšara"</string> + <!-- XTXT: Vaccination Details certificate id --> + <string name="vaccination_details_certificate_id">"Număr de certificare"</string> + <!-- XTXT: Vaccination Details subtitle--> + <string name="vaccination_details_subtitle">"Certificat de vaccinare"</string> + <!-- XTXT: Vaccination Details title--> + <string name="vaccination_details_title">"Vaccinarea %1$d din %2$d"</string> + <!-- XTXT: Vaccination Qr Code card title--> + <string name="vaccination_qrcode_card_title">"Certificatul de vaccinare %1$d din %2$d"</string> + <!-- XTXT: Vaccination Qr Code card subtitle--> + <string name="vaccination_qrcode_card_subtitle">"Vaccinat la %1$s - valabil până la %2$s"</string> + + <!-- XTXT: Vaccination List title--> + <string name="vaccination_list_title">"Dovada digitală a vaccinării"</string> + <!-- XTXT: Vaccination List complete vaccination subtitle--> + <string name="vaccination_list_complete_vaccination_subtitle">"ProtecÈ›ie prin vaccinare împotriva SARS-CoV-2"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_name_card_subtitle">"Născut(ă) pe %1$s"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_title">"Vaccinarea %1$d din %2$d"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_subtitle">"Efectuată pe %1$s"</string> + <!-- XTXT: Vaccination List immunity information card body--> + <plurals name="vaccination_list_immunity_card_body"> + <item quantity="one">"Acum aÈ›i efectuat toate vaccinările. TotuÈ™i, protecÈ›ia prin vaccinare nu va fi completă timp de încă %1$d zi."</item> + <item quantity="other">"Acum aÈ›i efectuat toate vaccinările. TotuÈ™i, protecÈ›ia prin vaccinare nu va fi completă timp de încă %1$d de zile."</item> + <item quantity="zero">"Acum aÈ›i efectuat toate vaccinările. TotuÈ™i, protecÈ›ia prin vaccinare nu va fi completă timp de încă %1$d zile."</item> + <item quantity="two">"Acum aÈ›i efectuat toate vaccinările. TotuÈ™i, protecÈ›ia prin vaccinare nu va fi completă timp de încă %1$d zile."</item> + <item quantity="few">"Acum aÈ›i efectuat toate vaccinările. TotuÈ™i, protecÈ›ia prin vaccinare nu va fi completă timp de încă %1$d zile."</item> + <item quantity="many">"Acum aÈ›i efectuat toate vaccinările. TotuÈ™i, protecÈ›ia prin vaccinare nu va fi completă timp de încă %1$d zile."</item> + </plurals> + <!-- XBUT: Vaccination List register additional vaccination button --> + <string name="vaccination_list_register_new_vaccination_button">"ÃŽnregistrare altă vaccinare"</string> + <!-- XBUT: Vaccination List delete button --> + <string name="vaccination_list_delete_button">"Ștergere"</string> + <!-- XTXT: Vaccination List deletion dialog title--> + <string name="vaccination_list_deletion_dialog_title">"DoriÈ›i să È™tergeÈ›i certificatul de vaccinare?"</string> + <!-- XTXT: Vaccination List deletion dialog message--> + <string name="vaccination_list_deletion_dialog_message">"Dacă È™tergeÈ›i certificatul de vaccinare, aplicaÈ›ia nu mai poate utiliza vaccinarea pentru a verifica starea vaccinării dvs."</string> + <!-- XBUT: Vaccination List deletion dialog positive button--> + <string name="vaccination_list_deletion_dialog_positive_button">"Ștergere"</string> + <!-- XBUT: Vaccination List deletion dialog negative button--> + <string name="vaccination_list_deletion_dialog_negative_button">"Anulare"</string> + <!-- XACT: Vaccination List Qr-Code for screen readers --> + <string name="vaccination_list_qr_code_accessibility">"Cod QR"</string> + + <!-- #################################### + Homescreen cards + ###################################### --> + <!-- XHED: Title for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_registration_title">"Adăugare certificat de vaccinare"</string> + <!-- YTXT: Body text for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_registration_body">"AdăugaÈ›i certificate de vaccinare în aplicaÈ›ie pentru a le avea mereu cu dvs. Pentru aceasta, scanaÈ›i codul QR din documentul dvs."</string> + <!-- XBUT: button for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_register">"Adăugare"</string> + <!-- XHED: Homescreen vaccination status card title --> + <string name="vaccination_card_status_title">"Dovada digitală a vaccinării"</string> + <!-- XHED: Homescreen vaccination status card vaccination name --> + <string name="vaccination_card_status_vaccination_name">"Vaccinare SARS-CoV-2"</string> + <!-- XTXT: Homescreen card incomplete vaccination status label --> + <string name="vaccination_card_status_vaccination_incomplete">"Vaccinare incompletă"</string> + <!-- XTXT: Homescreen card complete vaccination status label --> + <plurals name="vaccination_card_status_vaccination_complete" tools:ignore="UnusedQuantity"> + <item quantity="one">"ProtecÈ›ia prin vaccinare este completă în %1$d zi"</item> + <item quantity="other">"ProtecÈ›ia prin vaccinare este completă în %1$d de zile"</item> + <item quantity="zero">"ProtecÈ›ia prin vaccinare este completă în %1$d zile"</item> + <item quantity="two">"ProtecÈ›ia prin vaccinare este completă în %1$d zile"</item> + <item quantity="few">"ProtecÈ›ia prin vaccinare este completă în %1$d zile"</item> + <item quantity="many">"ProtecÈ›ia prin vaccinare este completă în %1$d zile"</item> + </plurals> + + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_invalid">"Acest cod QR nu este un certificat de vaccinare valabil."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_not_yet_supported">"Acest certificat de vaccinare nu este încă acceptat de versiunea aplicaÈ›iei dvs. ActualizaÈ›i-vă aplicaÈ›ia sau contactaÈ›i hotline-ul tehnic din „InformaÈ›ii aplicaÈ›ieâ€."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_scan_again">"Certificatul de vaccinare nu a putut fi salvat pe smartphone-ul dvs. ÃŽncercaÈ›i din nou mai târziu sau contactaÈ›i hotline-ul tehnic din „InformaÈ›ii aplicaÈ›ieâ€."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_already_registered">"Certificatul de vaccinare este deja înregistrat în aplicaÈ›ia dvs."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_different_person">"InformaÈ›iile personale din acest certificat de vaccinare nu corespund cu cele din certificatele deja înregistrate. PuteÈ›i înregistra certificate pentru o singură persoană în aplicaÈ›ie."</string> + + <!-- XTXT: Vaccination Consent title--> + <string name="vaccination_consent_title">"Consimțământul dvs."</string> + <!-- XTXT: Vaccination Consent subtitle--> + <string name="vaccination_consent_headline">"Adăugare certificat de vaccinare"</string> + <!-- XTXT: Vaccination Consent subtitle of qr info --> + <string name="vaccination_consent_info_subtitle_text">"AdăugaÈ›i certificatul de vaccinare digital în aplicaÈ›ie. De îndată ce protecÈ›ia prin vaccinare este completă, puteÈ›i prezenta codul QR în aplicaÈ›ie ca dovadă a vaccinării."</string> + <!-- XTXT: Vaccination Consent text of qr info --> + <string name="vaccination_consent_qr_info_text">"Pentru a adăuga un certificat de vaccinare în aplicaÈ›ie, scanaÈ›i codul QR pe care l-aÈ›i primit la vaccinare."</string> + <!-- XTXT: Vaccination Consent qr code text --> + <string name="vaccination_consent_qr_info_qr_code_text">"AplicaÈ›ia citeÈ™te informaÈ›iile de la codul QR È™i le salvează într-o zonă securizată pe smartphone-ul dvs."</string> + <!-- XTXT: Vaccination Consent time text --> + <string name="vaccination_consent_qr_info_time_text">"Datele vor rămâne pe smartphone. Vor fi transmise altor persoane doar dacă prezentaÈ›i certificatul de vaccinare pentru verificare."</string> + <!-- XTXT: Text for vaccination consent legal information button --> + <string name="vaccination_consent_onboarding_legal_information">"Pentru mai multe informaÈ›ii, consultaÈ›i înÈ™tiinÈ›area de confidenÈ›ialitate."</string> + <!-- XBUT: Text for vaccination consent accept button --> + <string name="vaccination_consent_accept_button">"Continuare"</string> + +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-tr/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-tr/antigen_strings.xml index 68a20d21463aefdba94be03d5df062e87c619313..9e493bfa6bc8ed889e0bb8a2ea19f7b313e6a57c 100644 --- a/Corona-Warn-App/src/main/res/values-tr/antigen_strings.xml +++ b/Corona-Warn-App/src/main/res/values-tr/antigen_strings.xml @@ -6,7 +6,7 @@ <!-- XHED: Register test homescreen card: title --> <string name="ag_homescreen_card_test_register_title">"Testinizi Kaydedin"</string> <!-- XTXT: Register test homescreen card: body --> - <string name="ag_homescreen_card_test_register_body">"DiÄŸer kullanıcıları daha hızlı uyarmak için test sonuçlarınızı almak üzere uygulamayı kullanın."</string> + <string name="ag_homescreen_card_test_register_body">"DiÄŸer kullanıcıları daha hızlı uyarmak için testlerinizi kaydetmek ve test sonuçlarınızı almak üzere uygulamayı kullanın."</string> <!-- #################################### Homescreen cards - common buttons @@ -142,7 +142,7 @@ <!-- XHED: Create RAT profile card title --> <string name="rat_profile_create_card_title">"Hızlı Test Profili OluÅŸtur"</string> <!-- XTXT: Create RAT profile card subtitle --> - <string name="rat_profile_create_card_subtitle">"KiÅŸisel verilerinizle bir profil oluÅŸturabilir ve her hızlı test sırasında QR kod aracılığıyla gönderebilirsiniz."</string> + <string name="rat_profile_create_card_subtitle">"KiÅŸisel verilerinizle bir profil oluÅŸturabilir ve her katılan test noktasına QR kod aracılığıyla gönderebilirsiniz."</string> <!-- XHED: Open RAT profile card title --> <string name="rat_profile_open_card_title">"Hızlı Test Profili"</string> <!-- XTXT: Open RAT profile card subtitle --> @@ -158,7 +158,7 @@ <!-- XBUT: Create RAT profile save button --> <string name="rat_profile_create_button">"Kaydet"</string> <!-- XTXT: Create RAT profile description --> - <string name="rat_profile_create_description">"Test noktalarında kaydınızı hızlandırmak için kiÅŸisel verilerinizi bir QR kod olarak kaydedin."</string> + <string name="rat_profile_create_description">"KiÅŸisel verilerinizle bir profil oluÅŸturabilir ve her katılan test noktasına QR kod aracılığıyla gönderebilirsiniz."</string> <!-- XTXT: Create RAT profile street hint --> <string name="rat_profile_create_street_hint">"Sokak ve Konut Numarası"</string> <!-- XTXT: Create RAT profile post code hint --> @@ -173,7 +173,7 @@ <!--RAT profile onboarding--> <string name="rat_profile_onboarding_image_content_description">"Elinde akıllı telefon tutan bir kadın bir binanın önünde duruyor. QR kod, taranacak hızlı test profilini sembolize ediyor."</string> <!-- XTXT: Create RAT profile onboarding title --> - <string name="rat_profile_onboarding_title">"Test noktalarında kaydınızı hızlandırmak için kiÅŸisel verilerinizi bir QR kod olarak kaydedin."</string> + <string name="rat_profile_onboarding_title">"KiÅŸisel verilerinizle bir profil oluÅŸturabilir ve her katılan test noktasına QR kod aracılığıyla gönderebilirsiniz."</string> <!-- XTXT: Create RAT profile onboarding subtitle --> <string name="rat_profile_onboarding_subtitle">"Hızlı test profili oluÅŸturduÄŸunuzda her hızlı testten önce kiÅŸisel verilerinizi yeniden doldurmanız gerekmez."</string> <!-- XTXT: Create RAT profile onboarding next button --> diff --git a/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml index 9424c7dacbbf20fa402c46bbec22c80da392f3de..09183f04e8434e1d2265920dd08218b601daf913 100644 --- a/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml +++ b/Corona-Warn-App/src/main/res/values-tr/contact_diary_strings.xml @@ -31,7 +31,7 @@ <!-- XTXT: Title for the contact diary onboarding screen --> <string name="contact_diary_information_card_title">"Temas kaydınızı tutun."</string> <!-- XTXT: Contact diary onboarding screen --> - <string name="contact_diary_onboarding_body">"Ä°htiyaç duyduÄŸunuzda elinizin altında eksiksiz bir liste olması için son 14 güne ait temaslarınıza iliÅŸkin bir genel bakış oluÅŸturun."</string> + <string name="contact_diary_onboarding_body">"Ä°htiyaç duyduÄŸunuzda elinizin altında eksiksiz bir liste olması için son 14 güne ait temaslarınıza iliÅŸkin bir genel bakış oluÅŸturun. Maruz kalma bilgileriniz de burada görüntülenir."</string> <!-- XTXT: Contact diary onboarding screen first functionality --> <string name="contact_diary_onboarding_functionality_first_section">"KarşılaÅŸtığınız kiÅŸileri girin."</string> <!-- XTXT: Contact diary onboarding screen second functionality --> diff --git a/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml index a8a5ef1c454ebf4d39c4366b5d04471ca6993982..a551f52bc1ec4ddbb7332fa1c53a956b85619b23 100644 --- a/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml +++ b/Corona-Warn-App/src/main/res/values-tr/release_info_strings.xml @@ -16,26 +16,22 @@ <!-- XHED: Titles for the release info screen bullet points --> <string-array name="new_release_title"> - <item>"Sorun Giderme Günlüklerini Kaydet"</item> - <item>"Hızlı Test Profilleri OluÅŸtur"</item> + <item>"Dijital Aşı Kanıtı"</item> </string-array> <!-- XTXT: Text bodies for the release info screen bullet points --> <string-array name="new_release_body"> - <item>"Artık uygulamanın teknik destek özelliÄŸinde bir hata günlüğü oluÅŸturabilirsiniz. Bu günlük, potansiyel hataların analizini basitleÅŸtirmek ve bu hataları daha hızlı düzeltmemize yardımcı olmak için uygulamada gerçekleÅŸtirdiÄŸiniz adımları kaydeder."</item> - <item>"Artık kiÅŸisel verilerinizde bir hızlı test profili oluÅŸturabilirsiniz. Ardından QR kod ile hızlı ve kolay bir biçimde test noktalarında profiliniz taranabilir."</item> + <item>"Artık aşı sertifikalarınızı uygulamaya kaydedebilir ve QR kod aracılığıyla sunabilirsiniz. Uygulama, son aşıdan 14 gün sonra tam aşı korumasını görüntüler."</item> </string-array> <!-- XTXT: Text labels that will be converted to Links --> <string-array name="new_release_linkified_labels"> <item/> - <item/> </string-array> <!-- XTXT: URL destinations for the lables in new_release_linkified_labels --> <string-array name="new_release_target_urls"> <item/> - <item/> </string-array> </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-tr/strings.xml b/Corona-Warn-App/src/main/res/values-tr/strings.xml index 71c09f5843efc960ef597e20c52abb5012210a3d..6af43c944accaa5322b4e22c2a9181f479fd3b63 100644 --- a/Corona-Warn-App/src/main/res/values-tr/strings.xml +++ b/Corona-Warn-App/src/main/res/values-tr/strings.xml @@ -411,7 +411,9 @@ <!-- YTXT: onboarding(together) - paragraph --> <string name="onboarding_body_4">"Dilerseniz uygulamayı kiÅŸisel enfeksiyon durumunuzu (örneÄŸin, negatif sonuç veren bir hızlı test) kanıtlamak için kullanabilirsiniz. Ancak lütfen unutmayın; enfeksiyon durumunuzu kanıtlamak için uygulamayı kullanmak zorunda deÄŸilsiniz. Enfeksiyon durumunuzu, ikamet ettiÄŸiniz bölgede geçerli olan yasal düzenlemeler uyarınca baÅŸka bir ÅŸekilde de kanıtlayabilirsiniz."</string> <!-- YTXT: onboarding(together) - paragraph --> - <string name="onboarding_body_5">"Uygulama kiÅŸilerin akıllı telefonları arasında ÅŸifrelenmiÅŸ rastgele kimlikleri paylaÅŸarak karşılaÅŸma günlüğü oluÅŸturur ve bu sırada hiçbir kiÅŸisel veriye eriÅŸim saÄŸlanmaz."</string> + <string name="onboarding_body_5">"KiÅŸisel aşı durumunuzu da doÄŸrulayabilirsiniz."</string> + <!-- YTXT: onboarding(together) - paragraph --> + <string name="onboarding_body_6">"Uygulama kiÅŸilerin akıllı telefonları arasında ÅŸifrelenmiÅŸ rastgele kimlikleri paylaÅŸarak karşılaÅŸma günlüğü oluÅŸturur ve bu sırada hiçbir kiÅŸisel veriye eriÅŸim saÄŸlanmaz."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"Bölgedeki bir grup insan akıllı telefonlarını kullanıyor."</string> <!-- XACT: Onboarding (privacy) page title --> @@ -747,7 +749,7 @@ <string name="settings_privacy_preserving_analytics_title">"Verileri PaylaÅŸ"</string> <!-- XTXT: privacy preserving analytics settings switch subtitle --> - <string name="settings_analytics_switch_subtitle">"Kullanıcı Verilerini PaylaÅŸ"</string> + <string name="settings_analytics_switch_subtitle">"Verileri PaylaÅŸ"</string> <!-- #################################### App Information @@ -1038,7 +1040,7 @@ <!-- YTXT: Body for consent main section second point --> <string name="submission_consent_main_second_point">"KimliÄŸiniz gizli tutulacaktır. DiÄŸer kullanıcılar, kimin test sonucunu paylaÅŸtığını öğrenmeyecektir."</string> <!-- YTXT: Body for consent main section third point --> - <string name="submission_consent_main_third_point">"“Check-In’lerim†bölümünde check-in yapan konuklarına uyarı gönderilecek etkinlikleri ve yerleri görebilirsiniz. Uyarı iÅŸlemlerinin dışında tutmak için listeden ayrı ayrı check-in’leri kaldırabilirsiniz."</string> + <string name="submission_consent_main_third_point">"“Check-In’lerim†bölümünde check-in yapan konuklarına uyarı gönderilecek etkinlikleri ve yerleri görebilirsiniz. Uyarı iÅŸlemlerinin dışında tutmak için listeden ayrı ayrı check-in’leri silebilirsiniz."</string> <!-- YTXT: Body for consent main section fourth point --> <string name="submission_consent_main_fourth_point">"Onay vermek için 16 yaşın üzerinde olmanız gerekir."</string> <!-- YTXT: Body for consent main section final id consent --> @@ -1053,7 +1055,7 @@ <!-- YTXT: Body for no consent section third point --> <string name="submission_no_consent_third_point">"KimliÄŸiniz gizli tutulacaktır. DiÄŸer kullanıcılar, kimin test sonucunu paylaÅŸtığını öğrenmeyecektir."</string> <!-- YTXT: Body for no consent section fourth point --> - <string name="submission_no_consent_fourth_point">"“Check-In’lerim†bölümünde check-in yapan konuklarına uyarı gönderilecek etkinlikleri ve yerleri görebilirsiniz. Uyarı iÅŸlemlerinin dışında tutmak için listeden ayrı ayrı check-in’leri kaldırabilirsiniz."</string> + <string name="submission_no_consent_fourth_point">"“Check-In’lerim†bölümünde check-in yapan konuklarına uyarı gönderilecek etkinlikleri ve yerleri görebilirsiniz. Uyarı iÅŸlemlerinin dışında tutmak için listeden ayrı ayrı check-in’leri silebilirsiniz."</string> <!-- YTXT: Body for no consent section fifth point --> <string name="submission_no_consent_fifth_point">"Onay vermek için 16 yaşın üzerinde olmanız gerekir."</string> @@ -1063,13 +1065,17 @@ <!-- XHED: Page subheadline for test result --> <string name="submission_test_result_subtitle">"Nasıl çalışır?"</string> <!-- XHED: Page headline for results next steps --> - <string name="submission_test_result_steps_added_heading">"Test baÅŸarıyla eklendi"</string> + <string name="submission_test_result_steps_added_heading">"PCR testiniz baÅŸarıyla eklendi."</string> <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Testiniz Corona-Warn-App\'e kaydedildi."</string> <!-- XHED: Page headline for pending test result next steps --> <string name="submission_test_result_pending_steps_waiting_heading">"Test sonucunuz henüz çıkmadı."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> - <string name="submission_test_result_pending_steps_waiting_body">"Test sonucunuz çıkar çıkmaz uygulamada görüntülenecektir.\n\nTest sonucunuz uygulama dışından da tarafınıza iletilecektir. Testinizin pozitif sonuç vermesi halinde kamu saÄŸlığı yetkilileri sizi bilgilendirecektir.\n\nUygulama dışından bir pozitif test sonucu aldıysanız lütfen uygulamaya kayıtlı testi kaldırın. TAN almak için \"TAN Talebi\" baÅŸlığının altında gösterilen numarayı arayın. Ardından bu TAN\'yi kullanarak sonucunuzu uygulamaya kaydedin ve diÄŸer kullanıcıları uyarın."</string> + <string name="submission_test_result_pending_steps_waiting_body">"Test sonucunuz çıkar çıkmaz uygulamada görüntülenecektir.\n\nTest sonucunuz uygulama dışından da tarafınıza iletilecektir. Testinizin pozitif sonuç vermesi halinde kamu saÄŸlığı yetkilileri sizi bilgilendirecektir.\n\nUygulama dışından bir pozitif test sonucu aldıysanız lütfen uygulamaya kayıtlı testi silin. TAN almak için \"TAN Talebi\" baÅŸlığının altında gösterilen numarayı arayın. Ardından bu TAN\'yi kullanarak sonucunuzu uygulamaya kaydedin ve diÄŸer kullanıcıları uyarın."</string> + <!-- XHED: Page headline for pending test result next steps --> + <string name="submission_test_result_pending_steps_waiting_pcr_heading">"Test sonucunuz henüz çıkmadı."</string> + <!-- YTXT: Body text for next steps section of waiting test result page --> + <string name="submission_test_result_pending_steps_waiting_pcr_body">"Test sonucunuz çıkar çıkmaz uygulamada görüntülenecektir.\n\nTest sonucunuz uygulama dışından da tarafınıza iletilecektir. Testinizin pozitif sonuç vermesi halinde kamu saÄŸlığı yetkilileri sizi bilgilendirecektir.\n\nUygulama dışından bir pozitif test sonucu aldıysanız lütfen uygulamaya kayıtlı testi silin. TAN almak için \"TAN Talebi\" baÅŸlığının altında gösterilen numarayı arayın. Ardından bu TAN\'yi kullanarak sonucunuzu uygulamaya kaydedin ve diÄŸer kullanıcıları uyarın."</string> <!-- XHED: Page headline for results next steps --> <string name="submission_test_result_steps_added_rat_heading">"Hızlı testiniz eklendi."</string> <!-- XHED: Page headline for pending test result next steps --> @@ -1101,12 +1107,21 @@ <string name="submission_test_result_positive_continue_button_with_symptoms">"Belirtileri Gir"</string> <!-- XBUT: positive test result : continue button without symptoms --> <string name="submission_test_result_positive_continue_button_wo_symptoms">"Belirtileri Girme"</string> + + <!-- XHED: Page headline for invalid test result screen --> - <string name="submission_test_result_invalid_steps_invalid_heading">"Test Sonucunuz"</string> + <string name="submission_test_result_invalid_steps_invalid_heading">"Testiniz deÄŸerlendirilemiyor"</string> + + <!-- XHED: Page headline for invalid test result screen --> + <string name="submission_test_result_delete_steps_invalid_heading">"Testi Sil"</string> + <!-- YTXT: Body text for next steps section of invalid test result--> - <string name="submission_test_result_invalid_steps_invalid_body">"Testinizi deÄŸerlendirirken bir problem oluÅŸtu. Lütfen sonraki adımlarınız için test merkezi veya laboratuvar ile görüşün.\n\nGerekirse yeni bir test kodu kaydedebilmeniz için lütfen testi Corona-Warn-App\'ten silin."</string> + <string name="submission_test_result_invalid_steps_invalid_body">"Testinizi deÄŸerlendirirken bir problem oluÅŸtu. Lütfen sonraki adımlarınız için test merkezi veya laboratuvar ile görüşün."</string> + <!-- YTXT: Body text for next steps section of invalid test result--> + <string name="submission_test_result_delete_steps_invalid_body">"Gerekirse yeni bir test kodu kaydedebilmeniz için lütfen testi Corona-Warn-App\'ten silin."</string> + <!-- XBUT: invalid test result : remove the test button --> - <string name="submission_test_result_invalid_remove_test_button">"Testi kaldır"</string> + <string name="submission_test_result_invalid_remove_test_button">"Testi Sil"</string> <!-- XHED: Dialog title for tracing required dailog --> <string name="submission_test_result_dialog_tracing_required_title">"Maruz Kalma Günlüğü gereklidir"</string> <!-- YTXT: Dialog text for tracing required dialog--> @@ -1116,9 +1131,9 @@ <!-- XHED: Dialog title for test removal --> <string name="submission_test_result_dialog_remove_test_title">"Test yalnızca bir kez taranabilir."</string> <!-- YTXT: Dialog text for test removal --> - <string name="submission_test_result_dialog_remove_test_message">"Testi kaldırırsanız test sonucunuzu alamazsınız. QR kod geçerli olsun veya olmasın test sonucunuzu test merkezinden veya laboratuvardan alacaksınız. Koronavirüs tanısı alırsanız kamu saÄŸlığı yetkilisi yasal olarak belirlenen kanal üzerinden bilgilendirilecektir ve kamu saÄŸlığı yetkilisi sizinle iletiÅŸime geçecektir."</string> + <string name="submission_test_result_dialog_remove_test_message">"Testi silerseniz test sonucunuzu alamazsınız. QR kod geçerli olsun veya olmasın test sonucunuzu test merkezinden veya laboratuvardan alacaksınız. Koronavirüs tanısı alırsanız kamu saÄŸlığı yetkilisi yasal olarak belirlenen kanal üzerinden bilgilendirilecektir ve kamu saÄŸlığı yetkilisi sizinle iletiÅŸime geçecektir."</string> <!-- XBUT: Positive button for test removal --> - <string name="submission_test_result_dialog_remove_test_button_positive">"Kaldır"</string> + <string name="submission_test_result_dialog_remove_test_button_positive">"Sil"</string> <!-- XBUT: Negative button for test removal --> <string name="submission_test_result_dialog_remove_test_button_negative">"Ä°ptal"</string> <!-- XHED: Title for test result card positive --> @@ -1158,17 +1173,13 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Test Sonucunu Al"</string> - <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"Uygulama üzerinden test sonucunuzu alın ve ardından diÄŸer kullanıcıları uyarın. Kendinizi koruyacak ve koronavirüsün yayılmasını durdurmaya yardımcı olacaksınız."</string> - <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">"Test yaptırdınız mı?"</string> + <string name="submission_dispatcher_headline">"Testinizi Kaydedin"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> <string name="submission_dispatcher_already_positive_subheadline">"PCR testinizin sonucu pozitif miydi?"</string> <!-- YTXT: Dispatcher text for QR code option --> - <string name="submission_dispatcher_card_qr">"QR Kodlu Test"</string> + <string name="submission_dispatcher_card_qr">"QR Kodu Tara"</string> <!-- YTXT: Body text for QR code dispatcher option --> - <string name="submission_dispatcher_qr_card_text">"Test belgenizin QR kodunu tarayarak testinizi kaydedin."</string> + <string name="submission_dispatcher_qr_card_text">"Uygulamada test sonucunuzu alın ve diÄŸer kullanıcıları uyarın."</string> <!-- YTXT: Dispatcher text for TAN code option --> <string name="submission_dispatcher_card_tan_code">"PCR Testi için TAN girin"</string> <!-- YTXT: Body text for TAN code dispatcher option --> @@ -1236,18 +1247,18 @@ <!-- YTXT: text after submission: pcr validation --> <string name="submission_done_share_keys">"DiÄŸer kullanıcıların uyarılabilmesi için rastgele kimliklerinizi paylaşın."</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"Kamu saÄŸlığı yetkiliniz önümüzdeki birkaç gün içinde size ulaÅŸacaktır."</string> + <string name="submission_done_contagious">"Kamu saÄŸlığı yetkiliniz önümüzdeki birkaç gün içinde size ulaÅŸabilir."</string> <!-- YTXT: text after submission: isolate --> - <string name="submission_done_isolate">"Bulaşıcı bir hastalık taşıyorsunuz. Kendinizi diÄŸer insanlardan izole edin."</string> + <string name="submission_done_isolate">"Yüksek bir olasılıkla enfekte oldunuz. Kendinizi diÄŸer insanlardan izole edin."</string> <!-- XHED: Title for further info --> <string name="submission_done_further_info_title">"DiÄŸer bilgiler:"</string> <!-- YTXT: submission done further info bullet points --> <string-array name="submission_done_further_info_bullet_points"> - <item>"Karantina süreniz genellikle 14 gündür. Lütfen belirtilerinizi nasıl geliÅŸtiÄŸini yakından izleyin."</item> + <item>"Ä°zolasyon süreniz genellikle 14 gündür. Lütfen belirtilerinizin nasıl geliÅŸtiÄŸini yakından izleyin."</item> <item>"Kamu saÄŸlığı yetkiliniz, temasa geçtiÄŸiniz kiÅŸilerin bir listesini oluÅŸturmanızı isteyecektir. Bu listeye, hasta olmadan önceki iki gün içinde 15 dakikadan uzun süreyle yakın temas halinde (2 metreden kısa mesafede, yüz yüze görüşme) olduÄŸunuz herkesi dahil etmeniz gerekir. Bunun için temas güncenizi kullanabilirsiniz: GiriÅŸleri dışa aktarmanız ve ardından yazdırmanız ya da e-posta yoluyla göndermeniz yeterlidir."</item> <item>"Lütfen özellikle akıllı telefonu olmadığı veya uygulamayı yüklemediÄŸi için doÄŸrudan uygulamanın uyarmayacağı kiÅŸileri göz önünde bulundurun."</item> - <item>"Hiçbir belirtiniz kalmasa ve kendinizi iyi hissetseniz dahi yine de hastalığı bulaÅŸtırabilirsiniz. Bu nedenle lütfen belirlenen karantina süresine uyun."</item> + <item>"Hiçbir belirtiniz kalmasa ve kendinizi iyi hissetseniz dahi yine de hastalığı bulaÅŸtırabilirsiniz. Bu nedenle lütfen belirlenen izolasyon süresine uyun."</item> </string-array> <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Tamamlandı"</string> @@ -1395,9 +1406,9 @@ <!-- XHED: submission status card positive result subtitle --> <string name="submission_status_card_positive_result_subtitle">"Lütfen unutmayın:"</string> <!-- YTXT: text for contagious card --> - <string name="submission_status_card_positive_result_contagious">"Bulaşıcı bir hastalık taşıyorsunuz. Kendinizi diÄŸer insanlardan izole edin."</string> + <string name="submission_status_card_positive_result_contagious">"Yüksek bir olasılıkla enfekte oldunuz. Kendinizi diÄŸer insanlardan izole edin."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"Kamu saÄŸlığı yetkiliniz önümüzdeki birkaç gün içinde size ulaÅŸacaktır."</string> + <string name="submission_status_card_positive_result_contact">"Kamu saÄŸlığı yetkiliniz önümüzdeki birkaç gün içinde size ulaÅŸabilir."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"DiÄŸer kullanıcıların uyarılabilmesi için rastgele kimliklerinizi paylaşın."</string> @@ -1959,7 +1970,7 @@ <!-- XACT: Button/Dialog label to cancel something--> <string name="generic_action_abort">"Ä°ptal Et"</string> <!-- XACT: Button/Dialog label to remove something--> - <string name="generic_action_remove">"Kaldır"</string> + <string name="generic_action_remove">"Sil"</string> <!-- #################################### Trace Location @@ -1991,7 +2002,7 @@ <!-- XHED: Trace location poster title --> <string name="trace_location_organiser_poster_title">"Yazdırma Sürümü"</string> <!-- XHED: Trace location check-ins consent screen title --> - <string name="trace_location_attendee_consent_title">"Konum Check-In’leri Paylaşılsın Mı?"</string> + <string name="trace_location_attendee_consent_title">"Check-In’ler Paylaşılsın Mı?"</string> <!-- XTXT: Trace location check-ins consent screen header description --> <string name="trace_location_attendee_consent_header_description">"Sizinle birlikte check in yapmış olan diÄŸer kullanıcıları uyarın. KiÅŸisel verileriniz paylaşılmayacaktır."</string> <!-- XBUT: Trace location check-ins consent screen header button --> @@ -2025,9 +2036,9 @@ <!-- XHED: Incompitability card title --> <string name="incompatible_headline">"Uyumsuzluk Uyarısı"</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_advertising_not_supported">"Akıllı telefonunuz Bluetooth üzerinden COVID-19 bildirimlerini yalnızca alabiliyor ancak gönderemiyor. Buna göre, bu arayüz ile maruz kalmalar konusunda uyarı alabilirsiniz ancak siz diÄŸer kullanıcıları uyaramazsınız. Check-in’lerden kaynaklanan uyarıları alabilir ve gönderebilirsiniz."</string> + <string name="incompatible_advertising_not_supported">"Akıllı telefonunuz Bluetooth üzerinden COVID-19 maruz kalma bildirimlerini yalnızca alabiliyor ancak gönderemiyor. Buna göre, bu arayüz ile maruz kalmalar konusunda uyarı alabilirsiniz ancak siz diÄŸer kullanıcıları uyaramazsınız. Check-in’lerden kaynaklanan uyarıları alabilir ve gönderebilirsiniz."</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_scanning_not_supported">"Akıllı telefonunuz Bluetooth üzerinden COVID-19 bildirimleri gönderemiyor veya alamıyor. Check-in’lerden kaynaklanan uyarıları alabilir ve gönderebilirsiniz."</string> + <string name="incompatible_scanning_not_supported">"Akıllı telefonunuz Bluetooth üzerinden COVID-19 maruz kalma bildirimleri gönderemiyor veya alamıyor. Check-in’lerden kaynaklanan uyarıları alabilir ve gönderebilirsiniz."</string> <!-- XTXT: Incompitability faq link for partial incompatibility --> <string name="incompatible_link_advertising_not_supported">"https://www.coronawarn.app/en/faq/#part_incompat"</string> <!-- XTXT: Incompitability faq link for full incompatibility --> diff --git a/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..d5d1096885ef77994e871ffae380903542d1ae60 --- /dev/null +++ b/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools"> + <!-- XTXT: Vaccination Details birth date --> + <string name="vaccination_details_birth_date">"DoÄŸum tarihi: %1$s"</string> + <!-- XTXT: Vaccination Details certificate date --> + <string name="vaccination_details_certificate_date">"Aşı Tarihi"</string> + <!-- XTXT: Vaccination Details vaccine name --> + <string name="vaccination_details_vaccine_name">"Aşı"</string> + <!-- XTXT: Vaccination Details vaccine manufacturer --> + <string name="vaccination_details_vaccine_manufacturer">"Ãœretici"</string> + <!-- XTXT: Vaccination Details vaccine type --> + <string name="vaccination_details_vaccine_medical_product_name">"Aşı tipi"</string> + <!-- XTXT: Vaccination Details certificate issuer --> + <string name="vaccination_details_certificate_issuer">"Düzenleyen"</string> + <!-- XTXT: Vaccination Details certificate country --> + <string name="vaccination_details_certificate_country">"Ãœlke"</string> + <!-- XTXT: Vaccination Details certificate id --> + <string name="vaccination_details_certificate_id">"Sertifika Numarası"</string> + <!-- XTXT: Vaccination Details subtitle--> + <string name="vaccination_details_subtitle">"Aşı Sertifikası"</string> + <!-- XTXT: Vaccination Details title--> + <string name="vaccination_details_title">"Aşı %1$d / %2$d"</string> + <!-- XTXT: Vaccination Qr Code card title--> + <string name="vaccination_qrcode_card_title">"%1$d / %2$d aşı sertifikası"</string> + <!-- XTXT: Vaccination Qr Code card subtitle--> + <string name="vaccination_qrcode_card_subtitle">"%1$s için aşı yapıldı - geçerlilik sonu: %2$s"</string> + + <!-- XTXT: Vaccination List title--> + <string name="vaccination_list_title">"Dijital Aşı Kanıtı"</string> + <!-- XTXT: Vaccination List complete vaccination subtitle--> + <string name="vaccination_list_complete_vaccination_subtitle">"SARS-CoV-2 Aşı Koruması"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_name_card_subtitle">"DoÄŸum tarihi: %1$s"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_title">"Aşı %1$d / %2$d"</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_subtitle">"GerçekleÅŸtirilme tarihi: %1$s"</string> + <!-- XTXT: Vaccination List immunity information card body--> + <plurals name="vaccination_list_immunity_card_body"> + <item quantity="one">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item> + <item quantity="other">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item> + <item quantity="zero">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item> + <item quantity="two">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item> + <item quantity="few">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item> + <item quantity="many">"Artık tüm aşıları aldınız ancak aşı korumanız %1$d gün daha tamamlanmayacaktır."</item> + </plurals> + <!-- XBUT: Vaccination List register additional vaccination button --> + <string name="vaccination_list_register_new_vaccination_button">"BaÅŸka Aşı Kaydet"</string> + <!-- XBUT: Vaccination List delete button --> + <string name="vaccination_list_delete_button">"Sil"</string> + <!-- XTXT: Vaccination List deletion dialog title--> + <string name="vaccination_list_deletion_dialog_title">"Aşı sertifikasını silmek istiyor musunuz?"</string> + <!-- XTXT: Vaccination List deletion dialog message--> + <string name="vaccination_list_deletion_dialog_message">"Aşı sertifikasını silerseniz uygulama artık bu aşıyı aşı durumunuzun doÄŸrulaması için kullanamaz."</string> + <!-- XBUT: Vaccination List deletion dialog positive button--> + <string name="vaccination_list_deletion_dialog_positive_button">"Sil"</string> + <!-- XBUT: Vaccination List deletion dialog negative button--> + <string name="vaccination_list_deletion_dialog_negative_button">"Ä°ptal Et"</string> + <!-- XACT: Vaccination List Qr-Code for screen readers --> + <string name="vaccination_list_qr_code_accessibility">"QR Kod"</string> + + <!-- #################################### + Homescreen cards + ###################################### --> + <!-- XHED: Title for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_registration_title">"Aşı Sertifikası Ekle"</string> + <!-- YTXT: Body text for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_registration_body">"Her zaman eriÅŸebilmek için uygulamaya aşı sertifikaları ekleyin. Bunun için, belgenizdeki QR kodu tarayın."</string> + <!-- XBUT: button for Vaccination Certificate Registration Home Card --> + <string name="vaccination_card_register">"Ekle"</string> + <!-- XHED: Homescreen vaccination status card title --> + <string name="vaccination_card_status_title">"Dijital Aşı Kanıtı"</string> + <!-- XHED: Homescreen vaccination status card vaccination name --> + <string name="vaccination_card_status_vaccination_name">"SARS-CoV-2 Aşısı"</string> + <!-- XTXT: Homescreen card incomplete vaccination status label --> + <string name="vaccination_card_status_vaccination_incomplete">"Aşı tamamlanmadı"</string> + <!-- XTXT: Homescreen card complete vaccination status label --> + <plurals name="vaccination_card_status_vaccination_complete" tools:ignore="UnusedQuantity"> + <item quantity="one">"%1$d gün içinde tam aşı koruması"</item> + <item quantity="other">"%1$d gün içinde tam aşı koruması"</item> + <item quantity="zero">"%1$d gün içinde tam aşı koruması"</item> + <item quantity="two">"%1$d gün içinde tam aşı koruması"</item> + <item quantity="few">"%1$d gün içinde tam aşı koruması"</item> + <item quantity="many">"%1$d gün içinde tam aşı koruması"</item> + </plurals> + + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_invalid">"Bu QR kod geçerli bir aşı sertifikası deÄŸildir."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_not_yet_supported">"Bu aşı sertifikası henüz uygulamanızın sürümünde desteklenmiyor. Lütfen uygulamanızı güncelleyin veya “Uygulama Bilgileri†bölümünde belirtilen teknik yardım hattı ile iletiÅŸime geçin."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_scan_again">"Aşı sertifikası akıllı telefonunuza kaydedilemedi. Lütfen daha sonra yeniden deneyin veya “Uygulama Bilgileri†bölümünde belirtilen teknik yardım hattı ile iletiÅŸime geçin."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_already_registered">"Aşı sertifikası zaten uygulamanıza kaydedilmiÅŸ."</string> + <!-- XTXT: Vaccination QR code scan error message--> + <string name="error_vc_different_person">"Bu aşı sertifikasındaki kiÅŸisel bilgiler, kaydedilmiÅŸ sertifikalardaki bilgilerle eÅŸleÅŸmiyor. Uygulamaya yalnızca bir kiÅŸiye ait sertifikalar kaydedebilirsiniz."</string> + + <!-- XTXT: Vaccination Consent title--> + <string name="vaccination_consent_title">"Ä°zniniz"</string> + <!-- XTXT: Vaccination Consent subtitle--> + <string name="vaccination_consent_headline">"Aşı Sertifikası Ekle"</string> + <!-- XTXT: Vaccination Consent subtitle of qr info --> + <string name="vaccination_consent_info_subtitle_text">"Uygulamaya dijital aşı sertifikanızı ekleyin. Aşı korumanız tamamlanır tamamlanmaz uygulamanıza aşınızın kanıtı olarak QR kodu sunabilirsiniz."</string> + <!-- XTXT: Vaccination Consent text of qr info --> + <string name="vaccination_consent_qr_info_text">"Uygulamaya bir aşı sertifikası eklemek için aşınız sırasında size verilen QR kodu tarayın."</string> + <!-- XTXT: Vaccination Consent qr code text --> + <string name="vaccination_consent_qr_info_qr_code_text">"Uygulama, QR kodun bilgilerini okur ve akıllı telefonunuzda güvenli bir alana kaydeder."</string> + <!-- XTXT: Vaccination Consent time text --> + <string name="vaccination_consent_qr_info_time_text">"Veriler, akıllı telefonda kalır. Yalnızca, doÄŸrulama için aşı sertifikanızı sunarsanız diÄŸer kullanıcılara aktarılır."</string> + <!-- XTXT: Text for vaccination consent legal information button --> + <string name="vaccination_consent_onboarding_legal_information">"Daha fazla bilgi için lütfen gizlilik bildirimine baÅŸvurun."</string> + <!-- XBUT: Text for vaccination consent accept button --> + <string name="vaccination_consent_accept_button">"Devam Et"</string> + +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values/antigen_strings.xml b/Corona-Warn-App/src/main/res/values/antigen_strings.xml index 40f157a6f3fc99e6abe1fbba1ef9a347a69fe6b1..e55b460bb10a438dadf160a0149d2a127ea89c13 100644 --- a/Corona-Warn-App/src/main/res/values/antigen_strings.xml +++ b/Corona-Warn-App/src/main/res/values/antigen_strings.xml @@ -143,7 +143,7 @@ <!-- XHED: Create RAT profile card title --> <string name="rat_profile_create_card_title">"Create Rapid Test Profile"</string> <!-- XTXT: Create RAT profile card subtitle --> - <string name="rat_profile_create_card_subtitle">"You can create a profile with your personal data, which you can submit via QR code during every rapid test."</string> + <string name="rat_profile_create_card_subtitle">"You can create a profile with your personal data, which you can submit via QR code to every participating testing point."</string> <!-- XHED: Open RAT profile card title --> <string name="rat_profile_open_card_title">"Rapid Test Profile"</string> <!-- XTXT: Open RAT profile card subtitle --> @@ -159,7 +159,7 @@ <!-- XBUT: Create RAT profile save button --> <string name="rat_profile_create_button">"Save"</string> <!-- XTXT: Create RAT profile description --> - <string name="rat_profile_create_description">"Save your personal data as a QR code to speed up registration at testing points."</string> + <string name="rat_profile_create_description">"You can create a profile with your personal data, which you can submit via QR code to every participating testing point."</string> <!-- XTXT: Create RAT profile street hint --> <string name="rat_profile_create_street_hint">"Street and House Number"</string> <!-- XTXT: Create RAT profile post code hint --> @@ -174,7 +174,7 @@ <!--RAT profile onboarding--> <string name="rat_profile_onboarding_image_content_description">"A woman with a smartphone in her hand is standing in front of a building. A QR code symbolizes the rapid test profile to be scanned."</string> <!-- XTXT: Create RAT profile onboarding title --> - <string name="rat_profile_onboarding_title">"Save your personal data as a QR code to speed up registration at testing points."</string> + <string name="rat_profile_onboarding_title">"You can create a profile with your personal data, which you can submit via QR code to every participating testing point."</string> <!-- XTXT: Create RAT profile onboarding subtitle --> <string name="rat_profile_onboarding_subtitle">"When you create a rapid test profile, you will not have to fill out your personal data again before every rapid test."</string> <!-- XTXT: Create RAT profile onboarding next button --> diff --git a/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml index a9e1cc9ce50cab0304bdf7c9b9cd6460a87cba60..fc49c3ebb20fe28e2e6b205f8fadb43ddeb2e628 100644 --- a/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml +++ b/Corona-Warn-App/src/main/res/values/contact_diary_strings.xml @@ -14,7 +14,7 @@ <string name="contact_diary_add_person_title">"Person"</string> <string name="contact_diary_add_person_text_input_name_hint">"Name"</string> <string name="contact_diary_add_text_input_phone_hint">"Phone"</string> - <string name="contact_diary_add_text_input_email_hint">"e-mail"</string> + <string name="contact_diary_add_text_input_email_hint">"E-mail"</string> <string name="contact_diary_add_person_save_button">"Save"</string> <string name="contact_diary_add_location_title">"Place"</string> <string name="contact_diary_add_location_text_input_hint">"Description"</string> @@ -32,7 +32,7 @@ <!-- XTXT: Title for the contact diary onboarding screen --> <string name="contact_diary_information_card_title">"Keep track of your contacts."</string> <!-- XTXT: Contact diary onboarding screen --> - <string name="contact_diary_onboarding_body">"Create an overview of your contacts in the last 14 days, so you’ll have a complete list at hand quickly if needed."</string> + <string name="contact_diary_onboarding_body">"Create an overview of your contacts in the last 14 days, so you’ll have a complete list at hand quickly if needed. Your exposures are also displayed here."</string> <!-- XTXT: Contact diary onboarding screen first functionality --> <string name="contact_diary_onboarding_functionality_first_section">"Enter the people you have met."</string> <!-- XTXT: Contact diary onboarding screen second functionality --> @@ -84,7 +84,6 @@ <!-- XTXT: Indicates this trace location caused a lows risk --> <string name="contact_diary_trace_location_risk_low">"low risk"</string> - <!-- XTXT: content description of contact journal image on home screen --> <string name="contact_diary_homescreen_card_image_content_description">"A closed book with a bookmark"</string> <!-- XTXT: content description of contact journal header image on onboarding screen --> diff --git a/Corona-Warn-App/src/main/res/values/release_info_strings.xml b/Corona-Warn-App/src/main/res/values/release_info_strings.xml index 111e4976d24252af61c03a60ba207e8e988da5c3..0139fcb8d8bae46019ffc85b06b1b8b89c02f793 100644 --- a/Corona-Warn-App/src/main/res/values/release_info_strings.xml +++ b/Corona-Warn-App/src/main/res/values/release_info_strings.xml @@ -17,22 +17,22 @@ <!-- XHED: Titles for the release info screen bullet points --> <string-array name="new_release_title"> - <item>Digitaler Impfnachweis</item> + <item>"Digital Proof of Vaccination"</item> </string-array> <!-- XTXT: Text bodies for the release info screen bullet points --> <string-array name="new_release_body"> - <item>Sie können jetzt Ihre Impfzertifikate in der App hinzufügen und per QR-Code vorweisen. 14 Tage nach der letzten Impfung zeigt die App den vollständigen Impfschutz an.</item> + <item>"You can now add your vaccination certificates in the app and present them via QR code. The app displays full vaccination protection 14 days after the final vaccination."</item> </string-array> <!-- XTXT: Text labels that will be converted to Links --> <string-array name="new_release_linkified_labels"> - <item></item> + <item /> </string-array> <!-- XTXT: URL destinations for the lables in new_release_linkified_labels --> <string-array name="new_release_target_urls"> - <item></item> + <item /> </string-array> -</resources> +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml index 6901a354374c9079304532a17c23779bbfe567f8..cf882005a7c7e62fbbee68fa03acce87151dd2c0 100644 --- a/Corona-Warn-App/src/main/res/values/strings.xml +++ b/Corona-Warn-App/src/main/res/values/strings.xml @@ -412,7 +412,9 @@ <!-- YTXT: onboarding(together) - paragraph --> <string name="onboarding_body_4">"If you want, you can use the app to prove your personal infection status (a negative rapid test, for example). Please note, however, that you are under no obligation to use the app to prove your infection status. You can also prove your infection status in another manner compliant with the legal regulations at your residence."</string> <!-- YTXT: onboarding(together) - paragraph --> - <string name="onboarding_body_5">"The app logs encounters between individuals by exchanging encrypted, random IDs between their smartphones, whereby no personal data whatsoever is accessed."</string> + <string name="onboarding_body_5">"Ebenso können Sie Ihren persönlichen Impfstatus nachweisen."</string> + <!-- YTXT: onboarding(together) - paragraph --> + <string name="onboarding_body_6">"Die App merkt sich Begegnungen zwischen Menschen, indem ihre Smartphones verschlüsselte Zufalls-IDs austauschen. Persönliche Daten werden dabei nicht ausgetauscht."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"A group of persons use their smartphones around town."</string> <!-- XACT: Onboarding (privacy) page title --> @@ -748,7 +750,7 @@ <string name="settings_privacy_preserving_analytics_title">"Share Data"</string> <!-- XTXT: privacy preserving analytics settings switch subtitle --> - <string name="settings_analytics_switch_subtitle">"Share User Data"</string> + <string name="settings_analytics_switch_subtitle">"Share Data"</string> <!-- #################################### App Information @@ -1039,7 +1041,7 @@ <!-- YTXT: Body for consent main section second point --> <string name="submission_consent_main_second_point">"Your identity will remain secret. Other users will not find out who has shared a test result."</string> <!-- YTXT: Body for consent main section third point --> - <string name="submission_consent_main_third_point">"Under “My Check-Insâ€, you can see the events and places whose checked-in guests will be warned. You can remove individual check-ins from the list to exclude them from the warning process."</string> + <string name="submission_consent_main_third_point">"Under “My Check-Insâ€, you can see the events and places whose checked-in guests will be warned. You can delete individual check-ins from the list to exclude them from the warning process."</string> <!-- YTXT: Body for consent main section fourth point --> <string name="submission_consent_main_fourth_point">"You must be at least 16 years old to grant your consent."</string> <!-- YTXT: Body for consent main section final id consent --> @@ -1054,7 +1056,7 @@ <!-- YTXT: Body for no consent section third point --> <string name="submission_no_consent_third_point">"Your identity will remain secret. Other users will not find out who has shared a test result."</string> <!-- YTXT: Body for no consent section fourth point --> - <string name="submission_no_consent_fourth_point">"Under “My Check-Insâ€, you can see the events and places whose checked-in guests will be warned. You can remove individual check-ins from the list to exclude them from the warning process."</string> + <string name="submission_no_consent_fourth_point">"Under “My Check-Insâ€, you can see the events and places whose checked-in guests will be warned. You can delete individual check-ins from the list to exclude them from the warning process."</string> <!-- YTXT: Body for no consent section fifth point --> <string name="submission_no_consent_fifth_point">"You must be at least 16 years old to grant your consent."</string> @@ -1064,13 +1066,13 @@ <!-- XHED: Page subheadline for test result --> <string name="submission_test_result_subtitle">"How this works:"</string> <!-- XHED: Page headline for results next steps --> - <string name="submission_test_result_steps_added_heading">"Test added successfully"</string> + <string name="submission_test_result_steps_added_heading">"Your PCR test was added successfully."</string> <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Your test has been stored in the Corona-Warn-App."</string> <!-- XHED: Page headline for pending test result next steps --> <string name="submission_test_result_pending_steps_waiting_heading">"Your test result is not available yet."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> - <string name="submission_test_result_pending_steps_waiting_body">"As soon as your test result becomes available, it will be displayed in the app.\n\nYou will also receive your test result outside of the app. The public health authorities will notify you, should your test be positive.\n\nIf you are notified of a positive test result outside the app, please remove the test currently registered in the app. Call the number shown under “Request TAN†to get a TAN. You can then use this TAN to register your result in the app and warn others."</string> + <string name="submission_test_result_pending_steps_waiting_body">"As soon as your test result becomes available, it will be displayed in the app.\n\nYou will also receive your test result outside of the app. The public health authorities will notify you, should your test be positive.\n\nIf you are notified of a positive test result outside the app, please delete the test currently registered in the app. Call the number shown under “Request TAN†to get a TAN. You can then use this TAN to register your result in the app and warn others."</string> <!-- XHED: Page headline for pending test result next steps --> <string name="submission_test_result_pending_steps_waiting_pcr_heading">"Your test result is not available yet."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> @@ -1109,17 +1111,18 @@ <!-- XHED: Page headline for invalid test result screen --> - <string name="submission_test_result_invalid_steps_invalid_heading">"Your Test Result"</string> + <string name="submission_test_result_invalid_steps_invalid_heading">"Your test cannot be evaluated"</string> + <!-- XHED: Page headline for invalid test result screen --> - <string name="submission_test_result_delete_steps_invalid_heading">"Test entfernen"</string> + <string name="submission_test_result_delete_steps_invalid_heading">"Delete Test"</string> <!-- YTXT: Body text for next steps section of invalid test result--> - <string name="submission_test_result_invalid_steps_invalid_body">"There was a problem evaluating your test. Please contact the test center or laboratory involved to find out how to proceed.\n\nPlease delete the test from your Corona-Warn-App so that you will be able to save a new test code there, if necessary."</string> + <string name="submission_test_result_invalid_steps_invalid_body">"There was a problem evaluating your test. Please contact the test center or laboratory involved to find out how to proceed."</string> <!-- YTXT: Body text for next steps section of invalid test result--> - <string name="submission_test_result_delete_steps_invalid_body">"Bitte entfernen Sie den Test wieder aus der Corona-Warn-App, damit Sie bei Bedarf einen neuen Test hinterlegen können."</string> + <string name="submission_test_result_delete_steps_invalid_body">"Please delete the test from the Corona-Warn-App, so that you can save a new test code here if necessary."</string> <!-- XBUT: invalid test result : remove the test button --> - <string name="submission_test_result_invalid_remove_test_button">"Remove test"</string> + <string name="submission_test_result_invalid_remove_test_button">"Delete Test"</string> <!-- XHED: Dialog title for tracing required dailog --> <string name="submission_test_result_dialog_tracing_required_title">"Exposure Logging required"</string> <!-- YTXT: Dialog text for tracing required dialog--> @@ -1129,9 +1132,9 @@ <!-- XHED: Dialog title for test removal --> <string name="submission_test_result_dialog_remove_test_title">"The test can only be scanned once."</string> <!-- YTXT: Dialog text for test removal --> - <string name="submission_test_result_dialog_remove_test_message">"If you remove the test, you can no longer retrieve your test result. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with coronavirus, the public health authority will be notified through the legally prescribed channel and will contact you."</string> + <string name="submission_test_result_dialog_remove_test_message">"If you delete the test, you can no longer retrieve your test result. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with coronavirus, the public health authority will be notified through the legally prescribed channel and will contact you."</string> <!-- XBUT: Positive button for test removal --> - <string name="submission_test_result_dialog_remove_test_button_positive">"Remove"</string> + <string name="submission_test_result_dialog_remove_test_button_positive">"Delete"</string> <!-- XBUT: Negative button for test removal --> <string name="submission_test_result_dialog_remove_test_button_negative">"Cancel"</string> <!-- XHED: Title for test result card positive --> @@ -1171,11 +1174,7 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Test registrieren"</string> - <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"Retrieve your test result through the app and then warn others. You’ll protect yourself and help to stop the spread of coronavirus."</string> - <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">"Have you been tested?"</string> + <string name="submission_dispatcher_headline">"Register Your Test"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> <string name="submission_dispatcher_already_positive_subheadline">"Was your PCR test positive?"</string> <!-- YTXT: Dispatcher text for QR code option --> @@ -1249,18 +1248,18 @@ <!-- YTXT: text after submission: pcr validation --> <string name="submission_done_share_keys">"Share your random IDs so that others can be warned."</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"The public health authority will contact you within the next few days."</string> + <string name="submission_done_contagious">"The public health authority may contact you within the next few days."</string> <!-- YTXT: text after submission: isolate --> - <string name="submission_done_isolate">"You are infectious. Isolate yourself from other people."</string> + <string name="submission_done_isolate">"There is a high probability that you are infectious. Isolate yourself from other people."</string> <!-- XHED: Title for further info --> <string name="submission_done_further_info_title">"Other information:"</string> <!-- YTXT: submission done further info bullet points --> <string-array name="submission_done_further_info_bullet_points"> - <item>"Your quarantine period is usually 14 days. Please monitor how your symptoms develop closely."</item> + <item>"Your isolation period is usually 14 days. Please monitor how your symptoms develop closely."</item> <item>"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 became ill. You can use your contact journal for this: simply export the entries and then print them out or send them via e-mail."</item> <item>"Please particularly consider people who will not be notified directly by the app since they don’t own a smartphone, or haven’t installed the app."</item> - <item>"Even when you no longer have any symptoms and you feel well again, you could still be infectious, so please follow the designated quarantine period."</item> + <item>"Even when you no longer have any symptoms and you feel well again, you could still be infectious, so please follow the designated isolation period."</item> </string-array> <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Done"</string> @@ -1408,9 +1407,9 @@ <!-- XHED: submission status card positive result subtitle --> <string name="submission_status_card_positive_result_subtitle">"Please note:"</string> <!-- YTXT: text for contagious card --> - <string name="submission_status_card_positive_result_contagious">"You are infectious. Isolate yourself from other people."</string> + <string name="submission_status_card_positive_result_contagious">"There is a high probability that you are infectious. Isolate yourself from other people."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"The public health authority will contact you within the next few days."</string> + <string name="submission_status_card_positive_result_contact">"The public health authority may contact you within the next few days."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"Share your random IDs so that others can be warned."</string> @@ -1972,7 +1971,7 @@ <!-- XACT: Button/Dialog label to cancel something--> <string name="generic_action_abort">"Cancel"</string> <!-- XACT: Button/Dialog label to remove something--> - <string name="generic_action_remove">"Remove"</string> + <string name="generic_action_remove">"Delete"</string> <!-- #################################### Trace Location @@ -2004,7 +2003,7 @@ <!-- XHED: Trace location poster title --> <string name="trace_location_organiser_poster_title">"Print Version"</string> <!-- XHED: Trace location check-ins consent screen title --> - <string name="trace_location_attendee_consent_title">"Share Location Check-Ins?"</string> + <string name="trace_location_attendee_consent_title">"Share Check-Ins?"</string> <!-- XTXT: Trace location check-ins consent screen header description --> <string name="trace_location_attendee_consent_header_description">"Warn others who checked in with you. Your personal data will not be shared."</string> <!-- XBUT: Trace location check-ins consent screen header button --> @@ -2038,11 +2037,11 @@ <!-- XHED: Incompitability card title --> <string name="incompatible_headline">"Incompatibility Warning"</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_advertising_not_supported">"Your smartphone can only receive COVID-19 notifications via Bluetooth, but not send them. This means you can be warned of exposures through this interface, but you cannot warn others of exposures yourself. You can send and receive warnings that result from check-ins."</string> + <string name="incompatible_advertising_not_supported">"Your smartphone can only receive COVID-19 exposure notifications via Bluetooth, but not send them. This means you can be warned of exposures through this interface, but you cannot warn others of exposures yourself. You can send and receive warnings that result from check-ins."</string> <!-- XTXT: Incompitability card content --> - <string name="incompatible_scanning_not_supported">"Your smartphone cannot send or receive COVID-19 notifications via Bluetooth. You can send and receive warnings that result from check-ins."</string> - <!-- XTXT: Incompatibility faq link for partial incompatibility --> + <string name="incompatible_scanning_not_supported">"Your smartphone cannot send or receive COVID-19 exposure notifications via Bluetooth. You can send and receive warnings that result from check-ins."</string> + <!-- XTXT: Incompitability faq link for partial incompatibility --> <string name="incompatible_link_advertising_not_supported">"https://www.coronawarn.app/en/faq/#part_incompat"</string> - <!-- XTXT: Incompatibility faq link for full incompatibility --> + <!-- XTXT: Incompitability faq link for full incompatibility --> <string name="incompatible_link_scanning_not_supported">"https://www.coronawarn.app/en/faq/#full_incompat"</string> -</resources> +</resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values/vaccination_strings.xml index 80ce5d67e97a08172f945bcd6420adb4d89a09f9..23686badeb4b8aed740ca219d7b2c806eab88a71 100644 --- a/Corona-Warn-App/src/main/res/values/vaccination_strings.xml +++ b/Corona-Warn-App/src/main/res/values/vaccination_strings.xml @@ -1,123 +1,115 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation"> +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <!-- XTXT: Vaccination Details birth date --> - <string name="vaccination_details_birth_date">Geboren %1$s</string> + <string name="vaccination_details_birth_date">"Born %1$s"</string> <!-- XTXT: Vaccination Details certificate date --> - <string name="vaccination_details_certificate_date">Datum der Impfung</string> + <string name="vaccination_details_certificate_date">"Vaccination Date"</string> <!-- XTXT: Vaccination Details vaccine name --> - <string name="vaccination_details_vaccine_name">Impfstoff</string> + <string name="vaccination_details_vaccine_name">"Vaccine"</string> <!-- XTXT: Vaccination Details vaccine manufacturer --> - <string name="vaccination_details_vaccine_manufacturer">Hersteller</string> + <string name="vaccination_details_vaccine_manufacturer">"Manufacturer"</string> <!-- XTXT: Vaccination Details vaccine type --> - <string name="vaccination_details_vaccine_medical_product_name">Impfstoffart</string> + <string name="vaccination_details_vaccine_medical_product_name">"Vaccine type"</string> <!-- XTXT: Vaccination Details certificate issuer --> - <string name="vaccination_details_certificate_issuer">Aussteller</string> + <string name="vaccination_details_certificate_issuer">"Issuer"</string> <!-- XTXT: Vaccination Details certificate country --> - <string name="vaccination_details_certificate_country">Land</string> + <string name="vaccination_details_certificate_country">"Country"</string> <!-- XTXT: Vaccination Details certificate id --> - <string name="vaccination_details_certificate_id">Zertifikationsnummer</string> + <string name="vaccination_details_certificate_id">"Certification Number"</string> <!-- XTXT: Vaccination Details subtitle--> - <string name="vaccination_details_subtitle">Impfzertifikat</string> + <string name="vaccination_details_subtitle">"Vaccination Certificate"</string> <!-- XTXT: Vaccination Details title--> - <string name="vaccination_details_title">Impfung %1$d von %2$d</string> + <string name="vaccination_details_title">"Vaccination %1$d of %2$d"</string> <!-- XTXT: Vaccination Qr Code card title--> - <string name="vaccination_qrcode_card_title">Impfzertifikat %1$d von %2$d</string> + <string name="vaccination_qrcode_card_title">"Vaccination certificate %1$d of %2$d"</string> <!-- XTXT: Vaccination Qr Code card subtitle--> - <string name="vaccination_qrcode_card_subtitle">Geimpft %1$s - gültig bis %2$s</string> + <string name="vaccination_qrcode_card_subtitle">"Vaccinated %1$s - valid to %2$s"</string> <!-- XTXT: Vaccination List title--> - <string name="vaccination_list_title">Digitaler Impfnachweis</string> + <string name="vaccination_list_title">"Digital Proof of Vaccination"</string> <!-- XTXT: Vaccination List complete vaccination subtitle--> <string name="vaccination_list_complete_vaccination_subtitle">SARS-CoV-2-Impfschutz</string> - <!-- XTXT: Vaccination List top card title--> - <string name="vaccination_list_top_card_title">SARS-CoV-2 Impfung</string> <!-- XTXT: Vaccination List top card subtitle--> - <string name="vaccination_list_top_card_subtitle">Unvollständiger Impfschutz</string> - <!-- XTXT: Vaccination List name card subtitle--> - <string name="vaccination_list_name_card_subtitle">geboren %1$s</string> + <string name="vaccination_list_name_card_subtitle">"Born %1$s"</string> <!-- XTXT: Vaccination List top card subtitle--> - <string name="vaccination_list_vaccination_card_title">Impfung %1$d von %2$d</string> + <string name="vaccination_list_vaccination_card_title">"Vaccination %1$d of %2$d"</string> <!-- XTXT: Vaccination List top card subtitle--> - <string name="vaccination_list_vaccination_card_subtitle">durchgeführt am %1$s</string> + <string name="vaccination_list_vaccination_card_subtitle">"Performed on %1$s"</string> <!-- XTXT: Vaccination List immunity information card body--> <plurals name="vaccination_list_immunity_card_body"> - <item quantity="one">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tag vollständig.</item> - <item quantity="other">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> - <item quantity="zero">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> - <item quantity="two">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> - <item quantity="few">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> - <item quantity="many">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + <item quantity="one">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d day."</item> + <item quantity="other">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item> + <item quantity="zero">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item> + <item quantity="two">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item> + <item quantity="few">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item> + <item quantity="many">"You have now received all the vaccinations, however, your vaccination protection will not be complete for another %1$d days."</item> </plurals> <!-- XBUT: Vaccination List register additional vaccination button --> - <string name="vaccination_list_register_new_vaccination_button">Weitere Impfung registrieren</string> + <string name="vaccination_list_register_new_vaccination_button">"Register Another Vaccination"</string> <!-- XBUT: Vaccination List delete button --> - <string name="vaccination_list_delete_button">Entfernen</string> + <string name="vaccination_list_delete_button">"Delete"</string> <!-- XTXT: Vaccination List deletion dialog title--> - <string name="vaccination_list_deletion_dialog_title">Wollen Sie das Impfzertifikat wirklich entfernen?</string> + <string name="vaccination_list_deletion_dialog_title">"Do you want to delete the vaccination certificate?"</string> <!-- XTXT: Vaccination List deletion dialog message--> - <string name="vaccination_list_deletion_dialog_message">Wenn Sie das Impfzertifikat entfernen, kann die App die Impfung nicht mehr für die Prüfung Ihres Impfstatus berücksichtigen.</string> + <string name="vaccination_list_deletion_dialog_message">"If you delete the vaccination certificate, the app can no longer use the vaccination for the verification of your vaccination status."</string> <!-- XBUT: Vaccination List deletion dialog positive button--> - <string name="vaccination_list_deletion_dialog_positive_button">Entfernen</string> + <string name="vaccination_list_deletion_dialog_positive_button">"Delete"</string> <!-- XBUT: Vaccination List deletion dialog negative button--> - <string name="vaccination_list_deletion_dialog_negative_button">Abbrechen</string> + <string name="vaccination_list_deletion_dialog_negative_button">"Cancel"</string> <!-- XACT: Vaccination List Qr-Code for screen readers --> - <string name="vaccination_list_qr_code_accessibility">Qr-Code</string> + <string name="vaccination_list_qr_code_accessibility">"QR Code"</string> <!-- #################################### Homescreen cards ###################################### --> <!-- XHED: Title for Vaccination Certificate Registration Home Card --> - <string name="vaccination_card_registration_title">"Impfzertifikat registrieren"</string> + <string name="vaccination_card_registration_title">"Add Vaccination Certificate"</string> <!-- YTXT: Body text for Vaccination Certificate Registration Home Card --> - <string name="vaccination_card_registration_body">"Scannen Sie den QR-Code auf Ihrem Impfzertifikat, um Ihre Impfung zu registrieren und einen digitalen Impfnachweis zu erhalten."</string> + <string name="vaccination_card_registration_body">"Add vaccination certificates in the app so you always have them with you. To do so, scan the QR code on your document."</string> <!-- XBUT: button for Vaccination Certificate Registration Home Card --> - <string name="vaccination_card_register">"Registrieren"</string> - - <!-- XHED: Homescreen card title --> - <string name="vaccination_card_status_title">Digitaler Impfnachweis</string> + <string name="vaccination_card_register">"Add"</string> + <!-- XHED: Homescreen vaccination status card title --> + <string name="vaccination_card_status_title">"Digital Proof of Vaccination"</string> <!-- XHED: Homescreen vaccination status card vaccination name --> - <string name="vaccination_card_status_vaccination_name">SARS-CoV-2 Impfschutz</string> + <string name="vaccination_card_status_vaccination_name">"SARS-CoV-2 Vaccination"</string> <!-- XTXT: Homescreen card incomplete vaccination status label --> - <string name="vaccination_card_status_vaccination_incomplete">Unvollständiger Impfschutz</string> + <string name="vaccination_card_status_vaccination_incomplete">"Vaccination incomplete"</string> <!-- XTXT: Homescreen card complete vaccination status label --> - <plurals name="vaccination_card_status_vaccination_complete"> - <item quantity="one">Vollständiger Impfschutz in %1$d Tag</item> - <item quantity="other">Vollständiger Impfschutz in %1$d Tagen</item> - <item quantity="zero">Vollständiger Impfschutz in %1$d Tagen</item> - <item quantity="two">Vollständiger Impfschutz in %1$d Tagen</item> - <item quantity="few">Vollständiger Impfschutz in %1$d Tagen</item> - <item quantity="many">Vollständiger Impfschutz in %1$d Tagen</item> + <plurals name="vaccination_card_status_vaccination_complete" tools:ignore="UnusedQuantity"> + <item quantity="one">"Full vaccination protection in %1$d day"</item> + <item quantity="other">"Full vaccination protection in %1$d days"</item> + <item quantity="zero">"Full vaccination protection in %1$d days"</item> + <item quantity="two">"Full vaccination protection in %1$d days"</item> + <item quantity="few">"Full vaccination protection in %1$d days"</item> + <item quantity="many">"Full vaccination protection in %1$d days"</item> </plurals> <!-- XTXT: Vaccination QR code scan error message--> - <string name="error_vc_invalid"></string> + <string name="error_vc_invalid">"This QR code is not a valid vaccination certificate."</string> <!-- XTXT: Vaccination QR code scan error message--> - <string name="error_vc_not_yet_supported"></string> + <string name="error_vc_not_yet_supported">"This vaccination certificate is not supported in your app version yet. Please update your app or contact the technical hotline under “App Informationâ€."</string> <!-- XTXT: Vaccination QR code scan error message--> - <string name="error_vc_scan_again"></string> + <string name="error_vc_scan_again">"The vaccination certificate could not be saved on your smartphone. Please try again later or contact the technical hotline under “App Informationâ€."</string> <!-- XTXT: Vaccination QR code scan error message--> - <string name="error_vc_already_registered"></string> + <string name="error_vc_already_registered">"The vaccination certificate is already registered in your app."</string> <!-- XTXT: Vaccination QR code scan error message--> - <string name="error_vc_different_person"></string> + <string name="error_vc_different_person">"The personal information of this vaccination certificate does not match that of the certificates already registered. You can only register certificates for one person in the app."</string> <!-- XTXT: Vaccination Consent title--> - <string name="vaccination_consent_title">Ihr Einverständnis</string> + <string name="vaccination_consent_title">"Your Consent"</string> <!-- XTXT: Vaccination Consent subtitle--> - <string name="vaccination_consent_headline">Impfzertifikat registrieren</string> + <string name="vaccination_consent_headline">"Add Vaccination Certificate"</string> <!-- XTXT: Vaccination Consent subtitle of qr info --> - <string name="vaccination_consent_info_subtitle_text">"Erstellen Sie einen digitalen Impfnachweis. Sie finden weitere Informationen in der FAQ zum Impfen."</string> - <!-- XTXT: Vaccination Consent subtitle of qr info (part that should be displayed as link) --> - <string name="vaccination_consent_info_subtitle_text_link_label">"FAQ zum Impfen."</string> + <string name="vaccination_consent_info_subtitle_text">"Add your digital vaccination certificate in the app. As soon as your vaccination protection is complete, you can present the QR code in your app as proof of your vaccination."</string> <!-- XTXT: Vaccination Consent text of qr info --> - <string name="vaccination_consent_qr_info_text">"Scannen Sie den QR-Code auf Ihrem Impfzertifikat, um das Zertifikat zu registrieren."</string> + <string name="vaccination_consent_qr_info_text">"To add a vaccination certificate in the app, scan the QR code that you received during your vaccination."</string> <!-- XTXT: Vaccination Consent qr code text --> - <string name="vaccination_consent_qr_info_qr_code_text">"Die App erstellt einen Impfnachweis. Der QR-Code zum vollständigen Impfnachweis erhalten Sie, wenn Sie alle Impfungen erhalten haben. Je nach Impfstoff können mehrere Impftermine nötig sein."</string> + <string name="vaccination_consent_qr_info_qr_code_text">"The app reads the information from the QR code and saves it in a secure area on your smartphone."</string> <!-- XTXT: Vaccination Consent time text --> - <string name="vaccination_consent_qr_info_time_text">"Ihr Impfnachweis wird in regelmäßigen Abständen automatisch aktualisiert. Wenn durch Mutationen des Coronavirus neue Impfungen nötig werden, kann Ihr Impfnachweis ungültig werden."</string> + <string name="vaccination_consent_qr_info_time_text">"The data will remain on the smartphone. It will only be transmitted to others if you present your vaccination certificate for verification."</string> <!-- XTXT: Text for vaccination consent legal information button --> - <string name="vaccination_consent_onboarding_legal_information">"Weitere Hinweise finden Sie in der Datenschutzerklärung."</string> + <string name="vaccination_consent_onboarding_legal_information">"For more information, please refer to the privacy notice."</string> <!-- XBUT: Text for vaccination consent accept button --> - <string name="vaccination_consent_accept_button">"Einverstanden"</string> - <!-- XTXT: Vaccination Consent FAQ Url --> - <string name="vaccination_consent_faq_url">"https://www.coronawarn.app/de/faq/"</string> + <string name="vaccination_consent_accept_button">"Continue"</string> + </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/BugCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/BugCensorTest.kt index 988042877fb6032ffa037c2ee5957c30ec905798..bb6d1f2f72da7c2ac8082e732351183e90880b90 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/BugCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/BugCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import org.junit.jupiter.api.Test @@ -100,15 +99,8 @@ class BugCensorTest : BaseTest() { } @Test - fun `loglines are only copied if the message is different`() { - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Message", - tag = "Tag", - throwable = null - ) - logLine.toNewLogLineIfDifferent("Message") shouldBe null - logLine.toNewLogLineIfDifferent("Message ") shouldNotBe logLine + fun `cesnsor string is nulled if not modified`() { + BugCensor.CensoredString("abc", 1..2).toNullIfUnmodified() shouldNotBe null + BugCensor.CensoredString("abc", null).toNullIfUnmodified() shouldBe null } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CensorInjectionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CensorInjectionTest.kt index cf4989e79c22668f3f03905bd2d0845dd589b5f8..915ca4bb0b46e5c24d9890a5d6516565e5218ced 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CensorInjectionTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CensorInjectionTest.kt @@ -13,7 +13,9 @@ import de.rki.coronawarnapp.submission.SubmissionSettings import io.github.classgraph.ClassGraph import io.kotest.matchers.collections.shouldContainAll import io.kotest.matchers.shouldBe +import io.mockk.every import io.mockk.mockk +import kotlinx.coroutines.flow.flowOf import org.junit.jupiter.api.Test import testhelpers.BaseTest import timber.log.Timber @@ -67,7 +69,12 @@ class MockProvider { @Singleton @Provides - fun diary(): ContactDiaryRepository = mockk() + fun diary(): ContactDiaryRepository = mockk() { + every { people } returns flowOf(emptyList()) + every { personEncounters } returns flowOf(emptyList()) + every { locations } returns flowOf(emptyList()) + every { locationVisits } returns flowOf(emptyList()) + } @Singleton @Provides @@ -75,15 +82,21 @@ class MockProvider { @Singleton @Provides - fun coronaTestRepository(): CoronaTestRepository = mockk() + fun coronaTestRepository(): CoronaTestRepository = mockk() { + every { coronaTests } returns flowOf(emptySet()) + } @Singleton @Provides - fun checkInRepository(): CheckInRepository = mockk() + fun checkInRepository(): CheckInRepository = mockk() { + every { allCheckIns } returns flowOf(emptyList()) + } @Singleton @Provides - fun traceLocationRepository(): TraceLocationRepository = mockk() + fun traceLocationRepository(): TraceLocationRepository = mockk() { + every { allTraceLocations } returns flowOf(emptyList()) + } @Singleton @Provides diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CheckInsCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CheckInsCensorTest.kt index 818cdbb8e7e03ed2b86cb1cfce7ea7c8e59a0245..b49f0ac8ac868f5e10a95e4d5253217f490c1cc5 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CheckInsCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CheckInsCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.presencetracing.CheckInsCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.presencetracing.checkins.CheckIn import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository import io.kotest.matchers.shouldBe @@ -12,6 +11,7 @@ import io.mockk.mockk import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest @@ -41,7 +41,7 @@ internal class CheckInsCensorTest : BaseTest() { } @Test - fun `checkLog() should return LogLine with censored check-in information`() = runBlocking { + fun `checkLog() should return LogLine with censored check-in information`() = runBlockingTest { every { checkInsRepo.allCheckIns } returns flowOf( listOf( mockCheckIn( @@ -59,36 +59,59 @@ internal class CheckInsCensorTest : BaseTest() { val censor = createInstance(this) - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = - """ - Let's go to Moe's Tavern in Near 742 Evergreen Terrace, 12345 Springfield. - Who needs the Kwik-E-Mart in Some Street, 12345 Springfield? I doooo! - """.trimIndent(), - tag = "I am tag", - throwable = null - ) + val logLineToCensor = + """ + Let's go to Moe's Tavern in Near 742 Evergreen Terrace, 12345 Springfield. + Who needs the Kwik-E-Mart in Some Street, 12345 Springfield? I doooo! + """.trimIndent() + + censor.checkLog(logLineToCensor)!!.string shouldBe """ + Let's go to CheckIn#1/Description in CheckIn#1/Address. + Who needs the CheckIn#2/Description in CheckIn#2/Address? I doooo! + """.trimIndent() + } - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ - Let's go to CheckIn#1/Description in CheckIn#1/Address. - Who needs the CheckIn#2/Description in CheckIn#2/Address? I doooo! - """.trimIndent() + @Test + fun `censoring should still work after user deletes his check-ins`() = runBlockingTest { + every { checkInsRepo.allCheckIns } returns flowOf( + listOf( + mockCheckIn( + checkInId = 1, + checkInDescription = "Moe's Tavern", + checkInAddress = "Near 742 Evergreen Terrace, 12345 Springfield" + ), + mockCheckIn( + checkInId = 2, + checkInDescription = "Kwik-E-Mart", + checkInAddress = "Some Street, 12345 Springfield" + ) + ), + listOf( + mockCheckIn( + checkInId = 1, + checkInDescription = "Moe's Tavern", + checkInAddress = "Near 742 Evergreen Terrace, 12345 Springfield" + ), + /* deleted: mockCheckIn( + checkInId = 2, + checkInDescription = "Kwik-E-Mart", + checkInAddress = "Some Street, 12345 Springfield" + )*/ + ) ) - // censoring should still work after user deletes his check-ins - every { checkInsRepo.allCheckIns } returns flowOf(emptyList()) + val censor = createInstance(this) - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ - Let's go to CheckIn#1/Description in CheckIn#1/Address. - Who needs the CheckIn#2/Description in CheckIn#2/Address? I doooo! - """.trimIndent() - ) + val logLineToCensor = + """ + Let's go to Moe's Tavern in Near 742 Evergreen Terrace, 12345 Springfield. + Who needs the Kwik-E-Mart in Some Street, 12345 Springfield? I doooo! + """.trimIndent() + + censor.checkLog(logLineToCensor)!!.string shouldBe """ + Let's go to CheckIn#1/Description in CheckIn#1/Address. + Who needs the CheckIn#2/Description in CheckIn#2/Address? I doooo! + """.trimIndent() } @Test @@ -96,13 +119,7 @@ internal class CheckInsCensorTest : BaseTest() { every { checkInsRepo.allCheckIns } returns flowOf(emptyList()) val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Some log message that shouldn't be censored.", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Some log message that shouldn't be censored." censor.checkLog(logLine) shouldBe null } @@ -126,13 +143,7 @@ internal class CheckInsCensorTest : BaseTest() { ) val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Some log message that shouldn't be censored.", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Some log message that shouldn't be censored." censor.checkLog(logLine) shouldBe null } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CoronaTestCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CoronaTestCensorTest.kt index f80997a6a41890e3097f493997f8db9ea38ce5b5..e61a463d49af4b386e64ff18df2eac1b0c3231a5 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CoronaTestCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CoronaTestCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.submission.CoronaTestCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.coronatest.CoronaTestRepository import de.rki.coronawarnapp.coronatest.type.CoronaTest import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest @@ -13,6 +12,7 @@ import io.mockk.impl.annotations.MockK import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.TestCoroutineScope import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -46,22 +46,15 @@ class CoronaTestCensorTest : BaseTest() { } private fun createInstance() = CoronaTestCensor( + debugScope = TestCoroutineScope(), coronaTestRepository = coronaTestRepository ) @Test fun `censoring replaces the logline message`() = runBlockingTest { val instance = createInstance() - val filterMe = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier", - tag = "I'm a tag", - throwable = null - ) - instance.checkLog(filterMe) shouldBe filterMe.copy( - message = "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" - ) + val filterMe = "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier" + instance.checkLog(filterMe)!!.string shouldBe "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" verify { coronaTestRepository.coronaTests } } @@ -71,26 +64,15 @@ class CoronaTestCensorTest : BaseTest() { coronaTests.value = emptySet() val instance = createInstance() - val filterMeNot = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier", - tag = "I'm a tag", - throwable = null - ) + val filterMeNot = + "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier" instance.checkLog(filterMeNot) shouldBe null } @Test fun `censoring returns null if there is no match`() = runBlockingTest { val instance = createInstance() - val filterMeNot = LogLine( - timestamp = 1, - priority = 3, - message = "I'm not a registration token ;)", - tag = "I'm a tag", - throwable = null - ) + val filterMeNot = "I'm not a registration token ;)" instance.checkLog(filterMeNot) shouldBe null } @@ -99,23 +81,13 @@ class CoronaTestCensorTest : BaseTest() { val censor = createInstance() - val filterMe = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier", - tag = "I'm a tag", - throwable = null - ) + val filterMe = "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier" - censor.checkLog(filterMe) shouldBe filterMe.copy( - message = "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" - ) + censor.checkLog(filterMe)!!.string shouldBe "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" // delete all tests coronaTests.value = emptySet() - censor.checkLog(filterMe) shouldBe filterMe.copy( - message = "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" - ) + censor.checkLog(filterMe)!!.string shouldBe "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryEncounterCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryEncounterCensorTest.kt index fead49fe948f4b9fc1d76262ba6fe22651ba2830..75740a998fe5238d8e097c4a0c0abd956321205d 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryEncounterCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryEncounterCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryEncounterCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPersonEncounter import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import io.kotest.matchers.shouldBe @@ -51,51 +50,57 @@ class DiaryEncounterCensorTest : BaseTest() { ) val instance = createInstance(this) - val censorMe = LogLine( - timestamp = 1, - priority = 3, - message = - """ - On A rainy day, - two persons Spilled coffee on each others laptops, - everyone disliked that. - """.trimIndent(), - tag = "I'm a tag", - throwable = null - ) + val censorMe = + """ + On A rainy day, + two persons Spilled coffee on each others laptops, + everyone disliked that. + """.trimIndent() + + instance.checkLog(censorMe)!!.string shouldBe + """ + On Encounter#2/Circumstances, + two persons Encounter#3/Circumstances, + everyone disliked that. + """.trimIndent() + } - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - On Encounter#2/Circumstances, - two persons Encounter#3/Circumstances, - everyone disliked that. - """.trimIndent() + @Test + fun `censoring should still work after encounters are deleted`() = runBlockingTest { + every { diaryRepo.personEncounters } returns flowOf( + listOf( + mockEncounter(1, _circumstances = ""), + mockEncounter(2, _circumstances = "A rainy day"), + mockEncounter(3, "Spilled coffee on each others laptops") + ), + listOf( + mockEncounter(1, _circumstances = ""), + // "a rainy day" was deleted + mockEncounter(3, "Spilled coffee on each others laptops") + ) ) - // censoring should still work after encounters are deleted - every { diaryRepo.personEncounters } returns flowOf(emptyList()) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - On Encounter#2/Circumstances, - two persons Encounter#3/Circumstances, - everyone disliked that. - """.trimIndent() - ) + val instance = createInstance(this) + val censorMe = + """ + On A rainy day, + two persons Spilled coffee on each others laptops, + everyone disliked that. + """.trimIndent() + + instance.checkLog(censorMe)!!.string shouldBe + """ + On Encounter#2/Circumstances, + two persons Encounter#3/Circumstances, + everyone disliked that. + """.trimIndent() } @Test fun `censoring returns null if all circumstances are blank`() = runBlockingTest { every { diaryRepo.personEncounters } returns flowOf(listOf(mockEncounter(1, _circumstances = ""))) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "That was strange.", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "That was strange." instance.checkLog(notCensored) shouldBe null } @@ -105,13 +110,7 @@ class DiaryEncounterCensorTest : BaseTest() { val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "Nothing ever happens.", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "Nothing ever happens." instance.checkLog(notCensored) shouldBe null } @@ -125,13 +124,7 @@ class DiaryEncounterCensorTest : BaseTest() { ) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "I like turtles", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "I like turtles" instance.checkLog(notCensored) shouldBe null } @@ -145,13 +138,7 @@ class DiaryEncounterCensorTest : BaseTest() { ) ) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" var isFinished = false diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryLocationCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryLocationCensorTest.kt index 191afcd5dcace16a5dce810c8aeeb8b6a9d2cbf4..fbc4cd1af89a58d9a29a7b226f2b86d19c1f2c82 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryLocationCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryLocationCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryLocationCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocation import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import io.kotest.matchers.shouldBe @@ -54,50 +53,55 @@ class DiaryLocationCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val censorMe = LogLine( - timestamp = 1, - priority = 3, - message = - """ - Bürgermeister of Munich (+49 089 3333) and Karl of Aachen [+49 0241 9999] called each other. - Both agreed that their emails (bürgermeister@münchen.de|karl@aachen.de) are awesome, - and that Bielefeld doesn't exist as it has neither phonenumber (null) nor email (null). - """.trimIndent(), - tag = "I'm a tag", - throwable = null - ) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - Bürgermeister of Location#1/Name (Location#1/PhoneNumber) and Karl of Location#3/Name [Location#3/PhoneNumber] called each other. - Both agreed that their emails (Location#1/EMail|Location#3/EMail) are awesome, - and that Location#2/Name doesn't exist as it has neither phonenumber (null) nor email (null). - """.trimIndent() - ) + val censorMe = + """ + Bürgermeister of Munich (+49 089 3333) and Karl of Aachen [+49 0241 9999] called each other. + Both agreed that their emails (bürgermeister@münchen.de|karl@aachen.de) are awesome, + and that Bielefeld doesn't exist as it has neither phonenumber (null) nor email (null). + """.trimIndent() + instance.checkLog(censorMe)!!.string shouldBe + """ + Bürgermeister of Location#1/Name (Location#1/PhoneNumber) and Karl of Location#3/Name [Location#3/PhoneNumber] called each other. + Both agreed that their emails (Location#1/EMail|Location#3/EMail) are awesome, + and that Location#2/Name doesn't exist as it has neither phonenumber (null) nor email (null). + """.trimIndent() + } - // censoring should still work after locations are deleted - every { diaryRepo.locations } returns flowOf(emptyList()) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - Bürgermeister of Location#1/Name (Location#1/PhoneNumber) and Karl of Location#3/Name [Location#3/PhoneNumber] called each other. - Both agreed that their emails (Location#1/EMail|Location#3/EMail) are awesome, - and that Location#2/Name doesn't exist as it has neither phonenumber (null) nor email (null). - """.trimIndent() + @Test + fun `censoring should still work after locations are deleted`() = runBlockingTest { + every { diaryRepo.locations } returns flowOf( + listOf( + mockLocation(1, "Munich", phone = "+49 089 3333", mail = "bürgermeister@münchen.de"), + mockLocation(2, "Bielefeld", phone = null, mail = null), + mockLocation(3, "Aachen", phone = "+49 0241 9999", mail = "karl@aachen.de") + ), + listOf( + mockLocation(1, "Munich", phone = "+49 089 3333", mail = "bürgermeister@münchen.de"), + // Bielefeld was deleted + mockLocation(3, "Aachen", phone = "+49 0241 9999", mail = "karl@aachen.de") + ) ) + + val instance = createInstance(this) + val censorMe = + """ + Bürgermeister of Munich (+49 089 3333) and Karl of Aachen [+49 0241 9999] called each other. + Both agreed that their emails (bürgermeister@münchen.de|karl@aachen.de) are awesome, + and that Bielefeld doesn't exist as it has neither phonenumber (null) nor email (null). + """.trimIndent() + instance.checkLog(censorMe)!!.string shouldBe + """ + Bürgermeister of Location#1/Name (Location#1/PhoneNumber) and Karl of Location#3/Name [Location#3/PhoneNumber] called each other. + Both agreed that their emails (Location#1/EMail|Location#3/EMail) are awesome, + and that Location#2/Name doesn't exist as it has neither phonenumber (null) nor email (null). + """.trimIndent() } @Test fun `censoring returns null if there are no locations no match`() = runBlockingTest { every { diaryRepo.locations } returns flowOf(emptyList()) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "Can't visit many cities during lockdown...", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "Can't visit many cities during lockdown..." instance.checkLog(notCensored) shouldBe null } @@ -111,13 +115,7 @@ class DiaryLocationCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" instance.checkLog(logLine) shouldBe null } @@ -132,13 +130,7 @@ class DiaryLocationCensorTest : BaseTest() { ) ) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" var isFinished = false diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryPersonCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryPersonCensorTest.kt index 1025df09c8876fd49a7e11f73c47603a77cb265f..1d8ccac54698f3af2e230df487c937a034129972 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryPersonCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryPersonCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryPersonCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPerson import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import io.kotest.matchers.shouldBe @@ -55,50 +54,56 @@ class DiaryPersonCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val censorMe = LogLine( - timestamp = 1, - priority = 3, - message = - """ - Ralf requested more coffee from +49 1234 7777, - but Matthias thought he had enough has had enough for today. - A quick mail to luka@sap.com confirmed this. - """.trimIndent(), - tag = "I'm a tag", - throwable = null - ) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - Person#2/Name requested more coffee from Person#1/PhoneNumber, - but Person#3/Name thought he had enough has had enough for today. - A quick mail to Person#1/EMail confirmed this. - """.trimIndent() - ) + val censorMe = + """ + Ralf requested more coffee from +49 1234 7777, + but Matthias thought he had enough has had enough for today. + A quick mail to luka@sap.com confirmed this. + """.trimIndent() + instance.checkLog(censorMe)!!.string shouldBe + """ + Person#2/Name requested more coffee from Person#1/PhoneNumber, + but Person#3/Name thought he had enough has had enough for today. + A quick mail to Person#1/EMail confirmed this. + """.trimIndent() + } - // censoring should still work after people are deleted - every { diaryRepo.people } returns flowOf(emptyList()) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - Person#2/Name requested more coffee from Person#1/PhoneNumber, - but Person#3/Name thought he had enough has had enough for today. - A quick mail to Person#1/EMail confirmed this. - """.trimIndent() + @Test + fun `censoring should still work after people are deleted`() = runBlockingTest { + every { diaryRepo.people } returns flowOf( + listOf( + mockPerson(1, "Luka", phone = "+49 1234 7777", mail = "luka@sap.com"), + mockPerson(2, "Ralf", phone = null, mail = null), + mockPerson(3, "Matthias", phone = null, mail = "matthias@sap.com") + ), + listOf( + mockPerson(1, "Luka", phone = "+49 1234 7777", mail = "luka@sap.com"), + mockPerson(2, "Ralf", phone = null, mail = null), + // Matthias was deleted + ) ) + + val instance = createInstance(this) + val censorMe = + """ + Ralf requested more coffee from +49 1234 7777, + but Matthias thought he had enough has had enough for today. + A quick mail to luka@sap.com confirmed this. + """.trimIndent() + + instance.checkLog(censorMe)!!.string shouldBe + """ + Person#2/Name requested more coffee from Person#1/PhoneNumber, + but Person#3/Name thought he had enough has had enough for today. + A quick mail to Person#1/EMail confirmed this. + """.trimIndent() } @Test fun `censoring returns null if there are no persons no match`() = runBlockingTest { every { diaryRepo.people } returns flowOf(emptyList()) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "May 2021 be better than 2020.", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "May 2021 be better than 2020." instance.checkLog(notCensored) shouldBe null } @@ -112,13 +117,7 @@ class DiaryPersonCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" instance.checkLog(logLine) shouldBe null } @@ -133,13 +132,7 @@ class DiaryPersonCensorTest : BaseTest() { ) ) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" var isFinished = false diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryVisitCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryVisitCensorTest.kt index 5c8a0ed5155bd74d96a1f685b60fbc362ab68ccb..3f554b853a6c7274f7c3f9ad9de3988200f29142 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryVisitCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryVisitCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryVisitCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocationVisit import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import io.kotest.matchers.shouldBe @@ -50,50 +49,54 @@ class DiaryVisitCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val censorMe = LogLine( - timestamp = 1, - priority = 3, - message = - """ - After having a Döner that was too spicy, - I got my beard shaved without mask, - only to find out the supermarket was out of toiletpaper. - """.trimIndent(), - tag = "I'm a tag", - throwable = null - ) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - After having a Visit#1/Circumstances, - I got my Visit#2/Circumstances, - only to find out the supermarket was Visit#3/Circumstances. - """.trimIndent() - ) + val censorMe = + """ + After having a Döner that was too spicy, + I got my beard shaved without mask, + only to find out the supermarket was out of toiletpaper. + """.trimIndent() + instance.checkLog(censorMe)!!.string shouldBe + """ + After having a Visit#1/Circumstances, + I got my Visit#2/Circumstances, + only to find out the supermarket was Visit#3/Circumstances. + """.trimIndent() + } - // censoring should still work even after visits are deleted - every { diaryRepo.locationVisits } returns flowOf(emptyList()) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - After having a Visit#1/Circumstances, - I got my Visit#2/Circumstances, - only to find out the supermarket was Visit#3/Circumstances. - """.trimIndent() + @Test + fun `censor should still work even after visits are deleted`() = runBlockingTest { + every { diaryRepo.locationVisits } returns flowOf( + listOf( + mockVisit(1, _circumstances = "Döner that was too spicy"), + mockVisit(2, _circumstances = "beard shaved without mask"), + mockVisit(3, _circumstances = "out of toiletpaper") + ), + listOf( + mockVisit(1, _circumstances = "Döner that was too spicy"), + // mockVisit(2, _circumstances = "beard shaved without mask"), => deleted + mockVisit(3, _circumstances = "out of toiletpaper") + ) ) + val instance = createInstance(this) + val censorMe = + """ + After having a Döner that was too spicy, + I got my beard shaved without mask, + only to find out the supermarket was out of toiletpaper. + """.trimIndent() + instance.checkLog(censorMe)!!.string shouldBe + """ + After having a Visit#1/Circumstances, + I got my Visit#2/Circumstances, + only to find out the supermarket was Visit#3/Circumstances. + """.trimIndent() } @Test fun `censoring returns null if all circumstances are blank`() = runBlockingTest { every { diaryRepo.locationVisits } returns flowOf(listOf(mockVisit(1, _circumstances = ""))) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "So many places to visit, but no place like home!", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "So many places to visit, but no place like home!" instance.checkLog(notCensored) shouldBe null } @@ -101,13 +104,7 @@ class DiaryVisitCensorTest : BaseTest() { fun `censoring returns null if there are no visits no match`() = runBlockingTest { every { diaryRepo.locationVisits } returns flowOf(emptyList()) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "So many places to visit, but no place like home!", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "So many places to visit, but no place like home!" instance.checkLog(notCensored) shouldBe null } @@ -120,13 +117,7 @@ class DiaryVisitCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "Wakey wakey, eggs and bakey.", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "Wakey wakey, eggs and bakey." instance.checkLog(notCensored) shouldBe null } @@ -140,13 +131,7 @@ class DiaryVisitCensorTest : BaseTest() { ) ) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" var isFinished = false diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrQrCodeCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrQrCodeCensorTest.kt index 58826f8ffb359ba6a12d6d2a13e81dad1c244f84..f7551bb70169af6bd8ce8f158cbbe5a5b8aa0567 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrQrCodeCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrQrCodeCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.submission.PcrQrCodeCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import kotlinx.coroutines.test.runBlockingTest @@ -30,29 +29,15 @@ class PcrQrCodeCensorTest : BaseTest() { fun `censoring replaces the logline message`() = runBlockingTest { PcrQrCodeCensor.lastGUID = testGUID val instance = createInstance() - val censored = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy qrcode: $testGUID", - tag = "I'm a tag", - throwable = null - ) - instance.checkLog(censored) shouldBe censored.copy( - message = "I'm a shy qrcode: ########-####-####-####-########3a2f" - ) + val censored = "I'm a shy qrcode: $testGUID" + instance.checkLog(censored)!!.string shouldBe "I'm a shy qrcode: ########-####-####-####-########3a2f" } @Test fun `censoring returns null if there is no match`() = runBlockingTest { PcrQrCodeCensor.lastGUID = testGUID.replace("f", "a") val instance = createInstance() - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy qrcode: $testGUID", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "I'm a shy qrcode: $testGUID" instance.checkLog(notCensored) shouldBe null } @@ -60,13 +45,7 @@ class PcrQrCodeCensorTest : BaseTest() { fun `censoring aborts if no qrcode was set`() = runBlockingTest { PcrQrCodeCensor.lastGUID = null val instance = createInstance() - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy qrcode: $testGUID", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "I'm a shy qrcode: $testGUID" instance.checkLog(notCensored) shouldBe null } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RACoronaTestCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RACoronaTestCensorTest.kt index 74c66acfadeafe2a4252b0a94df2457ebd7806bc..fa2b323d34acf04aca761b881f6685670a40b8e9 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RACoronaTestCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RACoronaTestCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.submission.RACoronaTestCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.coronatest.CoronaTestRepository import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest import io.kotest.matchers.shouldBe @@ -12,6 +11,7 @@ import io.mockk.mockk import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runBlockingTest import org.joda.time.LocalDate import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -32,7 +32,7 @@ internal class RACoronaTestCensorTest : BaseTest() { ) @Test - fun `checkLog() should return censored LogLine`() = runBlocking { + fun `checkLog() should return censored LogLine`() = runBlockingTest { every { coronaTestRepository.coronaTests } returns flowOf( setOf( mockk<RACoronaTest>().apply { @@ -45,33 +45,42 @@ internal class RACoronaTestCensorTest : BaseTest() { val censor = createInstance(this) - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = - """ - Hello! My name is John. My friends call me Mister Doe and I was born on 2020-01-01. - """.trimIndent(), - tag = "I am tag", - throwable = null - ) + val logLineToCensor = + """ + Hello! My name is John. My friends call me Mister Doe and I was born on 2020-01-01. + """.trimIndent() + + censor.checkLog(logLineToCensor)!!.string shouldBe + """ + Hello! My name is RATest/FirstName. My friends call me Mister RATest/LastName and I was born on RATest/DateOfBirth. + """.trimIndent() + } - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ - Hello! My name is RATest/FirstName. My friends call me Mister RATest/LastName and I was born on RATest/DateOfBirth. - """.trimIndent() + @Test + fun `censoring should still work when test gets deleted`() = runBlockingTest { + every { coronaTestRepository.coronaTests } returns flowOf( + setOf( + mockk<RACoronaTest>().apply { + every { firstName } returns "John" + every { lastName } returns "Doe" + every { dateOfBirth } returns LocalDate.parse("2020-01-01") + } + ), + // Test got deleted + emptySet() ) - // censoring should still work when test gets deleted - every { coronaTestRepository.coronaTests } returns flowOf(emptySet()) + val censor = createInstance(this) - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ - Hello! My name is RATest/FirstName. My friends call me Mister RATest/LastName and I was born on RATest/DateOfBirth. - """.trimIndent() - ) + val logLineToCensor = + """ + Hello! My name is John. My friends call me Mister Doe and I was born on 2020-01-01. + """.trimIndent() + + censor.checkLog(logLineToCensor)!!.string shouldBe + """ + Hello! My name is RATest/FirstName. My friends call me Mister RATest/LastName and I was born on RATest/DateOfBirth. + """.trimIndent() } @Test @@ -80,13 +89,7 @@ internal class RACoronaTestCensorTest : BaseTest() { val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } @@ -105,17 +108,7 @@ internal class RACoronaTestCensorTest : BaseTest() { val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } - - @Test - fun `censoring should still work when test gets deleted`() { - } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RatQrCodeCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RatQrCodeCensorTest.kt index 6689f4e48c0540cf28efe08ea1d02934218d7eb1..afef21806376c6d0c4039cb0959d2ea4490d8d42 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RatQrCodeCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RatQrCodeCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.submission.RatQrCodeCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import kotlinx.coroutines.test.runBlockingTest @@ -39,30 +38,17 @@ internal class RatQrCodeCensorTest { val censor = createInstance() - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the hash: $testHash of the rat test of Milhouse Van Houten. He was born on 1980-07-01", - tag = "I am tag", - throwable = null - ) + val logLineToCensor = + "Here comes the hash: $testHash of the rat test of Milhouse Van Houten. He was born on 1980-07-01" - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = "Here comes the hash: SHA256HASH-ENDING-WITH-15ad of the rat test of RATest/FirstName RATest/LastName. He was born on RATest/DateOfBirth" - ) + censor.checkLog(logLineToCensor)!!.string shouldBe "Here comes the hash: SHA256HASH-ENDING-WITH-15ad of the rat test of RATest/FirstName RATest/LastName. He was born on RATest/DateOfBirth" } @Test fun `checkLog() should return null if no data to censor was set`() = runBlockingTest { val censor = createInstance() - val logLineNotToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the hash: $testHash", - tag = "I am tag", - throwable = null - ) + val logLineNotToCensor = "Here comes the hash: $testHash" censor.checkLog(logLineNotToCensor) shouldBe null } @@ -79,13 +65,7 @@ internal class RatQrCodeCensorTest { val censor = createInstance() - val logLineNotToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the hash: $testHash", - tag = "I am tag", - throwable = null - ) + val logLineNotToCensor = "Here comes the hash: $testHash" censor.checkLog(logLineNotToCensor) shouldBe null } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/TraceLocationCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/TraceLocationCensorTest.kt index c7f6d6b7f41e7d877a2a0842a8051153fc765a8c..cb123802a53d20acd8349a4571f82d5eaa0adfc4 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/TraceLocationCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/TraceLocationCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.presencetracing.TraceLocationCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.presencetracing.locations.TraceLocationUserInput import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository @@ -52,7 +51,7 @@ internal class TraceLocationCensorTest : BaseTest() { } @Test - fun `checkLog() should return LogLine with censored trace location information from repository`() = runBlocking { + fun `checkLog() should return LogLine with censored trace location information from repository`() = runBlockingTest { every { traceLocationRepo.allTraceLocations } returns flowOf( listOf( mockTraceLocation( @@ -72,36 +71,66 @@ internal class TraceLocationCensorTest : BaseTest() { val censor = createInstance(this) - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = - """ - The type is LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT. Yesterday we went to the Rick Astley Concert. The spectacle took place in Never gonna give you up street 1, 12345 RickRoll City. - Afterwards we had some food in Sushi Place in Sushi Street 123, 12345 Fish Town. It a nice LOCATION_TYPE_PERMANENT_FOOD_SERVICE. - """.trimIndent(), - tag = "I am tag", - throwable = null - ) + val logLineToCensor = + """ + The type is LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT. Yesterday we went to the Rick Astley Concert. The spectacle took place in Never gonna give you up street 1, 12345 RickRoll City. + Afterwards we had some food in Sushi Place in Sushi Street 123, 12345 Fish Town. It a nice LOCATION_TYPE_PERMANENT_FOOD_SERVICE. + """.trimIndent() + + censor.checkLog(logLineToCensor)!!.string shouldBe + """ + The type is TraceLocation#2/Type. Yesterday we went to the TraceLocation#2/Description. The spectacle took place in TraceLocation#2/Address. + Afterwards we had some food in TraceLocation#1/Description in TraceLocation#1/Address. It a nice TraceLocation#1/Type. + """.trimIndent() + } - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ - The type is TraceLocation#2/Type. Yesterday we went to the TraceLocation#2/Description. The spectacle took place in TraceLocation#2/Address. - Afterwards we had some food in TraceLocation#1/Description in TraceLocation#1/Address. It a nice TraceLocation#1/Type. - """.trimIndent() + @Test + fun `censoring should still work after the user deletes his trace locations`() = runBlockingTest { + + every { traceLocationRepo.allTraceLocations } returns flowOf( + listOf( + mockTraceLocation( + traceLocationId = 1, + traceLocationType = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_FOOD_SERVICE, + traceLocationDescription = "Sushi Place", + traceLocationAddress = "Sushi Street 123, 12345 Fish Town" + ), + mockTraceLocation( + traceLocationId = 2, + traceLocationType = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT, + traceLocationDescription = "Rick Astley Concert", + traceLocationAddress = "Never gonna give you up street 1, 12345 RickRoll City" + ) + ), + listOf( + mockTraceLocation( + traceLocationId = 1, + traceLocationType = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_FOOD_SERVICE, + traceLocationDescription = "Sushi Place", + traceLocationAddress = "Sushi Street 123, 12345 Fish Town" + ), + /* deleted: mockTraceLocation( + traceLocationId = 2, + traceLocationType = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT, + traceLocationDescription = "Rick Astley Concert", + traceLocationAddress = "Never gonna give you up street 1, 12345 RickRoll City" + )*/ + ) ) - // censoring should still work after the user deletes his trace locations - every { traceLocationRepo.allTraceLocations } returns flowOf(emptyList()) + val censor = createInstance(this) - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ - The type is TraceLocation#2/Type. Yesterday we went to the TraceLocation#2/Description. The spectacle took place in TraceLocation#2/Address. - Afterwards we had some food in TraceLocation#1/Description in TraceLocation#1/Address. It a nice TraceLocation#1/Type. - """.trimIndent() - ) + val logLineToCensor = + """ + The type is LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT. Yesterday we went to the Rick Astley Concert. The spectacle took place in Never gonna give you up street 1, 12345 RickRoll City. + Afterwards we had some food in Sushi Place in Sushi Street 123, 12345 Fish Town. It a nice LOCATION_TYPE_PERMANENT_FOOD_SERVICE. + """.trimIndent() + + censor.checkLog(logLineToCensor)!!.string shouldBe + """ + The type is TraceLocation#2/Type. Yesterday we went to the TraceLocation#2/Description. The spectacle took place in TraceLocation#2/Address. + Afterwards we had some food in TraceLocation#1/Description in TraceLocation#1/Address. It a nice TraceLocation#1/Type. + """.trimIndent() } @Test @@ -119,25 +148,17 @@ internal class TraceLocationCensorTest : BaseTest() { val censor = createInstance(this) - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = - """ + val logLineToCensor = + """ The user just created a new traceLocation with Top Secret Private Event as the description and top secret address as the address. The type is LOCATION_TYPE_TEMPORARY_PRIVATE_EVENT. - """.trimIndent(), - tag = "I am tag", - throwable = null - ) + """.trimIndent() - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ + censor.checkLog(logLineToCensor)!!.string shouldBe + """ The user just created a new traceLocation with TraceLocationUserInput#Description as the description and TraceLocationUserInput#Address as the address. The type is TraceLocationUserInput#Type. - """.trimIndent() - ) + """.trimIndent() } @Test @@ -145,13 +166,7 @@ internal class TraceLocationCensorTest : BaseTest() { every { traceLocationRepo.allTraceLocations } returns flowOf(emptyList()) val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } @@ -176,13 +191,7 @@ internal class TraceLocationCensorTest : BaseTest() { ) val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensorTest.kt index 9093882a66e86caa3fbedebf1ce0a77da724a7f4..9954cd867b141eb7bb06b84ecaf4eefb40cbb81d 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensorTest.kt @@ -1,6 +1,5 @@ package de.rki.coronawarnapp.bugreporting.censors.submission -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfile import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfileSettings import io.kotest.matchers.shouldBe @@ -9,6 +8,7 @@ import io.mockk.every import io.mockk.impl.annotations.MockK import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runBlockingTest import org.joda.time.format.DateTimeFormat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -33,13 +33,7 @@ internal class RatProfileCensorTest : BaseTest() { val censor = createInstance() - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } @@ -50,13 +44,7 @@ internal class RatProfileCensorTest : BaseTest() { val censor = createInstance() - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "I'm a tag" censor.checkLog(logLine) shouldBe null } @@ -67,27 +55,28 @@ internal class RatProfileCensorTest : BaseTest() { val censor = createInstance() - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Mister First name who is also known as Last name and is born on 1950-08-01 lives in Main street, " + - "12132 in the beautiful city of London. You can reach him by phone: 111111111 or email: email@example.com", - tag = "I'm a tag", - throwable = null - ) - - censor.checkLog(logLine) shouldBe logLine.copy( - message = "Mister RAT-Profile/FirstName who is also known as RAT-Profile/LastName and is born on RAT-Profile/DateOfBirth lives in RAT-Profile/Street, " + - "RAT-Profile/Zip-Code in the beautiful city of RAT-Profile/City. You can reach him by phone: RAT-Profile/Phone or email: RAT-Profile/eMail" - ) - - // censoring should still work after the user deletes his profile - every { ratProfileSettings.profile.flow } returns flowOf(null) + val logLine = + "Mister First name who is also known as Last name and is born on 1950-08-01 lives in Main street, " + + "12132 in the beautiful city of London. You can reach him by phone: 111111111 or email: email@example.com" + + censor.checkLog(logLine)!!.string shouldBe + "Mister RAT-Profile/FirstName who is also known as RAT-Profile/LastName and is born on RAT-Profile/DateOfBirth lives in RAT-Profile/Street, " + + "RAT-Profile/Zip-Code in the beautiful city of RAT-Profile/City. You can reach him by phone: RAT-Profile/Phone or email: RAT-Profile/eMail" + } + + @Test + fun `censoring should still work after the user deletes his profile`() = runBlockingTest { + every { ratProfileSettings.profile.flow } returns flowOf(profile, null) + + val censor = createInstance() + + val logLine = + "Mister First name who is also known as Last name and is born on 1950-08-01 lives in Main street, " + + "12132 in the beautiful city of London. You can reach him by phone: 111111111 or email: email@example.com" - censor.checkLog(logLine) shouldBe logLine.copy( - message = "Mister RAT-Profile/FirstName who is also known as RAT-Profile/LastName and is born on RAT-Profile/DateOfBirth lives in RAT-Profile/Street, " + - "RAT-Profile/Zip-Code in the beautiful city of RAT-Profile/City. You can reach him by phone: RAT-Profile/Phone or email: RAT-Profile/eMail" - ) + censor.checkLog(logLine)!!.string shouldBe + "Mister RAT-Profile/FirstName who is also known as RAT-Profile/LastName and is born on RAT-Profile/DateOfBirth lives in RAT-Profile/Street, " + + "RAT-Profile/Zip-Code in the beautiful city of RAT-Profile/City. You can reach him by phone: RAT-Profile/Phone or email: RAT-Profile/eMail" } private val formatter = DateTimeFormat.forPattern("yyyy-MM-dd") diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt index e6c2927121c341a2a08c37e043b5953f86340121..a5509d80ba0f4b18c9362b39283f62a679235975 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt @@ -1,6 +1,5 @@ package de.rki.coronawarnapp.bugreporting.censors.vaccination -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1 import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData import io.kotest.matchers.shouldBe @@ -63,49 +62,27 @@ internal class CertificateQrCodeCensorTest { val censor = createInstance() - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the rawString: $testRawString of the vaccine certificate", - tag = "I am tag", - throwable = null - ) + val logLineToCensor = "Here comes the rawString: $testRawString of the vaccine certificate" - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = "Here comes the rawString: ########-####-####-####-########C\$AH of the vaccine certificate", - ) + censor.checkLog(logLineToCensor)!!.string shouldBe "Here comes the rawString: ########-####-####-####-########C\$AH of the vaccine certificate" - val certDataToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Hello my name is Kevin Bob, i was born at 1969-11-16, i have been " + - "vaccinated with: 12345 1214765 aaEd/easd ASD-2312 1969-04-20 DE Herbert" + - " urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ", - tag = "I am tag", - throwable = null - ) + val certDataToCensor = "Hello my name is Kevin Bob, i was born at 1969-11-16, i have been " + + "vaccinated with: 12345 1214765 aaEd/easd ASD-2312 1969-04-20 DE Herbert" + + " urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ" - censor.checkLog(certDataToCensor) shouldBe certDataToCensor.copy( - message = "Hello my name is nameData/familyName nameData/givenName, i was born at " + - "vaccinationCertificate/dob, i have been vaccinated with: vaccinationData/targetId " + - "vaccinationData/vaccineId vaccinationData/medicalProductId" + - " vaccinationData/marketAuthorizationHolderId vaccinationData/dt" + - " vaccinationData/countryOfVaccination vaccinationData/certificateIssuer" + - " vaccinationData/uniqueCertificateIdentifier" - ) + censor.checkLog(certDataToCensor)!!.string shouldBe "Hello my name is nameData/familyName nameData/givenName, i was born at " + + "vaccinationCertificate/dob, i have been vaccinated with: vaccinationData/targetId " + + "vaccinationData/vaccineId vaccinationData/medicalProductId" + + " vaccinationData/marketAuthorizationHolderId vaccinationData/dt" + + " vaccinationData/countryOfVaccination vaccinationData/certificateIssuer" + + " vaccinationData/uniqueCertificateIdentifier" } @Test fun `checkLog() should return null if no data to censor was set`() = runBlockingTest { val censor = createInstance() - val logLineNotToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the rawData: $testRawString", - tag = "I am tag", - throwable = null - ) + val logLineNotToCensor = "Here comes the rawData: $testRawString" censor.checkLog(logLineNotToCensor) shouldBe null } @@ -117,13 +94,7 @@ internal class CertificateQrCodeCensorTest { val censor = createInstance() - val logLineNotToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the rawString: $testRawString", - tag = "I am tag", - throwable = null - ) + val logLineNotToCensor = "Here comes the rawString: $testRawString" censor.checkLog(logLineNotToCensor) shouldBe null } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt index 029f51ee528a097dd1be66fd1158be739dfd4588..24b467db1b6a35c6a14bebda8416da7d2cc053d6 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt @@ -2,6 +2,8 @@ package de.rki.coronawarnapp.bugreporting.debuglog import android.app.Application import dagger.Lazy +import de.rki.coronawarnapp.bugreporting.censors.BugCensor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor import de.rki.coronawarnapp.bugreporting.censors.submission.CoronaTestCensor import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLogTree import de.rki.coronawarnapp.util.CWADebug @@ -29,7 +31,8 @@ class DebugLoggerTest : BaseIOTest() { @MockK lateinit var application: Application @MockK lateinit var component: ApplicationComponent - @MockK lateinit var coronaTestCensor: CoronaTestCensor + @MockK lateinit var coronaTestCensor1: CoronaTestCensor + @MockK lateinit var coronaTestCensor2: CoronaTestCensor private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!) private val cacheDir = File(testDir, "cache") @@ -49,10 +52,11 @@ class DebugLoggerTest : BaseIOTest() { every { application.cacheDir } returns cacheDir every { component.inject(any<DebugLogger>()) } answers { val logger = arg<DebugLogger>(0) - logger.bugCensors = Lazy { setOf(coronaTestCensor) } + logger.bugCensors = Lazy { setOf(coronaTestCensor1, coronaTestCensor2) } } - coEvery { coronaTestCensor.checkLog(any()) } returns null + coEvery { coronaTestCensor1.checkLog(any()) } returns null + coEvery { coronaTestCensor2.checkLog(any()) } returns null } @AfterEach @@ -178,19 +182,15 @@ class DebugLoggerTest : BaseIOTest() { setInjectionIsReady(component) } - runBlockingTest { - instance.start() + instance.start() - Timber.tag("Tag123").v("Message456") - advanceTimeBy(2000L) + Timber.tag("Tag123").v("Message456") + advanceTimeBy(2000L) - runningLog.readLines().last().substring(26) shouldBe """ - V/Tag123: Message456 - """.trimIndent() + runningLog.readLines().last().substring(25) shouldBe "V/Tag123: Message456" - instance.stop() - advanceUntilIdle() - } + instance.stop() + advanceUntilIdle() } @Test @@ -214,7 +214,7 @@ class DebugLoggerTest : BaseIOTest() { testCollector.latestValue shouldBe LogState( isLogging = true, isLowStorage = false, - logSize = 78L + logSize = 77L ) instance.stop() @@ -228,4 +228,39 @@ class DebugLoggerTest : BaseIOTest() { testCollector.cancel() } + + @Test + fun `affected text ranges are removed when censoring collisions occur`() = runBlockingTest { + val instance = createInstance(scope = this).apply { + init() + setInjectionIsReady(component) + } + + val logMsg = "Lukas says: A hot coffee is really nice!" + + coEvery { coronaTestCensor1.checkLog(any()) } answers { + val msg = arg<String>(0) + BugCensor.CensoredString(msg).censor("says: A hot coffee", "says: A hot tea") + } + + instance.start() + + Timber.tag("Test").v(logMsg) + advanceTimeBy(2000L) + + runningLog.readLines().last().substring(25) shouldBe "V/Test: Lukas says: A hot tea is really nice!" + + coEvery { coronaTestCensor2.checkLog(any()) } answers { + val msg = arg<String>(0) + BugCensor.CensoredString(msg).censor("says:", "sings:") + } + + Timber.tag("Test").v(logMsg) + advanceTimeBy(2000L) + + runningLog.readLines().last().substring(25) shouldBe "V/Test: Lukas <censoring-collision> is really nice!" + + instance.stop() + advanceUntilIdle() + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLineTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLineTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..50b05b41ba12f8373eb306e3c482706affefdae4 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLineTest.kt @@ -0,0 +1,39 @@ +package de.rki.coronawarnapp.bugreporting.debuglog + +import android.util.Log +import de.rki.coronawarnapp.util.trimToLength +import io.kotest.matchers.shouldBe +import okio.IOException +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class LogLineTest : BaseTest() { + + @Test + fun `log formatting`() { + LogLine( + timestamp = 123L, + priority = Log.ERROR, + tag = "IamATag", + message = "Low storage check failed.", + throwable = null + ).format() shouldBe """ + 1970-01-01T00:00:00.123Z E/IamATag: Low storage check failed. + """.trimIndent() + } + + @Test + fun `log formatting with error`() { + LogLine( + timestamp = 123L, + priority = Log.ERROR, + tag = "IamATag", + message = "Low storage check failed.", + throwable = IOException() + ).format().trimToLength(182) shouldBe """ + 1970-01-01T00:00:00.123Z E/IamATag: Low storage check failed. + java.io.IOException + at de.rki.coronawarnapp.bugreporting.debuglog.LogLineTest.log formatting with error(LogLineTest.kt: + """.trimIndent() + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheckTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheckTest.kt index f19da6396cfab4b4e4548fb1a9ad2e2af4a7cbdf..d8d72156fb5a1456a0424138ebee550ef62d85ee 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheckTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheckTest.kt @@ -1,16 +1,19 @@ package de.rki.coronawarnapp.bugreporting.debuglog.internal -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain import io.mockk.Called import io.mockk.MockKAnnotations import io.mockk.Runs +import io.mockk.coEvery +import io.mockk.coVerify import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.just import io.mockk.mockk import io.mockk.slot import io.mockk.verify +import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -22,7 +25,7 @@ class DebugLogStorageCheckTest : BaseTest() { @MockK lateinit var targetPath: File @MockK lateinit var logWriter: LogWriter - private var currentTime: Long = 5001L + private var ourTime: Long = 5001L @BeforeEach fun setup() { @@ -31,7 +34,7 @@ class DebugLogStorageCheckTest : BaseTest() { every { targetPath.usableSpace } returns 250 * 1000 * 1024L every { targetPath.parentFile } returns null every { targetPath.exists() } returns true - every { logWriter.write(any()) } just Runs + coEvery { logWriter.write(any()) } just Runs } @AfterEach @@ -40,12 +43,12 @@ class DebugLogStorageCheckTest : BaseTest() { private fun createInstance() = DebugLogStorageCheck( targetPath = targetPath, - timeProvider = { currentTime }, + timeProvider = { ourTime }, logWriter = logWriter ) @Test - fun `normal not low storage case`() { + fun `normal not low storage case`() = runBlockingTest { val instance = createInstance() instance.isLowStorage() shouldBe false @@ -53,34 +56,37 @@ class DebugLogStorageCheckTest : BaseTest() { } @Test - fun `on errors we print it but do expect low storage`() { - val unexpectedError = Exception("ಠ_ಠ") - every { targetPath.usableSpace } throws unexpectedError + fun `on errors we print it but do expect low storage`() = runBlockingTest { + val unexpectedException = IllegalThreadStateException("ಠ_ಠ") + every { targetPath.usableSpace } throws unexpectedException - val logSlot = slot<LogLine>() - every { logWriter.write(capture(logSlot)) } just Runs + val logSlot = slot<String>() + coEvery { logWriter.write(capture(logSlot)) } just Runs val instance = createInstance() instance.isLowStorage() shouldBe true - logSlot.captured.throwable shouldBe unexpectedError + logSlot.captured.apply { + this shouldContain "ಠ_ಠ" + this shouldContain "IllegalThreadStateException" + } } @Test - fun `low storage default is 200MB`() { + fun `low storage default is 200MB`() = runBlockingTest { every { targetPath.usableSpace } returns 199 * 1000 * 1024L val instance = createInstance() instance.isLowStorage() shouldBe true - currentTime += 60 * 1000L + ourTime += 60 * 1000L instance.isLowStorage() shouldBe true // We only write the warning once - verify(exactly = 1) { logWriter.write(any()) } + coVerify(exactly = 1) { logWriter.write(any()) } } @Test - fun `target path does not exists`() { + fun `target path does not exists`() = runBlockingTest { val parentPath = mockk<File>() every { parentPath.exists() } returns true every { parentPath.parentFile } returns null @@ -97,7 +103,7 @@ class DebugLogStorageCheckTest : BaseTest() { } @Test - fun `checks happen at most every 5 seconds`() { + fun `checks happen at most every 5 seconds`() = runBlockingTest { val instance = createInstance() instance.isLowStorage() shouldBe false @@ -107,7 +113,7 @@ class DebugLogStorageCheckTest : BaseTest() { verify(exactly = 1) { targetPath.usableSpace } - currentTime += 5000L + ourTime += 5000L instance.isLowStorage() shouldBe true diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt index 0bba493b4fee073d7150fd8fa0bd294693a80f55..475ec34f81a4545bdebb3fc77f33ec128d0cc395 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt @@ -8,7 +8,8 @@ import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK -import org.joda.time.DateTime +import org.joda.time.Instant +import org.joda.time.format.DateTimeFormat import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -27,7 +28,9 @@ class LogSnapshotterTest : BaseIOTest() { private val runningLogFake = File(testDir, "running.log") private val snapshotDir = File(cacheDir, "debuglog_snapshots") - private val expectedSnapshot = File(snapshotDir, "CWA Log 1970-01-01 00_00_00.000.zip") + private val fileNameDateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH_mm_ss.SSS") + private val userTime = Instant.EPOCH.toUserTimeZone() + private val expectedSnapshot = File(snapshotDir, "CWA Log ${userTime.toString(fileNameDateFormatter)}.zip") @BeforeEach fun setup() { @@ -39,7 +42,7 @@ class LogSnapshotterTest : BaseIOTest() { testDir.exists() shouldBe true every { debugLogger.runningLog } returns runningLogFake - every { timeStamper.nowUTC.toUserTimeZone() } returns DateTime.parse("1970-01-01T00:00:00.000Z") + every { timeStamper.nowUTC } returns userTime.toInstant() runningLogFake.parentFile!!.mkdirs() runningLogFake.writeText("1 Doge = 1 Doge") diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriterTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriterTest.kt index 19120d55091bae4e73d55d7e2bd18270d5a9540f..6c261a2c172e6e9ae32a5758df62078899db4079 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriterTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriterTest.kt @@ -45,4 +45,27 @@ class LogWriterTest : BaseIOTest() { logSize.value shouldBe 0L } } + + /** + * e.g. System cache cleaning interferring + */ + @Test + fun `if the file is deleted after setup we try to recreate it and do not crash`() = runBlockingTest { + createInstance().apply { + setup() + write("ABC") + logFile.readText() shouldBe "ABC\n" + + logSize.value shouldBe 4L + + logFile.delete() + logFile.parentFile!!.delete() + logFile.exists() shouldBe false + + write("DEF") + logFile.readText() shouldBe "Logfile was deleted.\nDEF\n" + + logSize.value shouldBe 25L + } + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/deadman/DeadmanNotificationTimeCalculationTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/deadman/DeadmanNotificationTimeCalculationTest.kt index f83e9638910e3534e3ccbd7f9549a569615b5803..ef310d304149b50c5b680022c97a3a0b3a693c43 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/deadman/DeadmanNotificationTimeCalculationTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/deadman/DeadmanNotificationTimeCalculationTest.kt @@ -1,16 +1,21 @@ package de.rki.coronawarnapp.deadman -import de.rki.coronawarnapp.nearby.ENFClient -import de.rki.coronawarnapp.nearby.modules.detectiontracker.TrackedExposureDetection +import de.rki.coronawarnapp.diagnosiskeys.download.createMockCachedKeyInfo +import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKey +import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository import de.rki.coronawarnapp.util.TimeStamper import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations +import io.mockk.coEvery +import io.mockk.coVerify import io.mockk.every import io.mockk.impl.annotations.MockK -import io.mockk.verify -import kotlinx.coroutines.flow.flowOf +import io.mockk.mockk +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runBlockingTest import org.joda.time.Instant +import org.joda.time.LocalDate +import org.joda.time.LocalTime import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest @@ -18,79 +23,109 @@ import testhelpers.BaseTest class DeadmanNotificationTimeCalculationTest : BaseTest() { @MockK lateinit var timeStamper: TimeStamper - @MockK lateinit var enfClient: ENFClient - @MockK lateinit var mockExposureDetection: TrackedExposureDetection + @MockK lateinit var keyCacheRepository: KeyCacheRepository + + private val allCachedKeysFlow = MutableStateFlow(emptyList<CachedKey>()) @BeforeEach fun setup() { MockKAnnotations.init(this) - every { timeStamper.nowUTC } returns Instant.parse("2020-08-01T23:00:00.000Z") - every { enfClient.lastSuccessfulTrackedExposureDetection() } returns flowOf(mockExposureDetection) + every { timeStamper.nowUTC } returns Instant.parse("2020-08-01T23:00:00") + coEvery { keyCacheRepository.allCachedKeys() } returns allCachedKeysFlow } private fun createTimeCalculator() = DeadmanNotificationTimeCalculation( timeStamper = timeStamper, - enfClient = enfClient + keyCacheRepository = keyCacheRepository ) + private fun mockCachedKey( + keyDay: LocalDate, + keyHour: LocalTime? = null, + isComplete: Boolean = true, + ): CachedKey = mockk<CachedKey>().apply { + every { info } returns createMockCachedKeyInfo( + dayIdentifier = keyDay, + hourIdentifier = keyHour, + isComplete = isComplete, + ) + } + @Test fun `12 hours difference`() { - every { timeStamper.nowUTC } returns Instant.parse("2020-08-28T14:00:00.000Z") + every { timeStamper.nowUTC } returns Instant.parse("2020-08-28T14:00:00") - createTimeCalculator().getHoursDiff(Instant.parse("2020-08-27T14:00:00.000Z")) shouldBe 720 + createTimeCalculator().getHoursDiff(Instant.parse("2020-08-27T14:00:00")) shouldBe 720 } @Test fun `negative time difference`() { - every { timeStamper.nowUTC } returns Instant.parse("2020-08-30T14:00:00.000Z") + every { timeStamper.nowUTC } returns Instant.parse("2020-08-30T14:00:00") - createTimeCalculator().getHoursDiff(Instant.parse("2020-08-27T14:00:00.000Z")) shouldBe -2160 + createTimeCalculator().getHoursDiff(Instant.parse("2020-08-27T14:00:00")) shouldBe -2160 } @Test fun `success in future case`() { - every { timeStamper.nowUTC } returns Instant.parse("2020-08-27T14:00:00.000Z") + every { timeStamper.nowUTC } returns Instant.parse("2020-08-27T14:00:00") - createTimeCalculator().getHoursDiff(Instant.parse("2020-08-27T15:00:00.000Z")) shouldBe 2220 + createTimeCalculator().getHoursDiff(Instant.parse("2020-08-27T15:00:00")) shouldBe 2220 } @Test fun `12 hours delay`() = runBlockingTest { every { timeStamper.nowUTC } returns Instant.parse("2020-08-28T14:00:00.000Z") - every { mockExposureDetection.finishedAt } returns Instant.parse("2020-08-27T14:00:00.000Z") + allCachedKeysFlow.value = listOf( + mockCachedKey(keyDay = LocalDate.parse("2020-08-27"), keyHour = LocalTime.parse("14:00:00")) + ) createTimeCalculator().getDelay() shouldBe 720 - verify(exactly = 1) { enfClient.lastSuccessfulTrackedExposureDetection() } + coVerify(exactly = 1) { keyCacheRepository.allCachedKeys() } + } + + @Test + fun `12 hours delay - only completed results count`() = runBlockingTest { + every { timeStamper.nowUTC } returns Instant.parse("2020-08-28T14:00:00.000Z") + allCachedKeysFlow.value = listOf( + mockCachedKey(keyDay = LocalDate.parse("2020-08-27"), keyHour = LocalTime.parse("14:00:00")), + mockCachedKey( + keyDay = LocalDate.parse("2020-08-27"), + keyHour = LocalTime.parse("16:00:00"), + isComplete = false + ) + ) + + createTimeCalculator().getDelay() shouldBe 720 + + coVerify(exactly = 1) { keyCacheRepository.allCachedKeys() } } @Test fun `negative delay`() = runBlockingTest { every { timeStamper.nowUTC } returns Instant.parse("2020-08-30T14:00:00.000Z") - every { mockExposureDetection.finishedAt } returns Instant.parse("2020-08-27T14:00:00.000Z") + allCachedKeysFlow.value = listOf( + mockCachedKey(keyDay = LocalDate.parse("2020-08-27"), keyHour = LocalTime.parse("14:00:00")), + ) createTimeCalculator().getDelay() shouldBe -2160 - - verify(exactly = 1) { enfClient.lastSuccessfulTrackedExposureDetection() } } @Test fun `success in future delay`() = runBlockingTest { every { timeStamper.nowUTC } returns Instant.parse("2020-08-27T14:00:00.000Z") - every { mockExposureDetection.finishedAt } returns Instant.parse("2020-08-27T15:00:00.000Z") + allCachedKeysFlow.value = listOf( + mockCachedKey(keyDay = LocalDate.parse("2020-08-27"), keyHour = LocalTime.parse("15:00:00")), + ) createTimeCalculator().getDelay() shouldBe 2220 - - verify(exactly = 1) { enfClient.lastSuccessfulTrackedExposureDetection() } } @Test fun `initial delay - no successful calculations yet`() = runBlockingTest { - every { timeStamper.nowUTC } returns Instant.parse("2020-08-27T14:00:00.000Z") - every { enfClient.lastSuccessfulTrackedExposureDetection() } returns flowOf(null) + every { timeStamper.nowUTC } returns Instant.parse("2020-08-27T14:00:00") + allCachedKeysFlow.value = emptyList() createTimeCalculator().getDelay() shouldBe 2160 - - verify(exactly = 1) { enfClient.lastSuccessfulTrackedExposureDetection() } } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/CommonSyncToolTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/CommonSyncToolTest.kt index 29b079f8ecc87ec5a3ef5ac93f880db3a5bd9058..ff29aad050cae69289498ebb4592a4dc7d8adf1e 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/CommonSyncToolTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/CommonSyncToolTest.kt @@ -38,9 +38,6 @@ abstract class CommonSyncToolTest : BaseIOTest() { private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!) - internal val String.loc get() = LocationCode(this) - internal val String.day get() = LocalDate.parse(this) - internal val String.hour get() = LocalTime.parse(this) val keyRepoData = mutableMapOf<String, CachedKey>() @BeforeEach @@ -130,28 +127,12 @@ abstract class CommonSyncToolTest : BaseIOTest() { hourIdentifier: LocalTime?, isComplete: Boolean = true ): CachedKey { - var keyInfo = CachedKeyInfo( - type = when (hourIdentifier) { - null -> CachedKeyInfo.Type.LOCATION_DAY - else -> CachedKeyInfo.Type.LOCATION_HOUR - }, + val keyInfo = createMockCachedKeyInfo( location = location, - day = dayIdentifier, - hour = hourIdentifier, - createdAt = when (hourIdentifier) { - null -> dayIdentifier.toLocalDateTime(LocalTime.MIDNIGHT).toDateTime(DateTimeZone.UTC).toInstant() - else -> dayIdentifier.toLocalDateTime(hourIdentifier).toDateTime(DateTimeZone.UTC).toInstant() - } + dayIdentifier = dayIdentifier, + hourIdentifier = hourIdentifier, + isComplete = isComplete ) - if (isComplete) { - keyInfo = keyInfo.copy( - etag = when (hourIdentifier) { - null -> "$location-$dayIdentifier" - else -> "$location-$dayIdentifier-$hourIdentifier" - }, - isDownloadComplete = true - ) - } Timber.i("mockKeyCacheCreateEntry(...): %s", keyInfo) val file = File(testDir, keyInfo.id) file.createNewFile() @@ -160,3 +141,39 @@ abstract class CommonSyncToolTest : BaseIOTest() { } } } + +internal val String.loc get() = LocationCode(this) +internal val String.day get() = LocalDate.parse(this) +internal val String.hour get() = LocalTime.parse(this) + +fun createMockCachedKeyInfo( + dayIdentifier: LocalDate, + hourIdentifier: LocalTime?, + isComplete: Boolean, + location: LocationCode = "EUR".loc, +): CachedKeyInfo { + var keyInfo = CachedKeyInfo( + type = when (hourIdentifier) { + null -> CachedKeyInfo.Type.LOCATION_DAY + else -> CachedKeyInfo.Type.LOCATION_HOUR + }, + location = location, + day = dayIdentifier, + hour = hourIdentifier, + createdAt = when (hourIdentifier) { + null -> dayIdentifier.toLocalDateTime(LocalTime.MIDNIGHT).toDateTime(DateTimeZone.UTC).toInstant() + else -> dayIdentifier.toLocalDateTime(hourIdentifier).toDateTime(DateTimeZone.UTC).toInstant() + } + ) + if (isComplete) { + keyInfo = keyInfo.copy( + etag = when (hourIdentifier) { + null -> "$location-$dayIdentifier" + else -> "$location-$dayIdentifier-$hourIdentifier" + }, + isDownloadComplete = true + ) + } + Timber.i("createMockCachedKeyInfo(...): %s", keyInfo) + return keyInfo +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/DayPackageSyncToolTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/DayPackageSyncToolTest.kt index 17c4989677b24761b43f3e92b7d797310e5ac8f5..2b9a8f4ce85749cab5e8d49d6395c23e60e66e17 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/DayPackageSyncToolTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/DayPackageSyncToolTest.kt @@ -1,17 +1,13 @@ package de.rki.coronawarnapp.diagnosiskeys.download import de.rki.coronawarnapp.appconfig.mapping.RevokedKeyPackage -import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKey -import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo.Type import io.kotest.matchers.shouldBe import io.mockk.coEvery import io.mockk.coVerify import io.mockk.coVerifySequence import io.mockk.every -import io.mockk.mockk import kotlinx.coroutines.test.runBlockingTest -import org.joda.time.DateTimeZone import org.joda.time.Instant import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach @@ -98,16 +94,8 @@ class DayPackageSyncToolTest : CommonSyncToolTest() { @Test fun `EXPECT_NEW_DAY_PACKAGES evaluation`() = runBlockingTest { - val cachedKey1 = mockk<CachedKey>().apply { - every { info } returns mockk<CachedKeyInfo>().apply { - every { toDateTime() } returns Instant.parse("2020-10-30T01:02:03.000Z").toDateTime(DateTimeZone.UTC) - } - } - val cachedKey2 = mockk<CachedKey>().apply { - every { info } returns mockk<CachedKeyInfo>().apply { - every { toDateTime() } returns Instant.parse("2020-10-31T01:02:03.000Z").toDateTime(DateTimeZone.UTC) - } - } + val cachedKey1 = mockCachedDay("EUR".loc, "2020-10-30".day) + val cachedKey2 = mockCachedDay("EUR".loc, "2020-10-31".day) val instance = createInstance() diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/HourPackageSyncToolTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/HourPackageSyncToolTest.kt index 0a58b9578d7bf70ad5b1e1e0944f5c8525be7f12..1f5590a3854f00be5f4accf70481ebaf816ca4b4 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/HourPackageSyncToolTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/HourPackageSyncToolTest.kt @@ -1,8 +1,6 @@ package de.rki.coronawarnapp.diagnosiskeys.download import de.rki.coronawarnapp.appconfig.mapping.RevokedKeyPackage -import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKey -import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo.Type import de.rki.coronawarnapp.exception.http.NetworkConnectTimeoutException import io.kotest.matchers.shouldBe @@ -10,9 +8,7 @@ import io.mockk.coEvery import io.mockk.coVerify import io.mockk.coVerifySequence import io.mockk.every -import io.mockk.mockk import kotlinx.coroutines.test.runBlockingTest -import org.joda.time.DateTimeZone import org.joda.time.Instant import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach @@ -184,16 +180,8 @@ class HourPackageSyncToolTest : CommonSyncToolTest() { @Test fun `EXPECT_NEW_HOUR_PACKAGES evaluation`() = runBlockingTest { - val cachedKey1 = mockk<CachedKey>().apply { - every { info } returns mockk<CachedKeyInfo>().apply { - every { toDateTime() } returns Instant.parse("2020-01-01T00:00:03.000Z").toDateTime(DateTimeZone.UTC) - } - } - val cachedKey2 = mockk<CachedKey>().apply { - every { info } returns mockk<CachedKeyInfo>().apply { - every { toDateTime() } returns Instant.parse("2020-01-01T01:00:03.000Z").toDateTime(DateTimeZone.UTC) - } - } + val cachedKey1 = mockCachedHour("EUR".loc, "2020-01-01".day, "00:00".hour) + val cachedKey2 = mockCachedHour("EUR".loc, "2020-01-01".day, "01:00".hour) val instance = createInstance() @@ -207,11 +195,7 @@ class HourPackageSyncToolTest : CommonSyncToolTest() { @Test fun `EXPECT_NEW_HOUR_PACKAGES does not get confused by same hour on next day`() = runBlockingTest { - val cachedKey1 = mockk<CachedKey>().apply { - every { info } returns mockk<CachedKeyInfo>().apply { - every { toDateTime() } returns Instant.parse("2020-01-01T00:00:03.000Z").toDateTime(DateTimeZone.UTC) - } - } + val cachedKey1 = mockCachedHour("EUR".loc, "2020-01-01".day, "00:00".hour) val instance = createInstance() diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt index 7f3f3be61ad7e40a5e30f25ed2d2388406e3dcf6..728fc06a90136da5a77f5ee56301572db7f38f96 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt @@ -5,8 +5,8 @@ import de.rki.coronawarnapp.appconfig.ConfigData import de.rki.coronawarnapp.coronatest.CoronaTestRepository import de.rki.coronawarnapp.coronatest.type.CoronaTest import de.rki.coronawarnapp.datadonation.analytics.modules.exposurewindows.AnalyticsExposureWindowCollector +import de.rki.coronawarnapp.diagnosiskeys.download.createMockCachedKeyInfo import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKey -import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository import de.rki.coronawarnapp.nearby.ENFClient import de.rki.coronawarnapp.risk.result.EwAggregatedRiskResult @@ -64,11 +64,7 @@ class RiskLevelTaskTest : BaseTest() { private val testAggregatedResult = mockk<EwAggregatedRiskResult>().apply { every { isIncreasedRisk() } returns true } - private val testCachedKey = mockk<CachedKey>().apply { - every { info } returns mockk<CachedKeyInfo>().apply { - every { toDateTime() } returns testTimeNow.toDateTime().minusDays(1) - } - } + private val testCachedKey = mockCachedKey(testTimeNow.toDateTime().minusDays(1)) @BeforeEach fun setup() { @@ -119,6 +115,13 @@ class RiskLevelTaskTest : BaseTest() { analyticsExposureWindowCollector = analyticsExposureWindowCollector, ) + private fun mockCachedKey( + dateTime: DateTime, + isComplete: Boolean = true, + ): CachedKey = mockk<CachedKey>().apply { + every { info } returns createMockCachedKeyInfo(dateTime.toLocalDate(), dateTime.toLocalTime(), isComplete) + } + @Test fun `last used config ID is set after calculation`() = runBlockingTest { every { configData.isDeviceTimeCorrect } returns true @@ -172,11 +175,7 @@ class RiskLevelTaskTest : BaseTest() { @Test fun `risk calculation is skipped if results are outdated while in background mode`() = runBlockingTest { - val cachedKey = mockk<CachedKey>().apply { - every { info } returns mockk<CachedKeyInfo>().apply { - every { toDateTime() } returns DateTime.parse("2020-12-28").minusDays(3) - } - } + val cachedKey = mockCachedKey(DateTime.parse("2020-12-28").minusDays(3)) val now = Instant.parse("2020-12-28") coEvery { keyCacheRepository.getAllCachedKeys() } returns listOf(cachedKey) @@ -191,11 +190,7 @@ class RiskLevelTaskTest : BaseTest() { @Test fun `risk calculation is skipped if results are outdated while no background mode`() = runBlockingTest { - val cachedKey = mockk<CachedKey>().apply { - every { info } returns mockk<CachedKeyInfo>().apply { - every { toDateTime() } returns DateTime.parse("2020-12-28").minusDays(3) - } - } + val cachedKey = mockCachedKey(DateTime.parse("2020-12-28").minusDays(3)) val now = Instant.parse("2020-12-28") coEvery { keyCacheRepository.getAllCachedKeys() } returns listOf(cachedKey) @@ -210,11 +205,7 @@ class RiskLevelTaskTest : BaseTest() { @Test fun `risk calculation is skipped if positive test is registered and viewed`() = runBlockingTest { - val cachedKey = mockk<CachedKey>().apply { - every { info } returns mockk<CachedKeyInfo>().apply { - every { toDateTime() } returns DateTime.parse("2020-12-28").minusDays(1) - } - } + val cachedKey = mockCachedKey(DateTime.parse("2020-12-28").minusDays(1)) val now = Instant.parse("2020-12-28") coEvery { keyCacheRepository.getAllCachedKeys() } returns listOf(cachedKey) @@ -236,11 +227,7 @@ class RiskLevelTaskTest : BaseTest() { @Test fun `risk calculation is not skipped if positive test is registered and not viewed`() = runBlockingTest { - val cachedKey = mockk<CachedKey>().apply { - every { info } returns mockk<CachedKeyInfo>().apply { - every { toDateTime() } returns DateTime.parse("2020-12-28").minusDays(1) - } - } + val cachedKey = mockCachedKey(DateTime.parse("2020-12-28").minusDays(1)) val now = Instant.parse("2020-12-28") val aggregatedRiskResult = mockk<EwAggregatedRiskResult>().apply { every { isIncreasedRisk() } returns true diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterViewModelTest.kt index 7d843d40c657bd1e0adc97f8ca448aedd471d96d..7438b8e3c027c075acbea0b19f55c0e2facc61ca 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterViewModelTest.kt @@ -1,6 +1,10 @@ package de.rki.coronawarnapp.ui.presencetracing.organizer.poster import android.graphics.Bitmap +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel +import de.rki.coronawarnapp.appconfig.AppConfigProvider +import de.rki.coronawarnapp.appconfig.ConfigData +import de.rki.coronawarnapp.appconfig.PresenceTracingConfig import de.rki.coronawarnapp.presencetracing.checkins.qrcode.PosterTemplateProvider import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator import de.rki.coronawarnapp.presencetracing.checkins.qrcode.Template @@ -13,6 +17,8 @@ import io.mockk.MockKAnnotations import io.mockk.coEvery import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import kotlinx.coroutines.flow.flowOf import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -32,6 +38,7 @@ class QrCodePosterViewModelTest : BaseTest() { @MockK lateinit var templateBitmap: Bitmap @MockK lateinit var textBox: QRCodeTextBoxAndroid @MockK lateinit var traceLocation: TraceLocation + @MockK lateinit var appConfigProvider: AppConfigProvider private lateinit var template: Template @BeforeEach @@ -48,13 +55,21 @@ class QrCodePosterViewModelTest : BaseTest() { textBox = textBox ) - coEvery { qrCodeGenerator.createQrCode("locationUrl", any(), any()) } returns qrCodeBitmap + coEvery { qrCodeGenerator.createQrCode("locationUrl", any(), any(), any(), any()) } returns qrCodeBitmap coEvery { posterTemplateProvider.template() } returns template coEvery { traceLocationRepository.traceLocationForId(any()) } returns traceLocation.apply { every { description } returns "description" every { address } returns "address" every { locationUrl } returns "locationUrl" } + + coEvery { appConfigProvider.currentConfig } returns flowOf( + mockk<ConfigData>().apply { + every { presenceTracing } returns mockk<PresenceTracingConfig>().apply { + every { qrCodeErrorCorrectionLevel } returns ErrorCorrectionLevel.M + } + } + ) } @Test @@ -72,6 +87,7 @@ class QrCodePosterViewModelTest : BaseTest() { qrCodeGenerator = qrCodeGenerator, posterTemplateProvider = posterTemplateProvider, traceLocationRepository = traceLocationRepository, - fileSharing = fileSharing + fileSharing = fileSharing, + appConfigProvider = appConfigProvider ) } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/update/UpdateCheckerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/update/UpdateCheckerTest.kt index 6ae3f903d234156b07ac9c16e54074c9d2b985b5..cd58fb66a6e30bf9991aa3c49fd54699adfdf063 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/update/UpdateCheckerTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/update/UpdateCheckerTest.kt @@ -12,7 +12,9 @@ import io.mockk.coVerifySequence import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.mockkObject +import kotlinx.coroutines.delay import kotlinx.coroutines.test.runBlockingTest +import okio.IOException import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest @@ -89,4 +91,40 @@ class UpdateCheckerTest : BaseTest() { appConfigProvider.getAppConfig() } } + + @Test + fun `timeout after 5 seconds`() = runBlockingTest { + every { configData.minVersionCode } returns 10 + every { BuildConfigWrap.VERSION_CODE } returns 9 + + coEvery { appConfigProvider.getAppConfig() } coAnswers { + delay(4_000) + configData + } + + createInstance().checkForUpdate().apply { + isUpdateNeeded shouldBe true + updateIntent shouldNotBe null + } + + coEvery { appConfigProvider.getAppConfig() } coAnswers { + delay(6_000) + throw IOException() + } + + createInstance().checkForUpdate().apply { + isUpdateNeeded shouldBe false + updateIntent shouldBe null + } + + coEvery { appConfigProvider.getAppConfig() } coAnswers { + delay(6_000) + configData + } + + createInstance().checkForUpdate().apply { + isUpdateNeeded shouldBe false + updateIntent shouldBe null + } + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonTest.kt index c10e167384a0e721ce480b4e8be9f92875f71d57..c63461ce23343dccbe41d1d0efe3c1b21856707b 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonTest.kt @@ -76,6 +76,7 @@ class VaccinatedPersonTest : BaseTest() { @Test fun `vaccination status - IMMUNITY`() { + // vaccinatedAt "2021-04-27" val immunityContainer = testData.personAVac2Container val personData = mockk<VaccinatedPersonData>().apply { every { vaccinations } returns setOf(testData.personAVac1Container, immunityContainer) @@ -85,23 +86,22 @@ class VaccinatedPersonTest : BaseTest() { valueSet = null ) - val vaccinatedAt = immunityContainer.vaccination.vaccinatedAt - vaccinatedPerson.apply { getVaccinationStatus( - vaccinatedAt.toDateTimeAtStartOfDay().toInstant() + Instant.parse("2021-04-27T12:00:00.000Z") ) shouldBe VaccinatedPerson.Status.COMPLETE getVaccinationStatus( - vaccinatedAt.toDateTimeAtStartOfDay().toInstant().plus(Duration.standardDays(13)) + Instant.parse("2021-05-10T12:00:00.000Z") ) shouldBe VaccinatedPerson.Status.COMPLETE getVaccinationStatus( - vaccinatedAt.toDateTimeAtStartOfDay().toInstant().plus(Duration.standardDays(14)) + Instant.parse("2021-05-11T12:00:00.000Z") ) shouldBe VaccinatedPerson.Status.IMMUNITY } } @Test fun `time until status IMMUNITY`() { + // vaccinatedAt "2021-04-27" val immunityContainer = testData.personAVac2Container val personData = mockk<VaccinatedPersonData>().apply { every { vaccinations } returns setOf(testData.personAVac1Container, immunityContainer) @@ -110,19 +110,16 @@ class VaccinatedPersonTest : BaseTest() { data = personData, valueSet = null ) - - val vaccinatedAt = immunityContainer.vaccination.vaccinatedAt - vaccinatedPerson.apply { getTimeUntilImmunity( - vaccinatedAt.toDateTimeAtStartOfDay().toInstant() - ) shouldBe Duration.standardDays(14) + Instant.parse("2021-04-27T12:00:00.000Z") + )!!.standardDays shouldBe Duration.standardDays(14).standardDays getTimeUntilImmunity( - vaccinatedAt.toDateTimeAtStartOfDay().toInstant().plus(Duration.standardDays(13)) - ) shouldBe Duration.standardDays(1) + Instant.parse("2021-05-10T12:00:00.000Z") + )!!.standardDays shouldBe Duration.standardDays(1).standardDays getTimeUntilImmunity( - vaccinatedAt.toDateTimeAtStartOfDay().toInstant().plus(Duration.standardDays(14)) - ) shouldBe Duration.ZERO + Instant.parse("2021-05-11T12:00:00.000Z") + )!!.standardDays shouldBe Duration.ZERO.standardDays } } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/ValueSetTestData.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/ValueSetTestData.kt new file mode 100644 index 0000000000000000000000000000000000000000..67e7a01f66f51fee0b09e1f2ea82cdec55a1a1af --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/ValueSetTestData.kt @@ -0,0 +1,87 @@ +package de.rki.coronawarnapp.vaccination.core + +import de.rki.coronawarnapp.vaccination.core.repository.storage.ValueSetsStorage +import de.rki.coronawarnapp.vaccination.core.server.valueset.DefaultVaccinationValueSet +import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet +import io.kotest.matchers.shouldBe +import java.util.Locale + +object ValueSetTestData { + + val vpItemDe = "1119305005" to "Impfstoff-Name" + val mpItemDe = "EU/1/21/1529" to "Arzneimittel-Name" + val maItemDe = "ORG-100001699" to "Hersteller-Name" + + val vpItemEn = vpItemDe.copy(second = "Vaccine-Name") + val mpItemEn = mpItemDe.copy(second = "MedicalProduct-Name") + val maItemEn = maItemDe.copy(second = "Manufactorer-Name") + + val storedValueSetDe = ValueSetsStorage.StoredVaccinationValueSet( + languageCode = Locale.GERMAN, + vp = createStoredValueSet(vpItemDe), + mp = createStoredValueSet(mpItemDe), + ma = createStoredValueSet(maItemDe) + ) + + val storedValueSetEn = ValueSetsStorage.StoredVaccinationValueSet( + languageCode = Locale.ENGLISH, + vp = createStoredValueSet(vpItemEn), + mp = createStoredValueSet(mpItemEn), + ma = createStoredValueSet(maItemEn) + ) + + val emptyStoredValueSet = ValueSetsStorage.StoredVaccinationValueSet( + languageCode = Locale.ENGLISH, + vp = ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet(items = emptyList()), + mp = ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet(items = emptyList()), + ma = ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet(items = emptyList()) + ) + + val valueSetDe = DefaultVaccinationValueSet( + languageCode = Locale.GERMAN, + vp = createValueSet(vpItemDe), + mp = createValueSet(mpItemDe), + ma = createValueSet(maItemDe) + ) + + val valueSetEn = DefaultVaccinationValueSet( + languageCode = Locale.ENGLISH, + vp = createValueSet(vpItemEn), + mp = createValueSet(mpItemEn), + ma = createValueSet(maItemEn) + ) + + val emptyValueSetEn = emptyStoredValueSet + + fun createStoredValueSet(keyText: Pair<String, String>): ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet { + val item = ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet.StoredItem( + key = keyText.first, + displayText = keyText.second + ) + return ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet(items = listOf(item)) + } + + fun createValueSet(keyText: Pair<String, String>): DefaultVaccinationValueSet.DefaultValueSet { + val item = DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( + key = keyText.first, + displayText = keyText.second + ) + return DefaultVaccinationValueSet.DefaultValueSet(items = listOf(item)) + } +} + +fun VaccinationValueSet.validateValues(v2: VaccinationValueSet) { + languageCode shouldBe v2.languageCode + vp.validateValues(v2.vp) + mp.validateValues(v2.mp) + ma.validateValues(v2.ma) +} + +fun VaccinationValueSet.ValueSet.validateValues(v2: VaccinationValueSet.ValueSet) { + items.forEachIndexed { index, item1 -> + val item2 = v2.items[index] + + item1.key shouldBe item2.key + item1.displayText shouldBe item2.displayText + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepositoryTest.kt index 374831b938ca7e4384a0ad152b7c144bdf7b1766..3ac9576d02d0740117dafee40677906c2aed214d 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepositoryTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepositoryTest.kt @@ -1,11 +1,11 @@ package de.rki.coronawarnapp.vaccination.core.repository -import de.rki.coronawarnapp.util.preferences.FlowPreference +import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.emptyValueSetEn +import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.valueSetDe +import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.valueSetEn import de.rki.coronawarnapp.vaccination.core.repository.storage.ValueSetsStorage -import de.rki.coronawarnapp.vaccination.core.server.valueset.DefaultVaccinationValueSet import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationServer -import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet -import io.kotest.matchers.shouldBe +import de.rki.coronawarnapp.vaccination.core.validateValues import io.mockk.MockKAnnotations import io.mockk.Ordering import io.mockk.coEvery @@ -14,13 +14,13 @@ import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.just import io.mockk.runs +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.first -import kotlinx.coroutines.test.TestCoroutineScope -import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest -import testhelpers.preferences.mockFlowPreference +import testhelpers.TestDispatcherProvider +import testhelpers.coroutines.runBlockingTest2 import java.util.Locale class ValueSetsRepositoryTest : BaseTest() { @@ -28,124 +28,68 @@ class ValueSetsRepositoryTest : BaseTest() { @MockK lateinit var vaccinationServer: VaccinationServer @MockK lateinit var valueSetsStorage: ValueSetsStorage - private val testScope = TestCoroutineScope() - - private val emptyValueSetEN = createValueSet(languageCode = Locale.ENGLISH) - private val valueSetPref: FlowPreference<ValueSetsStorage.StoredVaccinationValueSet> = - mockFlowPreference(emptyValueSetEN.toStoredVaccinationValueSet()) - - private val valueSetEN = createValueSet( - languageCode = Locale.ENGLISH, - vpItems = listOf( - DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( - key = "1119305005", - displayText = "Vaccine-Name" - ) - ), - mpItems = listOf( - DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( - key = "EU/1/21/1529", - displayText = "MedicalProduct-Name" - ) - ), - maItems = listOf( - DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( - key = "ORG-100001699", - displayText = "Manufactorer-Name" - ) - ) - ) - - private val valueSetDE = createValueSet( - languageCode = Locale.GERMAN, - vpItems = listOf( - DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( - key = "1119305005", - displayText = "Impfstoff-Name" - ) - ), - mpItems = listOf( - DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( - key = "EU/1/21/1529", - displayText = "Arzneimittel-Name" - ) - ), - maItems = listOf( - DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( - key = "ORG-100001699", - displayText = "Hersteller-Name" - ) - ) - ) - - private fun createValueSet( - languageCode: Locale, - vpItems: List<DefaultVaccinationValueSet.DefaultValueSet.DefaultItem> = emptyList(), - mpItems: List<DefaultVaccinationValueSet.DefaultValueSet.DefaultItem> = emptyList(), - maItems: List<DefaultVaccinationValueSet.DefaultValueSet.DefaultItem> = emptyList() - ) = DefaultVaccinationValueSet( - languageCode = languageCode, - vp = DefaultVaccinationValueSet.DefaultValueSet(items = vpItems), - mp = DefaultVaccinationValueSet.DefaultValueSet(items = mpItems), - ma = DefaultVaccinationValueSet.DefaultValueSet(items = maItems) - ) + private val testDispatcherProvider = TestDispatcherProvider() - private fun createInstance() = ValueSetsRepository( + private fun createInstance(scope: CoroutineScope) = ValueSetsRepository( vaccinationServer = vaccinationServer, valueSetsStorage = valueSetsStorage, - scope = testScope + scope = scope, + dispatcherProvider = testDispatcherProvider ) @BeforeEach fun setUp() { MockKAnnotations.init(this) coEvery { vaccinationServer.getVaccinationValueSets(any()) } returns null - coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) } returns valueSetEN - coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) } returns valueSetDE + coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) } returns valueSetEn + coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) } returns valueSetDe every { vaccinationServer.clear() } just runs - every { valueSetsStorage.valueSet } returns valueSetPref - every { valueSetsStorage.clear() } just runs + every { valueSetsStorage.vaccinationValueSet = any() } just runs + every { valueSetsStorage.vaccinationValueSet } returns emptyValueSetEn } @Test - fun `successful update for de`() = runBlockingTest { - createInstance().run { + fun `successful update for de`() = runBlockingTest2(ignoreActive = true) { + createInstance(this).run { triggerUpdateValueSet(languageCode = Locale.GERMAN) latestValueSet.first() - }.also { it.validateValues(valueSetDE) } + }.also { it.validateValues(valueSetDe) } - coVerify(exactly = 1) { + coVerify { vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) + valueSetsStorage.vaccinationValueSet = valueSetDe } coVerify(exactly = 0) { vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) + valueSetsStorage.vaccinationValueSet = valueSetEn } } @Test - fun `fallback to en`() = runBlockingTest { - createInstance().run { + fun `fallback to en`() = runBlockingTest2(ignoreActive = true) { + createInstance(this).run { triggerUpdateValueSet(languageCode = Locale.FRENCH) latestValueSet.first() - }.also { it.validateValues(valueSetEN) } + }.also { it.validateValues(valueSetEn) } coVerify(ordering = Ordering.ORDERED) { vaccinationServer.getVaccinationValueSets(languageCode = Locale.FRENCH) vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) + valueSetsStorage.vaccinationValueSet = valueSetEn } } @Test - fun `server returns nothing`() = runBlockingTest { + fun `server returns nothing`() = runBlockingTest2(ignoreActive = true) { coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) } returns null coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) } returns null - createInstance().run { + createInstance(this).run { triggerUpdateValueSet(languageCode = Locale.GERMAN) latestValueSet.first() - }.also { it.validateValues(emptyValueSetEN) } + }.also { it.validateValues(emptyValueSetEn) } coVerify(ordering = Ordering.ORDERED) { vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) @@ -154,37 +98,16 @@ class ValueSetsRepositoryTest : BaseTest() { } @Test - fun `mapping is to stored version is correct`() { - valueSetDE.also { it.toStoredVaccinationValueSet().validateValues(it) } - valueSetEN.also { it.toStoredVaccinationValueSet().validateValues(it) } - emptyValueSetEN.also { it.toStoredVaccinationValueSet().validateValues(it) } - } - - @Test - fun `clear data of server and local storage`() { - createInstance().run { + fun `clear data of server and local storage`() = runBlockingTest2(ignoreActive = true) { + createInstance(this).run { clear() - coVerify(exactly = 1) { + latestValueSet.first().validateValues(emptyValueSetEn) + + coVerify { vaccinationServer.clear() - valueSetsStorage.clear() + valueSetsStorage.vaccinationValueSet = emptyValueSetEn } } } - - private fun VaccinationValueSet.validateValues(v2: VaccinationValueSet) { - languageCode shouldBe v2.languageCode - vp.validateValues(v2.vp) - mp.validateValues(v2.mp) - ma.validateValues(v2.ma) - } - - private fun VaccinationValueSet.ValueSet.validateValues(v2: VaccinationValueSet.ValueSet) { - items.forEachIndexed { index, item1 -> - val item2 = v2.items[index] - - item1.key shouldBe item2.key - item1.displayText shouldBe item2.displayText - } - } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt index c362bebab70f4e7cfdccaa0e760174263e15374e..b13ce6a2ecf8e372a1cdfc43298816ef8c05c386 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt @@ -7,7 +7,6 @@ import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk -import io.mockk.mockkObject import org.joda.time.Instant import org.joda.time.LocalDate import org.junit.jupiter.api.BeforeEach @@ -23,7 +22,6 @@ class VaccinationContainerTest : BaseTest() { @BeforeEach fun setup() { DaggerVaccinationTestComponent.factory().create().inject(this) - mockkObject(Locale.getDefault()) } @Test @@ -62,8 +60,7 @@ class VaccinationContainerTest : BaseTest() { @Test fun `mapping to user facing data - valueset is null`() { - every { Locale.getDefault().language } returns "de" - testData.personAVac1Container.toVaccinationCertificate(null).apply { + testData.personAVac1Container.toVaccinationCertificate(null, userLocale = Locale.GERMAN).apply { firstName shouldBe "Andreas" lastName shouldBe "Astrá Eins" dateOfBirth shouldBe LocalDate.parse("1966-11-11") @@ -110,9 +107,8 @@ class VaccinationContainerTest : BaseTest() { every { mp } returns vpMockk every { ma } returns vpMockk } - every { Locale.getDefault().language } returns "de" - testData.personAVac1Container.toVaccinationCertificate(valueSet).apply { + testData.personAVac1Container.toVaccinationCertificate(valueSet, userLocale = Locale.GERMAN).apply { firstName shouldBe "Andreas" lastName shouldBe "Astrá Eins" dateOfBirth shouldBe LocalDate.parse("1966-11-11") diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorageTest.kt index e333cef8a7f2eb2ba48fd036fb38a1840c1c1f58..e79a54c44aca09f9ae6ca0c3fd02fe9e03c93d62 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorageTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorageTest.kt @@ -2,17 +2,21 @@ package de.rki.coronawarnapp.vaccination.core.repository.storage import android.content.Context import de.rki.coronawarnapp.util.serialization.SerializationModule +import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.emptyStoredValueSet +import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.emptyValueSetEn +import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.storedValueSetDe +import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.storedValueSetEn +import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.valueSetDe +import de.rki.coronawarnapp.vaccination.core.ValueSetTestData.valueSetEn +import de.rki.coronawarnapp.vaccination.core.validateValues import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest import testhelpers.preferences.MockSharedPreferences -import java.util.Locale class ValueSetsStorageTest : BaseTest() { @@ -21,28 +25,6 @@ class ValueSetsStorageTest : BaseTest() { private val gson = SerializationModule().baseGson() - private val storedValueSetDE = ValueSetsStorage.StoredVaccinationValueSet( - languageCode = Locale.GERMAN, - vp = createValueSet(key = "1119305005", displayText = "Impfstoff-Name"), - mp = createValueSet(key = "EU/1/21/1529", displayText = "Arzneimittel-Name"), - ma = createValueSet(key = "ORG-100001699", displayText = "Hersteller-Name") - ) - - private val storedValueSetEN = ValueSetsStorage.StoredVaccinationValueSet( - languageCode = Locale.ENGLISH, - vp = createValueSet(key = "1119305005", displayText = "Vaccine-Name"), - mp = createValueSet(key = "EU/1/21/1529", displayText = "MedicalProduct-Name"), - ma = createValueSet(key = "ORG-100001699", displayText = "Manufactorer-Name") - ) - - private fun createValueSet(key: String, displayText: String): ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet { - val item = ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet.StoredItem( - key = key, - displayText = displayText - ) - return ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet(items = listOf(item)) - } - @BeforeEach fun setup() { MockKAnnotations.init(this) @@ -56,40 +38,42 @@ class ValueSetsStorageTest : BaseTest() { ) @Test - fun `Default value is empty value set`() { - createInstance().valueSet.value.run { - languageCode shouldBe Locale.ENGLISH - vp.items shouldBe emptyList() - mp.items shouldBe emptyList() - ma.items shouldBe emptyList() - } + fun `Default value is an empty value set`() { + createInstance().vaccinationValueSet.validateValues(emptyValueSetEn) } @Test - fun `Clear resets value set`() { + fun `Updates values`() { createInstance().run { - valueSet.update { storedValueSetDE } - clear() + vaccinationValueSet = storedValueSetDe + vaccinationValueSet shouldBe storedValueSetDe - valueSet.value.also { - it.languageCode shouldBe Locale.ENGLISH - it.vp.items shouldBe emptyList() - it.mp.items shouldBe emptyList() - it.ma.items shouldBe emptyList() - } + vaccinationValueSet = storedValueSetEn + vaccinationValueSet shouldBe storedValueSetEn } } @Test - fun `Updates values`() = runBlockingTest { - createInstance().valueSet.run { - update { storedValueSetDE } - value shouldBe storedValueSetDE - flow.first() shouldBe storedValueSetDE + fun `Check mapping is correct`() { + createInstance().run { + storedValueSetDe.also { it.toStoredVaccinationValueSet() shouldBe it } + + storedValueSetEn.also { it.toStoredVaccinationValueSet() shouldBe it } + + valueSetDe.also { + it.toStoredVaccinationValueSet() shouldBe storedValueSetDe + it.toStoredVaccinationValueSet().validateValues(it) + } - update { storedValueSetEN } - value shouldBe storedValueSetEN - flow.first() shouldBe storedValueSetEN + valueSetEn.also { + it.toStoredVaccinationValueSet() shouldBe storedValueSetEn + it.toStoredVaccinationValueSet().validateValues(it) + } + + emptyValueSetEn.also { + it.toStoredVaccinationValueSet() shouldBe emptyStoredValueSet + it.toStoredVaccinationValueSet().validateValues(it) + } } } } diff --git a/gradle.properties b/gradle.properties index b781598ee9bb427e775a3622563938a304ed08d2..fa1b8e30ecbbea40dffe8fed20d0872c10341e01 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,4 +20,4 @@ org.gradle.dependency.verification.console=verbose VERSION_MAJOR=2 VERSION_MINOR=4 VERSION_PATCH=0 -VERSION_BUILD=1 +VERSION_BUILD=2