]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt
Fix possibly blocking OutputStream calls. https://redmine.stoutner.com/issues/914
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / LogcatActivity.kt
index e555f1943e062129802e4ceb2f86ca565b4e35b7..25c2bfc6e3d3a1af9b47b0ba8bd5f482b6660be3 100644 (file)
@@ -1,20 +1,20 @@
 /*
- * Copyright © 2019-2021 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2019-2022 Soren Stoutner <soren@stoutner.com>.
  *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
  *
- * Privacy Browser is free software: you can redistribute it and/or modify
+ * Privacy Browser Android is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
- * Privacy Browser is distributed in the hope that it will be useful,
+ * Privacy Browser Android is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
+ * along with Privacy Browser Android.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 package com.stoutner.privacybrowser.activities
@@ -43,6 +43,11 @@ import com.stoutner.privacybrowser.BuildConfig
 
 import com.stoutner.privacybrowser.R
 
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
 import java.io.BufferedReader
 import java.io.IOException
 import java.io.InputStreamReader
@@ -62,35 +67,40 @@ class LogcatActivity : AppCompatActivity() {
     private lateinit var logcatTextView: TextView
 
     // Define the save logcat activity result launcher.  It must be defined before `onCreate()` is run or the app will crash.
-    private val saveLogcatActivityResultLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument()) { fileNameUri: Uri? ->
+    private val saveLogcatActivityResultLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { fileUri: Uri? ->
         // Only save the file if the URI is not null, which happens if the user exited the file picker by pressing back.
-        if (fileNameUri != null) {
+        if (fileUri != null) {
             try {
                 // Get the logcat string.
                 val logcatString = logcatTextView.text.toString()
 
                 // Open an output stream.
-                val outputStream = contentResolver.openOutputStream(fileNameUri)!!
+                val outputStream = contentResolver.openOutputStream(fileUri)!!
 
-                // Write the logcat string to the output stream.
-                outputStream.write(logcatString.toByteArray(StandardCharsets.UTF_8))
+                // Save the logcat using a coroutine with Dispatchers.IO.
+                CoroutineScope(Dispatchers.Main).launch {
+                    withContext(Dispatchers.IO) {
+                        // Write the logcat string to the output stream.
+                        outputStream.write(logcatString.toByteArray(StandardCharsets.UTF_8))
 
-                // Close the output stream.
-                outputStream.close()
+                        // Close the output stream.
+                        outputStream.close()
+                    }
+                }
 
-                // Initialize the file name string from the file name URI last path segment.
-                var fileNameString = fileNameUri.lastPathSegment
+                // Initialize the file name string from the file URI last path segment.
+                var fileNameString = fileUri.lastPathSegment
 
                 // Query the exact file name if the API >= 26.
                 if (Build.VERSION.SDK_INT >= 26) {
                     // Get a cursor from the content resolver.
-                    val contentResolverCursor = contentResolver.query(fileNameUri, null, null, null)!!
+                    val contentResolverCursor = contentResolver.query(fileUri, null, null, null)!!
 
                     // Move to the fist row.
                     contentResolverCursor.moveToFirst()
 
                     // Get the file name from the cursor.
-                    fileNameString = contentResolverCursor.getString(contentResolverCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
+                    fileNameString = contentResolverCursor.getString(contentResolverCursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
 
                     // Close the cursor.
                     contentResolverCursor.close()
@@ -118,9 +128,6 @@ class LogcatActivity : AppCompatActivity() {
             window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
         }
 
-        // Set the theme.
-        setTheme(R.style.PrivacyBrowser)
-
         // Run the default commands.
         super.onCreate(savedInstanceState)
 
@@ -278,4 +285,4 @@ class LogcatActivity : AppCompatActivity() {
         // Stop the swipe to refresh animation if it is displayed.
         swipeRefreshLayout.isRefreshing = false
     }
-}
\ No newline at end of file
+}