Skip to content
Snippets Groups Projects
Unverified Commit bbabe50c authored by Kolya Opahle's avatar Kolya Opahle Committed by GitHub
Browse files

Merge branch 'release/1.8.x' into fix/3770-warn-others-app-reset

parents 13485f1b 8b4b7897
No related branches found
No related tags found
No related merge requests found
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="LockedOrientationActivity"
package="de.rki.coronawarnapp">
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
</application>
</manifest>
\ No newline at end of file
package de.rki.coronawarnapp.test.risklevel.entities
import com.google.android.gms.nearby.exposurenotification.ExposureWindow
data class ExposureWindowJson(
val dateMillisSinceEpoch: Long,
val reportType: Int,
val infectiousness: Int,
val calibrationConfidence: Int,
val scanInstances: List<ScanInstanceJson>
)
fun ExposureWindow.toExposureWindowJson(): ExposureWindowJson = ExposureWindowJson(
dateMillisSinceEpoch = dateMillisSinceEpoch,
reportType = reportType,
infectiousness = infectiousness,
calibrationConfidence = calibrationConfidence,
scanInstances = scanInstances.map { it.toScanInstanceJson() }
)
package de.rki.coronawarnapp.test.risklevel.entities
import com.google.android.gms.nearby.exposurenotification.ScanInstance
data class ScanInstanceJson(
val typicalAttenuationDb: Int,
val minAttenuationDb: Int,
val secondsSinceLastScan: Int
)
fun ScanInstance.toScanInstanceJson(): ScanInstanceJson = ScanInstanceJson(
typicalAttenuationDb = typicalAttenuationDb,
minAttenuationDb = minAttenuationDb,
secondsSinceLastScan = secondsSinceLastScan
)
package de.rki.coronawarnapp.test.risklevel.ui
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.Toast
import androidx.core.app.ShareCompat
import androidx.core.content.FileProvider
import androidx.core.view.ViewCompat
import androidx.core.view.children
import androidx.fragment.app.Fragment
......@@ -20,6 +23,8 @@ import de.rki.coronawarnapp.util.ui.observe2
import de.rki.coronawarnapp.util.ui.viewBindingLazy
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted
import timber.log.Timber
import java.io.File
import javax.inject.Inject
@Suppress("LongMethod")
......@@ -42,49 +47,43 @@ class TestRiskLevelCalculationFragment : Fragment(R.layout.fragment_test_risk_le
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
vm.tracingCardState.observe2(this) {
binding.tracingCard = it
}
binding.settingsViewModel = settingsViewModel
vm.showRiskStatusCard.observe2(this) {
binding.showRiskStatusCard = it
}
binding.buttonRetrieveDiagnosisKeys.setOnClickListener { vm.retrieveDiagnosisKeys() }
binding.buttonCalculateRiskLevel.setOnClickListener { vm.calculateRiskLevel() }
binding.buttonClearDiagnosisKeyCache.setOnClickListener { vm.clearKeyCache() }
binding.buttonResetRiskLevel.setOnClickListener { vm.resetRiskLevel() }
binding.buttonExposureWindowsShare.setOnClickListener { vm.shareExposureWindows() }
vm.riskLevelResetEvent.observe2(this) {
Toast.makeText(
requireContext(), "Reset done, please fetch diagnosis keys from server again",
Toast.LENGTH_SHORT
).show()
}
vm.additionalRiskCalcInfo.observe2(this) {
binding.labelRiskAdditionalInfo.text = it
}
vm.aggregatedRiskResult.observe2(this) {
binding.labelAggregatedRiskResult.text = it
}
vm.exposureWindowCountString.observe2(this) {
binding.labelExposureWindowCount.text = it
}
vm.exposureWindows.observe2(this) {
binding.labelExposureWindows.text = it
}
vm.backendParameters.observe2(this) {
binding.labelBackendParameters.text = it
}
vm.exposureWindowCount.observe2(this) { exposureWindowCount ->
binding.labelExposureWindowCount.text = "Retrieved $exposureWindowCount Exposure Windows"
binding.buttonExposureWindowsShare.visibility = when (exposureWindowCount > 0) {
true -> View.VISIBLE
false -> View.GONE
}
}
vm.shareFileEvent.observe2(this) {
shareExposureWindowsFile(it)
}
vm.fakeWindowsState.observe2(this) { currentType ->
binding.apply {
if (fakeWindowsToggleGroup.childCount != TestSettings.FakeExposureWindowTypes.values().size) {
......@@ -101,7 +100,6 @@ class TestRiskLevelCalculationFragment : Fragment(R.layout.fragment_test_risk_le
}
}
}
fakeWindowsToggleGroup.children.forEach {
it as RadioButton
it.isChecked = it.text == currentType.name
......@@ -117,8 +115,23 @@ class TestRiskLevelCalculationFragment : Fragment(R.layout.fragment_test_risk_le
}
}
private fun shareExposureWindowsFile(file: File) {
Timber.d("Opening Share-Intent for Exposure Windows")
val shareFileUri =
FileProvider.getUriForFile(requireContext(), requireContext().packageName + ".fileProvider", file)
val shareIntent = ShareCompat.IntentBuilder
.from(requireActivity())
.setStream(shareFileUri)
.setType("text/plain")
.intent
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
if (shareIntent.resolveActivity(requireActivity().packageManager) != null) {
startActivity(shareIntent)
}
}
companion object {
val TAG: String = TestRiskLevelCalculationFragment::class.simpleName!!
private val TAG = TestRiskLevelCalculationFragment::class.java.simpleName
val MENU_ITEM = TestMenuItem(
title = "ENF v2 Calculation",
description = "Window Mode related overview.",
......
......@@ -3,6 +3,8 @@ package de.rki.coronawarnapp.test.risklevel.ui
import android.content.Context
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.asLiveData
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import de.rki.coronawarnapp.appconfig.AppConfigProvider
......@@ -34,11 +36,13 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.withContext
import org.joda.time.Instant
import timber.log.Timber
import java.io.File
import java.util.Date
import java.util.concurrent.TimeUnit
......@@ -46,7 +50,7 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
@Assisted private val handle: SavedStateHandle,
@Assisted private val exampleArg: String?,
@AppContext private val context: Context, // App context
dispatcherProvider: DispatcherProvider,
private val dispatcherProvider: DispatcherProvider,
private val taskController: TaskController,
private val keyCacheRepository: KeyCacheRepository,
private val appConfigProvider: AppConfigProvider,
......@@ -57,6 +61,11 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
dispatcherProvider = dispatcherProvider
) {
// Use unique instance for pretty output
private val gson: Gson by lazy {
GsonBuilder().setPrettyPrinting().create()
}
val fakeWindowsState = testSettings.fakeExposureWindows.flow.asLiveData()
init {
......@@ -66,6 +75,7 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
}
val riskLevelResetEvent = SingleLiveEvent<Unit>()
val shareFileEvent = SingleLiveEvent<File>()
val showRiskStatusCard = SubmissionRepository.deviceUIStateFlow.map {
it.withSuccess(false) { true }
......@@ -75,14 +85,9 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
.sample(150L)
.asLiveData(dispatcherProvider.Default)
val exposureWindowCountString = riskLevelStorage
.exposureWindows
.map { "Retrieved ${it.size} Exposure Windows" }
.asLiveData()
val exposureWindows = riskLevelStorage
val exposureWindowCount = riskLevelStorage
.exposureWindows
.map { if (it.isEmpty()) "Exposure windows list is empty" else it.toString() }
.map { it.size }
.asLiveData()
val aggregatedRiskResult = riskLevelStorage
......@@ -216,6 +221,27 @@ class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor(
}
}
fun shareExposureWindows() {
Timber.d("Creating text file for Exposure Windows")
launch(dispatcherProvider.IO) {
val exposureWindows = riskLevelStorage.exposureWindows.firstOrNull()
val path = File(context.cacheDir, "share/")
path.mkdirs()
val file = File(path, "exposureWindows.txt")
file.bufferedWriter()
.use {
if (exposureWindows.isNullOrEmpty()) {
it.appendLine("Exposure windows list was empty")
} else {
it.appendLine(gson.toJson(exposureWindows))
}
}
shareFileEvent.postValue(file)
}
}
fun clearKeyCache() {
Timber.d("Clearing key cache")
launch { keyCacheRepository.clear() }
......
......@@ -23,6 +23,7 @@
type="de.rki.coronawarnapp.ui.tracing.card.TracingCardState" />
</data>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
......@@ -33,7 +34,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/environment_container"
style="@style/card"
......@@ -170,13 +171,17 @@
android:layout_height="wrap_content"
android:text="-" />
<TextView
android:id="@+id/label_exposure_windows"
android:layout_width="wrap_content"
<Button
android:id="@+id/buttonExposureWindowsShare"
style="@style/buttonPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:text="-" />
android:layout_marginTop="@dimen/spacing_normal"
android:layout_marginBottom="@dimen/spacing_normal"
android:text="Share ExposureWindows" />
</LinearLayout>
</ScrollView>
</layout>
\ No newline at end of file
</layout>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="share" path="share/" />
</paths>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment