diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt index 2a669104475..54ccba0807a 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt @@ -3,12 +3,20 @@ package de.rki.coronawarnapp.test.datadonation.ui import android.annotation.SuppressLint import android.os.Bundle import android.view.View +import android.widget.RadioButton +import android.widget.RadioGroup import android.widget.Toast +import androidx.annotation.StringRes import androidx.core.app.ShareCompat +import androidx.core.view.ViewCompat +import androidx.core.view.children import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentTestDatadonationBinding +import de.rki.coronawarnapp.datadonation.safetynet.SafetyNetException +import de.rki.coronawarnapp.datadonation.survey.SurveyException import de.rki.coronawarnapp.test.menu.ui.TestMenuItem +import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.viewBindingLazy @@ -71,6 +79,84 @@ class DataDonationTestFragment : Fragment(R.layout.fragment_test_datadonation), vm.errorEvents.observe2(this) { Toast.makeText(requireContext(), it.toString(), Toast.LENGTH_LONG).show() } + + binding.oneTimePasswordBody.text = vm.otp + + vm.surveyConfig.observe2(this) { + binding.surveyConfigBody.text = it + } + + vm.showErrorDialog.observe2(this) { + showErrorDialog(it) + } + + vm.currentSafetyNetExceptionType.observe2(this) { type -> + binding.apply { + if (safetynetExceptionSimulationRadioGroup.childCount != SafetyNetException.Type.values().size) { + SafetyNetException.Type.values() + .forEach { safetynetExceptionSimulationRadioGroup.addRadioButton(it.name) } + } + safetynetExceptionSimulationRadioGroup.children.checkByName(type.name) + } + } + + binding.apply { + safetynetExceptionSimulationRadioGroup.setOnCheckedChangeListener { group, checkedId -> + val rb = group.findViewById(checkedId) as RadioButton + if (!rb.isPressed) return@setOnCheckedChangeListener + vm.selectSafetyNetExceptionType(SafetyNetException.Type.valueOf(rb.text as String)) + } + + safetynetExceptionSimulationButton.setOnClickListener { vm.showSafetyNetErrorDialog() } + } + + vm.currentSurveyExceptionType.observe2(this) { type -> + binding.apply { + if (surveyExceptionSimulationRadioGroup.childCount != SurveyException.Type.values().size) { + SurveyException.Type.values() + .forEach { surveyExceptionSimulationRadioGroup.addRadioButton(it.name) } + } + surveyExceptionSimulationRadioGroup.children.checkByName(type.name) + } + } + + binding.apply { + surveyExceptionSimulationRadioGroup.setOnCheckedChangeListener { group, checkedId -> + val rb = group.findViewById(checkedId) as RadioButton + if (!rb.isPressed) return@setOnCheckedChangeListener + vm.selectSurveyExceptionType(SurveyException.Type.valueOf(rb.text as String)) + } + + surveyExceptionSimulationButton.setOnClickListener { vm.showSurveyErrorDialog() } + } + } + + private fun RadioGroup.addRadioButton(text: String) { + val rb = RadioButton(context).apply { + this.text = text + id = ViewCompat.generateViewId() + } + addView(rb) + } + + private fun Sequence.checkByName(name: String) { + forEach { + it as RadioButton + it.isChecked = it.text == name + } + } + + private fun showErrorDialog(@StringRes stringRes: Int) { + context?.let { + val dialog = DialogHelper.DialogInstance( + context = it, + title = R.string.datadonation_details_survey_consent_error_dialog_title, + message = stringRes, + positiveButton = R.string.datadonation_details_survey_consent_error_dialog_pos_button, + cancelable = false + ) + DialogHelper.showDialog(dialog) + } } companion object { diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragmentViewModel.kt index 342b26386f5..c0603cc8211 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragmentViewModel.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragmentViewModel.kt @@ -1,17 +1,25 @@ package de.rki.coronawarnapp.test.datadonation.ui +import androidx.annotation.StringRes import androidx.lifecycle.asLiveData import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.appconfig.AppConfigProvider import de.rki.coronawarnapp.appconfig.SafetyNetRequirementsContainer import de.rki.coronawarnapp.datadonation.safetynet.CWASafetyNet import de.rki.coronawarnapp.datadonation.safetynet.DeviceAttestation import de.rki.coronawarnapp.datadonation.safetynet.SafetyNetClientWrapper +import de.rki.coronawarnapp.datadonation.safetynet.SafetyNetException +import de.rki.coronawarnapp.datadonation.safetynet.errorMsgRes +import de.rki.coronawarnapp.datadonation.storage.OTPRepository +import de.rki.coronawarnapp.datadonation.survey.SurveyException +import de.rki.coronawarnapp.datadonation.survey.errorMsgRes 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.SimpleCWAViewModelFactory import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map import timber.log.Timber import java.security.SecureRandom @@ -19,7 +27,9 @@ class DataDonationTestFragmentViewModel @AssistedInject constructor( dispatcherProvider: DispatcherProvider, private val safetyNetClientWrapper: SafetyNetClientWrapper, private val secureRandom: SecureRandom, - private val cwaSafetyNet: CWASafetyNet + private val cwaSafetyNet: CWASafetyNet, + otpRepository: OTPRepository, + appConfigProvider: AppConfigProvider ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { private val currentReportInternal = MutableStateFlow(null) @@ -32,6 +42,21 @@ class DataDonationTestFragmentViewModel @AssistedInject constructor( val errorEvents = SingleLiveEvent() val copyJWSEvent = SingleLiveEvent() + val otp: String = otpRepository.otpAuthorizationResult?.toString() ?: "No OTP generated and authorized yet" + + val surveyConfig = appConfigProvider.currentConfig + .map { it.survey.toString() } + .asLiveData(context = dispatcherProvider.Default) + + private val currentSafetyNetExceptionTypeInternal = MutableStateFlow(SafetyNetException.Type.values().first()) + val currentSafetyNetExceptionType = + currentSafetyNetExceptionTypeInternal.asLiveData(context = dispatcherProvider.Default) + + private val currentSurveyExceptionTypeInternal = MutableStateFlow(SurveyException.Type.values().first()) + val currentSurveyExceptionType = currentSurveyExceptionTypeInternal.asLiveData(context = dispatcherProvider.Default) + + val showErrorDialog = SingleLiveEvent<@StringRes Int>() + fun createSafetyNetReport() { launch { val nonce = ByteArray(16) @@ -85,6 +110,26 @@ class DataDonationTestFragmentViewModel @AssistedInject constructor( } } + fun selectSafetyNetExceptionType(type: SafetyNetException.Type) { + currentSafetyNetExceptionTypeInternal.value = type + } + + fun showSafetyNetErrorDialog() { + currentSafetyNetExceptionTypeInternal.value.run { + SafetyNetException(this, "simulated") + }.also { showErrorDialog.postValue(it.errorMsgRes()) } + } + + fun selectSurveyExceptionType(type: SurveyException.Type) { + currentSurveyExceptionTypeInternal.value = type + } + + fun showSurveyErrorDialog() { + currentSurveyExceptionTypeInternal.value.run { + SurveyException(this) + }.also { showErrorDialog.postValue(it.errorMsgRes()) } + } + @AssistedFactory interface Factory : SimpleCWAViewModelFactory } diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_datadonation.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_datadonation.xml index fbdbea97591..1af2af29b52 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_datadonation.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_datadonation.xml @@ -36,9 +36,9 @@ + + + + + + + + + + + + + + + + + + + + +