From 0cabf60dc4aa0ee34d569f66c866cc9b503910d6 Mon Sep 17 00:00:00 2001 From: albexk Date: Thu, 14 Dec 2023 18:00:58 +0300 Subject: [PATCH] Fixes and refactoring in file saving and import functions --- client/android/AndroidManifest.xml | 5 +- .../src/org/amnezia/vpn/AmneziaActivity.kt | 25 ++++---- .../org/amnezia/vpn/ImportConfigActivity.kt | 64 +++++++++++++++---- 3 files changed, 67 insertions(+), 27 deletions(-) diff --git a/client/android/AndroidManifest.xml b/client/android/AndroidManifest.xml index ca6ce99aa..7a362a8a8 100644 --- a/client/android/AndroidManifest.xml +++ b/client/android/AndroidManifest.xml @@ -15,8 +15,9 @@ - - + + + diff --git a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt index 44f03e882..92223453b 100644 --- a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt +++ b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt @@ -321,13 +321,9 @@ class AmneziaActivity : QtActivity() { // saving file private fun alterDocument(uri: Uri) { try { - applicationContext.contentResolver.openFileDescriptor(uri, "w")?.use { fd -> - FileOutputStream(fd.fileDescriptor).use { fos -> - fos.write(tmpFileContentToSave.toByteArray()) - } + contentResolver.openOutputStream(uri)?.use { os -> + os.bufferedWriter().use { it.write(tmpFileContentToSave) } } - } catch (e: FileNotFoundException) { - e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } @@ -363,16 +359,17 @@ class AmneziaActivity : QtActivity() { @Suppress("unused") fun saveFile(fileName: String, data: String) { Log.v(TAG, "Save file $fileName") - // todo: refactor - tmpFileContentToSave = data + mainScope.launch { + tmpFileContentToSave = data - val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = "text/*" - putExtra(Intent.EXTRA_TITLE, fileName) + Intent(Intent.ACTION_CREATE_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "text/*" + putExtra(Intent.EXTRA_TITLE, fileName) + }.also { + startActivityForResult(it, CREATE_FILE_ACTION_CODE) + } } - - startActivityForResult(intent, CREATE_FILE_ACTION_CODE) } @Suppress("unused") diff --git a/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt b/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt index 2eaad7319..4910d851f 100644 --- a/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt +++ b/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt @@ -1,17 +1,23 @@ package org.amnezia.vpn +import android.Manifest import android.content.Intent import android.content.Intent.ACTION_SEND import android.content.Intent.ACTION_VIEW import android.content.Intent.CATEGORY_DEFAULT import android.content.Intent.EXTRA_TEXT import android.content.Intent.FLAG_ACTIVITY_NEW_TASK +import android.content.pm.PackageManager import android.net.Uri import android.os.Build.VERSION import android.os.Build.VERSION_CODES import android.os.Bundle +import android.os.Process +import android.widget.Toast import androidx.activity.ComponentActivity +import androidx.activity.result.contract.ActivityResultContracts.RequestPermission import java.io.BufferedReader +import java.io.IOException import org.amnezia.vpn.util.Log private const val TAG = "ImportConfigActivity" @@ -38,8 +44,16 @@ class ImportConfigActivity : ComponentActivity() { ACTION_SEND -> { Log.v(TAG, "Process SEND action, type: ${intent.type}") when (intent.type) { - "application/octet-stream" -> - processStream(intent) + "application/octet-stream" -> { + intent.getUriCompat()?.let { uri -> + checkPermissions( + uri, + onSuccess = ::processUri, + onFail = ::finish + ) + } + return + } "text/plain" -> { intent.getStringExtra(EXTRA_TEXT)?.let(::startMainActivity) @@ -55,20 +69,49 @@ class ImportConfigActivity : ComponentActivity() { finish() } - private fun processStream(intent: Intent) { - getUriCompat(intent)?.let { uri -> - contentResolver.openInputStream(uri)?.use { - it.bufferedReader().use(BufferedReader::readText).let(::startMainActivity) - } + private fun checkPermissions(uri: Uri, onSuccess: (Uri) -> Unit, onFail: () -> Unit) { + if (checkUriReadPermission(uri) == PackageManager.PERMISSION_GRANTED) { + onSuccess(uri) + } else { + val requestPermissionLauncher = + registerForActivityResult(RequestPermission()) { isGranted -> + if (isGranted) onSuccess(uri) + else { + Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show() + onFail() + } + } + requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE) } } - private fun getUriCompat(intent: Intent): Uri? = + private fun checkUriReadPermission(uri: Uri) = checkUriPermission( + uri, + Manifest.permission.READ_EXTERNAL_STORAGE, + null, + Process.myPid(), + Process.myUid(), + Intent.FLAG_GRANT_READ_URI_PERMISSION + ) + + private fun processUri(uri: Uri) { + try { + contentResolver.openInputStream(uri)?.use { + it.bufferedReader().use(BufferedReader::readText).let(::startMainActivity) + } + } catch (e: IOException) { + e.printStackTrace() + } finally { + finish() + } + } + + private fun Intent.getUriCompat(): Uri? = if (VERSION.SDK_INT >= VERSION_CODES.TIRAMISU) { - intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java) + getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java) } else { @Suppress("DEPRECATION") - intent.getParcelableExtra(Intent.EXTRA_STREAM) + getParcelableExtra(Intent.EXTRA_STREAM) } private fun startMainActivity(config: String) { @@ -83,6 +126,5 @@ class ImportConfigActivity : ComponentActivity() { startActivity(it) } } - finish() } }