From 54fbdadfc9a99b4c373e7d90df02d70545fc4376 Mon Sep 17 00:00:00 2001
From: Lukas Lechner <lukas.lechner@sap.com>
Date: Tue, 20 Apr 2021 10:25:14 +0200
Subject: [PATCH] Technical support function - Add share dialog
 (EXPOSUREAPP-6057) (#2847)

* Share error log instead of storing it locally

* Remove remaining "store-locally" logic

* Refactor DebugLogFragment.kt

* Fix string descriptions

* Fix DebugLogFragmentTest.kt

* Update strings.xml

Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com>
---
 .../bugreporting/DebugLogFragmentTest.kt      |  8 +--
 .../debuglog/export/SAFLogExport.kt           | 62 ----------------
 .../debuglog/ui/DebugLogFragment.kt           | 60 ++++------------
 .../debuglog/ui/DebugLogViewModel.kt          | 43 ++---------
 .../coronawarnapp/util/files/FileSharing.kt   | 31 +-------
 .../layout/bugreporting_debuglog_fragment.xml |  6 +-
 .../src/main/res/values-bg/strings.xml        | 12 +---
 .../src/main/res/values-de/strings.xml        | 13 ++--
 .../src/main/res/values-en/strings.xml        | 12 +---
 .../src/main/res/values-pl/strings.xml        | 12 +---
 .../src/main/res/values-ro/strings.xml        | 12 +---
 .../src/main/res/values-tr/strings.xml        | 12 +---
 .../src/main/res/values/strings.xml           | 12 +---
 .../src/main/res/xml/provider_paths.xml       |  2 +-
 .../debuglog/export/SAFLogExportTest.kt       | 72 -------------------
 15 files changed, 49 insertions(+), 320 deletions(-)
 delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/export/SAFLogExport.kt
 delete mode 100644 Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/export/SAFLogExportTest.kt

diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/bugreporting/DebugLogFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/bugreporting/DebugLogFragmentTest.kt
index c97a39b0d..c18496b74 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/bugreporting/DebugLogFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/bugreporting/DebugLogFragmentTest.kt
@@ -1,12 +1,10 @@
 package de.rki.coronawarnapp.bugreporting
 
-import android.content.ContentResolver
 import androidx.lifecycle.MutableLiveData
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import dagger.Module
 import dagger.android.ContributesAndroidInjector
 import de.rki.coronawarnapp.bugreporting.debuglog.DebugLogger
-import de.rki.coronawarnapp.bugreporting.debuglog.export.SAFLogExport
 import de.rki.coronawarnapp.bugreporting.debuglog.internal.LogSnapshotter
 import de.rki.coronawarnapp.bugreporting.debuglog.ui.DebugLogFragment
 import de.rki.coronawarnapp.bugreporting.debuglog.ui.DebugLogViewModel
@@ -36,8 +34,6 @@ class DebugLogFragmentTest : BaseUITest() {
     @MockK lateinit var enfClient: ENFClient
     @MockK lateinit var bugReportingSettings: BugReportingSettings
     @MockK lateinit var logSnapshotter: LogSnapshotter
-    @MockK lateinit var safLogExport: SAFLogExport
-    @MockK lateinit var contentResolver: ContentResolver
 
     private lateinit var inactiveViewModel: DebugLogViewModel
     private lateinit var activeViewModel: DebugLogViewModel
@@ -103,9 +99,7 @@ class DebugLogFragmentTest : BaseUITest() {
                 TestDispatcherProvider(),
                 enfClient,
                 bugReportingSettings,
-                logSnapshotter,
-                safLogExport,
-                contentResolver
+                logSnapshotter
             )
         )
         with(vm) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/export/SAFLogExport.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/export/SAFLogExport.kt
deleted file mode 100644
index 12d91f7ef..000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/export/SAFLogExport.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-package de.rki.coronawarnapp.bugreporting.debuglog.export
-
-import android.content.ContentResolver
-import android.content.Intent
-import android.net.Uri
-import de.rki.coronawarnapp.bugreporting.debuglog.internal.LogSnapshotter
-import de.rki.coronawarnapp.util.files.determineMimeType
-import okio.buffer
-import okio.sink
-import okio.source
-import timber.log.Timber
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class SAFLogExport @Inject constructor() {
-    private var lastId = 1
-    private val requestMap = mutableMapOf<Int, Request>()
-
-    fun createSAFRequest(snapshot: LogSnapshotter.Snapshot): Request {
-        val request = Request(
-            id = ++lastId,
-            snapshot = snapshot
-        )
-        requestMap[request.id] = request
-        return request
-    }
-
-    fun getRequest(id: Int): Request? = requestMap[id]
-
-    data class Request(
-        val id: Int,
-        val snapshot: LogSnapshotter.Snapshot,
-    ) {
-        fun createIntent() = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
-            addCategory(Intent.CATEGORY_OPENABLE)
-            type = snapshot.path.determineMimeType()
-            putExtra(Intent.EXTRA_TITLE, snapshot.path.name)
-        }
-
-        fun storeSnapshot(resolver: ContentResolver, uri: Uri): Result {
-            Timber.tag(TAG).d("Writing to %s", uri)
-            resolver.openOutputStream(uri)!!.sink().buffer().use { dest ->
-                snapshot.path.source().buffer().use { source ->
-                    dest.writeAll(source)
-                }
-            }
-            Timber.tag(TAG).i("%s was written to %s", snapshot, uri)
-
-            snapshot.delete().also {
-                Timber.tag(TAG).d("Snapshot deleted: %s", snapshot)
-            }
-            return Result(uri)
-        }
-
-        data class Result(val storageUri: Uri)
-    }
-
-    companion object {
-        private const val TAG = "SAFLogSharing"
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogFragment.kt
index 0adf631f1..7c2913791 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogFragment.kt
@@ -1,6 +1,5 @@
 package de.rki.coronawarnapp.bugreporting.debuglog.ui
 
-import android.app.Activity
 import android.content.Intent
 import android.os.Bundle
 import android.provider.Settings
@@ -12,11 +11,12 @@ import androidx.core.widget.NestedScrollView
 import androidx.fragment.app.Fragment
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.bugreporting.debuglog.internal.LogSnapshotter
 import de.rki.coronawarnapp.databinding.BugreportingDebuglogFragmentBinding
 import de.rki.coronawarnapp.util.ContextExtensions.getDrawableCompat
 import de.rki.coronawarnapp.util.di.AutoInject
+import de.rki.coronawarnapp.util.files.FileSharing
 import de.rki.coronawarnapp.util.setUrl
-import de.rki.coronawarnapp.util.tryHumanReadableError
 import de.rki.coronawarnapp.util.ui.doNavigate
 import de.rki.coronawarnapp.util.ui.observe2
 import de.rki.coronawarnapp.util.ui.popBackStack
@@ -26,12 +26,13 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
 import org.joda.time.Duration
 import org.joda.time.Instant
-import timber.log.Timber
 import javax.inject.Inject
 
 class DebugLogFragment : Fragment(R.layout.bugreporting_debuglog_fragment), AutoInject {
 
     @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
+    @Inject lateinit var fileSharing: FileSharing
+
     private val vm: DebugLogViewModel by cwaViewModels { viewModelFactory }
     private val binding: BugreportingDebuglogFragmentBinding by viewBindingLazy()
 
@@ -91,13 +92,13 @@ class DebugLogFragment : Fragment(R.layout.bugreporting_debuglog_fragment), Auto
                 toggleSendErrorLog.apply {
                     isGone = !it.isRecording
                     isEnabled = it.currentSize > 0L && !it.isActionInProgress
-                    setOnClickListener { vm.onShareButtonPress() }
+                    setOnClickListener { vm.onSendErrorLogPress() }
                 }
 
-                toggleStoreLog.apply {
+                toggleExportLog.apply {
                     isGone = !it.isRecording
                     isEnabled = it.currentSize > 0L && !it.isActionInProgress
-                    setOnClickListener { vm.onStoreLog() }
+                    setOnClickListener { vm.onExportLogPress() }
                 }
             }
         }
@@ -128,14 +129,8 @@ class DebugLogFragment : Fragment(R.layout.bugreporting_debuglog_fragment), Auto
                 DebugLogViewModel.Event.ShowLowStorageDialog -> {
                     showLowStorageError()
                 }
-                is DebugLogViewModel.Event.LocalExport -> {
-                    startActivityForResult(it.request.createIntent(), it.request.id)
-                }
-                is DebugLogViewModel.Event.ExportResult -> {
-                    showExportResult()
-                }
-                is DebugLogViewModel.Event.ShowLocalExportError -> {
-                    showLocalExportError(it.error)
+                is DebugLogViewModel.Event.Export -> {
+                    exportLog(it.snapshot)
                 }
             }
         }
@@ -164,14 +159,6 @@ class DebugLogFragment : Fragment(R.layout.bugreporting_debuglog_fragment), Auto
         binding.debugLogHistoryContainer.setOnClickListener { vm.onIdHistoryPress() }
     }
 
-    override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
-        Timber.d("onActivityResult(requestCode=$requestCode, resultCode=$resultCode, resultData=$resultData")
-        vm.processSAFResult(
-            requestCode,
-            if (resultCode == Activity.RESULT_OK) resultData?.data else null
-        )
-    }
-
     private fun showLogDeletionRequest() {
         MaterialAlertDialogBuilder(requireContext()).apply {
             setTitle(R.string.debugging_debuglog_stop_confirmation_title)
@@ -198,29 +185,10 @@ class DebugLogFragment : Fragment(R.layout.bugreporting_debuglog_fragment), Auto
         }.show()
     }
 
-    private fun showExportResult() {
-        MaterialAlertDialogBuilder(requireContext()).apply {
-            setTitle(R.string.debugging_debuglog_localexport_title)
-            setMessage(R.string.debugging_debuglog_localexport_message)
-            setPositiveButton(android.R.string.yes) { _, _ -> /* dismiss */ }
-        }.show()
-    }
-
-    private fun showLocalExportError(cause: Throwable) {
-        MaterialAlertDialogBuilder(requireContext()).apply {
-            setTitle(R.string.errors_generic_headline_short)
-            setMessage(
-                getString(R.string.debugging_debuglog_localexport_error_message) + "\n(" +
-                    cause.tryHumanReadableError(requireContext()).description + ")"
-            )
-            setPositiveButton(android.R.string.yes) { _, _ -> /* dismiss */ }
-            setNeutralButton(R.string.menu_settings) { _, _ ->
-                try {
-                    startActivity(Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS))
-                } catch (e: Exception) {
-                    Toast.makeText(requireContext(), e.toString(), Toast.LENGTH_LONG).show()
-                }
-            }
-        }.show()
+    private fun exportLog(snapshot: LogSnapshotter.Snapshot) {
+        val intent = fileSharing
+            .getFileIntentProvider(snapshot.path, snapshot.path.name, createChooserIntent = true)
+            .intent(requireActivity())
+        startActivity(intent)
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogViewModel.kt
index d9793e597..8e83edfe1 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogViewModel.kt
@@ -1,14 +1,11 @@
 package de.rki.coronawarnapp.bugreporting.debuglog.ui
 
-import android.content.ContentResolver
-import android.net.Uri
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.asLiveData
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.bugreporting.BugReportingSettings
 import de.rki.coronawarnapp.bugreporting.debuglog.DebugLogger
-import de.rki.coronawarnapp.bugreporting.debuglog.export.SAFLogExport
 import de.rki.coronawarnapp.bugreporting.debuglog.internal.LogSnapshotter
 import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.util.CWADebug
@@ -20,16 +17,13 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.combine
 import timber.log.Timber
-import java.io.IOException
 
 class DebugLogViewModel @AssistedInject constructor(
     private val debugLogger: DebugLogger,
     dispatcherProvider: DispatcherProvider,
     private val enfClient: ENFClient,
     bugReportingSettings: BugReportingSettings,
-    private val logSnapshotter: LogSnapshotter,
-    private val safLogExport: SAFLogExport,
-    private val contentResolver: ContentResolver,
+    private val logSnapshotter: LogSnapshotter
 ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
 
     private val isActionInProgress = MutableStateFlow(false)
@@ -55,7 +49,7 @@ class DebugLogViewModel @AssistedInject constructor(
         events.postValue(Event.NavigateToPrivacyFragment)
     }
 
-    fun onShareButtonPress() {
+    fun onSendErrorLogPress() {
         events.postValue(Event.NavigateToUploadFragment)
     }
 
@@ -93,33 +87,10 @@ class DebugLogViewModel @AssistedInject constructor(
         }
     }
 
-    fun onStoreLog() = launchWithProgress(finishProgressAction = false) {
-        Timber.d("storeLog()")
+    fun onExportLogPress() = launchWithProgress(finishProgressAction = true) {
+        Timber.d("onExportLogPress()")
         val snapshot = logSnapshotter.snapshot()
-        val shareRequest = safLogExport.createSAFRequest(snapshot)
-        events.postValue(Event.LocalExport(shareRequest))
-    }
-
-    fun processSAFResult(requestCode: Int, safPath: Uri?) = launchWithProgress {
-        if (safPath == null) {
-            Timber.i("No SAF path available.")
-            return@launchWithProgress
-        }
-
-        val request = safLogExport.getRequest(requestCode)
-        if (request == null) {
-            Timber.w("Unknown request with code $requestCode")
-            return@launchWithProgress
-        }
-
-        try {
-            val storageResult = request.storeSnapshot(contentResolver, safPath)
-            Timber.i("Log stored %s", storageResult)
-            events.postValue(Event.ExportResult(storageResult))
-        } catch (e: IOException) {
-            Timber.e(e, "Failed to store log file.")
-            events.postValue(Event.ShowLocalExportError(e))
-        }
+        events.postValue(Event.Export(snapshot))
     }
 
     private fun launchWithProgress(
@@ -156,10 +127,8 @@ class DebugLogViewModel @AssistedInject constructor(
         object NavigateToUploadHistory : Event()
         object ShowLogDeletionRequest : Event()
         object ShowLowStorageDialog : Event()
-        data class ShowLocalExportError(val error: Throwable) : Event()
         data class Error(val error: Throwable) : Event()
-        data class LocalExport(val request: SAFLogExport.Request) : Event()
-        data class ExportResult(val result: SAFLogExport.Request.Result) : Event()
+        data class Export(val snapshot: LogSnapshotter.Snapshot) : Event()
     }
 
     @AssistedFactory
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/files/FileSharing.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/files/FileSharing.kt
index 488c8a12f..632ee2a10 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/files/FileSharing.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/files/FileSharing.kt
@@ -4,7 +4,6 @@ import android.app.Activity
 import android.content.Context
 import android.content.Intent
 import android.net.Uri
-import androidx.annotation.StringRes
 import androidx.core.app.ShareCompat
 import androidx.core.content.FileProvider
 import dagger.Reusable
@@ -25,45 +24,19 @@ class FileSharing @Inject constructor(
         path
     )
 
-    fun getIntentProvider(
-        path: File,
-        title: String,
-        @StringRes chooserTitle: Int? = null
-    ): ShareIntentProvider = object : ShareIntentProvider {
-        override fun get(activity: Activity): Intent {
-            val builder = ShareCompat.IntentBuilder.from(activity).apply {
-                setType(path.determineMimeType())
-                setStream(getFileUri(path))
-                setSubject(title)
-                chooserTitle?.let { setChooserTitle(it) }
-            }
-
-            val intent = if (chooserTitle != null) {
-                builder.createChooserIntent()
-            } else {
-                builder.intent
-            }
-            return intent.apply {
-                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
-                Timber.tag(TAG).d("Intent created %s", this)
-            }
-        }
-    }
-
     fun getFileIntentProvider(
         path: File,
         title: String,
-        @StringRes chooserTitle: Int? = null
+        createChooserIntent: Boolean = false
     ): FileIntentProvider = object : FileIntentProvider {
         override fun intent(activity: Activity): Intent {
             val builder = ShareCompat.IntentBuilder.from(activity).apply {
                 setType(path.determineMimeType())
                 setStream(getFileUri(path))
                 setSubject(title)
-                chooserTitle?.let { setChooserTitle(it) }
             }
 
-            val intent = if (chooserTitle != null) {
+            val intent = if (createChooserIntent) {
                 builder.createChooserIntent()
             } else {
                 builder.intent
diff --git a/Corona-Warn-App/src/main/res/layout/bugreporting_debuglog_fragment.xml b/Corona-Warn-App/src/main/res/layout/bugreporting_debuglog_fragment.xml
index 2277fe672..1a236c4b8 100644
--- a/Corona-Warn-App/src/main/res/layout/bugreporting_debuglog_fragment.xml
+++ b/Corona-Warn-App/src/main/res/layout/bugreporting_debuglog_fragment.xml
@@ -174,13 +174,13 @@
             tools:text="@string/debugging_debuglog_action_share_log" />
 
         <Button
-            android:id="@+id/toggle_store_log"
+            android:id="@+id/toggle_export_log"
             style="@style/buttonPrimary"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginBottom="8dp"
-            android:text="@string/debugging_debuglog_action_local_log_store"
-            tools:text="@string/debugging_debuglog_action_local_log_store" />
+            android:text="@string/debugging_debuglog_action_local_log_export"
+            tools:text="@string/debugging_debuglog_action_local_log_export" />
 
         <Button
             android:id="@+id/toggle_recording"
diff --git a/Corona-Warn-App/src/main/res/values-bg/strings.xml b/Corona-Warn-App/src/main/res/values-bg/strings.xml
index 3b78ec988..253d3c980 100644
--- a/Corona-Warn-App/src/main/res/values-bg/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/strings.xml
@@ -852,10 +852,10 @@
     <string name="debugging_debuglog_action_start_recording">"Начало"</string>
     <!-- XBUT: Button text to stop the log recording -->
     <string name="debugging_debuglog_action_stop_recording">"Спиране и изтриване"</string>
-    <!-- XBUT: Button text to share the log recording -->
+    <!-- XBUT: Button text to send the log recording to the server -->
     <string name="debugging_debuglog_action_share_log">"Изпращане на отчет за грешки"</string>
-    <!-- XBUT: Button text to locally store the log recording -->
-    <string name="debugging_debuglog_action_local_log_store">"Локално запазване и продължаване"</string>
+    <!-- XBUT: Button text to export the log -->
+    <string name="debugging_debuglog_action_local_log_export">"Локално запазване и продължаване"</string>
     <!-- YTXT: Status text if a debug log is being recorded -->
     <string name="debugging_debuglog_status_recording">"Записването е активно"</string>
     <!-- YTXT: Status text if a debug log is being recorded but there is not enough free storage space -->
@@ -882,12 +882,6 @@
     <string name="debugging_debuglog_stop_confirmation_discard_button">"Продължаване на анализа"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"Необходими са поне 200 MB памет, за да се стартира анализа на грешките. Моля, освободете място."</string>
-    <!-- XHED: Dialog title if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_title">"Запазено локално"</string>
-    <!-- YTXT: Dialog message if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_message">"Анализът на грешките е запазен локално."</string>
-    <!-- YTXT: Dialog message if local export has failed -->
-    <string name="debugging_debuglog_localexport_error_message">"Отчетът за грешките не беше запазен. Моля, проверете дали има достатъчно свободна памет."</string>
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Подробна информация относно изпращането на отчети за грешки"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values-de/strings.xml b/Corona-Warn-App/src/main/res/values-de/strings.xml
index c18d91172..6d3f3cf7c 100644
--- a/Corona-Warn-App/src/main/res/values-de/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/strings.xml
@@ -862,10 +862,10 @@
     <string name="debugging_debuglog_action_start_recording">"Starten"</string>
     <!-- XBUT: Button text to stop the log recording -->
     <string name="debugging_debuglog_action_stop_recording">"Stoppen und löschen"</string>
-    <!-- XBUT: Button text to share the log recording -->
+    <!-- XBUT: Button text to send the log recording to the server-->
     <string name="debugging_debuglog_action_share_log">"Fehlerbericht senden"</string>
-    <!-- XBUT: Button text to locally store the log recording -->
-    <string name="debugging_debuglog_action_local_log_store">"Lokal speichern und fortsetzen"</string>
+    <!-- XBUT: Button text to export the log -->
+    <string name="debugging_debuglog_action_local_log_export">"Teilen und fortsetzen"</string>
     <!-- YTXT: Status text if a debug log is being recorded -->
     <string name="debugging_debuglog_status_recording">"Aufzeichnung läuft"</string>
     <!-- YTXT: Status text if a debug log is being recorded but there is not enough free storage space -->
@@ -892,12 +892,7 @@
     <string name="debugging_debuglog_stop_confirmation_discard_button">"Analyse fortführen"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"Sie brauchen mindestens 200 MB Speicherplatz, um die Fehleranalyse zu starten. Bitte geben Sie Speicherplatz frei."</string>
-    <!-- XHED: Dialog title if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_title">"Lokal gespeichert"</string>
-    <!-- YTXT: Dialog message if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_message">"Die Fehleranalyse wurde lokal gespeichert."</string>
-    <!-- YTXT: Dialog message if local export has failed -->
-    <string name="debugging_debuglog_localexport_error_message">"Das Speichern des Fehlerberichts ist fehlgeschlagen. Bitte überprüfen Sie, ob genügend Speicherplatz zur Verfügung steht."</string>
+
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Ausführliche Informationen zur Übersendung der Fehlerberichte"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values-en/strings.xml b/Corona-Warn-App/src/main/res/values-en/strings.xml
index 26cc64fa9..44a571143 100644
--- a/Corona-Warn-App/src/main/res/values-en/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/strings.xml
@@ -852,10 +852,10 @@
     <string name="debugging_debuglog_action_start_recording">"Start"</string>
     <!-- XBUT: Button text to stop the log recording -->
     <string name="debugging_debuglog_action_stop_recording">"Stop and Delete"</string>
-    <!-- XBUT: Button text to share the log recording -->
+    <!-- XBUT: Button text to send the log recording to the server -->
     <string name="debugging_debuglog_action_share_log">"Send Error Report"</string>
-    <!-- XBUT: Button text to locally store the log recording -->
-    <string name="debugging_debuglog_action_local_log_store">"Save Locally and Continue"</string>
+    <!-- XBUT: Button text to export the log -->
+    <string name="debugging_debuglog_action_local_log_export">"Save Locally and Continue"</string>
     <!-- YTXT: Status text if a debug log is being recorded -->
     <string name="debugging_debuglog_status_recording">"Recording Active"</string>
     <!-- YTXT: Status text if a debug log is being recorded but there is not enough free storage space -->
@@ -882,12 +882,6 @@
     <string name="debugging_debuglog_stop_confirmation_discard_button">"Continue Analysis"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"You need at least 200 MB of memory to start the error analysis. Please free up memory."</string>
-    <!-- XHED: Dialog title if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_title">"Saved Locally"</string>
-    <!-- YTXT: Dialog message if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_message">"The error analysis was saved locally."</string>
-    <!-- YTXT: Dialog message if local export has failed -->
-    <string name="debugging_debuglog_localexport_error_message">"The attempt to save the error report failed. Please check whether enough memory is available."</string>
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Detailed Information on Sending Error Reports"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values-pl/strings.xml b/Corona-Warn-App/src/main/res/values-pl/strings.xml
index f5836ab49..4cb9b8034 100644
--- a/Corona-Warn-App/src/main/res/values-pl/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/strings.xml
@@ -852,10 +852,10 @@
     <string name="debugging_debuglog_action_start_recording">"Uruchom"</string>
     <!-- XBUT: Button text to stop the log recording -->
     <string name="debugging_debuglog_action_stop_recording">"Zatrzymaj i usuń"</string>
-    <!-- XBUT: Button text to share the log recording -->
+    <!-- XBUT: Button text to send the log recording to the server -->
     <string name="debugging_debuglog_action_share_log">"Wyślij raport o błędzie"</string>
-    <!-- XBUT: Button text to locally store the log recording -->
-    <string name="debugging_debuglog_action_local_log_store">"Zapisz lokalnie i kontynuuj"</string>
+    <!-- XBUT: Button text to export the log -->
+    <string name="debugging_debuglog_action_local_log_export">"Zapisz lokalnie i kontynuuj"</string>
     <!-- YTXT: Status text if a debug log is being recorded -->
     <string name="debugging_debuglog_status_recording">"Nagrywanie aktywne"</string>
     <!-- YTXT: Status text if a debug log is being recorded but there is not enough free storage space -->
@@ -882,12 +882,6 @@
     <string name="debugging_debuglog_stop_confirmation_discard_button">"Kontynuuj analizÄ™"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"Aby rozpocząć analizę błędu, potrzebujesz co najmniej 200 MB pamięci. Zwolnij pamięć."</string>
-    <!-- XHED: Dialog title if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_title">"Zapisano lokalnie"</string>
-    <!-- YTXT: Dialog message if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_message">"Analiza błędu została zapisana lokalnie."</string>
-    <!-- YTXT: Dialog message if local export has failed -->
-    <string name="debugging_debuglog_localexport_error_message">"Próba zapisania raportu o błędzie nie powiodła się. Sprawdź, czy dostępna jest wystarczająca ilość pamięci."</string>
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Szczegółowe informacje na temat wysyłania raportów o błędach"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values-ro/strings.xml b/Corona-Warn-App/src/main/res/values-ro/strings.xml
index 26877ff06..35eca689b 100644
--- a/Corona-Warn-App/src/main/res/values-ro/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/strings.xml
@@ -852,10 +852,10 @@
     <string name="debugging_debuglog_action_start_recording">"Pornire"</string>
     <!-- XBUT: Button text to stop the log recording -->
     <string name="debugging_debuglog_action_stop_recording">"Oprire și ștergere"</string>
-    <!-- XBUT: Button text to share the log recording -->
+    <!-- XBUT: Button text to send the log recording to the server -->
     <string name="debugging_debuglog_action_share_log">"Trimitere raport de erori"</string>
-    <!-- XBUT: Button text to locally store the log recording -->
-    <string name="debugging_debuglog_action_local_log_store">"Salvare locală și continuare"</string>
+    <!-- XBUT: Button text to export the log -->
+    <string name="debugging_debuglog_action_local_log_export">"Salvare locală și continuare"</string>
     <!-- YTXT: Status text if a debug log is being recorded -->
     <string name="debugging_debuglog_status_recording">"Înregistrare activă"</string>
     <!-- YTXT: Status text if a debug log is being recorded but there is not enough free storage space -->
@@ -882,12 +882,6 @@
     <string name="debugging_debuglog_stop_confirmation_discard_button">"Continuare analiză"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"Aveți nevoie de cel puțin 200 MB de memorie pentru a începe analiza erorilor. Eliberați memorie."</string>
-    <!-- XHED: Dialog title if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_title">"Salvat local"</string>
-    <!-- YTXT: Dialog message if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_message">"Analiza erorilor a fost salvată local."</string>
-    <!-- YTXT: Dialog message if local export has failed -->
-    <string name="debugging_debuglog_localexport_error_message">"Încercarea de a salva un raport de erori a eșuat. Verificați dacă este disponibilă suficientă memorie."</string>
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Informații detaliate despre trimiterea rapoartelor de erori"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values-tr/strings.xml b/Corona-Warn-App/src/main/res/values-tr/strings.xml
index 523c06ce0..34cf7ca49 100644
--- a/Corona-Warn-App/src/main/res/values-tr/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/strings.xml
@@ -852,10 +852,10 @@
     <string name="debugging_debuglog_action_start_recording">"BaÅŸlat"</string>
     <!-- XBUT: Button text to stop the log recording -->
     <string name="debugging_debuglog_action_stop_recording">"Durdur ve Sil"</string>
-    <!-- XBUT: Button text to share the log recording -->
+    <!-- XBUT: Button text to send the log recording to the server -->
     <string name="debugging_debuglog_action_share_log">"Hata Raporu Gönder"</string>
-    <!-- XBUT: Button text to locally store the log recording -->
-    <string name="debugging_debuglog_action_local_log_store">"Yerel Olarak Kaydet ve Devam Et"</string>
+    <!-- XBUT: Button text to export the log -->
+    <string name="debugging_debuglog_action_local_log_export">"Yerel Olarak Kaydet ve Devam Et"</string>
     <!-- YTXT: Status text if a debug log is being recorded -->
     <string name="debugging_debuglog_status_recording">"Kayıt Etkin"</string>
     <!-- YTXT: Status text if a debug log is being recorded but there is not enough free storage space -->
@@ -882,12 +882,6 @@
     <string name="debugging_debuglog_stop_confirmation_discard_button">"Analizi Devam Ettir"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"Hata analizini başlatmak için en az 200 MB bellek alanınızın olması gerekir. Lütfen belleği boşaltın."</string>
-    <!-- XHED: Dialog title if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_title">"Yerel Olarak Kaydedildi"</string>
-    <!-- YTXT: Dialog message if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_message">"Hata analizi yerel olarak kaydedilmiÅŸtir."</string>
-    <!-- YTXT: Dialog message if local export has failed -->
-    <string name="debugging_debuglog_localexport_error_message">"Hata raporunu kaydetme denemesi başarısız oldu. Lütfen yeterli bellek alanı olup olmadığını kontrol edin."</string>
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Hata Raporlarını Gönderme Konusunda Ayrıntılı Bilgi"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml
index 2dcf9f6df..25a9ac057 100644
--- a/Corona-Warn-App/src/main/res/values/strings.xml
+++ b/Corona-Warn-App/src/main/res/values/strings.xml
@@ -879,10 +879,10 @@
     <string name="debugging_debuglog_action_start_recording">"Start"</string>
     <!-- XBUT: Button text to stop the log recording -->
     <string name="debugging_debuglog_action_stop_recording">"Stop and Delete"</string>
-    <!-- XBUT: Button text to share the log recording -->
+    <!-- XBUT: Button text to send the log recording to the server -->
     <string name="debugging_debuglog_action_share_log">"Send Error Report"</string>
-    <!-- XBUT: Button text to locally store the log recording -->
-    <string name="debugging_debuglog_action_local_log_store">"Save Locally and Continue"</string>
+    <!-- XBUT: Button text to export the log -->
+    <string name="debugging_debuglog_action_local_log_export">"Save Locally and Continue"</string>
     <!-- YTXT: Status text if a debug log is being recorded -->
     <string name="debugging_debuglog_status_recording">"Recording Active"</string>
     <!-- YTXT: Status text if a debug log is being recorded but there is not enough free storage space -->
@@ -909,12 +909,6 @@
     <string name="debugging_debuglog_stop_confirmation_discard_button">"Continue Analysis"</string>
     <!-- YTXT: Dialog message if there is not enough free storage to start a debug log -->
     <string name="debugging_debuglog_start_low_storage_error">"You need at least 200 MB of memory to start the error analysis. Please free up memory."</string>
-    <!-- XHED: Dialog title if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_title">"Saved Locally"</string>
-    <!-- YTXT: Dialog message if a user has stored a debug log locally -->
-    <string name="debugging_debuglog_localexport_message">"The error analysis was saved locally."</string>
-    <!-- YTXT: Dialog message if local export has failed -->
-    <string name="debugging_debuglog_localexport_error_message">"The attempt to save the error report failed. Please check whether enough memory is available."</string>
     <!-- XHED: Title for debug legal screen -->
     <string name="debugging_debuglog_legal_dialog_title">"Detailed Information on Sending Error Reports"</string>
     <!-- YTXT: Section Title for debug legal screen -->
diff --git a/Corona-Warn-App/src/main/res/xml/provider_paths.xml b/Corona-Warn-App/src/main/res/xml/provider_paths.xml
index 823eb8182..6f39652a1 100644
--- a/Corona-Warn-App/src/main/res/xml/provider_paths.xml
+++ b/Corona-Warn-App/src/main/res/xml/provider_paths.xml
@@ -5,7 +5,7 @@
         path="share/" />
     <cache-path
         name="shared_logs"
-        path="debuglog/shared/" />
+        path="debuglog_snapshots/" />
 
     <cache-path
         name="Poster"
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/export/SAFLogExportTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/export/SAFLogExportTest.kt
deleted file mode 100644
index d7716d193..000000000
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/export/SAFLogExportTest.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-package de.rki.coronawarnapp.bugreporting.debuglog.export
-
-import android.content.ContentResolver
-import de.rki.coronawarnapp.bugreporting.debuglog.internal.LogSnapshotter
-import io.kotest.matchers.shouldBe
-import io.kotest.matchers.shouldNotBe
-import io.mockk.MockKAnnotations
-import io.mockk.every
-import io.mockk.impl.annotations.MockK
-import io.mockk.mockk
-import org.junit.jupiter.api.AfterEach
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import testhelpers.BaseIOTest
-import timber.log.Timber
-import java.io.File
-
-class SAFLogExportTest : BaseIOTest() {
-
-    @MockK lateinit var contentResolver: ContentResolver
-
-    private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!)
-    private val zipFile = File(testDir, "logfile.zip")
-    private val uriFakeFile = File(testDir, "urifakefile")
-
-    @BeforeEach
-    fun setup() {
-        MockKAnnotations.init(this)
-
-        testDir.mkdirs()
-        testDir.exists() shouldBe true
-
-        every { contentResolver.openOutputStream(any()) } answers {
-            uriFakeFile.outputStream()
-        }
-    }
-
-    @AfterEach
-    fun teardown() {
-        testDir.deleteRecursively()
-        Timber.uprootAll()
-    }
-
-    private fun createInstance() = SAFLogExport()
-
-    @Test
-    fun `request creation and write`() {
-        val instance = createInstance()
-
-        zipFile.createNewFile()
-        zipFile.exists() shouldBe true
-        zipFile.writeText("testcontent")
-
-        val snapshot = LogSnapshotter.Snapshot(zipFile)
-        val request = instance.createSAFRequest(snapshot)
-        request.snapshot shouldBe snapshot
-
-        request.storeSnapshot(contentResolver, mockk())
-        zipFile.exists() shouldBe false
-        uriFakeFile.readText() shouldBe "testcontent"
-    }
-
-    @Test
-    fun `new requests increase id`() {
-        val instance = createInstance()
-        instance.createSAFRequest(mockk()).id shouldBe 2
-        instance.getRequest(2) shouldNotBe null
-        instance.createSAFRequest(mockk()).id shouldBe 3
-        instance.getRequest(3) shouldNotBe null
-        instance.getRequest(4) shouldBe null
-    }
-}
-- 
GitLab