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