diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt index eb03b76da..29c58e8d3 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt @@ -62,7 +62,6 @@ import com.kunzisoft.keepass.view.hideByFading import com.kunzisoft.keepass.view.showActionErrorIfNeeded import com.kunzisoft.keepass.viewmodels.EntryViewModel import java.util.* -import kotlin.collections.HashMap class EntryActivity : DatabaseLockActivity() { @@ -84,8 +83,8 @@ class EntryActivity : DatabaseLockActivity() { private var mEntryLoaded = false private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null - private var mAttachmentsToDownload: HashMap = HashMap() private var mExternalFileHelper: ExternalFileHelper? = null + private var mAttachmentSelected: Attachment? = null private var mIcon: IconImage? = null private var mIconColor: Int = 0 @@ -133,6 +132,15 @@ class EntryActivity : DatabaseLockActivity() { // Init SAF manager mExternalFileHelper = ExternalFileHelper(this) + mExternalFileHelper?.buildCreateDocument { createdFileUri -> + mAttachmentSelected?.let { attachment -> + if (createdFileUri != null) { + mAttachmentFileBinderManager + ?.startDownloadAttachment(createdFileUri, attachment) + } + mAttachmentSelected = null + } + } // Init attachment service binder manager mAttachmentFileBinderManager = AttachmentFileBinderManager(this) @@ -209,9 +217,8 @@ class EntryActivity : DatabaseLockActivity() { } mEntryViewModel.attachmentSelected.observe(this) { attachmentSelected -> - mExternalFileHelper?.createDocument(attachmentSelected.name)?.let { requestCode -> - mAttachmentsToDownload[requestCode] = attachmentSelected - } + mAttachmentSelected = attachmentSelected + mExternalFileHelper?.createDocument(attachmentSelected.name) } mEntryViewModel.historySelected.observe(this) { historySelected -> @@ -299,15 +306,6 @@ class EntryActivity : DatabaseLockActivity() { mEntryViewModel.loadDatabase(mDatabase) } } - - mExternalFileHelper?.onCreateDocumentResult(requestCode, resultCode, data) { createdFileUri -> - if (createdFileUri != null) { - mAttachmentsToDownload[requestCode]?.let { attachmentToDownload -> - mAttachmentFileBinderManager - ?.startDownloadAttachment(createdFileUri, attachmentToDownload) - } - } - } } override fun onCreateOptionsMenu(menu: Menu): Boolean { diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt index 8726d61aa..be3825349 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt @@ -157,6 +157,21 @@ class EntryEditActivity : DatabaseLockActivity(), // To retrieve attachment mExternalFileHelper = ExternalFileHelper(this) + mExternalFileHelper?.buildOpenDocument { uri -> + uri?.let { attachmentToUploadUri -> + UriUtil.getFileData(this, attachmentToUploadUri)?.also { documentFile -> + documentFile.name?.let { fileName -> + if (documentFile.length() > MAX_WARNING_BINARY_FILE) { + FileTooBigDialogFragment.build(attachmentToUploadUri, fileName) + .show(supportFragmentManager, "fileTooBigFragment") + } else { + mEntryEditViewModel.buildNewAttachment(attachmentToUploadUri, fileName) + } + } + } + } + } + mAttachmentFileBinderManager = AttachmentFileBinderManager(this) // Verify the education views entryEditActivityEducation = EntryEditActivityEducation(this) @@ -487,21 +502,6 @@ class EntryEditActivity : DatabaseLockActivity(), IconPickerActivity.onActivityResult(requestCode, resultCode, data) { icon -> mEntryEditViewModel.selectIcon(icon) } - - mExternalFileHelper?.onOpenDocumentResult(requestCode, resultCode, data) { uri -> - uri?.let { attachmentToUploadUri -> - UriUtil.getFileData(this, attachmentToUploadUri)?.also { documentFile -> - documentFile.name?.let { fileName -> - if (documentFile.length() > MAX_WARNING_BINARY_FILE) { - FileTooBigDialogFragment.build(attachmentToUploadUri, fileName) - .show(supportFragmentManager, "fileTooBigFragment") - } else { - mEntryEditViewModel.buildNewAttachment(attachmentToUploadUri, fileName) - } - } - } - } - } } /** @@ -594,7 +594,7 @@ class EntryEditActivity : DatabaseLockActivity(), && entryEditActivityEducation.checkAndPerformedAttachmentEducation( attachmentView, { - mExternalFileHelper?.openDocument() + addNewAttachment() }, { performedNextEducation(entryEditActivityEducation) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt index f853485a6..446a9e127 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt @@ -116,6 +116,22 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(), // Open database button mExternalFileHelper = ExternalFileHelper(this) + mExternalFileHelper?.buildOpenDocument { uri -> + uri?.let { + launchPasswordActivityWithPath(uri) + } + } + mExternalFileHelper?.buildCreateDocument("application/x-keepass") { databaseFileCreatedUri -> + mDatabaseFileUri = databaseFileCreatedUri + if (mDatabaseFileUri != null) { + AssignMasterKeyDialogFragment.getInstance(true) + .show(supportFragmentManager, "passwordDialog") + } else { + val error = getString(R.string.error_create_database) + Snackbar.make(coordinatorLayout, error, Snackbar.LENGTH_LONG).asError().show() + Log.e(TAG, error) + } + } openDatabaseButtonView = findViewById(R.id.open_keyfile_button) openDatabaseButtonView?.setOpenDocumentClickListener(mExternalFileHelper) @@ -263,8 +279,9 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(), * Create a new file by calling the content provider */ private fun createNewFile() { - mExternalFileHelper?.createDocument( getString(R.string.database_file_name_default) + - getString(R.string.database_file_extension_default), "application/x-keepass") + mExternalFileHelper?.createDocument( + getString(R.string.database_file_name_default) + + getString(R.string.database_file_extension_default)) } private fun fileNoFoundAction(e: FileNotFoundException) { @@ -368,29 +385,6 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(), override fun onAssignKeyDialogNegativeClick(mainCredential: MainCredential) {} - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - - mExternalFileHelper?.onOpenDocumentResult(requestCode, resultCode, data) { uri -> - if (uri != null) { - launchPasswordActivityWithPath(uri) - } - } - - // Retrieve the created URI from the file manager - mExternalFileHelper?.onCreateDocumentResult(requestCode, resultCode, data) { databaseFileCreatedUri -> - mDatabaseFileUri = databaseFileCreatedUri - if (mDatabaseFileUri != null) { - AssignMasterKeyDialogFragment.getInstance(true) - .show(supportFragmentManager, "passwordDialog") - } else { - val error = getString(R.string.error_create_database) - Snackbar.make(coordinatorLayout, error, Snackbar.LENGTH_LONG).asError().show() - Log.e(TAG, error) - } - } - } - override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt index ff9e7694e..583c9bcac 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt @@ -82,6 +82,9 @@ class IconPickerActivity : DatabaseLockActivity() { coordinatorLayout = findViewById(R.id.icon_picker_coordinator) mExternalFileHelper = ExternalFileHelper(this) + mExternalFileHelper?.buildOpenDocument { uri -> + addCustomIcon(uri) + } uploadButton = findViewById(R.id.icon_picker_upload) @@ -309,14 +312,6 @@ class IconPickerActivity : DatabaseLockActivity() { ) } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - - mExternalFileHelper?.onOpenDocumentResult(requestCode, resultCode, data) { uri -> - addCustomIcon(uri) - } - } - private fun setResult() { setResult(Activity.RESULT_OK, Intent().apply { putExtra(EXTRA_ICON, mIconImage) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/PasswordActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/PasswordActivity.kt index a6f6c8999..07be10b5a 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/PasswordActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/PasswordActivity.kt @@ -148,6 +148,12 @@ class PasswordActivity : DatabaseModeActivity(), AdvancedUnlockFragment.BuilderL mRememberKeyFile = PreferencesUtil.rememberKeyFileLocations(this) mExternalFileHelper = ExternalFileHelper(this@PasswordActivity) + mExternalFileHelper?.buildOpenDocument { uri -> + if (uri != null) { + mDatabaseKeyFileUri = uri + populateKeyFileTextView(uri) + } + } keyFileSelectionView?.setOpenDocumentClickListener(mExternalFileHelper) passwordView?.setOnEditorActionListener(onEditorActionListener) @@ -727,25 +733,15 @@ class PasswordActivity : DatabaseModeActivity(), AdvancedUnlockFragment.BuilderL // To get device credential unlock result advancedUnlockFragment?.onActivityResult(requestCode, resultCode, data) - var keyFileResult = false - mExternalFileHelper?.let { - keyFileResult = it.onOpenDocumentResult(requestCode, resultCode, data) { uri -> - if (uri != null) { - mDatabaseKeyFileUri = uri - populateKeyFileTextView(uri) - } + // this block if not a key file response + // TODO advance unlock response + when (resultCode) { + DatabaseLockActivity.RESULT_EXIT_LOCK -> { + clearCredentialsViews() + closeDatabase() } - } - if (!keyFileResult) { - // this block if not a key file response - when (resultCode) { - DatabaseLockActivity.RESULT_EXIT_LOCK -> { - clearCredentialsViews() - closeDatabase() - } - Activity.RESULT_CANCELED -> { - clearCredentialsViews() - } + Activity.RESULT_CANCELED -> { + clearCredentialsViews() } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/AssignMasterKeyDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/AssignMasterKeyDialogFragment.kt index 13c3a9d60..b976f1f54 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/AssignMasterKeyDialogFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/AssignMasterKeyDialogFragment.kt @@ -22,7 +22,6 @@ package com.kunzisoft.keepass.activities.dialogs import android.app.Dialog import android.content.Context import android.content.DialogInterface -import android.content.Intent import android.net.Uri import android.os.Bundle import android.text.Editable @@ -133,6 +132,18 @@ class AssignMasterKeyDialogFragment : DatabaseDialogFragment() { keyFileSelectionView = rootView?.findViewById(R.id.keyfile_selection) mExternalFileHelper = ExternalFileHelper(this) + mExternalFileHelper?.buildOpenDocument { uri -> + uri?.let { pathUri -> + UriUtil.getFileData(requireContext(), uri)?.length()?.let { lengthFile -> + keyFileSelectionView?.error = null + keyFileCheckBox?.isChecked = true + keyFileSelectionView?.uri = pathUri + if (lengthFile <= 0L) { + showEmptyKeyFileConfirmationDialog() + } + } + } + } keyFileSelectionView?.setOpenDocumentClickListener(mExternalFileHelper) val dialog = builder.create() @@ -208,7 +219,11 @@ class AssignMasterKeyDialogFragment : DatabaseDialogFragment() { passwordRepeatTextInputLayout?.error = getString(R.string.error_pass_match) } - if (mMasterPassword == null || mMasterPassword!!.isEmpty()) { + if ((mMasterPassword == null + || mMasterPassword!!.isEmpty()) + && (keyFileCheckBox == null + || !keyFileCheckBox!!.isChecked + || keyFileSelectionView?.uri == null)) { error = true showEmptyPasswordConfirmationDialog() } @@ -282,23 +297,6 @@ class AssignMasterKeyDialogFragment : DatabaseDialogFragment() { } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - - mExternalFileHelper?.onOpenDocumentResult(requestCode, resultCode, data) { uri -> - uri?.let { pathUri -> - UriUtil.getFileData(requireContext(), uri)?.length()?.let { lengthFile -> - keyFileSelectionView?.error = null - keyFileCheckBox?.isChecked = true - keyFileSelectionView?.uri = pathUri - if (lengthFile <= 0L) { - showEmptyKeyFileConfirmationDialog() - } - } - } - } - } - companion object { private const val ALLOW_NO_MASTER_KEY_ARG = "ALLOW_NO_MASTER_KEY_ARG" diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/helpers/ExternalFileHelper.kt b/app/src/main/java/com/kunzisoft/keepass/activities/helpers/ExternalFileHelper.kt index 2792c35ef..d2467cda5 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/helpers/ExternalFileHelper.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/helpers/ExternalFileHelper.kt @@ -20,14 +20,16 @@ package com.kunzisoft.keepass.activities.helpers import android.annotation.SuppressLint -import android.app.Activity.RESULT_OK +import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Build import android.util.Log import android.view.View -import androidx.annotation.RequiresApi +import androidx.activity.result.ActivityResultCallback +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import com.kunzisoft.keepass.activities.dialogs.FileManagerDialogFragment @@ -38,6 +40,10 @@ class ExternalFileHelper { private var activity: FragmentActivity? = null private var fragment: Fragment? = null + private var getContentResultLauncher: ActivityResultLauncher? = null + private var openDocumentResultLauncher: ActivityResultLauncher>? = null + private var createDocumentResultLauncher: ActivityResultLauncher? = null + constructor(context: FragmentActivity) { this.activity = context this.fragment = null @@ -48,94 +54,82 @@ class ExternalFileHelper { this.fragment = context } + fun buildOpenDocument(typeString: String = "*/*", + onFileSelected: ((uri: Uri?) -> Unit)?) { + + val resultCallback = ActivityResultCallback { result -> + result?.let { uri -> + UriUtil.takeUriPermission(activity?.contentResolver, uri) + onFileSelected?.invoke(uri) + } + } + + getContentResultLauncher = if (fragment != null) { + fragment?.registerForActivityResult( + GetContent(), + resultCallback + ) + } else { + activity?.registerForActivityResult( + GetContent(), + resultCallback + ) + } + + openDocumentResultLauncher = if (fragment != null) { + fragment?.registerForActivityResult( + OpenDocument(), + resultCallback + ) + } else { + activity?.registerForActivityResult( + OpenDocument(), + resultCallback + ) + } + } + + fun buildCreateDocument(typeString: String = "application/octet-stream", + onFileCreated: (fileCreated: Uri?)->Unit) { + + val resultCallback = ActivityResultCallback { result -> + onFileCreated.invoke(result) + } + + createDocumentResultLauncher = if (fragment != null) { + fragment?.registerForActivityResult( + CreateDocument(typeString), + resultCallback + ) + } else { + activity?.registerForActivityResult( + CreateDocument(typeString), + resultCallback + ) + } + } + fun openDocument(getContent: Boolean = false, typeString: String = "*/*") { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - try { - if (getContent) { - openActivityWithActionGetContent(typeString) - } else { - openActivityWithActionOpenDocument(typeString) - } - } catch (e: Exception) { - Log.e(TAG, "Unable to open document", e) - showFileManagerDialogFragment() + try { + if (getContent) { + getContentResultLauncher?.launch(typeString) + } else { + openDocumentResultLauncher?.launch(arrayOf(typeString)) } - } else { + } catch (e: Exception) { + Log.e(TAG, "Unable to open document", e) showFileManagerDialogFragment() } } - @RequiresApi(Build.VERSION_CODES.KITKAT) - private fun openActivityWithActionOpenDocument(typeString: String) { - val intentOpenDocument = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = typeString - addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) - } - addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + fun createDocument(titleString: String) { + try { + createDocumentResultLauncher?.launch(titleString) + } catch (e: Exception) { + Log.e(TAG, "Unable to create document", e) + showFileManagerDialogFragment() } - if (fragment != null) - fragment?.startActivityForResult(intentOpenDocument, OPEN_DOC) - else - activity?.startActivityForResult(intentOpenDocument, OPEN_DOC) - } - - @RequiresApi(Build.VERSION_CODES.KITKAT) - private fun openActivityWithActionGetContent(typeString: String) { - val intentGetContent = Intent(Intent.ACTION_GET_CONTENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = typeString - addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) - } - addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - } - if (fragment != null) - fragment?.startActivityForResult(intentGetContent, GET_CONTENT) - else - activity?.startActivityForResult(intentGetContent, GET_CONTENT) - } - - /** - * To use in onActivityResultCallback in Fragment or Activity - * @param onFileSelected Callback retrieve from data - * @return true if requestCode was captured, false elsewhere - */ - fun onOpenDocumentResult(requestCode: Int, resultCode: Int, data: Intent?, - onFileSelected: ((uri: Uri?) -> Unit)?): Boolean { - - when (requestCode) { - FILE_BROWSE -> { - if (resultCode == RESULT_OK) { - val filename = data?.dataString - var keyUri: Uri? = null - if (filename != null) { - keyUri = UriUtil.parse(filename) - } - onFileSelected?.invoke(keyUri) - } - return true - } - GET_CONTENT, OPEN_DOC -> { - if (resultCode == RESULT_OK) { - if (data != null) { - val uri = data.data - if (uri != null) { - UriUtil.takeUriPermission(activity?.contentResolver, uri) - onFileSelected?.invoke(uri) - } - } - } - return true - } - } - return false } /** @@ -155,62 +149,50 @@ class ExternalFileHelper { } } - fun createDocument(titleString: String, - typeString: String = "application/octet-stream"): Int? { - val idCode = getUnusedCreateFileRequestCode() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - try { - val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = typeString - putExtra(Intent.EXTRA_TITLE, titleString) + class OpenDocument : ActivityResultContracts.OpenDocument() { + @SuppressLint("InlinedApi") + override fun createIntent(context: Context, input: Array): Intent { + return super.createIntent(context, input).apply { + addCategory(Intent.CATEGORY_OPENABLE) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) } - if (fragment != null) - fragment?.startActivityForResult(intent, idCode) - else - activity?.startActivityForResult(intent, idCode) - return idCode - } catch (e: Exception) { - Log.e(TAG, "Unable to create document", e) - showFileManagerDialogFragment() + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) } - } else { - showFileManagerDialogFragment() } - return null } - /** - * To use in onActivityResultCallback in Fragment or Activity - * @param onFileCreated Callback retrieve from data - * @return true if requestCode was captured, false elsewhere - */ - fun onCreateDocumentResult(requestCode: Int, resultCode: Int, data: Intent?, - onFileCreated: (fileCreated: Uri?)->Unit) { - // Retrieve the created URI from the file manager - if (fileRequestCodes.contains(requestCode) && resultCode == RESULT_OK) { - onFileCreated.invoke(data?.data) - fileRequestCodes.remove(requestCode) + class GetContent : ActivityResultContracts.GetContent() { + @SuppressLint("InlinedApi") + override fun createIntent(context: Context, input: String): Intent { + return super.createIntent(context, input).apply { + addCategory(Intent.CATEGORY_OPENABLE) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) + } + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + } } } + class CreateDocument(private val typeString: String) : ActivityResultContracts.CreateDocument() { + override fun createIntent(context: Context, input: String): Intent { + return super.createIntent(context, input).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = typeString + } + } + } + + companion object { private const val TAG = "OpenFileHelper" - private const val GET_CONTENT = 25745 - private const val OPEN_DOC = 25845 - private const val FILE_BROWSE = 25645 - - private var CREATE_FILE_REQUEST_CODE_DEFAULT = 3853 - private var fileRequestCodes = ArrayList() - - private fun getUnusedCreateFileRequestCode(): Int { - val newCreateFileRequestCode = CREATE_FILE_REQUEST_CODE_DEFAULT++ - fileRequestCodes.add(newCreateFileRequestCode) - return newCreateFileRequestCode - } - @SuppressLint("InlinedApi") fun allowCreateDocumentByStorageAccessFramework(packageManager: PackageManager, typeString: String = "application/octet-stream"): Boolean { @@ -231,7 +213,7 @@ class ExternalFileHelper { fun View.setOpenDocumentClickListener(externalFileHelper: ExternalFileHelper?) { externalFileHelper?.let { fileHelper -> setOnClickListener { - fileHelper.openDocument() + fileHelper.openDocument(false) } setOnLongClickListener { fileHelper.openDocument(true) diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/SettingsActivity.kt b/app/src/main/java/com/kunzisoft/keepass/settings/SettingsActivity.kt index 2baa56008..a9197d910 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/SettingsActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/settings/SettingsActivity.kt @@ -49,7 +49,6 @@ open class SettingsActivity private var backupManager: BackupManager? = null private var mExternalFileHelper: ExternalFileHelper? = null - private var appPropertiesFileCreationRequestCode: Int? = null private var coordinatorLayout: CoordinatorLayout? = null private var toolbar: Toolbar? = null @@ -64,6 +63,41 @@ open class SettingsActivity toolbar = findViewById(R.id.toolbar) mExternalFileHelper = ExternalFileHelper(this) + mExternalFileHelper?.buildOpenDocument { selectedFileUri -> + // Import app properties result + try { + selectedFileUri?.let { uri -> + val appProperties = Properties() + contentResolver?.openInputStream(uri)?.use { inputStream -> + appProperties.load(inputStream) + } + PreferencesUtil.setAppProperties(this, appProperties) + + // Restart the current activity + reloadActivity() + Toast.makeText(this, R.string.success_import_app_properties, Toast.LENGTH_LONG).show() + } + } catch (e: Exception) { + Toast.makeText(this, R.string.error_import_app_properties, Toast.LENGTH_LONG).show() + Log.e(TAG, "Unable to import app properties", e) + } + } + mExternalFileHelper?.buildCreateDocument { createdFileUri -> + // Export app properties result + try { + createdFileUri?.let { uri -> + contentResolver?.openOutputStream(uri)?.use { outputStream -> + PreferencesUtil + .getAppProperties(this) + .store(outputStream, getString(R.string.description_app_properties)) + } + Toast.makeText(this, R.string.success_export_app_properties, Toast.LENGTH_LONG).show() + } + } catch (e: Exception) { + Toast.makeText(this, R.string.error_export_app_properties, Toast.LENGTH_LONG).show() + Log.e(DatabaseLockActivity.TAG, "Unable to export app properties", e) + } + } if (savedInstanceState?.getString(TITLE_KEY).isNullOrEmpty()) toolbar?.setTitle(R.string.settings) @@ -217,54 +251,10 @@ open class SettingsActivity } fun exportAppProperties() { - appPropertiesFileCreationRequestCode = mExternalFileHelper?.createDocument(getString(R.string.app_properties_file_name, + mExternalFileHelper?.createDocument(getString(R.string.app_properties_file_name, DateTime.now().toLocalDateTime().toString("yyyy-MM-dd'_'HH-mm"))) } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - - // Import app properties result - try { - mExternalFileHelper?.onOpenDocumentResult(requestCode, resultCode, data) { selectedFileUri -> - selectedFileUri?.let { uri -> - val appProperties = Properties() - contentResolver?.openInputStream(uri)?.use { inputStream -> - appProperties.load(inputStream) - } - PreferencesUtil.setAppProperties(this, appProperties) - - // Restart the current activity - reloadActivity() - Toast.makeText(this, R.string.success_import_app_properties, Toast.LENGTH_LONG).show() - } - } - } catch (e: Exception) { - Toast.makeText(this, R.string.error_import_app_properties, Toast.LENGTH_LONG).show() - Log.e(TAG, "Unable to import app properties", e) - } - - // Export app properties result - try { - if (requestCode == appPropertiesFileCreationRequestCode) { - mExternalFileHelper?.onCreateDocumentResult(requestCode, resultCode, data) { createdFileUri -> - createdFileUri?.let { uri -> - contentResolver?.openOutputStream(uri)?.use { outputStream -> - PreferencesUtil - .getAppProperties(this) - .store(outputStream, getString(R.string.description_app_properties)) - } - Toast.makeText(this, R.string.success_export_app_properties, Toast.LENGTH_LONG).show() - } - } - appPropertiesFileCreationRequestCode = null - } - } catch (e: Exception) { - Toast.makeText(this, R.string.error_export_app_properties, Toast.LENGTH_LONG).show() - Log.e(DatabaseLockActivity.TAG, "Unable to export app properties", e) - } - } - override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) diff --git a/app/src/main/java/com/kunzisoft/keepass/view/KeyFileSelectionView.kt b/app/src/main/java/com/kunzisoft/keepass/view/KeyFileSelectionView.kt index 3bf85978a..182623ac7 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/KeyFileSelectionView.kt +++ b/app/src/main/java/com/kunzisoft/keepass/view/KeyFileSelectionView.kt @@ -2,6 +2,7 @@ package com.kunzisoft.keepass.view import android.content.Context import android.net.Uri +import android.os.Parcelable import android.util.AttributeSet import android.view.LayoutInflater import android.widget.TextView @@ -9,6 +10,9 @@ import androidx.constraintlayout.widget.ConstraintLayout import com.google.android.material.textfield.TextInputLayout import com.kunzisoft.keepass.R import com.kunzisoft.keepass.utils.UriUtil +import android.os.Parcel +import android.os.Parcelable.Creator + class KeyFileSelectionView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, @@ -54,4 +58,45 @@ class KeyFileSelectionView @JvmOverloads constructor(context: Context, UriUtil.getFileData(context, value)?.name ?: value.path } ?: "" } + + override fun onSaveInstanceState(): Parcelable { + val superState = super.onSaveInstanceState() + val saveState = SavedState(superState) + saveState.mUri = this.mUri + return saveState + } + + override fun onRestoreInstanceState(state: Parcelable?) { + if (state !is SavedState) { + super.onRestoreInstanceState(state) + return + } + super.onRestoreInstanceState(state.superState) + this.mUri = state.mUri + } + + internal class SavedState : BaseSavedState { + var mUri: Uri? = null + + constructor(superState: Parcelable?) : super(superState) {} + + private constructor(parcel: Parcel) : super(parcel) { + mUri = parcel.readParcelable(Uri::class.java.classLoader) + } + + override fun writeToParcel(out: Parcel, flags: Int) { + super.writeToParcel(out, flags) + out.writeParcelable(mUri, flags) + } + + companion object CREATOR : Creator { + override fun createFromParcel(parcel: Parcel): SavedState { + return SavedState(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } } \ No newline at end of file