DownloadsFileSaver: initialize callback in constructor, not on the fly

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2020-10-02 12:11:48 +02:00
parent 1dc74b171c
commit a31f0cf788
3 changed files with 22 additions and 9 deletions

View File

@ -147,12 +147,14 @@ class LogViewerActivity : AppCompatActivity() {
} }
} }
private val downloadsFileSaver = DownloadsFileSaver(this)
private suspend fun saveLog() { private suspend fun saveLog() {
var exception: Throwable? = null var exception: Throwable? = null
var outputFile: DownloadsFileSaver.DownloadsFile? = null var outputFile: DownloadsFileSaver.DownloadsFile? = null
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
try { try {
outputFile = DownloadsFileSaver.save(this@LogViewerActivity, "wireguard-log.txt", "text/plain", true) outputFile = downloadsFileSaver.save("wireguard-log.txt", "text/plain", true)
outputFile?.outputStream?.write(rawLogLines.toString().toByteArray(Charsets.UTF_8)) outputFile?.outputStream?.write(rawLogLines.toString().toByteArray(Charsets.UTF_8))
} catch (e: Throwable) { } catch (e: Throwable) {
outputFile?.delete() outputFile?.delete()

View File

@ -32,6 +32,8 @@ import java.util.zip.ZipOutputStream
*/ */
class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) { class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
private var exportedFilePath: String? = null private var exportedFilePath: String? = null
private val downloadsFileSaver = DownloadsFileSaver(activity)
private fun exportZip() { private fun exportZip() {
lifecycleScope.launch { lifecycleScope.launch {
val tunnels = Application.getTunnelManager().getTunnels() val tunnels = Application.getTunnelManager().getTunnels()
@ -41,7 +43,7 @@ class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference
if (configs.isEmpty()) { if (configs.isEmpty()) {
throw IllegalArgumentException(context.getString(R.string.no_tunnels_error)) throw IllegalArgumentException(context.getString(R.string.no_tunnels_error))
} }
val outputFile = DownloadsFileSaver.save(activity, "wireguard-export.zip", "application/zip", true) val outputFile = downloadsFileSaver.save("wireguard-export.zip", "application/zip", true)
if (outputFile == null) { if (outputFile == null) {
withContext(Dispatchers.Main.immediate) { withContext(Dispatchers.Main.immediate) {
isEnabled = true isEnabled = true

View File

@ -14,6 +14,7 @@ import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.MediaStore.MediaColumns import android.provider.MediaStore.MediaColumns
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.wireguard.android.R import com.wireguard.android.R
@ -25,9 +26,18 @@ import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
import java.io.OutputStream import java.io.OutputStream
object DownloadsFileSaver { class DownloadsFileSaver(private val context: ComponentActivity) {
@Throws(Exception::class) private lateinit var activityResult: ActivityResultLauncher<String>
suspend fun save(context: ComponentActivity, name: String, mimeType: String?, overwriteExisting: Boolean) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { private lateinit var futureGrant: CompletableDeferred<Boolean>
init {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
futureGrant = CompletableDeferred()
activityResult = context.registerForActivityResult(ActivityResultContracts.RequestPermission()) { ret -> futureGrant.complete(ret) }
}
}
suspend fun save(name: String, mimeType: String?, overwriteExisting: Boolean) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val contentResolver = context.contentResolver val contentResolver = context.contentResolver
if (overwriteExisting) if (overwriteExisting)
@ -66,14 +76,13 @@ object DownloadsFileSaver {
} else { } else {
withContext(Dispatchers.Main.immediate) { withContext(Dispatchers.Main.immediate) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
val futureGrant = CompletableDeferred<Boolean>()
val activityResult = context.registerForActivityResult(ActivityResultContracts.RequestPermission(), futureGrant::complete)
activityResult.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) activityResult.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
val granted = futureGrant.await() val granted = futureGrant.await()
activityResult.unregister() if (!granted) {
if (!granted) futureGrant = CompletableDeferred()
return@withContext null return@withContext null
} }
}
@Suppress("DEPRECATION") val path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) @Suppress("DEPRECATION") val path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val file = File(path, name) val file = File(path, name)