fix: better static utils implementation

This commit is contained in:
J-Jamet 2023-05-08 20:30:16 +02:00
parent c8868f31e6
commit dfb418c12a
39 changed files with 226 additions and 310 deletions

View file

@ -20,7 +20,6 @@
package com.kunzisoft.keepass.database.element
import android.content.ContentResolver
import android.content.Context
import android.graphics.Color
import android.net.Uri
import android.util.Log
@ -58,6 +57,8 @@ import com.kunzisoft.keepass.icons.IconDrawableFactory
import com.kunzisoft.keepass.icons.InterfaceIconPackChooser
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.*
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
import com.kunzisoft.keepass.utils.UriHelper.getUriOutputStream
import java.io.*
import java.util.*
@ -786,7 +787,7 @@ class Database(private val iconPackChooser: InterfaceIconPackChooser) {
openDatabaseKDBX: (InputStream) -> Unit) {
try {
// Load Data, pass Uris as InputStreams
val databaseStream = UriUtilDatabase.getUriInputStream(contentResolver, databaseUri)
val databaseStream = contentResolver.getUriInputStream(databaseUri)
?: throw UnknownDatabaseLocationException()
BufferedInputStream(databaseStream).use { databaseInputStream ->
@ -867,7 +868,7 @@ class Database(private val iconPackChooser: InterfaceIconPackChooser) {
}
}
// Copy from the cache to the final stream
UriUtilDatabase.getUriOutputStream(contentResolver, saveUri)?.use { outputStream ->
contentResolver.getUriOutputStream(saveUri)?.use { outputStream ->
cacheFile.inputStream().use { inputStream ->
inputStream.readAllBytes { buffer ->
outputStream.write(buffer)
@ -1005,8 +1006,8 @@ class Database(private val iconPackChooser: InterfaceIconPackChooser) {
}
}
fun clearAndClose(context: Context? = null) {
clearIndexesAndBinaries(context?.let { UriUtilDatabase.getBinaryDir(context) })
fun clearAndClose(filesDirectory: File? = null) {
clearIndexesAndBinaries(filesDirectory)
this.mDatabaseKDB = null
this.mDatabaseKDBX = null
this.fileUri = null

View file

@ -29,7 +29,7 @@ import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.utils.StringUtil.removeSpaceChars
import com.kunzisoft.keepass.utils.StringUtil.toHexString
import com.kunzisoft.keepass.utils.UriUtilDatabase
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
import com.kunzisoft.keepass.utils.readEnum
import com.kunzisoft.keepass.utils.writeEnum
import org.apache.commons.codec.binary.Hex
@ -148,7 +148,7 @@ data class MainCredential(var password: String? = null,
@Throws(Exception::class)
private fun getKeyFileData(contentResolver: ContentResolver,
keyFileUri: Uri): ByteArray? {
UriUtilDatabase.getUriInputStream(contentResolver, keyFileUri)?.use { keyFileInputStream ->
contentResolver.getUriInputStream(keyFileUri)?.use { keyFileInputStream ->
return keyFileInputStream.readBytes()
}
return null

View file

@ -36,3 +36,17 @@ open class SingletonHolder<out T>(private val constructor: (iconPackChooser : In
}
}
}
open class SingletonHolderParameter<out T, in A>(private val constructor: (A) -> T) {
@Volatile
private var instance: T? = null
fun getInstance(arg: A): T {
return when {
instance != null -> instance!!
else -> synchronized(this) {
if (instance == null) instance = constructor(arg)
instance!!
}
}
}
}

View file

@ -19,65 +19,50 @@
*/
package com.kunzisoft.keepass.utils
import android.annotation.SuppressLint
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.os.Build
import android.util.Log
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream
import java.util.Locale
import java.io.*
import java.util.*
object UriUtilDatabase {
fun parse(stringUri: String?): Uri? {
return if (stringUri?.isNotEmpty() == true) {
Uri.parse(stringUri)
} else
null
object UriHelper {
fun String.parseUri(): Uri? {
return if (this.isNotEmpty()) Uri.parse(this) else null
}
fun decode(uri: String?): String {
return Uri.decode(uri) ?: ""
}
fun getBinaryDir(context: Context): File {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
context.applicationContext.noBackupFilesDir
} else {
context.applicationContext.filesDir
}
fun String.decodeUri(): String {
return Uri.decode(this) ?: ""
}
@Throws(FileNotFoundException::class)
fun getUriInputStream(contentResolver: ContentResolver, fileUri: Uri?): InputStream? {
fun ContentResolver.getUriInputStream(fileUri: Uri?): InputStream? {
if (fileUri == null)
return null
return when {
isFileScheme(fileUri) -> fileUri.path?.let { FileInputStream(it) }
isContentScheme(fileUri) -> contentResolver.openInputStream(fileUri)
fileUri.withFileScheme() -> fileUri.path?.let { FileInputStream(it) }
fileUri.withContentScheme() -> this.openInputStream(fileUri)
else -> null
}
}
@SuppressLint("Recycle")
@Throws(FileNotFoundException::class)
fun getUriOutputStream(contentResolver: ContentResolver, fileUri: Uri?): OutputStream? {
fun ContentResolver.getUriOutputStream(fileUri: Uri?): OutputStream? {
if (fileUri == null)
return null
return when {
isFileScheme(fileUri) -> fileUri.path?.let { FileOutputStream(it) }
isContentScheme(fileUri) -> {
fileUri.withFileScheme() -> fileUri.path?.let { FileOutputStream(it) }
fileUri.withContentScheme() -> {
try {
contentResolver.openOutputStream(fileUri, "wt")
this.openOutputStream(fileUri, "wt")
} catch (e: FileNotFoundException) {
Log.e(TAG, "Unable to open stream in `wt` mode, retry in `rwt` mode.", e)
// https://issuetracker.google.com/issues/180526528
// Try with rwt to fix content provider issue
val outStream = contentResolver.openOutputStream(fileUri, "rwt")
val outStream = this.openOutputStream(fileUri, "rwt")
Log.w(TAG, "`rwt` mode used.")
outStream
}
@ -86,16 +71,16 @@ object UriUtilDatabase {
}
}
private fun isFileScheme(fileUri: Uri): Boolean {
val scheme = fileUri.scheme
fun Uri.withFileScheme(): Boolean {
val scheme = this.scheme
if (scheme == null || scheme.isEmpty() || scheme.lowercase(Locale.ENGLISH) == "file") {
return true
}
return false
}
private fun isContentScheme(fileUri: Uri): Boolean {
val scheme = fileUri.scheme
fun Uri.withContentScheme(): Boolean {
val scheme = this.scheme
if (scheme != null && scheme.lowercase(Locale.ENGLISH) == "content") {
return true
}