Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Verified Commit b67a11f4 authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

EN: Display more details about app usage, add feature for deleting RPI storage

parent 15fb118b
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -57,4 +57,8 @@ android {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }

    kotlinOptions {
        jvmTarget = 1.8
    }
}
+31 −21
Original line number Diff line number Diff line
@@ -8,16 +8,18 @@ package org.microg.gms.nearby.core.ui
import android.content.Intent
import android.os.Bundle
import android.text.format.DateUtils
import androidx.core.text.HtmlCompat
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import org.json.JSONObject
import org.microg.gms.nearby.exposurenotification.ExposureDatabase
import java.util.concurrent.TimeUnit
import org.microg.gms.nearby.exposurenotification.merge

class ExposureNotificationsAppPreferencesFragment : PreferenceFragmentCompat() {
    private lateinit var open: Preference
    private lateinit var checks: Preference
    private lateinit var report: Preference
    private lateinit var apiUsage: Preference
    private val packageName: String?
        get() = arguments?.getString("package")

@@ -27,7 +29,8 @@ class ExposureNotificationsAppPreferencesFragment : PreferenceFragmentCompat() {

    override fun onBindPreferences() {
        open = preferenceScreen.findPreference("pref_exposure_app_open") ?: open
        checks = preferenceScreen.findPreference("pref_exposure_app_checks") ?: checks
        report = preferenceScreen.findPreference("pref_exposure_app_report") ?: report
        apiUsage = preferenceScreen.findPreference("pref_exposure_app_api_usage") ?: apiUsage
        open.onPreferenceClickListener = Preference.OnPreferenceClickListener {
            try {
                packageName?.let {
@@ -50,27 +53,34 @@ class ExposureNotificationsAppPreferencesFragment : PreferenceFragmentCompat() {
    fun updateContent() {
        packageName?.let { packageName ->
            lifecycleScope.launchWhenResumed {
                checks.summary = ExposureDatabase.with(requireContext()) { database ->
                    var str = getString(R.string.pref_exposure_app_checks_summary, database.countMethodCalls(packageName, "provideDiagnosisKeys"))
                val (reportTitle, reportSummary, apiUsageSummary) = ExposureDatabase.with(requireContext()) { database ->
                    val apiUsageSummary = database.methodUsageHistogram(packageName).map {
                        getString(R.string.pref_exposure_app_api_usage_summary_line, it.second, it.first.let { "<tt>$it</tt>" })
                    }.joinToString("<br>").takeIf { it.isNotEmpty() }
                    val token = database.lastMethodCallArgs(packageName, "provideDiagnosisKeys")?.let { JSONObject(it).getString("request_token") }
                            ?: return@with Triple(null, null, apiUsageSummary)
                    val lastCheckTime = database.lastMethodCall(packageName, "provideDiagnosisKeys")
                    if (lastCheckTime != null && lastCheckTime != 0L) {
                        str += "\n" + getString(R.string.pref_exposure_app_last_check_summary, DateUtils.getRelativeDateTimeString(context, lastCheckTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME))
                    }
                    val lastExposureSummaryTime = database.lastMethodCall(packageName, "getExposureSummary")
                    val lastExposureSummary = database.lastMethodCallArgs(packageName, "getExposureSummary")
                    if (lastExposureSummaryTime != null && lastExposureSummary != null && System.currentTimeMillis() - lastExposureSummaryTime <= TimeUnit.DAYS.toMillis(1)) {
                        try {
                            val json = JSONObject(lastExposureSummary)
                            val matchedKeys = json.optInt("response_matched_keys")
                            val daysSince = json.optInt("response_days_since", -1)
                            if (matchedKeys > 0 && daysSince >= 0) {
                                str += "\n" + resources.getQuantityString(R.plurals.pref_exposure_app_last_report_summary, matchedKeys, matchedKeys, daysSince)
                            }
                        } catch (ignored: Exception) {
                        }
                    }
                    str
                }
                            ?: return@with Triple(null, null, apiUsageSummary)
                    val config = database.loadConfiguration(packageName, token)
                            ?: return@with Triple(null, null, apiUsageSummary)
                    val merged = database.findAllMeasuredExposures(config.first).merge().sortedBy { it.timestamp }
                    val reportTitle = getString(R.string.pref_exposure_app_last_report_title, DateUtils.getRelativeTimeSpanString(lastCheckTime, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS))
                    val diagnosisKeysLine = getString(R.string.pref_exposure_app_last_report_summary_diagnosis_keys, database.countDiagnosisKeysInvolved(config.first))
                    val encountersLine = if (merged.isEmpty()) {
                        getString(R.string.pref_exposure_app_last_report_summary_encounters_no)
                    } else {
                        database.findAllMeasuredExposures(config.first).merge().map {
                            val riskScore = it.getRiskScore(config.second)
                            "· " + getString(R.string.pref_exposure_app_last_report_summary_encounters_line, DateUtils.formatDateRange(requireContext(), it.timestamp, it.timestamp + it.durationInMinutes * 60 * 1000L, DateUtils.FORMAT_SHOW_TIME or DateUtils.FORMAT_SHOW_DATE), riskScore)
                        }.joinToString("<br>").let { getString(R.string.pref_exposure_app_last_report_summary_encounters_prefix, merged.size) + "<br>$it<br><i>" + getString(R.string.pref_exposure_app_last_report_summary_encounters_suffix) + "</i>" }
                    }
                    Triple(reportTitle, "$diagnosisKeysLine<br>$encountersLine", apiUsageSummary)
                }
                report.isVisible = reportSummary != null
                report.title = reportTitle
                report.summary = HtmlCompat.fromHtml(reportSummary.orEmpty(), HtmlCompat.FROM_HTML_MODE_COMPACT).trim()
                apiUsage.isVisible = apiUsageSummary != null
                apiUsage.summary = HtmlCompat.fromHtml(apiUsageSummary.orEmpty(), HtmlCompat.FROM_HTML_MODE_COMPACT).trim()
            }
        }
    }
+24 −0
Original line number Diff line number Diff line
@@ -6,9 +6,15 @@
package org.microg.gms.nearby.core.ui

import android.annotation.TargetApi
import android.content.DialogInterface
import android.os.Bundle
import android.text.format.DateFormat
import android.util.Log
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.core.view.setPadding
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import com.db.williamchart.data.Scale
@@ -23,6 +29,7 @@ import kotlin.math.roundToLong
class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
    private lateinit var histogramCategory: PreferenceCategory
    private lateinit var histogram: BarChartPreference
    private lateinit var deleteAll: Preference

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        addPreferencesFromResource(R.xml.preferences_exposure_notifications_rpis)
@@ -31,6 +38,22 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
    override fun onBindPreferences() {
        histogramCategory = preferenceScreen.findPreference("prefcat_exposure_rpi_histogram") ?: histogramCategory
        histogram = preferenceScreen.findPreference("pref_exposure_rpi_histogram") ?: histogram
        deleteAll = preferenceScreen.findPreference("pref_exposure_rpi_delete_all") ?: deleteAll
        deleteAll.onPreferenceClickListener = Preference.OnPreferenceClickListener {
            AlertDialog.Builder(requireContext())
                    .setTitle(R.string.pref_exposure_rpi_delete_all_title)
                    .setView(R.layout.exposure_notification_confirm_delete)
                    .setPositiveButton(R.string.pref_exposure_rpi_delete_all_warning_confirm_button) { _, _ ->
                        lifecycleScope.launchWhenStarted {
                            ExposureDatabase.with(requireContext()) { it.deleteAllCollectedAdvertisements() }
                            updateChart()
                        }
                    }
                    .setNegativeButton(android.R.string.cancel) { _, _ -> }
                    .create()
                    .show()
            true
        }
    }

    override fun onResume() {
@@ -66,6 +89,7 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
                val totalRpiCount = database.totalRpiCount
                totalRpiCount to map
            }
            deleteAll.isEnabled = totalRpiCount != 0L
            histogramCategory.title = getString(R.string.prefcat_exposure_rpis_histogram_title, totalRpiCount)
            histogram.labelsFormatter = { it.roundToInt().toString() }
            histogram.scale = Scale(0f, rpiHistogram.values.max()?.coerceAtLeast(0.1f) ?: 0.1f)
+17 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ SPDX-FileCopyrightText: 2020, microG Project Team
  ~ SPDX-License-Identifier: Apache-2.0
  -->

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:padding="?attr/dialogPreferredPadding"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/pref_exposure_rpi_delete_all_warning" />
</FrameLayout>
+10 −2
Original line number Diff line number Diff line
@@ -11,10 +11,18 @@
    <string name="pref_exposure_collected_rpis_title">Gesammelte IDs</string>
    <string name="pref_exposure_collected_rpis_summary"><xliff:g example="63">%1$d</xliff:g> IDs in den letzten 60 Minuten</string>
    <string name="pref_exposure_advertising_id_title">Aktuell verwendete ID</string>
    <string name="pref_exposure_app_checks_summary"><xliff:g example="5">%1$d</xliff:g> Prüfungen während der letzen 14 Tage</string>
    <string name="pref_exposure_app_last_check_summary">Letzte Prüfung: <xliff:g example="3 hours ago">%1$s</xliff:g></string>
    <string name="pref_exposure_app_last_report_title">Letzter Bericht (<xliff:g example="vor 2 Stunden">%1$s</xliff:g>)</string>
    <string name="pref_exposure_app_last_report_summary_diagnosis_keys"><xliff:g example="121031">%1$d</xliff:g> Diagnoseschlüssel verarbeitet.</string>
    <string name="pref_exposure_app_last_report_summary_encounters_no">Keine Risiko-Begegnung erfasst.</string>
    <string name="pref_exposure_app_last_report_summary_encounters_prefix"><xliff:g example="3">%1$d</xliff:g> Risiko-Begegnungen:</string>
    <string name="pref_exposure_app_last_report_summary_encounters_line"><xliff:g example="Gestern, 12:00 - 12:30">%1$s</xliff:g>, Risiko-Level <xliff:g example="99">%2$d</xliff:g></string>
    <string name="pref_exposure_app_last_report_summary_encounters_suffix">Hinweis: Der Risiko-Level wird durch die App bestimmt. Hohe Werte können ein niedriges Risiko bedeuten oder andersherum.</string>
    <string name="pref_exposure_app_api_usage_title">Nutzung der API in den letzten 14 Tagen</string>
    <string name="pref_exposure_app_api_usage_summary_line"><xliff:g example="12">%1$d</xliff:g> Aufrufe von <xliff:g example="provideDiagnosisKeys">%2$s</xliff:g></string>
    <string name="prefcat_exposure_rpis_histogram_title"><xliff:g example="230">%1$d</xliff:g> gesammelte IDs</string>
    <string name="pref_exposure_rpi_delete_all_title">Alle gesammelten IDs löschen</string>
    <string name="pref_exposure_rpi_delete_all_warning">Nach dem Löschen der gesammelten IDs kannst du nicht mehr informiert werden, falls einer deiner Kontakte der letzten 14 Tage positiv getested wurde.</string>
    <string name="pref_exposure_rpi_delete_all_warning_confirm_button">Trotzdem löschen</string>
    <string name="pref_exposure_info_summary">"Die Exposure Notifications API ermöglicht es Apps, dich zu warnen, falls du Kontakt zu einer positiv getesteten Person hattest.

Das Datum, die Zeitdauer und die Signalstärke, die dem Kontakt zugeordnet sind, werden mit der zugehörigen App geteilt."</string>
Loading