From f4f5e869790065a967f0e93dcb93c3dda536220d Mon Sep 17 00:00:00 2001 From: Clay Perry Date: Tue, 8 Jul 2025 12:52:14 -0400 Subject: [PATCH 01/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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 daf717becd2aa566a7c1ccb9ffe734f3e1670804 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 1 Sep 2025 18:15:00 +0200 Subject: [PATCH 25/25] 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) } }