mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-04-04 05:17:36 +03:00
fix: better static utils implementation
This commit is contained in:
parent
c8868f31e6
commit
dfb418c12a
39 changed files with 226 additions and 310 deletions
|
@ -2,10 +2,10 @@ package com.kunzisoft.keepass.tests.stream
|
|||
|
||||
import android.content.Context
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.kunzisoft.keepass.utils.readAllBytes
|
||||
import com.kunzisoft.keepass.database.element.binary.BinaryCache
|
||||
import com.kunzisoft.keepass.database.element.binary.BinaryFile
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
|
||||
import com.kunzisoft.keepass.utils.readAllBytes
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import org.junit.Test
|
||||
import java.io.DataInputStream
|
||||
|
@ -19,7 +19,7 @@ class BinaryDataTest {
|
|||
InstrumentationRegistry.getInstrumentation().context
|
||||
}
|
||||
|
||||
private val cacheDirectory = UriUtil.getBinaryDir(InstrumentationRegistry.getInstrumentation().targetContext)
|
||||
private val cacheDirectory = InstrumentationRegistry.getInstrumentation().targetContext.getBinaryDir()
|
||||
private val fileA = File(cacheDirectory, TEST_FILE_CACHE_A)
|
||||
private val fileB = File(cacheDirectory, TEST_FILE_CACHE_B)
|
||||
private val fileC = File(cacheDirectory, TEST_FILE_CACHE_C)
|
||||
|
|
|
@ -30,7 +30,7 @@ import androidx.core.text.HtmlCompat
|
|||
import com.kunzisoft.keepass.BuildConfig
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.stylish.StylishActivity
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
|
||||
import org.joda.time.DateTime
|
||||
|
||||
class AboutActivity : StylishActivity() {
|
||||
|
@ -46,7 +46,7 @@ class AboutActivity : StylishActivity() {
|
|||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||
|
||||
val appName = if (UriUtil.contributingUser(this))
|
||||
val appName = if (this.isContributingUser())
|
||||
getString(R.string.app_name) + " " + getString(R.string.app_name_part3)
|
||||
else
|
||||
getString(R.string.app_name)
|
||||
|
|
|
@ -36,11 +36,11 @@ import androidx.activity.result.ActivityResultLauncher
|
|||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.core.graphics.BlendModeColorFilterCompat
|
||||
import androidx.core.graphics.BlendModeCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
|
@ -67,7 +67,7 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
|
|||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
import com.kunzisoft.keepass.utils.UuidUtil
|
||||
import com.kunzisoft.keepass.view.changeControlColor
|
||||
import com.kunzisoft.keepass.view.changeTitleColor
|
||||
|
@ -473,7 +473,7 @@ class EntryActivity : DatabaseLockActivity() {
|
|||
}
|
||||
R.id.menu_goto_url -> {
|
||||
mUrl?.let { url ->
|
||||
UriUtil.gotoUrl(this, url)
|
||||
this.openUrl(url)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
|
|||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
|
||||
import com.kunzisoft.keepass.view.*
|
||||
import com.kunzisoft.keepass.viewmodels.ColorPickerViewModel
|
||||
import com.kunzisoft.keepass.viewmodels.EntryEditViewModel
|
||||
|
@ -185,7 +185,7 @@ class EntryEditActivity : DatabaseLockActivity(),
|
|||
mExternalFileHelper = ExternalFileHelper(this)
|
||||
mExternalFileHelper?.buildOpenDocument { uri ->
|
||||
uri?.let { attachmentToUploadUri ->
|
||||
UriUtil.getFileData(this, attachmentToUploadUri)?.also { documentFile ->
|
||||
attachmentToUploadUri.getDocumentFile(this)?.also { documentFile ->
|
||||
documentFile.name?.let { fileName ->
|
||||
if (documentFile.length() > MAX_WARNING_BINARY_FILE) {
|
||||
FileTooBigDialogFragment.build(attachmentToUploadUri, fileName)
|
||||
|
|
|
@ -54,8 +54,8 @@ import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
|||
import com.kunzisoft.keepass.autofill.AutofillComponent
|
||||
import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.education.FileDatabaseSelectActivityEducation
|
||||
import com.kunzisoft.keepass.database.element.MainCredential
|
||||
import com.kunzisoft.keepass.education.FileDatabaseSelectActivityEducation
|
||||
import com.kunzisoft.keepass.hardware.HardwareKey
|
||||
import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
|
@ -65,7 +65,12 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
|
|||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.utils.*
|
||||
import com.kunzisoft.keepass.utils.DexUtil
|
||||
import com.kunzisoft.keepass.utils.MagikeyboardUtil
|
||||
import com.kunzisoft.keepass.utils.MenuUtil
|
||||
import com.kunzisoft.keepass.utils.UriHelper.parseUri
|
||||
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
import com.kunzisoft.keepass.view.asError
|
||||
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
|
||||
import com.kunzisoft.keepass.viewmodels.DatabaseFilesViewModel
|
||||
|
@ -179,7 +184,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
|
|||
&& savedInstanceState.getBoolean(EXTRA_STAY, false))) {
|
||||
val databasePath = PreferencesUtil.getDefaultDatabasePath(this)
|
||||
|
||||
UriUtil.parse(databasePath)?.let { databaseFileUri ->
|
||||
databasePath?.parseUri()?.let { databaseFileUri ->
|
||||
launchPasswordActivityWithPath(databaseFileUri)
|
||||
} ?: run {
|
||||
Log.i(TAG, "No default database to prepare")
|
||||
|
@ -326,7 +331,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
|
|||
super.onResume()
|
||||
|
||||
// Define special title
|
||||
specialTitle?.isVisible = UriUtil.contributingUser(this)
|
||||
specialTitle?.isVisible = this.isContributingUser()
|
||||
|
||||
// Show open and create button or special mode
|
||||
when (mSpecialMode) {
|
||||
|
@ -426,7 +431,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
|
|||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> UriUtil.gotoUrl(this, R.string.file_manager_explanation_url)
|
||||
android.R.id.home -> this.openUrl(R.string.file_manager_explanation_url)
|
||||
}
|
||||
MenuUtil.onDefaultMenuOptionsItemSelected(this, item)
|
||||
return super.onOptionsItemSelected(item)
|
||||
|
|
|
@ -69,7 +69,6 @@ import com.kunzisoft.keepass.database.search.SearchParameters
|
|||
import com.kunzisoft.keepass.education.GroupActivityEducation
|
||||
import com.kunzisoft.keepass.magikeyboard.MagikeyboardService
|
||||
import com.kunzisoft.keepass.model.GroupInfo
|
||||
import com.kunzisoft.keepass.database.element.MainCredential
|
||||
import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK
|
||||
|
@ -81,7 +80,7 @@ import com.kunzisoft.keepass.settings.SettingsActivity
|
|||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.BACK_PREVIOUS_KEYBOARD_ACTION
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
import com.kunzisoft.keepass.view.*
|
||||
import com.kunzisoft.keepass.viewmodels.GroupEditViewModel
|
||||
import com.kunzisoft.keepass.viewmodels.GroupViewModel
|
||||
|
@ -302,7 +301,7 @@ class GroupActivity : DatabaseLockActivity(),
|
|||
lockAndExit()
|
||||
}
|
||||
R.id.menu_contribute -> {
|
||||
UriUtil.gotoUrl(this@GroupActivity, R.string.contribution_url)
|
||||
this@GroupActivity.openUrl(R.string.contribution_url)
|
||||
}
|
||||
R.id.menu_about -> {
|
||||
startActivity(Intent(this@GroupActivity, AboutActivity::class.java))
|
||||
|
|
|
@ -46,7 +46,8 @@ import com.kunzisoft.keepass.database.element.icon.IconImage
|
|||
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
import com.kunzisoft.keepass.view.asError
|
||||
import com.kunzisoft.keepass.view.updateLockPaddingLeft
|
||||
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
|
||||
|
@ -243,7 +244,7 @@ class IconPickerActivity : DatabaseLockActivity() {
|
|||
}
|
||||
}
|
||||
R.id.menu_external_icon -> {
|
||||
UriUtil.gotoUrl(this, R.string.external_icon_url)
|
||||
this.openUrl(R.string.external_icon_url)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,7 +258,7 @@ class IconPickerActivity : DatabaseLockActivity() {
|
|||
// on Progress with thread
|
||||
val asyncResult: Deferred<IconPickerViewModel.IconCustomState?> = async {
|
||||
val iconCustomState = IconPickerViewModel.IconCustomState(null, true, R.string.error_upload_file)
|
||||
UriUtil.getFileData(this@IconPickerActivity, iconToUploadUri)?.also { documentFile ->
|
||||
iconToUploadUri?.getDocumentFile(this@IconPickerActivity)?.also { documentFile ->
|
||||
if (documentFile.length() > MAX_ICON_SIZE) {
|
||||
iconCustomState.errorStringId = R.string.error_file_to_big
|
||||
} else {
|
||||
|
|
|
@ -73,6 +73,7 @@ import com.kunzisoft.keepass.tasks.ActionRunnable
|
|||
import com.kunzisoft.keepass.utils.BACK_PREVIOUS_KEYBOARD_ACTION
|
||||
import com.kunzisoft.keepass.utils.MenuUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getUri
|
||||
import com.kunzisoft.keepass.view.MainCredentialView
|
||||
import com.kunzisoft.keepass.view.asError
|
||||
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
|
||||
|
@ -344,7 +345,7 @@ class MainCredentialActivity : DatabaseModeActivity(), AdvancedUnlockFragment.Bu
|
|||
if (action == VIEW_INTENT) {
|
||||
fillCredentials(
|
||||
intent.data,
|
||||
UriUtil.getUriFromIntent(intent, KEY_KEYFILE),
|
||||
intent.getUri(KEY_KEYFILE),
|
||||
HardwareKey.getHardwareKeyFromString(intent.getStringExtra(KEY_HARDWARE_KEY))
|
||||
)
|
||||
} else {
|
||||
|
@ -357,7 +358,7 @@ class MainCredentialActivity : DatabaseModeActivity(), AdvancedUnlockFragment.Bu
|
|||
try {
|
||||
intent?.removeExtra(KEY_KEYFILE)
|
||||
intent?.removeExtra(KEY_HARDWARE_KEY)
|
||||
} catch (e: Exception) {}
|
||||
} catch (_: Exception) {}
|
||||
mDatabaseFileUri?.let {
|
||||
mDatabaseFileViewModel.checkIfIsDefaultDatabase(it)
|
||||
}
|
||||
|
|
|
@ -21,12 +21,12 @@ package com.kunzisoft.keepass.activities.dialogs
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
|
||||
class FileManagerDialogFragment : DialogFragment() {
|
||||
|
||||
|
@ -42,7 +42,7 @@ class FileManagerDialogFragment : DialogFragment() {
|
|||
textDescription.text = getString(R.string.file_manager_install_description)
|
||||
|
||||
root.findViewById<Button>(R.id.file_manager_button).setOnClickListener {
|
||||
UriUtil.gotoUrl(requireContext(), R.string.file_manager_explanation_url)
|
||||
context?.openUrl(R.string.file_manager_explanation_url)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import androidx.appcompat.app.AlertDialog
|
|||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
|
||||
import com.kunzisoft.keepass.database.element.MainCredential
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
|
||||
import com.kunzisoft.keepass.view.MainCredentialView
|
||||
|
||||
class MainCredentialDialogFragment : DatabaseDialogFragment() {
|
||||
|
@ -74,7 +74,7 @@ class MainCredentialDialogFragment : DatabaseDialogFragment() {
|
|||
mainCredentialView = root.findViewById(R.id.main_credential_view)
|
||||
databaseUri?.let {
|
||||
root.findViewById<TextView>(R.id.title_database)?.text =
|
||||
UriUtil.getFileData(requireContext(), it)?.name
|
||||
it.getDocumentFile(requireContext())?.name
|
||||
}
|
||||
builder.setView(root)
|
||||
// Add action buttons
|
||||
|
|
|
@ -28,7 +28,7 @@ import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY
|
|||
import androidx.fragment.app.DialogFragment
|
||||
import com.kunzisoft.keepass.BuildConfig
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
|
||||
/**
|
||||
* Custom Dialog that asks the user to download the pro version or make a donation.
|
||||
|
@ -45,7 +45,7 @@ class ProFeatureDialogFragment : DialogFragment() {
|
|||
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_ad_free), FROM_HTML_MODE_LEGACY)).append("\n\n")
|
||||
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_buy_pro), FROM_HTML_MODE_LEGACY))
|
||||
builder.setPositiveButton(R.string.download) { _, _ ->
|
||||
UriUtil.gotoUrl(activity,
|
||||
activity.openUrl(
|
||||
activity.getString(R.string.play_store_url,
|
||||
activity.getString(R.string.keepro_app_id))
|
||||
)
|
||||
|
@ -54,7 +54,7 @@ class ProFeatureDialogFragment : DialogFragment() {
|
|||
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_feature_generosity), FROM_HTML_MODE_LEGACY)).append("\n\n")
|
||||
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_donation), FROM_HTML_MODE_LEGACY))
|
||||
builder.setPositiveButton(R.string.contribute) { _, _ ->
|
||||
UriUtil.gotoUrl(activity, R.string.contribution_url)
|
||||
activity.openUrl(R.string.contribution_url)
|
||||
}
|
||||
}
|
||||
builder.setMessage(stringBuilder)
|
||||
|
|
|
@ -35,11 +35,12 @@ import com.google.android.material.textfield.TextInputLayout
|
|||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
|
||||
import com.kunzisoft.keepass.activities.helpers.setOpenDocumentClickListener
|
||||
import com.kunzisoft.keepass.database.element.MainCredential
|
||||
import com.kunzisoft.keepass.hardware.HardwareKey
|
||||
import com.kunzisoft.keepass.hardware.HardwareKeyActivity
|
||||
import com.kunzisoft.keepass.database.element.MainCredential
|
||||
import com.kunzisoft.keepass.password.PasswordEntropy
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
import com.kunzisoft.keepass.view.HardwareKeySelectionView
|
||||
import com.kunzisoft.keepass.view.KeyFileSelectionView
|
||||
import com.kunzisoft.keepass.view.PassKeyView
|
||||
|
@ -136,7 +137,7 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
|
|||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
|
||||
rootView.findViewById<View>(R.id.credentials_information)?.setOnClickListener {
|
||||
UriUtil.gotoUrl(activity, R.string.credentials_explanation_url)
|
||||
activity.openUrl(R.string.credentials_explanation_url)
|
||||
}
|
||||
|
||||
passwordCheckBox = rootView.findViewById(R.id.password_checkbox)
|
||||
|
@ -154,7 +155,7 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
|
|||
mExternalFileHelper = ExternalFileHelper(this)
|
||||
mExternalFileHelper?.buildOpenDocument { uri ->
|
||||
uri?.let { pathUri ->
|
||||
UriUtil.getFileData(requireContext(), uri)?.length()?.let { lengthFile ->
|
||||
pathUri.getDocumentFile(requireContext())?.length()?.let { lengthFile ->
|
||||
keyFileSelectionView.error = null
|
||||
keyFileCheckBox.isChecked = true
|
||||
keyFileSelectionView.uri = pathUri
|
||||
|
|
|
@ -44,7 +44,8 @@ import com.kunzisoft.keepass.otp.OtpElement.Companion.MIN_TOTP_PERIOD
|
|||
import com.kunzisoft.keepass.otp.OtpTokenType
|
||||
import com.kunzisoft.keepass.otp.OtpType
|
||||
import com.kunzisoft.keepass.otp.TokenCalculator
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
import java.util.*
|
||||
|
||||
class SetOTPDialogFragment : DatabaseDialogFragment() {
|
||||
|
@ -205,7 +206,7 @@ class SetOTPDialogFragment : DatabaseDialogFragment() {
|
|||
}
|
||||
// Proprietary only on full version
|
||||
mTotpTokenTypeArray = OtpTokenType.getTotpTokenTypeValues(
|
||||
UriUtil.contributingUser(activity)
|
||||
activity.isContributingUser()
|
||||
)
|
||||
totpTokenTypeAdapter = ArrayAdapter(activity,
|
||||
android.R.layout.simple_spinner_item, mTotpTokenTypeArray!!).apply {
|
||||
|
@ -241,7 +242,7 @@ class SetOTPDialogFragment : DatabaseDialogFragment() {
|
|||
}
|
||||
|
||||
root?.findViewById<View>(R.id.otp_information)?.setOnClickListener {
|
||||
UriUtil.gotoUrl(activity, R.string.otp_explanation_url)
|
||||
activity.openUrl(R.string.otp_explanation_url)
|
||||
}
|
||||
|
||||
return builder.create()
|
||||
|
|
|
@ -26,7 +26,7 @@ import androidx.appcompat.app.AlertDialog
|
|||
import androidx.core.text.HtmlCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
|
||||
/**
|
||||
* Custom Dialog that asks the user to download the pro version or make a donation.
|
||||
|
@ -40,7 +40,7 @@ class UnderDevelopmentFeatureDialogFragment : DialogFragment() {
|
|||
|
||||
val stringBuilder = SpannableStringBuilder()
|
||||
/*
|
||||
if (UriUtil.contributingUser(activity)) {
|
||||
if (activity.isContributingUser()) {
|
||||
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_thanks), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n")
|
||||
.append(HtmlCompat.fromHtml(getString(R.string.html_rose), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n")
|
||||
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_work_hard), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n")
|
||||
|
@ -52,7 +52,7 @@ class UnderDevelopmentFeatureDialogFragment : DialogFragment() {
|
|||
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_contibute), HtmlCompat.FROM_HTML_MODE_LEGACY)).append(" ")
|
||||
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_encourage), HtmlCompat.FROM_HTML_MODE_LEGACY))
|
||||
builder.setPositiveButton(R.string.contribute) { _, _ ->
|
||||
UriUtil.gotoUrl(requireContext(), R.string.contribution_url)
|
||||
context?.openUrl(R.string.contribution_url)
|
||||
}
|
||||
//}
|
||||
builder.setMessage(stringBuilder)
|
||||
|
|
|
@ -33,7 +33,7 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.kunzisoft.keepass.activities.dialogs.FileManagerDialogFragment
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.takeUriPermission
|
||||
|
||||
class ExternalFileHelper {
|
||||
|
||||
|
@ -57,10 +57,8 @@ class ExternalFileHelper {
|
|||
fun buildOpenDocument(onFileSelected: ((uri: Uri?) -> Unit)?) {
|
||||
|
||||
val resultCallback = ActivityResultCallback<Uri?> { result ->
|
||||
result?.let { uri ->
|
||||
UriUtil.takeUriPermission(activity?.contentResolver, uri)
|
||||
onFileSelected?.invoke(uri)
|
||||
}
|
||||
activity?.contentResolver?.takeUriPermission(result)
|
||||
onFileSelected?.invoke(result)
|
||||
}
|
||||
|
||||
getContentResultLauncher = if (fragment != null) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.kunzisoft.keepass.database.element.Database
|
|||
import com.kunzisoft.keepass.database.element.MainCredential
|
||||
import com.kunzisoft.keepass.model.CipherEncryptDatabase
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
|
||||
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
|
||||
|
||||
abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
|
||||
|
@ -76,7 +77,7 @@ abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
|
|||
}
|
||||
|
||||
protected fun closeDatabase() {
|
||||
mDatabase?.clearAndClose(this)
|
||||
mDatabase?.clearAndClose(this.getBinaryDir())
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
|
|
@ -27,7 +27,8 @@ import com.kunzisoft.keepass.model.DatabaseFile
|
|||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.utils.IOActionTask
|
||||
import com.kunzisoft.keepass.utils.SingletonHolderParameter
|
||||
import com.kunzisoft.keepass.utils.UriUtilDatabase
|
||||
import com.kunzisoft.keepass.utils.UriHelper.decodeUri
|
||||
import com.kunzisoft.keepass.utils.UriHelper.parseUri
|
||||
import com.kunzisoft.keepass.viewmodels.FileDatabaseInfo
|
||||
|
||||
class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
||||
|
@ -46,9 +47,9 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
|||
databaseUri)
|
||||
DatabaseFile(
|
||||
databaseUri,
|
||||
UriUtilDatabase.parse(fileDatabaseHistoryEntity?.keyFileUri),
|
||||
fileDatabaseHistoryEntity?.keyFileUri?.parseUri(),
|
||||
HardwareKey.getHardwareKeyFromString(fileDatabaseHistoryEntity?.hardwareKey),
|
||||
UriUtilDatabase.decode(fileDatabaseHistoryEntity?.databaseUri),
|
||||
fileDatabaseHistoryEntity?.databaseUri?.decodeUri(),
|
||||
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity?.databaseAlias
|
||||
?: ""),
|
||||
fileDatabaseInfo.exists,
|
||||
|
@ -71,8 +72,7 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
|||
{
|
||||
it?.let { fileHistoryEntity ->
|
||||
fileHistoryEntity.keyFileUri?.let { keyFileUri ->
|
||||
keyFileUriResultListener.invoke(UriUtilDatabase.parse(
|
||||
keyFileUri))
|
||||
keyFileUriResultListener.invoke(keyFileUri.parseUri())
|
||||
}
|
||||
} ?: keyFileUriResultListener.invoke(null)
|
||||
}
|
||||
|
@ -96,10 +96,10 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
|||
) {
|
||||
databaseFileListLoaded.add(
|
||||
DatabaseFile(
|
||||
UriUtilDatabase.parse(fileDatabaseHistoryEntity.databaseUri),
|
||||
UriUtilDatabase.parse(fileDatabaseHistoryEntity.keyFileUri),
|
||||
fileDatabaseHistoryEntity.databaseUri.parseUri(),
|
||||
fileDatabaseHistoryEntity.keyFileUri?.parseUri(),
|
||||
HardwareKey.getHardwareKeyFromString(fileDatabaseHistoryEntity.hardwareKey),
|
||||
UriUtilDatabase.decode(fileDatabaseHistoryEntity.databaseUri),
|
||||
fileDatabaseHistoryEntity.databaseUri.decodeUri(),
|
||||
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity.databaseAlias),
|
||||
fileDatabaseInfo.exists,
|
||||
fileDatabaseInfo.getLastModificationString(),
|
||||
|
@ -165,10 +165,10 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
|||
FileDatabaseInfo(applicationContext,
|
||||
fileDatabaseHistory.databaseUri)
|
||||
DatabaseFile(
|
||||
UriUtilDatabase.parse(fileDatabaseHistory.databaseUri),
|
||||
UriUtilDatabase.parse(fileDatabaseHistory.keyFileUri),
|
||||
fileDatabaseHistory.databaseUri.parseUri(),
|
||||
fileDatabaseHistory.keyFileUri?.parseUri(),
|
||||
HardwareKey.getHardwareKeyFromString(fileDatabaseHistory.hardwareKey),
|
||||
UriUtilDatabase.decode(fileDatabaseHistory.databaseUri),
|
||||
fileDatabaseHistory.databaseUri.decodeUri(),
|
||||
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistory.databaseAlias),
|
||||
fileDatabaseInfo.exists,
|
||||
fileDatabaseInfo.getLastModificationString(),
|
||||
|
@ -192,10 +192,10 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
|||
val returnValue = databaseFileHistoryDao.delete(fileDatabaseHistory)
|
||||
if (returnValue > 0) {
|
||||
DatabaseFile(
|
||||
UriUtilDatabase.parse(fileDatabaseHistory.databaseUri),
|
||||
UriUtilDatabase.parse(fileDatabaseHistory.keyFileUri),
|
||||
fileDatabaseHistory.databaseUri.parseUri(),
|
||||
fileDatabaseHistory.keyFileUri?.parseUri(),
|
||||
HardwareKey.getHardwareKeyFromString(fileDatabaseHistory.hardwareKey),
|
||||
UriUtilDatabase.decode(fileDatabaseHistory.databaseUri),
|
||||
fileDatabaseHistory.databaseUri.decodeUri(),
|
||||
databaseFileToDelete.databaseAlias
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.kunzisoft.keepass.database.element.Database
|
|||
import com.kunzisoft.keepass.database.element.MainCredential
|
||||
import com.kunzisoft.keepass.hardware.HardwareKey
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
|
||||
|
||||
class CreateDatabaseRunnable(
|
||||
context: Context,
|
||||
|
@ -47,7 +48,7 @@ class CreateDatabaseRunnable(
|
|||
createData(mDatabaseUri, databaseName, rootName, templateGroupName)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
mDatabase.clearAndClose(context)
|
||||
mDatabase.clearAndClose(context.getBinaryDir())
|
||||
setError(e)
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import com.kunzisoft.keepass.model.CipherEncryptDatabase
|
|||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
||||
import com.kunzisoft.keepass.utils.UriUtilDatabase
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
|
||||
|
||||
class LoadDatabaseRunnable(
|
||||
private val context: Context,
|
||||
|
@ -47,9 +47,11 @@ class LoadDatabaseRunnable(
|
|||
private val mLoadDatabaseResult: ((Result) -> Unit)?,
|
||||
) : ActionRunnable() {
|
||||
|
||||
private val binaryDir = context.getBinaryDir()
|
||||
|
||||
override fun onStartRun() {
|
||||
// Clear before we load
|
||||
mDatabase.clearAndClose(context)
|
||||
mDatabase.clearAndClose(binaryDir)
|
||||
}
|
||||
|
||||
override fun onActionRun() {
|
||||
|
@ -60,7 +62,7 @@ class LoadDatabaseRunnable(
|
|||
mMainCredential,
|
||||
mChallengeResponseRetriever,
|
||||
mReadonly,
|
||||
UriUtilDatabase.getBinaryDir(context),
|
||||
binaryDir,
|
||||
{ memoryWanted ->
|
||||
BinaryData.canMemoryBeAllocatedInRAM(context, memoryWanted)
|
||||
},
|
||||
|
@ -91,7 +93,7 @@ class LoadDatabaseRunnable(
|
|||
// Register the current time to init the lock timer
|
||||
PreferencesUtil.saveCurrentTime(context)
|
||||
} else {
|
||||
mDatabase.clearAndClose(context)
|
||||
mDatabase.clearAndClose(binaryDir)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import com.kunzisoft.keepass.database.exception.DatabaseException
|
|||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
||||
import com.kunzisoft.keepass.utils.UriUtilDatabase
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
|
||||
|
||||
class ReloadDatabaseRunnable(
|
||||
private val context: Context,
|
||||
|
@ -35,10 +35,11 @@ class ReloadDatabaseRunnable(
|
|||
private val mLoadDatabaseResult: ((Result) -> Unit)?
|
||||
) : ActionRunnable() {
|
||||
|
||||
private val binaryDir = context.getBinaryDir()
|
||||
|
||||
override fun onStartRun() {
|
||||
// Clear before we load
|
||||
mDatabase.clearIndexesAndBinaries(UriUtilDatabase.getBinaryDir(
|
||||
context))
|
||||
mDatabase.clearIndexesAndBinaries(binaryDir)
|
||||
mDatabase.wasReloaded = true
|
||||
}
|
||||
|
||||
|
@ -57,7 +58,7 @@ class ReloadDatabaseRunnable(
|
|||
// Register the current time to init the lock timer
|
||||
PreferencesUtil.saveCurrentTime(context)
|
||||
} else {
|
||||
mDatabase.clearAndClose(context)
|
||||
mDatabase.clearAndClose(binaryDir)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,11 +11,10 @@ import androidx.activity.result.ActivityResultCallback
|
|||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.kunzisoft.keepass.BuildConfig
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openExternalApp
|
||||
|
||||
/**
|
||||
* Special activity to deal with hardware key drivers,
|
||||
|
@ -158,8 +157,7 @@ class HardwareKeyActivity: DatabaseModeActivity(){
|
|||
context.getString(R.string.error_driver_required, hardwareKey.toString())
|
||||
)
|
||||
.setPositiveButton(R.string.download) { _, _ ->
|
||||
UriUtil.openExternalApp(
|
||||
context,
|
||||
context.openExternalApp(
|
||||
context.getString(R.string.key_driver_app_id),
|
||||
context.getString(R.string.key_driver_url)
|
||||
)
|
||||
|
|
|
@ -13,7 +13,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openExternalApp
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class HardwareKeyResponseHelper {
|
||||
|
@ -134,7 +134,7 @@ class HardwareKeyResponseHelper {
|
|||
activity.getString(R.string.error_driver_required, hardwareKey.toString())
|
||||
)
|
||||
.setPositiveButton(R.string.download) { _, _ ->
|
||||
UriUtil.openExternalApp(activity, activity.getString(R.string.key_driver_app_id))
|
||||
activity.openExternalApp(activity.getString(R.string.key_driver_app_id))
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
builder.create().show()
|
||||
|
|
|
@ -36,7 +36,7 @@ import com.kunzisoft.keepass.model.AttachmentState
|
|||
import com.kunzisoft.keepass.model.EntryAttachmentState
|
||||
import com.kunzisoft.keepass.model.StreamDirection
|
||||
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -218,7 +218,7 @@ class AttachmentFileNotificationService: LockNotificationService() {
|
|||
}
|
||||
)
|
||||
|
||||
val fileName = UriUtil.getFileData(this, attachmentNotification.uri)?.name
|
||||
val fileName = attachmentNotification.uri.getDocumentFile(this)?.name
|
||||
?: attachmentNotification.uri.path
|
||||
|
||||
val builder = buildNewNotification().apply {
|
||||
|
|
|
@ -47,7 +47,9 @@ import com.kunzisoft.keepass.icons.IconPackChooser
|
|||
import com.kunzisoft.keepass.services.ClipboardEntryNotificationService
|
||||
import com.kunzisoft.keepass.settings.preference.IconPackListPreference
|
||||
import com.kunzisoft.keepass.settings.preferencedialogfragment.DurationDialogFragmentCompat
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
import com.kunzisoft.keepass.utils.UriUtil.releaseAllUnnecessaryPermissionUris
|
||||
|
||||
|
||||
class NestedAppSettingsFragment : NestedSettingsFragment() {
|
||||
|
@ -81,7 +83,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||
findPreference<Preference>(getString(R.string.remember_database_locations_key))?.setOnPreferenceChangeListener { _, newValue ->
|
||||
if (!(newValue as Boolean)) {
|
||||
FileDatabaseHistoryAction.getInstance(activity.applicationContext).deleteAll {
|
||||
UriUtil.releaseAllUnnecessaryPermissionUris(activity.applicationContext)
|
||||
activity.releaseAllUnnecessaryPermissionUris()
|
||||
}
|
||||
}
|
||||
true
|
||||
|
@ -90,7 +92,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||
findPreference<Preference>(getString(R.string.remember_keyfile_locations_key))?.setOnPreferenceChangeListener { _, newValue ->
|
||||
if (!(newValue as Boolean)) {
|
||||
FileDatabaseHistoryAction.getInstance(activity.applicationContext).deleteAllKeyFiles {
|
||||
UriUtil.releaseAllUnnecessaryPermissionUris(activity.applicationContext)
|
||||
activity.releaseAllUnnecessaryPermissionUris()
|
||||
}
|
||||
}
|
||||
true
|
||||
|
@ -168,7 +170,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||
}
|
||||
|
||||
findPreference<Preference>(getString(R.string.magic_keyboard_explanation_key))?.setOnPreferenceClickListener {
|
||||
UriUtil.gotoUrl(requireContext(), R.string.magic_keyboard_explanation_url)
|
||||
context?.openUrl(R.string.magic_keyboard_explanation_url)
|
||||
false
|
||||
}
|
||||
|
||||
|
@ -185,7 +187,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||
}
|
||||
|
||||
findPreference<Preference>(getString(R.string.autofill_explanation_key))?.setOnPreferenceClickListener {
|
||||
UriUtil.gotoUrl(requireContext(), R.string.autofill_explanation_url)
|
||||
context?.openUrl(R.string.autofill_explanation_url)
|
||||
false
|
||||
}
|
||||
|
||||
|
@ -202,7 +204,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||
}
|
||||
|
||||
findPreference<Preference>(getString(R.string.clipboard_explanation_key))?.setOnPreferenceClickListener {
|
||||
UriUtil.gotoUrl(requireContext(), R.string.clipboard_explanation_url)
|
||||
context?.openUrl(R.string.clipboard_explanation_url)
|
||||
false
|
||||
}
|
||||
|
||||
|
@ -360,7 +362,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||
}
|
||||
|
||||
findPreference<Preference>(getString(R.string.advanced_unlock_explanation_key))?.setOnPreferenceClickListener {
|
||||
UriUtil.gotoUrl(requireContext(), R.string.advanced_unlock_explanation_url)
|
||||
context?.openUrl(R.string.advanced_unlock_explanation_url)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +406,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||
findPreference<ListPreference>(getString(R.string.setting_style_key))?.setOnPreferenceChangeListener { _, newValue ->
|
||||
var styleEnabled = true
|
||||
val styleIdString = newValue as String
|
||||
if (!UriUtil.contributingUser(activity)) {
|
||||
if (!activity.isContributingUser()) {
|
||||
for (themeIdDisabled in BuildConfig.STYLES_DISABLED) {
|
||||
if (themeIdDisabled == styleIdString) {
|
||||
styleEnabled = false
|
||||
|
@ -435,7 +437,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||
findPreference<IconPackListPreference>(getString(R.string.setting_icon_pack_choose_key))?.setOnPreferenceChangeListener { _, newValue ->
|
||||
var iconPackEnabled = true
|
||||
val iconPackId = newValue as String
|
||||
if (!UriUtil.contributingUser(activity)) {
|
||||
if (!activity.isContributingUser()) {
|
||||
for (iconPackIdDisabled in BuildConfig.ICON_PACKS_DISABLED) {
|
||||
if (iconPackIdDisabled == iconPackId) {
|
||||
iconPackEnabled = false
|
||||
|
|
|
@ -36,7 +36,7 @@ import com.kunzisoft.keepass.education.Education
|
|||
import com.kunzisoft.keepass.magikeyboard.MagikeyboardService
|
||||
import com.kunzisoft.keepass.password.PassphraseGenerator
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
|
||||
import java.util.*
|
||||
|
||||
object PreferencesUtil {
|
||||
|
@ -173,7 +173,7 @@ object PreferencesUtil {
|
|||
|
||||
fun setStyle(context: Context, styleString: String) {
|
||||
var tempThemeString = styleString
|
||||
if (!UriUtil.contributingUser(context)) {
|
||||
if (!context.isContributingUser()) {
|
||||
if (tempThemeString in BuildConfig.STYLES_DISABLED) {
|
||||
tempThemeString = Stylish.defaultStyle(context)
|
||||
}
|
||||
|
|
|
@ -5,11 +5,12 @@ import android.graphics.Bitmap
|
|||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import com.kunzisoft.keepass.utils.readAllBytes
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.binary.BinaryCache
|
||||
import com.kunzisoft.keepass.database.element.binary.BinaryData
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
|
||||
import com.kunzisoft.keepass.utils.UriHelper.getUriOutputStream
|
||||
import com.kunzisoft.keepass.utils.readAllBytes
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
@ -29,7 +30,7 @@ object BinaryDatabaseManager {
|
|||
update: ((percent: Int)->Unit)? = null,
|
||||
canceled: ()-> Boolean = { false },
|
||||
bufferSize: Int = DEFAULT_BUFFER_SIZE) {
|
||||
UriUtil.getUriOutputStream(contentResolver, attachmentToUploadUri)?.use { outputStream ->
|
||||
contentResolver.getUriOutputStream(attachmentToUploadUri)?.use { outputStream ->
|
||||
downloadFromDatabase(database.binaryCache, outputStream, binaryData, update, canceled, bufferSize)
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +65,7 @@ object BinaryDatabaseManager {
|
|||
canceled: ()-> Boolean = { false },
|
||||
bufferSize: Int = DEFAULT_BUFFER_SIZE) {
|
||||
val fileSize = contentResolver.openFileDescriptor(attachmentFromDownloadUri, "r")?.statSize ?: 0
|
||||
UriUtil.getUriInputStream(contentResolver, attachmentFromDownloadUri)?.use { inputStream ->
|
||||
contentResolver.getUriInputStream(attachmentFromDownloadUri)?.use { inputStream ->
|
||||
uploadToDatabase(database.binaryCache, inputStream, fileSize, binaryData, update, canceled, bufferSize)
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +98,7 @@ object BinaryDatabaseManager {
|
|||
binaryData: BinaryData?) {
|
||||
try {
|
||||
binaryData?.let {
|
||||
UriUtil.getUriInputStream(contentResolver, bitmapUri)?.use { inputStream ->
|
||||
contentResolver.getUriInputStream(bitmapUri)?.use { inputStream ->
|
||||
BitmapFactory.decodeStream(inputStream)?.let { bitmap ->
|
||||
val bitmapResized = bitmap.resize(DEFAULT_ICON_WIDTH)
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
|
|
|
@ -36,6 +36,8 @@ import com.kunzisoft.keepass.services.ClipboardEntryNotificationService
|
|||
import com.kunzisoft.keepass.services.KeyboardEntryNotificationService
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
|
||||
import com.kunzisoft.keepass.utils.UriUtil.releaseAllUnnecessaryPermissionUris
|
||||
|
||||
const val DATABASE_START_TASK_ACTION = "com.kunzisoft.keepass.DATABASE_START_TASK_ACTION"
|
||||
const val DATABASE_STOP_TASK_ACTION = "com.kunzisoft.keepass.DATABASE_STOP_TASK_ACTION"
|
||||
|
@ -161,8 +163,8 @@ fun Context.closeDatabase(database: Database?) {
|
|||
cancelAll()
|
||||
}
|
||||
// Clear data
|
||||
database?.clearAndClose(this)
|
||||
database?.clearAndClose(this.getBinaryDir())
|
||||
|
||||
// Release not useful URI permission
|
||||
UriUtil.releaseAllUnnecessaryPermissionUris(applicationContext)
|
||||
applicationContext.releaseAllUnnecessaryPermissionUris()
|
||||
}
|
||||
|
|
|
@ -28,13 +28,15 @@ import android.view.MenuItem
|
|||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.AboutActivity
|
||||
import com.kunzisoft.keepass.settings.SettingsActivity
|
||||
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
|
||||
object MenuUtil {
|
||||
|
||||
fun defaultMenuInflater(context: Context, inflater: MenuInflater, menu: Menu) {
|
||||
inflater.inflate(R.menu.settings, menu)
|
||||
inflater.inflate(R.menu.about, menu)
|
||||
if (!UriUtil.contributingUser(context))
|
||||
if (!context.isContributingUser())
|
||||
menu.findItem(R.id.menu_contribute)?.isVisible = false
|
||||
}
|
||||
|
||||
|
@ -46,7 +48,7 @@ object MenuUtil {
|
|||
timeoutEnable: Boolean = false) {
|
||||
when (item.itemId) {
|
||||
R.id.menu_contribute -> {
|
||||
UriUtil.gotoUrl(activity, R.string.contribution_url)
|
||||
activity.openUrl(R.string.contribution_url)
|
||||
}
|
||||
R.id.menu_app_settings -> {
|
||||
// To avoid flickering when launch settings in a LockingActivity
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePassDX.
|
||||
*
|
||||
* KeePassDX 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.
|
||||
*
|
||||
* KeePassDX 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 KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.utils
|
||||
open class SingletonHolderParameter<out T, in A>(private val constructor: (A) -> T) {
|
||||
@Volatile
|
||||
private var instance: T? = null
|
||||
fun getInstance(arg: A): T {
|
||||
return when {
|
||||
instance != null -> instance!!
|
||||
else -> synchronized(this) {
|
||||
if (instance == null) instance = constructor(arg)
|
||||
instance!!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,26 +32,25 @@ import com.kunzisoft.keepass.BuildConfig
|
|||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||
import com.kunzisoft.keepass.education.Education
|
||||
import java.io.*
|
||||
import java.util.*
|
||||
import com.kunzisoft.keepass.utils.UriHelper.withContentScheme
|
||||
import com.kunzisoft.keepass.utils.UriHelper.withFileScheme
|
||||
import java.io.File
|
||||
|
||||
|
||||
object UriUtil {
|
||||
|
||||
fun getFileData(context: Context, fileUri: Uri?): DocumentFile? {
|
||||
if (fileUri == null)
|
||||
return null
|
||||
fun Uri.getDocumentFile(context: Context): DocumentFile? {
|
||||
return try {
|
||||
when {
|
||||
isFileScheme(fileUri) -> {
|
||||
fileUri.path?.let {
|
||||
this.withFileScheme() -> {
|
||||
this.path?.let {
|
||||
File(it).let { file ->
|
||||
return DocumentFile.fromFile(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
isContentScheme(fileUri) -> {
|
||||
DocumentFile.fromSingleUri(context, fileUri)
|
||||
this.withContentScheme() -> {
|
||||
DocumentFile.fromSingleUri(context, this)
|
||||
}
|
||||
else -> {
|
||||
Log.e("FileData", "Content scheme not known")
|
||||
|
@ -64,66 +63,6 @@ object UriUtil {
|
|||
}
|
||||
}
|
||||
|
||||
@Throws(FileNotFoundException::class)
|
||||
fun getUriOutputStream(contentResolver: ContentResolver, fileUri: Uri?): OutputStream? {
|
||||
if (fileUri == null)
|
||||
return null
|
||||
return when {
|
||||
isFileScheme(fileUri) -> fileUri.path?.let { FileOutputStream(it) }
|
||||
isContentScheme(fileUri) -> {
|
||||
try {
|
||||
contentResolver.openOutputStream(fileUri, "wt")
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.e(TAG, "Unable to open stream in `wt` mode, retry in `rwt` mode.", e)
|
||||
// https://issuetracker.google.com/issues/180526528
|
||||
// Try with rwt to fix content provider issue
|
||||
val outStream = contentResolver.openOutputStream(fileUri, "rwt")
|
||||
Log.w(TAG, "`rwt` mode used.")
|
||||
outStream
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(FileNotFoundException::class)
|
||||
fun getUriInputStream(contentResolver: ContentResolver, fileUri: Uri?): InputStream? {
|
||||
if (fileUri == null)
|
||||
return null
|
||||
return when {
|
||||
isFileScheme(fileUri) -> fileUri.path?.let { FileInputStream(it) }
|
||||
isContentScheme(fileUri) -> contentResolver.openInputStream(fileUri)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun isFileScheme(fileUri: Uri): Boolean {
|
||||
val scheme = fileUri.scheme
|
||||
if (scheme == null || scheme.isEmpty() || scheme.lowercase(Locale.ENGLISH) == "file") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isContentScheme(fileUri: Uri): Boolean {
|
||||
val scheme = fileUri.scheme
|
||||
if (scheme != null && scheme.lowercase(Locale.ENGLISH) == "content") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun parse(stringUri: String?): Uri? {
|
||||
return if (stringUri?.isNotEmpty() == true) {
|
||||
Uri.parse(stringUri)
|
||||
} else
|
||||
null
|
||||
}
|
||||
|
||||
fun decode(uri: String?): String {
|
||||
return Uri.decode(uri) ?: ""
|
||||
}
|
||||
|
||||
private fun persistUriPermission(contentResolver: ContentResolver?,
|
||||
uri: Uri,
|
||||
release: Boolean,
|
||||
|
@ -190,18 +129,19 @@ object UriUtil {
|
|||
}
|
||||
}
|
||||
|
||||
fun takeUriPermission(contentResolver: ContentResolver?,
|
||||
uri: Uri,
|
||||
readOnly: Boolean = false) {
|
||||
persistUriPermission(contentResolver, uri, false, readOnly)
|
||||
fun ContentResolver.takeUriPermission(uri: Uri?, readOnly: Boolean = false) {
|
||||
uri?.let {
|
||||
persistUriPermission(this, it, false, readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
fun releaseUriPermission(contentResolver: ContentResolver?,
|
||||
uri: Uri) {
|
||||
persistUriPermission(contentResolver, uri, release = true, readOnly = false)
|
||||
fun ContentResolver.releaseUriPermission(uri: Uri?) {
|
||||
uri?.let {
|
||||
persistUriPermission(this, it, release = true, readOnly = false)
|
||||
}
|
||||
}
|
||||
|
||||
fun releaseAllUnnecessaryPermissionUris(applicationContext: Context?) {
|
||||
fun Context.releaseAllUnnecessaryPermissionUris() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
applicationContext?.let { appContext ->
|
||||
val fileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(appContext)
|
||||
|
@ -220,17 +160,17 @@ object UriUtil {
|
|||
resolver.persistedUriPermissions.forEach { uriPermission ->
|
||||
val uri = uriPermission.uri
|
||||
if (!listToNotRemove.contains(uri))
|
||||
releaseUriPermission(resolver, uri)
|
||||
resolver.releaseUriPermission(uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getUriFromIntent(intent: Intent?, key: String): Uri? {
|
||||
fun Intent.getUri(key: String): Uri? {
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
val clipData = intent?.clipData
|
||||
val clipData = this.clipData
|
||||
if (clipData != null) {
|
||||
if (clipData.description.label == key) {
|
||||
if (clipData.itemCount == 1) {
|
||||
|
@ -243,12 +183,12 @@ object UriUtil {
|
|||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return intent?.getParcelableExtra(key)
|
||||
return this.getParcelableExtra(key)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun gotoUrl(context: Context, url: String?) {
|
||||
fun Context.openUrl(url: String?) {
|
||||
try {
|
||||
if (url != null && url.isNotEmpty()) {
|
||||
// Default http:// if no protocol specified
|
||||
|
@ -257,28 +197,30 @@ object UriUtil {
|
|||
} else {
|
||||
url
|
||||
}
|
||||
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(newUrl)))
|
||||
this.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(newUrl)))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(context, R.string.no_url_handler, Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(this, R.string.no_url_handler, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun gotoUrl(context: Context, resId: Int) {
|
||||
gotoUrl(context, context.getString(resId))
|
||||
fun Context.openUrl(resId: Int) {
|
||||
this.openUrl(this.getString(resId))
|
||||
}
|
||||
|
||||
fun contributingUser(context: Context): Boolean {
|
||||
return (Education.isEducationScreenReclickedPerformed(context)
|
||||
fun Context.isContributingUser(): Boolean {
|
||||
return (Education.isEducationScreenReclickedPerformed(this)
|
||||
|| isExternalAppInstalled(
|
||||
context,
|
||||
context.getString(R.string.keepro_app_id),
|
||||
false
|
||||
)
|
||||
)
|
||||
this,
|
||||
this.getString(R.string.keepro_app_id),
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun isExternalAppInstalled(context: Context, packageName: String, showError: Boolean = true): Boolean {
|
||||
private fun isExternalAppInstalled(context: Context,
|
||||
packageName: String,
|
||||
showError: Boolean = true): Boolean {
|
||||
try {
|
||||
context.applicationContext.packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES)
|
||||
Education.setEducationScreenReclickedPerformed(context)
|
||||
|
@ -290,16 +232,16 @@ object UriUtil {
|
|||
return false
|
||||
}
|
||||
|
||||
fun openExternalApp(context: Context, packageName: String, sourcesURL: String? = null) {
|
||||
fun Context.openExternalApp(packageName: String, sourcesURL: String? = null) {
|
||||
var launchIntent: Intent? = null
|
||||
try {
|
||||
launchIntent = context.packageManager.getLaunchIntentForPackage(packageName)?.apply {
|
||||
launchIntent = this.packageManager.getLaunchIntentForPackage(packageName)?.apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
} catch (ignored: Exception) { }
|
||||
try {
|
||||
if (launchIntent == null) {
|
||||
context.startActivity(
|
||||
this.startActivity(
|
||||
Intent(Intent.ACTION_VIEW)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.setData(
|
||||
|
@ -309,7 +251,7 @@ object UriUtil {
|
|||
) {
|
||||
sourcesURL
|
||||
} else {
|
||||
context.getString(
|
||||
this.getString(
|
||||
if (BuildConfig.CLOSED_STORE)
|
||||
R.string.play_store_url
|
||||
else
|
||||
|
@ -321,18 +263,18 @@ object UriUtil {
|
|||
)
|
||||
)
|
||||
} else {
|
||||
context.startActivity(launchIntent)
|
||||
this.startActivity(launchIntent)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "App cannot be open", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun getBinaryDir(context: Context): File {
|
||||
fun Context.getBinaryDir(): File {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
context.applicationContext.noBackupFilesDir
|
||||
this.applicationContext.noBackupFilesDir
|
||||
} else {
|
||||
context.applicationContext.filesDir
|
||||
this.applicationContext.filesDir
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import android.widget.TextView
|
|||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
|
||||
|
||||
|
||||
class KeyFileSelectionView @JvmOverloads constructor(context: Context,
|
||||
|
@ -66,7 +66,7 @@ class KeyFileSelectionView @JvmOverloads constructor(context: Context,
|
|||
}
|
||||
}
|
||||
keyFileNameView.text = value?.let {
|
||||
UriUtil.getFileData(context, value)?.name ?: value.path
|
||||
value.getDocumentFile(context)?.name ?: value.path
|
||||
} ?: ""
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ import com.kunzisoft.keepass.database.helper.isStandardPasswordName
|
|||
import com.kunzisoft.keepass.model.EntryInfo.Companion.APPLICATION_ID_FIELD_NAME
|
||||
import com.kunzisoft.keepass.password.PasswordGenerator
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openExternalApp
|
||||
|
||||
|
||||
class TextFieldView @JvmOverloads constructor(context: Context,
|
||||
|
@ -253,7 +253,7 @@ class TextFieldView @JvmOverloads constructor(context: Context,
|
|||
val packageName = valueView.text.toString()
|
||||
// TODO #996 if (UriUtil.isExternalAppInstalled(context, packageName)) {
|
||||
valueView.customLink {
|
||||
UriUtil.openExternalApp(context, packageName)
|
||||
context.openExternalApp(packageName)
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@ import androidx.lifecycle.AndroidViewModel
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import com.kunzisoft.keepass.app.App
|
||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||
import com.kunzisoft.keepass.utils.IOActionTask
|
||||
import com.kunzisoft.keepass.model.DatabaseFile
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.IOActionTask
|
||||
import com.kunzisoft.keepass.utils.UriHelper.parseUri
|
||||
|
||||
class DatabaseFileViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
|
@ -26,8 +26,8 @@ class DatabaseFileViewModel(application: Application) : AndroidViewModel(applica
|
|||
fun checkIfIsDefaultDatabase(databaseUri: Uri) {
|
||||
IOActionTask(
|
||||
{
|
||||
(UriUtil.parse(PreferencesUtil.getDefaultDatabasePath(getApplication<App>().applicationContext))
|
||||
== databaseUri)
|
||||
(PreferencesUtil.getDefaultDatabasePath(getApplication<App>().applicationContext)
|
||||
?.parseUri() == databaseUri)
|
||||
},
|
||||
{
|
||||
isDefaultDatabase.value = it
|
||||
|
|
|
@ -6,11 +6,12 @@ import androidx.lifecycle.AndroidViewModel
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import com.kunzisoft.keepass.app.App
|
||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||
import com.kunzisoft.keepass.utils.IOActionTask
|
||||
import com.kunzisoft.keepass.hardware.HardwareKey
|
||||
import com.kunzisoft.keepass.model.DatabaseFile
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.IOActionTask
|
||||
import com.kunzisoft.keepass.utils.UriHelper.parseUri
|
||||
import com.kunzisoft.keepass.utils.UriUtil.releaseUriPermission
|
||||
|
||||
class DatabaseFilesViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
|
@ -31,7 +32,8 @@ class DatabaseFilesViewModel(application: Application) : AndroidViewModel(applic
|
|||
fun checkDefaultDatabase() {
|
||||
IOActionTask(
|
||||
{
|
||||
UriUtil.parse(PreferencesUtil.getDefaultDatabasePath(getApplication<App>().applicationContext))
|
||||
PreferencesUtil.getDefaultDatabasePath(getApplication<App>().applicationContext)
|
||||
?.parseUri()
|
||||
},
|
||||
{
|
||||
defaultDatabase.value = it
|
||||
|
@ -118,18 +120,8 @@ class DatabaseFilesViewModel(application: Application) : AndroidViewModel(applic
|
|||
databaseFileDeleted?.let { _ ->
|
||||
// Release database and keyfile URIs permissions
|
||||
val contentResolver = getApplication<App>().applicationContext.contentResolver
|
||||
databaseFileDeleted.databaseUri?.let { databaseUri ->
|
||||
UriUtil.releaseUriPermission(
|
||||
contentResolver,
|
||||
databaseUri
|
||||
)
|
||||
}
|
||||
databaseFileDeleted.keyFileUri?.let { keyFileUri ->
|
||||
UriUtil.releaseUriPermission(
|
||||
contentResolver,
|
||||
keyFileUri
|
||||
)
|
||||
}
|
||||
contentResolver.releaseUriPermission(databaseFileDeleted.databaseUri)
|
||||
contentResolver.releaseUriPermission(databaseFileDeleted.keyFileUri)
|
||||
// Call the feedback
|
||||
databaseFilesLoaded.value = getDatabaseFilesLoadedValue().apply {
|
||||
databaseFileAction = DatabaseFileAction.DELETE
|
||||
|
|
|
@ -23,10 +23,12 @@ import android.content.Context
|
|||
import android.net.Uri
|
||||
import android.text.format.Formatter
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.kunzisoft.keepass.utils.UriHelper.parseUri
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
|
||||
import com.kunzisoft.keepass.utils.UriUtil.takeUriPermission
|
||||
import java.io.Serializable
|
||||
import java.text.DateFormat
|
||||
import java.util.Date
|
||||
import java.util.*
|
||||
|
||||
class FileDatabaseInfo : Serializable {
|
||||
|
||||
|
@ -43,16 +45,14 @@ class FileDatabaseInfo : Serializable {
|
|||
|
||||
constructor(context: Context, filePath: String) {
|
||||
this.context = context
|
||||
this.fileUri = UriUtil.parse(filePath)
|
||||
this.fileUri = filePath.parseUri()
|
||||
init()
|
||||
}
|
||||
|
||||
fun init() {
|
||||
// Check permission
|
||||
fileUri?.let { uri ->
|
||||
UriUtil.takeUriPermission(context.contentResolver, uri)
|
||||
}
|
||||
documentFile = UriUtil.getFileData(context, fileUri)
|
||||
context.contentResolver.takeUriPermission(fileUri)
|
||||
documentFile = fileUri?.getDocumentFile(context)
|
||||
}
|
||||
|
||||
var exists: Boolean = false
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
package com.kunzisoft.keepass.database.element
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
|
@ -58,6 +57,8 @@ import com.kunzisoft.keepass.icons.IconDrawableFactory
|
|||
import com.kunzisoft.keepass.icons.InterfaceIconPackChooser
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
||||
import com.kunzisoft.keepass.utils.*
|
||||
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
|
||||
import com.kunzisoft.keepass.utils.UriHelper.getUriOutputStream
|
||||
import java.io.*
|
||||
import java.util.*
|
||||
|
||||
|
@ -786,7 +787,7 @@ class Database(private val iconPackChooser: InterfaceIconPackChooser) {
|
|||
openDatabaseKDBX: (InputStream) -> Unit) {
|
||||
try {
|
||||
// Load Data, pass Uris as InputStreams
|
||||
val databaseStream = UriUtilDatabase.getUriInputStream(contentResolver, databaseUri)
|
||||
val databaseStream = contentResolver.getUriInputStream(databaseUri)
|
||||
?: throw UnknownDatabaseLocationException()
|
||||
|
||||
BufferedInputStream(databaseStream).use { databaseInputStream ->
|
||||
|
@ -867,7 +868,7 @@ class Database(private val iconPackChooser: InterfaceIconPackChooser) {
|
|||
}
|
||||
}
|
||||
// Copy from the cache to the final stream
|
||||
UriUtilDatabase.getUriOutputStream(contentResolver, saveUri)?.use { outputStream ->
|
||||
contentResolver.getUriOutputStream(saveUri)?.use { outputStream ->
|
||||
cacheFile.inputStream().use { inputStream ->
|
||||
inputStream.readAllBytes { buffer ->
|
||||
outputStream.write(buffer)
|
||||
|
@ -1005,8 +1006,8 @@ class Database(private val iconPackChooser: InterfaceIconPackChooser) {
|
|||
}
|
||||
}
|
||||
|
||||
fun clearAndClose(context: Context? = null) {
|
||||
clearIndexesAndBinaries(context?.let { UriUtilDatabase.getBinaryDir(context) })
|
||||
fun clearAndClose(filesDirectory: File? = null) {
|
||||
clearIndexesAndBinaries(filesDirectory)
|
||||
this.mDatabaseKDB = null
|
||||
this.mDatabaseKDBX = null
|
||||
this.fileUri = null
|
||||
|
|
|
@ -29,7 +29,7 @@ import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
|||
import com.kunzisoft.keepass.hardware.HardwareKey
|
||||
import com.kunzisoft.keepass.utils.StringUtil.removeSpaceChars
|
||||
import com.kunzisoft.keepass.utils.StringUtil.toHexString
|
||||
import com.kunzisoft.keepass.utils.UriUtilDatabase
|
||||
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
|
||||
import com.kunzisoft.keepass.utils.readEnum
|
||||
import com.kunzisoft.keepass.utils.writeEnum
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
|
@ -148,7 +148,7 @@ data class MainCredential(var password: String? = null,
|
|||
@Throws(Exception::class)
|
||||
private fun getKeyFileData(contentResolver: ContentResolver,
|
||||
keyFileUri: Uri): ByteArray? {
|
||||
UriUtilDatabase.getUriInputStream(contentResolver, keyFileUri)?.use { keyFileInputStream ->
|
||||
contentResolver.getUriInputStream(keyFileUri)?.use { keyFileInputStream ->
|
||||
return keyFileInputStream.readBytes()
|
||||
}
|
||||
return null
|
||||
|
|
|
@ -36,3 +36,17 @@ open class SingletonHolder<out T>(private val constructor: (iconPackChooser : In
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class SingletonHolderParameter<out T, in A>(private val constructor: (A) -> T) {
|
||||
@Volatile
|
||||
private var instance: T? = null
|
||||
fun getInstance(arg: A): T {
|
||||
return when {
|
||||
instance != null -> instance!!
|
||||
else -> synchronized(this) {
|
||||
if (instance == null) instance = constructor(arg)
|
||||
instance!!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,65 +19,50 @@
|
|||
*/
|
||||
package com.kunzisoft.keepass.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.Locale
|
||||
import java.io.*
|
||||
import java.util.*
|
||||
|
||||
|
||||
object UriUtilDatabase {
|
||||
fun parse(stringUri: String?): Uri? {
|
||||
return if (stringUri?.isNotEmpty() == true) {
|
||||
Uri.parse(stringUri)
|
||||
} else
|
||||
null
|
||||
object UriHelper {
|
||||
|
||||
fun String.parseUri(): Uri? {
|
||||
return if (this.isNotEmpty()) Uri.parse(this) else null
|
||||
}
|
||||
|
||||
fun decode(uri: String?): String {
|
||||
return Uri.decode(uri) ?: ""
|
||||
}
|
||||
|
||||
fun getBinaryDir(context: Context): File {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
context.applicationContext.noBackupFilesDir
|
||||
} else {
|
||||
context.applicationContext.filesDir
|
||||
}
|
||||
fun String.decodeUri(): String {
|
||||
return Uri.decode(this) ?: ""
|
||||
}
|
||||
|
||||
@Throws(FileNotFoundException::class)
|
||||
fun getUriInputStream(contentResolver: ContentResolver, fileUri: Uri?): InputStream? {
|
||||
fun ContentResolver.getUriInputStream(fileUri: Uri?): InputStream? {
|
||||
if (fileUri == null)
|
||||
return null
|
||||
return when {
|
||||
isFileScheme(fileUri) -> fileUri.path?.let { FileInputStream(it) }
|
||||
isContentScheme(fileUri) -> contentResolver.openInputStream(fileUri)
|
||||
fileUri.withFileScheme() -> fileUri.path?.let { FileInputStream(it) }
|
||||
fileUri.withContentScheme() -> this.openInputStream(fileUri)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("Recycle")
|
||||
@Throws(FileNotFoundException::class)
|
||||
fun getUriOutputStream(contentResolver: ContentResolver, fileUri: Uri?): OutputStream? {
|
||||
fun ContentResolver.getUriOutputStream(fileUri: Uri?): OutputStream? {
|
||||
if (fileUri == null)
|
||||
return null
|
||||
return when {
|
||||
isFileScheme(fileUri) -> fileUri.path?.let { FileOutputStream(it) }
|
||||
isContentScheme(fileUri) -> {
|
||||
fileUri.withFileScheme() -> fileUri.path?.let { FileOutputStream(it) }
|
||||
fileUri.withContentScheme() -> {
|
||||
try {
|
||||
contentResolver.openOutputStream(fileUri, "wt")
|
||||
this.openOutputStream(fileUri, "wt")
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.e(TAG, "Unable to open stream in `wt` mode, retry in `rwt` mode.", e)
|
||||
// https://issuetracker.google.com/issues/180526528
|
||||
// Try with rwt to fix content provider issue
|
||||
val outStream = contentResolver.openOutputStream(fileUri, "rwt")
|
||||
val outStream = this.openOutputStream(fileUri, "rwt")
|
||||
Log.w(TAG, "`rwt` mode used.")
|
||||
outStream
|
||||
}
|
||||
|
@ -86,16 +71,16 @@ object UriUtilDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
private fun isFileScheme(fileUri: Uri): Boolean {
|
||||
val scheme = fileUri.scheme
|
||||
fun Uri.withFileScheme(): Boolean {
|
||||
val scheme = this.scheme
|
||||
if (scheme == null || scheme.isEmpty() || scheme.lowercase(Locale.ENGLISH) == "file") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isContentScheme(fileUri: Uri): Boolean {
|
||||
val scheme = fileUri.scheme
|
||||
fun Uri.withContentScheme(): Boolean {
|
||||
val scheme = this.scheme
|
||||
if (scheme != null && scheme.lowercase(Locale.ENGLISH) == "content") {
|
||||
return true
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue