Merge branch 'master' of github.com:Dev-ClayP/KeePassDX into Dev-ClayP-master

This commit is contained in:
J-Jamet
2025-09-01 17:34:46 +02:00
19 changed files with 212 additions and 387 deletions

View File

@@ -9,7 +9,7 @@ android {
defaultConfig {
applicationId "com.kunzisoft.keepass"
minSdkVersion 15
minSdkVersion 19
targetSdkVersion 34
versionCode = 139
versionName = "4.1.7"

View File

@@ -359,77 +359,40 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
isViewTranslateAnimationRunning = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
imageView.run {
val translationY = if (velY > 0) {
originalViewBounds.top + height - top
} 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) {

View File

@@ -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<TextView>(R.id.activity_about_privacy_text).apply {

View File

@@ -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)

View File

@@ -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
@@ -330,13 +329,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

View File

@@ -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 ->

View File

@@ -38,7 +38,6 @@ class App : MultiDexApplication() {
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver)
Stylish.load(this)
PRNGFixes.apply()
}
}

View File

@@ -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)
)
}
}
}

View File

@@ -77,27 +77,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 {

View File

@@ -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)
}
}
}
@@ -140,42 +138,38 @@ 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<Uri>()
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<Uri>()
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)
}
}
}
}
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
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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()) {

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -122,8 +122,7 @@
android:inputType="textPassword"
android:importantForAccessibility="no"
android:importantForAutofill="no"
android:hint="@string/otp_secret"
tools:targetApi="jelly_bean" />
android:hint="@string/otp_secret" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
@@ -178,8 +177,7 @@
tools:text="30"
android:maxLength="3"
android:digits="0123456789"
android:imeOptions="actionNext"
tools:targetApi="jelly_bean" />
android:imeOptions="actionNext" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/setup_otp_counter_label"
@@ -198,8 +196,7 @@
android:importantForAutofill="no"
android:hint="@string/otp_counter"
tools:text="1"
android:imeOptions="actionNext"
tools:targetApi="jelly_bean" />
android:imeOptions="actionNext" />
</com.google.android.material.textfield.TextInputLayout>
<androidx.constraintlayout.widget.Guideline
@@ -228,8 +225,7 @@
tools:text="6"
android:maxLength="2"
android:digits="0123456789"
android:imeOptions="actionNext"
tools:targetApi="jelly_bean" />
android:imeOptions="actionNext" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -65,7 +65,6 @@
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_right_white_24dp"
app:tint="?attr/colorOnSurface"
android:importantForAccessibility="no"
tools:targetApi="jelly_bean" />
android:importantForAccessibility="no" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@@ -9,7 +9,7 @@ android {
ndkVersion "21.4.7075529"
defaultConfig {
minSdkVersion 15
minSdkVersion 19
targetSdkVersion 34
multiDexEnabled true

View File

@@ -6,7 +6,7 @@ android {
compileSdkVersion 34
defaultConfig {
minSdkVersion 15
minSdkVersion 19
targetSdk 34
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -148,23 +148,6 @@ fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int = 0): Pa
@Suppress("DEPRECATION") getPackageInfo(packageName, flags)
}
@SuppressLint("InlinedApi")
fun PackageManager.allowCreateDocumentByStorageAccessFramework(): Boolean {
return when {
// To check if a custom file manager can manage the ACTION_CREATE_DOCUMENT
// queries filter is in Manifest
Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT -> {
queryIntentActivitiesCompat(
Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "application/octet-stream"
}, PackageManager.MATCH_DEFAULT_ONLY
).isNotEmpty()
}
else -> true
}
}
@SuppressLint("QueryPermissionsNeeded")
private fun PackageManager.queryIntentActivitiesCompat(intent: Intent, flags: Int): List<ResolveInfo> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {