feat: 优化代码

pull/105/head
kunfei 5 years ago
parent 440ad903d8
commit 75c99dbe7d
  1. 2
      app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt
  2. 4
      app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt
  3. 123
      app/src/main/java/io/legado/app/utils/FileUtils.kt
  4. 173
      app/src/main/java/io/legado/app/utils/RealPathUtil.kt
  5. 17
      app/src/main/java/io/legado/app/utils/UriExtensions.kt

@ -193,7 +193,7 @@ class BgTextConfigDialog : DialogFragment() {
) )
.rationale(R.string.bg_image_per) .rationale(R.string.bg_image_per)
.onGranted { .onGranted {
FileUtils.getRealPath(requireContext(), uri)?.let { path -> RealPathUtil.getPath(requireContext(), uri)?.let { path ->
ReadBookConfig.getConfig().setBg(2, path) ReadBookConfig.getConfig().setBg(2, path)
ReadBookConfig.upBg() ReadBookConfig.upBg()
postEvent(EventBus.UP_CONFIG, false) postEvent(EventBus.UP_CONFIG, false)

@ -11,7 +11,7 @@ import io.legado.app.R
import io.legado.app.base.BaseActivity import io.legado.app.base.BaseActivity
import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.utils.FileUtils import io.legado.app.utils.RealPathUtil
import kotlinx.android.synthetic.main.activity_qrcode_capture.* import kotlinx.android.synthetic.main.activity_qrcode_capture.*
import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.android.synthetic.main.view_title_bar.*
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
@ -98,7 +98,7 @@ class QrCodeActivity : BaseActivity(R.layout.activity_qrcode_capture), QRCodeVie
zxingview.startSpotAndShowRect() // 显示扫描框,并开始识别 zxingview.startSpotAndShowRect() // 显示扫描框,并开始识别
if (resultCode == Activity.RESULT_OK && requestCode == requestQrImage) { if (resultCode == Activity.RESULT_OK && requestCode == requestQrImage) {
val picturePath = FileUtils.getRealPath(this, it) val picturePath = RealPathUtil.getPath(this, it)
// 本来就用到 QRCodeView 时可直接调 QRCodeView 的方法,走通用的回调 // 本来就用到 QRCodeView 时可直接调 QRCodeView 的方法,走通用的回调
zxingview.decodeQRCode(picturePath) zxingview.decodeQRCode(picturePath)
} }

@ -1,11 +1,6 @@
package io.legado.app.utils package io.legado.app.utils
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.os.Environment import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import io.legado.app.App import io.legado.app.App
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@ -105,122 +100,4 @@ object FileUtils {
return sdCardDirectory return sdCardDirectory
} }
fun getRealPath(context: Context, uri: Uri): String? {
// DocumentProvider
if (DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":")
val type = split[0]
if ("primary".equals(type, ignoreCase = true)) {
@Suppress("DEPRECATION")
return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
}
} else if (isDownloadsDocument(uri)) {
val id = DocumentsContract.getDocumentId(uri)
val split = id.split(":")
val type = split[0]
if ("raw".equals(type, ignoreCase = true)) {
//处理某些机型(比如Google Pixel )ID是raw:/storage/emulated/0/Download/c20f8664da05ab6b4644913048ea8c83.mp4
return split[1]
}
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)
)
return getDataColumn(context, contentUri, null, null)
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex())
val contentUri: Uri = when (split[0]) {
"image" -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
"video" -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
"audio" -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
else -> uri
}
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri, selection, selectionArgs)
}// MediaProvider
// DownloadsProvider
} else if ("content".equals(uri.scheme, ignoreCase = true)) {
// Return the remote address
return if (isGooglePhotosUri(uri))
uri.lastPathSegment
else
getDataColumn(context, uri, null, null)
} else if ("file".equals(uri.scheme, ignoreCase = true)) {
return uri.path
}// File
// MediaStore (and general)
return null
}
private fun getDataColumn(
context: Context, uri: Uri, selection: String?,
selectionArgs: Array<String>?
): String? {
val column = "_data"
val projection = arrayOf(column)
try {
context.contentResolver.query(
uri,
projection,
selection,
selectionArgs,
null
)?.use { cursor ->
if (cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(index)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
private fun isGooglePhotosUri(uri: Uri): Boolean {
return "com.google.android.apps.photos.content" == uri.authority
}
} }

@ -0,0 +1,173 @@
package io.legado.app.utils
import android.annotation.SuppressLint
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
@Suppress("unused")
object RealPathUtil {
/**
* Method for return file path of Gallery image
* @return path of the selected image file from gallery
*/
private var filePathUri: Uri? = null
@Suppress("DEPRECATION")
fun getPath(
context: Context,
uri: Uri
): String? {
//check here to KITKAT or new version
@SuppressLint("ObsoleteSdkInt")
val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
filePathUri = uri
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":").toTypedArray()
val type = split[0]
if ("primary".equals(type, ignoreCase = true)) {
return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
}
} else if (isDownloadsDocument(uri)) {
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
java.lang.Long.valueOf(id)
)
//return getDataColumn(context, uri, null, null);
return getDataColumn(context, contentUri, null, null)
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":").toTypedArray()
val type = split[0]
var contentUri: Uri? = null
if ("image" == type) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else if ("video" == type) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if ("audio" == type) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
val selection = "_id=?"
val selectionArgs = arrayOf(
split[1]
)
return getDataColumn(context, contentUri, selection, selectionArgs)
}
} else if ("content".equals(
uri.scheme,
ignoreCase = true
)
) { // Return the remote address
return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(
context,
uri,
null,
null
)
} else if ("file".equals(uri.scheme, ignoreCase = true)) {
return uri.path
}
return null
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
private fun getDataColumn(
context: Context, uri: Uri?, selection: String?,
selectionArgs: Array<String>?
): String? {
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(
column
)
var input: FileInputStream? = null
var output: FileOutputStream? = null
try {
cursor =
context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(index)
}
} catch (e: IllegalArgumentException) {
e.printStackTrace()
val file = File(context.cacheDir, "tmp")
val filePath = file.absolutePath
try {
val pfd =
context.contentResolver.openFileDescriptor(filePathUri!!, "r")
?: return null
val fd = pfd.fileDescriptor
input = FileInputStream(fd)
output = FileOutputStream(filePath)
var read: Int
val bytes = ByteArray(4096)
while (input.read(bytes).also { read = it } != -1) {
output.write(bytes, 0, read)
}
input.close()
output.close()
return File(filePath).absolutePath
} catch (ignored: IOException) {
ignored.printStackTrace()
}
} finally {
cursor?.close()
}
return null
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
private fun isGooglePhotosUri(uri: Uri): Boolean {
return "com.google.android.apps.photos.content" == uri.authority
}
}

@ -2,15 +2,14 @@ package io.legado.app.utils
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import java.io.File import java.io.File
@Throws(Exception::class) @Throws(Exception::class)
fun Uri.readBytes(context: Context): ByteArray? { fun Uri.readBytes(context: Context): ByteArray? {
if (DocumentFile.isDocumentUri(context, this)) { if (this.toString().isContentPath()) {
return DocumentUtils.readBytes(context, this) return DocumentUtils.readBytes(context, this)
} else { } else {
val path = FileUtils.getRealPath(context, this) val path = RealPathUtil.getPath(context, this)
if (path?.isNotEmpty() == true) { if (path?.isNotEmpty() == true) {
return File(path).readBytes() return File(path).readBytes()
} }
@ -20,10 +19,10 @@ fun Uri.readBytes(context: Context): ByteArray? {
@Throws(Exception::class) @Throws(Exception::class)
fun Uri.readText(context: Context): String? { fun Uri.readText(context: Context): String? {
if (DocumentFile.isDocumentUri(context, this)) { if (this.toString().isContentPath()) {
return DocumentUtils.readText(context, this) return DocumentUtils.readText(context, this)
} else { } else {
val path = FileUtils.getRealPath(context, this) val path = RealPathUtil.getPath(context, this)
if (path?.isNotEmpty() == true) { if (path?.isNotEmpty() == true) {
return File(path).readText() return File(path).readText()
} }
@ -33,10 +32,10 @@ fun Uri.readText(context: Context): String? {
@Throws(Exception::class) @Throws(Exception::class)
fun Uri.writeBytes(context: Context, byteArray: ByteArray): Boolean { fun Uri.writeBytes(context: Context, byteArray: ByteArray): Boolean {
if (DocumentFile.isDocumentUri(context, this)) { if (this.toString().isContentPath()) {
return DocumentUtils.writeBytes(context, byteArray, this) return DocumentUtils.writeBytes(context, byteArray, this)
} else { } else {
val path = FileUtils.getRealPath(context, this) val path = RealPathUtil.getPath(context, this)
if (path?.isNotEmpty() == true) { if (path?.isNotEmpty() == true) {
File(path).writeBytes(byteArray) File(path).writeBytes(byteArray)
return true return true
@ -47,10 +46,10 @@ fun Uri.writeBytes(context: Context, byteArray: ByteArray): Boolean {
@Throws(Exception::class) @Throws(Exception::class)
fun Uri.writeText(context: Context, text: String): Boolean { fun Uri.writeText(context: Context, text: String): Boolean {
if (DocumentFile.isDocumentUri(context, this)) { if (this.toString().isContentPath()) {
return DocumentUtils.writeText(context, text, this) return DocumentUtils.writeText(context, text, this)
} else { } else {
val path = FileUtils.getRealPath(context, this) val path = RealPathUtil.getPath(context, this)
if (path?.isNotEmpty() == true) { if (path?.isNotEmpty() == true) {
File(path).writeText(text) File(path).writeText(text)
return true return true

Loading…
Cancel
Save