Export notification logs through document picker
This commit is contained in:
@@ -3,6 +3,7 @@ package se.ajpanton.notificationlog
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
@@ -15,11 +16,17 @@ import se.ajpanton.notificationlog.settings.LogField
|
|||||||
import se.ajpanton.notificationlog.settings.LogViewSettingsStore
|
import se.ajpanton.notificationlog.settings.LogViewSettingsStore
|
||||||
import se.ajpanton.notificationlog.settings.TimestampZone
|
import se.ajpanton.notificationlog.settings.TimestampZone
|
||||||
import se.ajpanton.notificationlog.capture.NotificationCaptureService
|
import se.ajpanton.notificationlog.capture.NotificationCaptureService
|
||||||
|
import se.ajpanton.notificationlog.export.LogExporter
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
||||||
private var binding: FragmentViewLogsBinding? = null
|
private var binding: FragmentViewLogsBinding? = null
|
||||||
|
private var pendingExport: ExportFormat? = null
|
||||||
|
private val createDocument = registerForActivityResult(androidx.activity.result.contract.ActivityResultContracts.CreateDocument("application/octet-stream")) { uri ->
|
||||||
|
uri?.let(::writeExport)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@@ -27,6 +34,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
|||||||
binding!!.notificationAccess.setOnClickListener {
|
binding!!.notificationAccess.setOnClickListener {
|
||||||
startActivity(Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS))
|
startActivity(Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS))
|
||||||
}
|
}
|
||||||
|
binding!!.exportLogs.setOnClickListener { chooseExportFormat() }
|
||||||
binding!!.clearLogs.setOnClickListener {
|
binding!!.clearLogs.setOnClickListener {
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle("Clear logs?")
|
.setTitle("Clear logs?")
|
||||||
@@ -90,4 +98,32 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
|||||||
ComponentName(requireContext(), NotificationCaptureService::class.java),
|
ComponentName(requireContext(), NotificationCaptureService::class.java),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun chooseExportFormat() {
|
||||||
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setItems(arrayOf("CSV", "Formatted text", "HTML ZIP")) { _, which ->
|
||||||
|
pendingExport = ExportFormat.entries[which]
|
||||||
|
createDocument.launch("notification-log.${pendingExport!!.extension}")
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeExport(uri: Uri) {
|
||||||
|
val format = pendingExport ?: return
|
||||||
|
val context = requireContext().applicationContext
|
||||||
|
Thread {
|
||||||
|
val entries = EncryptedNotificationLogStore(context).readAll()
|
||||||
|
val settings = LogViewSettingsStore(context).load()
|
||||||
|
context.contentResolver.openOutputStream(uri)?.use { output -> when (format) {
|
||||||
|
ExportFormat.CSV -> output.write(LogExporter.csv(entries, settings).encodeToByteArray())
|
||||||
|
ExportFormat.FORMATTED -> output.write(LogExporter.formatted(entries, settings).encodeToByteArray())
|
||||||
|
ExportFormat.HTML_ZIP -> ZipOutputStream(output).use { zip ->
|
||||||
|
zip.putNextEntry(java.util.zip.ZipEntry("notification-log.html"))
|
||||||
|
zip.write(LogExporter.html(entries, settings).encodeToByteArray())
|
||||||
|
zip.closeEntry()
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class ExportFormat(val extension: String) { CSV("csv"), FORMATTED("txt"), HTML_ZIP("zip") }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="@dimen/page_padding">
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="@dimen/page_padding">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"><Button android:id="@+id/notification_access" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enable notification access"/><Button android:id="@+id/clear_logs" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Clear logs" /></LinearLayout>
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"><Button android:id="@+id/notification_access" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enable notification access"/><Button android:id="@+id/export_logs" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Export logs"/><Button android:id="@+id/clear_logs" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Clear logs" /></LinearLayout>
|
||||||
<ScrollView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1">
|
<ScrollView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">
|
||||||
<TextView android:id="@+id/empty_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="No logs yet." />
|
<TextView android:id="@+id/empty_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="No logs yet." />
|
||||||
|
|||||||
Reference in New Issue
Block a user