diff --git a/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsRpisFragment.kt b/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsRpisFragment.kt
index 111baf23..d643a1c3 100644
--- a/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsRpisFragment.kt
+++ b/play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsRpisFragment.kt
@@ -24,6 +24,7 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
private lateinit var histogramCategory: PreferenceCategory
private lateinit var histogram: BarChartPreference
private lateinit var deleteAll: Preference
+ private lateinit var exportDb: Preference
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences_exposure_notifications_rpis)
@@ -33,6 +34,7 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
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
+ exportDb = preferenceScreen.findPreference("pref_exposure_export_database") ?: exportDb
deleteAll.onPreferenceClickListener = Preference.OnPreferenceClickListener {
AlertDialog.Builder(requireContext())
.setTitle(R.string.pref_exposure_rpi_delete_all_title)
@@ -48,6 +50,10 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
.show()
true
}
+ exportDb.onPreferenceClickListener = Preference.OnPreferenceClickListener {
+ ExposureDatabase.export(requireContext())
+ true
+ }
}
override fun onResume() {
diff --git a/play-services-nearby-core-ui/src/main/res/values-de/strings.xml b/play-services-nearby-core-ui/src/main/res/values-de/strings.xml
index 175a19bf..9183c387 100644
--- a/play-services-nearby-core-ui/src/main/res/values-de/strings.xml
+++ b/play-services-nearby-core-ui/src/main/res/values-de/strings.xml
@@ -33,6 +33,8 @@
Alle gesammelten IDs löschen
Nach dem Löschen der gesammelten IDs kannst du nicht mehr informiert werden, falls einer deiner Kontakte der letzten 14 Tage positiv getested wurde.
Trotzdem löschen
+ Datenbank Export
+ Exportiere die aktuelle Datenbank um sie mit einer anderen App zu analysieren.
"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."
diff --git a/play-services-nearby-core-ui/src/main/res/values/strings.xml b/play-services-nearby-core-ui/src/main/res/values/strings.xml
index 71a2787b..21a7b7a1 100644
--- a/play-services-nearby-core-ui/src/main/res/values/strings.xml
+++ b/play-services-nearby-core-ui/src/main/res/values/strings.xml
@@ -43,6 +43,8 @@
Delete all collected IDs
Deleting collected IDs will make it impossible to notify you in case any of your contacts of the last 14 days is diagnosed.
Delete anyways
+ Export Database
+ Export the current database for analysis with another app.
"Exposure Notifications API allows apps to notify you if you were exposed to someone who reported to be diagnosed positive.
The date, duration, and signal strength associated with an exposure will be shared with the corresponding app."
diff --git a/play-services-nearby-core-ui/src/main/res/xml/preferences_exposure_notifications_rpis.xml b/play-services-nearby-core-ui/src/main/res/xml/preferences_exposure_notifications_rpis.xml
index 7ef08d91..63737f95 100644
--- a/play-services-nearby-core-ui/src/main/res/xml/preferences_exposure_notifications_rpis.xml
+++ b/play-services-nearby-core-ui/src/main/res/xml/preferences_exposure_notifications_rpis.xml
@@ -18,6 +18,12 @@
android:key="pref_exposure_rpi_delete_all"
android:title="@string/pref_exposure_rpi_delete_all_title" />
+
+
+
+
+
+
+
diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureDatabase.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureDatabase.kt
index 5f16ede7..f0bd9a4a 100644
--- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureDatabase.kt
+++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureDatabase.kt
@@ -8,13 +8,17 @@ package org.microg.gms.nearby.exposurenotification
import android.annotation.TargetApi
import android.content.ContentValues
import android.content.Context
+import android.content.Intent
import android.database.sqlite.SQLiteCursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteDatabase.CONFLICT_IGNORE
import android.database.sqlite.SQLiteOpenHelper
+import android.net.Uri
import android.os.Parcel
import android.os.Parcelable
import android.util.Log
+import androidx.core.content.FileProvider
+import com.google.android.gms.nearby.exposurenotification.CalibrationConfidence
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
@@ -964,6 +968,53 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
}
}
+ fun export(context: Context) {
+ // FileProvider cannot directly access /databases, so we have to copy the database first
+ // In addition, we filter out only the Advertisements table to not export sensitive TEKs
+
+ // Create a new database which will store only the Advertisements table
+ val exportDir = File(context.getCacheDir(), "exposureDatabase")
+ exportDir.mkdir()
+ val exportFile = File(exportDir, "database.db")
+ if (exportFile.delete()) {
+ Log.d("EN-DB-Exporter", "Deleted old export database.")
+ }
+ val db = SQLiteDatabase.openOrCreateDatabase(exportFile, null)
+
+ // Attach the full database to the new empty db
+ val databaseFile = context.getDatabasePath(DB_NAME);
+ db.execSQL("ATTACH '$databaseFile' AS fulldb;")
+
+ // copy TABLE_ADVERTISEMENTS over
+ db.execSQL("CREATE TABLE $TABLE_ADVERTISEMENTS AS SELECT * FROM fulldb.$TABLE_ADVERTISEMENTS;")
+
+ // Detach original db, close new db
+ db.execSQL("DETACH DATABASE fulldb;")
+ db.close()
+
+ // Use the FileProvider to get a content URI for the new DB
+ val fileUri: Uri? = try {
+ FileProvider.getUriForFile(context,"org.microg.gms.nearby.exposurenotification.export", exportFile)
+ } catch (e: IllegalArgumentException) {
+ Log.e("EN-DB-Exporter", "The database file can't be shared: $exportFile $e")
+ null
+ }
+
+ // Open a sharesheet
+ if (fileUri != null) {
+ // Grant temporary read permission to the content URI
+ val sendIntent: Intent = Intent().apply {
+ action = Intent.ACTION_SEND
+ putExtra(Intent.EXTRA_STREAM, fileUri)
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ type = "application/vnd.sqlite3"
+ }
+
+ val shareIntent = Intent.createChooser(sendIntent, null)
+ context.startActivity(shareIntent)
+ }
+ }
+
@Deprecated(message = "Sync database access is slow", replaceWith = ReplaceWith("with(context, call)"))
fun withSync(context: Context, call: (ExposureDatabase) -> T): T {
val it = runBlocking { ref(context) }
diff --git a/play-services-nearby-core/src/main/res/xml/preferences_exposure_notifications_exportedfiles.xml b/play-services-nearby-core/src/main/res/xml/preferences_exposure_notifications_exportedfiles.xml
new file mode 100644
index 00000000..2d62db66
--- /dev/null
+++ b/play-services-nearby-core/src/main/res/xml/preferences_exposure_notifications_exportedfiles.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file