From f4f5e869790065a967f0e93dcb93c3dda536220d Mon Sep 17 00:00:00 2001 From: Clay Perry Date: Tue, 8 Jul 2025 12:52:14 -0400 Subject: [PATCH 01/29] Updated Minimum SDK to 16 --- app/build.gradle | 2 +- crypto/build.gradle | 2 +- database/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3d9c1502c..b288d1c9c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ android { defaultConfig { applicationId "com.kunzisoft.keepass" - minSdkVersion 15 + minSdkVersion 16 targetSdkVersion 34 versionCode = 134 versionName = "4.1.2" diff --git a/crypto/build.gradle b/crypto/build.gradle index adbe03f94..c29556613 100644 --- a/crypto/build.gradle +++ b/crypto/build.gradle @@ -9,7 +9,7 @@ android { ndkVersion "21.4.7075529" defaultConfig { - minSdkVersion 15 + minSdkVersion 16 targetSdkVersion 34 multiDexEnabled true diff --git a/database/build.gradle b/database/build.gradle index 6e4d46938..2ae6ab36b 100644 --- a/database/build.gradle +++ b/database/build.gradle @@ -6,7 +6,7 @@ android { compileSdkVersion 34 defaultConfig { - minSdkVersion 15 + minSdkVersion 16 targetSdk 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From 09dc1d6baa4c1bc62f8ac0ae8a430fba708f39ff Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 09:57:23 -0400 Subject: [PATCH 02/29] Removed sdk checks on TextFieldView.kt Removed SDK checks that will always resolve to true now. Since we are updating min sdk to 19, these checks are no longer necessary. --- .../kunzisoft/keepass/view/TextFieldView.kt | 49 ++++++++----------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/view/TextFieldView.kt b/app/src/main/java/com/kunzisoft/keepass/view/TextFieldView.kt index 6077aa7e5..d9fbf49fa 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/TextFieldView.kt +++ b/app/src/main/java/com/kunzisoft/keepass/view/TextFieldView.kt @@ -63,13 +63,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() - } + it.marginStart = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + 4f, + resources.displayMetrics + ).toInt() + } } protected val valueView = AppCompatTextView(context).apply { @@ -88,13 +87,11 @@ 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() - } + it.marginStart = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + 8f, + resources.displayMetrics + ).toInt() } setTextIsSelectable(true) } @@ -128,9 +125,7 @@ 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) - } + it.addRule(ALIGN_PARENT_END) } } showButton.apply { @@ -138,14 +133,14 @@ open class TextFieldView @JvmOverloads constructor(context: Context, 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) - } + + 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) - } + + it.addRule(ALIGN_PARENT_END) + } } } @@ -153,18 +148,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) - } + 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(START_OF, showButtonId) it.addRule(BELOW, labelViewId) } } From d88882f439b9eaf36a0d555ba72631584f526791 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:15:36 -0400 Subject: [PATCH 03/29] Removed PRNGFixes App.kt --- app/src/main/java/com/kunzisoft/keepass/app/App.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/app/App.kt b/app/src/main/java/com/kunzisoft/keepass/app/App.kt index b3dcca2f9..0486a9f22 100644 --- a/app/src/main/java/com/kunzisoft/keepass/app/App.kt +++ b/app/src/main/java/com/kunzisoft/keepass/app/App.kt @@ -28,6 +28,5 @@ class App : MultiDexApplication() { super.onCreate() Stylish.load(this) - PRNGFixes.apply() } } From 26b8a616be377055ec045e14d6120dda16ad51b0 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:19:54 -0400 Subject: [PATCH 04/29] Update AboutActivity.kt Removed old SDK Check --- .../java/com/kunzisoft/keepass/activities/AboutActivity.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/AboutActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/AboutActivity.kt index e86e8f690..105810a1d 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/AboutActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/AboutActivity.kt @@ -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 - } + textDirection = View.TEXT_DIRECTION_ANY_RTL + } findViewById(R.id.activity_about_privacy_text).apply { From fd7f0fceb262841e16bc532efd2326a661f0f6c7 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:21:55 -0400 Subject: [PATCH 05/29] Update UriUtil.kt Removed Old SDK Check --- .../java/com/kunzisoft/keepass/utils/UriUtil.kt | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt b/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt index 0ddf1e257..db32ab627 100644 --- a/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt +++ b/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt @@ -167,15 +167,13 @@ 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) { - if (clipData.itemCount == 1) { - val clipItem = clipData.getItemAt(0) - if (clipItem != null) { - return clipItem.uri - } + val clipData = this.clipData + if (clipData != null) { + if (clipData.description.label == key) { + if (clipData.itemCount == 1) { + val clipItem = clipData.getItemAt(0) + if (clipItem != null) { + return clipItem.uri } } } From 6c1c401a714caf0c7ff75391d69ac2b14e3d0e1e Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:23:44 -0400 Subject: [PATCH 06/29] Update NodesAdapter.kt Removed old SDK check --- .../main/java/com/kunzisoft/keepass/adapters/NodesAdapter.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/adapters/NodesAdapter.kt b/app/src/main/java/com/kunzisoft/keepass/adapters/NodesAdapter.kt index 7c2efbdc6..b58005093 100644 --- a/app/src/main/java/com/kunzisoft/keepass/adapters/NodesAdapter.kt +++ b/app/src/main/java/com/kunzisoft/keepass/adapters/NodesAdapter.kt @@ -530,9 +530,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 - } + textDirection = View.TEXT_DIRECTION_LTR + } holder?.otpContainer?.setOnClickListener { otpElement?.token?.let { token -> From daeee10de904e5635c60d4ca3d0db9269ed9eac9 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:25:15 -0400 Subject: [PATCH 07/29] Update TemplateEditView.kt Removed old SDK check --- .../com/kunzisoft/keepass/view/TemplateEditView.kt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/view/TemplateEditView.kt b/app/src/main/java/com/kunzisoft/keepass/view/TemplateEditView.kt index c6909237c..8963534ba 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/TemplateEditView.kt +++ b/app/src/main/java/com/kunzisoft/keepass/view/TemplateEditView.kt @@ -123,13 +123,11 @@ 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 - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_NO - } + if (field.protectedValue.isProtected) { + textDirection = TEXT_DIRECTION_LTR + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_NO } } } From 90c8cb34559559647b0ee9c025fcd76f58cb1d39 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:26:12 -0400 Subject: [PATCH 08/29] Update ViewUtil.kt Removed SDK check --- app/src/main/java/com/kunzisoft/keepass/view/ViewUtil.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/view/ViewUtil.kt b/app/src/main/java/com/kunzisoft/keepass/view/ViewUtil.kt index 3838cff8d..1ada1c3b9 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/ViewUtil.kt +++ b/app/src/main/java/com/kunzisoft/keepass/view/ViewUtil.kt @@ -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) - } + updatePaddingRelative(lockPadding) } } From daae535fa18e1882b7e6ec2d50bf8c170f5c7f53 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:28:27 -0400 Subject: [PATCH 09/29] Update TemplateView.kt Removed old SDK checks --- .../main/java/com/kunzisoft/keepass/view/TemplateView.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/view/TemplateView.kt b/app/src/main/java/com/kunzisoft/keepass/view/TemplateView.kt index d14cc137d..92e4b0140 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/TemplateView.kt +++ b/app/src/main/java/com/kunzisoft/keepass/view/TemplateView.kt @@ -63,9 +63,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 - } + textDirection = TEXT_DIRECTION_LTR if (mFirstTimeAskAllowCopyProtectedFields) { setCopyButtonState(TextFieldView.ButtonState.DEACTIVATE) setCopyButtonClickListener { _, _ -> @@ -179,9 +177,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 - } + textDirection = TEXT_DIRECTION_LTR mLastOtpTokenView = this mOtpRunnable = Runnable { if (otpElement.shouldRefreshToken()) { From 05fc6f87ec77c6f4d5b1d2a3880a5cea3312bd98 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:39:34 -0400 Subject: [PATCH 10/29] Update build.gradle changed minsdk to 19 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index b288d1c9c..5263418d8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ android { defaultConfig { applicationId "com.kunzisoft.keepass" - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion 34 versionCode = 134 versionName = "4.1.2" From 43f7e0854831b04476be9da6db1d7e8548d6c296 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:40:13 -0400 Subject: [PATCH 11/29] Update build.gradle changed minsdk to 19 --- crypto/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/build.gradle b/crypto/build.gradle index c29556613..265a6bb8a 100644 --- a/crypto/build.gradle +++ b/crypto/build.gradle @@ -9,7 +9,7 @@ android { ndkVersion "21.4.7075529" defaultConfig { - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion 34 multiDexEnabled true From b5dc8d9adf47f09aeb8e1520a4be4d55eae7585e Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:40:38 -0400 Subject: [PATCH 12/29] Update build.gradle changed minsdk to 19 --- database/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/build.gradle b/database/build.gradle index 2ae6ab36b..f0d7adb9b 100644 --- a/database/build.gradle +++ b/database/build.gradle @@ -6,7 +6,7 @@ android { compileSdkVersion 34 defaultConfig { - minSdkVersion 16 + minSdkVersion 19 targetSdk 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From 1f4e59cbdc751e51d4851c742d672a7a0ffda1e2 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:44:21 -0400 Subject: [PATCH 13/29] Update fragment_set_otp.xml Removed sdk target checks for jelly_bean --- app/src/main/res/layout/fragment_set_otp.xml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/layout/fragment_set_otp.xml b/app/src/main/res/layout/fragment_set_otp.xml index 14da1e1b0..872073917 100644 --- a/app/src/main/res/layout/fragment_set_otp.xml +++ b/app/src/main/res/layout/fragment_set_otp.xml @@ -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" /> @@ -178,8 +177,7 @@ tools:text="30" android:maxLength="3" android:digits="0123456789" - android:imeOptions="actionNext" - tools:targetApi="jelly_bean" /> + android:imeOptions="actionNext" /> + android:imeOptions="actionNext" /> + android:imeOptions="actionNext" /> @@ -237,4 +233,4 @@ - \ No newline at end of file + From 1fc4f150bfb45a3729534c56c6c6981aa751d25e Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 10:45:16 -0400 Subject: [PATCH 14/29] Update item_breadcrumb.xml Removed jelly_bean target check --- app/src/main/res/layout/item_breadcrumb.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/res/layout/item_breadcrumb.xml b/app/src/main/res/layout/item_breadcrumb.xml index 3fd284c8e..9ca31eeea 100644 --- a/app/src/main/res/layout/item_breadcrumb.xml +++ b/app/src/main/res/layout/item_breadcrumb.xml @@ -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" /> From a88f6b968a2a23b098b9de97bc27ac36b1b53d68 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 11:04:12 -0400 Subject: [PATCH 15/29] Update UriUtil.kt Removed KitKat sdk check --- .../com/kunzisoft/keepass/utils/UriUtil.kt | 86 +++++++++---------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt b/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt index db32ab627..61af75836 100644 --- a/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt +++ b/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt @@ -67,55 +67,53 @@ 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 - // Check current permissions allowed - persistedUriPermissions.find { uriPermission -> - uriPermission.uri == uri - }?.let { uriPermission -> - Log.d(TAG, "Check URI permission : $uriPermission") - if (uriPermission.isReadPermission) { - readPermissionAllowed = true - } - if (uriPermission.isWritePermission) { - writePermissionAllowed = true - } + contentResolver?.apply { + var readPermissionAllowed = false + var writePermissionAllowed = false + // Check current permissions allowed + persistedUriPermissions.find { uriPermission -> + uriPermission.uri == uri + }?.let { uriPermission -> + Log.d(TAG, "Check URI permission : $uriPermission") + if (uriPermission.isReadPermission) { + readPermissionAllowed = true } - - // Release permission - if (release) { - if (writePermissionAllowed) { - Log.d(TAG, "Release write permission : $uri") - val removeFlags: Int = Intent.FLAG_GRANT_WRITE_URI_PERMISSION - releasePersistableUriPermission(uri, removeFlags) - } - if (readPermissionAllowed) { - Log.d(TAG, "Release read permission $uri") - val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION - releasePersistableUriPermission(uri, takeFlags) - } + if (uriPermission.isWritePermission) { + writePermissionAllowed = true } + } - // Take missing permission - if (!readPermissionAllowed) { - Log.d(TAG, "Take read permission $uri") + // Release permission + if (release) { + if (writePermissionAllowed) { + Log.d(TAG, "Release write permission : $uri") + val removeFlags: Int = Intent.FLAG_GRANT_WRITE_URI_PERMISSION + releasePersistableUriPermission(uri, removeFlags) + } + if (readPermissionAllowed) { + Log.d(TAG, "Release read permission $uri") val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION - takePersistableUriPermission(uri, takeFlags) + releasePersistableUriPermission(uri, takeFlags) } - if (readOnly) { - if (writePermissionAllowed) { - Log.d(TAG, "Release write permission $uri") - val removeFlags: Int = Intent.FLAG_GRANT_WRITE_URI_PERMISSION - releasePersistableUriPermission(uri, removeFlags) - } - } else { - if (!writePermissionAllowed) { - Log.d(TAG, "Take write permission $uri") - val takeFlags: Int = Intent.FLAG_GRANT_WRITE_URI_PERMISSION - takePersistableUriPermission(uri, takeFlags) - } + } + + // Take missing permission + if (!readPermissionAllowed) { + Log.d(TAG, "Take read permission $uri") + val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION + takePersistableUriPermission(uri, takeFlags) + } + if (readOnly) { + if (writePermissionAllowed) { + Log.d(TAG, "Release write permission $uri") + val removeFlags: Int = Intent.FLAG_GRANT_WRITE_URI_PERMISSION + releasePersistableUriPermission(uri, removeFlags) + } + } else { + if (!writePermissionAllowed) { + Log.d(TAG, "Take write permission $uri") + val takeFlags: Int = Intent.FLAG_GRANT_WRITE_URI_PERMISSION + takePersistableUriPermission(uri, takeFlags) } } } From 3b054504a1beb8dab46ea646f838318d9252ec1d Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 11:05:01 -0400 Subject: [PATCH 16/29] Update UriUtil.kt removed another kitkat check --- .../com/kunzisoft/keepass/utils/UriUtil.kt | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt b/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt index 61af75836..c53a29e7d 100644 --- a/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt +++ b/app/src/main/java/com/kunzisoft/keepass/utils/UriUtil.kt @@ -138,27 +138,25 @@ 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 -> - val listToNotRemove = mutableListOf() - databaseFileList.forEach { - it.databaseUri?.let { databaseUri -> - listToNotRemove.add(databaseUri) - } - it.keyFileUri?.let { keyFileUri -> - listToNotRemove.add(keyFileUri) - } + applicationContext?.let { appContext -> + val fileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(appContext) + fileDatabaseHistoryAction.getDatabaseFileList { databaseFileList -> + val listToNotRemove = mutableListOf() + databaseFileList.forEach { + it.databaseUri?.let { databaseUri -> + listToNotRemove.add(databaseUri) } - // Remove URI permission for not database files - val resolver = appContext.contentResolver - resolver.persistedUriPermissions.forEach { uriPermission -> - val uri = uriPermission.uri - if (!listToNotRemove.contains(uri)) - resolver.releaseUriPermission(uri) + it.keyFileUri?.let { keyFileUri -> + listToNotRemove.add(keyFileUri) } } + // Remove URI permission for not database files + val resolver = appContext.contentResolver + resolver.persistedUriPermissions.forEach { uriPermission -> + val uri = uriPermission.uri + if (!listToNotRemove.contains(uri)) + resolver.releaseUriPermission(uri) + } } } } From 87be2f4b9e988cf58d6c8e456bed1d9a0cf4b75f Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 11:09:44 -0400 Subject: [PATCH 17/29] Update UriHelper.kt removed PackageManager.allowCreateDocumentByStorageAccessFramework() it will always eval to true with sdk update --- .../com/kunzisoft/keepass/utils/UriHelper.kt | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/database/src/main/java/com/kunzisoft/keepass/utils/UriHelper.kt b/database/src/main/java/com/kunzisoft/keepass/utils/UriHelper.kt index 11e9389bb..28868038f 100644 --- a/database/src/main/java/com/kunzisoft/keepass/utils/UriHelper.kt +++ b/database/src/main/java/com/kunzisoft/keepass/utils/UriHelper.kt @@ -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 { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { From 6eae0f02d374e85c7fdbdfade72b2131560a04c2 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 11:11:53 -0400 Subject: [PATCH 18/29] Update FileDatabaseSelectActivity.kt removed PackageManager.allowCreateDocumentByStorageAccessFramework() --- .../keepass/activities/FileDatabaseSelectActivity.kt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt index cfafd0853..7e752e4f7 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt @@ -70,7 +70,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 @@ -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 - } + createDatabaseButtonView?.visibility = View.VISIBLE } else -> { // Disable create button if in selection mode or request for autofill From 3035f9b6860ade559601dea6800f249658995448 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 11:14:18 -0400 Subject: [PATCH 19/29] Update TimeoutHelper.kt Removed old SDK check --- .../keepass/timeout/TimeoutHelper.kt | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/timeout/TimeoutHelper.kt b/app/src/main/java/com/kunzisoft/keepass/timeout/TimeoutHelper.kt index 2042e315a..a32081606 100644 --- a/app/src/main/java/com/kunzisoft/keepass/timeout/TimeoutHelper.kt +++ b/app/src/main/java/com/kunzisoft/keepass/timeout/TimeoutHelper.kt @@ -65,27 +65,19 @@ 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( - AlarmManager.RTC, - triggerTime, - getLockPendingIntent(context) - ) - } else { - alarmManager.setExact( - AlarmManager.RTC, - triggerTime, - getLockPendingIntent(context) - ) - } - } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + && !alarmManager.canScheduleExactAlarms()) { alarmManager.set( AlarmManager.RTC, triggerTime, getLockPendingIntent(context) ) + } else { + alarmManager.setExact( + AlarmManager.RTC, + triggerTime, + getLockPendingIntent(context) + ) } } } From 600d548fcefc09d371010adf66b93f7dbd9efc6a Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 11:15:46 -0400 Subject: [PATCH 20/29] Update BroadcastAction.kt removed old SDK check --- .../keepass/utils/BroadcastAction.kt | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/utils/BroadcastAction.kt b/app/src/main/java/com/kunzisoft/keepass/utils/BroadcastAction.kt index 8d42310fa..b7f4d6c50 100644 --- a/app/src/main/java/com/kunzisoft/keepass/utils/BroadcastAction.kt +++ b/app/src/main/java/com/kunzisoft/keepass/utils/BroadcastAction.kt @@ -76,27 +76,19 @@ 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( - AlarmManager.RTC_WAKEUP, - first, - lockPendingIntent - ) - } else { - alarmManager.setExact( - AlarmManager.RTC_WAKEUP, - first, - lockPendingIntent - ) - } - } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + && !alarmManager.canScheduleExactAlarms()) { alarmManager.set( AlarmManager.RTC_WAKEUP, first, lockPendingIntent ) + } else { + alarmManager.setExact( + AlarmManager.RTC_WAKEUP, + first, + lockPendingIntent + ) } } } else { From 082c839639a39ee45c49d94e4614a5dc7e09fc97 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 11:18:59 -0400 Subject: [PATCH 21/29] Update EntryEditActivity.kt removed old sdk checks --- .../com/kunzisoft/keepass/activities/EntryEditActivity.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt index ce9a54fd0..49f6544c6 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt @@ -604,16 +604,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) From 1f678fc975cfa101702792e97dc76c5dd7a0d5f0 Mon Sep 17 00:00:00 2001 From: Dev-ClayP Date: Wed, 9 Jul 2025 11:24:30 -0400 Subject: [PATCH 22/29] Update Loupe.kt removed old sdk checks --- .../main/java/com/igreenwood/loupe/Loupe.kt | 276 ++++++------------ 1 file changed, 89 insertions(+), 187 deletions(-) diff --git a/app/src/main/java/com/igreenwood/loupe/Loupe.kt b/app/src/main/java/com/igreenwood/loupe/Loupe.kt index a6f36bb45..de9f45242 100644 --- a/app/src/main/java/com/igreenwood/loupe/Loupe.kt +++ b/app/src/main/java/com/igreenwood/loupe/Loupe.kt @@ -358,78 +358,41 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener, val imageView = imageViewRef.get() ?: return isViewTranslateAnimationRunning = true - - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - imageView.run { - val translationY = if (velY > 0) { - originalViewBounds.top + height - top - } else { - originalViewBounds.top - height - top - } - animate() - .setDuration(dismissAnimationDuration) - .setInterpolator(dismissAnimationInterpolator) - .translationY(translationY.toFloat()) - .setUpdateListener { - val amount = calcTranslationAmount() - changeBackgroundAlpha(amount) - onViewTranslateListener?.onViewTranslate(imageView, amount) - } - .setListener(object : Animator.AnimatorListener { - override fun onAnimationStart(p0: Animator) { - - } - - 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 - } - }) - } - } else { - ObjectAnimator.ofFloat(imageView, View.TRANSLATION_Y, if (velY > 0) { - originalViewBounds.top + imageView.height - imageView.top + + imageView.run { + val translationY = if (velY > 0) { + originalViewBounds.top + height - 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() + originalViewBounds.top - height - top } + animate() + .setDuration(dismissAnimationDuration) + .setInterpolator(dismissAnimationInterpolator) + .translationY(translationY.toFloat()) + .setUpdateListener { + val amount = calcTranslationAmount() + changeBackgroundAlpha(amount) + onViewTranslateListener?.onViewTranslate(imageView, amount) + } + .setListener(object : Animator.AnimatorListener { + override fun onAnimationStart(p0: Animator) { + + } + + 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 + } + }) } } @@ -657,137 +620,76 @@ 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) - .setInterpolator(restoreAnimationInterpolator) - .translationY((originalViewBounds.top - top).toFloat()) - .setUpdateListener { - val amount = calcTranslationAmount() - changeBackgroundAlpha(amount) - onViewTranslateListener?.onViewTranslate(this, amount) + imageView.run { + animate() + .setDuration(restoreAnimationDuration) + .setInterpolator(restoreAnimationInterpolator) + .translationY((originalViewBounds.top - top).toFloat()) + .setUpdateListener { + val amount = calcTranslationAmount() + changeBackgroundAlpha(amount) + onViewTranslateListener?.onViewTranslate(this, amount) + } + .setListener(object : Animator.AnimatorListener { + override fun onAnimationStart(p0: Animator) { + // no op } - .setListener(object : Animator.AnimatorListener { - override fun onAnimationStart(p0: Animator) { - // no op - } - override fun onAnimationEnd(p0: Animator) { - onViewTranslateListener?.onRestore(imageView) - } + override fun onAnimationEnd(p0: Animator) { + onViewTranslateListener?.onRestore(imageView) + } - override fun onAnimationCancel(p0: Animator) { - // no op - } + override fun onAnimationCancel(p0: Animator) { + // no op + } - override fun onAnimationRepeat(p0: Animator) { - // no op - } - }) - } - } 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() - } + override fun onAnimationRepeat(p0: Animator) { + // no op + } + }) } + } 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 - } else { - originalViewBounds.top - height - top - } - animate() - .setDuration(dismissAnimationDuration) - .setInterpolator(AccelerateDecelerateInterpolator()) - .translationY(translationY.toFloat()) - .setUpdateListener { - val amount = calcTranslationAmount() - changeBackgroundAlpha(amount) - onViewTranslateListener?.onViewTranslate(this, amount) + + imageView.run { + val translationY = if (y - initialY > 0) { + originalViewBounds.top + height - top + } else { + originalViewBounds.top - height - top + } + animate() + .setDuration(dismissAnimationDuration) + .setInterpolator(AccelerateDecelerateInterpolator()) + .translationY(translationY.toFloat()) + .setUpdateListener { + val amount = calcTranslationAmount() + changeBackgroundAlpha(amount) + onViewTranslateListener?.onViewTranslate(this, amount) + } + .setListener(object : Animator.AnimatorListener { + override fun onAnimationStart(p0: Animator) { + isViewTranslateAnimationRunning = true } - .setListener(object : Animator.AnimatorListener { - override fun onAnimationStart(p0: Animator) { - isViewTranslateAnimationRunning = true - } - override fun onAnimationEnd(p0: Animator) { - isViewTranslateAnimationRunning = false - onViewTranslateListener?.onDismiss(imageView) - cleanup() - } + override fun onAnimationEnd(p0: Animator) { + isViewTranslateAnimationRunning = false + onViewTranslateListener?.onDismiss(imageView) + cleanup() + } - override fun onAnimationCancel(p0: Animator) { - isViewTranslateAnimationRunning = false - } + override fun onAnimationCancel(p0: Animator) { + isViewTranslateAnimationRunning = false + } - override fun onAnimationRepeat(p0: Animator) { - // no op - } - }) - } - } 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() - } + override fun onAnimationRepeat(p0: Animator) { + // no op + } + }) } + } private fun processFlingToDismiss(velocityY: Float) { From 7632face63cdee7b682ae8314dfc9e312e902c7d Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 19 Aug 2025 10:09:48 +0200 Subject: [PATCH 23/29] fix: Update issue template --- .github/ISSUE_TEMPLATE/{bug_report.yaml => bug_report.yml} | 4 ++-- .github/ISSUE_TEMPLATE/config.yml | 1 + .../{feature_request.yaml => feature_request.yml} | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) rename .github/ISSUE_TEMPLATE/{bug_report.yaml => bug_report.yml} (97%) create mode 100644 .github/ISSUE_TEMPLATE/config.yml rename .github/ISSUE_TEMPLATE/{feature_request.yaml => feature_request.yml} (96%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yml similarity index 97% rename from .github/ISSUE_TEMPLATE/bug_report.yaml rename to .github/ISSUE_TEMPLATE/bug_report.yml index ecd65ef2a..b517d6ad6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,7 +1,7 @@ name: Bug Report description: Report a bug. -title: "" -labels: bug +title: "[Bug]: " +labels: ["bug"] body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..3ba13e0ce --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yml similarity index 96% rename from .github/ISSUE_TEMPLATE/feature_request.yaml rename to .github/ISSUE_TEMPLATE/feature_request.yml index 027913c26..8b1c1f388 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,7 +1,7 @@ name: Feature request description: Suggest an idea. -title: "" -labels: feature +title: "[Feat]: " +labels: ["feature"] body: - type: markdown attributes: From d34f460b9874267964155ef7e9489832c663c0db Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 19 Aug 2025 10:12:11 +0200 Subject: [PATCH 24/29] fix: Remove title in template issue --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 - .github/ISSUE_TEMPLATE/feature_request.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index b517d6ad6..d08d4ae39 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,5 @@ name: Bug Report description: Report a bug. -title: "[Bug]: " labels: ["bug"] body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 8b1c1f388..e5204a75c 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,5 @@ name: Feature request description: Suggest an idea. -title: "[Feat]: " labels: ["feature"] body: - type: markdown From a28d77ba32ef18df401be75ed83fbd52bc6aa059 Mon Sep 17 00:00:00 2001 From: Richard Macklin Date: Sat, 26 Jul 2025 17:42:39 -0700 Subject: [PATCH 25/29] feat: Remember the last read-only state of each database The app has supported a global setting for opening (all) databases in read-only mode. But that's not particularly flexible for the use case where you have one database that should be read-only and one that should be read-write. Previously, to handle this use case you could open one database in read-only mode, but the next time you attempted to open the same database, it would "forget" that, so you would have to toggle it to read-only mode again manually. This commit changes that behavior so that if you toggle a database to read-only mode, it'll be remembered the next time you open the database. (You can still toggle it back to read-write if you change your mind, and that, too, will be remembered the next time you open the database.) --- .../3.json | 96 +++++++++++++++++++ .../activities/MainCredentialActivity.kt | 14 +++ .../keepass/app/database/AppDatabase.kt | 5 +- .../app/database/FileDatabaseHistoryAction.kt | 6 ++ .../app/database/FileDatabaseHistoryEntity.kt | 3 + .../kunzisoft/keepass/model/DatabaseFile.kt | 1 + 6 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 app/schemas/com.kunzisoft.keepass.app.database.AppDatabase/3.json diff --git a/app/schemas/com.kunzisoft.keepass.app.database.AppDatabase/3.json b/app/schemas/com.kunzisoft.keepass.app.database.AppDatabase/3.json new file mode 100644 index 000000000..f9b3b72ef --- /dev/null +++ b/app/schemas/com.kunzisoft.keepass.app.database.AppDatabase/3.json @@ -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')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt index de0991f5e..8077c9b19 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt @@ -52,6 +52,7 @@ import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper import com.kunzisoft.keepass.activities.helpers.SpecialMode import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity +import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction import com.kunzisoft.keepass.autofill.AutofillComponent import com.kunzisoft.keepass.autofill.AutofillHelper import com.kunzisoft.keepass.biometric.DeviceUnlockFragment @@ -203,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 @@ -702,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) } diff --git a/app/src/main/java/com/kunzisoft/keepass/app/database/AppDatabase.kt b/app/src/main/java/com/kunzisoft/keepass/app/database/AppDatabase.kt index 16d1a190c..117e8b67a 100644 --- a/app/src/main/java/com/kunzisoft/keepass/app/database/AppDatabase.kt +++ b/app/src/main/java/com/kunzisoft/keepass/app/database/AppDatabase.kt @@ -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() { diff --git a/app/src/main/java/com/kunzisoft/keepass/app/database/FileDatabaseHistoryAction.kt b/app/src/main/java/com/kunzisoft/keepass/app/database/FileDatabaseHistoryAction.kt index 1818f8f6e..6f649f362 100644 --- a/app/src/main/java/com/kunzisoft/keepass/app/database/FileDatabaseHistoryAction.kt +++ b/app/src/main/java/com/kunzisoft/keepass/app/database/FileDatabaseHistoryAction.kt @@ -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 ) diff --git a/app/src/main/java/com/kunzisoft/keepass/app/database/FileDatabaseHistoryEntity.kt b/app/src/main/java/com/kunzisoft/keepass/app/database/FileDatabaseHistoryEntity.kt index 96fd5df08..c406a7468 100644 --- a/app/src/main/java/com/kunzisoft/keepass/app/database/FileDatabaseHistoryEntity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/app/database/FileDatabaseHistoryEntity.kt @@ -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 ) { diff --git a/database/src/main/java/com/kunzisoft/keepass/model/DatabaseFile.kt b/database/src/main/java/com/kunzisoft/keepass/model/DatabaseFile.kt index 92470c2fe..fa2320fe9 100644 --- a/database/src/main/java/com/kunzisoft/keepass/model/DatabaseFile.kt +++ b/database/src/main/java/com/kunzisoft/keepass/model/DatabaseFile.kt @@ -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, From e9d20a51a578144fa2f2e5b636903568d4e12064 Mon Sep 17 00:00:00 2001 From: Richard Macklin Date: Fri, 1 Aug 2025 10:05:24 -0700 Subject: [PATCH 26/29] Remove global "Write-protected" setting This addresses J-Jamet's feedback that keeping the global setting would potentially lead to confusion, so it should be removed now that we are remembering each database's read-only state. --- .../keepass/activities/FileDatabaseSelectActivity.kt | 2 +- .../kunzisoft/keepass/activities/MainCredentialActivity.kt | 2 +- .../java/com/kunzisoft/keepass/settings/PreferencesUtil.kt | 7 ------- app/src/main/res/xml/preferences_application.xml | 5 ----- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt index 2ba2638d3..12597efc8 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt @@ -263,7 +263,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(), GroupActivity.launch( this@FileDatabaseSelectActivity, database, - PreferencesUtil.enableReadOnlyDatabase(this@FileDatabaseSelectActivity) + false ) } ACTION_DATABASE_LOAD_TASK -> { diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt index 8077c9b19..42ae3882a 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt @@ -148,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) diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt index 741b390dd..9bc6ae1c6 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt +++ b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt @@ -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()) diff --git a/app/src/main/res/xml/preferences_application.xml b/app/src/main/res/xml/preferences_application.xml index 8ee384ec5..41b2930b5 100644 --- a/app/src/main/res/xml/preferences_application.xml +++ b/app/src/main/res/xml/preferences_application.xml @@ -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"/> - Date: Fri, 1 Aug 2025 10:05:42 -0700 Subject: [PATCH 27/29] Remove no-longer-needed `enable_read_only_*` string resources (We just removed the usages of these strings) --- app/src/main/res/values-ar/strings.xml | 2 -- app/src/main/res/values-az/strings.xml | 2 -- app/src/main/res/values-bg/strings.xml | 2 -- app/src/main/res/values-ca/strings.xml | 2 -- app/src/main/res/values-cs/strings.xml | 2 -- app/src/main/res/values-da/strings.xml | 2 -- app/src/main/res/values-de/strings.xml | 2 -- app/src/main/res/values-el/strings.xml | 2 -- app/src/main/res/values-es/strings.xml | 2 -- app/src/main/res/values-et/strings.xml | 2 -- app/src/main/res/values-eu/strings.xml | 2 -- app/src/main/res/values-fr/strings.xml | 2 -- app/src/main/res/values-gl/strings.xml | 2 -- app/src/main/res/values-hr/strings.xml | 2 -- app/src/main/res/values-hu/strings.xml | 2 -- app/src/main/res/values-in/strings.xml | 2 -- app/src/main/res/values-it/strings.xml | 2 -- app/src/main/res/values-iw/strings.xml | 2 -- app/src/main/res/values-ja/strings.xml | 2 -- app/src/main/res/values-nb/strings.xml | 2 -- app/src/main/res/values-nl/strings.xml | 2 -- app/src/main/res/values-pa/strings.xml | 1 - app/src/main/res/values-pl/strings.xml | 2 -- app/src/main/res/values-pt-rBR/strings.xml | 2 -- app/src/main/res/values-pt-rPT/strings.xml | 2 -- app/src/main/res/values-pt/strings.xml | 2 -- app/src/main/res/values-ro/strings.xml | 2 -- app/src/main/res/values-ru/strings.xml | 2 -- app/src/main/res/values-sk/strings.xml | 2 -- app/src/main/res/values-sq/strings.xml | 2 -- app/src/main/res/values-sv/strings.xml | 2 -- app/src/main/res/values-ta/strings.xml | 2 -- app/src/main/res/values-th/strings.xml | 2 -- app/src/main/res/values-tr/strings.xml | 2 -- app/src/main/res/values-uk/strings.xml | 2 -- app/src/main/res/values-vi/strings.xml | 2 -- app/src/main/res/values-zh-rCN/strings.xml | 2 -- app/src/main/res/values-zh-rTW/strings.xml | 2 -- app/src/main/res/values/donottranslate.xml | 2 -- app/src/main/res/values/strings.xml | 2 -- 40 files changed, 79 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 1cb256a24..494875b23 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -213,8 +213,6 @@ إهتزاز عند اللمس صوت عند اللمس اسمح بدون المفتاح الرئيسي - محمي من التعديل - افتح قاعدة البيانات في وضع القراءة افتراضيا تلميحات تعليمية أعد عرض كل المعلومات التعليمية إعادة تعيين الشاشات التلميحات diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index b48c8a1c3..6ee009306 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -349,7 +349,6 @@ Axtarış məlumatlarını yadda saxla Avtomatik doldurma təklifləri əlavə edildi. Ana açar olmamasına icazə ver - Məlumat bazasını standart olaraq yazma-qorumalı (dəyişməz) aç Məlumat bazasını avtomatik olaraq yadda saxla Bütün təlim məlumatlarını yenidən göstər Təlim ipuclarını sıfırlamaq @@ -572,7 +571,6 @@ Əgər şəxsiyyəti təsdiq edən məlumatlar seçilməyibsə, \"Aç\" düyməsinin sıxılmasına icazə ver Şifrəni sil Məlumat bazasına bağlantı cəhdindən sonra daxil edilmiş şifrəni sil - Yazma qorumalı Hər önəmli prossesdən sonra məlumat bazasını yadda saxla (\"Modifikasiya edilə bilən\" modda keçərlidir) Ekranı açıq saxla Şifrəyə baxarkən və ya redaktə edərkən ekranı açıq saxla diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 41cb7e4ad..2091a718a 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -352,7 +352,6 @@ Настройки на Magikeyboard Избор на записи Разрешаване без главна парола - Само за четене %1$s Записът %1$s е достъпен в Magikeyboard Запис @@ -402,7 +401,6 @@ Бутон за заключване Включете услугата за попълване на формуляри в други приложения Свойства - По подразбиране отваря хранилището само за четене Не забравяйте да потвърдите записа и да го запазите в хранилището. \n \nАко се задейства автоматичното заключване, а сте направили промени, рискувате загуба на данни. diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index fa2887728..3a9c202d5 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -471,8 +471,6 @@ Metadades, paperera de reciclatge, plantilles, historial Algorisme de xifratge de la base de dades utilitzat per a totes les dades Suprimeix la contrasenya introduïda després d\'un intent de connexió a una base de dades - Protegit contra l\'escriptura - Obre la base de dades en mode només de lectura per defecte Permet que les aplicacions de tercers gravin o facin captures de pantalla de l\'aplicació Ressalta els elements per saber com funciona l\'aplicació Reinicia els consells educatius diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 91bb6d430..bf764789e 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -224,8 +224,6 @@ Aktivovat vlastní klávesnici, která snadno vyplní hesla a další položky identity Umožnit bez hlavního klíče Povolit klepnutí na \"Otevřít\", i když není vybráno žádné heslo - Chráněno před zápisem - Ve výchozím stavu otevřít databázi pouze pro čtení Vzdělávací nápovědy Zvýraznit prvky k pochopení práce s aplikací Nastavit vzdělávací nápovědy do výchozího stavu diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 0639d64a5..64fbac849 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -223,8 +223,6 @@ Aktiver et brugerdefineret tastatur, der udfylder adgangskoder og alle identitetsfelter Tillad ingen hovednøgle Tillader at trykke på knappen \"Åbn\", hvis der ikke er valgt nogen legitimationsoplysninger - Skrivebeskyttet - Åbn som standard databasen skrivebeskyttet Praktiske tips Fremhæv elementer for at lære, hvordan appen fungerer Nulstil praktiske tips diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 360035ae6..b98393928 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -277,9 +277,7 @@ Bedienelemente hervorheben, um die Funktionsweise der App zu lernen Änderbar Schreibgeschützt - Schreibgeschützt Datenbank-Schreibschutz aktivieren - Datenbank standardmäßig schreibgeschützt öffnen 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. Eintrag bearbeiten Die Datenbank konnte nicht geladen werden. diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 999e287d3..f585bfe61 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -259,8 +259,6 @@ Επισήμανση στοιχείων για να μάθετε πώς λειτουργεί η εφαρμογή Προστασία εγγραφής Τροποποιήσιμο - Προστασία Εγγραφής - Ανοίξτε τη βάση δεδομένων μόνο για ανάγνωση από προεπιλογή Προστασία Εγγραφής της βάσης δεδομένων σας Αλλάξτε τη λειτουργία ανοίγματος για το session. \n diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index c6ce8639d..992ccb923 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -271,8 +271,6 @@ Permite pulsar el botón \"Abrir\" si no son seleccionadas las credenciales Consejos educativos Destaca los elementos para aprender cómo funciona la aplicación - Protegida contra escritura - Abre la base de datos como solo lectura por defecto Proteja la base de datos contra escritura Magikeyboard Magikeyboard (KeePassDX) diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index de8e12b02..bc89cded7 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -531,7 +531,6 @@ Automaattäite soovitused on lisatud. Kui andmebaas on avatud ainult lugemiseks, siis andmete salvestamine pole võimalik. Kustutab salasõna, mis oli kasutusel andmebaasiga ühenduse loomise ajal - Vaikimisi ava andmebaas vaid lugemiseks Luba teistel rakendusel teha sellest rakendusest ekraanitõmmist või salvestada tema ekraanivaadet Sulge andmebaas Peale automaattäite kasutamist sulega andmebaas @@ -547,7 +546,6 @@ Ära kasuta peavõtit Kui kasutajanimi või salasõna pole valitud, siis võimaldab klõpsida „Ava“ nuppu Kustuta salasõna - Kirjutuskaitstud Ekraanitõmmiste lubamine Koolitusvihjed Õppimaks, kuidas rakendus toimib, tõsta esile kasutajaliidese elemente diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index a7440d78e..2cad4c545 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -397,7 +397,6 @@ Gakoaren eratorpen funtzioak erabiliko duen memoria kopurua. Datuak gordetzeko eskatu formulario bat betetzean Ireki zure aurreko datu-base fitxategia zure fitxategi kudeatzailetik erabiltzen jarraitzeko. - Idazketaren aurka babestuta Aplikazioen blokeo zerrenda Tekla automatikoaren akzioa Aldatu automatikoki aurreko teklatura datu-basearen kredentzialen pantailan @@ -478,7 +477,6 @@ Zifraketa algoritmorako gakoa sortzeko, gako nagusia itxuraldatu egiten da eratorpen funtzio eta ausazko gatz baten bidez. Bilaketa pantaila Erabiltzaileari datu-baseko sarrera hautatzeko aukera erakutsi - Lehenetsi irakurketa soilerako datu-basea irekitzea Berrezarri hezkuntza-pistak Sarrerek zure identitate digitalak administratzen laguntzen dute. \n diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 1f9ac47f0..4d0aefe9c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -283,8 +283,6 @@ Autorise l’appui du bouton \"Ouvrir\" si aucun identifiant n’est sélectionné Protéger en écriture Modifiable - Protéger en écriture - Ouvre la base de données en lecture seule par défaut Protégez en écriture votre base de données Changez le mode d’ouverture pour la session. \n diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 13c39327f..9802a2569 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -556,7 +556,6 @@ Gardar base de datos automaticamente Manter a pantalla acesa Permitir pulsar o botón \"Abrir\" se non seleccionar ningunha credencial - Só lectura Destacar elementos para saber como funciona a aplicación Suxestións educativas restabelecidas Crear o teu arquivo de base de datos @@ -593,7 +592,6 @@ Engadir campos personalizados Completado de formularios %1$s dispoñíbel no Magikeyboard - Abrir a base de datos en modo de só lectura por defecto Configure a xestión do contrasinal dun só uso (HOTP / TOTP) para xerar un token solicitado para a autenticación de dous factores (2FA). Desbloquee a súa base de datos Eliminar contrasinal diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 7cb8ce296..5d537d245 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -310,8 +310,6 @@ Dozvoljava dodir gumba „Otvori”, ako nisu odabrani nikoji podaci za prijavu Izbriši lozinku Briše upisanu lozinku nakon pokušaja povezivanja s bazom podataka - Zaštićeno od pisanja - Standardno otvori bazu podataka u zaštićenom stanju Automatski spremi bazu podataka Automatski spremi bazu podataka nakon svake važne radnje (samo u modusu „Promjenjivo”) Edukativne poruke diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 609d381f5..d51d2a978 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -245,8 +245,6 @@ Hang gombnyomáskor Mesterkulcs elhagyásának engedélyezése A „Megnyitás” gomb engedélyezése, ha nincsenek hitelesítő adatok kiválasztva - Írásvédett - Az adatbázis megnyitása alapértelmezetten írásvédett módban Oktatóképernyők Elemek kiemelése, hogy megtudja hogyan működik az alkalmazás Oktatóképernyők visszaállítása diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 7b0c15dc4..e4f226d30 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -554,7 +554,6 @@ Izinkan tidak ada kunci utama Memungkinkan mengetuk tombol \"Buka\" jika tidak ada kredensial yang dipilih Menghapus kata sandi yang dimasukkan setelah upaya koneksi ke basis data - Buka basis data baca-saja secara baku Biarkan layar nyala Sorot elemen untuk mempelajari cara kerja aplikasi Buat file pengelola kata sandi pertama Anda. @@ -618,7 +617,6 @@ \nPeriksa kompatibilitas dan keamanan KeyStore dengan produsen perangkat Anda dan pembuat ROM yang Anda gunakan. Lindungi basis data Anda dari penulisan Coba simpan informasi terbagi ketika membuat sebuah pilihan entri manual untuk penggunaan mudah di waktu mendatang - Terlindungi-tulis Jaga layar tetap menyala saat melihat atau menyunting sebuah entri Kotak centang kunci perangkat keras Menunggu untuk permintaan tantangan… diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 58ef0c4dd..37ef2ad12 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -222,8 +222,6 @@ Attiva una tastiera personale che inserisce le tue password e i campi di identità Non consentire chiavi principali Permetti di toccare il pulsante \"Apri\" se non sono selezionate credenziali - Protetto da scrittura - Apri il database in sola lettura in modo predefinito Suggerimenti educativi Evidenzia gli elementi per imparare come funziona l\'app Ripristina i suggerimenti educativi diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 54320e9cd..aef987119 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -334,7 +334,6 @@ אזהרה: לוח ההעתקה משותף לכל היישומים. אם מידע רגיש יועתק, תוכנות אחרות עשויות לשחזר אותו. השבת Magikeyboard (KeePassDX) - מוגן מפני כתיבה נקה בסגירה רשומה %1$s זמין ב־Magikeyboard @@ -469,7 +468,6 @@ פעולת מקש אוטומטית אפשר עבודה ללא מפתח ראשי מאפשר הקשה על הכפתור \"פתח\" אם לא נבחרו אישורים - פתח את מסד הנתונים לקריאה בלבד כברירת מחדל מחק סיסמה מוחק את הסיסמה שהוזנה לאחר ניסיון התחברות למסד נתונים הראה שוב את כל המידע הלימודי diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index e7c2d0cf9..768ea7262 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -400,8 +400,6 @@ 認証情報が選択されていない場合でも、[開く] ボタンのタップを許可します パスワードの削除 入力されたパスワードをデータベースへの接続試行後に削除します - 書き込み禁止 - デフォルトでデータベースを読み取り専用として開きます データベースの自動保存 重要なアクションを起こすたびにデータベースを保存します( [変更可能] モードのとき) 教育的なヒント diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 4c72a6d63..24233be04 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -218,8 +218,6 @@ Aktiver et egendefinert tastatur som fyller inn passordene og alle identitetsfelter Tillat ingen hovednøkkel Tillater å trykke på \"Åpne\"-knappen hvis ingen legitimasjon er valgt - Skrivebeskyttet - Åpne databasen skrivebeskyttet som standard Lærerike tips Fremhev elementer for å finne ut hvordan appen fungerer Tilbakestill lærerike tips diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index f80f31bca..b4e7cbb1f 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -230,8 +230,6 @@ Activeer een aangepast toetsenbord dat je wachtwoorden en identiteitsvelden vult Geen hoofdwachtwoord toestaan Schakel de knop \"Openen\" in als er geen referenties zijn geselecteerd - Alleen-lezen - Open de database standaard alleen-lezen Informatieve tips Markeer elementen om te leren hoe de app werkt Informatieve tips opnieuw instellen diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index 7c36ba666..6a2079916 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -331,7 +331,6 @@ ਐਂਟਰੀ ਐਂਟਰੀ ਡਾਟਾਬੇਸ ਬੰਦ ਕਰੋ - ਲਿਖਣ ਤੋਂ ਸੁਰੱਖਿਅਤ ਐਂਟਰੀਆਂ ਵਿੱਚੋਂ ਲੱਭੋ ਐਂਟਰੀ ਨੂੰ ਸੋਧੋ ਅਟੈਚਮੈਂਟ ਜੋੜੋ diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index f1bea4812..0764caae3 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -225,8 +225,6 @@ Aktywuj niestandardową klawiaturę wypełniającą hasła i wszystkie pola tożsamości Zezwalaj na brak klucza głównego Umożliwia naciśnięcie przycisku \"Otwórz\", jeśli nie wybrano żadnych poświadczeń - Ochrona przed zapisem - Domyślnie otwarte bazy danych są tylko do odczytu Wskazówki edukacyjne Podświetl elementy, aby dowiedzieć się, jak działa aplikacja Zresetuj wskazówki edukacyjne diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 45ee1be04..92d234c07 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -222,8 +222,6 @@ Ative um teclado customizado, populando suas senhas e todos os campos de identidade Permitir chave-mestra vazia Permite tocar no botão \"Abrir\" mesmo se nenhuma credencial for selecionada - Somente leitura - Abre o banco de dados no modo somente leitura por padrão Dicas educacionais Destaque os elementos para aprender como o aplicativo funciona Reiniciar telas educacionais diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index efc8ffab2..11ebb1a23 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -269,8 +269,6 @@ Permite tocar no botão \"Abrir\" se não estiverem selecionadas nenhumas credenciais Dicas educacionais Destacar elementos para saber como a aplicação funciona - Apenas leitura - Abrir a base de dados com permissão de apenas leitura por predefinição Proteger a base de dados contra alterações Altere o modo de abertura para a sessão. \n diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 276616a33..8016ca296 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -1,7 +1,5 @@ - Abrir a base de dados com permissão de apenas leitura por predefinição - Apenas leitura Alterável Apenas leitura Destacar elementos para saber como a aplicação funciona diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index a98a7546f..623deb078 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -336,8 +336,6 @@ Permite apăsarea butonului \"Deschidere\" în cazul în care nu sunt selectate credențiale Ștergere parolă Șterge parola introdusă după o încercare de conectare la o bază de date - Protejat la scriere - Deschideți baza de date numai în citire în mod implicit Salvare automată a bazei de date Salvați baza de date după fiecare acțiune importantă (în modul \"Modificabil\") Sugestii educaționale diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 0bdc680eb..23b40a62f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -226,8 +226,6 @@ Активируйте пользовательскую клавиатуру для простого заполнения паролей и любых идентификаторов Разрешить без главного пароля Разрешить нажимать кнопку \"Открыть\", если главный пароль не указан - Только чтение - По умолчанию открывать базу только для чтения Обучающие подсказки Выделять элементы, чтобы показать, как работает приложение Вернуть обучающие подсказки diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 054e31f8d..4decad49c 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -620,8 +620,6 @@ Umožňuje klepnúť na tlačidlo „Otvoriť“, ak nie sú vybraté žiadne poverenia Vymazať heslo Odstráni heslo zadané po pokuse o pripojenie k databáze - Ochrana proti zápisu - V predvolenom nastavení otvorte databázu len na čítanie Nechajte obrazovku zapnutú Pri sledovaní alebo úprave záznamu ponechať obrazovku zapnutú Režim snímky obrazovky diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index bb39889c1..6d56c71c0 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -555,7 +555,6 @@ Shtypje tastesh me dridhje Ruaj hollësi kërkimi Listë bllokimesh që pengon vetëplotësim përkatësish web - Mbrojtur nga shkrimi Mbaje ekranin ndezur Ndihmëza edukative Jepni titull, emër përdoruesi, ose lëndë fushash të tjera, për të marrë fjalëkalimet tuaja. @@ -610,7 +609,6 @@ Shfaq mundësi për ta lënë përdoruesin të përzgjedhë zë baze të dhënash Provo të ruash informacion, kur bëhet një përzgjedhje dorazi e zërit, për përdorim më të kollajtë në të ardhmen S’lejohet ruajtje të dhënash për një bazë të dhënash të hapur vetëm-për-lexim. - Si parazgjedhje, bazën e të dhënave hape si vetëm-për-lexim Ruaje bazën e të dhënave pas çdo veprimi të rëndësishëm (nën mënyrën “E ndryshueshme”) Mbaje hapur ekranin, kur shihet ose përpunohet një zë Lejo aplikacione palësh të treta të regjistrojnë, ose bëjnë foto ekrani të aplikacionit diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 3342ad6b5..666254906 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -279,8 +279,6 @@ Markerar element för att lära dig hur appen fungerar Skrivskyddad Modifierbar - Skrivskyddad - Öppna databasen i skrivskyddat läge som standard Skrivskydda din databas Ändra öppningsläge för sessionen. \n diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index 970ebc979..946f50536 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -647,8 +647,6 @@ வலை களங்களை தானாக நிரப்புவதைத் தடுக்கும் பிளாக்லிச்ட் படிக்க மட்டும் திறக்கப்பட்ட தரவுத்தளத்திற்கு தரவு சேமிப்பு அனுமதிக்கப்படவில்லை. ஆட்டோஃபில் பரிந்துரைகள் சேர்க்கப்பட்டன. - எழுது பாதுகாக்கப்பட்ட - இயல்பாகவே தரவுத்தளத்தை படிக்க மட்டுமே திறக்கவும் உங்கள் டிசிட்டல் அடையாளங்களை நிர்வகிக்க உள்ளீடுகள் உதவுகின்றன.\n\n குழுக்கள் (~ கோப்புறைகள்) உங்கள் தரவுத்தளத்தில் உள்ளீடுகளை ஒழுங்கமைக்கின்றன. உள்ளீடுகள் மூலம் தேடுங்கள் உங்கள் நுழைவுடன் தொடர்புபடுத்த ஒரு வலுவான கடவுச்சொல்லை உருவாக்குங்கள், படிவத்தின் அளவுகோல்களின்படி அதை எளிதாக வரையறுக்கவும், பாதுகாப்பான கடவுச்சொல்லை மறந்துவிடாதீர்கள். diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 195344a31..9f2cdfbc8 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -416,7 +416,6 @@ การแนะนำแบบอินไลน์ ถามเพื่อบันทึกข้อมูล บล็อกการกรอกอัตโนมัติ - ป้องกันการเขียน รีเซ็ทคำแนะนำการใช้งาน แสดงคำแนะนำการใช้งานอีกครั้ง โดยการ<strong>ร่วมแก้ไข</strong> @@ -620,7 +619,6 @@ อนุญาตให้ไม่มีรหัสผ่านหลัก อนุญาตให้แตะปุ่ม \"เปิด\" เมื่อไม่มีข้อมูลประจำตัวถูกเลือก ลบรหัสผ่านที่ป้อนแล้วหลังจากพยายามเชื่อมต่อที่ฐานข้อมูล - เปิดฐานข้อมูลแบบอ่านอย่างเดียวเป็นค่าเรื่มต้น คำแนะนำการใช้งานถูกรีเซ็ทแล้ว ชุดไอคอน บันทึกฐานข้อมูลหลังจากการกระทำที่สำคัญ(ในโหมด\"แก้ไขได้\") diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index cafe7823b..28b5aa6b8 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -236,8 +236,6 @@ Tuşa basıldığında ses çıkar Ana anahtar olmamasına izin ver Seçili kimlik bilgisi yoksa \"Aç\" düğmesine dokunmaya izin verir - Yazma korumalı - Veri tabanını öntanımlı olarak salt okunur aç Eğitim ipuçları Uygulamanın nasıl çalıştığını öğrenmek için ögeleri vurgulayın Eğitici ipuçlarını sıfırla diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 5c08cfcb6..7e2dca9e4 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -314,8 +314,6 @@ Виділяти елементи, щоб дізнатися, як працює застосунок Навчальні підказки Автозбереження бази даних - Типово відкривати базу даних лише для читання - Захист від запису Видаляти пароль, введений після спроби з\'єднання з базою даних Видаляти пароль Дозволяє натискання «Відкрити», якщо не вибрано головний пароль diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index b2c1205a7..19f93744c 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -568,8 +568,6 @@ 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 Xóa mật khẩu Xóa mật khẩu đã nhập sau khi cố gắng kết nối với cơ sở dữ liệu - Bảo vệ chống ghi - Mở cơ sở dữ liệu ở chế độ chỉ đọc theo mặc định Tự động lưu cơ sở dữ liệu Lưu cơ sở dữ liệu sau mỗi hành động quan trọng (ở chế độ \"Có thể sửa đổi\") Giữ màn hình luôn bật diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index a53d4b5e0..d6d8858b9 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -190,8 +190,6 @@ 其他 键盘 魔法键盘 - 写入保护(只读模式) - 默认以只读方式打开数据库 下载 贡献 应用中使用的主题 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 51dfa818b..3ea1a9310 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -218,8 +218,6 @@ 自動儲存資料庫 高亮界面元素來學習本應用工作方式 教學提示 - 預設以唯讀方式開啟資料庫 - 寫入保護(唯讀模式) 已儲存加密密碼 加密 加密演算法 diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index 394e1dee0..f563e16ad 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -67,8 +67,6 @@ false delete_entered_password_key true - enable_read_only_key - false enable_auto_save_database_key true enable_keep_screen_on_key diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8fe153bda..0ec99e00d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -575,8 +575,6 @@ Allows tapping the \"Open\" button if no credentials are selected Delete password Deletes the password entered after a connection attempt to a database - Write-protected - Open the database read-only by default Autosave database Save the database after every important action (in \"Modifiable\" mode) Keep screen on From daf717becd2aa566a7c1ccb9ffe734f3e1670804 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 1 Sep 2025 18:15:00 +0200 Subject: [PATCH 28/29] fix: Remove JELLY_BEAN_MR1 conditions and unused PRNGFixes --- .../com/kunzisoft/keepass/app/PRNGFixes.java | 399 ------------------ .../keepass/view/PasswordTextEditFieldView.kt | 9 +- .../keepass/view/TextEditFieldView.kt | 16 +- .../keepass/view/TextSelectFieldView.kt | 37 +- 4 files changed, 23 insertions(+), 438 deletions(-) delete mode 100644 app/src/main/java/com/kunzisoft/keepass/app/PRNGFixes.java diff --git a/app/src/main/java/com/kunzisoft/keepass/app/PRNGFixes.java b/app/src/main/java/com/kunzisoft/keepass/app/PRNGFixes.java deleted file mode 100644 index 6e168417e..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/app/PRNGFixes.java +++ /dev/null @@ -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"); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/view/PasswordTextEditFieldView.kt b/app/src/main/java/com/kunzisoft/keepass/view/PasswordTextEditFieldView.kt index 0b6b26ae3..ba0394eca 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/PasswordTextEditFieldView.kt +++ b/app/src/main/java/com/kunzisoft/keepass/view/PasswordTextEditFieldView.kt @@ -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,18 +103,14 @@ 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) - } + 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) - } + it.addRule(ALIGN_END, passwordProgressViewId) } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/view/TextEditFieldView.kt b/app/src/main/java/com/kunzisoft/keepass/view/TextEditFieldView.kt index ae5a09e50..486c75b99 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/TextEditFieldView.kt +++ b/app/src/main/java/com/kunzisoft/keepass/view/TextEditFieldView.kt @@ -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 - } + 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) - } + it.addRule(ALIGN_PARENT_END) } - visibility = View.GONE + visibility = GONE contentDescription = context.getString(R.string.menu_edit) } @@ -91,9 +87,7 @@ 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) - } + it.addRule(START_OF, actionImageButtonId) } } valueView.apply { @@ -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 diff --git a/app/src/main/java/com/kunzisoft/keepass/view/TextSelectFieldView.kt b/app/src/main/java/com/kunzisoft/keepass/view/TextSelectFieldView.kt index 781c5dda6..24dbd9ff0 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/TextSelectFieldView.kt +++ b/app/src/main/java/com/kunzisoft/keepass/view/TextSelectFieldView.kt @@ -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 - } + 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 - ) - } + setCompoundDrawablesRelativeWithIntrinsicBounds( + null, + null, + drawable, + null + ) isFocusable = false inputType = InputType.TYPE_NULL maxLines = 1 @@ -94,9 +95,7 @@ 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) - } + 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) - } + 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(START_OF, actionImageButtonId) it?.addRule(BELOW, labelViewId) } } From c911b7c511b8bc668cc1d6c1486b2272da178577 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 1 Sep 2025 19:01:35 +0200 Subject: [PATCH 29/29] fix: Import DatabaseFile --- .../com/kunzisoft/keepass/activities/MainCredentialActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt index 42ae3882a..cd45b54a3 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt @@ -67,6 +67,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