mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Merge branch 'develop' into feature/Passkeys
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
name: Bug Report
|
||||
description: Report a bug.
|
||||
title: ""
|
||||
labels: bug
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -1,7 +1,6 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea.
|
||||
title: ""
|
||||
labels: feature
|
||||
labels: ["feature"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 3,
|
||||
"identityHash": "a20aec7cf09664b1102ec659fa51160a",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "file_database_history",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`database_uri` TEXT NOT NULL, `database_alias` TEXT NOT NULL, `keyfile_uri` TEXT, `hardware_key` TEXT, `read_only` INTEGER, `updated` INTEGER NOT NULL, PRIMARY KEY(`database_uri`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "databaseUri",
|
||||
"columnName": "database_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "databaseAlias",
|
||||
"columnName": "database_alias",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "keyFileUri",
|
||||
"columnName": "keyfile_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "hardwareKey",
|
||||
"columnName": "hardware_key",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "readOnly",
|
||||
"columnName": "read_only",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "updated",
|
||||
"columnName": "updated",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"database_uri"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "cipher_database",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`database_uri` TEXT NOT NULL, `encrypted_value` TEXT NOT NULL, `specs_parameters` TEXT NOT NULL, PRIMARY KEY(`database_uri`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "databaseUri",
|
||||
"columnName": "database_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "encryptedValue",
|
||||
"columnName": "encrypted_value",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "specParameters",
|
||||
"columnName": "specs_parameters",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"database_uri"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a20aec7cf09664b1102ec659fa51160a')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -359,8 +359,6 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
|
||||
|
||||
isViewTranslateAnimationRunning = true
|
||||
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
imageView.run {
|
||||
val translationY = if (velY > 0) {
|
||||
originalViewBounds.top + height - top
|
||||
@@ -396,41 +394,6 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
ObjectAnimator.ofFloat(imageView, View.TRANSLATION_Y, if (velY > 0) {
|
||||
originalViewBounds.top + imageView.height - imageView.top
|
||||
} else {
|
||||
originalViewBounds.top - imageView.height - imageView.top
|
||||
}.toFloat()).apply {
|
||||
duration = dismissAnimationDuration
|
||||
interpolator = dismissAnimationInterpolator
|
||||
addUpdateListener {
|
||||
val amount = calcTranslationAmount()
|
||||
changeBackgroundAlpha(amount)
|
||||
onViewTranslateListener?.onViewTranslate(imageView, amount)
|
||||
}
|
||||
addListener(object : Animator.AnimatorListener {
|
||||
override fun onAnimationStart(p0: Animator) {
|
||||
// no op
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(p0: Animator) {
|
||||
isViewTranslateAnimationRunning = false
|
||||
onViewTranslateListener?.onDismiss(imageView)
|
||||
cleanup()
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(p0: Animator) {
|
||||
isViewTranslateAnimationRunning = false
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(p0: Animator) {
|
||||
// no op
|
||||
}
|
||||
})
|
||||
start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processFlingBitmap(velocityX: Float, velocityY: Float) {
|
||||
@@ -657,8 +620,6 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
|
||||
|
||||
private fun restoreViewTransform() {
|
||||
val imageView = imageViewRef.get() ?: return
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
imageView.run {
|
||||
animate()
|
||||
.setDuration(restoreAnimationDuration)
|
||||
@@ -687,41 +648,12 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
ObjectAnimator.ofFloat(imageView, View.TRANSLATION_Y, (originalViewBounds.top - imageView.top).toFloat()).apply {
|
||||
duration = restoreAnimationDuration
|
||||
interpolator = restoreAnimationInterpolator
|
||||
addUpdateListener {
|
||||
val amount = calcTranslationAmount()
|
||||
changeBackgroundAlpha(amount)
|
||||
onViewTranslateListener?.onViewTranslate(imageView, amount)
|
||||
}
|
||||
addListener(object : Animator.AnimatorListener {
|
||||
override fun onAnimationStart(p0: Animator) {
|
||||
// no op
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(p0: Animator) {
|
||||
onViewTranslateListener?.onRestore(imageView)
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(p0: Animator) {
|
||||
// no op
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(p0: Animator) {
|
||||
// no op
|
||||
}
|
||||
})
|
||||
start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startDragToDismissAnimation() {
|
||||
val imageView = imageViewRef.get() ?: return
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
imageView.run {
|
||||
val translationY = if (y - initialY > 0) {
|
||||
originalViewBounds.top + height - top
|
||||
@@ -757,37 +689,7 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
ObjectAnimator.ofFloat(imageView, View.TRANSLATION_Y, imageView.translationY).apply {
|
||||
duration = dismissAnimationDuration
|
||||
interpolator = AccelerateDecelerateInterpolator()
|
||||
addUpdateListener {
|
||||
val amount = calcTranslationAmount()
|
||||
changeBackgroundAlpha(amount)
|
||||
onViewTranslateListener?.onViewTranslate(imageView, amount)
|
||||
}
|
||||
addListener(object : Animator.AnimatorListener {
|
||||
override fun onAnimationStart(p0: Animator) {
|
||||
isViewTranslateAnimationRunning = true
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(p0: Animator) {
|
||||
isViewTranslateAnimationRunning = false
|
||||
onViewTranslateListener?.onDismiss(imageView)
|
||||
cleanup()
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(p0: Animator) {
|
||||
isViewTranslateAnimationRunning = false
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(p0: Animator) {
|
||||
// no op
|
||||
}
|
||||
})
|
||||
start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processFlingToDismiss(velocityY: Float) {
|
||||
|
||||
@@ -78,9 +78,8 @@ class AboutActivity : StylishActivity() {
|
||||
movementMethod = LinkMovementMethod.getInstance()
|
||||
text = HtmlCompat.fromHtml(getString(R.string.html_about_licence, DateTime().year),
|
||||
HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
textDirection = View.TEXT_DIRECTION_ANY_RTL
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
findViewById<TextView>(R.id.activity_about_privacy_text).apply {
|
||||
|
||||
@@ -644,16 +644,12 @@ class EntryEditActivity : DatabaseLockActivity(),
|
||||
isVisible = isEnabled
|
||||
}
|
||||
menu?.findItem(R.id.menu_add_attachment)?.apply {
|
||||
// Attachment not compatible below KitKat
|
||||
isEnabled = !mIsTemplate
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
|
||||
isVisible = isEnabled
|
||||
}
|
||||
menu?.findItem(R.id.menu_add_otp)?.apply {
|
||||
// OTP not compatible below KitKat
|
||||
isEnabled = mAllowOTP
|
||||
&& !mIsTemplate
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
|
||||
isVisible = isEnabled
|
||||
}
|
||||
return super.onPrepareOptionsMenu(menu)
|
||||
|
||||
@@ -71,7 +71,6 @@ import com.kunzisoft.keepass.utils.MagikeyboardUtil
|
||||
import com.kunzisoft.keepass.utils.MenuUtil
|
||||
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
import com.kunzisoft.keepass.utils.allowCreateDocumentByStorageAccessFramework
|
||||
import com.kunzisoft.keepass.utils.getParcelableCompat
|
||||
import com.kunzisoft.keepass.view.asError
|
||||
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
|
||||
@@ -262,7 +261,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
|
||||
GroupActivity.launch(
|
||||
this@FileDatabaseSelectActivity,
|
||||
database,
|
||||
PreferencesUtil.enableReadOnlyDatabase(this@FileDatabaseSelectActivity)
|
||||
false
|
||||
)
|
||||
}
|
||||
ACTION_DATABASE_LOAD_TASK -> {
|
||||
@@ -329,13 +328,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
|
||||
// Show open and create button or special mode
|
||||
when (mSpecialMode) {
|
||||
SpecialMode.DEFAULT -> {
|
||||
if (packageManager.allowCreateDocumentByStorageAccessFramework()) {
|
||||
// There is an activity which can handle this intent.
|
||||
createDatabaseButtonView?.visibility = View.VISIBLE
|
||||
} else{
|
||||
// No Activity found that can handle this intent.
|
||||
createDatabaseButtonView?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// Disable create button if in selection mode or request for autofill
|
||||
|
||||
@@ -50,6 +50,7 @@ import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.DuplicateUuidDialog
|
||||
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
|
||||
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
|
||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||
import com.kunzisoft.keepass.biometric.DeviceUnlockFragment
|
||||
import com.kunzisoft.keepass.biometric.DeviceUnlockManager
|
||||
import com.kunzisoft.keepass.biometric.deviceUnlockError
|
||||
@@ -67,6 +68,7 @@ import com.kunzisoft.keepass.hardware.HardwareKey
|
||||
import com.kunzisoft.keepass.model.CipherDecryptDatabase
|
||||
import com.kunzisoft.keepass.model.CipherEncryptDatabase
|
||||
import com.kunzisoft.keepass.model.CredentialStorage
|
||||
import com.kunzisoft.keepass.model.DatabaseFile
|
||||
import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK
|
||||
@@ -74,8 +76,8 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.MAIN_CREDENTIAL_KEY
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.READ_ONLY_KEY
|
||||
import com.kunzisoft.keepass.settings.DeviceUnlockSettingsActivity
|
||||
import com.kunzisoft.keepass.settings.AppearanceSettingsActivity
|
||||
import com.kunzisoft.keepass.settings.DeviceUnlockSettingsActivity
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.utils.BACK_PREVIOUS_KEYBOARD_ACTION
|
||||
@@ -146,7 +148,7 @@ class MainCredentialActivity : DatabaseModeActivity() {
|
||||
mReadOnly = if (savedInstanceState != null && savedInstanceState.containsKey(KEY_READ_ONLY)) {
|
||||
savedInstanceState.getBoolean(KEY_READ_ONLY)
|
||||
} else {
|
||||
PreferencesUtil.enableReadOnlyDatabase(this)
|
||||
false
|
||||
}
|
||||
mRememberKeyFile = PreferencesUtil.rememberKeyFileLocations(this)
|
||||
mRememberHardwareKey = PreferencesUtil.rememberHardwareKey(this)
|
||||
@@ -202,6 +204,13 @@ class MainCredentialActivity : DatabaseModeActivity() {
|
||||
}
|
||||
mForceReadOnly = databaseFileNotExists
|
||||
|
||||
// Restore read-only state from database file if not forced
|
||||
if (!mForceReadOnly) {
|
||||
databaseFile?.readOnly?.let { savedReadOnlyState ->
|
||||
mReadOnly = savedReadOnlyState
|
||||
}
|
||||
}
|
||||
|
||||
invalidateOptionsMenu()
|
||||
|
||||
// Post init uri with KeyFile only if needed
|
||||
@@ -701,6 +710,12 @@ class MainCredentialActivity : DatabaseModeActivity() {
|
||||
R.id.menu_open_file_read_mode_key -> {
|
||||
mReadOnly = !mReadOnly
|
||||
changeOpenFileReadIcon(item)
|
||||
// Save the read-only state to database
|
||||
mDatabaseFileUri?.let { databaseUri ->
|
||||
FileDatabaseHistoryAction.getInstance(applicationContext).addOrUpdateDatabaseFile(
|
||||
DatabaseFile(databaseUri = databaseUri, readOnly = mReadOnly)
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> MenuUtil.onDefaultMenuOptionsItemSelected(this, item)
|
||||
}
|
||||
|
||||
@@ -538,9 +538,8 @@ class NodesAdapter (
|
||||
holder?.otpToken?.apply {
|
||||
text = otpElement?.tokenString
|
||||
setTextSize(mTextSizeUnit, mOtpTokenTextDefaultDimension, mPrefSizeMultiplier)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
textDirection = View.TEXT_DIRECTION_LTR
|
||||
}
|
||||
|
||||
}
|
||||
holder?.otpContainer?.setOnClickListener {
|
||||
otpElement?.token?.let { token ->
|
||||
|
||||
@@ -38,7 +38,6 @@ class App : MultiDexApplication() {
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver)
|
||||
|
||||
Stylish.load(this)
|
||||
PRNGFixes.apply()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,399 +0,0 @@
|
||||
package com.kunzisoft.keepass.app;
|
||||
|
||||
/*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will Google be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, as long as the origin is not misrepresented.
|
||||
*/
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Provider;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.SecureRandomSpi;
|
||||
import java.security.Security;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Fixes for the output of the default PRNG having low entropy.
|
||||
*
|
||||
* The fixes need to be applied via {@link #apply()} before any use of Java
|
||||
* Cryptography Architecture primitives. A good place to invoke them is in the
|
||||
* application's {@code onCreate}.
|
||||
*/
|
||||
public final class PRNGFixes {
|
||||
|
||||
private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL =
|
||||
getBuildFingerprintAndDeviceSerial();
|
||||
|
||||
/** Hidden constructor to prevent instantiation. */
|
||||
private PRNGFixes() {}
|
||||
|
||||
/**
|
||||
* Applies all fixes.
|
||||
*
|
||||
* @throws SecurityException if a fix is needed but could not be applied.
|
||||
*/
|
||||
public static void apply() {
|
||||
try {
|
||||
if (supportedOnThisDevice()) {
|
||||
applyOpenSSLFix();
|
||||
installLinuxPRNGSecureRandom();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Do nothing, do the best we can to implement the workaround
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean supportedOnThisDevice() {
|
||||
// Blacklist on samsung devices
|
||||
if (Build.MANUFACTURER.toLowerCase(Locale.ENGLISH).contains("samsung")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (onSELinuxEnforce()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File urandom = new File("/dev/urandom");
|
||||
|
||||
// Test permissions
|
||||
if ( !(urandom.canRead() && urandom.canWrite()) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Test actually writing to urandom
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(urandom);
|
||||
fos.write(0);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private static boolean onSELinuxEnforce() {
|
||||
try {
|
||||
ProcessBuilder builder = new ProcessBuilder("getenforce");
|
||||
builder.redirectErrorStream(true);
|
||||
java.lang.Process process = builder.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
process.waitFor();
|
||||
|
||||
String output = reader.readLine();
|
||||
|
||||
if (output == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return output.toLowerCase(Locale.US).startsWith("enforcing");
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
|
||||
* fix is not needed.
|
||||
*
|
||||
* @throws SecurityException if the fix is needed but could not be applied.
|
||||
*/
|
||||
private static void applyOpenSSLFix() throws SecurityException {
|
||||
if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
|
||||
|| (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2)) {
|
||||
// No need to apply the fix
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Mix in the device- and invocation-specific seed.
|
||||
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||
.getMethod("RAND_seed", byte[].class)
|
||||
.invoke(null, generateSeed());
|
||||
|
||||
// Mix output of Linux PRNG into OpenSSL's PRNG
|
||||
int bytesRead = (Integer) Class.forName(
|
||||
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||
.getMethod("RAND_load_file", String.class, long.class)
|
||||
.invoke(null, "/dev/urandom", 1024);
|
||||
if (bytesRead != 1024) {
|
||||
throw new IOException(
|
||||
"Unexpected number of bytes read from Linux PRNG: "
|
||||
+ bytesRead);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SecurityException("Failed to seed OpenSSL PRNG", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
|
||||
* default. Does nothing if the implementation is already the default or if
|
||||
* there is not need to install the implementation.
|
||||
*
|
||||
* @throws SecurityException if the fix is needed but could not be applied.
|
||||
*/
|
||||
private static void installLinuxPRNGSecureRandom()
|
||||
throws SecurityException {
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
// No need to apply the fix
|
||||
return;
|
||||
}
|
||||
|
||||
// Install a Linux PRNG-based SecureRandom implementation as the
|
||||
// default, if not yet installed.
|
||||
Provider[] secureRandomProviders =
|
||||
Security.getProviders("SecureRandom.SHA1PRNG");
|
||||
if ((secureRandomProviders == null)
|
||||
|| (secureRandomProviders.length < 1)
|
||||
|| (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
secureRandomProviders[0].getClass()))) {
|
||||
Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
|
||||
}
|
||||
|
||||
// Assert that new SecureRandom() and
|
||||
// SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
|
||||
// by the Linux PRNG-based SecureRandom implementation.
|
||||
SecureRandom rng1 = new SecureRandom();
|
||||
if (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
rng1.getProvider().getClass())) {
|
||||
throw new SecurityException(
|
||||
"new SecureRandom() backed by wrong Provider: "
|
||||
+ rng1.getProvider().getClass());
|
||||
}
|
||||
|
||||
SecureRandom rng2;
|
||||
try {
|
||||
rng2 = SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new SecurityException("SHA1PRNG not available", e);
|
||||
}
|
||||
if (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
rng2.getProvider().getClass())) {
|
||||
throw new SecurityException(
|
||||
"SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
|
||||
+ " Provider: " + rng2.getProvider().getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code Provider} of {@code SecureRandom} engines which pass through
|
||||
* all requests to the Linux PRNG.
|
||||
*/
|
||||
private static class LinuxPRNGSecureRandomProvider extends Provider {
|
||||
|
||||
public LinuxPRNGSecureRandomProvider() {
|
||||
super("LinuxPRNG",
|
||||
1.0,
|
||||
"A Linux-specific random number provider that uses"
|
||||
+ " /dev/urandom");
|
||||
// Although /dev/urandom is not a SHA-1 PRNG, some apps
|
||||
// explicitly request a SHA1PRNG SecureRandom and we thus need to
|
||||
// prevent them from getting the default implementation whose output
|
||||
// may have low entropy.
|
||||
put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
|
||||
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SecureRandomSpi} which passes all requests to the Linux PRNG
|
||||
* ({@code /dev/urandom}).
|
||||
*/
|
||||
public static class LinuxPRNGSecureRandom extends SecureRandomSpi {
|
||||
|
||||
/*
|
||||
* IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
|
||||
* are passed through to the Linux PRNG (/dev/urandom). Instances of
|
||||
* this class seed themselves by mixing in the current time, PID, UID,
|
||||
* build fingerprint, and hardware serial number (where available) into
|
||||
* Linux PRNG.
|
||||
*
|
||||
* Concurrency: Read requests to the underlying Linux PRNG are
|
||||
* serialized (on sLock) to ensure that multiple threads do not get
|
||||
* duplicated PRNG output.
|
||||
*/
|
||||
|
||||
private static final File URANDOM_FILE = new File("/dev/urandom");
|
||||
|
||||
|
||||
private static final Object sLock = new Object();
|
||||
|
||||
/**
|
||||
* Input stream for reading from Linux PRNG or {@code null} if not yet
|
||||
* opened.
|
||||
*
|
||||
* @GuardedBy("sLock")
|
||||
*/
|
||||
private static DataInputStream sUrandomIn;
|
||||
|
||||
/**
|
||||
* Output stream for writing to Linux PRNG or {@code null} if not yet
|
||||
* opened.
|
||||
*
|
||||
* @GuardedBy("sLock")
|
||||
*/
|
||||
private static OutputStream sUrandomOut;
|
||||
|
||||
/**
|
||||
* Whether this engine instance has been seeded. This is needed because
|
||||
* each instance needs to seed itself if the client does not explicitly
|
||||
* seed it.
|
||||
*/
|
||||
private boolean mSeeded;
|
||||
|
||||
@Override
|
||||
protected void engineSetSeed(byte[] bytes) {
|
||||
try {
|
||||
OutputStream out;
|
||||
synchronized (sLock) {
|
||||
out = getUrandomOutputStream();
|
||||
}
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
mSeeded = true;
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(
|
||||
"Failed to mix seed into " + URANDOM_FILE, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineNextBytes(byte[] bytes) {
|
||||
if (!mSeeded) {
|
||||
// Mix in the device- and invocation-specific seed.
|
||||
engineSetSeed(generateSeed());
|
||||
}
|
||||
|
||||
try {
|
||||
DataInputStream in;
|
||||
synchronized (sLock) {
|
||||
in = getUrandomInputStream();
|
||||
}
|
||||
synchronized (in) {
|
||||
in.readFully(bytes);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(
|
||||
"Failed to read from " + URANDOM_FILE, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineGenerateSeed(int size) {
|
||||
byte[] seed = new byte[size];
|
||||
engineNextBytes(seed);
|
||||
return seed;
|
||||
}
|
||||
|
||||
private DataInputStream getUrandomInputStream() {
|
||||
synchronized (sLock) {
|
||||
if (sUrandomIn == null) {
|
||||
// NOTE: Consider inserting a BufferedInputStream between
|
||||
// DataInputStream and FileInputStream if you need higher
|
||||
// PRNG output performance and can live with future PRNG
|
||||
// output being pulled into this process prematurely.
|
||||
try {
|
||||
sUrandomIn = new DataInputStream(
|
||||
new FileInputStream(URANDOM_FILE));
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Failed to open "
|
||||
+ URANDOM_FILE + " for reading", e);
|
||||
}
|
||||
}
|
||||
return sUrandomIn;
|
||||
}
|
||||
}
|
||||
|
||||
private OutputStream getUrandomOutputStream() {
|
||||
synchronized (sLock) {
|
||||
if (sUrandomOut == null) {
|
||||
try {
|
||||
sUrandomOut = new FileOutputStream(URANDOM_FILE);
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Failed to open "
|
||||
+ URANDOM_FILE + " for writing", e);
|
||||
}
|
||||
}
|
||||
return sUrandomOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a device- and invocation-specific seed to be mixed into the
|
||||
* Linux PRNG.
|
||||
*/
|
||||
private static byte[] generateSeed() {
|
||||
try {
|
||||
ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
|
||||
DataOutputStream seedBufferOut =
|
||||
new DataOutputStream(seedBuffer);
|
||||
seedBufferOut.writeLong(System.currentTimeMillis());
|
||||
seedBufferOut.writeLong(System.nanoTime());
|
||||
seedBufferOut.writeInt(Process.myPid());
|
||||
seedBufferOut.writeInt(Process.myUid());
|
||||
seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
|
||||
seedBufferOut.close();
|
||||
return seedBuffer.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Failed to generate seed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hardware serial number of this device.
|
||||
*
|
||||
* @return serial number or {@code null} if not available.
|
||||
*/
|
||||
private static String getDeviceSerialNumber() {
|
||||
// We're using the Reflection API because Build.SERIAL is only available
|
||||
// since API Level 9 (Gingerbread, Android 2.3).
|
||||
try {
|
||||
return (String) Build.class.getField("SERIAL").get(null);
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBuildFingerprintAndDeviceSerial() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
String fingerprint = Build.FINGERPRINT;
|
||||
if (fingerprint != null) {
|
||||
result.append(fingerprint);
|
||||
}
|
||||
String serial = getDeviceSerialNumber();
|
||||
if (serial != null) {
|
||||
result.append(serial);
|
||||
}
|
||||
try {
|
||||
return result.toString().getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("UTF-8 encoding not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,10 +26,11 @@ import android.content.Context
|
||||
import androidx.room.AutoMigration
|
||||
|
||||
@Database(
|
||||
version = 2,
|
||||
version = 3,
|
||||
entities = [FileDatabaseHistoryEntity::class, CipherDatabaseEntity::class],
|
||||
autoMigrations = [
|
||||
AutoMigration (from = 1, to = 2)
|
||||
AutoMigration (from = 1, to = 2),
|
||||
AutoMigration (from = 2, to = 3)
|
||||
]
|
||||
)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
@@ -49,6 +49,7 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
||||
databaseUri,
|
||||
fileDatabaseHistoryEntity?.keyFileUri?.parseUri(),
|
||||
HardwareKey.getHardwareKeyFromString(fileDatabaseHistoryEntity?.hardwareKey),
|
||||
fileDatabaseHistoryEntity?.readOnly,
|
||||
fileDatabaseHistoryEntity?.databaseUri?.decodeUri(),
|
||||
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity?.databaseAlias
|
||||
?: ""),
|
||||
@@ -99,6 +100,7 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
||||
fileDatabaseHistoryEntity.databaseUri.parseUri(),
|
||||
fileDatabaseHistoryEntity.keyFileUri?.parseUri(),
|
||||
HardwareKey.getHardwareKeyFromString(fileDatabaseHistoryEntity.hardwareKey),
|
||||
fileDatabaseHistoryEntity.readOnly,
|
||||
fileDatabaseHistoryEntity.databaseUri.decodeUri(),
|
||||
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity.databaseAlias),
|
||||
fileDatabaseInfo.exists,
|
||||
@@ -147,6 +149,8 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
||||
?: "",
|
||||
databaseFileToAddOrUpdate.keyFileUri?.toString(),
|
||||
databaseFileToAddOrUpdate.hardwareKey?.value,
|
||||
databaseFileToAddOrUpdate.readOnly
|
||||
?: fileDatabaseHistoryRetrieve?.readOnly,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
|
||||
@@ -168,6 +172,7 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
||||
fileDatabaseHistory.databaseUri.parseUri(),
|
||||
fileDatabaseHistory.keyFileUri?.parseUri(),
|
||||
HardwareKey.getHardwareKeyFromString(fileDatabaseHistory.hardwareKey),
|
||||
fileDatabaseHistory.readOnly,
|
||||
fileDatabaseHistory.databaseUri.decodeUri(),
|
||||
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistory.databaseAlias),
|
||||
fileDatabaseInfo.exists,
|
||||
@@ -195,6 +200,7 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
|
||||
fileDatabaseHistory.databaseUri.parseUri(),
|
||||
fileDatabaseHistory.keyFileUri?.parseUri(),
|
||||
HardwareKey.getHardwareKeyFromString(fileDatabaseHistory.hardwareKey),
|
||||
fileDatabaseHistory.readOnly,
|
||||
fileDatabaseHistory.databaseUri.decodeUri(),
|
||||
databaseFileToDelete.databaseAlias
|
||||
)
|
||||
|
||||
@@ -38,6 +38,9 @@ data class FileDatabaseHistoryEntity(
|
||||
@ColumnInfo(name = "hardware_key")
|
||||
var hardwareKey: String?,
|
||||
|
||||
@ColumnInfo(name = "read_only")
|
||||
var readOnly: Boolean?,
|
||||
|
||||
@ColumnInfo(name = "updated")
|
||||
val updated: Long
|
||||
) {
|
||||
|
||||
@@ -618,12 +618,6 @@ object PreferencesUtil {
|
||||
context.resources.getBoolean(R.bool.allow_no_password_default))
|
||||
}
|
||||
|
||||
fun enableReadOnlyDatabase(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getBoolean(context.getString(R.string.enable_read_only_key),
|
||||
context.resources.getBoolean(R.bool.enable_read_only_default))
|
||||
}
|
||||
|
||||
fun deletePasswordAfterConnexionAttempt(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getBoolean(context.getString(R.string.delete_entered_password_key),
|
||||
@@ -804,7 +798,6 @@ object PreferencesUtil {
|
||||
when (name) {
|
||||
context.getString(R.string.allow_no_password_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.delete_entered_password_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.enable_read_only_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.enable_auto_save_database_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.enable_keep_screen_on_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.auto_focus_search_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
|
||||
@@ -65,7 +65,6 @@ object TimeoutHelper {
|
||||
(context.applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager?)?.let { alarmManager ->
|
||||
val triggerTime = System.currentTimeMillis() + timeout
|
||||
Log.d(TAG, "TimeoutHelper start")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||
&& !alarmManager.canScheduleExactAlarms()) {
|
||||
alarmManager.set(
|
||||
@@ -80,13 +79,6 @@ object TimeoutHelper {
|
||||
getLockPendingIntent(context)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
alarmManager.set(
|
||||
AlarmManager.RTC,
|
||||
triggerTime,
|
||||
getLockPendingIntent(context)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ class LockReceiver(private var lockAction: () -> Unit) : BroadcastReceiver() {
|
||||
// Launch the effective action after a small time
|
||||
val first: Long = System.currentTimeMillis() + context.getString(R.string.timeout_screen_off).toLong()
|
||||
(context.getSystemService(ALARM_SERVICE) as AlarmManager?)?.let { alarmManager ->
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||
&& !alarmManager.canScheduleExactAlarms()) {
|
||||
alarmManager.set(
|
||||
@@ -92,13 +91,6 @@ class LockReceiver(private var lockAction: () -> Unit) : BroadcastReceiver() {
|
||||
lockPendingIntent
|
||||
)
|
||||
}
|
||||
} else {
|
||||
alarmManager.set(
|
||||
AlarmManager.RTC_WAKEUP,
|
||||
first,
|
||||
lockPendingIntent
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cancelLockPendingIntent(context)
|
||||
|
||||
@@ -67,7 +67,6 @@ object UriUtil {
|
||||
readOnly: Boolean) {
|
||||
try {
|
||||
// try to persist read and write permissions
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
contentResolver?.apply {
|
||||
var readPermissionAllowed = false
|
||||
var writePermissionAllowed = false
|
||||
@@ -118,7 +117,6 @@ object UriUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (release)
|
||||
Log.e(TAG, "Unable to release persistable URI permission", e)
|
||||
@@ -140,7 +138,6 @@ object UriUtil {
|
||||
}
|
||||
|
||||
fun Context.releaseAllUnnecessaryPermissionUris() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
applicationContext?.let { appContext ->
|
||||
val fileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(appContext)
|
||||
fileDatabaseHistoryAction.getDatabaseFileList { databaseFileList ->
|
||||
@@ -163,11 +160,9 @@ object UriUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Intent.getUri(key: String): Uri? {
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
val clipData = this.clipData
|
||||
if (clipData != null) {
|
||||
if (clipData.description.label == key) {
|
||||
@@ -179,7 +174,6 @@ object UriUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return this.getParcelableExtraCompat(key)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package com.kunzisoft.keepass.view
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.text.Spannable
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
@@ -104,21 +103,17 @@ class PasswordTextEditFieldView @JvmOverloads constructor(context: Context,
|
||||
id = passwordProgressViewId
|
||||
layoutParams = (layoutParams as LayoutParams?)?.also {
|
||||
it.addRule(LEFT_OF, actionImageButtonId)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it.addRule(START_OF, actionImageButtonId)
|
||||
}
|
||||
}
|
||||
}
|
||||
mPasswordEntropyView.apply {
|
||||
id = passwordEntropyViewId
|
||||
layoutParams = (layoutParams as LayoutParams?)?.also {
|
||||
it.addRule(ALIGN_RIGHT, passwordProgressViewId)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it.addRule(ALIGN_END, passwordProgressViewId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getEntropyStrength(passwordText: String) {
|
||||
mPasswordEntropyCalculator.getEntropyStrength(passwordText) { entropyStrength ->
|
||||
|
||||
@@ -125,7 +125,6 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
setMaxChars(templateAttribute.options.getNumberChars())
|
||||
setMaxLines(templateAttribute.options.getNumberLines())
|
||||
setActionClick(templateAttribute, field, this)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
if (field.protectedValue.isProtected) {
|
||||
textDirection = TEXT_DIRECTION_LTR
|
||||
}
|
||||
@@ -135,7 +134,6 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun buildListItemsView(templateAttribute: TemplateAttribute,
|
||||
field: Field): TextSelectFieldView? {
|
||||
|
||||
@@ -68,9 +68,7 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
// Here the value is often empty
|
||||
|
||||
if (field.protectedValue.isProtected) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
textDirection = TEXT_DIRECTION_LTR
|
||||
}
|
||||
if (mFirstTimeAskAllowCopyProtectedFields) {
|
||||
setCopyButtonState(TextFieldView.ButtonState.DEACTIVATE)
|
||||
setCopyButtonClickListener { _, _ ->
|
||||
@@ -184,9 +182,7 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
otpElement.type.name,
|
||||
ProtectedString(false, otpElement.token)))
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
textDirection = TEXT_DIRECTION_LTR
|
||||
}
|
||||
mLastOtpTokenView = this
|
||||
mOtpRunnable = Runnable {
|
||||
if (otpElement.shouldRefreshToken()) {
|
||||
|
||||
@@ -51,9 +51,7 @@ open class TextEditFieldView @JvmOverloads constructor(context: Context,
|
||||
imeOptions = EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
||||
importantForAutofill = IMPORTANT_FOR_AUTOFILL_NO
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_NO
|
||||
}
|
||||
maxLines = 1
|
||||
}
|
||||
private var actionImageButton = AppCompatImageButton(
|
||||
@@ -70,11 +68,9 @@ open class TextEditFieldView @JvmOverloads constructor(context: Context,
|
||||
resources.displayMetrics
|
||||
).toInt()
|
||||
it.addRule(ALIGN_PARENT_RIGHT)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it.addRule(ALIGN_PARENT_END)
|
||||
}
|
||||
}
|
||||
visibility = View.GONE
|
||||
visibility = GONE
|
||||
contentDescription = context.getString(R.string.menu_edit)
|
||||
}
|
||||
|
||||
@@ -91,11 +87,9 @@ open class TextEditFieldView @JvmOverloads constructor(context: Context,
|
||||
id = labelViewId
|
||||
layoutParams = (layoutParams as LayoutParams?)?.also {
|
||||
it.addRule(LEFT_OF, actionImageButtonId)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it.addRule(START_OF, actionImageButtonId)
|
||||
}
|
||||
}
|
||||
}
|
||||
valueView.apply {
|
||||
id = valueViewId
|
||||
}
|
||||
@@ -192,7 +186,7 @@ open class TextEditFieldView @JvmOverloads constructor(context: Context,
|
||||
actionImageButton.setImageDrawable(ContextCompat.getDrawable(context, it))
|
||||
}
|
||||
actionImageButton.setOnClickListener(onActionClickListener)
|
||||
actionImageButton.visibility = if (onActionClickListener == null) View.GONE else View.VISIBLE
|
||||
actionImageButton.visibility = if (onActionClickListener == null) GONE else VISIBLE
|
||||
}
|
||||
|
||||
override var isFieldVisible: Boolean
|
||||
|
||||
@@ -62,13 +62,12 @@ open class TextFieldView @JvmOverloads constructor(context: Context,
|
||||
4f,
|
||||
resources.displayMetrics
|
||||
).toInt()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it.marginStart = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
4f,
|
||||
resources.displayMetrics
|
||||
).toInt()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
protected val valueView = AppCompatTextView(context).apply {
|
||||
@@ -87,14 +86,12 @@ open class TextFieldView @JvmOverloads constructor(context: Context,
|
||||
8f,
|
||||
resources.displayMetrics
|
||||
).toInt()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it.marginStart = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
8f,
|
||||
resources.displayMetrics
|
||||
).toInt()
|
||||
}
|
||||
}
|
||||
setTextIsSelectable(true)
|
||||
}
|
||||
private var showButton = AppCompatImageButton(
|
||||
@@ -127,24 +124,22 @@ open class TextFieldView @JvmOverloads constructor(context: Context,
|
||||
id = copyButtonId
|
||||
layoutParams = (layoutParams as LayoutParams?)?.also {
|
||||
it.addRule(ALIGN_PARENT_RIGHT)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it.addRule(ALIGN_PARENT_END)
|
||||
}
|
||||
}
|
||||
}
|
||||
showButton.apply {
|
||||
id = showButtonId
|
||||
layoutParams = (layoutParams as LayoutParams?)?.also {
|
||||
if (copyButton.isVisible) {
|
||||
it.addRule(LEFT_OF, copyButtonId)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
|
||||
it.addRule(START_OF, copyButtonId)
|
||||
}
|
||||
|
||||
} else {
|
||||
it.addRule(ALIGN_PARENT_RIGHT)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
|
||||
it.addRule(ALIGN_PARENT_END)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,18 +147,14 @@ open class TextFieldView @JvmOverloads constructor(context: Context,
|
||||
id = labelViewId
|
||||
layoutParams = (layoutParams as LayoutParams?)?.also {
|
||||
it.addRule(LEFT_OF, showButtonId)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it.addRule(START_OF, showButtonId)
|
||||
}
|
||||
}
|
||||
}
|
||||
valueView.apply {
|
||||
id = valueViewId
|
||||
layoutParams = (layoutParams as LayoutParams?)?.also {
|
||||
it.addRule(LEFT_OF, showButtonId)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it.addRule(START_OF, showButtonId)
|
||||
}
|
||||
it.addRule(BELOW, labelViewId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,12 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.*
|
||||
import android.widget.AdapterView
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.appcompat.widget.AppCompatImageButton
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -51,9 +56,7 @@ class TextSelectFieldView @JvmOverloads constructor(context: Context,
|
||||
imeOptions = EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
||||
importantForAutofill = IMPORTANT_FOR_AUTOFILL_NO
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_NO
|
||||
}
|
||||
val drawable = ContextCompat.getDrawable(context, R.drawable.ic_arrow_down_white_24dp)
|
||||
?.apply {
|
||||
mutate().colorFilter = BlendModeColorFilterCompat
|
||||
@@ -65,14 +68,12 @@ class TextSelectFieldView @JvmOverloads constructor(context: Context,
|
||||
drawable,
|
||||
null
|
||||
)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
null,
|
||||
null,
|
||||
drawable,
|
||||
null
|
||||
)
|
||||
}
|
||||
isFocusable = false
|
||||
inputType = InputType.TYPE_NULL
|
||||
maxLines = 1
|
||||
@@ -94,10 +95,8 @@ class TextSelectFieldView @JvmOverloads constructor(context: Context,
|
||||
resources.displayMetrics
|
||||
).toInt()
|
||||
it.addRule(ALIGN_PARENT_RIGHT)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it.addRule(ALIGN_PARENT_END)
|
||||
}
|
||||
}
|
||||
visibility = View.GONE
|
||||
contentDescription = context.getString(R.string.menu_edit)
|
||||
}
|
||||
@@ -132,18 +131,14 @@ class TextSelectFieldView @JvmOverloads constructor(context: Context,
|
||||
id = labelViewId
|
||||
layoutParams = (layoutParams as LayoutParams?).also {
|
||||
it?.addRule(LEFT_OF, actionImageButtonId)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it?.addRule(START_OF, actionImageButtonId)
|
||||
}
|
||||
}
|
||||
}
|
||||
valueSpinnerView.apply {
|
||||
id = valueViewId
|
||||
layoutParams = (layoutParams as LayoutParams?).also {
|
||||
it?.addRule(LEFT_OF, actionImageButtonId)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
it?.addRule(START_OF, actionImageButtonId)
|
||||
}
|
||||
it?.addRule(BELOW, labelViewId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,11 +234,7 @@ fun View.updateLockPaddingStart() {
|
||||
R.dimen.hidden_lock_button_size
|
||||
}
|
||||
).let { lockPadding ->
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
updatePaddingRelative(lockPadding)
|
||||
} else {
|
||||
updatePadding(lockPadding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,8 +122,7 @@
|
||||
android:inputType="textPassword"
|
||||
android:importantForAccessibility="no"
|
||||
android:importantForAutofill="no"
|
||||
android:hint="@string/otp_secret"
|
||||
tools:targetApi="jelly_bean" />
|
||||
android:hint="@string/otp_secret" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -178,8 +177,7 @@
|
||||
tools:text="30"
|
||||
android:maxLength="3"
|
||||
android:digits="0123456789"
|
||||
android:imeOptions="actionNext"
|
||||
tools:targetApi="jelly_bean" />
|
||||
android:imeOptions="actionNext" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/setup_otp_counter_label"
|
||||
@@ -198,8 +196,7 @@
|
||||
android:importantForAutofill="no"
|
||||
android:hint="@string/otp_counter"
|
||||
tools:text="1"
|
||||
android:imeOptions="actionNext"
|
||||
tools:targetApi="jelly_bean" />
|
||||
android:imeOptions="actionNext" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
@@ -228,8 +225,7 @@
|
||||
tools:text="6"
|
||||
android:maxLength="2"
|
||||
android:digits="0123456789"
|
||||
android:imeOptions="actionNext"
|
||||
tools:targetApi="jelly_bean" />
|
||||
android:imeOptions="actionNext" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
@@ -65,7 +65,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_arrow_right_white_24dp"
|
||||
app:tint="?attr/colorOnSurface"
|
||||
android:importantForAccessibility="no"
|
||||
tools:targetApi="jelly_bean" />
|
||||
android:importantForAccessibility="no" />
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
@@ -213,8 +213,6 @@
|
||||
<string name="keyboard_key_vibrate_title">إهتزاز عند اللمس</string>
|
||||
<string name="keyboard_key_sound_title">صوت عند اللمس</string>
|
||||
<string name="allow_no_password_title">اسمح بدون المفتاح الرئيسي</string>
|
||||
<string name="enable_read_only_title">محمي من التعديل</string>
|
||||
<string name="enable_read_only_summary">افتح قاعدة البيانات في وضع القراءة افتراضيا</string>
|
||||
<string name="enable_education_screens_title">تلميحات تعليمية</string>
|
||||
<string name="reset_education_screens_summary">أعد عرض كل المعلومات التعليمية</string>
|
||||
<string name="reset_education_screens_text">إعادة تعيين الشاشات التلميحات</string>
|
||||
|
||||
@@ -349,7 +349,6 @@
|
||||
<string name="autofill_save_search_info_title">Axtarış məlumatlarını yadda saxla</string>
|
||||
<string name="autofill_inline_suggestions_keyboard">Avtomatik doldurma təklifləri əlavə edildi.</string>
|
||||
<string name="allow_no_password_title">Ana açar olmamasına icazə ver</string>
|
||||
<string name="enable_read_only_summary">Məlumat bazasını standart olaraq yazma-qorumalı (dəyişməz) aç</string>
|
||||
<string name="enable_auto_save_database_title">Məlumat bazasını avtomatik olaraq yadda saxla</string>
|
||||
<string name="reset_education_screens_summary">Bütün təlim məlumatlarını yenidən göstər</string>
|
||||
<string name="reset_education_screens_text">Təlim ipuclarını sıfırlamaq</string>
|
||||
@@ -572,7 +571,6 @@
|
||||
<string name="allow_no_password_summary">Əgər şəxsiyyəti təsdiq edən məlumatlar seçilməyibsə, \"Aç\" düyməsinin sıxılmasına icazə ver</string>
|
||||
<string name="delete_entered_password_title">Şifrəni sil</string>
|
||||
<string name="delete_entered_password_summary">Məlumat bazasına bağlantı cəhdindən sonra daxil edilmiş şifrəni sil</string>
|
||||
<string name="enable_read_only_title">Yazma qorumalı</string>
|
||||
<string name="enable_auto_save_database_summary">Hər önəmli prossesdən sonra məlumat bazasını yadda saxla (\"Modifikasiya edilə bilən\" modda keçərlidir)</string>
|
||||
<string name="enable_keep_screen_on_title">Ekranı açıq saxla</string>
|
||||
<string name="enable_keep_screen_on_summary">Şifrəyə baxarkən və ya redaktə edərkən ekranı açıq saxla</string>
|
||||
|
||||
@@ -352,7 +352,6 @@
|
||||
<string name="keyboard_setting_label">Настройки на Magikeyboard</string>
|
||||
<string name="keyboard_selection_entry_title">Избор на записи</string>
|
||||
<string name="allow_no_password_title">Разрешаване без главна парола</string>
|
||||
<string name="enable_read_only_title">Само за четене</string>
|
||||
<string name="keyboard_notification_entry_content_text">%1$s</string>
|
||||
<string name="keyboard_notification_entry_content_title">Записът %1$s е достъпен в Magikeyboard</string>
|
||||
<string name="keyboard_notification_entry_content_title_text">Запис</string>
|
||||
@@ -402,7 +401,6 @@
|
||||
<string name="lock_database_show_button_title">Бутон за заключване</string>
|
||||
<string name="autofill_explanation_summary">Включете услугата за попълване на формуляри в други приложения</string>
|
||||
<string name="properties">Свойства</string>
|
||||
<string name="enable_read_only_summary">По подразбиране отваря хранилището само за четене</string>
|
||||
<string name="education_validate_entry_summary">Не забравяйте да потвърдите записа и да го запазите в хранилището.
|
||||
\n
|
||||
\nАко се задейства автоматичното заключване, а сте направили промени, рискувате загуба на данни.</string>
|
||||
|
||||
@@ -471,8 +471,6 @@
|
||||
<string name="menu_database_settings_summary">Metadades, paperera de reciclatge, plantilles, historial</string>
|
||||
<string name="encryption_explanation">Algorisme de xifratge de la base de dades utilitzat per a totes les dades</string>
|
||||
<string name="delete_entered_password_summary">Suprimeix la contrasenya introduïda després d\'un intent de connexió a una base de dades</string>
|
||||
<string name="enable_read_only_title">Protegit contra l\'escriptura</string>
|
||||
<string name="enable_read_only_summary">Obre la base de dades en mode només de lectura per defecte</string>
|
||||
<string name="enable_screenshot_mode_summary">Permet que les aplicacions de tercers gravin o facin captures de pantalla de l\'aplicació</string>
|
||||
<string name="enable_education_screens_summary">Ressalta els elements per saber com funciona l\'aplicació</string>
|
||||
<string name="reset_education_screens_title">Reinicia els consells educatius</string>
|
||||
|
||||
@@ -224,8 +224,6 @@
|
||||
<string name="magic_keyboard_explanation_summary">Aktivovat vlastní klávesnici, která snadno vyplní hesla a další položky identity</string>
|
||||
<string name="allow_no_password_title">Umožnit bez hlavního klíče</string>
|
||||
<string name="allow_no_password_summary">Povolit klepnutí na \"Otevřít\", i když není vybráno žádné heslo</string>
|
||||
<string name="enable_read_only_title">Chráněno před zápisem</string>
|
||||
<string name="enable_read_only_summary">Ve výchozím stavu otevřít databázi pouze pro čtení</string>
|
||||
<string name="enable_education_screens_title">Vzdělávací nápovědy</string>
|
||||
<string name="enable_education_screens_summary">Zvýraznit prvky k pochopení práce s aplikací</string>
|
||||
<string name="reset_education_screens_title">Nastavit vzdělávací nápovědy do výchozího stavu</string>
|
||||
|
||||
@@ -223,8 +223,6 @@
|
||||
<string name="magic_keyboard_explanation_summary">Aktiver et brugerdefineret tastatur, der udfylder adgangskoder og alle identitetsfelter</string>
|
||||
<string name="allow_no_password_title">Tillad ingen hovednøgle</string>
|
||||
<string name="allow_no_password_summary">Tillader at trykke på knappen \"Åbn\", hvis der ikke er valgt nogen legitimationsoplysninger</string>
|
||||
<string name="enable_read_only_title">Skrivebeskyttet</string>
|
||||
<string name="enable_read_only_summary">Åbn som standard databasen skrivebeskyttet</string>
|
||||
<string name="enable_education_screens_title">Praktiske tips</string>
|
||||
<string name="enable_education_screens_summary">Fremhæv elementer for at lære, hvordan appen fungerer</string>
|
||||
<string name="reset_education_screens_title">Nulstil praktiske tips</string>
|
||||
|
||||
@@ -277,9 +277,7 @@
|
||||
<string name="enable_education_screens_summary">Bedienelemente hervorheben, um die Funktionsweise der App zu lernen</string>
|
||||
<string name="menu_open_file_read_and_write">Änderbar</string>
|
||||
<string name="menu_file_selection_read_only">Schreibgeschützt</string>
|
||||
<string name="enable_read_only_title">Schreibgeschützt</string>
|
||||
<string name="education_read_only_title">Datenbank-Schreibschutz aktivieren</string>
|
||||
<string name="enable_read_only_summary">Datenbank standardmäßig schreibgeschützt öffnen</string>
|
||||
<string name="education_read_only_summary">Den Öffnungsmodus für die Sitzung ändern. \n \n„Schreibgeschützt“ verhindert unbeabsichtigte Änderungen an der Datenbank. \nMit „Änderbar“ lässt sich jedes Element frei bearbeiten, hinzufügen oder löschen.</string>
|
||||
<string name="edit_entry">Eintrag bearbeiten</string>
|
||||
<string name="error_load_database">Die Datenbank konnte nicht geladen werden.</string>
|
||||
|
||||
@@ -259,8 +259,6 @@
|
||||
<string name="enable_education_screens_summary">Επισήμανση στοιχείων για να μάθετε πώς λειτουργεί η εφαρμογή</string>
|
||||
<string name="menu_file_selection_read_only">Προστασία εγγραφής</string>
|
||||
<string name="menu_open_file_read_and_write">Τροποποιήσιμο</string>
|
||||
<string name="enable_read_only_title">Προστασία Εγγραφής</string>
|
||||
<string name="enable_read_only_summary">Ανοίξτε τη βάση δεδομένων μόνο για ανάγνωση από προεπιλογή</string>
|
||||
<string name="education_read_only_title">Προστασία Εγγραφής της βάσης δεδομένων σας</string>
|
||||
<string name="education_read_only_summary">Αλλάξτε τη λειτουργία ανοίγματος για το session.
|
||||
\n
|
||||
|
||||
@@ -271,8 +271,6 @@
|
||||
<string name="allow_no_password_summary">Permite pulsar el botón \"Abrir\" si no son seleccionadas las credenciales</string>
|
||||
<string name="enable_education_screens_title">Consejos educativos</string>
|
||||
<string name="enable_education_screens_summary">Destaca los 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_summary">Abre la base de datos como solo lectura por defecto</string>
|
||||
<string name="education_read_only_title">Proteja la base de datos contra escritura</string>
|
||||
<string name="keyboard_name">Magikeyboard</string>
|
||||
<string name="keyboard_label">Magikeyboard (KeePassDX)</string>
|
||||
|
||||
@@ -531,7 +531,6 @@
|
||||
<string name="autofill_inline_suggestions_keyboard">Automaattäite soovitused on lisatud.</string>
|
||||
<string name="autofill_read_only_save">Kui andmebaas on avatud ainult lugemiseks, siis andmete salvestamine pole võimalik.</string>
|
||||
<string name="delete_entered_password_summary">Kustutab salasõna, mis oli kasutusel andmebaasiga ühenduse loomise ajal</string>
|
||||
<string name="enable_read_only_summary">Vaikimisi ava andmebaas vaid lugemiseks</string>
|
||||
<string name="enable_screenshot_mode_summary">Luba teistel rakendusel teha sellest rakendusest ekraanitõmmist või salvestada tema ekraanivaadet</string>
|
||||
<string name="autofill_close_database_title">Sulge andmebaas</string>
|
||||
<string name="autofill_close_database_summary">Peale automaattäite kasutamist sulega andmebaas</string>
|
||||
@@ -547,7 +546,6 @@
|
||||
<string name="allow_no_password_title">Ära kasuta peavõtit</string>
|
||||
<string name="allow_no_password_summary">Kui kasutajanimi või salasõna pole valitud, siis võimaldab klõpsida „Ava“ nuppu</string>
|
||||
<string name="delete_entered_password_title">Kustuta salasõna</string>
|
||||
<string name="enable_read_only_title">Kirjutuskaitstud</string>
|
||||
<string name="enable_screenshot_mode_title">Ekraanitõmmiste lubamine</string>
|
||||
<string name="enable_education_screens_title">Koolitusvihjed</string>
|
||||
<string name="enable_education_screens_summary">Õppimaks, kuidas rakendus toimib, tõsta esile kasutajaliidese elemente</string>
|
||||
|
||||
@@ -397,7 +397,6 @@
|
||||
<string name="memory_usage_explanation">Gakoaren eratorpen funtzioak erabiliko duen memoria kopurua.</string>
|
||||
<string name="autofill_ask_to_save_data_summary">Datuak gordetzeko eskatu formulario bat betetzean</string>
|
||||
<string name="education_select_database_summary">Ireki zure aurreko datu-base fitxategia zure fitxategi kudeatzailetik erabiltzen jarraitzeko.</string>
|
||||
<string name="enable_read_only_title">Idazketaren aurka babestuta</string>
|
||||
<string name="autofill_application_id_blocklist_title">Aplikazioen blokeo zerrenda</string>
|
||||
<string name="keyboard_previous_fill_in_title">Tekla automatikoaren akzioa</string>
|
||||
<string name="keyboard_previous_database_credentials_summary">Aldatu automatikoki aurreko teklatura datu-basearen kredentzialen pantailan</string>
|
||||
@@ -478,7 +477,6 @@
|
||||
<string name="kdf_explanation">Zifraketa algoritmorako gakoa sortzeko, gako nagusia itxuraldatu egiten da eratorpen funtzio eta ausazko gatz baten bidez.</string>
|
||||
<string name="keyboard_previous_search_title">Bilaketa pantaila</string>
|
||||
<string name="autofill_manual_selection_summary">Erabiltzaileari datu-baseko sarrera hautatzeko aukera erakutsi</string>
|
||||
<string name="enable_read_only_summary">Lehenetsi irakurketa soilerako datu-basea irekitzea</string>
|
||||
<string name="reset_education_screens_title">Berrezarri hezkuntza-pistak</string>
|
||||
<string name="education_new_node_summary">Sarrerek zure identitate digitalak administratzen laguntzen dute.
|
||||
\n
|
||||
|
||||
@@ -283,8 +283,6 @@
|
||||
<string name="allow_no_password_summary">Autorise l’appui du bouton \"Ouvrir\" si aucun identifiant n’est sélectionné</string>
|
||||
<string name="menu_file_selection_read_only">Protéger en écriture</string>
|
||||
<string name="menu_open_file_read_and_write">Modifiable</string>
|
||||
<string name="enable_read_only_title">Protéger en écriture</string>
|
||||
<string name="enable_read_only_summary">Ouvre la base de données en lecture seule par défaut</string>
|
||||
<string name="education_read_only_title">Protégez en écriture votre base de données</string>
|
||||
<string name="education_read_only_summary">Changez le mode d’ouverture pour la session.
|
||||
\n
|
||||
|
||||
@@ -556,7 +556,6 @@
|
||||
<string name="enable_auto_save_database_title">Gardar base de datos automaticamente</string>
|
||||
<string name="enable_keep_screen_on_title">Manter a pantalla acesa</string>
|
||||
<string name="allow_no_password_summary">Permitir pulsar o botón \"Abrir\" se non seleccionar ningunha credencial</string>
|
||||
<string name="enable_read_only_title">Só lectura</string>
|
||||
<string name="enable_education_screens_summary">Destacar elementos para saber como funciona a aplicación</string>
|
||||
<string name="reset_education_screens_text">Suxestións educativas restabelecidas</string>
|
||||
<string name="education_create_database_title">Crear o teu arquivo de base de datos</string>
|
||||
@@ -593,7 +592,6 @@
|
||||
<string name="education_entry_new_field_title">Engadir campos personalizados</string>
|
||||
<string name="menu_form_filling_settings">Completado de formularios</string>
|
||||
<string name="keyboard_notification_entry_content_title">%1$s dispoñíbel no Magikeyboard</string>
|
||||
<string name="enable_read_only_summary">Abrir a base de datos en modo de só lectura por defecto</string>
|
||||
<string name="education_setup_OTP_summary">Configure a xestión do contrasinal dun só uso (HOTP / TOTP) para xerar un token solicitado para a autenticación de dous factores (2FA).</string>
|
||||
<string name="education_unlock_title">Desbloquee a súa base de datos</string>
|
||||
<string name="delete_entered_password_title">Eliminar contrasinal</string>
|
||||
|
||||
@@ -310,8 +310,6 @@
|
||||
<string name="allow_no_password_summary">Dozvoljava dodir gumba „Otvori”, ako nisu odabrani nikoji podaci za prijavu</string>
|
||||
<string name="delete_entered_password_title">Izbriši lozinku</string>
|
||||
<string name="delete_entered_password_summary">Briše upisanu lozinku nakon pokušaja povezivanja s bazom podataka</string>
|
||||
<string name="enable_read_only_title">Zaštićeno od pisanja</string>
|
||||
<string name="enable_read_only_summary">Standardno otvori bazu podataka u zaštićenom stanju</string>
|
||||
<string name="enable_auto_save_database_title">Automatski spremi bazu podataka</string>
|
||||
<string name="enable_auto_save_database_summary">Automatski spremi bazu podataka nakon svake važne radnje (samo u modusu „Promjenjivo”)</string>
|
||||
<string name="enable_education_screens_title">Edukativne poruke</string>
|
||||
|
||||
@@ -245,8 +245,6 @@
|
||||
<string name="keyboard_key_sound_title">Hang gombnyomáskor</string>
|
||||
<string name="allow_no_password_title">Mesterkulcs elhagyásának engedélyezése</string>
|
||||
<string name="allow_no_password_summary">A „Megnyitás” gomb engedélyezése, ha nincsenek hitelesítő adatok kiválasztva</string>
|
||||
<string name="enable_read_only_title">Írásvédett</string>
|
||||
<string name="enable_read_only_summary">Az adatbázis megnyitása alapértelmezetten írásvédett módban</string>
|
||||
<string name="enable_education_screens_title">Oktatóképernyők</string>
|
||||
<string name="enable_education_screens_summary">Elemek kiemelése, hogy megtudja hogyan működik az alkalmazás</string>
|
||||
<string name="reset_education_screens_title">Oktatóképernyők visszaállítása</string>
|
||||
|
||||
@@ -554,7 +554,6 @@
|
||||
<string name="allow_no_password_title">Izinkan tidak ada kunci utama</string>
|
||||
<string name="allow_no_password_summary">Memungkinkan mengetuk tombol \"Buka\" jika tidak ada kredensial yang dipilih</string>
|
||||
<string name="delete_entered_password_summary">Menghapus kata sandi yang dimasukkan setelah upaya koneksi ke basis data</string>
|
||||
<string name="enable_read_only_summary">Buka basis data baca-saja secara baku</string>
|
||||
<string name="enable_keep_screen_on_title">Biarkan layar nyala</string>
|
||||
<string name="enable_education_screens_summary">Sorot elemen untuk mempelajari cara kerja aplikasi</string>
|
||||
<string name="education_create_database_summary">Buat file pengelola kata sandi pertama Anda.</string>
|
||||
@@ -618,7 +617,6 @@
|
||||
\nPeriksa kompatibilitas dan keamanan KeyStore dengan produsen perangkat Anda dan pembuat ROM yang Anda gunakan.</string>
|
||||
<string name="education_read_only_title">Lindungi basis data Anda dari penulisan</string>
|
||||
<string name="keyboard_save_search_info_summary">Coba simpan informasi terbagi ketika membuat sebuah pilihan entri manual untuk penggunaan mudah di waktu mendatang</string>
|
||||
<string name="enable_read_only_title">Terlindungi-tulis</string>
|
||||
<string name="enable_keep_screen_on_summary">Jaga layar tetap menyala saat melihat atau menyunting sebuah entri</string>
|
||||
<string name="content_description_hardware_key_checkbox">Kotak centang kunci perangkat keras</string>
|
||||
<string name="waiting_challenge_request">Menunggu untuk permintaan tantangan…</string>
|
||||
|
||||
@@ -222,8 +222,6 @@
|
||||
<string name="magic_keyboard_explanation_summary">Attiva una tastiera personale che inserisce le tue password e i campi di identità</string>
|
||||
<string name="allow_no_password_title">Non consentire chiavi principali</string>
|
||||
<string name="allow_no_password_summary">Permetti di toccare il pulsante \"Apri\" se non sono selezionate credenziali</string>
|
||||
<string name="enable_read_only_title">Protetto da scrittura</string>
|
||||
<string name="enable_read_only_summary">Apri il database in sola lettura in modo predefinito</string>
|
||||
<string name="enable_education_screens_title">Suggerimenti educativi</string>
|
||||
<string name="enable_education_screens_summary">Evidenzia gli elementi per imparare come funziona l\'app</string>
|
||||
<string name="reset_education_screens_title">Ripristina i suggerimenti educativi</string>
|
||||
|
||||
@@ -334,7 +334,6 @@
|
||||
<string name="allow_copy_password_warning">אזהרה: לוח ההעתקה משותף לכל היישומים. אם מידע רגיש יועתק, תוכנות אחרות עשויות לשחזר אותו.</string>
|
||||
<string name="disable">השבת</string>
|
||||
<string name="keyboard_label">Magikeyboard (KeePassDX)</string>
|
||||
<string name="enable_read_only_title">מוגן מפני כתיבה</string>
|
||||
<string name="keyboard_notification_entry_clear_close_title">נקה בסגירה</string>
|
||||
<string name="keyboard_notification_entry_content_title_text">רשומה</string>
|
||||
<string name="keyboard_notification_entry_content_title">%1$s זמין ב־Magikeyboard</string>
|
||||
@@ -469,7 +468,6 @@
|
||||
<string name="keyboard_auto_go_action_title">פעולת מקש אוטומטית</string>
|
||||
<string name="allow_no_password_title">אפשר עבודה ללא מפתח ראשי</string>
|
||||
<string name="allow_no_password_summary">מאפשר הקשה על הכפתור \"פתח\" אם לא נבחרו אישורים</string>
|
||||
<string name="enable_read_only_summary">פתח את מסד הנתונים לקריאה בלבד כברירת מחדל</string>
|
||||
<string name="delete_entered_password_title">מחק סיסמה</string>
|
||||
<string name="delete_entered_password_summary">מוחק את הסיסמה שהוזנה לאחר ניסיון התחברות למסד נתונים</string>
|
||||
<string name="reset_education_screens_summary">הראה שוב את כל המידע הלימודי</string>
|
||||
|
||||
@@ -400,8 +400,6 @@
|
||||
<string name="allow_no_password_summary">認証情報が選択されていない場合でも、[開く] ボタンのタップを許可します</string>
|
||||
<string name="delete_entered_password_title">パスワードの削除</string>
|
||||
<string name="delete_entered_password_summary">入力されたパスワードをデータベースへの接続試行後に削除します</string>
|
||||
<string name="enable_read_only_title">書き込み禁止</string>
|
||||
<string name="enable_read_only_summary">デフォルトでデータベースを読み取り専用として開きます</string>
|
||||
<string name="enable_auto_save_database_title">データベースの自動保存</string>
|
||||
<string name="enable_auto_save_database_summary">重要なアクションを起こすたびにデータベースを保存します( [変更可能] モードのとき)</string>
|
||||
<string name="enable_education_screens_title">教育的なヒント</string>
|
||||
|
||||
@@ -218,8 +218,6 @@
|
||||
<string name="magic_keyboard_explanation_summary">Aktiver et egendefinert tastatur som fyller inn passordene og alle identitetsfelter</string>
|
||||
<string name="allow_no_password_title">Tillat ingen hovednøkkel</string>
|
||||
<string name="allow_no_password_summary">Tillater å trykke på \"Åpne\"-knappen hvis ingen legitimasjon er valgt</string>
|
||||
<string name="enable_read_only_title">Skrivebeskyttet</string>
|
||||
<string name="enable_read_only_summary">Åpne databasen skrivebeskyttet som standard</string>
|
||||
<string name="enable_education_screens_title">Lærerike tips</string>
|
||||
<string name="enable_education_screens_summary">Fremhev elementer for å finne ut hvordan appen fungerer</string>
|
||||
<string name="reset_education_screens_title">Tilbakestill lærerike tips</string>
|
||||
|
||||
@@ -230,8 +230,6 @@
|
||||
<string name="magic_keyboard_explanation_summary">Activeer een aangepast toetsenbord dat je wachtwoorden en identiteitsvelden vult</string>
|
||||
<string name="allow_no_password_title">Geen hoofdwachtwoord toestaan</string>
|
||||
<string name="allow_no_password_summary">Schakel de knop \"Openen\" in als er geen referenties zijn geselecteerd</string>
|
||||
<string name="enable_read_only_title">Alleen-lezen</string>
|
||||
<string name="enable_read_only_summary">Open de database standaard alleen-lezen</string>
|
||||
<string name="enable_education_screens_title">Informatieve tips</string>
|
||||
<string name="enable_education_screens_summary">Markeer elementen om te leren hoe de app werkt</string>
|
||||
<string name="reset_education_screens_title">Informatieve tips opnieuw instellen</string>
|
||||
|
||||
@@ -331,7 +331,6 @@
|
||||
<string name="keyboard_notification_entry_content_title_text">ਐਂਟਰੀ</string>
|
||||
<string name="keyboard_entry_category">ਐਂਟਰੀ</string>
|
||||
<string name="autofill_close_database_title">ਡਾਟਾਬੇਸ ਬੰਦ ਕਰੋ</string>
|
||||
<string name="enable_read_only_title">ਲਿਖਣ ਤੋਂ ਸੁਰੱਖਿਅਤ</string>
|
||||
<string name="education_search_title">ਐਂਟਰੀਆਂ ਵਿੱਚੋਂ ਲੱਭੋ</string>
|
||||
<string name="education_entry_edit_title">ਐਂਟਰੀ ਨੂੰ ਸੋਧੋ</string>
|
||||
<string name="education_add_attachment_title">ਅਟੈਚਮੈਂਟ ਜੋੜੋ</string>
|
||||
|
||||
@@ -225,8 +225,6 @@
|
||||
<string name="magic_keyboard_explanation_summary">Aktywuj niestandardową klawiaturę wypełniającą hasła i wszystkie pola tożsamości</string>
|
||||
<string name="allow_no_password_title">Zezwalaj na brak klucza głównego</string>
|
||||
<string name="allow_no_password_summary">Umożliwia naciśnięcie przycisku \"Otwórz\", jeśli nie wybrano żadnych poświadczeń</string>
|
||||
<string name="enable_read_only_title">Ochrona przed zapisem</string>
|
||||
<string name="enable_read_only_summary">Domyślnie otwarte bazy danych są tylko do odczytu</string>
|
||||
<string name="enable_education_screens_title">Wskazówki edukacyjne</string>
|
||||
<string name="enable_education_screens_summary">Podświetl elementy, aby dowiedzieć się, jak działa aplikacja</string>
|
||||
<string name="reset_education_screens_title">Zresetuj wskazówki edukacyjne</string>
|
||||
|
||||
@@ -222,8 +222,6 @@
|
||||
<string name="magic_keyboard_explanation_summary">Ative um teclado customizado, populando suas senhas e todos os campos de identidade</string>
|
||||
<string name="allow_no_password_title">Permitir chave-mestra vazia</string>
|
||||
<string name="allow_no_password_summary">Permite tocar no botão \"Abrir\" mesmo se nenhuma credencial for selecionada</string>
|
||||
<string name="enable_read_only_title">Somente leitura</string>
|
||||
<string name="enable_read_only_summary">Abre o banco de dados no modo somente leitura por padrão</string>
|
||||
<string name="enable_education_screens_title">Dicas educacionais</string>
|
||||
<string name="enable_education_screens_summary">Destaque os elementos para aprender como o aplicativo funciona</string>
|
||||
<string name="reset_education_screens_title">Reiniciar telas educacionais</string>
|
||||
|
||||
@@ -269,8 +269,6 @@
|
||||
<string name="allow_no_password_summary">Permite tocar no botão \"Abrir\" se não estiverem selecionadas nenhumas credenciais</string>
|
||||
<string name="enable_education_screens_title">Dicas educacionais</string>
|
||||
<string name="enable_education_screens_summary">Destacar elementos para saber como a aplicação funciona</string>
|
||||
<string name="enable_read_only_title">Apenas leitura</string>
|
||||
<string name="enable_read_only_summary">Abrir a base de dados com permissão de apenas leitura por predefinição</string>
|
||||
<string name="education_read_only_title">Proteger a base de dados contra alterações</string>
|
||||
<string name="education_read_only_summary">Altere o modo de abertura para a sessão.
|
||||
\n
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="enable_read_only_summary">Abrir a base de dados com permissão de apenas leitura por predefinição</string>
|
||||
<string name="enable_read_only_title">Apenas leitura</string>
|
||||
<string name="menu_open_file_read_and_write">Alterável</string>
|
||||
<string name="menu_file_selection_read_only">Apenas leitura</string>
|
||||
<string name="enable_education_screens_summary">Destacar elementos para saber como a aplicação funciona</string>
|
||||
|
||||
@@ -336,8 +336,6 @@
|
||||
<string name="allow_no_password_summary">Permite apăsarea butonului \"Deschidere\" în cazul în care nu sunt selectate credențiale</string>
|
||||
<string name="delete_entered_password_title">Ștergere parolă</string>
|
||||
<string name="delete_entered_password_summary">Șterge parola introdusă după o încercare de conectare la o bază de date</string>
|
||||
<string name="enable_read_only_title">Protejat la scriere</string>
|
||||
<string name="enable_read_only_summary">Deschideți baza de date numai în citire în mod implicit</string>
|
||||
<string name="enable_auto_save_database_title">Salvare automată a bazei de date</string>
|
||||
<string name="enable_auto_save_database_summary">Salvați baza de date după fiecare acțiune importantă (în modul \"Modificabil\")</string>
|
||||
<string name="enable_education_screens_title">Sugestii educaționale</string>
|
||||
|
||||
@@ -226,8 +226,6 @@
|
||||
<string name="magic_keyboard_explanation_summary">Активируйте пользовательскую клавиатуру для простого заполнения паролей и любых идентификаторов</string>
|
||||
<string name="allow_no_password_title">Разрешить без главного пароля</string>
|
||||
<string name="allow_no_password_summary">Разрешить нажимать кнопку \"Открыть\", если главный пароль не указан</string>
|
||||
<string name="enable_read_only_title">Только чтение</string>
|
||||
<string name="enable_read_only_summary">По умолчанию открывать базу только для чтения</string>
|
||||
<string name="enable_education_screens_title">Обучающие подсказки</string>
|
||||
<string name="enable_education_screens_summary">Выделять элементы, чтобы показать, как работает приложение</string>
|
||||
<string name="reset_education_screens_title">Вернуть обучающие подсказки</string>
|
||||
|
||||
@@ -620,8 +620,6 @@
|
||||
<string name="allow_no_password_summary">Umožňuje klepnúť na tlačidlo „Otvoriť“, ak nie sú vybraté žiadne poverenia</string>
|
||||
<string name="delete_entered_password_title">Vymazať heslo</string>
|
||||
<string name="delete_entered_password_summary">Odstráni heslo zadané po pokuse o pripojenie k databáze</string>
|
||||
<string name="enable_read_only_title">Ochrana proti zápisu</string>
|
||||
<string name="enable_read_only_summary">V predvolenom nastavení otvorte databázu len na čítanie</string>
|
||||
<string name="enable_keep_screen_on_title">Nechajte obrazovku zapnutú</string>
|
||||
<string name="enable_keep_screen_on_summary">Pri sledovaní alebo úprave záznamu ponechať obrazovku zapnutú</string>
|
||||
<string name="enable_screenshot_mode_title">Režim snímky obrazovky</string>
|
||||
|
||||
@@ -555,7 +555,6 @@
|
||||
<string name="keyboard_key_vibrate_title">Shtypje tastesh me dridhje</string>
|
||||
<string name="autofill_save_search_info_title">Ruaj hollësi kërkimi</string>
|
||||
<string name="autofill_web_domain_blocklist_summary">Listë bllokimesh që pengon vetëplotësim përkatësish web</string>
|
||||
<string name="enable_read_only_title">Mbrojtur nga shkrimi</string>
|
||||
<string name="enable_keep_screen_on_title">Mbaje ekranin ndezur</string>
|
||||
<string name="enable_education_screens_title">Ndihmëza edukative</string>
|
||||
<string name="education_search_summary">Jepni titull, emër përdoruesi, ose lëndë fushash të tjera, për të marrë fjalëkalimet tuaja.</string>
|
||||
@@ -610,7 +609,6 @@
|
||||
<string name="autofill_manual_selection_summary">Shfaq mundësi për ta lënë përdoruesin të përzgjedhë zë baze të dhënash</string>
|
||||
<string name="autofill_save_search_info_summary">Provo të ruash informacion, kur bëhet një përzgjedhje dorazi e zërit, për përdorim më të kollajtë në të ardhmen</string>
|
||||
<string name="autofill_read_only_save">S’lejohet ruajtje të dhënash për një bazë të dhënash të hapur vetëm-për-lexim.</string>
|
||||
<string name="enable_read_only_summary">Si parazgjedhje, bazën e të dhënave hape si vetëm-për-lexim</string>
|
||||
<string name="enable_auto_save_database_summary">Ruaje bazën e të dhënave pas çdo veprimi të rëndësishëm (nën mënyrën “E ndryshueshme”)</string>
|
||||
<string name="enable_keep_screen_on_summary">Mbaje hapur ekranin, kur shihet ose përpunohet një zë</string>
|
||||
<string name="enable_screenshot_mode_summary">Lejo aplikacione palësh të treta të regjistrojnë, ose bëjnë foto ekrani të aplikacionit</string>
|
||||
|
||||
@@ -279,8 +279,6 @@
|
||||
<string name="enable_education_screens_summary">Markerar element för att lära dig hur appen fungerar</string>
|
||||
<string name="menu_file_selection_read_only">Skrivskyddad</string>
|
||||
<string name="menu_open_file_read_and_write">Modifierbar</string>
|
||||
<string name="enable_read_only_title">Skrivskyddad</string>
|
||||
<string name="enable_read_only_summary">Öppna databasen i skrivskyddat läge som standard</string>
|
||||
<string name="education_read_only_title">Skrivskydda din databas</string>
|
||||
<string name="education_read_only_summary">Ändra öppningsläge för sessionen.
|
||||
\n
|
||||
|
||||
@@ -647,8 +647,6 @@
|
||||
<string name="autofill_web_domain_blocklist_summary">வலை களங்களை தானாக நிரப்புவதைத் தடுக்கும் பிளாக்லிச்ட்</string>
|
||||
<string name="autofill_read_only_save">படிக்க மட்டும் திறக்கப்பட்ட தரவுத்தளத்திற்கு தரவு சேமிப்பு அனுமதிக்கப்படவில்லை.</string>
|
||||
<string name="autofill_inline_suggestions_keyboard">ஆட்டோஃபில் பரிந்துரைகள் சேர்க்கப்பட்டன.</string>
|
||||
<string name="enable_read_only_title">எழுது பாதுகாக்கப்பட்ட</string>
|
||||
<string name="enable_read_only_summary">இயல்பாகவே தரவுத்தளத்தை படிக்க மட்டுமே திறக்கவும்</string>
|
||||
<string name="education_new_node_summary">உங்கள் டிசிட்டல் அடையாளங்களை நிர்வகிக்க உள்ளீடுகள் உதவுகின்றன.\n\n குழுக்கள் (~ கோப்புறைகள்) உங்கள் தரவுத்தளத்தில் உள்ளீடுகளை ஒழுங்கமைக்கின்றன.</string>
|
||||
<string name="education_search_title">உள்ளீடுகள் மூலம் தேடுங்கள்</string>
|
||||
<string name="education_generate_password_summary">உங்கள் நுழைவுடன் தொடர்புபடுத்த ஒரு வலுவான கடவுச்சொல்லை உருவாக்குங்கள், படிவத்தின் அளவுகோல்களின்படி அதை எளிதாக வரையறுக்கவும், பாதுகாப்பான கடவுச்சொல்லை மறந்துவிடாதீர்கள்.</string>
|
||||
|
||||
@@ -416,7 +416,6 @@
|
||||
<string name="autofill_inline_suggestions_title">การแนะนำแบบอินไลน์</string>
|
||||
<string name="autofill_ask_to_save_data_title">ถามเพื่อบันทึกข้อมูล</string>
|
||||
<string name="autofill_block">บล็อกการกรอกอัตโนมัติ</string>
|
||||
<string name="enable_read_only_title">ป้องกันการเขียน</string>
|
||||
<string name="reset_education_screens_title">รีเซ็ทคำแนะนำการใช้งาน</string>
|
||||
<string name="reset_education_screens_summary">แสดงคำแนะนำการใช้งานอีกครั้ง</string>
|
||||
<string name="html_text_dev_feature_contibute">โดยการ<strong>ร่วมแก้ไข</strong></string>
|
||||
@@ -620,7 +619,6 @@
|
||||
<string name="allow_no_password_title">อนุญาตให้ไม่มีรหัสผ่านหลัก</string>
|
||||
<string name="allow_no_password_summary">อนุญาตให้แตะปุ่ม \"เปิด\" เมื่อไม่มีข้อมูลประจำตัวถูกเลือก</string>
|
||||
<string name="delete_entered_password_summary">ลบรหัสผ่านที่ป้อนแล้วหลังจากพยายามเชื่อมต่อที่ฐานข้อมูล</string>
|
||||
<string name="enable_read_only_summary">เปิดฐานข้อมูลแบบอ่านอย่างเดียวเป็นค่าเรื่มต้น</string>
|
||||
<string name="reset_education_screens_text">คำแนะนำการใช้งานถูกรีเซ็ทแล้ว</string>
|
||||
<string name="icon_pack_choose_title">ชุดไอคอน</string>
|
||||
<string name="enable_auto_save_database_summary">บันทึกฐานข้อมูลหลังจากการกระทำที่สำคัญ(ในโหมด\"แก้ไขได้\")</string>
|
||||
|
||||
@@ -236,8 +236,6 @@
|
||||
<string name="keyboard_key_sound_title">Tuşa basıldığında ses çıkar</string>
|
||||
<string name="allow_no_password_title">Ana anahtar olmamasına izin ver</string>
|
||||
<string name="allow_no_password_summary">Seçili kimlik bilgisi yoksa \"Aç\" düğmesine dokunmaya izin verir</string>
|
||||
<string name="enable_read_only_title">Yazma korumalı</string>
|
||||
<string name="enable_read_only_summary">Veri tabanını öntanımlı olarak salt okunur aç</string>
|
||||
<string name="enable_education_screens_title">Eğitim ipuçları</string>
|
||||
<string name="enable_education_screens_summary">Uygulamanın nasıl çalıştığını öğrenmek için ögeleri vurgulayın</string>
|
||||
<string name="reset_education_screens_title">Eğitici ipuçlarını sıfırla</string>
|
||||
|
||||
@@ -314,8 +314,6 @@
|
||||
<string name="enable_education_screens_summary">Виділяти елементи, щоб дізнатися, як працює застосунок</string>
|
||||
<string name="enable_education_screens_title">Навчальні підказки</string>
|
||||
<string name="enable_auto_save_database_title">Автозбереження бази даних</string>
|
||||
<string name="enable_read_only_summary">Типово відкривати базу даних лише для читання</string>
|
||||
<string name="enable_read_only_title">Захист від запису</string>
|
||||
<string name="delete_entered_password_summary">Видаляти пароль, введений після спроби з\'єднання з базою даних</string>
|
||||
<string name="delete_entered_password_title">Видаляти пароль</string>
|
||||
<string name="allow_no_password_summary">Дозволяє натискання «Відкрити», якщо не вибрано головний пароль</string>
|
||||
|
||||
@@ -568,8 +568,6 @@
|
||||
<string name="allow_no_password_summary">Cho phép nhấn vào nút \"Mở\" nếu không có thông tin xác thực nào được chọn</string>
|
||||
<string name="delete_entered_password_title">Xóa mật khẩu</string>
|
||||
<string name="delete_entered_password_summary">Xóa mật khẩu đã nhập sau khi cố gắng kết nối với cơ sở dữ liệu</string>
|
||||
<string name="enable_read_only_title">Bảo vệ chống ghi</string>
|
||||
<string name="enable_read_only_summary">Mở cơ sở dữ liệu ở chế độ chỉ đọc theo mặc định</string>
|
||||
<string name="enable_auto_save_database_title">Tự động lưu cơ sở dữ liệu</string>
|
||||
<string name="enable_auto_save_database_summary">Lưu cơ sở dữ liệu sau mỗi hành động quan trọng (ở chế độ \"Có thể sửa đổi\")</string>
|
||||
<string name="enable_keep_screen_on_title">Giữ màn hình luôn bật</string>
|
||||
|
||||
@@ -190,8 +190,6 @@
|
||||
<string name="other">其他</string>
|
||||
<string name="keyboard">键盘</string>
|
||||
<string name="magic_keyboard_title">魔法键盘</string>
|
||||
<string name="enable_read_only_title">写入保护(只读模式)</string>
|
||||
<string name="enable_read_only_summary">默认以只读方式打开数据库</string>
|
||||
<string name="download">下载</string>
|
||||
<string name="contribute">贡献</string>
|
||||
<string name="style_choose_summary">应用中使用的主题</string>
|
||||
|
||||
@@ -218,8 +218,6 @@
|
||||
<string name="enable_auto_save_database_title">自動儲存資料庫</string>
|
||||
<string name="enable_education_screens_summary">高亮界面元素來學習本應用工作方式</string>
|
||||
<string name="enable_education_screens_title">教學提示</string>
|
||||
<string name="enable_read_only_summary">預設以唯讀方式開啟資料庫</string>
|
||||
<string name="enable_read_only_title">寫入保護(唯讀模式)</string>
|
||||
<string name="encrypted_value_stored">已儲存加密密碼</string>
|
||||
<string name="encryption">加密</string>
|
||||
<string name="encryption_algorithm">加密演算法</string>
|
||||
|
||||
@@ -67,8 +67,6 @@
|
||||
<bool name="allow_no_password_default" translatable="false">false</bool>
|
||||
<string name="delete_entered_password_key" translatable="false">delete_entered_password_key</string>
|
||||
<bool name="delete_entered_password_default" translatable="false">true</bool>
|
||||
<string name="enable_read_only_key" translatable="false">enable_read_only_key</string>
|
||||
<bool name="enable_read_only_default" translatable="false">false</bool>
|
||||
<string name="enable_auto_save_database_key" translatable="false">enable_auto_save_database_key</string>
|
||||
<bool name="enable_auto_save_database_default" translatable="false">true</bool>
|
||||
<string name="enable_keep_screen_on_key" translatable="false">enable_keep_screen_on_key</string>
|
||||
|
||||
@@ -575,8 +575,6 @@
|
||||
<string name="allow_no_password_summary">Allows tapping the \"Open\" button if no credentials are selected</string>
|
||||
<string name="delete_entered_password_title">Delete password</string>
|
||||
<string name="delete_entered_password_summary">Deletes the password entered after a connection attempt to a database</string>
|
||||
<string name="enable_read_only_title">Write-protected</string>
|
||||
<string name="enable_read_only_summary">Open the database read-only by default</string>
|
||||
<string name="enable_auto_save_database_title">Autosave database</string>
|
||||
<string name="enable_auto_save_database_summary">Save the database after every important action (in \"Modifiable\" mode)</string>
|
||||
<string name="enable_keep_screen_on_title">Keep screen on</string>
|
||||
|
||||
@@ -32,11 +32,6 @@
|
||||
android:title="@string/delete_entered_password_title"
|
||||
android:summary="@string/delete_entered_password_summary"
|
||||
android:defaultValue="@bool/delete_entered_password_default"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/enable_read_only_key"
|
||||
android:title="@string/enable_read_only_title"
|
||||
android:summary="@string/enable_read_only_summary"
|
||||
android:defaultValue="@bool/enable_read_only_default"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/enable_auto_save_database_key"
|
||||
android:title="@string/enable_auto_save_database_title"
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.kunzisoft.keepass.hardware.HardwareKey
|
||||
data class DatabaseFile(var databaseUri: Uri? = null,
|
||||
var keyFileUri: Uri? = null,
|
||||
var hardwareKey: HardwareKey? = null,
|
||||
var readOnly: Boolean? = null,
|
||||
var databaseDecodedPath: String? = null,
|
||||
var databaseAlias: String? = null,
|
||||
var databaseFileExists: Boolean = false,
|
||||
|
||||
@@ -148,23 +148,6 @@ fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int = 0): Pa
|
||||
@Suppress("DEPRECATION") getPackageInfo(packageName, flags)
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
fun PackageManager.allowCreateDocumentByStorageAccessFramework(): Boolean {
|
||||
return when {
|
||||
// To check if a custom file manager can manage the ACTION_CREATE_DOCUMENT
|
||||
// queries filter is in Manifest
|
||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT -> {
|
||||
queryIntentActivitiesCompat(
|
||||
Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "application/octet-stream"
|
||||
}, PackageManager.MATCH_DEFAULT_ONLY
|
||||
).isNotEmpty()
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("QueryPermissionsNeeded")
|
||||
private fun PackageManager.queryIntentActivitiesCompat(intent: Intent, flags: Int): List<ResolveInfo> {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
|
||||
Reference in New Issue
Block a user