diff --git a/Corona-Warn-App/build.gradle b/Corona-Warn-App/build.gradle index 58d5fd5c02e..3ad809646f4 100644 --- a/Corona-Warn-App/build.gradle +++ b/Corona-Warn-App/build.gradle @@ -32,8 +32,8 @@ android { applicationId 'de.rki.coronawarnapp' minSdkVersion 23 targetSdkVersion 29 - versionCode 15 - versionName "0.8.8" + versionCode 16 + versionName "0.8.9" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" buildConfigField "String", "DOWNLOAD_CDN_URL", "\"$DOWNLOAD_CDN_URL\"" diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt index b33fa710367..c7f8960056a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt @@ -27,6 +27,9 @@ import de.rki.coronawarnapp.exception.ApplicationConfigurationInvalidException import de.rki.coronawarnapp.http.requests.RegistrationTokenRequest import de.rki.coronawarnapp.http.requests.ReqistrationRequest import de.rki.coronawarnapp.http.requests.TanRequestBody +import de.rki.coronawarnapp.http.service.DistributionService +import de.rki.coronawarnapp.http.service.SubmissionService +import de.rki.coronawarnapp.http.service.VerificationService import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.ApplicationConfiguration import de.rki.coronawarnapp.service.diagnosiskey.DiagnosisKeyConstants import de.rki.coronawarnapp.service.submission.SubmissionConstants @@ -41,19 +44,36 @@ import java.io.File import java.util.Date import java.util.UUID -object WebRequestBuilder { - private val TAG: String? = WebRequestBuilder::class.simpleName - - private const val EXPORT_BINARY_FILE_NAME = "export.bin" - private const val EXPORT_SIGNATURE_FILE_NAME = "export.sig" - - private val serviceFactory = ServiceFactory() - - private val distributionService by lazy { serviceFactory.distributionService() } - private val verificationService by lazy { serviceFactory.verificationService() } - private val submissionService by lazy { serviceFactory.submissionService() } +class WebRequestBuilder( + private val distributionService: DistributionService, + private val verificationService: VerificationService, + private val submissionService: SubmissionService, + private val verificationKeys: VerificationKeys +) { + companion object { + private val TAG: String? = WebRequestBuilder::class.simpleName + private const val EXPORT_BINARY_FILE_NAME = "export.bin" + private const val EXPORT_SIGNATURE_FILE_NAME = "export.sig" + + @Volatile + private var instance: WebRequestBuilder? = null + + fun getInstance(): WebRequestBuilder { + return instance ?: synchronized(this) { + instance ?: buildWebRequestBuilder().also { instance = it } + } + } - private val verificationKeys = VerificationKeys() + private fun buildWebRequestBuilder(): WebRequestBuilder { + val serviceFactory = ServiceFactory() + return WebRequestBuilder( + serviceFactory.distributionService(), + serviceFactory.verificationService(), + serviceFactory.submissionService(), + VerificationKeys() + ) + } + } suspend fun asyncGetDateIndex(): List = withContext(Dispatchers.IO) { return@withContext distributionService diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/NotificationHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/NotificationHelper.kt index 4a1b47a284f..5501bad178d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/NotificationHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/NotificationHelper.kt @@ -92,7 +92,7 @@ object NotificationHelper { private fun buildNotification(title: String, content: String, visibility: Int): Notification? { val builder = NotificationCompat.Builder(CoronaWarnApplication.getAppContext(), channelId) .setSmallIcon(NotificationConstants.NOTIFICATION_SMALL_ICON) - .setPriority(NotificationCompat.PRIORITY_HIGH) + .setPriority(NotificationCompat.PRIORITY_MAX) .setVisibility(visibility) .setContentIntent(createPendingIntentToMainActivity()) .setAutoCancel(true) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt index 596ba092533..137dc448bf0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt @@ -6,8 +6,7 @@ import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass object ApplicationConfigurationService { suspend fun asyncRetrieveApplicationConfiguration(): ApplicationConfigurationOuterClass.ApplicationConfiguration { - return WebRequestBuilder - .asyncGetApplicationConfigurationFromServer() + return WebRequestBuilder.getInstance().asyncGetApplicationConfigurationFromServer() } suspend fun asyncRetrieveExposureConfiguration(): ExposureConfiguration = diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt index fc4cc03daa3..bf03586ffb9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt @@ -48,7 +48,7 @@ object DiagnosisKeyService { */ suspend fun asyncSubmitKeys(authCode: String, keysToReport: List) { Log.d(TAG, "Diagnosis Keys will be submitted.") - WebRequestBuilder.asyncSubmitKeysToServer( + WebRequestBuilder.getInstance().asyncSubmitKeysToServer( authCode, false, keysToReport diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt index 6cdd39fee0d..1f8f64b59ed 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt @@ -24,7 +24,7 @@ object SubmissionService { private suspend fun asyncRegisterDeviceViaGUID(guid: String) { val registrationToken = - WebRequestBuilder.asyncGetRegistrationToken( + WebRequestBuilder.getInstance().asyncGetRegistrationToken( guid, QR_CODE_KEY_TYPE ) @@ -35,7 +35,7 @@ object SubmissionService { private suspend fun asyncRegisterDeviceViaTAN(tan: String) { val registrationToken = - WebRequestBuilder.asyncGetRegistrationToken( + WebRequestBuilder.getInstance().asyncGetRegistrationToken( tan, TELE_TAN_KEY_TYPE ) @@ -45,7 +45,7 @@ object SubmissionService { } suspend fun asyncRequestAuthCode(registrationToken: String): String { - return WebRequestBuilder.asyncGetTan(registrationToken) + return WebRequestBuilder.getInstance().asyncGetTan(registrationToken) } suspend fun asyncSubmitExposureKeys() { @@ -58,7 +58,7 @@ object SubmissionService { val registrationToken = LocalData.registrationToken() ?: throw NoRegistrationTokenSetException() return TestResult.fromInt( - WebRequestBuilder.asyncGetTestResult(registrationToken) + WebRequestBuilder.getInstance().asyncGetTestResult(registrationToken) ) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainFragment.kt index 3634469bef8..e699c28da94 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainFragment.kt @@ -77,25 +77,28 @@ class MainFragment : BaseFragment() { } private fun setButtonOnClickListener() { - binding.mainTest.submissionStatusCardFetching.submissionStatusCardFetchingButton.setOnClickListener { - doNavigate( - MainFragmentDirections.actionMainFragmentToSubmissionResultFragment() - ) + binding.mainTestUnregistered.submissionStatusCardUnregistered.setOnClickListener { + toSubmissionIntro() } - binding.mainTest.submissionStatusCardContent.submissionStatusCardContentButton.setOnClickListener { - doNavigate( - MainFragmentDirections.actionMainFragmentToSubmissionResultFragment() - ) + binding.mainTestUnregistered.submissionStatusCardUnregisteredButton.setOnClickListener { + toSubmissionIntro() } - binding.mainTestPositive.submissionStatusCardPositiveResultShowButton.setOnClickListener { + binding.mainTestDone.submissionStatusCardDone.setOnClickListener { doNavigate( - MainFragmentDirections.actionMainFragmentToSubmissionResultFragment() + MainFragmentDirections.actionMainFragmentToSubmissionDoneFragment() ) } - binding.mainTest.submissionStatusCardUnregistered.submissionStatusCardUnregisteredButton.setOnClickListener { - doNavigate( - MainFragmentDirections.actionMainFragmentToSubmissionIntroFragment() - ) + binding.mainTestResult.submissionStatusCardContent.setOnClickListener { + toSubmissionResult() + } + binding.mainTestResult.submissionStatusCardContentButton.setOnClickListener { + toSubmissionResult() + } + binding.mainTestPositive.submissionStatusCardPositive.setOnClickListener { + toSubmissionResult() + } + binding.mainTestPositive.submissionStatusCardPositiveButton.setOnClickListener { + toSubmissionResult() } binding.mainTracing.setOnClickListener { doNavigate(MainFragmentDirections.actionMainFragmentToSettingsTracingFragment()) @@ -122,6 +125,18 @@ class MainFragment : BaseFragment() { } } + private fun toSubmissionResult() { + doNavigate( + MainFragmentDirections.actionMainFragmentToSubmissionResultFragment() + ) + } + + private fun toSubmissionIntro() { + doNavigate( + MainFragmentDirections.actionMainFragmentToSubmissionIntroFragment() + ) + } + private fun showPopup(view: View) { val popup = PopupMenu(requireContext(), view) popup.inflate(R.menu.menu_main) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt index c18d49a0153..cae07743b57 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel import de.rki.coronawarnapp.storage.SubmissionRepository +import de.rki.coronawarnapp.util.TanHelper class SubmissionTanViewModel : ViewModel() { @@ -16,7 +17,21 @@ class SubmissionTanViewModel : ViewModel() { val isValidTanFormat = Transformations.map(tan) { - it != null && it.length == TanConstants.MAX_LENGTH + it != null && + it.length == TanConstants.MAX_LENGTH && + TanHelper.isChecksumValid(it) && + TanHelper.allCharactersValid(it) + } + + val tanChecksumValid = + Transformations.map(tan) { + ((it !== null && it.trim().length == TanConstants.MAX_LENGTH) && + TanHelper.isChecksumValid(it).not()).not() + } + + val tanCharactersValid = + Transformations.map(tan) { + !((it != null) && TanHelper.allCharactersValid(it).not()) } fun storeTeletan() { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt index b6be13be81d..644cf1ee0f3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanConstants.kt @@ -1,6 +1,6 @@ package de.rki.coronawarnapp.ui.submission object TanConstants { - const val MAX_LENGTH = 7 + const val MAX_LENGTH = 10 val ALPHA_NUMERIC_CHARS = ('a'..'z').plus('A'..'Z').plus('0'..'9') } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt index 70cc48b6833..b7b02a82572 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/TanInput.kt @@ -8,6 +8,9 @@ import android.view.inputmethod.InputMethodManager import android.widget.FrameLayout import androidx.core.widget.doOnTextChanged import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.ui.submission.TanConstants.MAX_LENGTH +import de.rki.coronawarnapp.util.TanHelper +import java.util.Locale import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_edittext import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_1 import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_2 @@ -16,6 +19,11 @@ import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_4 import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_5 import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_6 import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_7 +import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_8 +import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_9 +import kotlinx.android.synthetic.main.view_tan_input.view.tan_input_textview_10 +import kotlinx.android.synthetic.main.view_tan_input.view.dash_view_1 +import kotlinx.android.synthetic.main.view_tan_input.view.dash_view_2 class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) { @@ -30,7 +38,7 @@ class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, att TanConstants.ALPHA_NUMERIC_CHARS.contains(it) } } - private val lengthFilter = InputFilter.LengthFilter(TanConstants.MAX_LENGTH) + private var lengthFilter = InputFilter.LengthFilter(MAX_LENGTH) var listener: ((String?) -> Unit)? = null @@ -41,6 +49,9 @@ class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, att tan_input_edittext.filters = arrayOf(whitespaceFilter, alphaNumericFilter, lengthFilter) + dash_view_1.text = "-" + dash_view_2.text = "-" + // register listener tan_input_edittext.doOnTextChanged { text, _, _, _ -> updateTan(text) } setOnClickListener { showKeyboard() } @@ -56,9 +67,20 @@ class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, att } } + private fun limitLength(length: Int?) { + lengthFilter = InputFilter.LengthFilter(if (length != null) length else MAX_LENGTH) + tan_input_edittext.filters = arrayOf(whitespaceFilter, alphaNumericFilter, lengthFilter) + } + private fun updateTan(text: CharSequence?) { - this.tan = text?.toString() + this.tan = text?.toString()?.toUpperCase(Locale.ROOT) updateDigits() + tan?.let { + limitLength( + if (TanHelper.allCharactersValid(it)) null + else it.length + ) + } notifyListener() } @@ -71,9 +93,24 @@ class TanInput(context: Context, attrs: AttributeSet) : FrameLayout(context, att tan_input_textview_4, tan_input_textview_5, tan_input_textview_6, - tan_input_textview_7 + tan_input_textview_7, + tan_input_textview_8, + tan_input_textview_9, + tan_input_textview_10 ).forEachIndexed { i, tanDigit -> tanDigit.text = digitAtIndex(i) + tanDigit.background = + if (digitAtIndex(i) == "") + resources.getDrawable(R.drawable.tan_input_digit, null) + else if (TanHelper.isTanCharacterValid(digitAtIndex(i))) + resources.getDrawable(R.drawable.tan_input_digit_entered, null) + else resources.getDrawable(R.drawable.tan_input_digit_error, null) + + tanDigit.setTextColor( + if (TanHelper.isTanCharacterValid(digitAtIndex(i))) + resources.getColor(R.color.colorTextSemanticNeutral, null) + else resources.getColor(R.color.colorTextSemanticRed, null) + ) } private fun digitAtIndex(index: Int): String = tan?.getOrNull(index)?.toString() ?: "" diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt index 9fe260c58c7..64b71b742bb 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt @@ -76,7 +76,7 @@ object CachedKeyFileHolder { return@withContext getLast3Hours(currentDate) .map { getURLForHour(currentDate.toServerFormat(), it) } .map { url -> async { - return@async WebRequestBuilder.asyncGetKeyFilesFromServer(url) + return@async WebRequestBuilder.getInstance().asyncGetKeyFilesFromServer(url) } }.awaitAll() } else { throw IllegalStateException( @@ -152,7 +152,7 @@ object CachedKeyFileHolder { */ private suspend fun String.createDayEntryForUrl() = keyCache.createEntry( this.generateCacheKeyFromString(), - WebRequestBuilder.asyncGetKeyFilesFromServer(this).toURI(), + WebRequestBuilder.getInstance().asyncGetKeyFilesFromServer(this).toURI(), DAY ) @@ -183,13 +183,13 @@ object CachedKeyFileHolder { * Get all dates from server based as formatted dates */ private suspend fun getDatesFromServer() = - WebRequestBuilder.asyncGetDateIndex() + WebRequestBuilder.getInstance().asyncGetDateIndex() /** * Get all hours from server based as formatted dates */ private suspend fun getHoursFromServer(day: Date) = - WebRequestBuilder.asyncGetHourIndex(day) + WebRequestBuilder.getInstance().asyncGetHourIndex(day) /** * TODO remove before release diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TanHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TanHelper.kt new file mode 100644 index 00000000000..7fa1562c70e --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TanHelper.kt @@ -0,0 +1,35 @@ +package de.rki.coronawarnapp.util + +import de.rki.coronawarnapp.ui.submission.TanConstants.MAX_LENGTH +import java.nio.charset.StandardCharsets +import java.security.MessageDigest +import java.util.Locale + +object TanHelper { + private const val VALID_CHARACTERS = "23456789ABCDEFGHJKMNPQRSTUVWXYZ" + + fun isChecksumValid(tan: String): Boolean { + if (tan.trim().length != MAX_LENGTH) + return false + val subTan = tan.substring(0, MAX_LENGTH - 1).toUpperCase(Locale.ROOT) + val tanDigest = MessageDigest.getInstance("SHA-256") + .digest(subTan.toByteArray(StandardCharsets.US_ASCII)) + var checkChar = "%02x".format(tanDigest[0])[0] + if (checkChar == '0') checkChar = 'G' + if (checkChar == '1') checkChar = 'H' + + return checkChar.toUpperCase() == tan.last().toUpperCase() + } + + fun allCharactersValid(tan: String): Boolean { + for (character in tan) { + if (!isTanCharacterValid(character.toString())) + return false + } + return true + } + + fun isTanCharacterValid(character: String): Boolean { + return VALID_CHARACTERS.contains(character) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt index 9b0914336fa..85b2671eb3b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt @@ -2,12 +2,13 @@ package de.rki.coronawarnapp.util.formatter +import android.content.Context import android.content.res.ColorStateList import android.graphics.drawable.Drawable +import android.text.format.DateUtils import de.rki.coronawarnapp.CoronaWarnApplication import de.rki.coronawarnapp.R import de.rki.coronawarnapp.risk.RiskLevelConstants -import java.text.DateFormat import java.util.Date /*Texter*/ @@ -190,6 +191,15 @@ fun formatRiskActiveTracingDaysInRetentionPeriod( } } +fun formatRelativeDateTimeString(appContext: Context, date: Date): CharSequence? = + DateUtils.getRelativeDateTimeString( + appContext, + date.time, + DateUtils.DAY_IN_MILLIS, + DateUtils.DAY_IN_MILLIS * 2, + 0 + ) + /** * Formats the risk card text display of the last time diagnosis keys were * successfully fetched from the server @@ -211,9 +221,7 @@ fun formatTimeFetched( if (lastTimeDiagnosisKeysFetched != null) { appContext.getString( R.string.risk_card_body_time_fetched, - DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format( - lastTimeDiagnosisKeysFetched - ) + formatRelativeDateTimeString(appContext, lastTimeDiagnosisKeysFetched) ) } else { appContext.getString(R.string.risk_card_body_not_yet_fetched) @@ -228,10 +236,7 @@ fun formatTimeFetched( if (lastTimeDiagnosisKeysFetched != null) { appContext.getString( R.string.risk_card_body_time_fetched, - DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM) - .format( - lastTimeDiagnosisKeysFetched - ) + formatRelativeDateTimeString(appContext, lastTimeDiagnosisKeysFetched) ) } else { appContext.getString(R.string.risk_card_body_not_yet_fetched) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt index dbe3e29ed71..7f16f3ed7ff 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt @@ -74,7 +74,7 @@ fun formatTestStatusIcon(uiState: DeviceUIState?): Drawable? { DeviceUIState.PAIRED_NO_RESULT -> appContext.getDrawable(R.drawable.ic_test_result_illustration_pending) DeviceUIState.PAIRED_POSITIVE_TELETAN, DeviceUIState.PAIRED_POSITIVE -> appContext.getDrawable(R.drawable.ic_test_result_illustration_positive) - DeviceUIState.PAIRED_NEGATIVE -> appContext.getDrawable(R.drawable.ic_main_illustration_negative) + DeviceUIState.PAIRED_NEGATIVE -> appContext.getDrawable(R.drawable.ic_test_result_illustration_negative) DeviceUIState.PAIRED_ERROR -> appContext.getDrawable(R.drawable.ic_test_result_illustration_invalid) else -> appContext.getDrawable(R.drawable.ic_test_result_illustration_invalid) } @@ -166,17 +166,17 @@ fun formatSubmissionStatusCardFetchingVisible( uiStateState == ApiRequestState.FAILED) ) -fun formatSubmissionStatusCardContentVisible( - deviceRegistered: Boolean?, - uiStateState: ApiRequestState? -): Int = formatVisibility(deviceRegistered == true && uiStateState == ApiRequestState.SUCCESS) +fun formatSubmissionStatusCardUnregisteredVisible( + deviceRegistered: Boolean? +): Int = formatVisibility(deviceRegistered == false) -fun formatShowSubmissionStatusCard(deviceUiState: DeviceUIState?): Int = - formatVisibility( - deviceUiState != DeviceUIState.PAIRED_POSITIVE && - deviceUiState != DeviceUIState.PAIRED_POSITIVE_TELETAN && - deviceUiState != DeviceUIState.SUBMITTED_FINAL - ) +fun formatSubmissionStatusCardContentVisible( + deviceUiState: DeviceUIState? +): Int = formatVisibility( + deviceUiState == DeviceUIState.PAIRED_ERROR || + deviceUiState == DeviceUIState.PAIRED_NEGATIVE || + deviceUiState == DeviceUIState.PAIRED_NO_RESULT +) fun formatShowSubmissionStatusPositiveCard(deviceUiState: DeviceUIState?): Int = formatVisibility( @@ -193,3 +193,8 @@ fun formatShowRiskStatusCard(deviceUiState: DeviceUIState?): Int = deviceUiState != DeviceUIState.PAIRED_POSITIVE_TELETAN && deviceUiState != DeviceUIState.SUBMITTED_FINAL ) + +fun formatShowTanCharacterError( + charactersValid: Boolean, + checksumValid: Boolean +): Int = formatVisibility(checksumValid && !charactersValid) diff --git a/Corona-Warn-App/src/main/res/color/card_dark.xml b/Corona-Warn-App/src/main/res/color/card_dark.xml new file mode 100644 index 00000000000..e20c80f4994 --- /dev/null +++ b/Corona-Warn-App/src/main/res/color/card_dark.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/card_dark.xml b/Corona-Warn-App/src/main/res/drawable/card_dark.xml new file mode 100644 index 00000000000..b09174ef0a8 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/card_dark.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/ic_icon_drilldowncard_dark.xml b/Corona-Warn-App/src/main/res/drawable/ic_icon_drilldowncard_dark.xml deleted file mode 100644 index ee2dcdb3abf..00000000000 --- a/Corona-Warn-App/src/main/res/drawable/ic_icon_drilldowncard_dark.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - diff --git a/Corona-Warn-App/src/main/res/drawable/ic_step_1.xml b/Corona-Warn-App/src/main/res/drawable/ic_step_1.xml deleted file mode 100644 index 45b76198137..00000000000 --- a/Corona-Warn-App/src/main/res/drawable/ic_step_1.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/Corona-Warn-App/src/main/res/drawable/ic_step_2.xml b/Corona-Warn-App/src/main/res/drawable/ic_step_2.xml deleted file mode 100644 index 64729728a7d..00000000000 --- a/Corona-Warn-App/src/main/res/drawable/ic_step_2.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/Corona-Warn-App/src/main/res/drawable/ic_step_background.xml b/Corona-Warn-App/src/main/res/drawable/ic_step_background.xml deleted file mode 100644 index b1270b99fb0..00000000000 --- a/Corona-Warn-App/src/main/res/drawable/ic_step_background.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - diff --git a/Corona-Warn-App/src/main/res/drawable/ic_test_result_illustration_positive_card.xml b/Corona-Warn-App/src/main/res/drawable/ic_test_result_illustration_positive_card.xml new file mode 100644 index 00000000000..f7af213827d --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_test_result_illustration_positive_card.xml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml b/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml index d06cdb9200e..48e3d0c51a8 100644 --- a/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml +++ b/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml @@ -1,11 +1,20 @@ - - - - \ No newline at end of file + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/tan_input_digit_entered.xml b/Corona-Warn-App/src/main/res/drawable/tan_input_digit_entered.xml new file mode 100644 index 00000000000..0550164c034 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/tan_input_digit_entered.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/tan_input_digit_error.xml b/Corona-Warn-App/src/main/res/drawable/tan_input_digit_error.xml new file mode 100644 index 00000000000..01780eeb09b --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/tan_input_digit_error.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + diff --git a/Corona-Warn-App/src/main/res/layout/fragment_main.xml b/Corona-Warn-App/src/main/res/layout/fragment_main.xml index 1e6f7749013..27b5cd78e59 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_main.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_main.xml @@ -131,56 +131,70 @@ app:showDetails="@{false}" app:tracingViewModel="@{tracingViewModel}" /> + + app:layout_constraintTop_toBottomOf="@id/main_risk" /> - + app:layout_constraintTop_toBottomOf="@id/main_test_unregistered" /> - - + + + + app:layout_constraintTop_toBottomOf="@+id/main_test_positive" /> + app:constraint_referenced_ids="main_test_done, main_risk" /> - + - - - - diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_tan.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_tan.xml index c940d704475..4337a0b5e99 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_tan.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_tan.xml @@ -5,6 +5,7 @@ + + + + + +