mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Better UriUtil methods
This commit is contained in:
@@ -21,7 +21,6 @@ package com.kunzisoft.keepass.activities
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
@@ -348,7 +347,7 @@ class EntryActivity : LockingHideActivity() {
|
||||
{
|
||||
// Open Keepass doc to create field references
|
||||
startActivity(Intent(Intent.ACTION_VIEW,
|
||||
Uri.parse(getString(R.string.field_references_url))))
|
||||
UriUtil.parse(getString(R.string.field_references_url))))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,13 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
if (fileName.isEmpty())
|
||||
fileName = it
|
||||
}
|
||||
launchPasswordActivityWithPath(fileName)
|
||||
UriUtil.parse(fileName)?.let { fileNameUri ->
|
||||
launchPasswordActivityWithPath(fileNameUri)
|
||||
} ?: run {
|
||||
Log.e(TAG, "Unable to open the database link")
|
||||
Snackbar.make(activity_file_selection_coordinator_layout, getString(R.string.error_can_not_handle_uri), Snackbar.LENGTH_LONG).asError().show()
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
// Create button
|
||||
@@ -147,10 +153,9 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
mOpenFileHelper = OpenFileHelper(this)
|
||||
browseButtonView = findViewById(R.id.browse_button)
|
||||
browseButtonView?.setOnClickListener(mOpenFileHelper!!.getOpenFileOnClickViewListener {
|
||||
Uri.parse("file://" + openFileNameView!!.text.toString())
|
||||
UriUtil.parse(openFileNameView?.text?.toString())
|
||||
})
|
||||
|
||||
|
||||
// History list
|
||||
val fileDatabaseHistoryRecyclerView = findViewById<RecyclerView>(R.id.file_list)
|
||||
fileDatabaseHistoryRecyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
|
||||
@@ -159,9 +164,11 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
// Construct adapter with listeners
|
||||
mAdapterDatabaseHistory = FileDatabaseHistoryAdapter(this)
|
||||
mAdapterDatabaseHistory?.setOnFileDatabaseHistoryOpenListener { fileDatabaseHistoryEntityToOpen ->
|
||||
UriUtil.parse(fileDatabaseHistoryEntityToOpen.databaseUri)?.let { databaseFileUri ->
|
||||
launchPasswordActivity(
|
||||
fileDatabaseHistoryEntityToOpen.databaseUri,
|
||||
fileDatabaseHistoryEntityToOpen.keyFileUri)
|
||||
databaseFileUri,
|
||||
UriUtil.parse(fileDatabaseHistoryEntityToOpen.keyFileUri))
|
||||
}
|
||||
updateFileListVisibility()
|
||||
}
|
||||
mAdapterDatabaseHistory?.setOnFileDatabaseHistoryDeleteListener { fileDatabaseHistoryToDelete ->
|
||||
@@ -186,14 +193,12 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
&& savedInstanceState.containsKey(EXTRA_STAY)
|
||||
&& savedInstanceState.getBoolean(EXTRA_STAY, false))) {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val fileName = prefs.getString(PasswordActivity.KEY_DEFAULT_FILENAME, "")
|
||||
val databasePath = prefs.getString(PasswordActivity.KEY_DEFAULT_DATABASE_PATH, "")
|
||||
|
||||
try {
|
||||
UriUtil.verifyFilePath(fileName) { path ->
|
||||
launchPasswordActivityWithPath(path)
|
||||
}
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.e(TAG, "Unable to launch Password Activity", e)
|
||||
UriUtil.parse(databasePath)?.let { databaseFileUri ->
|
||||
launchPasswordActivityWithPath(databaseFileUri)
|
||||
} ?: run {
|
||||
Log.e(TAG, "Unable to launch Password Activity")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,12 +234,12 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
Log.e(TAG, error, e)
|
||||
}
|
||||
|
||||
private fun launchPasswordActivity(fileName: String, keyFile: String?) {
|
||||
private fun launchPasswordActivity(databaseUri: Uri, keyFile: Uri?) {
|
||||
EntrySelectionHelper.doEntrySelectionAction(intent,
|
||||
{
|
||||
try {
|
||||
PasswordActivity.launch(this@FileDatabaseSelectActivity,
|
||||
fileName, keyFile)
|
||||
databaseUri, keyFile)
|
||||
} catch (e: FileNotFoundException) {
|
||||
fileNoFoundAction(e)
|
||||
}
|
||||
@@ -242,7 +247,7 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
{
|
||||
try {
|
||||
PasswordActivity.launchForKeyboardResult(this@FileDatabaseSelectActivity,
|
||||
fileName, keyFile)
|
||||
databaseUri, keyFile)
|
||||
finish()
|
||||
} catch (e: FileNotFoundException) {
|
||||
fileNoFoundAction(e)
|
||||
@@ -252,7 +257,7 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
try {
|
||||
PasswordActivity.launchForAutofillResult(this@FileDatabaseSelectActivity,
|
||||
fileName, keyFile,
|
||||
databaseUri, keyFile,
|
||||
assistStructure)
|
||||
} catch (e: FileNotFoundException) {
|
||||
fileNoFoundAction(e)
|
||||
@@ -262,8 +267,8 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
})
|
||||
}
|
||||
|
||||
private fun launchPasswordActivityWithPath(path: String) {
|
||||
launchPasswordActivity(path, "")
|
||||
private fun launchPasswordActivityWithPath(databaseUri: Uri) {
|
||||
launchPasswordActivity(databaseUri, null)
|
||||
// Delete flickering for kitkat <=
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
|
||||
overridePendingTransition(0, 0)
|
||||
@@ -323,7 +328,7 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
keyFileChecked: Boolean, keyFile: Uri?) {
|
||||
|
||||
try {
|
||||
UriUtil.parseUriFile(mDatabaseFileUri)?.let { databaseUri ->
|
||||
mDatabaseFileUri?.let { databaseUri ->
|
||||
|
||||
// Create the new database
|
||||
ProgressDialogThread(this@FileDatabaseSelectActivity,
|
||||
@@ -388,7 +393,7 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
) { uri ->
|
||||
if (uri != null) {
|
||||
if (PreferencesUtil.autoOpenSelectedFile(this@FileDatabaseSelectActivity)) {
|
||||
launchPasswordActivityWithPath(uri.toString())
|
||||
launchPasswordActivityWithPath(uri)
|
||||
} else {
|
||||
fileSelectExpandableLayout?.expand(false)
|
||||
openFileNameView?.setText(uri.toString())
|
||||
|
||||
@@ -46,7 +46,6 @@ import androidx.biometric.BiometricManager
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.FingerPrintExplanationDialog
|
||||
import com.kunzisoft.keepass.activities.dialogs.PasswordEncodingDialogFragment
|
||||
import com.kunzisoft.keepass.utils.ClipDataCompat
|
||||
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
||||
import com.kunzisoft.keepass.activities.helpers.OpenFileHelper
|
||||
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
||||
@@ -70,7 +69,6 @@ import com.kunzisoft.keepass.view.AdvancedUnlockInfoView
|
||||
import com.kunzisoft.keepass.view.asError
|
||||
import kotlinx.android.synthetic.main.activity_password.*
|
||||
import java.io.FileNotFoundException
|
||||
import java.lang.Exception
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class PasswordActivity : StylishActivity() {
|
||||
@@ -196,21 +194,16 @@ class PasswordActivity : StylishActivity() {
|
||||
|
||||
val databaseUriRetrieve = intent.data
|
||||
// Stop activity here if we can't verify database URI
|
||||
try {
|
||||
UriUtil.verifyFileUri(databaseUriRetrieve)
|
||||
} catch (e : Exception) {
|
||||
Log.e(TAG, "File URI not validate", e)
|
||||
Toast.makeText(this@PasswordActivity, e.message, Toast.LENGTH_LONG).show()
|
||||
if (!UriUtil.verifyFileUri(databaseUriRetrieve)) {
|
||||
Log.e(TAG, "File URI not validate")
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
databaseUri = databaseUriRetrieve
|
||||
keyFileUri = ClipDataCompat.getUriFromIntent(intent, KEY_KEYFILE)
|
||||
keyFileUri = UriUtil.getUriFromIntent(intent, KEY_KEYFILE)
|
||||
|
||||
} else {
|
||||
databaseUri = UriUtil.parseUriFile(intent.getStringExtra(KEY_FILENAME))
|
||||
keyFileUri = UriUtil.parseUriFile(intent.getStringExtra(KEY_KEYFILE))
|
||||
databaseUri = intent.getParcelableExtra(KEY_FILENAME)
|
||||
keyFileUri = intent.getParcelableExtra(KEY_KEYFILE)
|
||||
}
|
||||
|
||||
// Post init uri with KeyFile if needed
|
||||
@@ -245,15 +238,17 @@ class PasswordActivity : StylishActivity() {
|
||||
|
||||
// Define listeners for default database checkbox and validate button
|
||||
checkboxDefaultDatabaseView?.setOnCheckedChangeListener { _, isChecked ->
|
||||
var newDefaultFileName = ""
|
||||
var newDefaultFileName: Uri? = null
|
||||
if (isChecked) {
|
||||
newDefaultFileName = databaseFileUri?.toString() ?: newDefaultFileName
|
||||
newDefaultFileName = databaseFileUri ?: newDefaultFileName
|
||||
}
|
||||
|
||||
newDefaultFileName?.let {
|
||||
prefs?.edit()?.apply {
|
||||
putString(KEY_DEFAULT_FILENAME, newDefaultFileName)
|
||||
putString(KEY_DEFAULT_DATABASE_PATH, newDefaultFileName.toString())
|
||||
apply()
|
||||
}
|
||||
}
|
||||
|
||||
val backupManager = BackupManager(this@PasswordActivity)
|
||||
backupManager.dataChanged()
|
||||
@@ -261,10 +256,10 @@ class PasswordActivity : StylishActivity() {
|
||||
confirmButtonView?.setOnClickListener { verifyCheckboxesAndLoadDatabase() }
|
||||
|
||||
// Retrieve settings for default database
|
||||
val defaultFilename = prefs?.getString(KEY_DEFAULT_FILENAME, "")
|
||||
val defaultFilename = prefs?.getString(KEY_DEFAULT_DATABASE_PATH, "")
|
||||
if (databaseFileUri != null
|
||||
&& databaseFileUri.path != null && databaseFileUri.path!!.isNotEmpty()
|
||||
&& databaseFileUri == UriUtil.parseUriFile(defaultFilename)) {
|
||||
&& databaseFileUri == UriUtil.parse(defaultFilename)) {
|
||||
checkboxDefaultDatabaseView?.isChecked = true
|
||||
}
|
||||
|
||||
@@ -388,7 +383,7 @@ class PasswordActivity : StylishActivity() {
|
||||
|
||||
private fun verifyCheckboxesAndLoadDatabase(cipherDatabaseEntity: CipherDatabaseEntity? = null) {
|
||||
val password: String? = passwordView?.text?.toString()
|
||||
val keyFile: Uri? = UriUtil.parseUriFile(keyFileView?.text?.toString())
|
||||
val keyFile: Uri? = UriUtil.parse(keyFileView?.text?.toString())
|
||||
verifyCheckboxesAndLoadDatabase(password, keyFile, cipherDatabaseEntity)
|
||||
}
|
||||
|
||||
@@ -401,7 +396,7 @@ class PasswordActivity : StylishActivity() {
|
||||
}
|
||||
|
||||
private fun verifyKeyFileCheckboxAndLoadDatabase(password: String?) {
|
||||
val keyFile: Uri? = UriUtil.parseUriFile(keyFileView?.text?.toString())
|
||||
val keyFile: Uri? = UriUtil.parse(keyFileView?.text?.toString())
|
||||
val keyFileUri = if (checkboxKeyFileView?.isChecked != true) null else keyFile
|
||||
loadDatabase(password, keyFileUri)
|
||||
}
|
||||
@@ -632,7 +627,7 @@ class PasswordActivity : StylishActivity() {
|
||||
|
||||
private val TAG = PasswordActivity::class.java.name
|
||||
|
||||
const val KEY_DEFAULT_FILENAME = "defaultFileName"
|
||||
const val KEY_DEFAULT_DATABASE_PATH = "KEY_DEFAULT_DATABASE_PATH"
|
||||
|
||||
private const val KEY_FILENAME = "fileName"
|
||||
private const val KEY_KEYFILE = "keyFile"
|
||||
@@ -641,10 +636,10 @@ class PasswordActivity : StylishActivity() {
|
||||
private const val KEY_PASSWORD = "password"
|
||||
private const val KEY_LAUNCH_IMMEDIATELY = "launchImmediately"
|
||||
|
||||
private fun buildAndLaunchIntent(activity: Activity, fileName: String, keyFile: String?,
|
||||
private fun buildAndLaunchIntent(activity: Activity, databaseFile: Uri, keyFile: Uri?,
|
||||
intentBuildLauncher: (Intent) -> Unit) {
|
||||
val intent = Intent(activity, PasswordActivity::class.java)
|
||||
intent.putExtra(KEY_FILENAME, fileName)
|
||||
intent.putExtra(KEY_FILENAME, databaseFile)
|
||||
if (keyFile != null)
|
||||
intent.putExtra(KEY_KEYFILE, keyFile)
|
||||
intentBuildLauncher.invoke(intent)
|
||||
@@ -659,10 +654,9 @@ class PasswordActivity : StylishActivity() {
|
||||
@Throws(FileNotFoundException::class)
|
||||
fun launch(
|
||||
activity: Activity,
|
||||
fileName: String,
|
||||
keyFile: String?) {
|
||||
UriUtil.verifyFilePath(fileName)
|
||||
buildAndLaunchIntent(activity, fileName, keyFile) { intent ->
|
||||
databaseFile: Uri,
|
||||
keyFile: Uri?) {
|
||||
buildAndLaunchIntent(activity, databaseFile, keyFile) { intent ->
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
}
|
||||
@@ -676,11 +670,9 @@ class PasswordActivity : StylishActivity() {
|
||||
@Throws(FileNotFoundException::class)
|
||||
fun launchForKeyboardResult(
|
||||
activity: Activity,
|
||||
fileName: String,
|
||||
keyFile: String?) {
|
||||
UriUtil.verifyFilePath(fileName)
|
||||
|
||||
buildAndLaunchIntent(activity, fileName, keyFile) { intent ->
|
||||
databaseFile: Uri,
|
||||
keyFile: Uri?) {
|
||||
buildAndLaunchIntent(activity, databaseFile, keyFile) { intent ->
|
||||
EntrySelectionHelper.startActivityForEntrySelection(activity, intent)
|
||||
}
|
||||
}
|
||||
@@ -695,20 +687,18 @@ class PasswordActivity : StylishActivity() {
|
||||
@Throws(FileNotFoundException::class)
|
||||
fun launchForAutofillResult(
|
||||
activity: Activity,
|
||||
fileName: String,
|
||||
keyFile: String?,
|
||||
databaseFile: Uri,
|
||||
keyFile: Uri?,
|
||||
assistStructure: AssistStructure?) {
|
||||
UriUtil.verifyFilePath(fileName)
|
||||
|
||||
if (assistStructure != null) {
|
||||
buildAndLaunchIntent(activity, fileName, keyFile) { intent ->
|
||||
buildAndLaunchIntent(activity, databaseFile, keyFile) { intent ->
|
||||
AutofillHelper.startActivityForAutofillResult(
|
||||
activity,
|
||||
intent,
|
||||
assistStructure)
|
||||
}
|
||||
} else {
|
||||
launch(activity, fileName, keyFile)
|
||||
launch(activity, databaseFile, keyFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,13 +200,11 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
|
||||
var error = false
|
||||
if (keyFileCheckBox != null
|
||||
&& keyFileCheckBox!!.isChecked) {
|
||||
val keyFile = UriUtil.parseUriFile(keyFileView?.text?.toString())
|
||||
mKeyFile = keyFile
|
||||
|
||||
// Verify that a keyfile is set
|
||||
if (keyFile == null || keyFile.toString().isEmpty()) {
|
||||
UriUtil.parse(keyFileView?.text?.toString())?.let { uri ->
|
||||
mKeyFile = uri
|
||||
} ?: run {
|
||||
error = true
|
||||
// TODO better keyfile check
|
||||
keyFileTextInputLayout?.error = getString(R.string.error_nokeyfile)
|
||||
}
|
||||
}
|
||||
@@ -250,7 +248,7 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
|
||||
|
||||
mOpenFileHelper?.onActivityResultCallback(requestCode, resultCode, data
|
||||
) { uri ->
|
||||
UriUtil.parseUriFile(uri)?.let { pathUri ->
|
||||
uri?.let { pathUri ->
|
||||
keyFileCheckBox?.isChecked = true
|
||||
keyFileView?.text = pathUri.toString()
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class OpenFileHelper {
|
||||
this.fragment = context
|
||||
}
|
||||
|
||||
inner class OpenFileOnClickViewListener(private val dataUri: (() -> Uri)?) : View.OnClickListener {
|
||||
inner class OpenFileOnClickViewListener(private val dataUri: (() -> Uri?)?) : View.OnClickListener {
|
||||
|
||||
override fun onClick(v: View) {
|
||||
try {
|
||||
@@ -97,7 +97,7 @@ class OpenFileHelper {
|
||||
activity?.startActivityForResult(i, GET_CONTENT)
|
||||
}
|
||||
|
||||
fun getOpenFileOnClickViewListener(dataUri: () -> Uri): OpenFileOnClickViewListener {
|
||||
fun getOpenFileOnClickViewListener(dataUri: () -> Uri?): OpenFileOnClickViewListener {
|
||||
return OpenFileOnClickViewListener(dataUri)
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ class OpenFileHelper {
|
||||
val filename = data?.dataString
|
||||
var keyUri: Uri? = null
|
||||
if (filename != null) {
|
||||
keyUri = UriUtil.parseUriFile(filename)
|
||||
keyUri = UriUtil.parse(filename)
|
||||
}
|
||||
keyFileCallback?.invoke(keyUri)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package com.kunzisoft.keepass.adapters
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.util.TypedValue
|
||||
@@ -32,6 +31,7 @@ import android.widget.ViewSwitcher
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryEntity
|
||||
import com.kunzisoft.keepass.utils.FileDatabaseInfo
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
|
||||
class FileDatabaseHistoryAdapter(private val context: Context)
|
||||
: RecyclerView.Adapter<FileDatabaseHistoryAdapter.FileDatabaseHistoryViewHolder>() {
|
||||
@@ -80,7 +80,7 @@ class FileDatabaseHistoryAdapter(private val context: Context)
|
||||
holder.fileAlias.text = fileDatabaseInfo.retrieveDatabaseAlias(fileHistoryEntity.databaseAlias)
|
||||
|
||||
// File path
|
||||
holder.filePath.text = Uri.decode(fileDatabaseInfo.fileUri.toString())
|
||||
holder.filePath.text = UriUtil.decode(fileDatabaseInfo.fileUri?.toString())
|
||||
|
||||
holder.filePreciseInfoContainer.visibility = if (fileDatabaseInfo.found()) {
|
||||
// Modification
|
||||
|
||||
@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.app.database
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.kunzisoft.keepass.utils.SingletonHolderParameter
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
|
||||
class FileDatabaseHistoryAction(applicationContext: Context) {
|
||||
|
||||
@@ -51,7 +52,7 @@ class FileDatabaseHistoryAction(applicationContext: Context) {
|
||||
{
|
||||
it?.let { fileHistoryEntity ->
|
||||
fileHistoryEntity.keyFileUri?.let { keyFileUri ->
|
||||
keyFileUriResultListener.invoke(Uri.parse(keyFileUri))
|
||||
keyFileUriResultListener.invoke(UriUtil.parse(keyFileUri))
|
||||
}
|
||||
} ?: keyFileUriResultListener.invoke(null)
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ import com.kunzisoft.keepass.settings.preference.IconPackListPreference
|
||||
import com.kunzisoft.keepass.settings.preference.InputNumberPreference
|
||||
import com.kunzisoft.keepass.settings.preference.InputTextPreference
|
||||
import com.kunzisoft.keepass.settings.preferencedialogfragment.*
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
|
||||
class NestedSettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceClickListener {
|
||||
|
||||
@@ -177,6 +178,7 @@ class NestedSettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferen
|
||||
private fun startEnableService() {
|
||||
if (autofillManager != null && !autofillManager.hasEnabledAutofillServices()) {
|
||||
val intent = Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE)
|
||||
// TODO Autofill
|
||||
intent.data = Uri.parse("package:com.example.android.autofill.service")
|
||||
Log.d(javaClass.name, "enableService(): intent=$intent")
|
||||
startActivityForResult(intent, REQUEST_CODE_AUTOFILL)
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.utils;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ClipDataCompat {
|
||||
private static Method getClipDataFromIntent;
|
||||
private static Method getDescription;
|
||||
private static Method getItemCount;
|
||||
private static Method getLabel;
|
||||
private static Method getItemAt;
|
||||
private static Method getUri;
|
||||
|
||||
private static boolean initSucceded;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class clipData = Class.forName("android.content.ClipData");
|
||||
getDescription = clipData.getMethod("getDescription", (Class[])null);
|
||||
getItemCount = clipData.getMethod("getItemCount", (Class[])null);
|
||||
getItemAt = clipData.getMethod("getItemAt", new Class[]{int.class});
|
||||
Class clipDescription = Class.forName("android.content.ClipDescription");
|
||||
getLabel = clipDescription.getMethod("getLabel", (Class[])null);
|
||||
|
||||
Class clipDataItem = Class.forName("android.content.ClipData$Item");
|
||||
getUri = clipDataItem.getMethod("getUri", (Class[])null);
|
||||
|
||||
getClipDataFromIntent = Intent.class.getMethod("getClipData", (Class[])null);
|
||||
|
||||
initSucceded = true;
|
||||
} catch (Exception e) {
|
||||
initSucceded = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Uri getUriFromIntent(Intent i, String key) {
|
||||
if (initSucceded) {
|
||||
try {
|
||||
Object clip = getClipDataFromIntent.invoke(i);
|
||||
|
||||
if (clip != null) {
|
||||
Object clipDescription = getDescription.invoke(clip);
|
||||
CharSequence label = (CharSequence)getLabel.invoke(clipDescription);
|
||||
if (label.equals(key)) {
|
||||
int itemCount = (int) getItemCount.invoke(clip);
|
||||
if (itemCount == 1) {
|
||||
Object clipItem = getItemAt.invoke(clip,0);
|
||||
if (clipItem != null) {
|
||||
return (Uri)getUri.invoke(clipItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
// Fall through below to backup method if reflection fails
|
||||
}
|
||||
}
|
||||
|
||||
return i.getParcelableExtra(key);
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,12 @@ class FileDatabaseInfo : FileInfo {
|
||||
|
||||
fun retrieveDatabaseTitle(titleCallback: (String)->Unit) {
|
||||
|
||||
FileDatabaseHistoryAction.getInstance(context.applicationContext).getFileDatabaseHistory(fileUri) {
|
||||
fileDatabaseHistoryEntity ->
|
||||
|
||||
titleCallback.invoke(retrieveDatabaseAlias(fileDatabaseHistoryEntity?.databaseAlias ?: ""))
|
||||
fileUri?.let { fileUri ->
|
||||
FileDatabaseHistoryAction.getInstance(context.applicationContext)
|
||||
.getFileDatabaseHistory(fileUri) { fileDatabaseHistoryEntity ->
|
||||
titleCallback.invoke(retrieveDatabaseAlias(fileDatabaseHistoryEntity?.databaseAlias
|
||||
?: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.*
|
||||
open class FileInfo : Serializable {
|
||||
|
||||
var context: Context
|
||||
var fileUri: Uri
|
||||
var fileUri: Uri?
|
||||
var filePath: String? = null
|
||||
var fileName: String? = ""
|
||||
var lastModification = Date()
|
||||
@@ -45,18 +45,20 @@ open class FileInfo : Serializable {
|
||||
|
||||
constructor(context: Context, filePath: String) {
|
||||
this.context = context
|
||||
this.fileUri = Uri.parse(filePath)
|
||||
this.fileUri = UriUtil.parse(filePath)
|
||||
init()
|
||||
}
|
||||
|
||||
fun init() {
|
||||
this.filePath = fileUri.path
|
||||
if (EXTERNAL_STORAGE_AUTHORITY == fileUri.authority) {
|
||||
this.filePath = fileUri?.path
|
||||
if (EXTERNAL_STORAGE_AUTHORITY == fileUri?.authority) {
|
||||
fileUri?.let { fileUri ->
|
||||
DocumentFile.fromSingleUri(context, fileUri)?.let { file ->
|
||||
size = file.length()
|
||||
fileName = file.name
|
||||
lastModification = Date(file.lastModified())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filePath?.let {
|
||||
File(it).let { file ->
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import com.kunzisoft.keepass.R
|
||||
import java.io.File
|
||||
@@ -131,81 +132,72 @@ object UriUtil {
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(FileNotFoundException::class)
|
||||
fun verifyFilePath(fileName: String?, doActionIfFileExists: ((String) -> Unit)? = null) {
|
||||
fun verifyFileUri(fileUri: Uri?): Boolean {
|
||||
|
||||
if (fileName != null && fileName.isNotEmpty()) {
|
||||
val fileUri = parseUriFile(fileName)
|
||||
verifyFileUri(fileUri, doActionIfFileExists)
|
||||
} else {
|
||||
throw FileNotFoundException("File name is empty")
|
||||
if (fileUri == null || fileUri == Uri.EMPTY)
|
||||
return false
|
||||
|
||||
val scheme = fileUri.scheme
|
||||
return when {
|
||||
scheme == null || scheme.isEmpty() -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun verifyFileUri(fileUri: Uri?, doActionIfFileExists: ((filePath: String) -> Unit)? = null) {
|
||||
|
||||
/* TODO errorString
|
||||
@IntegerRes
|
||||
var errorStringId: Int? = null
|
||||
*/
|
||||
|
||||
val scheme = fileUri?.scheme
|
||||
|
||||
if (scheme == null || scheme.isEmpty()) {
|
||||
throw FileNotFoundException("Uri scheme is empty")
|
||||
// TODO error errorStringId = R.string.error_can_not_handle_uri
|
||||
}
|
||||
else {
|
||||
when {
|
||||
scheme.equals("file", ignoreCase = true) -> {
|
||||
val filePath = fileUri.path
|
||||
|
||||
if (filePath == null || filePath.isEmpty())
|
||||
throw FileNotFoundException("Unable to retrieve file path")
|
||||
false
|
||||
else {
|
||||
if (!File(filePath).exists()) {
|
||||
throw FileNotFoundException("File do not exists")
|
||||
// TODO error errorStringId = R.string.file_not_found
|
||||
} else {
|
||||
doActionIfFileExists?.invoke(filePath)
|
||||
}
|
||||
File(filePath).exists()
|
||||
}
|
||||
}
|
||||
scheme.equals("content", ignoreCase = true) -> {
|
||||
doActionIfFileExists?.invoke(fileUri.toString())
|
||||
// TODO verify
|
||||
}
|
||||
else -> throw FileNotFoundException("Uri scheme not recognized")
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun parseUriFile(text: String?): Uri? {
|
||||
if (text == null || text.isEmpty()) {
|
||||
fun parse(stringUri: String?): Uri? {
|
||||
return if (stringUri?.isNotEmpty() == true) {
|
||||
val uriParsed = Uri.parse(stringUri)
|
||||
if (verifyFileUri(uriParsed))
|
||||
uriParsed
|
||||
else
|
||||
null
|
||||
} else
|
||||
null
|
||||
}
|
||||
|
||||
fun decode(uri: String?): String {
|
||||
return Uri.decode(uri) ?: ""
|
||||
}
|
||||
|
||||
fun getUriFromIntent(intent: Intent, key: String): Uri? {
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
val clipData = intent.clipData
|
||||
if (clipData != null) {
|
||||
if (clipData.description.label == key) {
|
||||
if (clipData.itemCount == 1) {
|
||||
val clipItem = clipData.getItemAt(0)
|
||||
if (clipItem != null) {
|
||||
return clipItem.uri
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return intent.getParcelableExtra(key)
|
||||
}
|
||||
return null
|
||||
}
|
||||
return parseUriFile(Uri.parse(text))
|
||||
}
|
||||
|
||||
fun parseUriFile(uri: Uri?): Uri? {
|
||||
if (uri == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Add file scheme if URI scheme is null
|
||||
var currentUri = uri
|
||||
if (currentUri.scheme == null || currentUri.scheme!!.isEmpty()) {
|
||||
currentUri = currentUri.buildUpon().scheme("file").authority("").build()
|
||||
}
|
||||
return currentUri
|
||||
}
|
||||
|
||||
@Throws(ActivityNotFoundException::class)
|
||||
fun gotoUrl(context: Context, url: String?) {
|
||||
try {
|
||||
if (url != null && url.isNotEmpty()) {
|
||||
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
|
||||
context.startActivity(Intent(Intent.ACTION_VIEW, parse(url)))
|
||||
}
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Toast.makeText(context, R.string.no_url_handler, Toast.LENGTH_LONG).show()
|
||||
|
||||
Reference in New Issue
Block a user