From 0d90fad8e986a982d08423fc2ba298b433365984 Mon Sep 17 00:00:00 2001 From: Philipp Woessner <64482866+pwoessner@users.noreply.github.com> Date: Fri, 5 Jun 2020 18:05:04 +0200 Subject: [PATCH] Improved test fragments for risk level calculation (#205) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added text style for 3 hour mode * possibility to see all key qr codes, added risk level reset, set transmission risk level for risk level calc Co-authored-by: Jakob Möller <jakob.moeller@sap.com> --- .../rki/coronawarnapp/TestForAPIFragment.kt | 77 +++++++++++++++---- .../coronawarnapp/TestRiskLevelCalculation.kt | 41 +++++++++- .../res/layout/fragment_test_for_a_p_i.xml | 10 +-- .../fragment_test_risk_level_calculation.xml | 36 ++++++++- .../src/main/res/layout/test_qr_code_view.xml | 7 ++ 5 files changed, 145 insertions(+), 26 deletions(-) create mode 100644 Corona-Warn-App/src/main/res/layout/test_qr_code_view.xml diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt index 5eebf8110..8a2247446 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestForAPIFragment.kt @@ -2,11 +2,14 @@ package de.rki.coronawarnapp import android.content.Intent import android.graphics.Bitmap +import android.graphics.Color import android.os.Bundle +import android.util.Base64 import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ImageView import android.widget.Switch import android.widget.Toast import androidx.core.content.pm.PackageInfoCompat @@ -14,6 +17,8 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import androidx.lifecycle.viewModelScope +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager2.widget.ViewPager2 import com.google.android.gms.common.GoogleApiAvailability import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient @@ -21,8 +26,11 @@ import com.google.android.gms.nearby.exposurenotification.ExposureSummary import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey import com.google.gson.Gson import com.google.gson.reflect.TypeToken +import com.google.protobuf.ByteString +import com.google.zxing.BarcodeFormat import com.google.zxing.integration.android.IntentIntegrator import com.google.zxing.integration.android.IntentResult +import com.google.zxing.qrcode.QRCodeWriter import de.rki.coronawarnapp.databinding.FragmentTestForAPIBinding import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.ExceptionCategory.INTERNAL @@ -56,7 +64,6 @@ import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_insert_expo import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_retrieve_exposure_summary import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_tracing_duration_in_retention_period import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.button_tracing_intervals -import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.image_qr_code import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_exposure_summary_attenuation import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_exposure_summary_daysSinceLastExposure import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_exposure_summary_matchedKeyCount @@ -64,6 +71,7 @@ import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_exposure_sum import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_exposure_summary_summationRiskScore import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_googlePlayServices_version import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.label_my_keys +import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.qr_code_viewpager import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.test_api_switch_last_three_hours_from_server import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.text_my_keys import kotlinx.android.synthetic.main.fragment_test_for_a_p_i.text_scanned_key @@ -93,6 +101,7 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel } private var myExposureKeysJSON: String? = null + private var myExposureKeys: List<TemporaryExposureKey>? = mutableListOf() private var otherExposureKey: AppleLegacyKeyExchange.Key? = null private var otherExposureKeyList = mutableListOf<AppleLegacyKeyExchange.Key>() @@ -103,6 +112,9 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel // ViewModel for MainActivity private val tracingViewModel: TracingViewModel by activityViewModels() + private lateinit var qrPager: ViewPager2 + private lateinit var qrPagerAdapter: RecyclerView.Adapter<QRPagerAdapter.QRViewHolder> + // Data and View binding private var _binding: FragmentTestForAPIBinding? = null private val binding: FragmentTestForAPIBinding get() = _binding!! @@ -147,15 +159,16 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel internalExposureNotificationPermissionHelper = InternalExposureNotificationPermissionHelper(this, this) + qrPager = qr_code_viewpager + qrPagerAdapter = QRPagerAdapter() + qrPager.adapter = qrPagerAdapter + button_api_test_start.setOnClickListener { start() } button_api_get_exposure_keys.setOnClickListener { getExposureKeys() - tracingViewModel.viewModelScope.launch { - ExposureSharingService.shareKeysAsBitmap(300, 300, updateQRImageView) - } } val last3HoursSwitch = test_api_switch_last_three_hours_from_server as Switch @@ -257,13 +270,6 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel getExposureKeys() } - private val updateQRImageView = { bitmap: Bitmap? -> - bitmap?.let { - image_qr_code.setImageBitmap(bitmap) - image_qr_code.visibility = View.VISIBLE - } - } - private val prettyKey = { key: AppleLegacyKeyExchange.Key -> StringBuilder() .append("\nKey data: ${key.keyData}") @@ -439,10 +445,6 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel ) label_my_keys.text = myKeysLabelAndCount text_my_keys.text = myExposureKeysJSON - - tracingViewModel.viewModelScope.launch { - ExposureSharingService.shareKeysAsBitmap(300, 300, updateQRImageView) - } } private fun showToast(message: String) { @@ -461,6 +463,9 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel override fun onKeySharePermissionGranted(keys: List<TemporaryExposureKey>) { myExposureKeysJSON = keysToJson(keys) + myExposureKeys = keys + qrPagerAdapter.notifyDataSetChanged() + updateKeysDisplay() } @@ -507,4 +512,46 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel CONFIG_SCORE ) .build() + + private inner class QRPagerAdapter : + RecyclerView.Adapter<QRPagerAdapter.QRViewHolder>() { + + inner class QRViewHolder(val qrCode: ImageView) : RecyclerView.ViewHolder(qrCode) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QRViewHolder { + val imageView = LayoutInflater.from(parent.context) + .inflate(R.layout.test_qr_code_view, parent, false) as ImageView + return QRViewHolder(imageView) + } + + override fun getItemCount(): Int = myExposureKeys?.size ?: 0 + + override fun onBindViewHolder(holder: QRViewHolder, position: Int) { + myExposureKeys?.get(position)?.let { + holder.qrCode.setImageBitmap(bitmapForImage(it)) + } + } + + private fun bitmapForImage(key: TemporaryExposureKey): Bitmap { + val key = AppleLegacyKeyExchange.Key.newBuilder() + .setKeyData(ByteString.copyFrom(key.keyData)) + .setRollingPeriod(key.rollingPeriod) + .setRollingStartNumber(key.rollingStartIntervalNumber) + .build().toByteArray() + val bMatrix = QRCodeWriter().encode( + Base64.encodeToString(key, Base64.DEFAULT), + BarcodeFormat.QR_CODE, + 300, + 300 + ) + val bmp = + Bitmap.createBitmap(bMatrix.width, bMatrix.height, Bitmap.Config.RGB_565) + for (x in 0 until bMatrix.width) { + for (y in 0 until bMatrix.height) { + bmp.setPixel(x, y, if (bMatrix.get(x, y)) Color.BLACK else Color.WHITE) + } + } + return bmp + } + } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt index 06ab72e5b..ef572b3a2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt @@ -6,6 +6,7 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.EditText import android.widget.Toast import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -26,6 +27,8 @@ import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService import de.rki.coronawarnapp.sharing.ExposureSharingService +import de.rki.coronawarnapp.storage.AppDatabase +import de.rki.coronawarnapp.storage.FileStorageHelper import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction import de.rki.coronawarnapp.transaction.RiskLevelTransaction @@ -33,7 +36,10 @@ import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel import de.rki.coronawarnapp.util.KeyFileHelper +import kotlinx.android.synthetic.main.fragment_test_risk_level_calculation.transmission_number +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.io.File import java.util.UUID import java.util.concurrent.TimeUnit @@ -94,6 +100,33 @@ class TestRiskLevelCalculation : Fragment() { } } + binding.buttonResetRiskLevel.setOnClickListener { + tracingViewModel.viewModelScope.launch { + withContext(Dispatchers.IO) { + try { + // Database Reset + AppDatabase.getInstance(requireContext()).clearAllTables() + // Delete Database Instance + AppDatabase.resetInstance(requireContext()) + // Export File Reset + FileStorageHelper.getAllFilesInKeyExportDirectory().forEach { it.delete() } + + LocalData.lastCalculatedRiskLevel(RiskLevel.UNDETERMINED.raw) + LocalData.lastSuccessfullyCalculatedRiskLevel(RiskLevel.UNDETERMINED.raw) + LocalData.lastTimeDiagnosisKeysFromServerFetch(null) + LocalData.googleApiToken(null) + } catch (e: java.lang.Exception) { + e.report(ExceptionCategory.INTERNAL) + } + } + RiskLevelTransaction.start() + Toast.makeText( + requireContext(), "Resetted, please fetch diagnosis keys from server again", + Toast.LENGTH_SHORT + ).show() + } + } + startObserving() } @@ -151,12 +184,18 @@ class TestRiskLevelCalculation : Fragment() { val appleKeyList = mutableListOf<AppleLegacyKeyExchange.Key>() + val text = (transmission_number as EditText).text.toString() + var number = 5 + if (!text.isBlank()) { + number = Integer.valueOf(text) + } + appleKeyList.add( AppleLegacyKeyExchange.Key.newBuilder() .setKeyData(key.keyData) .setRollingPeriod(144) .setRollingStartNumber(key.rollingStartNumber) - .setTransmissionRiskLevel(1) + .setTransmissionRiskLevel(number) .build() ) diff --git a/Corona-Warn-App/src/main/res/layout/fragment_test_for_a_p_i.xml b/Corona-Warn-App/src/main/res/layout/fragment_test_for_a_p_i.xml index 2aadb21fc..bd05b3126 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_test_for_a_p_i.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_test_for_a_p_i.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<layout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> +<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> @@ -111,11 +110,10 @@ android:lines="5" android:visibility="gone" /> - <ImageView - android:id="@+id/image_qr_code" + <androidx.viewpager2.widget.ViewPager2 + android:id="@+id/qr_code_viewpager" android:layout_width="match_parent" - android:layout_height="200dp" - app:srcCompat="@drawable/button" /> + android:layout_height="200dp" /> <TextView android:id="@+id/label_other_keys" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_test_risk_level_calculation.xml b/Corona-Warn-App/src/main/res/layout/fragment_test_risk_level_calculation.xml index 64cadd014..c55150b3d 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_test_risk_level_calculation.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_test_risk_level_calculation.xml @@ -49,6 +49,34 @@ app:showDetails="@{false}" app:tracingViewModel="@{tracingViewModel}" /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Transmission Risk Level for scan: " /> + + <EditText + android:id="@+id/transmission_number" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ems="10" + android:inputType="number" + android:text="5" /> + </LinearLayout> + + <Button + android:id="@+id/button_provide_key_via_qr" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/spacing_normal" + android:text="Scan Local QR Code" /> + <Button android:id="@+id/button_retrieve_diagnosis_keys" style="@style/buttonPrimary" @@ -58,20 +86,20 @@ android:text="Retrieve Diagnosis Keys" /> <Button - android:id="@+id/button_provide_key_via_qr" + android:id="@+id/button_calculate_risk_level" style="@style/buttonPrimary" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" - android:text="Scan Local QR Code" /> + android:text="Calculate Risk Level" /> <Button - android:id="@+id/button_calculate_risk_level" + android:id="@+id/button_reset_risk_level" style="@style/buttonPrimary" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" - android:text="Calculate Risk Level" /> + android:text="Reset Risk Level" /> <TextView android:id="@+id/label_exposure_summary_title" diff --git a/Corona-Warn-App/src/main/res/layout/test_qr_code_view.xml b/Corona-Warn-App/src/main/res/layout/test_qr_code_view.xml new file mode 100644 index 000000000..c5ccf3344 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/test_qr_code_view.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<ImageView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/image_qr_code" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:srcCompat="@drawable/button" /> -- GitLab