Merge branch 'develop' into feature/Autofill_Inline

This commit is contained in:
J-Jamet
2021-01-08 16:36:34 +01:00
59 changed files with 1007 additions and 350 deletions

View File

@@ -1,5 +1,16 @@
KeePassDX(2.9.9)
* Detect file changes and reload database #794
KeePassDX(2.9.8)
* Fix specific attachments with kdbx3.1 databases #828
* Fix small bugs
KeePassDX(2.9.7)
* Remove write permission since Android 10 #823
* Fix small bugs
KeePassDX(2.9.6) KeePassDX(2.9.6)
* * Fix KeyFile bug #820
KeePassDX(2.9.5) KeePassDX(2.9.5)
* Unlock database by device credentials (PIN/Password/Pattern) with Android M+ #102 #152 #811 * Unlock database by device credentials (PIN/Password/Pattern) with Android M+ #102 #152 #811

View File

@@ -12,8 +12,8 @@ android {
applicationId "com.kunzisoft.keepass" applicationId "com.kunzisoft.keepass"
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 30 targetSdkVersion 30
versionCode = 50 versionCode = 53
versionName = "2.9.6" versionName = "2.9.9"
multiDexEnabled true multiDexEnabled true
testApplicationId = "com.kunzisoft.keepass.tests" testApplicationId = "com.kunzisoft.keepass.tests"
@@ -92,7 +92,7 @@ android {
} }
} }
def room_version = "2.2.5" def room_version = "2.2.6"
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

View File

@@ -14,10 +14,15 @@
android:name="android.permission.USE_BIOMETRIC" /> android:name="android.permission.USE_BIOMETRIC" />
<uses-permission <uses-permission
android:name="android.permission.VIBRATE"/> android:name="android.permission.VIBRATE"/>
<!-- Write permission until Android 10 -->
<uses-permission <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
<!-- Open apps from links -->
<uses-permission <uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"/> android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<application <application
android:label="@string/app_name" android:label="@string/app_name"

View File

@@ -39,6 +39,7 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.appbar.CollapsingToolbarLayout import com.google.android.material.appbar.CollapsingToolbarLayout
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.activities.lock.LockingActivity import com.kunzisoft.keepass.activities.lock.LockingActivity
import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged
import com.kunzisoft.keepass.database.element.Attachment import com.kunzisoft.keepass.database.element.Attachment
@@ -53,6 +54,7 @@ import com.kunzisoft.keepass.model.StreamDirection
import com.kunzisoft.keepass.notifications.AttachmentFileNotificationService import com.kunzisoft.keepass.notifications.AttachmentFileNotificationService
import com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService import com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_ENTRY_HISTORY import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_ENTRY_HISTORY
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RELOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RESTORE_ENTRY_HISTORY import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RESTORE_ENTRY_HISTORY
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
@@ -151,6 +153,10 @@ class EntryActivity : LockingActivity() {
if (result.isSuccess) if (result.isSuccess)
finish() finish()
} }
ACTION_DATABASE_RELOAD_TASK -> {
// Close the current activity
finish()
}
} }
coordinatorLayout?.showActionError(result) coordinatorLayout?.showActionError(result)
} }
@@ -408,6 +414,9 @@ class EntryActivity : LockingActivity() {
menu.findItem(R.id.menu_save_database)?.isVisible = false menu.findItem(R.id.menu_save_database)?.isVisible = false
menu.findItem(R.id.menu_edit)?.isVisible = false menu.findItem(R.id.menu_edit)?.isVisible = false
} }
if (mSpecialMode != SpecialMode.DEFAULT) {
menu.findItem(R.id.menu_reload_database)?.isVisible = false
}
val gotoUrl = menu.findItem(R.id.menu_goto_url) val gotoUrl = menu.findItem(R.id.menu_goto_url)
gotoUrl?.apply { gotoUrl?.apply {
@@ -501,6 +510,9 @@ class EntryActivity : LockingActivity() {
R.id.menu_save_database -> { R.id.menu_save_database -> {
mProgressDatabaseTaskProvider?.startDatabaseSave(!mReadOnly) mProgressDatabaseTaskProvider?.startDatabaseSave(!mReadOnly)
} }
R.id.menu_reload_database -> {
mProgressDatabaseTaskProvider?.startDatabaseReload(false)
}
android.R.id.home -> finish() // close this activity and return to preview activity (if there is any) android.R.id.home -> finish() // close this activity and return to preview activity (if there is any)
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)

View File

@@ -61,6 +61,7 @@ import com.kunzisoft.keepass.notifications.AttachmentFileNotificationService
import com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService import com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_ENTRY_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_ENTRY_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RELOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK
import com.kunzisoft.keepass.notifications.KeyboardEntryNotificationService import com.kunzisoft.keepass.notifications.KeyboardEntryNotificationService
import com.kunzisoft.keepass.otp.OtpElement import com.kunzisoft.keepass.otp.OtpElement
@@ -335,6 +336,10 @@ class EntryEditActivity : LockingActivity(),
Log.e(TAG, "Unable to retrieve entry after database action", e) Log.e(TAG, "Unable to retrieve entry after database action", e)
} }
} }
ACTION_DATABASE_RELOAD_TASK -> {
// Close the current activity
finish()
}
} }
coordinatorLayout?.showActionError(result) coordinatorLayout?.showActionError(result)
} }
@@ -610,13 +615,7 @@ class EntryEditActivity : LockingActivity(),
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu) super.onCreateOptionsMenu(menu)
MenuUtil.contributionMenuInflater(menuInflater, menu)
val inflater = menuInflater
inflater.inflate(R.menu.database, menu)
// Save database not needed here
menu.findItem(R.id.menu_save_database)?.isVisible = false
MenuUtil.contributionMenuInflater(inflater, menu)
return true return true
} }
@@ -673,9 +672,6 @@ class EntryEditActivity : LockingActivity(),
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.menu_save_database -> {
mProgressDatabaseTaskProvider?.startDatabaseSave(!mReadOnly)
}
R.id.menu_contribute -> { R.id.menu_contribute -> {
MenuUtil.onContributionItemSelected(this) MenuUtil.onContributionItemSelected(this)
return true return true

View File

@@ -70,6 +70,7 @@ import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Compa
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_GROUP_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_GROUP_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_NODES_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_NODES_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_MOVE_NODES_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_MOVE_NODES_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RELOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_GROUP_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_GROUP_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.NEW_NODES_KEY import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.NEW_NODES_KEY
@@ -317,7 +318,12 @@ class GroupActivity : LockingActivity(),
if (result.isSuccess) { if (result.isSuccess) {
// Rebuild all the list to avoid bug when delete node from sort // Rebuild all the list to avoid bug when delete node from sort
try {
mListNodesFragment?.rebuildList() mListNodesFragment?.rebuildList()
} catch (e: Exception) {
Log.e(TAG, "Unable to rebuild the list after deletion")
e.printStackTrace()
}
// Add trash in views list if it doesn't exists // Add trash in views list if it doesn't exists
if (database.isRecycleBinEnabled) { if (database.isRecycleBinEnabled) {
@@ -337,6 +343,12 @@ class GroupActivity : LockingActivity(),
} }
} }
} }
ACTION_DATABASE_RELOAD_TASK -> {
// Reload the current activity
startActivity(intent)
finish()
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
}
} }
coordinatorLayout?.showActionError(result) coordinatorLayout?.showActionError(result)
@@ -873,6 +885,8 @@ class GroupActivity : LockingActivity(),
} }
if (mSpecialMode == SpecialMode.DEFAULT) { if (mSpecialMode == SpecialMode.DEFAULT) {
MenuUtil.defaultMenuInflater(inflater, menu) MenuUtil.defaultMenuInflater(inflater, menu)
} else {
menu.findItem(R.id.menu_reload_database)?.isVisible = false
} }
// Menu for recycle bin // Menu for recycle bin
@@ -998,6 +1012,10 @@ class GroupActivity : LockingActivity(),
mProgressDatabaseTaskProvider?.startDatabaseSave(!mReadOnly) mProgressDatabaseTaskProvider?.startDatabaseSave(!mReadOnly)
return true return true
} }
R.id.menu_reload_database -> {
mProgressDatabaseTaskProvider?.startDatabaseReload(false)
return true
}
R.id.menu_empty_recycle_bin -> { R.id.menu_empty_recycle_bin -> {
mCurrentGroup?.getChildren()?.let { listChildren -> mCurrentGroup?.getChildren()?.let { listChildren ->
// Automatically delete all elements // Automatically delete all elements
@@ -1125,7 +1143,16 @@ class GroupActivity : LockingActivity(),
private fun rebuildListNodes() { private fun rebuildListNodes() {
mListNodesFragment = supportFragmentManager.findFragmentByTag(LIST_NODES_FRAGMENT_TAG) as ListNodesFragment? mListNodesFragment = supportFragmentManager.findFragmentByTag(LIST_NODES_FRAGMENT_TAG) as ListNodesFragment?
// to refresh fragment // to refresh fragment
try {
mListNodesFragment?.rebuildList() mListNodesFragment?.rebuildList()
} catch (e: Exception) {
e.printStackTrace()
coordinatorLayout?.let { coordinatorLayout ->
Snackbar.make(coordinatorLayout,
R.string.error_rebuild_list,
Snackbar.LENGTH_LONG).asError().show()
}
}
mCurrentGroup = mListNodesFragment?.mainGroup mCurrentGroup = mListNodesFragment?.mainGroup
// Remove search in intent // Remove search in intent
deletePreviousSearchGroup() deletePreviousSearchGroup()

View File

@@ -22,30 +22,24 @@ package com.kunzisoft.keepass.activities
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.*
import androidx.appcompat.view.ActionMode
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.util.Log
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.view.ActionMode
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.NodeAdapter
import com.kunzisoft.keepass.database.element.SortNodeEnum
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.activities.dialogs.SortDialogFragment import com.kunzisoft.keepass.activities.dialogs.SortDialogFragment
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.activities.stylish.StylishFragment
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.activities.stylish.StylishFragment
import com.kunzisoft.keepass.adapters.NodeAdapter
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.SortNodeEnum
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.Type import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.settings.PreferencesUtil
import java.util.* import java.util.*
class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionListener { class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionListener {
@@ -197,7 +191,12 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
} }
// Refresh data // Refresh data
try {
rebuildList() rebuildList()
} catch (e: Exception) {
Log.e(TAG, "Unable to rebuild the list during resume")
e.printStackTrace()
}
if (isASearchResult && mAdapter!= null && mAdapter!!.isEmpty) { if (isASearchResult && mAdapter!= null && mAdapter!!.isEmpty) {
// To show the " no search entry found " // To show the " no search entry found "
@@ -209,10 +208,12 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
} }
} }
@Throws(IllegalArgumentException::class)
fun rebuildList() { fun rebuildList() {
// Add elements to the list // Add elements to the list
mainGroup?.let { mainGroup -> mainGroup?.let { mainGroup ->
mAdapter?.apply { mAdapter?.apply {
// Thrown an exception when sort cannot be performed
rebuildList(mainGroup) rebuildList(mainGroup)
// To visually change the elements // To visually change the elements
if (PreferencesUtil.APPEARANCE_CHANGED) { if (PreferencesUtil.APPEARANCE_CHANGED) {
@@ -231,8 +232,13 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
} }
// Tell the adapter to refresh it's list // Tell the adapter to refresh it's list
try {
mAdapter?.notifyChangeSort(sortNodeEnum, sortNodeParameters) mAdapter?.notifyChangeSort(sortNodeEnum, sortNodeParameters)
rebuildList() rebuildList()
} catch (e:Exception) {
Log.e(TAG, "Unable to rebuild the list with the sort")
e.printStackTrace()
}
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {

View File

@@ -588,13 +588,13 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
// Check permission // Check permission
private fun checkPermission() { private fun checkPermission() {
val writePermission = android.Manifest.permission.WRITE_EXTERNAL_STORAGE if (Build.VERSION.SDK_INT in 23..28
val permissions = arrayOf(writePermission)
if (Build.VERSION.SDK_INT >= 23
&& !readOnly && !readOnly
&& !mPermissionAsked) { && !mPermissionAsked) {
mPermissionAsked = true mPermissionAsked = true
// Check self permission to show or not the dialog // Check self permission to show or not the dialog
val writePermission = android.Manifest.permission.WRITE_EXTERNAL_STORAGE
val permissions = arrayOf(writePermission)
if (toolbar != null if (toolbar != null
&& ActivityCompat.checkSelfPermission(this, writePermission) != PackageManager.PERMISSION_GRANTED) { && ActivityCompat.checkSelfPermission(this, writePermission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, permissions, WRITE_EXTERNAL_STORAGE_REQUEST) ActivityCompat.requestPermissions(this, permissions, WRITE_EXTERNAL_STORAGE_REQUEST)
@@ -720,7 +720,7 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
when (resultCode) { when (resultCode) {
LockingActivity.RESULT_EXIT_LOCK -> { LockingActivity.RESULT_EXIT_LOCK -> {
clearCredentialsViews() clearCredentialsViews()
Database.getInstance().closeAndClear(UriUtil.getBinaryDir(this)) Database.getInstance().clearAndClose(UriUtil.getBinaryDir(this))
} }
Activity.RESULT_CANCELED -> { Activity.RESULT_CANCELED -> {
clearCredentialsViews() clearCredentialsViews()

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2020 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.activities.dialogs
import android.app.Dialog
import android.os.Bundle
import android.text.SpannableStringBuilder
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
class DatabaseChangedDialogFragment : DialogFragment() {
var actionDatabaseListener: ActionDatabaseChangedListener? = null
override fun onPause() {
super.onPause()
actionDatabaseListener = null
this.dismiss()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
val oldSnapFileDatabaseInfo: SnapFileDatabaseInfo? = arguments?.getParcelable(OLD_FILE_DATABASE_INFO)
val newSnapFileDatabaseInfo: SnapFileDatabaseInfo? = arguments?.getParcelable(NEW_FILE_DATABASE_INFO)
if (oldSnapFileDatabaseInfo != null && newSnapFileDatabaseInfo != null) {
// Use the Builder class for convenient dialog construction
val builder = AlertDialog.Builder(activity)
val stringBuilder = SpannableStringBuilder()
if (newSnapFileDatabaseInfo.exists) {
stringBuilder.append(getString(R.string.warning_database_info_changed))
stringBuilder.append("\n\n" +oldSnapFileDatabaseInfo.toString(activity)
+ "\n\n" +
newSnapFileDatabaseInfo.toString(activity) + "\n\n")
stringBuilder.append(getString(R.string.warning_database_info_changed_options))
} else {
stringBuilder.append(getString(R.string.warning_database_revoked))
}
builder.setMessage(stringBuilder)
builder.setPositiveButton(android.R.string.ok) { _, _ ->
actionDatabaseListener?.validateDatabaseChanged()
}
return builder.create()
}
}
return super.onCreateDialog(savedInstanceState)
}
interface ActionDatabaseChangedListener {
fun validateDatabaseChanged()
}
companion object {
const val DATABASE_CHANGED_DIALOG_TAG = "databaseChangedDialogFragment"
private const val OLD_FILE_DATABASE_INFO = "OLD_FILE_DATABASE_INFO"
private const val NEW_FILE_DATABASE_INFO = "NEW_FILE_DATABASE_INFO"
fun getInstance(oldSnapFileDatabaseInfo: SnapFileDatabaseInfo,
newSnapFileDatabaseInfo: SnapFileDatabaseInfo)
: DatabaseChangedDialogFragment {
val fragment = DatabaseChangedDialogFragment()
fragment.arguments = Bundle().apply {
putParcelable(OLD_FILE_DATABASE_INFO, oldSnapFileDatabaseInfo)
putParcelable(NEW_FILE_DATABASE_INFO, newSnapFileDatabaseInfo)
}
return fragment
}
}
}

View File

@@ -18,7 +18,7 @@ import com.kunzisoft.keepass.view.SpecialModeView
abstract class SpecialModeActivity : StylishActivity() { abstract class SpecialModeActivity : StylishActivity() {
protected var mSpecialMode: SpecialMode = SpecialMode.DEFAULT protected var mSpecialMode: SpecialMode = SpecialMode.DEFAULT
protected var mTypeMode: TypeMode = TypeMode.DEFAULT private var mTypeMode: TypeMode = TypeMode.DEFAULT
private var mSpecialModeView: SpecialModeView? = null private var mSpecialModeView: SpecialModeView? = null

View File

@@ -34,7 +34,7 @@ class App : MultiDexApplication() {
} }
override fun onTerminate() { override fun onTerminate() {
Database.getInstance().closeAndClear(UriUtil.getBinaryDir(this)) Database.getInstance().clearAndClose(UriUtil.getBinaryDir(this))
super.onTerminate() super.onTerminate()
} }
} }

View File

@@ -47,7 +47,7 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
UriUtil.decode(fileDatabaseHistoryEntity?.databaseUri), UriUtil.decode(fileDatabaseHistoryEntity?.databaseUri),
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity?.databaseAlias ?: ""), fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity?.databaseAlias ?: ""),
fileDatabaseInfo.exists, fileDatabaseInfo.exists,
fileDatabaseInfo.getModificationString(), fileDatabaseInfo.getLastModificationString(),
fileDatabaseInfo.getSizeString() fileDatabaseInfo.getSizeString()
) )
}, },
@@ -90,7 +90,7 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
UriUtil.decode(fileDatabaseHistoryEntity.databaseUri), UriUtil.decode(fileDatabaseHistoryEntity.databaseUri),
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity.databaseAlias), fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity.databaseAlias),
fileDatabaseInfo.exists, fileDatabaseInfo.exists,
fileDatabaseInfo.getModificationString(), fileDatabaseInfo.getLastModificationString(),
fileDatabaseInfo.getSizeString() fileDatabaseInfo.getSizeString()
) )
) )
@@ -152,7 +152,7 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
UriUtil.decode(fileDatabaseHistory.databaseUri), UriUtil.decode(fileDatabaseHistory.databaseUri),
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistory.databaseAlias), fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistory.databaseAlias),
fileDatabaseInfo.exists, fileDatabaseInfo.exists,
fileDatabaseInfo.getModificationString(), fileDatabaseInfo.getLastModificationString(),
fileDatabaseInfo.getSizeString() fileDatabaseInfo.getSizeString()
) )
} }

View File

@@ -117,10 +117,10 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// To wait resume // To wait resume
if (keepConnection) {
activityResult = ActivityResult(requestCode, resultCode, data) activityResult = ActivityResult(requestCode, resultCode, data)
}
keepConnection = false keepConnection = false
super.onActivityResult(requestCode, resultCode, data)
} }
override fun onResume() { override fun onResume() {
@@ -237,7 +237,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
Mode.WAIT_CREDENTIAL Mode.WAIT_CREDENTIAL
}) })
} }
} ?: throw IODatabaseException() }
} }
} }
} }
@@ -304,7 +304,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
private fun openAdvancedUnlockPrompt(cryptoPrompt: AdvancedUnlockCryptoPrompt) { private fun openAdvancedUnlockPrompt(cryptoPrompt: AdvancedUnlockCryptoPrompt) {
requireActivity().runOnUiThread { activity?.runOnUiThread {
if (allowOpenBiometricPrompt) { if (allowOpenBiometricPrompt) {
if (cryptoPrompt.isDeviceCredentialOperation) if (cryptoPrompt.isDeviceCredentialOperation)
keepConnection = true keepConnection = true
@@ -329,7 +329,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
mAdvancedUnlockInfoView?.setIconViewClickListener { _ -> mAdvancedUnlockInfoView?.setIconViewClickListener { _ ->
openAdvancedUnlockPrompt(cryptoPrompt) openAdvancedUnlockPrompt(cryptoPrompt)
} }
} ?: throw Exception("AdvancedUnlockHelper not initialized") } ?: throw Exception("AdvancedUnlockManager not initialized")
} }
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
@@ -358,13 +358,14 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
} ?: deleteEncryptedDatabaseKey() } ?: deleteEncryptedDatabaseKey()
} }
} ?: throw IODatabaseException() } ?: throw IODatabaseException()
} ?: throw Exception("AdvancedUnlockHelper not initialized") } ?: throw Exception("AdvancedUnlockManager not initialized")
} }
@Synchronized @Synchronized
fun initAdvancedUnlockMode() { fun initAdvancedUnlockMode() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mAllowAdvancedUnlockMenu = false mAllowAdvancedUnlockMenu = false
try {
when (biometricMode) { when (biometricMode) {
Mode.BIOMETRIC_UNAVAILABLE -> initNotAvailable() Mode.BIOMETRIC_UNAVAILABLE -> initNotAvailable()
Mode.BIOMETRIC_SECURITY_UPDATE_REQUIRED -> initSecurityUpdateRequired() Mode.BIOMETRIC_SECURITY_UPDATE_REQUIRED -> initSecurityUpdateRequired()
@@ -374,6 +375,9 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
Mode.STORE_CREDENTIAL -> initEncryptData() Mode.STORE_CREDENTIAL -> initEncryptData()
Mode.EXTRACT_CREDENTIAL -> initDecryptData() Mode.EXTRACT_CREDENTIAL -> initDecryptData()
} }
} catch (e: Exception) {
onGenericException(e)
}
invalidateBiometricMenu() invalidateBiometricMenu()
} }
} }
@@ -388,7 +392,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
&& (biometricMode != Mode.BIOMETRIC_UNAVAILABLE && (biometricMode != Mode.BIOMETRIC_UNAVAILABLE
&& biometricMode != Mode.KEY_MANAGER_UNAVAILABLE) && biometricMode != Mode.KEY_MANAGER_UNAVAILABLE)
mAddBiometricMenuInProgress = false mAddBiometricMenuInProgress = false
requireActivity().invalidateOptionsMenu() activity?.invalidateOptionsMenu()
} }
} }
} }
@@ -442,7 +446,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
} }
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
requireActivity().runOnUiThread { activity?.runOnUiThread {
Log.e(TAG, "Biometric authentication error. Code : $errorCode Error : $errString") Log.e(TAG, "Biometric authentication error. Code : $errorCode Error : $errString")
setAdvancedUnlockedMessageView(errString.toString()) setAdvancedUnlockedMessageView(errString.toString())
} }
@@ -450,7 +454,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
override fun onAuthenticationFailed() { override fun onAuthenticationFailed() {
requireActivity().runOnUiThread { activity?.runOnUiThread {
Log.e(TAG, "Biometric authentication failed, biometric not recognized") Log.e(TAG, "Biometric authentication failed, biometric not recognized")
setAdvancedUnlockedMessageView(R.string.advanced_unlock_not_recognized) setAdvancedUnlockedMessageView(R.string.advanced_unlock_not_recognized)
} }
@@ -458,7 +462,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
override fun onAuthenticationSucceeded() { override fun onAuthenticationSucceeded() {
requireActivity().runOnUiThread { activity?.runOnUiThread {
when (biometricMode) { when (biometricMode) {
Mode.BIOMETRIC_UNAVAILABLE -> { Mode.BIOMETRIC_UNAVAILABLE -> {
} }
@@ -485,7 +489,9 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
advancedUnlockManager?.decryptData(value) advancedUnlockManager?.decryptData(value)
} ?: deleteEncryptedDatabaseKey() } ?: deleteEncryptedDatabaseKey()
} }
} ?: throw IODatabaseException() } ?: run {
onAuthenticationError(-1, getString(R.string.error_database_uri_null))
}
} }
} }
} }
@@ -515,7 +521,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
} }
private fun showViews(show: Boolean) { private fun showViews(show: Boolean) {
requireActivity().runOnUiThread { activity?.runOnUiThread {
mAdvancedUnlockInfoView?.visibility = if (show) mAdvancedUnlockInfoView?.visibility = if (show)
View.VISIBLE View.VISIBLE
else { else {
@@ -526,20 +532,20 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
private fun setAdvancedUnlockedTitleView(textId: Int) { private fun setAdvancedUnlockedTitleView(textId: Int) {
requireActivity().runOnUiThread { activity?.runOnUiThread {
mAdvancedUnlockInfoView?.setTitle(textId) mAdvancedUnlockInfoView?.setTitle(textId)
} }
} }
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
private fun setAdvancedUnlockedMessageView(textId: Int) { private fun setAdvancedUnlockedMessageView(textId: Int) {
requireActivity().runOnUiThread { activity?.runOnUiThread {
mAdvancedUnlockInfoView?.setMessage(textId) mAdvancedUnlockInfoView?.setMessage(textId)
} }
} }
private fun setAdvancedUnlockedMessageView(text: CharSequence) { private fun setAdvancedUnlockedMessageView(text: CharSequence) {
requireActivity().runOnUiThread { activity?.runOnUiThread {
mAdvancedUnlockInfoView?.message = text mAdvancedUnlockInfoView?.message = text
} }
} }
@@ -548,6 +554,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
readOnlyEducationPerformed: Boolean, readOnlyEducationPerformed: Boolean,
onEducationViewClick: ((TapTargetView?) -> Unit)? = null, onEducationViewClick: ((TapTargetView?) -> Unit)? = null,
onOuterViewClick: ((TapTargetView?) -> Unit)? = null) { onOuterViewClick: ((TapTargetView?) -> Unit)? = null) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& !readOnlyEducationPerformed) { && !readOnlyEducationPerformed) {
val biometricCanAuthenticate = AdvancedUnlockManager.canAuthenticate(requireContext()) val biometricCanAuthenticate = AdvancedUnlockManager.canAuthenticate(requireContext())
@@ -560,6 +567,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
onEducationViewClick, onEducationViewClick,
onOuterViewClick) onOuterViewClick)
} }
} catch (ignored: Exception) {}
} }
enum class Mode { enum class Mode {

View File

@@ -26,7 +26,6 @@ import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.UriUtil import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.closeDatabase
class CreateDatabaseRunnable(context: Context, class CreateDatabaseRunnable(context: Context,
private val mDatabase: Database, private val mDatabase: Database,
@@ -47,7 +46,7 @@ class CreateDatabaseRunnable(context: Context,
createData(mDatabaseUri, databaseName, rootName) createData(mDatabaseUri, databaseName, rootName)
} }
} catch (e: Exception) { } catch (e: Exception) {
mDatabase.closeAndClear(UriUtil.getBinaryDir(context)) mDatabase.clearAndClose(UriUtil.getBinaryDir(context))
setError(e) setError(e)
} }

View File

@@ -31,7 +31,6 @@ 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.UriUtil import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.closeDatabase
class LoadDatabaseRunnable(private val context: Context, class LoadDatabaseRunnable(private val context: Context,
private val mDatabase: Database, private val mDatabase: Database,
@@ -47,7 +46,7 @@ class LoadDatabaseRunnable(private val context: Context,
override fun onStartRun() { override fun onStartRun() {
// Clear before we load // Clear before we load
mDatabase.closeAndClear(UriUtil.getBinaryDir(context)) mDatabase.clearAndClose(UriUtil.getBinaryDir(context))
} }
override fun onActionRun() { override fun onActionRun() {
@@ -59,9 +58,6 @@ class LoadDatabaseRunnable(private val context: Context,
mFixDuplicateUUID, mFixDuplicateUUID,
progressTaskUpdater) progressTaskUpdater)
} }
catch (e: DuplicateUuidDatabaseException) {
setError(e)
}
catch (e: LoadDatabaseException) { catch (e: LoadDatabaseException) {
setError(e) setError(e)
} }
@@ -83,7 +79,7 @@ class LoadDatabaseRunnable(private val context: Context,
// 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.closeAndClear(UriUtil.getBinaryDir(context)) mDatabase.clearAndClose(UriUtil.getBinaryDir(context))
} }
} }

View File

@@ -26,6 +26,8 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment
import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment.Companion.DATABASE_CHANGED_DIALOG_TAG
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
import com.kunzisoft.keepass.database.element.Entry import com.kunzisoft.keepass.database.element.Entry
@@ -35,6 +37,7 @@ import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.Type import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_ASSIGN_PASSWORD_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_ASSIGN_PASSWORD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_COPY_NODES_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_COPY_NODES_TASK
@@ -44,6 +47,7 @@ import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Compa
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_ENTRY_HISTORY import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_ENTRY_HISTORY
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_NODES_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_NODES_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RELOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_MOVE_NODES_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_MOVE_NODES_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_REMOVE_UNLINKED_DATA_TASK import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_REMOVE_UNLINKED_DATA_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RESTORE_ENTRY_HISTORY import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RESTORE_ENTRY_HISTORY
@@ -84,6 +88,7 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
private var serviceConnection: ServiceConnection? = null private var serviceConnection: ServiceConnection? = null
private var progressTaskDialogFragment: ProgressTaskDialogFragment? = null private var progressTaskDialogFragment: ProgressTaskDialogFragment? = null
private var databaseChangedDialogFragment: DatabaseChangedDialogFragment? = null
private val actionTaskListener = object: DatabaseTaskNotificationService.ActionTaskListener { private val actionTaskListener = object: DatabaseTaskNotificationService.ActionTaskListener {
override fun onStartAction(titleId: Int?, messageId: Int?, warningId: Int?) { override fun onStartAction(titleId: Int?, messageId: Int?, warningId: Int?) {
@@ -101,6 +106,28 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
} }
} }
private val mActionDatabaseListener = object: DatabaseChangedDialogFragment.ActionDatabaseChangedListener {
override fun validateDatabaseChanged() {
mBinder?.getService()?.saveDatabaseInfo()
}
}
private var databaseInfoListener = object: DatabaseTaskNotificationService.DatabaseInfoListener {
override fun onDatabaseInfoChanged(previousDatabaseInfo: SnapFileDatabaseInfo,
newDatabaseInfo: SnapFileDatabaseInfo) {
if (databaseChangedDialogFragment == null) {
databaseChangedDialogFragment = activity.supportFragmentManager
.findFragmentByTag(DATABASE_CHANGED_DIALOG_TAG) as DatabaseChangedDialogFragment?
databaseChangedDialogFragment?.actionDatabaseListener = mActionDatabaseListener
}
if (progressTaskDialogFragment == null) {
databaseChangedDialogFragment = DatabaseChangedDialogFragment.getInstance(previousDatabaseInfo, newDatabaseInfo)
databaseChangedDialogFragment?.actionDatabaseListener = mActionDatabaseListener
databaseChangedDialogFragment?.show(activity.supportFragmentManager, DATABASE_CHANGED_DIALOG_TAG)
}
}
}
private fun startDialog(titleId: Int? = null, private fun startDialog(titleId: Int? = null,
messageId: Int? = null, messageId: Int? = null,
warningId: Int? = null) { warningId: Int? = null) {
@@ -140,11 +167,14 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
override fun onServiceConnected(name: ComponentName?, serviceBinder: IBinder?) { override fun onServiceConnected(name: ComponentName?, serviceBinder: IBinder?) {
mBinder = (serviceBinder as DatabaseTaskNotificationService.ActionTaskBinder?)?.apply { mBinder = (serviceBinder as DatabaseTaskNotificationService.ActionTaskBinder?)?.apply {
addActionTaskListener(actionTaskListener) addActionTaskListener(actionTaskListener)
addDatabaseFileInfoListener(databaseInfoListener)
getService().checkAction() getService().checkAction()
getService().checkDatabaseInfo()
} }
} }
override fun onServiceDisconnected(name: ComponentName?) { override fun onServiceDisconnected(name: ComponentName?) {
mBinder?.removeDatabaseFileInfoListener(databaseInfoListener)
mBinder?.removeActionTaskListener(actionTaskListener) mBinder?.removeActionTaskListener(actionTaskListener)
mBinder = null mBinder = null
} }
@@ -206,6 +236,7 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
fun unregisterProgressTask() { fun unregisterProgressTask() {
stopDialog() stopDialog()
mBinder?.removeDatabaseFileInfoListener(databaseInfoListener)
mBinder?.removeActionTaskListener(actionTaskListener) mBinder?.removeActionTaskListener(actionTaskListener)
mBinder = null mBinder = null
@@ -264,6 +295,13 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
, ACTION_DATABASE_LOAD_TASK) , ACTION_DATABASE_LOAD_TASK)
} }
fun startDatabaseReload(fixDuplicateUuid: Boolean) {
start(Bundle().apply {
putBoolean(DatabaseTaskNotificationService.FIX_DUPLICATE_UUID_KEY, fixDuplicateUuid)
}
, ACTION_DATABASE_RELOAD_TASK)
}
fun startDatabaseAssignPassword(databaseUri: Uri, fun startDatabaseAssignPassword(databaseUri: Uri,
masterPasswordChecked: Boolean, masterPasswordChecked: Boolean,
masterPassword: String?, masterPassword: String?,

View File

@@ -0,0 +1,63 @@
/*
* 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.database.action
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.exception.DuplicateUuidDatabaseException
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.UriUtil
class ReloadDatabaseRunnable(private val context: Context,
private val mDatabase: Database,
private val progressTaskUpdater: ProgressTaskUpdater?,
private val mLoadDatabaseResult: ((Result) -> Unit)?)
: ActionRunnable() {
override fun onStartRun() {
// Clear before we load
mDatabase.clear(UriUtil.getBinaryDir(context))
}
override fun onActionRun() {
try {
mDatabase.reloadData(context.contentResolver,
UriUtil.getBinaryDir(context),
progressTaskUpdater)
}
catch (e: LoadDatabaseException) {
setError(e)
}
if (result.isSuccess) {
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
} else {
mDatabase.clearAndClose(UriUtil.getBinaryDir(context))
}
}
override fun onFinishRun() {
mLoadDatabaseResult?.invoke(result)
}
}

View File

@@ -31,10 +31,7 @@ import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.NodeIdInt import com.kunzisoft.keepass.database.element.node.NodeIdInt
import com.kunzisoft.keepass.database.element.node.NodeIdUUID import com.kunzisoft.keepass.database.element.node.NodeIdUUID
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
import com.kunzisoft.keepass.database.exception.DatabaseOutputException import com.kunzisoft.keepass.database.exception.*
import com.kunzisoft.keepass.database.exception.FileNotFoundDatabaseException
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
import com.kunzisoft.keepass.database.exception.SignatureDatabaseException
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDB import com.kunzisoft.keepass.database.file.DatabaseHeaderKDB
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX
import com.kunzisoft.keepass.database.file.input.DatabaseInputKDB import com.kunzisoft.keepass.database.file.input.DatabaseInputKDB
@@ -330,29 +327,11 @@ class Database {
} }
@Throws(LoadDatabaseException::class) @Throws(LoadDatabaseException::class)
fun loadData(uri: Uri, password: String?, keyfile: Uri?, private fun readDatabaseStream(contentResolver: ContentResolver, uri: Uri,
readOnly: Boolean, openDatabaseKDB: (InputStream) -> DatabaseKDB,
contentResolver: ContentResolver, openDatabaseKDBX: (InputStream) -> DatabaseKDBX) {
cacheDirectory: File,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?) {
this.fileUri = uri
isReadOnly = readOnly
if (uri.scheme == "file") {
val file = File(uri.path!!)
isReadOnly = !file.canWrite()
}
// Pass KeyFile Uri as InputStreams
var databaseInputStream: InputStream? = null var databaseInputStream: InputStream? = null
var keyFileInputStream: InputStream? = null
try { try {
// Get keyFile inputStream
keyfile?.let {
keyFileInputStream = UriUtil.getUriInputStream(contentResolver, keyfile)
}
// Load Data, pass Uris as InputStreams // Load Data, pass Uris as InputStreams
val databaseStream = UriUtil.getUriInputStream(contentResolver, uri) val databaseStream = UriUtil.getUriInputStream(contentResolver, uri)
?: throw IOException("Database input stream cannot be retrieve") ?: throw IOException("Database input stream cannot be retrieve")
@@ -374,22 +353,10 @@ class Database {
when { when {
// Header of database KDB // Header of database KDB
DatabaseHeaderKDB.matchesHeader(sig1, sig2) -> setDatabaseKDB(DatabaseInputKDB( DatabaseHeaderKDB.matchesHeader(sig1, sig2) -> setDatabaseKDB(openDatabaseKDB(databaseInputStream))
cacheDirectory,
fixDuplicateUUID)
.openDatabase(databaseInputStream,
password,
keyFileInputStream,
progressTaskUpdater))
// Header of database KDBX // Header of database KDBX
DatabaseHeaderKDBX.matchesHeader(sig1, sig2) -> setDatabaseKDBX(DatabaseInputKDBX( DatabaseHeaderKDBX.matchesHeader(sig1, sig2) -> setDatabaseKDBX(openDatabaseKDBX(databaseInputStream))
cacheDirectory,
fixDuplicateUUID)
.openDatabase(databaseInputStream,
password,
keyFileInputStream,
progressTaskUpdater))
// Header not recognized // Header not recognized
else -> throw SignatureDatabaseException() else -> throw SignatureDatabaseException()
@@ -397,15 +364,87 @@ class Database {
this.mSearchHelper = SearchHelper() this.mSearchHelper = SearchHelper()
loaded = true loaded = true
} catch (e: LoadDatabaseException) { } catch (e: LoadDatabaseException) {
throw e throw e
} finally {
databaseInputStream?.close()
}
}
@Throws(LoadDatabaseException::class)
fun loadData(uri: Uri, password: String?, keyfile: Uri?,
readOnly: Boolean,
contentResolver: ContentResolver,
cacheDirectory: File,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?) {
// Save database URI
this.fileUri = uri
// Check if the file is writable
this.isReadOnly = readOnly
if (uri.scheme == "file") {
val file = File(uri.path!!)
isReadOnly = !file.canWrite()
}
// Pass KeyFile Uri as InputStreams
var keyFileInputStream: InputStream? = null
try {
// Get keyFile inputStream
keyfile?.let {
keyFileInputStream = UriUtil.getUriInputStream(contentResolver, keyfile)
}
} catch (e: Exception) { } catch (e: Exception) {
throw FileNotFoundDatabaseException() throw FileNotFoundDatabaseException()
} finally { } finally {
keyFileInputStream?.close() keyFileInputStream?.close()
databaseInputStream?.close()
} }
// Read database stream for the first time
readDatabaseStream(contentResolver, uri,
{ databaseInputStream ->
DatabaseInputKDB(cacheDirectory)
.openDatabase(databaseInputStream,
password,
keyFileInputStream,
progressTaskUpdater,
fixDuplicateUUID)
},
{ databaseInputStream ->
DatabaseInputKDBX(cacheDirectory)
.openDatabase(databaseInputStream,
password,
keyFileInputStream,
progressTaskUpdater,
fixDuplicateUUID)
}
)
}
@Throws(LoadDatabaseException::class)
fun reloadData(contentResolver: ContentResolver,
cacheDirectory: File,
progressTaskUpdater: ProgressTaskUpdater?) {
// Retrieve the stream from the old database URI
fileUri?.let { oldDatabaseUri ->
readDatabaseStream(contentResolver, oldDatabaseUri,
{ databaseInputStream ->
DatabaseInputKDB(cacheDirectory)
.openDatabase(databaseInputStream,
masterKey,
progressTaskUpdater)
},
{ databaseInputStream ->
DatabaseInputKDBX(cacheDirectory)
.openDatabase(databaseInputStream,
masterKey,
progressTaskUpdater)
}
)
} ?: throw IODatabaseException()
} }
fun isGroupSearchable(group: Group, omitBackup: Boolean): Boolean { fun isGroupSearchable(group: Group, omitBackup: Boolean): Boolean {
@@ -531,7 +570,7 @@ class Database {
this.fileUri = uri this.fileUri = uri
} }
fun closeAndClear(filesDirectory: File? = null) { fun clear(filesDirectory: File? = null) {
drawFactory.clearCache() drawFactory.clearCache()
// Delete the cache of the database if present // Delete the cache of the database if present
mDatabaseKDB?.clearCache() mDatabaseKDB?.clearCache()
@@ -544,7 +583,10 @@ class Database {
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Unable to clear the directory cache.", e) Log.e(TAG, "Unable to clear the directory cache.", e)
} }
}
fun clearAndClose(filesDirectory: File? = null) {
clear(filesDirectory)
this.mDatabaseKDB = null this.mDatabaseKDB = null
this.mDatabaseKDBX = null this.mDatabaseKDBX = null
this.fileUri = null this.fileUri = null

View File

@@ -41,6 +41,13 @@ abstract class DatabaseInput<PwDb : DatabaseVersioned<*, *, *, *>>
abstract fun openDatabase(databaseInputStream: InputStream, abstract fun openDatabase(databaseInputStream: InputStream,
password: String?, password: String?,
keyInputStream: InputStream?, keyInputStream: InputStream?,
progressTaskUpdater: ProgressTaskUpdater?): PwDb progressTaskUpdater: ProgressTaskUpdater?,
fixDuplicateUUID: Boolean = false): PwDb
@Throws(LoadDatabaseException::class)
abstract fun openDatabase(databaseInputStream: InputStream,
masterKey: ByteArray,
progressTaskUpdater: ProgressTaskUpdater?,
fixDuplicateUUID: Boolean = false): PwDb
} }

View File

@@ -45,8 +45,7 @@ import javax.crypto.spec.SecretKeySpec
/** /**
* Load a KDB database file. * Load a KDB database file.
*/ */
class DatabaseInputKDB(cacheDirectory: File, class DatabaseInputKDB(cacheDirectory: File)
private val fixDuplicateUUID: Boolean = false)
: DatabaseInput<DatabaseKDB>(cacheDirectory) { : DatabaseInput<DatabaseKDB>(cacheDirectory) {
private lateinit var mDatabaseToOpen: DatabaseKDB private lateinit var mDatabaseToOpen: DatabaseKDB
@@ -55,7 +54,28 @@ class DatabaseInputKDB(cacheDirectory: File,
override fun openDatabase(databaseInputStream: InputStream, override fun openDatabase(databaseInputStream: InputStream,
password: String?, password: String?,
keyInputStream: InputStream?, keyInputStream: InputStream?,
progressTaskUpdater: ProgressTaskUpdater?): DatabaseKDB { progressTaskUpdater: ProgressTaskUpdater?,
fixDuplicateUUID: Boolean): DatabaseKDB {
return openDatabase(databaseInputStream, progressTaskUpdater, fixDuplicateUUID) {
mDatabaseToOpen.retrieveMasterKey(password, keyInputStream)
}
}
@Throws(LoadDatabaseException::class)
override fun openDatabase(databaseInputStream: InputStream,
masterKey: ByteArray,
progressTaskUpdater: ProgressTaskUpdater?,
fixDuplicateUUID: Boolean): DatabaseKDB {
return openDatabase(databaseInputStream, progressTaskUpdater, fixDuplicateUUID) {
mDatabaseToOpen.masterKey = masterKey
}
}
@Throws(LoadDatabaseException::class)
private fun openDatabase(databaseInputStream: InputStream,
progressTaskUpdater: ProgressTaskUpdater?,
fixDuplicateUUID: Boolean,
assignMasterKey: (() -> Unit)? = null): DatabaseKDB {
try { try {
// Load entire file, most of it's encrypted. // Load entire file, most of it's encrypted.
@@ -84,7 +104,7 @@ class DatabaseInputKDB(cacheDirectory: File,
mDatabaseToOpen = DatabaseKDB() mDatabaseToOpen = DatabaseKDB()
mDatabaseToOpen.changeDuplicateId = fixDuplicateUUID mDatabaseToOpen.changeDuplicateId = fixDuplicateUUID
mDatabaseToOpen.retrieveMasterKey(password, keyInputStream) assignMasterKey?.invoke()
// Select algorithm // Select algorithm
when { when {

View File

@@ -63,8 +63,7 @@ import javax.crypto.Cipher
import javax.crypto.CipherInputStream import javax.crypto.CipherInputStream
import kotlin.math.min import kotlin.math.min
class DatabaseInputKDBX(cacheDirectory: File, class DatabaseInputKDBX(cacheDirectory: File)
private val fixDuplicateUUID: Boolean = false)
: DatabaseInput<DatabaseKDBX>(cacheDirectory) { : DatabaseInput<DatabaseKDBX>(cacheDirectory) {
private var randomStream: StreamCipher? = null private var randomStream: StreamCipher? = null
@@ -98,12 +97,30 @@ class DatabaseInputKDBX(cacheDirectory: File,
override fun openDatabase(databaseInputStream: InputStream, override fun openDatabase(databaseInputStream: InputStream,
password: String?, password: String?,
keyInputStream: InputStream?, keyInputStream: InputStream?,
progressTaskUpdater: ProgressTaskUpdater?): DatabaseKDBX { progressTaskUpdater: ProgressTaskUpdater?,
fixDuplicateUUID: Boolean): DatabaseKDBX {
return openDatabase(databaseInputStream, progressTaskUpdater, fixDuplicateUUID) {
mDatabase.retrieveMasterKey(password, keyInputStream)
}
}
@Throws(LoadDatabaseException::class)
override fun openDatabase(databaseInputStream: InputStream,
masterKey: ByteArray,
progressTaskUpdater: ProgressTaskUpdater?,
fixDuplicateUUID: Boolean): DatabaseKDBX {
return openDatabase(databaseInputStream, progressTaskUpdater, fixDuplicateUUID) {
mDatabase.masterKey = masterKey
}
}
@Throws(LoadDatabaseException::class)
private fun openDatabase(databaseInputStream: InputStream,
progressTaskUpdater: ProgressTaskUpdater?,
fixDuplicateUUID: Boolean,
assignMasterKey: (() -> Unit)? = null): DatabaseKDBX {
try { try {
// TODO performance
progressTaskUpdater?.updateMessage(R.string.retrieving_db_key) progressTaskUpdater?.updateMessage(R.string.retrieving_db_key)
mDatabase = DatabaseKDBX() mDatabase = DatabaseKDBX()
mDatabase.changeDuplicateId = fixDuplicateUUID mDatabase.changeDuplicateId = fixDuplicateUUID
@@ -116,9 +133,8 @@ class DatabaseInputKDBX(cacheDirectory: File,
hashOfHeader = headerAndHash.hash hashOfHeader = headerAndHash.hash
val pbHeader = headerAndHash.header val pbHeader = headerAndHash.header
mDatabase.retrieveMasterKey(password, keyInputStream) assignMasterKey?.invoke()
mDatabase.makeFinalKey(header.masterSeed) mDatabase.makeFinalKey(header.masterSeed)
// TODO performance
progressTaskUpdater?.updateMessage(R.string.decrypting_db) progressTaskUpdater?.updateMessage(R.string.decrypting_db)
val engine: CipherEngine val engine: CipherEngine
@@ -958,7 +974,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
// Create empty binary if not retrieved in pool // Create empty binary if not retrieved in pool
if (binaryRetrieve == null) { if (binaryRetrieve == null) {
binaryRetrieve = mDatabase.buildNewBinary(cacheDirectory, binaryRetrieve = mDatabase.buildNewBinary(cacheDirectory,
compression = false, protection = true, binaryPoolId = id) compression = false, protection = false, binaryPoolId = id)
} }
return binaryRetrieve return binaryRetrieve
} }
@@ -1024,10 +1040,12 @@ class DatabaseInputKDBX(cacheDirectory: File,
return xpp.safeNextText() return xpp.safeNextText()
} }
@Throws(XmlPullParserException::class, IOException::class)
private fun readBase64String(xpp: XmlPullParser): ByteArray {
//readNextNode = false; @Throws(XmlPullParserException::class, IOException::class)
private fun readProtectedBase64String(xpp: XmlPullParser): ByteArray? {
if (xpp.attributeCount > 0) {
val protect = xpp.getAttributeValue(null, DatabaseKDBXXML.AttrProtected)
if (protect != null && protect.equals(DatabaseKDBXXML.ValTrue, ignoreCase = true)) {
Base64.decode(xpp.safeNextText(), BASE_64_FLAG)?.let { data -> Base64.decode(xpp.safeNextText(), BASE_64_FLAG)?.let { data ->
val plainText = ByteArray(data.size) val plainText = ByteArray(data.size)
randomStream?.processBytes(data, 0, data.size, plainText, 0) randomStream?.processBytes(data, 0, data.size, plainText, 0)
@@ -1035,18 +1053,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
} }
return ByteArray(0) return ByteArray(0)
} }
@Throws(XmlPullParserException::class, IOException::class)
private fun readProtectedBase64String(xpp: XmlPullParser): ByteArray? {
//(xpp.getEventType() == XmlPullParser.START_TAG);
if (xpp.attributeCount > 0) {
val protect = xpp.getAttributeValue(null, DatabaseKDBXXML.AttrProtected)
if (protect != null && protect.equals(DatabaseKDBXXML.ValTrue, ignoreCase = true)) {
return readBase64String(xpp)
} }
}
return null return null
} }

View File

@@ -38,7 +38,6 @@ import com.kunzisoft.keepass.database.element.entry.EntryKDBX
import com.kunzisoft.keepass.database.element.group.GroupKDBX import com.kunzisoft.keepass.database.element.group.GroupKDBX
import com.kunzisoft.keepass.database.element.icon.IconImageCustom import com.kunzisoft.keepass.database.element.icon.IconImageCustom
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
import com.kunzisoft.keepass.database.element.database.BinaryAttachment
import com.kunzisoft.keepass.database.element.security.MemoryProtectionConfig import com.kunzisoft.keepass.database.element.security.MemoryProtectionConfig
import com.kunzisoft.keepass.database.element.security.ProtectedString import com.kunzisoft.keepass.database.element.security.ProtectedString
import com.kunzisoft.keepass.database.exception.DatabaseOutputException import com.kunzisoft.keepass.database.exception.DatabaseOutputException
@@ -420,41 +419,56 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
writeObject(name, String(Base64.encode(data, BASE_64_FLAG))) writeObject(name, String(Base64.encode(data, BASE_64_FLAG)))
} }
/*
// Normally used by a single entry but obsolete because binaries are in meta tag with kdbx3.1-
// or in file header with kdbx4
// binary.isProtected attribute is not used to create the XML
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class) @Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
private fun writeBinary(binary : BinaryAttachment) { private fun writeEntryBinary(binary : BinaryAttachment) {
val binaryLength = binary.length() if (binary.length() > 0) {
if (binaryLength > 0) {
if (binary.isProtected) { if (binary.isProtected) {
xml.attribute(null, DatabaseKDBXXML.AttrProtected, DatabaseKDBXXML.ValTrue) xml.attribute(null, DatabaseKDBXXML.AttrProtected, DatabaseKDBXXML.ValTrue)
binary.getInputDataStream().use { inputStream ->
binary.getInputDataStream().readBytes(BUFFER_SIZE_BYTES) { buffer -> inputStream.readBytes(BUFFER_SIZE_BYTES) { buffer ->
val encoded = ByteArray(buffer.size) val encoded = ByteArray(buffer.size)
randomStream!!.processBytes(buffer, 0, encoded.size, encoded, 0) randomStream!!.processBytes(buffer, 0, encoded.size, encoded, 0)
val charArray = String(Base64.encode(encoded, BASE_64_FLAG)).toCharArray() xml.text(String(Base64.encode(encoded, BASE_64_FLAG)))
xml.text(charArray, 0, charArray.size) }
} }
} else { } else {
if (binary.isCompressed) {
xml.attribute(null, DatabaseKDBXXML.AttrCompressed, DatabaseKDBXXML.ValTrue)
}
// Write the XML // Write the XML
binary.getInputDataStream().readBytes(BUFFER_SIZE_BYTES) { buffer -> binary.getInputDataStream().use { inputStream ->
val charArray = String(Base64.encode(buffer, BASE_64_FLAG)).toCharArray() inputStream.readBytes(BUFFER_SIZE_BYTES) { buffer ->
xml.text(charArray, 0, charArray.size) xml.text(String(Base64.encode(buffer, BASE_64_FLAG)))
} }
} }
} }
} }
}
*/
// Only uses with kdbx3.1 to write binaries in meta tag
// With kdbx4, don't use this method because binaries are in header file
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class) @Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
private fun writeMetaBinaries() { private fun writeMetaBinaries() {
xml.startTag(null, DatabaseKDBXXML.ElemBinaries) xml.startTag(null, DatabaseKDBXXML.ElemBinaries)
// Use indexes because necessarily in DatabaseV4 (binary header ref is the order) // Use indexes because necessarily (binary header ref is the order)
mDatabaseKDBX.binaryPool.doForEachOrderedBinary { index, keyBinary -> mDatabaseKDBX.binaryPool.doForEachOrderedBinary { index, keyBinary ->
xml.startTag(null, DatabaseKDBXXML.ElemBinary) xml.startTag(null, DatabaseKDBXXML.ElemBinary)
xml.attribute(null, DatabaseKDBXXML.AttrId, index.toString()) xml.attribute(null, DatabaseKDBXXML.AttrId, index.toString())
writeBinary(keyBinary.binary) val binary = keyBinary.binary
if (binary.length() > 0) {
if (binary.isCompressed) {
xml.attribute(null, DatabaseKDBXXML.AttrCompressed, DatabaseKDBXXML.ValTrue)
}
// Write the XML
binary.getInputDataStream().use { inputStream ->
inputStream.readBytes(BUFFER_SIZE_BYTES) { buffer ->
xml.text(String(Base64.encode(buffer, BASE_64_FLAG)))
}
}
}
xml.endTag(null, DatabaseKDBXXML.ElemBinary) xml.endTag(null, DatabaseKDBXXML.ElemBinary)
} }
@@ -523,13 +537,11 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
if (protect) { if (protect) {
xml.attribute(null, DatabaseKDBXXML.AttrProtected, DatabaseKDBXXML.ValTrue) xml.attribute(null, DatabaseKDBXXML.AttrProtected, DatabaseKDBXXML.ValTrue)
val data = value.toString().toByteArray()
val data = value.toString().toByteArray(charset("UTF-8")) val dataLength = data.size
val valLength = data.size if (data.isNotEmpty()) {
val encoded = ByteArray(dataLength)
if (valLength > 0) { randomStream!!.processBytes(data, 0, dataLength, encoded, 0)
val encoded = ByteArray(valLength)
randomStream!!.processBytes(data, 0, valLength, encoded, 0)
xml.text(String(Base64.encode(encoded, BASE_64_FLAG))) xml.text(String(Base64.encode(encoded, BASE_64_FLAG)))
} }
} else { } else {

View File

@@ -0,0 +1,62 @@
package com.kunzisoft.keepass.model
import android.content.Context
import android.net.Uri
import android.os.Parcel
import android.os.Parcelable
import android.text.format.Formatter
import com.kunzisoft.keepass.viewmodels.FileDatabaseInfo
import java.text.DateFormat
import java.util.*
/**
* Utility data class to get FileDatabaseInfo at a `t` time
*/
data class SnapFileDatabaseInfo(var fileUri: Uri?,
var exists: Boolean,
var lastModification: Long?,
var size: Long?): Parcelable {
constructor(parcel: Parcel) : this(
parcel.readParcelable(Uri::class.java.classLoader),
parcel.readByte() != 0.toByte(),
parcel.readValue(Long::class.java.classLoader) as? Long,
parcel.readValue(Long::class.java.classLoader) as? Long) {
}
fun toString(context: Context): String {
val lastModificationString = DateFormat.getDateTimeInstance()
.format(Date(lastModification ?: 0))
return "$lastModificationString, " +
Formatter.formatFileSize(context, size ?: 0)
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeParcelable(fileUri, flags)
parcel.writeByte(if (exists) 1 else 0)
parcel.writeValue(lastModification)
parcel.writeValue(size)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<SnapFileDatabaseInfo> {
override fun createFromParcel(parcel: Parcel): SnapFileDatabaseInfo {
return SnapFileDatabaseInfo(parcel)
}
override fun newArray(size: Int): Array<SnapFileDatabaseInfo?> {
return arrayOfNulls(size)
}
fun fromFileDatabaseInfo(fileDatabaseInfo: FileDatabaseInfo): SnapFileDatabaseInfo {
return SnapFileDatabaseInfo(
fileDatabaseInfo.fileUri,
fileDatabaseInfo.exists,
fileDatabaseInfo.getLastModification(),
fileDatabaseInfo.getSize())
}
}
}

View File

@@ -22,9 +22,8 @@ package com.kunzisoft.keepass.notifications
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Binder import android.os.*
import android.os.Bundle import android.util.Log
import android.os.IBinder
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.GroupActivity import com.kunzisoft.keepass.activities.GroupActivity
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
@@ -40,6 +39,7 @@ import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.database.element.node.Node import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.Type import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
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.timeout.TimeoutHelper import com.kunzisoft.keepass.timeout.TimeoutHelper
@@ -47,6 +47,7 @@ import com.kunzisoft.keepass.utils.DATABASE_START_TASK_ACTION
import com.kunzisoft.keepass.utils.DATABASE_STOP_TASK_ACTION import com.kunzisoft.keepass.utils.DATABASE_STOP_TASK_ACTION
import com.kunzisoft.keepass.utils.LOCK_ACTION import com.kunzisoft.keepass.utils.LOCK_ACTION
import com.kunzisoft.keepass.utils.closeDatabase import com.kunzisoft.keepass.utils.closeDatabase
import com.kunzisoft.keepass.viewmodels.FileDatabaseInfo
import kotlinx.coroutines.* import kotlinx.coroutines.*
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
@@ -65,6 +66,9 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
private var mAllowFinishAction = AtomicBoolean() private var mAllowFinishAction = AtomicBoolean()
private var mActionRunning = false private var mActionRunning = false
private var mSnapFileDatabaseInfo: SnapFileDatabaseInfo? = null
private var mDatabaseInfoListeners = LinkedList<DatabaseInfoListener>()
private var mIconId: Int = R.drawable.notification_ic_database_load private var mIconId: Int = R.drawable.notification_ic_database_load
private var mTitleId: Int = R.string.database_opened private var mTitleId: Int = R.string.database_opened
private var mMessageId: Int? = null private var mMessageId: Int? = null
@@ -93,6 +97,14 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
mAllowFinishAction.set(false) mAllowFinishAction.set(false)
} }
} }
fun addDatabaseFileInfoListener(databaseInfoListener: DatabaseInfoListener) {
mDatabaseInfoListeners.add(databaseInfoListener)
}
fun removeDatabaseFileInfoListener(databaseInfoListener: DatabaseInfoListener) {
mDatabaseInfoListeners.remove(databaseInfoListener)
}
} }
interface ActionTaskListener { interface ActionTaskListener {
@@ -101,6 +113,11 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
fun onStopAction(actionTask: String, result: ActionRunnable.Result) fun onStopAction(actionTask: String, result: ActionRunnable.Result)
} }
interface DatabaseInfoListener {
fun onDatabaseInfoChanged(previousDatabaseInfo: SnapFileDatabaseInfo,
newDatabaseInfo: SnapFileDatabaseInfo)
}
/** /**
* Force to call [ActionTaskListener.onStartAction] if the action is still running * Force to call [ActionTaskListener.onStartAction] if the action is still running
*/ */
@@ -112,6 +129,31 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
} }
} }
fun checkDatabaseInfo() {
mDatabase.fileUri?.let {
val previousDatabaseInfo = mSnapFileDatabaseInfo
val lastFileDatabaseInfo = SnapFileDatabaseInfo.fromFileDatabaseInfo(
FileDatabaseInfo(applicationContext, it))
if (previousDatabaseInfo != null) {
if (previousDatabaseInfo != lastFileDatabaseInfo) {
Log.i(TAG, "Database file modified " +
"$previousDatabaseInfo != $lastFileDatabaseInfo ")
// Call listener to indicate a change in database info
mDatabaseInfoListeners.forEach { listener ->
listener.onDatabaseInfoChanged(previousDatabaseInfo, lastFileDatabaseInfo)
}
}
}
}
}
fun saveDatabaseInfo() {
mDatabase.fileUri?.let {
mSnapFileDatabaseInfo = SnapFileDatabaseInfo.fromFileDatabaseInfo(
FileDatabaseInfo(applicationContext, it))
}
}
override fun onBind(intent: Intent): IBinder? { override fun onBind(intent: Intent): IBinder? {
super.onBind(intent) super.onBind(intent)
return mActionTaskBinder return mActionTaskBinder
@@ -138,6 +180,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
val actionRunnable: ActionRunnable? = when (intentAction) { val actionRunnable: ActionRunnable? = when (intentAction) {
ACTION_DATABASE_CREATE_TASK -> buildDatabaseCreateActionTask(intent) ACTION_DATABASE_CREATE_TASK -> buildDatabaseCreateActionTask(intent)
ACTION_DATABASE_LOAD_TASK -> buildDatabaseLoadActionTask(intent) ACTION_DATABASE_LOAD_TASK -> buildDatabaseLoadActionTask(intent)
ACTION_DATABASE_RELOAD_TASK -> buildDatabaseReloadActionTask()
ACTION_DATABASE_ASSIGN_PASSWORD_TASK -> buildDatabaseAssignPasswordActionTask(intent) ACTION_DATABASE_ASSIGN_PASSWORD_TASK -> buildDatabaseAssignPasswordActionTask(intent)
ACTION_DATABASE_CREATE_GROUP_TASK -> buildDatabaseCreateGroupActionTask(intent) ACTION_DATABASE_CREATE_GROUP_TASK -> buildDatabaseCreateGroupActionTask(intent)
ACTION_DATABASE_UPDATE_GROUP_TASK -> buildDatabaseUpdateGroupActionTask(intent) ACTION_DATABASE_UPDATE_GROUP_TASK -> buildDatabaseUpdateGroupActionTask(intent)
@@ -193,6 +236,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
} }
} finally { } finally {
removeIntentData(intent) removeIntentData(intent)
// Save the database info after performing action
saveDatabaseInfo()
TimeoutHelper.releaseTemporarilyDisableTimeout() TimeoutHelper.releaseTemporarilyDisableTimeout()
if (TimeoutHelper.checkTimeAndLockIfTimeout(this@DatabaseTaskNotificationService)) { if (TimeoutHelper.checkTimeAndLockIfTimeout(this@DatabaseTaskNotificationService)) {
if (!mDatabase.loaded) { if (!mDatabase.loaded) {
@@ -214,7 +259,9 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
} }
return when (intentAction) { return when (intentAction) {
ACTION_DATABASE_LOAD_TASK, null -> { ACTION_DATABASE_LOAD_TASK,
ACTION_DATABASE_RELOAD_TASK,
null -> {
START_STICKY START_STICKY
} }
else -> { else -> {
@@ -248,7 +295,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
else -> { else -> {
when (intentAction) { when (intentAction) {
ACTION_DATABASE_CREATE_TASK -> R.string.creating_database ACTION_DATABASE_CREATE_TASK -> R.string.creating_database
ACTION_DATABASE_LOAD_TASK -> R.string.loading_database ACTION_DATABASE_LOAD_TASK,
ACTION_DATABASE_RELOAD_TASK -> R.string.loading_database
ACTION_DATABASE_SAVE -> R.string.saving_database ACTION_DATABASE_SAVE -> R.string.saving_database
else -> { else -> {
R.string.command_execution R.string.command_execution
@@ -258,13 +306,15 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
} }
mMessageId = when (intentAction) { mMessageId = when (intentAction) {
ACTION_DATABASE_LOAD_TASK -> null ACTION_DATABASE_LOAD_TASK,
ACTION_DATABASE_RELOAD_TASK -> null
else -> null else -> null
} }
mWarningId = mWarningId =
if (!saveAction if (!saveAction
|| intentAction == ACTION_DATABASE_LOAD_TASK) || intentAction == ACTION_DATABASE_LOAD_TASK
|| intentAction == ACTION_DATABASE_RELOAD_TASK)
null null
else else
R.string.do_not_kill_app R.string.do_not_kill_app
@@ -465,6 +515,17 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
} }
} }
private fun buildDatabaseReloadActionTask(): ActionRunnable {
return ReloadDatabaseRunnable(
this,
mDatabase,
this
) { result ->
// No need to add each info to reload database
result.data = Bundle()
}
}
private fun buildDatabaseAssignPasswordActionTask(intent: Intent): ActionRunnable? { private fun buildDatabaseAssignPasswordActionTask(intent: Intent): ActionRunnable? {
return if (intent.hasExtra(DATABASE_URI_KEY) return if (intent.hasExtra(DATABASE_URI_KEY)
&& intent.hasExtra(MASTER_PASSWORD_CHECKED_KEY) && intent.hasExtra(MASTER_PASSWORD_CHECKED_KEY)
@@ -770,6 +831,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
const val ACTION_DATABASE_CREATE_TASK = "ACTION_DATABASE_CREATE_TASK" const val ACTION_DATABASE_CREATE_TASK = "ACTION_DATABASE_CREATE_TASK"
const val ACTION_DATABASE_LOAD_TASK = "ACTION_DATABASE_LOAD_TASK" const val ACTION_DATABASE_LOAD_TASK = "ACTION_DATABASE_LOAD_TASK"
const val ACTION_DATABASE_RELOAD_TASK = "ACTION_DATABASE_RELOAD_TASK"
const val ACTION_DATABASE_ASSIGN_PASSWORD_TASK = "ACTION_DATABASE_ASSIGN_PASSWORD_TASK" const val ACTION_DATABASE_ASSIGN_PASSWORD_TASK = "ACTION_DATABASE_ASSIGN_PASSWORD_TASK"
const val ACTION_DATABASE_CREATE_GROUP_TASK = "ACTION_DATABASE_CREATE_GROUP_TASK" const val ACTION_DATABASE_CREATE_GROUP_TASK = "ACTION_DATABASE_CREATE_GROUP_TASK"
const val ACTION_DATABASE_UPDATE_GROUP_TASK = "ACTION_DATABASE_UPDATE_GROUP_TASK" const val ACTION_DATABASE_UPDATE_GROUP_TASK = "ACTION_DATABASE_UPDATE_GROUP_TASK"

View File

@@ -103,6 +103,6 @@ class MainPreferenceFragment : PreferenceFragmentCompat() {
} }
interface Callback { interface Callback {
fun onNestedPreferenceSelected(key: NestedSettingsFragment.Screen) fun onNestedPreferenceSelected(key: NestedSettingsFragment.Screen, reload: Boolean = false)
} }
} }

View File

@@ -552,6 +552,10 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
settingActivity?.mProgressDatabaseTaskProvider?.startDatabaseSave(!mDatabaseReadOnly) settingActivity?.mProgressDatabaseTaskProvider?.startDatabaseSave(!mDatabaseReadOnly)
true true
} }
R.id.menu_reload_database -> {
settingActivity?.mProgressDatabaseTaskProvider?.startDatabaseReload(false)
return true
}
else -> { else -> {
// Check the time lock before launching settings // Check the time lock before launching settings

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. * Copyright 2020 Jeremy Jamet / Kunzisoft.
* *
* This file is part of KeePassDX. * This file is part of KeePassDX.
* *
@@ -21,7 +21,6 @@ package com.kunzisoft.keepass.settings
import android.app.Activity import android.app.Activity
import android.app.backup.BackupManager import android.app.backup.BackupManager
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
@@ -37,6 +36,7 @@ import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
import com.kunzisoft.keepass.activities.lock.LockingActivity import com.kunzisoft.keepass.activities.lock.LockingActivity
import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService
import com.kunzisoft.keepass.timeout.TimeoutHelper import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.view.showActionError import com.kunzisoft.keepass.view.showActionError
@@ -95,14 +95,30 @@ open class SettingsActivity
backupManager = BackupManager(this) backupManager = BackupManager(this)
mProgressDatabaseTaskProvider?.onActionFinish = { actionTask, result -> mProgressDatabaseTaskProvider?.onActionFinish = { actionTask, result ->
when (actionTask) {
DatabaseTaskNotificationService.ACTION_DATABASE_RELOAD_TASK -> {
// Reload the current activity
startActivity(intent)
finish()
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
}
else -> {
// Call result in fragment // Call result in fragment
(supportFragmentManager (supportFragmentManager
.findFragmentByTag(TAG_NESTED) as NestedSettingsFragment?) .findFragmentByTag(TAG_NESTED) as NestedSettingsFragment?)
?.onProgressDialogThreadResult(actionTask, result) ?.onProgressDialogThreadResult(actionTask, result)
coordinatorLayout?.showActionError(result) coordinatorLayout?.showActionError(result)
} }
} }
}
// To reload the current screen
if (intent.extras?.containsKey(FRAGMENT_ARG) == true) {
intent.extras?.getString(FRAGMENT_ARG)?.let { fragmentScreenName ->
onNestedPreferenceSelected(NestedSettingsFragment.Screen.valueOf(fragmentScreenName), true)
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
@@ -193,25 +209,33 @@ open class SettingsActivity
hideOrShowLockButton(NestedSettingsFragment.Screen.APPLICATION) hideOrShowLockButton(NestedSettingsFragment.Screen.APPLICATION)
} }
private fun replaceFragment(key: NestedSettingsFragment.Screen) { private fun replaceFragment(key: NestedSettingsFragment.Screen, reload: Boolean) {
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction().apply {
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, if (reload) {
setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out,
R.anim.slide_in_left, R.anim.slide_out_right) R.anim.slide_in_left, R.anim.slide_out_right)
.replace(R.id.fragment_container, NestedSettingsFragment.newInstance(key, mReadOnly), TAG_NESTED) } else {
.addToBackStack(TAG_NESTED) setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
.commit() R.anim.slide_in_left, R.anim.slide_out_right)
}
replace(R.id.fragment_container, NestedSettingsFragment.newInstance(key, mReadOnly), TAG_NESTED)
addToBackStack(TAG_NESTED)
commit()
}
toolbar?.title = NestedSettingsFragment.retrieveTitle(resources, key) toolbar?.title = NestedSettingsFragment.retrieveTitle(resources, key)
// To reload the current screen
intent.putExtra(FRAGMENT_ARG, key.name)
hideOrShowLockButton(key) hideOrShowLockButton(key)
} }
override fun onNestedPreferenceSelected(key: NestedSettingsFragment.Screen) { override fun onNestedPreferenceSelected(key: NestedSettingsFragment.Screen, reload: Boolean) {
if (mTimeoutEnable) if (mTimeoutEnable)
TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(this) { TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(this) {
replaceFragment(key) replaceFragment(key, reload)
} }
else else
replaceFragment(key) replaceFragment(key, reload)
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
@@ -226,6 +250,7 @@ open class SettingsActivity
private const val SHOW_LOCK = "SHOW_LOCK" private const val SHOW_LOCK = "SHOW_LOCK"
private const val TITLE_KEY = "TITLE_KEY" private const val TITLE_KEY = "TITLE_KEY"
private const val TAG_NESTED = "TAG_NESTED" private const val TAG_NESTED = "TAG_NESTED"
private const val FRAGMENT_ARG = "FRAGMENT_ARG"
fun launch(activity: Activity, readOnly: Boolean, timeoutEnable: Boolean) { fun launch(activity: Activity, readOnly: Boolean, timeoutEnable: Boolean) {
val intent = Intent(activity, SettingsActivity::class.java) val intent = Intent(activity, SettingsActivity::class.java)

View File

@@ -138,5 +138,5 @@ fun Context.closeDatabase() {
cancelAll() cancelAll()
} }
// Clear data // Clear data
Database.getInstance().closeAndClear(UriUtil.getBinaryDir(this)) Database.getInstance().clearAndClose(UriUtil.getBinaryDir(this))
} }

View File

@@ -48,8 +48,8 @@ import java.util.*
class EntryContentsView @JvmOverloads constructor(context: Context, class EntryContentsView @JvmOverloads constructor(context: Context,
var attrs: AttributeSet? = null, attrs: AttributeSet? = null,
var defStyle: Int = 0) defStyle: Int = 0)
: LinearLayout(context, attrs, defStyle) { : LinearLayout(context, attrs, defStyle) {
private var fontInVisibility: Boolean = false private var fontInVisibility: Boolean = false
@@ -306,7 +306,7 @@ class EntryContentsView @JvmOverloads constructor(context: Context,
allowCopy: Boolean, allowCopy: Boolean,
onCopyButtonClickListener: OnClickListener?) { onCopyButtonClickListener: OnClickListener?) {
val entryCustomField: EntryField? = EntryField(context, attrs, defStyle) val entryCustomField: EntryField? = EntryField(context)
entryCustomField?.apply { entryCustomField?.apply {
setLabel(title) setLabel(title)
setValue(value.toString(), value.isProtected) setValue(value.toString(), value.isProtected)

View File

@@ -23,7 +23,6 @@ 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.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.UriUtil import com.kunzisoft.keepass.utils.UriUtil
import java.io.Serializable import java.io.Serializable
import java.text.DateFormat import java.text.DateFormat
@@ -58,7 +57,11 @@ class FileDatabaseInfo : Serializable {
} }
private set private set
fun getModificationString(): String? { fun getLastModification(): Long? {
return documentFile?.lastModified()
}
fun getLastModificationString(): String? {
return documentFile?.lastModified()?.let { return documentFile?.lastModified()?.let {
if (it != 0L) { if (it != 0L) {
DateFormat.getDateTimeInstance() DateFormat.getDateTimeInstance()
@@ -69,6 +72,10 @@ class FileDatabaseInfo : Serializable {
} }
} }
fun getSize(): Long? {
return documentFile?.length()
}
fun getSizeString(): String? { fun getSizeString(): String? {
return documentFile?.let { return documentFile?.let {
Formatter.formatFileSize(context, it.length()) Formatter.formatFileSize(context, it.length())

View File

@@ -0,0 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportHeight="24"
android:viewportWidth="24" >
<path android:fillColor="#FFFFFF" android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"/>
</vector>

View File

@@ -22,6 +22,6 @@
<item android:id="@+id/menu_contribute" <item android:id="@+id/menu_contribute"
android:icon="@drawable/ic_heart_white_24dp" android:icon="@drawable/ic_heart_white_24dp"
android:title="@string/contribute" android:title="@string/contribute"
android:orderInCategory="95" android:orderInCategory="99"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
</menu> </menu>

View File

@@ -24,4 +24,9 @@
android:title="@string/menu_save_database" android:title="@string/menu_save_database"
android:orderInCategory="95" android:orderInCategory="95"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item android:id="@+id/menu_reload_database"
android:icon="@drawable/ic_reload_white_24dp"
android:title="@string/menu_reload_database"
android:orderInCategory="96"
app:showAsAction="ifRoom" />
</menu> </menu>

View File

@@ -212,11 +212,11 @@
<string name="lock">Zamknout</string> <string name="lock">Zamknout</string>
<string name="lock_database_screen_off_title">Zámek obrazovky</string> <string name="lock_database_screen_off_title">Zámek obrazovky</string>
<string name="lock_database_screen_off_summary">Při zhasnutí obrazovky uzamknout databázi</string> <string name="lock_database_screen_off_summary">Při zhasnutí obrazovky uzamknout databázi</string>
<string name="advanced_unlock">Pokročilé odemčení</string> <string name="advanced_unlock">Rozšířené odemknutí</string>
<string name="biometric_unlock_enable_title">Biometrické odemčení</string> <string name="biometric_unlock_enable_title">Biometrické odemčení</string>
<string name="biometric_unlock_enable_summary">Nechá otevřít databázi snímáním biometrického údaje</string> <string name="biometric_unlock_enable_summary">Nechá otevřít databázi snímáním biometrického údaje</string>
<string name="biometric_delete_all_key_title">Smazat šifrovací klíče</string> <string name="biometric_delete_all_key_title">Smazat šifrovací klíče</string>
<string name="biometric_delete_all_key_summary">Smazat všechny šifrovací klíče související s rozpoznáním pokročilého odemknutí</string> <string name="biometric_delete_all_key_summary">Smazat všechny šifrovací klíče související s rozpoznáním rozšířeného odemknutí</string>
<string name="unavailable_feature_text">Tuto funkci se nedaří spustit.</string> <string name="unavailable_feature_text">Tuto funkci se nedaří spustit.</string>
<string name="unavailable_feature_version">V zařízení je instalován Android %1$s, ale potřebná je verze %2$s a novější.</string> <string name="unavailable_feature_version">V zařízení je instalován Android %1$s, ale potřebná je verze %2$s a novější.</string>
<string name="unavailable_feature_hardware">Hardware nebyl rozpoznán.</string> <string name="unavailable_feature_hardware">Hardware nebyl rozpoznán.</string>
@@ -353,10 +353,10 @@
<string name="content_description_update_from_list">Aktualizovat</string> <string name="content_description_update_from_list">Aktualizovat</string>
<string name="content_description_keyboard_close_fields">Zavři kolonky</string> <string name="content_description_keyboard_close_fields">Zavři kolonky</string>
<string name="error_create_database_file">Nelze vytvořit databázi s tímto heslem a klíčem ze souboru.</string> <string name="error_create_database_file">Nelze vytvořit databázi s tímto heslem a klíčem ze souboru.</string>
<string name="menu_advanced_unlock_settings">Pokročilé odemčení</string> <string name="menu_advanced_unlock_settings">Rozšířené odemknutí</string>
<string name="biometric">Biometrika</string> <string name="biometric">Biometrika</string>
<string name="biometric_auto_open_prompt_title">Automaticky otevřít pobídku</string> <string name="biometric_auto_open_prompt_title">Automaticky otevřít pobídku</string>
<string name="biometric_auto_open_prompt_summary">Automaticky žádat pokročilé odemknutí, je-li databáze nastavena k jejímu použití</string> <string name="biometric_auto_open_prompt_summary">Automaticky žádat rozšířené odemknutí, je-li databáze nastavena k jejímu použití</string>
<string name="enable">Zapnout</string> <string name="enable">Zapnout</string>
<string name="disable">Vypnout</string> <string name="disable">Vypnout</string>
<string name="master_key">Hlavní klíč</string> <string name="master_key">Hlavní klíč</string>
@@ -385,7 +385,7 @@
<string name="contains_duplicate_uuid_procedure">Opravit chybu založením nového UUID pro duplikáty a pokračovat\?</string> <string name="contains_duplicate_uuid_procedure">Opravit chybu založením nového UUID pro duplikáty a pokračovat\?</string>
<string name="database_opened">Databáze otevřena</string> <string name="database_opened">Databáze otevřena</string>
<string name="clipboard_explanation_summary">Kopírujte pole záznamů pomocí schránky Vašeho zařízení</string> <string name="clipboard_explanation_summary">Kopírujte pole záznamů pomocí schránky Vašeho zařízení</string>
<string name="advanced_unlock_explanation_summary">K snadnějšímu otevření databáze použijte pokročilé odemknutí</string> <string name="advanced_unlock_explanation_summary">K snadnějšímu otevření databáze použijte rozšířené odemknutí</string>
<string name="database_data_compression_title">Komprese dat</string> <string name="database_data_compression_title">Komprese dat</string>
<string name="database_data_compression_summary">Komprese dat snižuje velikost databáze</string> <string name="database_data_compression_summary">Komprese dat snižuje velikost databáze</string>
<string name="max_history_items_title">Maximální počet</string> <string name="max_history_items_title">Maximální počet</string>
@@ -517,20 +517,31 @@
<string name="select_entry">Vybrat záznam</string> <string name="select_entry">Vybrat záznam</string>
<string name="back_to_previous_keyboard">Zpět na předchozí klávesnici</string> <string name="back_to_previous_keyboard">Zpět na předchozí klávesnici</string>
<string name="custom_fields">Vlastní položky</string> <string name="custom_fields">Vlastní položky</string>
<string name="advanced_unlock_delete_all_key_warning">Smazat všechny šifrovací klíče související s rozpoznáním pokročilého odemknutí\?</string> <string name="advanced_unlock_delete_all_key_warning">Smazat všechny šifrovací klíče související s rozpoznáním rozšířeného odemknutí\?</string>
<string name="device_credential_unlock_enable_summary">Dovolí pro otevření databáze použít heslo Vašeho zařízení</string> <string name="device_credential_unlock_enable_summary">Dovolí pro otevření databáze použít heslo Vašeho zařízení</string>
<string name="device_credential_unlock_enable_title">Odemknutí heslem zařízení</string> <string name="device_credential_unlock_enable_title">Odemknutí heslem zařízení</string>
<string name="device_credential">Heslo zařízení</string> <string name="device_credential">Heslo zařízení</string>
<string name="credential_before_click_advanced_unlock_button">Zadejte heslo a klikněte na tlačítko \"Pokročilé odemknutí\".</string> <string name="credential_before_click_advanced_unlock_button">Zadejte heslo a klikněte na tlačítko \"Rozšířené odemknutí\".</string>
<string name="advanced_unlock_prompt_not_initialized">Nelze inicializovat pobídku pro pokročilé odemknutí.</string> <string name="advanced_unlock_prompt_not_initialized">Nelze inicializovat pobídku pro rozšířené odemknutí.</string>
<string name="advanced_unlock_scanning_error">Chyba při pokročilém odemknutí: %1$s</string> <string name="advanced_unlock_scanning_error">Chyba při rozšířeném odemknutí: %1$s</string>
<string name="advanced_unlock_not_recognized">Otisk pro pokročilé odemknutí nebyl rozpoznán</string> <string name="advanced_unlock_not_recognized">Otisk pro rozšířené odemknutí nebyl rozpoznán</string>
<string name="advanced_unlock_invalid_key">Nelze načíst klíč pokročilého odemknutí. Prosím, smažte jej a opakujte proces rozpoznání uzamknutí.</string> <string name="advanced_unlock_invalid_key">Nelze načíst klíč rozšířeného odemknutí. Prosím, smažte jej a opakujte proces rozpoznání odemknutí.</string>
<string name="advanced_unlock_prompt_extract_credential_message">Načíst důvěrný údaj pomocí dat pokročilého odemknutí</string> <string name="advanced_unlock_prompt_extract_credential_message">Načíst důvěrný údaj pomocí dat rozšířeného odemknutí</string>
<string name="advanced_unlock_prompt_extract_credential_title">Otevřít databázi pomocí rozpoznání pokročilého odemknutí</string> <string name="advanced_unlock_prompt_extract_credential_title">Otevřít databázi pomocí rozpoznání rozšířeného odemknutí</string>
<string name="advanced_unlock_prompt_store_credential_message">Varování: Pokud použijete rozpoznání pokročilého odemknutí, musíte si i nadále pamatovat hlavní heslo.</string> <string name="advanced_unlock_prompt_store_credential_message">Varování: Pokud použijete rozpoznání rozšířeného odemknutí, musíte si i nadále pamatovat hlavní heslo.</string>
<string name="advanced_unlock_prompt_store_credential_title">Rozpoznání pokročilého odemknutí</string> <string name="advanced_unlock_prompt_store_credential_title">Rozpoznání rozšířeného odemknutí</string>
<string name="open_advanced_unlock_prompt_store_credential">Pro uložení důvěrných údajů otevřete pobídku pokročilého odemknutí</string> <string name="open_advanced_unlock_prompt_store_credential">Pro uložení důvěrných údajů otevřete pobídku rozšířeného odemknutí</string>
<string name="open_advanced_unlock_prompt_unlock_database">Pro odemknutí databáze otevřete pobídku pokročilého odemknutí</string> <string name="open_advanced_unlock_prompt_unlock_database">Pro odemknutí databáze otevřete pobídku rozšířeného odemknutí</string>
<string name="menu_keystore_remove_key">Smazat klíč pokročilého odemknutí</string> <string name="menu_keystore_remove_key">Smazat klíč rozšířeného odemknutí</string>
<string name="education_advanced_unlock_title">Rozšířené odemknutí databáze</string>
<string name="advanced_unlock_timeout">Timeout rozšířeného odemknutí</string>
<string name="temp_advanced_unlock_timeout_summary">Trvání použití rozšířeného odemknutí než bude obsah téhož smazán</string>
<string name="temp_advanced_unlock_enable_summary">Za účelem rozšířeného odemknutí neukládat žádný šifrovaný obsah</string>
<string name="temp_advanced_unlock_enable_title">Přechodné rozšířené odemknutí</string>
<string name="advanced_unlock_tap_delete">Pro odstranění klíčů rozšířeného odemknutí klepnout</string>
<string name="kdf_Argon2id">Argon2id</string>
<string name="kdf_Argon2d">Argon2d</string>
<string name="education_advanced_unlock_summary">Abyste rychle odemknuli databázi, propojte své heslo s naskenovanou biometrikou nebo údaji zámku zařízení.</string>
<string name="temp_advanced_unlock_timeout_title">Vypršení pokročilého odemknutí</string>
<string name="content">Obsah</string>
</resources> </resources>

View File

@@ -118,8 +118,8 @@
<string name="never">Nie</string> <string name="never">Nie</string>
<string name="no_results">Keine Suchergebnisse</string> <string name="no_results">Keine Suchergebnisse</string>
<string name="no_url_handler">Bitte einen Webbrowser installieren, um diese URL zu öffnen.</string> <string name="no_url_handler">Bitte einen Webbrowser installieren, um diese URL zu öffnen.</string>
<string name="omit_backup_search_title">Papierkorb/Sicherung nicht durchsuchen</string> <string name="omit_backup_search_title">Recycle bin und Backup nicht durchsuchen</string>
<string name="omit_backup_search_summary">Die Gruppen „Sicherung“ und „Papierkorb“ werden bei der Suche nicht berücksichtigt</string> <string name="omit_backup_search_summary">Die Gruppen „Backup“ und „Recycle bin“ werden bei der Suche nicht berücksichtigt</string>
<string name="auto_focus_search_title">Schnellsuche</string> <string name="auto_focus_search_title">Schnellsuche</string>
<string name="auto_focus_search_summary">Beim Öffnen einer Datenbank eine Suche veranlassen</string> <string name="auto_focus_search_summary">Beim Öffnen einer Datenbank eine Suche veranlassen</string>
<string name="progress_create">Neue Datenbank anlegen </string> <string name="progress_create">Neue Datenbank anlegen </string>
@@ -218,7 +218,7 @@
<string name="autofill_explanation_summary">Automatisches Ausfüllen aktivieren, um schnell Formulare in anderen Apps auszufüllen</string> <string name="autofill_explanation_summary">Automatisches Ausfüllen aktivieren, um schnell Formulare in anderen Apps auszufüllen</string>
<string name="clipboard">Zwischenablage</string> <string name="clipboard">Zwischenablage</string>
<string name="biometric_delete_all_key_title">Verschlüsselungsschlüssel löschen</string> <string name="biometric_delete_all_key_title">Verschlüsselungsschlüssel löschen</string>
<string name="biometric_delete_all_key_summary">Alle mit der biometrischen Erkennung verbundenen Verschlüsselungsschlüssel löschen.</string> <string name="biometric_delete_all_key_summary">Lösche alle Verschlüsselungsschlüssel, die mit der erweiterten Entsperrerkennung zusammenhängen</string>
<string name="unavailable_feature_version">Auf dem Gerät läuft Android %1$s, eine Version ab %2$s wäre aber nötig.</string> <string name="unavailable_feature_version">Auf dem Gerät läuft Android %1$s, eine Version ab %2$s wäre aber nötig.</string>
<string name="unavailable_feature_hardware">Keine entsprechende Hardware.</string> <string name="unavailable_feature_hardware">Keine entsprechende Hardware.</string>
<string name="recycle_bin_title">Papierkorb-Nutzung</string> <string name="recycle_bin_title">Papierkorb-Nutzung</string>
@@ -231,7 +231,7 @@
<string name="database_description_title">Datenbankbeschreibung</string> <string name="database_description_title">Datenbankbeschreibung</string>
<string name="database_version_title">Datenbankversion</string> <string name="database_version_title">Datenbankversion</string>
<string name="text_appearance">Text</string> <string name="text_appearance">Text</string>
<string name="application_appearance">App</string> <string name="application_appearance">Interface</string>
<string name="other">Andere</string> <string name="other">Andere</string>
<string name="keyboard">Tastatur</string> <string name="keyboard">Tastatur</string>
<string name="magic_keyboard_title">Magikeyboard</string> <string name="magic_keyboard_title">Magikeyboard</string>
@@ -267,7 +267,7 @@
<string name="education_donation_title">Mitmachen</string> <string name="education_donation_title">Mitmachen</string>
<string name="education_donation_summary">Mithelfen, um Stabilität und Sicherheit zu verbessern und weitere Funktionen zu ermöglichen.</string> <string name="education_donation_summary">Mithelfen, um Stabilität und Sicherheit zu verbessern und weitere Funktionen zu ermöglichen.</string>
<string name="html_text_ad_free">Anders als viele andere Passwortmanager ist dieser &lt;strong&gt;werbefrei&lt;/strong&gt;, &lt;strong&gt;quelloffen&lt;/strong&gt; und unter einer &lt;strong&gt;Copyleft-Lizenz&lt;/strong&gt;. Es werden keine persönlichen Daten gesammelt, in welcher Form auch immer, unabhängig von der verwendeten Version (kostenlos oder Pro).</string> <string name="html_text_ad_free">Anders als viele andere Passwortmanager ist dieser &lt;strong&gt;werbefrei&lt;/strong&gt;, &lt;strong&gt;quelloffen&lt;/strong&gt; und unter einer &lt;strong&gt;Copyleft-Lizenz&lt;/strong&gt;. Es werden keine persönlichen Daten gesammelt, in welcher Form auch immer, unabhängig von der verwendeten Version (kostenlos oder Pro).</string>
<string name="html_text_buy_pro">Mit dem Kauf der Pro-Version erhält man Zugang zu diesem &lt;strong&gt;visuellen Stil&lt;/strong&gt; und unterstützt insbesondere &lt;strong&gt;die Umsetzung gemeinschaftlicher Projektarbeiten.&lt;/strong&gt;</string> <string name="html_text_buy_pro">Mit dem Kauf der Pro-Version erhalten Sie Zugriff auf diesen &lt;strong&gt;visuellen Stil&lt;/strong&gt; und unterstützen insbesondere &lt;strong&gt;die Umsetzung gemeinschaftlicher Projekte.&lt;/strong&gt;</string>
<string name="html_text_feature_generosity">Dieser &lt;strong&gt;visuelle Stil&lt;/strong&gt; wurde wegen Ihrer Großzügigkeit freigeschaltet.</string> <string name="html_text_feature_generosity">Dieser &lt;strong&gt;visuelle Stil&lt;/strong&gt; wurde wegen Ihrer Großzügigkeit freigeschaltet.</string>
<string name="html_text_donation">Um unsere Freiheit zu bewahren und immer aktiv zu bleiben, zählen wir auf Ihren &lt;strong&gt;Beitrag.&lt;/strong&gt;</string> <string name="html_text_donation">Um unsere Freiheit zu bewahren und immer aktiv zu bleiben, zählen wir auf Ihren &lt;strong&gt;Beitrag.&lt;/strong&gt;</string>
<string name="html_text_dev_feature">Diese Funktion ist &lt;strong&gt;in Entwicklung&lt;/strong&gt; und erfordert &lt;strong&gt;Ihren Beitrag&lt;/strong&gt;, um bald verfügbar zu sein.</string> <string name="html_text_dev_feature">Diese Funktion ist &lt;strong&gt;in Entwicklung&lt;/strong&gt; und erfordert &lt;strong&gt;Ihren Beitrag&lt;/strong&gt;, um bald verfügbar zu sein.</string>
@@ -276,7 +276,7 @@
<string name="html_text_dev_feature_encourage">Sie ermutigen die Entwickler:innen, &lt;strong&gt;neue Funktionen&lt;/strong&gt; einzuführen und gemäß Ihren Anmerkungen &lt;strong&gt;Fehler zu beheben&lt;/strong&gt;.</string> <string name="html_text_dev_feature_encourage">Sie ermutigen die Entwickler:innen, &lt;strong&gt;neue Funktionen&lt;/strong&gt; einzuführen und gemäß Ihren Anmerkungen &lt;strong&gt;Fehler zu beheben&lt;/strong&gt;.</string>
<string name="html_text_dev_feature_thanks">Vielen Dank für Ihre Unterstützung.</string> <string name="html_text_dev_feature_thanks">Vielen Dank für Ihre Unterstützung.</string>
<string name="html_text_dev_feature_work_hard">Wir bemühen uns, diese Funktion bald zu veröffentlichen.</string> <string name="html_text_dev_feature_work_hard">Wir bemühen uns, diese Funktion bald zu veröffentlichen.</string>
<string name="html_text_dev_feature_upgrade">Vergessen Sie nicht, Ihre Anwendung aktuell zu halten, indem Sie neue Versionen installieren.</string> <string name="html_text_dev_feature_upgrade">Denken Sie daran, Ihre App auf dem neuesten Stand zu halten, indem Sie neue Versionen installieren.</string>
<string name="download">Download</string> <string name="download">Download</string>
<string name="contribute">Unterstützen</string> <string name="contribute">Unterstützen</string>
<string name="encryption_chacha20">ChaCha20</string> <string name="encryption_chacha20">ChaCha20</string>
@@ -302,7 +302,7 @@
<string name="education_read_only_summary">Den Öffnungsmodus für die Sitzung ändern. <string name="education_read_only_summary">Den Öffnungsmodus für die Sitzung ändern.
\n \n
\n„Schreibgeschützt“ verhindert unbeabsichtigte Änderungen an der Datenbank. \n„Schreibgeschützt“ verhindert unbeabsichtigte Änderungen an der Datenbank.
\nMit „Änderbar“ können alle Elemente hinzugefügt, gelöscht oder geändert werden.</string> \nMit „Änderbar“ können Sie alle Elemente nach Belieben hinzufügen, löschen oder ändern.</string>
<string name="edit_entry">Eintrag bearbeiten</string> <string name="edit_entry">Eintrag bearbeiten</string>
<string name="error_load_database">Datenbank kann nicht geladen werden.</string> <string name="error_load_database">Datenbank kann nicht geladen werden.</string>
<string name="error_load_database_KDF_memory">Laden des Schlüssels fehlgeschlagen. Bitte versuchen, die „Speicherplatznutzung“ von KDF zu verringern.</string> <string name="error_load_database_KDF_memory">Laden des Schlüssels fehlgeschlagen. Bitte versuchen, die „Speicherplatznutzung“ von KDF zu verringern.</string>
@@ -336,7 +336,7 @@
<string name="show_recent_files_summary">Speicherort zuletzt verwendeter Datenbanken anzeigen</string> <string name="show_recent_files_summary">Speicherort zuletzt verwendeter Datenbanken anzeigen</string>
<string name="hide_broken_locations_title">Defekte Datenbankverknüpfungen ausblenden</string> <string name="hide_broken_locations_title">Defekte Datenbankverknüpfungen ausblenden</string>
<string name="hide_broken_locations_summary">Nicht funktionierende Verknüpfungen in der Liste der zuletzt verwendeten Datenbanken ausblenden</string> <string name="hide_broken_locations_summary">Nicht funktionierende Verknüpfungen in der Liste der zuletzt verwendeten Datenbanken ausblenden</string>
<string name="do_not_kill_app">Nicht die Anwendung beenden …</string> <string name="do_not_kill_app">App nicht beenden …</string>
<string name="lock_database_back_root_summary">Datenbank sperren, wenn auf dem Hauptbildschirm der Zurück-Button gedrückt wird</string> <string name="lock_database_back_root_summary">Datenbank sperren, wenn auf dem Hauptbildschirm der Zurück-Button gedrückt wird</string>
<string name="clear_clipboard_notification_title">Beim Schließen löschen</string> <string name="clear_clipboard_notification_title">Beim Schließen löschen</string>
<string name="recycle_bin">Papierkorb</string> <string name="recycle_bin">Papierkorb</string>
@@ -373,8 +373,8 @@
<string name="biometric">Biometrisch</string> <string name="biometric">Biometrisch</string>
<string name="enable">Aktivieren</string> <string name="enable">Aktivieren</string>
<string name="disable">Deaktivieren</string> <string name="disable">Deaktivieren</string>
<string name="biometric_auto_open_prompt_title">Biometrische Abfrage automatisch öffnen</string> <string name="biometric_auto_open_prompt_title">Abfrage automatisch öffnen</string>
<string name="biometric_auto_open_prompt_summary">Automatisch nach Biometrie fragen, wenn die Datenbank dafür eingerichtet ist</string> <string name="biometric_auto_open_prompt_summary">Automatisch nach der erweiterten Entsperrung fragen, wenn die Datenbank dafür eingerichtet ist</string>
<string name="master_key">Hauptschlüssel</string> <string name="master_key">Hauptschlüssel</string>
<string name="security">Sicherheit</string> <string name="security">Sicherheit</string>
<string name="entry_history">Verlauf</string> <string name="entry_history">Verlauf</string>
@@ -500,7 +500,7 @@
<string name="upload_attachment">%1$s hochladen</string> <string name="upload_attachment">%1$s hochladen</string>
<string name="education_add_attachment_title">Anhang hinzufügen</string> <string name="education_add_attachment_title">Anhang hinzufügen</string>
<string name="database_data_remove_unlinked_attachments_summary">Entfernt Anhänge die in der Datenbank enthalten, aber keinem Eintrag zugeordnet sind</string> <string name="database_data_remove_unlinked_attachments_summary">Entfernt Anhänge die in der Datenbank enthalten, aber keinem Eintrag zugeordnet sind</string>
<string name="warning_sure_add_file">Die Datei trotzdem hinzufügen\?</string> <string name="warning_sure_add_file">Soll die Datei trotzdem hinzugefügt werden\?</string>
<string name="show_uuid_summary">Zeigt die mit einem Eintrag verknüpfte UUID an</string> <string name="show_uuid_summary">Zeigt die mit einem Eintrag verknüpfte UUID an</string>
<string name="show_uuid_title">UUID anzeigen</string> <string name="show_uuid_title">UUID anzeigen</string>
<string name="autofill_read_only_save">Das Speichern von Daten ist für eine als schreibgeschützt geöffnete Datenbank nicht zulässig.</string> <string name="autofill_read_only_save">Das Speichern von Daten ist für eine als schreibgeschützt geöffnete Datenbank nicht zulässig.</string>
@@ -527,7 +527,7 @@
<string name="open_advanced_unlock_prompt_store_credential">Öffne den erweiterten Entsperrdialog zum Speichern von Anmeldeinformationen</string> <string name="open_advanced_unlock_prompt_store_credential">Öffne den erweiterten Entsperrdialog zum Speichern von Anmeldeinformationen</string>
<string name="open_advanced_unlock_prompt_unlock_database">Öffnen des erweiterten Entsperrdialogs zum Entsperren der Datenbank</string> <string name="open_advanced_unlock_prompt_unlock_database">Öffnen des erweiterten Entsperrdialogs zum Entsperren der Datenbank</string>
<string name="menu_keystore_remove_key">Löschen des Schlüssels zum erweiterten Entsperren</string> <string name="menu_keystore_remove_key">Löschen des Schlüssels zum erweiterten Entsperren</string>
<string name="advanced_unlock_prompt_store_credential_title">Fortschrittliche Entsperrerkennung</string> <string name="advanced_unlock_prompt_store_credential_title">Erweiterte Entsperrerkennung</string>
<string name="education_advanced_unlock_summary">Ihr Passwort verbinden mit Ihrem gescannten biometrischen oder berechtigen Gerät um schnell Ihre Datenbank zu entsperren.</string> <string name="education_advanced_unlock_summary">Ihr Passwort verbinden mit Ihrem gescannten biometrischen oder berechtigen Gerät um schnell Ihre Datenbank zu entsperren.</string>
<string name="education_advanced_unlock_title">Erweiterte Entsperrung der Datenbank</string> <string name="education_advanced_unlock_title">Erweiterte Entsperrung der Datenbank</string>
<string name="advanced_unlock_timeout">Verfallzeit der erweiterten Entsperrung</string> <string name="advanced_unlock_timeout">Verfallzeit der erweiterten Entsperrung</string>
@@ -535,16 +535,16 @@
<string name="temp_advanced_unlock_timeout_title">Verfall der erweiterten Entsperrung</string> <string name="temp_advanced_unlock_timeout_title">Verfall der erweiterten Entsperrung</string>
<string name="temp_advanced_unlock_enable_summary">Keinen verschlüsselten Inhalt speichern, um erweiterte Entsperrung zu benutzen</string> <string name="temp_advanced_unlock_enable_summary">Keinen verschlüsselten Inhalt speichern, um erweiterte Entsperrung zu benutzen</string>
<string name="temp_advanced_unlock_enable_title">Temporäre erweiterte Entsperrung</string> <string name="temp_advanced_unlock_enable_title">Temporäre erweiterte Entsperrung</string>
<string name="device_credential_unlock_enable_summary">Erlaubt Ihnn die Geräteanmeldedaten zum Öffnen der Datenbank zu verwenden</string> <string name="device_credential_unlock_enable_summary">Erlaubt Ihn die Geräteanmeldedaten zum Öffnen der Datenbank zu verwenden</string>
<string name="advanced_unlock_tap_delete">Drücken um erweiterte Entsperrschlüssel zu löschen</string> <string name="advanced_unlock_tap_delete">Drücken um erweiterte Entsperrschlüssel zu löschen</string>
<string name="content">Inhalt</string> <string name="content">Inhalt</string>
<string name="advanced_unlock_prompt_extract_credential_title">Öffne Datenbank mit fortgeschriitener Entsperrungs-Erkennung</string> <string name="advanced_unlock_prompt_extract_credential_title">Öffne Datenbank mit erweiterter Entsperrerkennung</string>
<string name="enter">Eingabetaste</string> <string name="enter">Eingabetaste</string>
<string name="backspace">Rücktaste</string> <string name="backspace">Rücktaste</string>
<string name="select_entry">Wähle Eintrag</string> <string name="select_entry">Wähle Eintrag</string>
<string name="back_to_previous_keyboard">Zurück zur vorherigen Tastatur</string> <string name="back_to_previous_keyboard">Zurück zur vorherigen Tastatur</string>
<string name="custom_fields">Benutzerdefinierte Felder</string> <string name="custom_fields">Benutzerdefinierte Felder</string>
<string name="advanced_unlock_delete_all_key_warning">Löschen aller Schlüssel in Zusammenhang mit Erkennung des erweiterterten Entsperrens\?</string> <string name="advanced_unlock_delete_all_key_warning">Alle Verschlüsselungsschlüssel, die mit der erweiterten Entsperrerkennung zusammenhängen, löschen\?</string>
<string name="device_credential_unlock_enable_title">Geräteanmeldedaten entsperren</string> <string name="device_credential_unlock_enable_title">Geräteanmeldedaten entsperren</string>
<string name="device_credential">Geräteanmeldedaten</string> <string name="device_credential">Geräteanmeldedaten</string>
<string name="credential_before_click_advanced_unlock_button">Geben sie das Passwort ein, und dann klicken sie den \"Erweitertes Entsperren\" Knopf.</string> <string name="credential_before_click_advanced_unlock_button">Geben sie das Passwort ein, und dann klicken sie den \"Erweitertes Entsperren\" Knopf.</string>
@@ -553,4 +553,6 @@
<string name="advanced_unlock_not_recognized">Konnte den Abdruck des erweiterten Entsperrens nicht erkennen</string> <string name="advanced_unlock_not_recognized">Konnte den Abdruck des erweiterten Entsperrens nicht erkennen</string>
<string name="advanced_unlock_invalid_key">Kann den Schlüssel zum erweiterten Entsperren nicht lesen. Bitte löschen sie ihn und wiederholen sie Prozedur zum Erkennen des Entsperrens.</string> <string name="advanced_unlock_invalid_key">Kann den Schlüssel zum erweiterten Entsperren nicht lesen. Bitte löschen sie ihn und wiederholen sie Prozedur zum Erkennen des Entsperrens.</string>
<string name="advanced_unlock_prompt_extract_credential_message">Extrahiere Datenbankanmeldedaten mit Daten aus erweitertem Entsperren</string> <string name="advanced_unlock_prompt_extract_credential_message">Extrahiere Datenbankanmeldedaten mit Daten aus erweitertem Entsperren</string>
<string name="kdf_Argon2id">Argon2id</string>
<string name="kdf_Argon2d">Argon2d</string>
</resources> </resources>

View File

@@ -541,4 +541,6 @@
<string name="temp_advanced_unlock_timeout_title">Λήξη προηγμένου ξεκλειδώματος</string> <string name="temp_advanced_unlock_timeout_title">Λήξη προηγμένου ξεκλειδώματος</string>
<string name="advanced_unlock_tap_delete">Πατήστε για διαγραφή προηγμένων κλειδιών ξεκλειδώματος</string> <string name="advanced_unlock_tap_delete">Πατήστε για διαγραφή προηγμένων κλειδιών ξεκλειδώματος</string>
<string name="content">Περιεχόμενα</string> <string name="content">Περιεχόμενα</string>
<string name="kdf_Argon2id">Argon2id</string>
<string name="kdf_Argon2d">Argon2d</string>
</resources> </resources>

View File

@@ -19,9 +19,9 @@
Spanish translation by José I. Paños. Updated by David García-Abad (23-09-2013) Spanish translation by José I. Paños. Updated by David García-Abad (23-09-2013)
--><resources> --><resources>
<string name="feedback">Commentario</string> <string name="feedback">Comentarios</string>
<string name="homepage">Página de inicio</string> <string name="homepage">Página de inicio</string>
<string name="about_description">Implementación para Android del gestor de contraseñas KeePass</string> <string name="about_description">Implementación en Android del gestor de contraseñas KeePass</string>
<string name="accept">Aceptar</string> <string name="accept">Aceptar</string>
<string name="add_entry">Añadir entrada</string> <string name="add_entry">Añadir entrada</string>
<string name="add_group">Añadir grupo</string> <string name="add_group">Añadir grupo</string>
@@ -31,30 +31,30 @@
<string name="application">Aplicación</string> <string name="application">Aplicación</string>
<string name="menu_app_settings">Configuración de la aplicación</string> <string name="menu_app_settings">Configuración de la aplicación</string>
<string name="brackets">Paréntesis</string> <string name="brackets">Paréntesis</string>
<string name="file_manager_install_description">Explora ficheros con OpenIntents File Manager</string> <string name="file_manager_install_description">Se requiere un administrador de archivos que acepte la acciones de intención ACTION_CREATE_DOCUMENT y ACTION_OPEN_DOCUMENT para crear, abrir y guardar los archivos de la base de datos.</string>
<string name="clipboard_cleared">Portapapeles limpiado</string> <string name="clipboard_cleared">Portapapeles limpiado</string>
<string name="clipboard_timeout">Portapapeles caducado</string> <string name="clipboard_timeout">Portapapeles caducado</string>
<string name="clipboard_timeout_summary">Duración del almacenamiento en el portapapeles (si lo admite el dispositivo)</string> <string name="clipboard_timeout_summary">Duración del almacenamiento en el portapapeles (si lo admite su dispositivo)</string>
<string name="select_to_copy">Seleccionar para copiar %1$s en el portapapeles</string> <string name="select_to_copy">Seleccionar para copiar %1$s en el portapapeles</string>
<string name="retrieving_db_key">Creando clave de la base de datos…</string> <string name="retrieving_db_key">Recuperando la clave de la base de datos…</string>
<string name="database">Base de datos</string> <string name="database">Base de datos</string>
<string name="decrypting_db">Descifrando el contenido de la base de datos…</string> <string name="decrypting_db">Descifrando el contenido de la base de datos…</string>
<string name="default_checkbox">Utilice como base de datos por defecto</string> <string name="default_checkbox">Utilizar como base de datos por defecto</string>
<string name="digits">Dígitos</string> <string name="digits">Dígitos</string>
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft es \u0020de &lt;strong&gt;código abierto&lt;/strong&gt; y &lt;strong&gt;sin publicidad&lt;/strong&gt;. <string name="html_about_licence">KeePassDX © %1$d Kunzisoft es de &lt;strong&gt;código abierto&lt;/strong&gt; y &lt;strong&gt;sin publicidad&lt;/strong&gt;.
\nSe proporciona tal cual, bajo licencia &lt;strong&gt;GPLv3&lt;/strong&gt;, sin ninguna garantía.</string> \nSe proporciona tal cual, bajo licencia &lt;strong&gt;GPLv3&lt;/strong&gt;, sin ninguna garantía.</string>
<string name="select_database_file">Abrir base de datos existente</string> <string name="select_database_file">Abrir base de datos existente</string>
<string name="entry_accessed">Acceso</string> <string name="entry_accessed">Accedido</string>
<string name="entry_cancel">Cancelar</string> <string name="entry_cancel">Cancelar</string>
<string name="entry_notes">Notas</string> <string name="entry_notes">Notas</string>
<string name="entry_confpassword">Confirmar contraseña</string> <string name="entry_confpassword">Confirmar contraseña</string>
<string name="entry_created">Creación</string> <string name="entry_created">Creado</string>
<string name="entry_expires">Caducidad</string> <string name="entry_expires">Caduca</string>
<string name="entry_keyfile">Archivo de clave</string> <string name="entry_keyfile">Archivo de clave</string>
<string name="entry_modified">Modificación</string> <string name="entry_modified">Modificada</string>
<string name="entry_password">Contraseña</string> <string name="entry_password">Contraseña</string>
<string name="save">Guardar</string> <string name="save">Guardar</string>
<string name="entry_title">Nombre</string> <string name="entry_title">Título</string>
<string name="entry_url">URL</string> <string name="entry_url">URL</string>
<string name="entry_user_name">Nombre de usuario</string> <string name="entry_user_name">Nombre de usuario</string>
<string name="error_arc4">No se admite el cifrador de flujo Arcfour.</string> <string name="error_arc4">No se admite el cifrador de flujo Arcfour.</string>
@@ -64,11 +64,11 @@
<string name="error_invalid_path">Asegúrese de que la ruta sea correcta.</string> <string name="error_invalid_path">Asegúrese de que la ruta sea correcta.</string>
<string name="error_no_name">Proporcione un nombre.</string> <string name="error_no_name">Proporcione un nombre.</string>
<string name="error_nokeyfile">Seleccione un archivo de clave.</string> <string name="error_nokeyfile">Seleccione un archivo de clave.</string>
<string name="error_out_of_memory">No queda memoria para cargar toda la base de datos.</string> <string name="error_out_of_memory">No hay memoria para cargar toda la base de datos.</string>
<string name="error_pass_gen_type">Debe seleccionar al menos un tipo de generación de contraseñas.</string> <string name="error_pass_gen_type">Debe seleccionar al menos un tipo de generación de contraseñas.</string>
<string name="error_pass_match">Las contraseñas no coinciden.</string> <string name="error_pass_match">Las contraseñas no coinciden.</string>
<string name="error_rounds_too_large">Pasadas demasiado grande. Establecido a 2147483648.</string> <string name="error_rounds_too_large">Pasadas demasiado grande. Establecido a 2147483648.</string>
<string name="error_wrong_length">Proporcione un número entero positivo en el campo «Longitud».</string> <string name="error_wrong_length">Introduzca un número entero positivo en el campo \"Longitud\".</string>
<string name="file_browser">Explorador de archivos</string> <string name="file_browser">Explorador de archivos</string>
<string name="generate_password">Generar contraseña</string> <string name="generate_password">Generar contraseña</string>
<string name="hint_conf_pass">Confirmar contraseña</string> <string name="hint_conf_pass">Confirmar contraseña</string>
@@ -78,7 +78,7 @@
<string name="hint_length">Longitud</string> <string name="hint_length">Longitud</string>
<string name="password">Contraseña</string> <string name="password">Contraseña</string>
<string name="hint_pass">Contraseña</string> <string name="hint_pass">Contraseña</string>
<string name="invalid_credentials">Contraseña o archivo de clave no válido.</string> <string name="invalid_credentials">No se pudieron leer las credenciales.</string>
<string name="invalid_db_sig">No se pudo reconocer el formato de la base de datos.</string> <string name="invalid_db_sig">No se pudo reconocer el formato de la base de datos.</string>
<string name="length">Longitud</string> <string name="length">Longitud</string>
<string name="list_size_title">Tamaño de los elementos de la lista</string> <string name="list_size_title">Tamaño de los elementos de la lista</string>
@@ -103,7 +103,7 @@
<string name="minus">Menos</string> <string name="minus">Menos</string>
<string name="never">Nunca</string> <string name="never">Nunca</string>
<string name="no_results">Sin resultado de búsqueda</string> <string name="no_results">Sin resultado de búsqueda</string>
<string name="no_url_handler">Instale un navegador web para abrir este URL.</string> <string name="no_url_handler">Instale un navegador web para abrir esta URL.</string>
<string name="omit_backup_search_title">No buscar en las entradas de respaldo</string> <string name="omit_backup_search_title">No buscar en las entradas de respaldo</string>
<string name="omit_backup_search_summary">Omite los grupos «Respaldo» y «Papelera de reciclaje» de los resultados de búsqueda</string> <string name="omit_backup_search_summary">Omite los grupos «Respaldo» y «Papelera de reciclaje» de los resultados de búsqueda</string>
<string name="progress_create">Creando nueva base de datos…</string> <string name="progress_create">Creando nueva base de datos…</string>
@@ -124,7 +124,9 @@
<string name="unsupported_db_version">No se admite esta versión de la base de datos.</string> <string name="unsupported_db_version">No se admite esta versión de la base de datos.</string>
<string name="uppercase">Mayúsculas</string> <string name="uppercase">Mayúsculas</string>
<string name="version_label">Versión %1$s</string> <string name="version_label">Versión %1$s</string>
<string name="education_unlock_summary">Introduzca una contraseña y/o un archivo de clave para desbloquear su base de datos.</string> <string name="education_unlock_summary">Introduzca la contraseña y/o el archivo clave para desbloquear su base de datos.
\n
\nHaga una copia de seguridad de su archivo de base de datos en un lugar seguro después de cada cambio.</string>
<string-array name="timeout_options"> <string-array name="timeout_options">
<item>5 segundos</item> <item>5 segundos</item>
<item>10 segundos</item> <item>10 segundos</item>
@@ -146,28 +148,28 @@
<string name="extended_ASCII">ASCII extendido</string> <string name="extended_ASCII">ASCII extendido</string>
<string name="allow">Permitir</string> <string name="allow">Permitir</string>
<string name="clipboard_error_title">Error del portapapeles</string> <string name="clipboard_error_title">Error del portapapeles</string>
<string name="clipboard_error">Algunos dispositivos Android tienen un error en la implementación del portapapeles que provoca fallos al copiar desde las aplicaciones.</string> <string name="clipboard_error">Algunos dispositivos no permiten que las aplicaciones usen el portapapeles.</string>
<string name="clipboard_error_clear">Falló la limpieza del portapapeles</string> <string name="clipboard_error_clear">No se pudo limpiar el portapapeles</string>
<string name="error_string_key">Cada cadena debe tener un nombre de campo.</string> <string name="error_string_key">Cada cadena debe tener un nombre de campo.</string>
<string name="error_autofill_enable_service">El servicio de autocompletado no se ha podido habilitar.</string> <string name="error_autofill_enable_service">El servicio de autocompletado no se ha podido habilitar.</string>
<string name="field_name">Nombre del campo</string> <string name="field_name">Nombre del campo</string>
<string name="field_value">Valor del campo</string> <string name="field_value">Valor del campo</string>
<string name="file_not_found_content">No se pudo encontrar el archivo. Intente volver a abrirlo en el explorador de archivos.</string> <string name="file_not_found_content">No se pudo encontrar el archivo. Intente volver a abrirlo en el explorador de archivos.</string>
<string name="invalid_algorithm">El algoritmo es incorrecto.</string> <string name="invalid_algorithm">Algoritmo incorrecto.</string>
<string name="keyfile_is_empty">El archivo de clave está vacío.</string> <string name="keyfile_is_empty">El archivo de clave está vacío.</string>
<string name="copy_field">Copia de %1$s</string> <string name="copy_field">Copia de %1$s</string>
<string name="menu_form_filling_settings">Llenado de formulario</string> <string name="menu_form_filling_settings">Llenado de formulario</string>
<string name="protection">Protección</string> <string name="protection">Protección</string>
<string name="read_only">Protegida contra escritura</string> <string name="read_only">Protegida contra escritura</string>
<string name="read_only_warning">KeePassDX necesita permiso de escritura para modificar la base de datos.</string> <string name="read_only_warning">Dependiendo del administrador de archivos, puede que KeePassDX no permita escribir en su almacenamiento.</string>
<string name="encryption_explanation">Algoritmo de cifrado utilizado en todos los datos.</string> <string name="encryption_explanation">Algoritmo de cifrado utilizado para todos los datos.</string>
<string name="kdf_explanation">Para generar la clave del algoritmo de cifrado, la clave maestra se transforma mediante una función de derivación de claves con una sal aleatoria.</string> <string name="kdf_explanation">Para generar la clave del algoritmo de cifrado, la clave maestra se transforma mediante una función de derivación de claves con una sal aleatoria.</string>
<string name="memory_usage">Uso de memoria</string> <string name="memory_usage">Uso de memoria</string>
<string name="memory_usage_explanation">Cantidad de memoria (en bytes) que usará la función de derivación de clave.</string> <string name="memory_usage_explanation">Cantidad de memoria (en bytes) que usará la función de derivación de clave.</string>
<string name="parallelism">Paralelismo</string> <string name="parallelism">Paralelismo</string>
<string name="parallelism_explanation">Grado de paralelismo (p. ej. número de hilos) usados por la función de derivación de clave.</string> <string name="parallelism_explanation">Grado de paralelismo (p. ej. número de hilos) usados por la función de derivación de clave.</string>
<string name="sort_menu">Ordenar</string> <string name="sort_menu">Ordenar</string>
<string name="sort_ascending">Inferiores primero ↓</string> <string name="sort_ascending">Más bajo primero ↓</string>
<string name="sort_groups_before">Agrupar antes</string> <string name="sort_groups_before">Agrupar antes</string>
<string name="sort_recycle_bin_bottom">Papelera debajo</string> <string name="sort_recycle_bin_bottom">Papelera debajo</string>
<string name="sort_title">Título</string> <string name="sort_title">Título</string>
@@ -177,8 +179,8 @@
<string name="sort_last_access_time">Acceso</string> <string name="sort_last_access_time">Acceso</string>
<string name="search_results">Resultados de búsqueda</string> <string name="search_results">Resultados de búsqueda</string>
<string name="warning">Atención</string> <string name="warning">Atención</string>
<string name="entry_not_found">Datos de entrada no encontrados.</string> <string name="entry_not_found">No se pudieron encontrar los datos de entrada.</string>
<string name="warning_password_encoding">Evite emplear en la base de datos caracteres que no pertenezcan al formato de codificación del texto (los caracteres no reconocidos se convierten a la misma letra).</string> <string name="warning_password_encoding">Evite los caracteres de la contraseña fuera del formato de codificación de texto en el archivo de la base de datos (los caracteres no reconocidos se convierten a la misma letra).</string>
<string name="warning_empty_password">¿Continuar sin la protección de desbloqueo de contraseña\?</string> <string name="warning_empty_password">¿Continuar sin la protección de desbloqueo de contraseña\?</string>
<string name="warning_no_encryption_key">¿Continuar sin clave de cifrado\?</string> <string name="warning_no_encryption_key">¿Continuar sin clave de cifrado\?</string>
<string name="encrypted_value_stored">Contraseña cifrada almacenada</string> <string name="encrypted_value_stored">Contraseña cifrada almacenada</string>
@@ -197,25 +199,25 @@
<string name="list_password_generator_options_summary">Establecer los caracteres permitidos del generador de contraseñas</string> <string name="list_password_generator_options_summary">Establecer los caracteres permitidos del generador de contraseñas</string>
<string name="clipboard">Portapapeles</string> <string name="clipboard">Portapapeles</string>
<string name="clipboard_notifications_title">Notificaciones del portapapeles</string> <string name="clipboard_notifications_title">Notificaciones del portapapeles</string>
<string name="clipboard_notifications_summary">Mostrar notificaciones del portapapeles para copiar campos al examinar una entrada</string> <string name="clipboard_notifications_summary">Mostrar las notificaciones del portapapeles para copiar campos al examinar una entrada</string>
<string name="lock">Bloquear</string> <string name="lock">Bloquear</string>
<string name="lock_database_screen_off_title">Bloqueo de pantalla</string> <string name="lock_database_screen_off_title">Bloqueo de pantalla</string>
<string name="lock_database_screen_off_summary">Bloquear la base de datos cuando la pantalla esté apagada</string> <string name="lock_database_screen_off_summary">Bloquear la base de datos cuando la pantalla esté apagada</string>
<string name="advanced_unlock">Desbloqueo avanzado</string> <string name="advanced_unlock">Desbloqueo avanzado</string>
<string name="biometric_unlock_enable_title">Desbloqueo biométrico</string> <string name="biometric_unlock_enable_title">Desbloqueo biométrico</string>
<string name="biometric_unlock_enable_summary">Le permite escanear su huella dactilar u otro dato biométrico para abrir la base de datos</string> <string name="biometric_unlock_enable_summary">Le permite escanear sus datos biométricos para abrir la base de datos</string>
<string name="biometric_delete_all_key_title">Eliminar claves de cifrado</string> <string name="biometric_delete_all_key_title">Eliminar claves de cifrado</string>
<string name="biometric_delete_all_key_summary">Eliminar todas las claves de cifrado relacionadas con el reconocimiento biométrico</string> <string name="biometric_delete_all_key_summary">Eliminar todas las claves de cifrado relacionadas con el reconocimiento de desbloqueo avanzado</string>
<string name="unavailable_feature_text">No se pudo iniciar esta funcionalidad.</string> <string name="unavailable_feature_text">No se pudo iniciar esta funcionalidad.</string>
<string name="unavailable_feature_version">La versión de Android del dispositivo es %1$s, pero es necesaria la %2$s o posterior.</string> <string name="unavailable_feature_version">El dispositivo funciona con Android %1$s, pero necesita %2$s o posterior.</string>
<string name="unavailable_feature_hardware">No se encontró el hardware correspondiente.</string> <string name="unavailable_feature_hardware">No se pudo encontrar el hardware correspondiente.</string>
<string name="file_name">Nombre del archivo</string> <string name="file_name">Nombre del archivo</string>
<string name="path">Ruta</string> <string name="path">Ruta</string>
<string name="assign_master_key">Asignar una clave maestra</string> <string name="assign_master_key">Asignar una clave maestra</string>
<string name="create_keepass_file">Crear base de datos nueva</string> <string name="create_keepass_file">Crear una base de datos nueva</string>
<string name="recycle_bin_title">Uso de la papelera de reciclaje</string> <string name="recycle_bin_title">Uso de la papelera de reciclaje</string>
<string name="recycle_bin_summary">Mueve los grupos y las entradas al grupo \"Papelera de reciclaje\" antes de eliminarlos</string> <string name="recycle_bin_summary">Mueve los grupos y las entradas al grupo \"Papelera de reciclaje\" antes de eliminarlos</string>
<string name="monospace_font_fields_enable_title">Fuente de los campos</string> <string name="monospace_font_fields_enable_title">Tipografía del campo</string>
<string name="monospace_font_fields_enable_summary">Cambiar la fuente de los campos para una mejor visibilidad del carácter</string> <string name="monospace_font_fields_enable_summary">Cambiar la fuente de los campos para una mejor visibilidad del carácter</string>
<string name="allow_copy_password_title">Portapapeles de confianza</string> <string name="allow_copy_password_title">Portapapeles de confianza</string>
<string name="allow_copy_password_summary">Permitir copiar la contraseña de entrada y los campos protegidos al portapapeles</string> <string name="allow_copy_password_summary">Permitir copiar la contraseña de entrada y los campos protegidos al portapapeles</string>
@@ -223,11 +225,11 @@
<string name="database_description_title">Descripción de la base de datos</string> <string name="database_description_title">Descripción de la base de datos</string>
<string name="database_version_title">Versión de la base de datos</string> <string name="database_version_title">Versión de la base de datos</string>
<string name="text_appearance">Texto</string> <string name="text_appearance">Texto</string>
<string name="application_appearance">Aplicación</string> <string name="application_appearance">Interfaz</string>
<string name="other">Otro</string> <string name="other">Otro</string>
<string name="keyboard">Teclado</string> <string name="keyboard">Teclado</string>
<string name="magic_keyboard_title">Teclado mágico</string> <string name="magic_keyboard_title">Teclado mágico</string>
<string name="magic_keyboard_explanation_summary">Active un teclado personalizado que llene sus contraseñas y todos los campos de identidad fácilmente.</string> <string name="magic_keyboard_explanation_summary">Active un teclado personalizado que llene sus contraseñas y todos los campos de identidad fácilmente</string>
<string name="reset_education_screens_title">Restablecer sugerencias didácticas</string> <string name="reset_education_screens_title">Restablecer sugerencias didácticas</string>
<string name="reset_education_screens_summary">Mostrar de nuevo toda la información didáctica</string> <string name="reset_education_screens_summary">Mostrar de nuevo toda la información didáctica</string>
<string name="reset_education_screens_text">Se restablecieron las sugerencias didácticas</string> <string name="reset_education_screens_text">Se restablecieron las sugerencias didácticas</string>
@@ -259,20 +261,20 @@
<string name="education_donation_title">Participar</string> <string name="education_donation_title">Participar</string>
<string name="education_donation_summary">Participe para aumentar la estabilidad, la seguridad y agregar más funciones.</string> <string name="education_donation_summary">Participe para aumentar la estabilidad, la seguridad y agregar más funciones.</string>
<string name="html_text_ad_free">A diferencia de muchas aplicaciones de administración de contraseñas, esta es &lt;strong&gt;sin publicidad&lt;/strong&gt;, &lt;strong&gt;software libre con copyleft&lt;/strong&gt; y no recopila datos personales en sus servidores, sin importar la versión que use.</string> <string name="html_text_ad_free">A diferencia de muchas aplicaciones de administración de contraseñas, esta es &lt;strong&gt;sin publicidad&lt;/strong&gt;, &lt;strong&gt;software libre con copyleft&lt;/strong&gt; y no recopila datos personales en sus servidores, sin importar la versión que use.</string>
<string name="html_text_buy_pro">Al comprar la versión pro, tendrá acceso a &lt;strong&gt;la característica visual &lt;/strong&gt;y usted ayudará especialmente a &lt;strong&gt;la realización de proyectos comunitarios.&lt;/strong&gt;</string> <string name="html_text_buy_pro">Al comprar la versión pro, tendrá acceso al &lt;strong&gt;estilo visual &lt;/strong&gt;y ayudará especialmente a &lt;strong&gt;la realización de proyectos comunitarios.&lt;/strong&gt;</string>
<string name="html_text_feature_generosity">Esta &lt;strong&gt;característica visual &lt;/strong&gt;está disponible gracias a tu generosidad.</string> <string name="html_text_feature_generosity">Este &lt;strong&gt;estilo visual &lt;/strong&gt;está disponible gracias a tu generosidad.</string>
<string name="html_text_donation">Para mantener nuestra libertad y estar siempre vigente, contamos con tu &lt;strong&gt;contribución.&lt;/strong&gt;</string> <string name="html_text_donation">Para mantener nuestra libertad y estar siempre vigente, contamos con tu &lt;strong&gt;contribución.&lt;/strong&gt;</string>
<string name="html_text_dev_feature">Esta función está &lt;strong&gt;en desarrollo&lt;/strong&gt; y requiere de tu &lt;strong&gt;contribución&lt;/strong&gt; para estar disponible dentro de poco.</string> <string name="html_text_dev_feature">Esta función está &lt;strong&gt;en desarrollo&lt;/strong&gt; y requiere de tu &lt;strong&gt;contribución&lt;/strong&gt; para estar disponible dentro de poco.</string>
<string name="html_text_dev_feature_buy_pro">Al comprar la versión &lt;strong&gt;pro&lt;/strong&gt;,</string> <string name="html_text_dev_feature_buy_pro">Al comprar la versión &lt;strong&gt;pro&lt;/strong&gt;,</string>
<string name="html_text_dev_feature_contibute">Al &lt;strong&gt;contribuir&lt;/strong&gt;,</string> <string name="html_text_dev_feature_contibute">Al &lt;strong&gt;contribuir&lt;/strong&gt;,</string>
<string name="html_text_dev_feature_encourage">usted alienta a los desarrolladores a crear &lt;strong&gt;nuevas funciones&lt;/strong&gt; y a &lt;strong&gt;errores de configuración&lt;/strong&gt; de acuerdo con tus comentarios.</string> <string name="html_text_dev_feature_encourage">anima a los desarrolladores a crear &lt;strong&gt;nuevas funciones&lt;/strong&gt; y a &lt;strong&gt;corregir errores&lt;/strong&gt; de acuerdo con sus comentarios.</string>
<string name="html_text_dev_feature_thanks">Muchas gracias por tu contribución.</string> <string name="html_text_dev_feature_thanks">Muchas gracias por tu contribución.</string>
<string name="html_text_dev_feature_work_hard">Estamos trabajando duro para lanzar esta característica rápidamente.</string> <string name="html_text_dev_feature_work_hard">Estamos trabajando duro para lanzar esta característica rápidamente.</string>
<string name="html_text_dev_feature_upgrade">No olvide mantener su aplicación actualizada.</string> <string name="html_text_dev_feature_upgrade">Recuerde mantener su aplicación actualizada instalando nuevas versiones.</string>
<string name="download">Descargar</string> <string name="download">Descargar</string>
<string name="contribute">Contribuir</string> <string name="contribute">Contribuir</string>
<string name="encryption_chacha20">ChaCha20</string> <string name="encryption_chacha20">ChaCha20</string>
<string name="kdf_AES">AES-KDF</string> <string name="kdf_AES">AES</string>
<string name="style_choose_title">Tema de aplicación</string> <string name="style_choose_title">Tema de aplicación</string>
<string name="style_choose_summary">Tema utilizado en la aplicación</string> <string name="style_choose_summary">Tema utilizado en la aplicación</string>
<string name="icon_pack_choose_title">Seleccione un paquete de iconos</string> <string name="icon_pack_choose_title">Seleccione un paquete de iconos</string>
@@ -280,7 +282,7 @@
<string name="edit_entry">Editar entrada</string> <string name="edit_entry">Editar entrada</string>
<string name="error_load_database">No se pudo cargar la base de datos.</string> <string name="error_load_database">No se pudo cargar la base de datos.</string>
<string name="error_load_database_KDF_memory">No se pudo cargar la clave. Intente disminuir el uso de memoria de KDF.</string> <string name="error_load_database_KDF_memory">No se pudo cargar la clave. Intente disminuir el uso de memoria de KDF.</string>
<string name="error_move_folder_in_itself">No se puede mover un grupo dentro de sí mismo.</string> <string name="error_move_folder_in_itself">No puede mover un grupo dentro de sí mismo.</string>
<string name="list_entries_show_username_title">Enseña nombres de usuario</string> <string name="list_entries_show_username_title">Enseña nombres de usuario</string>
<string name="list_entries_show_username_summary">Enseña nombres de usuador en las listras de entradas</string> <string name="list_entries_show_username_summary">Enseña nombres de usuador en las listras de entradas</string>
<string name="menu_copy">Copiar</string> <string name="menu_copy">Copiar</string>
@@ -291,13 +293,13 @@
<string name="menu_open_file_read_and_write">Modificable</string> <string name="menu_open_file_read_and_write">Modificable</string>
<string name="build_label">Compilación %1$s</string> <string name="build_label">Compilación %1$s</string>
<string name="clipboard_warning">Si la eliminación del cortapapeles falla, elimine su historial manualmente.</string> <string name="clipboard_warning">Si la eliminación del cortapapeles falla, elimine su historial manualmente.</string>
<string name="allow_copy_password_warning">ATENCIÓN: todas las aplicaciones comparten el portapapeles. Si copia datos confidenciales, otros programas podrían recuperarlos.</string> <string name="allow_copy_password_warning">Advertencia: El portapapeles es compartido por todas las aplicaciones. Si se copian datos sensibles, otros programas pueden recuperarlos.</string>
<string name="allow_no_password_title">No permitir claves maestras</string> <string name="allow_no_password_title">No permitir claves maestras</string>
<string name="allow_no_password_summary">Activar el botón «Abrir» si no se selecciona ninguna credencial</string> <string name="allow_no_password_summary">Permite pulsar el botón \"Abrir\" si no se seleccionan credenciales</string>
<string name="enable_education_screens_title">Pantallas didácticas</string> <string name="enable_education_screens_title">Sugerencias educativas</string>
<string name="enable_education_screens_summary">Resaltar los elementos para conocer cómo funciona la aplicación</string> <string name="enable_education_screens_summary">Destacar elementos para aprender cómo funciona la aplicación</string>
<string name="enable_read_only_title">Protegida contra escritura</string> <string name="enable_read_only_title">Protegida contra escritura</string>
<string name="enable_read_only_summary">Abrir su base de datos protegida contra escritura de manera predeterminada</string> <string name="enable_read_only_summary">Abrir la base de datos de solo lectura por defecto</string>
<string name="education_read_only_title">Proteja la base de datos contra escritura</string> <string name="education_read_only_title">Proteja la base de datos contra escritura</string>
<string name="keyboard_name">Teclado mágico</string> <string name="keyboard_name">Teclado mágico</string>
<string name="keyboard_label">Teclado mágico (KeePassDX)</string> <string name="keyboard_label">Teclado mágico (KeePassDX)</string>
@@ -315,56 +317,56 @@
<string name="keyboard_appearance_category">Apariencia</string> <string name="keyboard_appearance_category">Apariencia</string>
<string name="keyboard_theme_title">Tema del teclado</string> <string name="keyboard_theme_title">Tema del teclado</string>
<string name="keyboard_keys_category">Teclas</string> <string name="keyboard_keys_category">Teclas</string>
<string name="keyboard_key_vibrate_title">Vibrar al pulsar</string> <string name="keyboard_key_vibrate_title">Vibrar al pulsar tecla</string>
<string name="keyboard_key_sound_title">Emitir sonido al pulsar</string> <string name="keyboard_key_sound_title">Sonar al pulsar tecla</string>
<string name="selection_mode">Modo de selección</string> <string name="selection_mode">Modo de selección</string>
<string name="do_not_kill_app">No cierre la aplicación…</string> <string name="do_not_kill_app">No cierre la aplicación…</string>
<string name="lock_database_back_root_summary">Bloquear la base de datos cuando se pulsa el botón Atrás en la pantalla inicial</string> <string name="lock_database_back_root_summary">Bloquear la base de datos cuando el usuario pulse el botón atrás en la pantalla inicial</string>
<string name="clear_clipboard_notification_title">Vaciar al cerrar</string> <string name="clear_clipboard_notification_title">Vaciar al cerrar</string>
<string name="clear_clipboard_notification_summary">Bloquear la base de datos cuando la duración del portapapeles expire o la notificación sea cerrada</string> <string name="clear_clipboard_notification_summary">Bloquear la base de datos cuando expire la duración del portapapeles o cuando se cierre la notificación después de empezar a utilizarla</string>
<string name="recycle_bin">Papelera de reciclaje</string> <string name="recycle_bin">Papelera de reciclaje</string>
<string name="keyboard_selection_entry_title">Selección de entrada</string> <string name="keyboard_selection_entry_title">Selección de entrada</string>
<string name="keyboard_selection_entry_summary">Mostrar campos de entrada en el Teclado mágico al ver una entrada</string> <string name="keyboard_selection_entry_summary">Mostrar campos de entrada en el Teclado mágico al ver una entrada</string>
<string name="delete_entered_password_title">Eliminar contraseña</string> <string name="delete_entered_password_title">Eliminar contraseña</string>
<string name="delete_entered_password_summary">Elimina la contraseña proporcionada tras un intento de conexión</string> <string name="delete_entered_password_summary">Elimina la contraseña introducida tras un intento de conexión a una bse de datos</string>
<string name="content_description_open_file">Abrir archivo</string> <string name="content_description_open_file">Abrir archivo</string>
<string name="content_description_node_children">Elementos secundarios del nodo</string> <string name="content_description_node_children">Nodos hijo</string>
<string name="content_description_add_node">Añadir nodo</string> <string name="content_description_add_node">Añadir nodo</string>
<string name="content_description_add_entry">Añadir entrada</string> <string name="content_description_add_entry">Añadir entrada</string>
<string name="content_description_add_group">Añadir grupo</string> <string name="content_description_add_group">Añadir grupo</string>
<string name="content_description_file_information">Información de archivo</string> <string name="content_description_file_information">Información del archivo</string>
<string name="content_description_password_checkbox">Casilla de contraseña</string> <string name="content_description_password_checkbox">Casilla de verificación de la contraseña</string>
<string name="content_description_keyfile_checkbox">Casilla de archivo de clave</string> <string name="content_description_keyfile_checkbox">Casilla de verificación del archivo de clave</string>
<string name="content_description_entry_icon">Icono de entrada</string> <string name="content_description_entry_icon">Icono de entrada</string>
<string name="entry_password_generator">Generador de contraseñas</string> <string name="entry_password_generator">Generador de contraseñas</string>
<string name="content_description_password_length">Longitud de contraseña</string> <string name="content_description_password_length">Longitud de contraseña</string>
<string name="entry_add_field">Añadir campo</string> <string name="entry_add_field">Añadir campo</string>
<string name="content_description_remove_field">Eliminar campo</string> <string name="content_description_remove_field">Eliminar el campo</string>
<string name="entry_UUID">UUID</string> <string name="entry_UUID">UUID</string>
<string name="error_move_entry_here">No se puede mover una entrada aquí.</string> <string name="error_move_entry_here">No puede mover una entrada aquí.</string>
<string name="error_copy_entry_here">No se puede copiar una entrada aquí.</string> <string name="error_copy_entry_here">No puede copiar una entrada aquí.</string>
<string name="list_groups_show_number_entries_title">Mostrar cantidad de entradas</string> <string name="list_groups_show_number_entries_title">Mostrar el número de entradas</string>
<string name="list_groups_show_number_entries_summary">Mostrar la cantidad de entradas en un grupo</string> <string name="list_groups_show_number_entries_summary">Mostrar el número de entradas en un grupo</string>
<string name="content_description_background">Fondo</string> <string name="content_description_background">Fondo</string>
<string name="content_description_update_from_list">Actualizar</string> <string name="content_description_update_from_list">Actualizar</string>
<string name="content_description_keyboard_close_fields">Cerrar campos</string> <string name="content_description_keyboard_close_fields">Cerrar campos</string>
<string name="error_create_database_file">No se puede crear la base de datos con esta contraseña y este archivo de clave.</string> <string name="error_create_database_file">No se puede crear la base de datos con esta contraseña y este archivo de clave.</string>
<string name="menu_advanced_unlock_settings">Desbloqueo avanzado</string> <string name="menu_advanced_unlock_settings">Desbloqueo avanzado</string>
<string name="biometric">Biometría</string> <string name="biometric">Biometría</string>
<string name="biometric_auto_open_prompt_title">Abrir petición de datos biométricos automáticamente</string> <string name="biometric_auto_open_prompt_title">Abrir petición automáticamente</string>
<string name="biometric_auto_open_prompt_summary">Abrir automáticamente la petición de datos biométricos cuando se define una clave biométrica para una base de datos</string> <string name="biometric_auto_open_prompt_summary">Solicitar automáticamente el desbloqueo avanzado si la base de datos está configurada para utilizarlo</string>
<string name="enable">Activar</string> <string name="enable">Activar</string>
<string name="disable">Desactivar</string> <string name="disable">Desactivar</string>
<string name="education_read_only_summary">Cambiar el modo de apertura de la sesión. <string name="education_read_only_summary">Cambiar el modo de apertura de la sesión.
\n \n
\n\"Protegido contra escritura\" evita cambios no deseados en la base de datos. \n\"Protegido contra escritura\" evita cambios no deseados en la base de datos.
\n\"Modificable\" le permite agregar, eliminar o modificar todos los elementos.</string> \n\"Modificable\" le permite agregar, eliminar o modificar todos los elementos como desee.</string>
<string name="lock_database_back_root_title">Presione hacia atrás en la raíz para bloquear</string> <string name="lock_database_back_root_title">Presione \'Atrás\' para bloquear</string>
<string name="content_description_repeat_toggle_password_visibility">Repetir la visibilidad de la contraseña</string> <string name="content_description_repeat_toggle_password_visibility">Repetir la visibilidad de la contraseña</string>
<string name="master_key">Llave maestra</string> <string name="master_key">Clave maestra</string>
<string name="security">Seguridad</string> <string name="security">Seguridad</string>
<string name="entry_history">Historial</string> <string name="entry_history">Historial</string>
<string name="entry_setup_otp">Configuración de contraseña de un solo uso</string> <string name="entry_setup_otp">Establecer una contraseña de un solo uso</string>
<string name="otp_type">Tipo de contraseña de un solo uso</string> <string name="otp_type">Tipo de contraseña de un solo uso</string>
<string name="otp_secret">Secreto</string> <string name="otp_secret">Secreto</string>
<string name="otp_period">Período (segundos)</string> <string name="otp_period">Período (segundos)</string>
@@ -377,16 +379,16 @@
<string name="error_otp_secret_key">Clave secreta debe estar en formato Base32.</string> <string name="error_otp_secret_key">Clave secreta debe estar en formato Base32.</string>
<string name="error_otp_counter">Contador debe estar entre %1$d y %2$d.</string> <string name="error_otp_counter">Contador debe estar entre %1$d y %2$d.</string>
<string name="error_save_database">No se puede guardar la base de datos.</string> <string name="error_save_database">No se puede guardar la base de datos.</string>
<string name="error_string_type">Este texto no encaja con la información requerida.</string> <string name="error_string_type">Este texto no coincide con el elemento requerido.</string>
<string name="error_create_database">No fue posible crear el archivo de base de datos.</string> <string name="error_create_database">No fue posible crear el archivo de base de datos.</string>
<string name="html_about_contribution">Parar lograr &lt;strong&gt;mantener nuestra libertad&lt;/strong&gt;, &lt;strong&gt;corregir errores&lt;/strong&gt;, &lt;strong&gt;agregar características&lt;/strong&gt; y &lt;strong&gt;siempre estar activos&lt;/strong&gt;, contamos con tu &lt;strong&gt;contribución&lt;/strong&gt;.</string> <string name="html_about_contribution">Parar lograr &lt;strong&gt;mantener nuestra libertad&lt;/strong&gt;, &lt;strong&gt;corregir errores&lt;/strong&gt;, &lt;strong&gt;agregar características&lt;/strong&gt; y &lt;strong&gt;estar siempre activos&lt;/strong&gt;, contamos con tu &lt;strong&gt;contribución&lt;/strong&gt;.</string>
<string name="content_description_add_item">Añadir elemento</string> <string name="content_description_add_item">Añadir elemento</string>
<string name="download_complete">Descarga completa!</string> <string name="download_complete">¡Completado!</string>
<string name="download_finalization">Finalizando…</string> <string name="download_finalization">Finalizando…</string>
<string name="download_progression">En progreso: %1$d%%</string> <string name="download_progression">En progreso: %1$d%%</string>
<string name="download_initialization">Inicializando…</string> <string name="download_initialization">Inicializando…</string>
<string name="download_attachment">Descargar %1$s</string> <string name="download_attachment">Descargar %1$s</string>
<string name="enable_auto_save_database_summary">Guardar la base de datos tras acciones importantes (en modo \"Modificable\")</string> <string name="enable_auto_save_database_summary">Guardar la base de datos después de cada acción importante (en modo \"Modificable\")</string>
<string name="enable_auto_save_database_title">Guardar base de datos automáticamente</string> <string name="enable_auto_save_database_title">Guardar base de datos automáticamente</string>
<string name="autofill_block">Bloquear autocompletado</string> <string name="autofill_block">Bloquear autocompletado</string>
<string name="keyboard_change">Cambiar teclado</string> <string name="keyboard_change">Cambiar teclado</string>
@@ -395,12 +397,12 @@
<string name="compression_none">Ninguna</string> <string name="compression_none">Ninguna</string>
<string name="compression">Compresión</string> <string name="compression">Compresión</string>
<string name="database_default_username_title">Nombre de usuario predeterminado</string> <string name="database_default_username_title">Nombre de usuario predeterminado</string>
<string name="settings_database_force_changing_master_key_next_time_summary">Requerir cambiar la contraseña maestra la próxima vez (una sola vez)</string> <string name="settings_database_force_changing_master_key_next_time_summary">Requerir cambiar la contraseña maestra la próxima vez (una vez)</string>
<string name="settings_database_force_changing_master_key_next_time_title">Forzar renovación la próxima vez</string> <string name="settings_database_force_changing_master_key_next_time_title">Forzar renovación la próxima vez</string>
<string name="settings_database_force_changing_master_key_summary">Requerir un cambio de contraseña maestra (días)</string> <string name="settings_database_force_changing_master_key_summary">Requerir un cambio de la contraseña maestra (días)</string>
<string name="settings_database_force_changing_master_key_title">Forzar renovación</string> <string name="settings_database_force_changing_master_key_title">Forzar renovación</string>
<string name="max_history_size_title">Tamaño máximo</string> <string name="max_history_size_title">Tamaño máximo</string>
<string name="advanced_unlock_explanation_summary">Usar desbloqueo avanzado para abrir una base de datos de manera más fácil</string> <string name="advanced_unlock_explanation_summary">Usar el desbloqueo avanzado para abrir una base de datos más fácilmente</string>
<string name="lock_database_show_button_summary">Muestra el botón de bloqueo en la interfaz</string> <string name="lock_database_show_button_summary">Muestra el botón de bloqueo en la interfaz</string>
<string name="lock_database_show_button_title">Mostrar botón de bloqueo</string> <string name="lock_database_show_button_title">Mostrar botón de bloqueo</string>
<string name="autofill_preference_title">Configuración de autocompletado</string> <string name="autofill_preference_title">Configuración de autocompletado</string>
@@ -409,8 +411,8 @@
<string name="warning_database_read_only">Otorga acceso de escritura para guardar cambios en la base de datos</string> <string name="warning_database_read_only">Otorga acceso de escritura para guardar cambios en la base de datos</string>
<string name="show_recent_files_summary">Mostrar ubicaciones de bases de datos recientes</string> <string name="show_recent_files_summary">Mostrar ubicaciones de bases de datos recientes</string>
<string name="show_recent_files_title">Mostrar archivos recientes</string> <string name="show_recent_files_title">Mostrar archivos recientes</string>
<string name="remember_database_locations_summary">Recordar la ubicación de las bases de datos</string> <string name="remember_database_locations_summary">Lleva un registro de los lugares donde se almacenan las bases de datos</string>
<string name="remember_database_locations_title">Guardar ubicaciones de bases de datos</string> <string name="remember_database_locations_title">Recordar las ubicaciones de las bases de datos</string>
<string name="contains_duplicate_uuid">La base de datos contiene UUIDs duplicados.</string> <string name="contains_duplicate_uuid">La base de datos contiene UUIDs duplicados.</string>
<string name="menu_restore_entry_history">Restaurar historial</string> <string name="menu_restore_entry_history">Restaurar historial</string>
<string name="menu_empty_recycle_bin">Vaciar papelera de reciclaje</string> <string name="menu_empty_recycle_bin">Vaciar papelera de reciclaje</string>
@@ -419,12 +421,12 @@
<string name="invalid_db_same_uuid">%1$s con la misma UUID %2$s ya existe.</string> <string name="invalid_db_same_uuid">%1$s con la misma UUID %2$s ya existe.</string>
<string name="error_label_exists">Esta etiqueta ya existe.</string> <string name="error_label_exists">Esta etiqueta ya existe.</string>
<string name="discard">Descartar</string> <string name="discard">Descartar</string>
<string name="discard_changes">¿Descartar cambios\?</string> <string name="discard_changes">¿Descartar los cambios\?</string>
<string name="validate">Validar</string> <string name="validate">Validar</string>
<string name="contribution">Contribución</string> <string name="contribution">Contribución</string>
<string name="contact">Contactar</string> <string name="contact">Contacto</string>
<string name="error_otp_period">Período debe estar entre %1$d y %2$d segundos.</string> <string name="error_otp_period">El período debe estar entre %1$d y %2$d segundos.</string>
<string name="error_copy_group_here">No se puede copiar un grupo aquí.</string> <string name="error_copy_group_here">No puede copiar un grupo aquí.</string>
<string name="database_data_compression_summary">La compresión de datos reduce el tamaño de la base de datos</string> <string name="database_data_compression_summary">La compresión de datos reduce el tamaño de la base de datos</string>
<string name="database_data_compression_title">Compresión de datos</string> <string name="database_data_compression_title">Compresión de datos</string>
<string name="warning_empty_keyfile">No se recomienda agregar un archivo de claves vacío.</string> <string name="warning_empty_keyfile">No se recomienda agregar un archivo de claves vacío.</string>
@@ -433,19 +435,19 @@
<string name="warning_replace_file">Al cargar este archivo reemplazará el existente.</string> <string name="warning_replace_file">Al cargar este archivo reemplazará el existente.</string>
<string name="warning_permanently_delete_nodes">¿Borrar los nodos seleccionados de forma permanente\?</string> <string name="warning_permanently_delete_nodes">¿Borrar los nodos seleccionados de forma permanente\?</string>
<string name="warning_database_link_revoked">El acceso al archivo fue revocado por el administrador de archivos</string> <string name="warning_database_link_revoked">El acceso al archivo fue revocado por el administrador de archivos</string>
<string name="command_execution">Ejecutando el comando </string> <string name="command_execution">Ejecutando el comando…</string>
<string name="hide_broken_locations_summary">Ocultar enlaces rotos en la lista de bases de datos recientes</string> <string name="hide_broken_locations_summary">Ocultar enlaces rotos en la lista de bases de datos recientes</string>
<string name="hide_broken_locations_title">Ocultar enlaces de bases de datos rotos</string> <string name="hide_broken_locations_title">Ocultar enlaces de bases de datos rotos</string>
<string name="remember_keyfile_locations_summary">Realiza un seguimiento de dónde se almacenan los archivos de claves</string> <string name="remember_keyfile_locations_summary">Realiza un seguimiento de dónde se almacenan los archivos de claves</string>
<string name="remember_keyfile_locations_title">Recuerdar las ubicaciones de los archivos de claves</string> <string name="remember_keyfile_locations_title">Recordar las ubicaciones de los archivos de clave</string>
<string name="subdomain_search_summary">Buscar dominios web con restricciones de subdominios</string> <string name="subdomain_search_summary">Buscar dominios web con restricciones de subdominios</string>
<string name="subdomain_search_title">Búsqueda de subdominio</string> <string name="subdomain_search_title">Búsqueda de subdominio</string>
<string name="auto_focus_search_summary">Solicite una búsqueda al abrir una base de datos</string> <string name="auto_focus_search_summary">Solicite una búsqueda al abrir una base de datos</string>
<string name="auto_focus_search_title">Búsqueda rápida</string> <string name="auto_focus_search_title">Búsqueda rápida</string>
<string name="menu_delete_entry_history">Borrar historial</string> <string name="menu_delete_entry_history">Eliminar el historial</string>
<string name="error_otp_digits">El token debe tener de %1$d a %2$d dígitos.</string> <string name="error_otp_digits">El token debe contener de %1$d a %2$d dígitos.</string>
<string name="entry_attachments">Archivos adjuntos</string> <string name="entry_attachments">Archivos adjuntos</string>
<string name="entry_add_attachment">Adjuntar</string> <string name="entry_add_attachment">Añadir el archivo adjunto</string>
<string name="content_description_credentials_information">Información de credenciales</string> <string name="content_description_credentials_information">Información de credenciales</string>
<string name="database_opened">Base de datos abierta</string> <string name="database_opened">Base de datos abierta</string>
<string name="education_add_attachment_title">Adjuntar</string> <string name="education_add_attachment_title">Adjuntar</string>
@@ -455,4 +457,92 @@
<string name="warning_file_too_big">Se supone que una base de datos KeePass contiene solo pequeños archivos de utilidad (como archivos de clave PGP). <string name="warning_file_too_big">Se supone que una base de datos KeePass contiene solo pequeños archivos de utilidad (como archivos de clave PGP).
\n \n
\nLa base de datos puede volverse muy grande y reducir su rendimiento con esta subida.</string> \nLa base de datos puede volverse muy grande y reducir su rendimiento con esta subida.</string>
<string name="recycle_bin_group_title">Grupo de la papelera de reciclaje</string>
<string name="filter">Filtrar</string>
<string name="database_data_remove_unlinked_attachments_summary">Elimina los archivos adjuntos contenidos en la base de datos pero no vinculados a una entrada</string>
<string name="database_data_remove_unlinked_attachments_title">Eliminar los datos no vinculados</string>
<string name="data">Datos</string>
<string name="advanced_unlock_delete_all_key_warning">¿Borrar todas las claves de encriptación relacionadas con el reconocimiento de desbloqueo avanzado\?</string>
<string name="advanced_unlock_timeout">Tiempo límite de desbloqueo avanzado</string>
<string name="temp_advanced_unlock_timeout_summary">Duración del uso de desbloqueo avanzado antes de borrar su contenido</string>
<string name="temp_advanced_unlock_timeout_title">Expiración de desbloqueo avanzado</string>
<string name="temp_advanced_unlock_enable_summary">No almacenar ningún contenido encriptado para utilizar el desbloqueo avanzado</string>
<string name="temp_advanced_unlock_enable_title">Desbloqueo avanzado temporal</string>
<string name="device_credential_unlock_enable_summary">Le permite usar la credenciales de su dispositivo para abrir la base de datos</string>
<string name="device_credential_unlock_enable_title">Desbloqueo de las credenciales del dispositivo</string>
<string name="advanced_unlock_tap_delete">Toque para eliminar las teclas de desbloqueo avanzadas</string>
<string name="content">Contenido</string>
<string name="clipboard_explanation_summary">Copiar los campos de entrada usando el portapapeles de su dispositivo</string>
<string name="device_credential">Credenciales del dispositivo</string>
<string name="credential_before_click_advanced_unlock_button">Introduzca la contraseña y luego haga clic en el botón \"Desbloqueo avanzado\".</string>
<string name="advanced_unlock_prompt_not_initialized">No se pudo inicializar el indicador de desbloqueo avanzado.</string>
<string name="advanced_unlock_scanning_error">Error de desbloqueo avanzado: %1$s</string>
<string name="advanced_unlock_not_recognized">No se pudo reconocer la impresión de desbloqueo avanzado</string>
<string name="advanced_unlock_invalid_key">No se pudo leer la llave de desbloqueo avanzada. Por favor, bórrela y repita el procedimiento de reconocimiento de desbloqueo.</string>
<string name="advanced_unlock_prompt_extract_credential_message">Extraer la credencial de la base de datos con datos de desbloqueo avanzado</string>
<string name="advanced_unlock_prompt_extract_credential_title">Abrir la base de datos con reconocimiento de desbloqueo avanzado</string>
<string name="advanced_unlock_prompt_store_credential_message">Advertencia: Aún debes recordar tu contraseña maestra si usas el reconocimiento de desbloqueo avanzado.</string>
<string name="advanced_unlock_prompt_store_credential_title">Reconocimiento de desbloqueo avanzado</string>
<string name="open_advanced_unlock_prompt_store_credential">Abrir el indicador de desbloqueo avanzado para almacenar las credenciales</string>
<string name="open_advanced_unlock_prompt_unlock_database">Abrir el aviso de desbloqueo avanzado para desbloquear la base de datos</string>
<string name="keystore_not_accessible">El almacén de claves no está debidamente inicializado.</string>
<string name="biometric_security_update_required">Se requiere una actualización de la seguridad biométrica.</string>
<string name="configure_biometric">No se ha inscrito ninguna credencial biométrica o del dispositivo.</string>
<string name="warning_empty_keyfile_explanation">El contenido del archivo clave nunca debe modificarse y, en el mejor de los casos, debe contener datos generados al azar.</string>
<string name="warning_empty_recycle_bin">¿Borrar permanentemente todos los nodos de la papelera de reciclaje\?</string>
<string name="registration_mode">Modo de registro</string>
<string name="save_mode">Modo de guardado</string>
<string name="search_mode">Modo de búsqueda</string>
<string name="contains_duplicate_uuid_procedure">¿Resolver el problema generando nuevos UUID para que los duplicados continúen\?</string>
<string name="menu_keystore_remove_key">Borrar la clave de desbloqueo avanzado</string>
<string name="error_field_name_already_exists">El nombre del campo ya existe.</string>
<string name="error_registration_read_only">Guardar un nuevo elemento no está permitido en una base de datos de sólo lectura</string>
<string name="settings_database_recommend_changing_master_key_title">Recomendar la renovación</string>
<string name="max_history_size_summary">Limitar el tamaño del historial (en bytes) por entrada</string>
<string name="max_history_items_summary">Limitar el número de elementos del historial por entrada</string>
<string name="max_history_items_title">Número máximo</string>
<string name="device_keyboard_setting_title">Configuración del teclado del dispositivo</string>
<string name="database_custom_color_title">Color personalizado de la base de datos</string>
<string name="settings_database_recommend_changing_master_key_summary">Recomendar cambiar la contraseña maestra (días)</string>
<string name="notification">Notificación</string>
<string name="hide_expired_entries_title">Ocultar las entradas expiradas</string>
<string name="keyboard_search_share_title">Buscar información compartida</string>
<string name="kdf_Argon2id">Argon2id</string>
<string name="kdf_Argon2d">Argon2d</string>
<string name="upload_attachment">Subir %1$s</string>
<string name="education_setup_OTP_summary">Configurar la gestión de contraseñas de una sola vez (HOTP / TOTP) para generar un token solicitado para la autenticación de dos factores (2FA).</string>
<string name="education_setup_OTP_title">Establecer la contaseña de un solo uso</string>
<string name="education_advanced_unlock_summary">Vincule su contraseña con su credencial biométrica o del dispositivo escaneada para desbloquear rápidamente su base de datos.</string>
<string name="education_advanced_unlock_title">Desbloqueo avanzado de la base de datos</string>
<string name="autofill_read_only_save">No se permite guardar datos en una base de datos abierta como de sólo lectura.</string>
<string name="autofill_block_restart">Reiniciar la aplicación que contiene el formulario para activar el bloqueo.</string>
<string name="autofill_web_domain_blocklist_summary">Lista de bloqueo que impide el llenado automático de los dominios web</string>
<string name="autofill_web_domain_blocklist_title">Lista de bloqueo de los dominios web</string>
<string name="autofill_application_id_blocklist_summary">Lista de bloqueo que impide el llenado automático de las aplicaciones</string>
<string name="autofill_application_id_blocklist_title">Lista de bloqueo de las aplicaciones</string>
<string name="autofill_ask_to_save_data_summary">Pedir que se guarden los datos cuando se valide un formulario</string>
<string name="autofill_ask_to_save_data_title">Pedir que se guarden los datos</string>
<string name="autofill_save_search_info_summary">Intente guardar la información de la búsqueda cuando haga una selección de entrada manual</string>
<string name="autofill_save_search_info_title">Guardar la información de la búsqueda</string>
<string name="autofill_auto_search_summary">Sugerir automáticamente los resultados de la búsqueda desde el dominio web o el ID de la aplicación</string>
<string name="autofill_auto_search_title">Búsqueda automática</string>
<string name="autofill_close_database_summary">Cerrar la base de datos después de una selección de autocompletado</string>
<string name="autofill_close_database_title">Cerrar la base de datos</string>
<string name="enter">Entrar</string>
<string name="backspace">Retroceder</string>
<string name="select_entry">Seleccionar la entrada</string>
<string name="back_to_previous_keyboard">Volver al teclado anterior</string>
<string name="custom_fields">Campos personalizados</string>
<string name="keyboard_previous_lock_summary">Cambiar automáticamente al teclado anterior después de bloquear la base de datos</string>
<string name="keyboard_previous_lock_title">Bloquear la base de datos</string>
<string name="keyboard_previous_fill_in_summary">Cambiar automáticamente al teclado anterior después de ejecutar \"Acción de la tecla automática\"</string>
<string name="keyboard_previous_fill_in_title">Acción de la tecla automática</string>
<string name="keyboard_previous_database_credentials_summary">Cambiar automáticamente al teclado anterior en la pantalla de credenciales de la base de datos</string>
<string name="keyboard_previous_database_credentials_title">Pantalla de credenciales de la base de datos</string>
<string name="keyboard_auto_go_action_title">Acción de la tecla automática</string>
<string name="keyboard_save_search_info_summary">Intentar guardar la información compartida cuando hagas una selección de entrada manual</string>
<string name="keyboard_save_search_info_title">Guardar información compartida</string>
<string name="keyboard_search_share_summary">Buscar automáticamente la información compartida para llenar el teclado</string>
<string name="show_uuid_summary">Muestra el UUID vinculado a una entrada</string>
<string name="show_uuid_title">Mostrar UUID</string>
</resources> </resources>

View File

@@ -550,4 +550,6 @@
<string name="temp_advanced_unlock_enable_title">Déverrouillage avancé temporaire</string> <string name="temp_advanced_unlock_enable_title">Déverrouillage avancé temporaire</string>
<string name="advanced_unlock_tap_delete">Appuyez pour supprimer les clés de déverrouillage avancées</string> <string name="advanced_unlock_tap_delete">Appuyez pour supprimer les clés de déverrouillage avancées</string>
<string name="content">Contenu</string> <string name="content">Contenu</string>
<string name="kdf_Argon2id">Argon2id</string>
<string name="kdf_Argon2d">Argon2d</string>
</resources> </resources>

View File

@@ -525,4 +525,6 @@
<string name="temp_advanced_unlock_enable_summary">Nemoj spremati šifrirani sadržaj za napredno otključavanje</string> <string name="temp_advanced_unlock_enable_summary">Nemoj spremati šifrirani sadržaj za napredno otključavanje</string>
<string name="content">Sadržaj</string> <string name="content">Sadržaj</string>
<string name="temp_advanced_unlock_enable_title">Privremeno napredno otključavanje</string> <string name="temp_advanced_unlock_enable_title">Privremeno napredno otključavanje</string>
<string name="kdf_Argon2id">Argon2id</string>
<string name="kdf_Argon2d">Argon2d</string>
</resources> </resources>

View File

@@ -401,9 +401,9 @@
<string name="hide_broken_locations_title">Nascondi i collegamenti dei database corrotti</string> <string name="hide_broken_locations_title">Nascondi i collegamenti dei database corrotti</string>
<string name="show_recent_files_summary">Mostra le posizioni dei database recenti</string> <string name="show_recent_files_summary">Mostra le posizioni dei database recenti</string>
<string name="show_recent_files_title">Mostra file recenti</string> <string name="show_recent_files_title">Mostra file recenti</string>
<string name="remember_keyfile_locations_title">Ricorda la posizione dei file chiave</string> <string name="remember_keyfile_locations_title">Ricorda posizione file chiave</string>
<string name="remember_database_locations_summary">Ricorda la posizione dei database</string> <string name="remember_database_locations_summary">Ricorda la posizione dei database</string>
<string name="remember_database_locations_title">Ricorda la posizione dei database</string> <string name="remember_database_locations_title">Ricorda posizione database</string>
<string name="contains_duplicate_uuid_procedure">Per continuare, risolvi il problema generando nuovi UUID per i duplicati\?</string> <string name="contains_duplicate_uuid_procedure">Per continuare, risolvi il problema generando nuovi UUID per i duplicati\?</string>
<string name="error_create_database">Impossibile creare il file del database.</string> <string name="error_create_database">Impossibile creare il file del database.</string>
<string name="entry_add_attachment">Aggiungi allegato</string> <string name="entry_add_attachment">Aggiungi allegato</string>
@@ -540,8 +540,10 @@
<string name="device_credential">Credenziali del dispositivo</string> <string name="device_credential">Credenziali del dispositivo</string>
<string name="credential_before_click_advanced_unlock_button">Inserisci la password, quindi clicca sull\'icona \"Sblocco avanzato\".</string> <string name="credential_before_click_advanced_unlock_button">Inserisci la password, quindi clicca sull\'icona \"Sblocco avanzato\".</string>
<string name="advanced_unlock_scanning_error">Errore sblocco avanzato: %1$s</string> <string name="advanced_unlock_scanning_error">Errore sblocco avanzato: %1$s</string>
<string name="advanced_unlock_prompt_extract_credential_title">Apri il database autenticando con lo sblocco avanzato</string> <string name="advanced_unlock_prompt_extract_credential_title">Apri il database con lo sblocco avanzato</string>
<string name="open_advanced_unlock_prompt_unlock_database">Autentica con lo sblocco avanzato per sbloccare il database</string> <string name="open_advanced_unlock_prompt_unlock_database">Autentica con lo sblocco avanzato per sbloccare il database</string>
<string name="open_advanced_unlock_prompt_store_credential">Autentica con lo sblocco avanzato per salvare le credenziali</string> <string name="open_advanced_unlock_prompt_store_credential">Autentica con lo sblocco avanzato per salvare le credenziali</string>
<string name="menu_keystore_remove_key">Elimina chiave di sblocco avanzato</string> <string name="menu_keystore_remove_key">Elimina chiave di sblocco avanzato</string>
<string name="kdf_Argon2id">Argon2id</string>
<string name="kdf_Argon2d">Argon2d</string>
</resources> </resources>

View File

@@ -388,4 +388,12 @@
<string name="registration_mode">രജിസ്ട്രേഷൻ മോഡ്</string> <string name="registration_mode">രജിസ്ട്രേഷൻ മോഡ്</string>
<string name="search_mode">തിരയൽ മോഡ്</string> <string name="search_mode">തിരയൽ മോഡ്</string>
<string name="error_registration_read_only">read-only ഡാറ്റാബേസിൽ പുതിയ ഒരു ഇനം സംരക്ഷിക്കാൻ കഴിയില്ല</string> <string name="error_registration_read_only">read-only ഡാറ്റാബേസിൽ പുതിയ ഒരു ഇനം സംരക്ഷിക്കാൻ കഴിയില്ല</string>
<string name="education_advanced_unlock_title">വിപുലമായ ഡാറ്റാബേസ് അൺലോക്ക്</string>
<string name="select_entry">എൻ‌ട്രി തിരഞ്ഞെടുക്കുക</string>
<string name="custom_fields">ഇഷ്‌ടാനുസൃത ഫീൽഡുകൾ</string>
<string name="keyboard_keys_category">കീകൾ</string>
<string name="notification">അറിയിപ്പ്</string>
<string name="settings_database_recommend_changing_master_key_title">പുതുക്കൽ ശുപാർശ ചെയ്യുക</string>
<string name="content">ഉള്ളടക്കം</string>
<string name="device_credential">ഉപകരണ ക്രെഡൻഷ്യൽ</string>
</resources> </resources>

View File

@@ -535,4 +535,5 @@
<string name="temp_advanced_unlock_enable_summary">Nie przechowuj żadnych zaszyfrowanych treści, aby korzystać z zaawansowanego odblokowywania</string> <string name="temp_advanced_unlock_enable_summary">Nie przechowuj żadnych zaszyfrowanych treści, aby korzystać z zaawansowanego odblokowywania</string>
<string name="advanced_unlock_tap_delete">Naciśnij, aby usunąć zaawansowane klucze odblokowujące</string> <string name="advanced_unlock_tap_delete">Naciśnij, aby usunąć zaawansowane klucze odblokowujące</string>
<string name="content">Zawartość</string> <string name="content">Zawartość</string>
<string name="advanced_unlock_prompt_extract_credential_title">Otwórz bazę danych z zaawansowanym rozpoznawaniem odblokowania</string>
</resources> </resources>

View File

@@ -519,10 +519,10 @@
<string name="advanced_unlock_not_recognized">Невозможно распознать расширенную разблокировку</string> <string name="advanced_unlock_not_recognized">Невозможно распознать расширенную разблокировку</string>
<string name="advanced_unlock_invalid_key">Невозможно прочитать ключ расширенной разблокировки. Удалите его и повторите процедуру распознавания разблокировки.</string> <string name="advanced_unlock_invalid_key">Невозможно прочитать ключ расширенной разблокировки. Удалите его и повторите процедуру распознавания разблокировки.</string>
<string name="advanced_unlock_prompt_extract_credential_message">Извлекать учётные данные базы с использованием расширенной разблокировки</string> <string name="advanced_unlock_prompt_extract_credential_message">Извлекать учётные данные базы с использованием расширенной разблокировки</string>
<string name="advanced_unlock_prompt_extract_credential_title">Открывать базу с расширенным распознаванием разблокировки</string> <string name="advanced_unlock_prompt_extract_credential_title">Открыть базу с расширенным распознаванием разблокировки</string>
<string name="advanced_unlock_prompt_store_credential_message">Предупреждение: даже при использовании расширенной разблокировки вам всё равно необходимо помнить главный пароль.</string> <string name="advanced_unlock_prompt_store_credential_message">Предупреждение: даже при использовании расширенной разблокировки вам всё равно необходимо помнить главный пароль.</string>
<string name="open_advanced_unlock_prompt_store_credential">Открывать запрос расширенной разблокировки для сохранения учётных данных</string> <string name="open_advanced_unlock_prompt_store_credential">Открыть запрос расширенной разблокировки для сохранения учётных данных</string>
<string name="open_advanced_unlock_prompt_unlock_database">Открывать запрос расширенной разблокировки для разблокировки базы</string> <string name="open_advanced_unlock_prompt_unlock_database">Открыть запрос расширенной разблокировки для разблокировки базы</string>
<string name="advanced_unlock_delete_all_key_warning">Удалить все ключи шифрования, связанные с распознаванием расширенной разблокировки\?</string> <string name="advanced_unlock_delete_all_key_warning">Удалить все ключи шифрования, связанные с распознаванием расширенной разблокировки\?</string>
<string name="advanced_unlock_scanning_error">Ошибка расширенной разблокировки: %1$s</string> <string name="advanced_unlock_scanning_error">Ошибка расширенной разблокировки: %1$s</string>
<string name="advanced_unlock_prompt_store_credential_title">Распознавание расширенной разблокировки</string> <string name="advanced_unlock_prompt_store_credential_title">Распознавание расширенной разблокировки</string>
@@ -541,4 +541,6 @@
<string name="temp_advanced_unlock_enable_summary">Не сохранять зашифрованное содержимое для использования расширенной разблокировки</string> <string name="temp_advanced_unlock_enable_summary">Не сохранять зашифрованное содержимое для использования расширенной разблокировки</string>
<string name="advanced_unlock_tap_delete">Нажмите, чтобы удалить ключи расширенной разблокировки</string> <string name="advanced_unlock_tap_delete">Нажмите, чтобы удалить ключи расширенной разблокировки</string>
<string name="content">Содержимое</string> <string name="content">Содержимое</string>
<string name="kdf_Argon2id">Argon2ID</string>
<string name="kdf_Argon2d">Argon2D</string>
</resources> </resources>

View File

@@ -525,4 +525,6 @@
<string name="temp_advanced_unlock_enable_title">Geçici gelişmiş kilit açma</string> <string name="temp_advanced_unlock_enable_title">Geçici gelişmiş kilit açma</string>
<string name="advanced_unlock_tap_delete">Gelişmiş kilit açma anahtarlarını silmek için dokunun</string> <string name="advanced_unlock_tap_delete">Gelişmiş kilit açma anahtarlarını silmek için dokunun</string>
<string name="content">İçerik</string> <string name="content">İçerik</string>
<string name="kdf_Argon2id">Argon2id</string>
<string name="kdf_Argon2d">Argon2d</string>
</resources> </resources>

View File

@@ -541,4 +541,6 @@
<string name="temp_advanced_unlock_enable_title">Тимчасове розширене розблокування</string> <string name="temp_advanced_unlock_enable_title">Тимчасове розширене розблокування</string>
<string name="advanced_unlock_tap_delete">Торкнутися, щоб видалити клавіші розширеного розблокування</string> <string name="advanced_unlock_tap_delete">Торкнутися, щоб видалити клавіші розширеного розблокування</string>
<string name="content">Вміст</string> <string name="content">Вміст</string>
<string name="kdf_Argon2id">Argon2id</string>
<string name="kdf_Argon2d">Argon2d</string>
</resources> </resources>

View File

@@ -541,4 +541,6 @@
<string name="temp_advanced_unlock_enable_title">临时性高级解锁</string> <string name="temp_advanced_unlock_enable_title">临时性高级解锁</string>
<string name="advanced_unlock_tap_delete">点击删除高级解锁密钥</string> <string name="advanced_unlock_tap_delete">点击删除高级解锁密钥</string>
<string name="content">内容</string> <string name="content">内容</string>
<string name="kdf_Argon2id">Argon2id</string>
<string name="kdf_Argon2d">Argon2d</string>
</resources> </resources>

View File

@@ -134,6 +134,8 @@
<string name="error_string_type">This text does not match the requested item.</string> <string name="error_string_type">This text does not match the requested item.</string>
<string name="error_registration_read_only">Saving a new item is not allowed in a read-only database</string> <string name="error_registration_read_only">Saving a new item is not allowed in a read-only database</string>
<string name="error_field_name_already_exists">The field name already exists.</string> <string name="error_field_name_already_exists">The field name already exists.</string>
<string name="error_database_uri_null">Database URI cannot be retrieved.</string>
<string name="error_rebuild_list">Unable to properly rebuild the list.</string>
<string name="field_name">Field name</string> <string name="field_name">Field name</string>
<string name="field_value">Field value</string> <string name="field_value">Field value</string>
<string name="file_not_found_content">Could not find file. Try reopening it from your file browser.</string> <string name="file_not_found_content">Could not find file. Try reopening it from your file browser.</string>
@@ -183,6 +185,7 @@
<string name="menu_hide_password">Hide password</string> <string name="menu_hide_password">Hide password</string>
<string name="menu_lock">Lock database</string> <string name="menu_lock">Lock database</string>
<string name="menu_save_database">Save database</string> <string name="menu_save_database">Save database</string>
<string name="menu_reload_database">Reload database</string>
<string name="menu_open">Open</string> <string name="menu_open">Open</string>
<string name="menu_search">Search</string> <string name="menu_search">Search</string>
<string name="menu_showpass">Show password</string> <string name="menu_showpass">Show password</string>
@@ -270,6 +273,9 @@
<string name="warning_sure_remove_data">Remove this data anyway?</string> <string name="warning_sure_remove_data">Remove this data anyway?</string>
<string name="warning_empty_keyfile">It is not recommended to add an empty keyfile.</string> <string name="warning_empty_keyfile">It is not recommended to add an empty keyfile.</string>
<string name="warning_empty_keyfile_explanation">The content of the keyfile should never be changed, and in the best case, should contain randomly generated data.</string> <string name="warning_empty_keyfile_explanation">The content of the keyfile should never be changed, and in the best case, should contain randomly generated data.</string>
<string name="warning_database_info_changed">The information contained in your database file has been modified outside the app.</string>
<string name="warning_database_info_changed_options">Overwrite the external modifications by saving the database or reload it with the latest changes.</string>
<string name="warning_database_revoked">Access to the file revoked by the file manager, close the database and reopen it from its location.</string>
<string name="version_label">Version %1$s</string> <string name="version_label">Version %1$s</string>
<string name="build_label">Build %1$s</string> <string name="build_label">Build %1$s</string>
<string name="configure_biometric">No biometric or device credential is enrolled.</string> <string name="configure_biometric">No biometric or device credential is enrolled.</string>

View File

@@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.4.10' ext.kotlin_version = '1.4.21'
repositories { repositories {
jcenter() jcenter()
google() google()

View File

@@ -1 +1 @@
* * Fix KeyFile bug #820

View File

@@ -0,0 +1,2 @@
* Fix small bugs
* Remove write permission since Android 10

View File

@@ -0,0 +1,2 @@
* Fix specific attachments with kdbx3.1 databases #828
* Fix small bugs

View File

@@ -0,0 +1 @@
* Detect file changes and reload database #794

View File

@@ -1 +1 @@
* * Correction du bug de fichier de clé #820

View File

@@ -0,0 +1,2 @@
* Correction de petits bugs
* Suppression des permissions d'écriture à partir d'Android 10

View File

@@ -0,0 +1,2 @@
* Correction des pièces jointes spécifiques avec les bases kdbx3.1 #828
* Correction de petits bugs

View File

@@ -0,0 +1 @@
* Détection des changements de fichiers et rechargement de base de données #794

View File

@@ -1,7 +1,7 @@
<b>Multi-format KeePass password manager</b>, the app allows saving and using passwords, keys and digital identities in a secure way, by integrating the Android design standards. <b>Multi-format KeePass password manager</b>, the app allows saving and using passwords, keys and digital identities in a secure way, by integrating the Android design standards.
This pro version is under development, buying it encourages <b>faster development</b>, <b>better service</b>, and you contribute to the creation of <b>open source softwares without advertising</b>. This pro version is under development, buying it encourages <b>faster development</b>, <b>better service</b>, and you contribute to the creation of <b>open source softwares without advertising</b>.
<i>Currently, the application has the same features as the free version with the themes unlocked but is intended to integrate the elements of connection and synchronization facilitated for sites and services commonly used.</i> <i>Currently, the application has the same features as the free version with the themes unlocked but is intended to integrate elements related to non-free sites and services commonly used.</i>
<b>Features</b> <b>Features</b>
- Create database files / entries and groups. - Create database files / entries and groups.

View File

@@ -1,7 +1,7 @@
<b>Gestionnaire de mots de passe KeePass multiformats</b>, l'application permet d'enregistrer et d'utiliser des mots de passe, des clés et des identités numériques de manière sécurisée, en intégrant les normes de conception Android. <b>Gestionnaire de mots de passe KeePass multiformats</b>, l'application permet d'enregistrer et d'utiliser des mots de passe, des clés et des identités numériques de manière sécurisée, en intégrant les normes de conception Android.
Cette version pro est en cours de développement, en l'achetant vous encouragez <b>un développement plus rapide</b>, <b>un meilleur service</b> et vous contribuez à la création de <b>logiciels open source sans publicité</b>. Cette version pro est en cours de développement, en l'achetant vous encouragez <b>un développement plus rapide</b>, <b>un meilleur service</b> et vous contribuez à la création de <b>logiciels open source sans publicité</b>.
<i>Actuellement, l'application possède les mêmes fonctionnalités que la version gratuite avec les thèmes débloqués mais est destinée à intégrer les éléments de connexion et de synchronisation facilités pour les sites et services couramment utilisés.</i> <i>Actuellement, l'application possède les mêmes fonctionnalités que la version gratuite avec les thèmes débloqués mais est destinée à intégrer des éléments liés à des sites et services non gratuits couramment utilisés.</i>
<b>Fonctionnalités</b> <b>Fonctionnalités</b>
- Création de bases de données / entrées et groupes. - Création de bases de données / entrées et groupes.

View File

@@ -1,7 +1,7 @@
<b>複数の形式に対応する KeePass パスワード マネージャー</b>。Android の設計基準が組み込まれており、パスワード、鍵、デジタル ID を安全な方法で保存して使用できます。 <b>複数の形式に対応する KeePass パスワード マネージャー</b>。Android の設計基準が組み込まれており、パスワード、鍵、デジタル ID を安全な方法で保存して使用できます。
この pro バージョンは開発中です。購入することで<b>開発の加速</b>と<b>サービスの改善</b>を支援し、<b>広告なしのオープンソース ソフトウェア</b>の作成に貢献できます。 この pro バージョンは開発中です。購入することで<b>開発の加速</b>と<b>サービスの改善</b>を支援し、<b>広告なしのオープンソース ソフトウェア</b>の作成に貢献できます。
<i>現在、このアプリケーションの機能はテーマのロックが解除された free バージョンと同じです。よく利用されるサイトやサービスの接続と同期を楽にする要素を統合することが予定されています。</i> <i>現在、このアプリケーションの機能はテーマのロックが解除された free バージョンと同じです。一般的に使われている不自由なサイトやサービスに関連する要素を統合することを計画しています。</i>
<b>機能</b> <b>機能</b>
- データベースファイル / エントリー・グループの作成 - データベースファイル / エントリー・グループの作成