Merge pull request #1432 from dvalter/fix/Android-R-import-export

Fix import/export for Android R+
This commit is contained in:
Tlaster 2021-04-28 22:41:50 -07:00 committed by GitHub
commit f1ff56b8f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 33 deletions

View File

@ -84,8 +84,8 @@ public class DataImportExportUtils implements Constants {
| FLAG_HOST_MAPPING | FLAG_KEYBOARD_SHORTCUTS | FLAG_FILTERS | FLAG_TABS; | FLAG_HOST_MAPPING | FLAG_KEYBOARD_SHORTCUTS | FLAG_FILTERS | FLAG_TABS;
@WorkerThread @WorkerThread
public static void exportData(final Context context, @NonNull final DocumentFile dst, final int flags) throws IOException { public static void exportData(final Context context, @NonNull final Uri dst, final int flags) throws IOException {
try (OutputStream fos = context.getContentResolver().openOutputStream(dst.getUri()); try (OutputStream fos = context.getContentResolver().openOutputStream(dst);
ZipOutputStream zos = new ZipOutputStream(fos)) { ZipOutputStream zos = new ZipOutputStream(fos)) {
if (hasFlag(flags, FLAG_PREFERENCES)) { if (hasFlag(flags, FLAG_PREFERENCES)) {
exportSharedPreferencesData(zos, context, SHARED_PREFERENCES_NAME, ENTRY_PREFERENCES, exportSharedPreferencesData(zos, context, SHARED_PREFERENCES_NAME, ENTRY_PREFERENCES,
@ -199,9 +199,9 @@ public class DataImportExportUtils implements Constants {
} }
} }
public static void importData(final Context context, final DocumentFile src, final int flags) throws IOException { public static void importData(final Context context, final Uri src, final int flags) throws IOException {
if (src == null) throw new FileNotFoundException(); if (src == null) throw new FileNotFoundException();
try (InputStream inputStream = context.getContentResolver().openInputStream(src.getUri()); try (InputStream inputStream = context.getContentResolver().openInputStream(src);
ZipInputStream zipInputStream = new ZipInputStream(inputStream) ZipInputStream zipInputStream = new ZipInputStream(inputStream)
) { ) {
ZipEntry entry; ZipEntry entry;

View File

@ -6,6 +6,7 @@ import android.net.Uri
import android.os.AsyncTask import android.os.AsyncTask
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.DocumentsContract
import android.util.Log import android.util.Log
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
@ -17,7 +18,6 @@ import org.mariotaku.twidere.fragment.DataExportImportTypeSelectorDialogFragment
import org.mariotaku.twidere.fragment.ProgressDialogFragment import org.mariotaku.twidere.fragment.ProgressDialogFragment
import org.mariotaku.twidere.util.DataImportExportUtils import org.mariotaku.twidere.util.DataImportExportUtils
import java.io.File import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -67,12 +67,7 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
return return
} }
if (task == null || task!!.status != AsyncTask.Status.RUNNING) { if (task == null || task!!.status != AsyncTask.Status.RUNNING) {
val folder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { task = ExportSettingsTask(this, path, flags)
DocumentFile.fromTreeUri(this, path)
} else {
DocumentFile.fromFile(File(path.path))
}
task = ExportSettingsTask(this, folder, flags)
task!!.execute() task!!.execute()
} }
} }
@ -85,30 +80,53 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (savedInstanceState == null) { if (savedInstanceState == null) {
val intent = Intent(this, FileSelectorActivity::class.java) val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
intent.action = IntentConstants.INTENT_ACTION_PICK_DIRECTORY val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
i
} else {
val i = Intent(this, FileSelectorActivity::class.java)
i.action = IntentConstants.INTENT_ACTION_PICK_DIRECTORY
i
}
startActivityForResult(intent, REQUEST_PICK_DIRECTORY) startActivityForResult(intent, REQUEST_PICK_DIRECTORY)
} }
} }
internal class ExportSettingsTask( internal class ExportSettingsTask(
private val activity: DataExportActivity, private val activity: DataExportActivity,
private val folder: DocumentFile?, private val folderUri: Uri?,
private val flags: Int private val flags: Int
) : AsyncTask<Any, Any, Boolean>() { ) : AsyncTask<Any, Any, Boolean>() {
override fun doInBackground(vararg params: Any): Boolean? { override fun doInBackground(vararg params: Any): Boolean? {
if (folder == null || !folder.isDirectory) return false if (folderUri == null) return false
val sdf = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.US) val sdf = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.US)
val fileName = String.format("Twidere_Settings_%s.zip", sdf.format(Date())) val fileName = String.format("Twidere_Settings_%s.zip", sdf.format(Date()))
val file = folder.findFile(fileName) ?: folder.createFile("application/zip", fileName)
?: return false
// val file = File(folder, fileName) // val file = File(folder, fileName)
// file.delete() // file.delete()
return try { return try {
DataImportExportUtils.exportData(activity, file, flags) val createdDocumentUri = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val docId = DocumentsContract.getTreeDocumentId(folderUri)
val dirUri = DocumentsContract.buildDocumentUriUsingTree(folderUri, docId)
DocumentsContract.createDocument(
activity.contentResolver,
dirUri,
"application/zip",
fileName)
} else {
val folder = DocumentFile.fromFile(File(folderUri.path!!))
val file = folder.findFile(fileName)
?: folder.createFile("application/zip", fileName) ?: return false
file.uri
})
?: return false
DataImportExportUtils.exportData(activity, createdDocumentUri, flags)
true true
} catch (e: IOException) { } catch (e: Throwable) {
Log.w(LOGTAG, e) Log.w(LOGTAG, e)
false false
} }

View File

@ -76,12 +76,7 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
return return
} }
if (importSettingsTask == null || importSettingsTask!!.status != AsyncTask.Status.RUNNING) { if (importSettingsTask == null || importSettingsTask!!.status != AsyncTask.Status.RUNNING) {
val file = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { importSettingsTask = ImportSettingsTask(this, path, flags)
DocumentFile.fromSingleUri(this, path)
} else {
DocumentFile.fromFile(File(path.path))
}
importSettingsTask = ImportSettingsTask(this, file, flags)
importSettingsTask!!.execute() importSettingsTask!!.execute()
} }
} }
@ -94,25 +89,28 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (savedInstanceState == null) { if (savedInstanceState == null) {
val intent = Intent(this, FileSelectorActivity::class.java) val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
intent.action = INTENT_ACTION_PICK_FILE val i = Intent(Intent.ACTION_OPEN_DOCUMENT)
i.type = "*/*"
i
} else {
val i = Intent(this, FileSelectorActivity::class.java)
i.action = INTENT_ACTION_PICK_FILE
i
}
startActivityForResult(intent, REQUEST_PICK_FILE) startActivityForResult(intent, REQUEST_PICK_FILE)
} }
} }
internal class ImportSettingsTask( internal class ImportSettingsTask(
private val activity: DataImportActivity, private val activity: DataImportActivity,
private val file: DocumentFile?, private val uri: Uri?,
private val flags: Int private val flags: Int
) : AsyncTask<Any, Any, Boolean>() { ) : AsyncTask<Any, Any, Boolean>() {
override fun doInBackground(vararg params: Any): Boolean? { override fun doInBackground(vararg params: Any): Boolean? {
if (file == null) {
return false
}
if (!file.isFile) return false
return try { return try {
DataImportExportUtils.importData(activity, file, flags) DataImportExportUtils.importData(activity, uri, flags)
true true
} catch (e: IOException) { } catch (e: IOException) {
Log.w(LOGTAG, e) Log.w(LOGTAG, e)