thread task

v4
laoyuyu 2 years ago
parent 8097992c00
commit 7ba3ea3185
  1. 387
      PublicComponent/src/main/java/com/arialyy/aria/util/FileUri.kt

@ -0,0 +1,387 @@
package com.arialyy.aria.util
import android.annotation.SuppressLint
import android.content.*
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.*
import androidx.core.content.FileProvider
import com.arialyy.aria.core.DuaContext
import timber.log.Timber
import java.io.*
/**
* # FileUri
*
* - Uri & Path Tool
*
* @author javakam
* @date 2020/8/24 11:24
*/
object FileUri {
//Android R
//----------------------------------------------------------------
/**
* `MANAGE_EXTERNAL_STORAGE` 权限检查
*
* @return `true` Have permission
*/
fun isExternalStorageManager(): Boolean =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) Environment.isExternalStorageManager() else false
/**
* 跳转到 `MANAGE_EXTERNAL_STORAGE` 权限设置页面
*
* @return `true` Has been set
*/
fun jumpManageAppAllFilesPermissionSetting(
context: Context,
isNewTask: Boolean = false,
): Boolean {
if (isExternalStorageManager()) return true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.data = Uri.parse("package:${context.packageName}")
if (isNewTask) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
} catch (e: Exception) {
Timber.e("jumpManageAppAllFilesPermissionSetting: $e")
}
}
return false
}
//从 FilePath 中获取 Uri (Get Uri from FilePath)
//----------------------------------------------------------------
fun getUriByPath(path: String?): Uri? =
if (path.isNullOrBlank()) null else getUriByFile(File(path))
/**
* Return a content URI for a given file.
*
* @param file The file.
* @param isOriginal true content:// or file:// ; false file://xxx
* @return a content URI for a given file
*/
fun getUriByFile(file: File?, isOriginal: Boolean = false): Uri? {
return if (isOriginal) Uri.fromFile(file)
else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val authority = DuaContext.context.packageName + AUTHORITY
FileProvider.getUriForFile(DuaContext.context, authority, file ?: return null)
} else {
Uri.fromFile(file)
}
}
}
fun getShareUri(path: String?): Uri? =
if (path.isNullOrBlank()) null else getUriByFile(File(path), isOriginal = false)
/**
* @return content:// or file://
*/
fun getShareUri(file: File?): Uri? = getUriByFile(file, isOriginal = false)
fun getOriginalUri(path: String?): Uri? =
if (path.isNullOrBlank()) null else getUriByFile(File(path), isOriginal = true)
/**
* @return file://xxx
*/
fun getOriginalUri(file: File?): Uri? = getUriByFile(file, isOriginal = true)
//获取Uri对应的文件路径, Compatible with API 26
//----------------------------------------------------------------
/**
* ### Get the file path through Uri
*
* - Need permission: RequiresPermission(permission.READ_EXTERNAL_STORAGE)
*
* - Modified from: https://github.com/coltoscosmin/FileUtils/blob/master/FileUtils.java
*
* @return file path
*/
fun getPathByUri(uri: Uri?): String? {
return uri?.use {
Timber.i(
"FileUri getPathByUri -> " +
"Uri: " + uri +
", Authority: " + uri.authority +
", Fragment: " + uri.fragment +
", Port: " + uri.port +
", Query: " + uri.query +
", Scheme: " + uri.scheme +
", Host: " + uri.host +
", Segments: " + uri.pathSegments.toString()
)
// 以 file:// 开头的使用第三方应用打开 (open with third-party applications starting with file://)
if (ContentResolver.SCHEME_FILE.equals(uri.scheme, ignoreCase = true)) return getDataColumn(
uri
)
@SuppressLint("ObsoleteSdkInt")
val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
// Before 4.4 , API 19 content:// 开头, 比如 content://media/external/images/media/123
if (!isKitKat && ContentResolver.SCHEME_CONTENT.equals(uri.scheme, true)) {
if (isGooglePhotosUri(uri)) return uri.lastPathSegment
return getDataColumn(uri)
}
val context = DuaContext.context
// After 4.4 , API 19
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// LocalStorageProvider
if (isLocalStorageDocument(uri)) {
// The path is the id
return DocumentsContract.getDocumentId(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)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
.toString() + File.separator + split[1]
} else {
@Suppress("DEPRECATION")
return Environment.getExternalStorageDirectory()
.toString() + File.separator + split[1]
}
} else if ("home".equals(type, ignoreCase = true)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
.toString() + File.separator + "documents" + File.separator + split[1]
} else {
@Suppress("DEPRECATION")
return Environment.getExternalStorageDirectory()
.toString() + File.separator + "documents" + File.separator + split[1]
}
} else {
@Suppress("DEPRECATION")
val sdcardPath =
Environment.getExternalStorageDirectory()
.toString() + File.separator + "documents" + File.separator + split[1]
return if (sdcardPath.startsWith("file://")) {
sdcardPath.replace("file://", "")
} else {
sdcardPath
}
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
val id = DocumentsContract.getDocumentId(uri)
if (id != null && id.startsWith("raw:")) {
return id.substring(4)
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
val contentUriPrefixesToTry = arrayOf(
"content://downloads/public_downloads",
"content://downloads/my_downloads",
"content://downloads/all_downloads"
)
for (contentUriPrefix in contentUriPrefixesToTry) {
val contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), id.toLong())
try {
val path = getDataColumn(contentUri)
if (!path.isNullOrBlank()) return path
} catch (e: Exception) {
Timber.e(e.toString())
}
}
} else {
//testPath(uri)
return getDataColumn(uri)
}
}
// MediaProvider
else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":").toTypedArray()
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
"download" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Downloads.EXTERNAL_CONTENT_URI
} else null
else -> null
}
val selectionArgs = arrayOf(split[1])
return getDataColumn(contentUri, "_id=?", selectionArgs)
}
//GoogleDriveProvider
else if (isGoogleDriveUri(uri)) {
return getGoogleDriveFilePath(uri, context)
}
}
// MediaStore (and general)
else if ("content".equals(uri.scheme, ignoreCase = true)) {
// Return the remote address
if (isGooglePhotosUri(uri)) {
return uri.lastPathSegment
}
// Google drive legacy provider
else if (isGoogleDriveUri(uri)) {
return getGoogleDriveFilePath(uri, context)
}
// Huawei
else if (isHuaWeiUri(uri)) {
val uriPath = getDataColumn(uri) ?: uri.toString()
//content://com.huawei.hidisk.fileprovider/root/storage/emulated/0/Android/data/com.xxx.xxx/
if (uriPath.startsWith("/root")) {
return uriPath.replace("/root".toRegex(), "")
}
}
return getDataColumn(uri)
}
return getDataColumn(uri)
}
}
/**
* BUG : 部分机型进入"文件管理器" 执行到 cursor.getColumnIndexOrThrow(column);出现
* Caused by: java.lang.IllegalArgumentException: column '_data' does not exist. Available columns: []
*
* Fixed :
* https://stackoverflow.com/questions/42508383/illegalargumentexception-column-data-does-not-exist
*
*/
private fun getDataColumn(
uri: Uri?,
selection: String? = null,
selectionArgs: Array<String>? = null
): String? {
@Suppress("DEPRECATION")
val column = MediaStore.Files.FileColumns.DATA
val projection = arrayOf(column)
try {
DuaContext.context.contentResolver.query(
uri ?: return null,
projection,
selection,
selectionArgs,
null
)?.use { c: Cursor ->
if (c.moveToFirst()) {
val columnIndex = c.getColumnIndex(column)
return c.getString(columnIndex)
}
}
} catch (e: Throwable) {
Timber.e("getDataColumn -> ${e.message}")
}
return null
}
//The Uri to check
//----------------------------------------------------------------
private fun getGoogleDriveFilePath(uri: Uri, context: Context): String? {
context.contentResolver.query(uri, null, null, null, null)?.use { c: Cursor ->
/*
Get the column indexes of the data in the Cursor,
move to the first row in the Cursor, get the data, and display it.
*/
val nameIndex: Int = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
//val sizeIndex: Int = c.getColumnIndex(OpenableColumns.SIZE)
if (!c.moveToFirst()) {
return uri.toString()
}
val name: String = c.getString(nameIndex)
//val size = c.getLong(sizeIndex).toString()
val file = File(context.cacheDir, name)
var inputStream: InputStream? = null
var outputStream: FileOutputStream? = null
try {
inputStream = context.contentResolver.openInputStream(uri)
outputStream = FileOutputStream(file)
var read = 0
val maxBufferSize = 1 * 1024 * 1024
val bytesAvailable: Int = inputStream?.available() ?: 0
val bufferSize = bytesAvailable.coerceAtMost(maxBufferSize)
val buffers = ByteArray(bufferSize)
while (inputStream?.read(buffers)?.also { read = it } != -1) {
outputStream.write(buffers, 0, read)
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
inputStream?.close()
outputStream?.close()
}
return file.path
}
return uri.toString()
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
fun isGooglePhotosUri(uri: Uri?): Boolean {
return "com.google.android.apps.photos.content".equals(uri?.authority, true)
}
fun isGoogleDriveUri(uri: Uri?): Boolean {
return "com.google.android.apps.docs.storage.legacy" == uri?.authority || "com.google.android.apps.docs.storage" == uri?.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is local.
*/
fun isLocalStorageDocument(uri: Uri?): Boolean {
return AUTHORITY.equals(uri?.authority, true)
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private fun isExternalStorageDocument(uri: Uri?): Boolean {
return "com.android.externalstorage.documents".equals(uri?.authority, true)
}
/**
* @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".equals(uri?.authority, true)
}
/**
* @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".equals(uri?.authority, true)
}
/**
* content://com.huawei.hidisk.fileprovider/root/storage/emulated/0/Android/data/com.xxx.xxx/
*
* @param uri
* @return
*/
private fun isHuaWeiUri(uri: Uri?): Boolean {
return "com.huawei.hidisk.fileprovider".equals(uri?.authority, true)
}
}
Loading…
Cancel
Save