根据 uri 获取文件

This commit is contained in:
luyao 2019-12-09 16:37:15 +08:00
parent 53a549013f
commit b3d578339d
7 changed files with 284 additions and 1 deletions

View File

@ -39,6 +39,7 @@
<activity android:name="luyao.util.ktx.ui.ShellExtActivity"/>
<activity android:name="luyao.util.ktx.ui.LifeCycleActivity"/>
<activity android:name="luyao.util.ktx.ui.KtxSpanActivity"/>
<activity android:name="luyao.util.ktx.ui.ChooseFileActivity" />
</application>
</manifest>

View File

@ -0,0 +1,78 @@
package luyao.util.ktx.ui
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.activity_choose_file.*
import luyao.ktx.R
import luyao.util.ktx.base.BaseActivity
import luyao.util.ktx.ext.startFileChooser
import luyao.util.ktx.ext.toRealFile
/**
* Created by luyao
* on 2019/12/9 15:00
*/
class ChooseFileActivity : BaseActivity() {
private var allowMultiple = false
override fun getLayoutResId() = R.layout.activity_choose_file
override fun initView() {
singleChoose.setOnClickListener { chooseFile(1001, false) }
multipleChoose.setOnClickListener { chooseFile(1001, true) }
}
private fun chooseFile(requestCode: Int, multiple: Boolean) {
allowMultiple = multiple
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED
) {
startFileChooser(requestCode, allowMultiple)
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
1002
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startFileChooser(1001, allowMultiple)
}
}
override fun initData() {
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if ((requestCode == 1001) && (resultCode == Activity.RESULT_OK)) {
data?.data?.let { // single
uriResult.text = it.toRealFile()?.path ?: ""
}
data?.clipData?.let {
// multiple
val builder = StringBuilder()
for (i in 0 until it.itemCount) {
it.getItemAt(i).uri.let { uri ->
builder.append("${uri.toRealFile()?.path}\n\n")
}
}
uriResult.text = builder.toString()
}
}
}
}

View File

@ -22,6 +22,7 @@ class ExtActivity : CommonListActivity() {
add(ItemBean("SharedPreferencesExt", SharedPreferencesActivity::class.java))
add(ItemBean("ShellExt", ShellExtActivity::class.java))
add(ItemBean("ToastExt", ToastExtActivity::class.java))
add(ItemBean("UriExt",ChooseFileActivity::class.java))
}
}

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/title_layout"/>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/singleChoose"
android:text="Single Choose"
style="@style/NormalButton"/>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/multipleChoose"
android:text="Multiple Choose"
style="@style/NormalButton"/>
<TextView
android:id="@+id/uriResult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="@color/black"
android:textSize="16sp"/>
</LinearLayout>

View File

@ -32,7 +32,7 @@ val Context.screenWidth
val Context.screenHeight
get() = resources.displayMetrics.heightPixels
fun fromKitKat() = fromSpecificVersion(Build.VERSION_CODES.KITKAT)
fun fromM() = fromSpecificVersion(Build.VERSION_CODES.M)
fun beforeM() = beforeSpecificVersion(Build.VERSION_CODES.M)
fun fromN() = fromSpecificVersion(Build.VERSION_CODES.N)

View File

@ -1,5 +1,6 @@
package luyao.util.ktx.ext
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
@ -153,4 +154,15 @@ fun Context.sendEmail(email: String, subject: String?, text: String?) {
}
}
fun Activity.startFileChooser(requestCode: Int, allowMultiple: Boolean = false) {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*"
intent.addCategory(Intent.CATEGORY_OPENABLE)
if (fromSpecificVersion(Build.VERSION_CODES.JELLY_BEAN_MR2)) intent.putExtra(
Intent.EXTRA_ALLOW_MULTIPLE,
allowMultiple
)
startActivityForResult(Intent.createChooser(intent, "Choose File"), requestCode)
}

View File

@ -0,0 +1,161 @@
package luyao.util.ktx.ext
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.text.TextUtils
import luyao.util.ktx.Ktx
import java.io.File
import java.lang.reflect.Array
/*
* from Blankj
* https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/UriUtils.java
*/
/**
* Created by luyao
* on 2019/12/9 15:20
*/
fun Uri.toRealFile(): File? {
val authority = authority
val scheme = scheme
val path = path
if (fromN() && path != null && path.startsWith("/external/")) {
val file = File(Environment.getExternalStorageDirectory().absolutePath + path.replace("/external", ""))
if (file.exists()) {
return file
}
}
if (ContentResolver.SCHEME_FILE == scheme) {
return if (path != null) File(path) else null
} else if (fromKitKat() && DocumentsContract.isDocumentUri(Ktx.app, this)) {
if ("com.android.externalstorage.documents" == authority) {
val docId = DocumentsContract.getDocumentId(this)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
if ("primary".equals(type, ignoreCase = true)) {
return File(Environment.getExternalStorageDirectory().toString() + "/" + split[1])
} else {
// Below logic is how External Storage provider build URI for documents
// http://stackoverflow.com/questions/28605278/android-5-sd-card-label
val mStorageManager = Ktx.app.storageManager
try {
val storageVolumeClazz = Class.forName("android.os.storage.StorageVolume")
val getVolumeList = mStorageManager?.javaClass?.getMethod("getVolumeList")
val getUuid = storageVolumeClazz.getMethod("getUuid")
val getState = storageVolumeClazz.getMethod("getState")
val getPath = storageVolumeClazz.getMethod("getPath")
val isPrimary = storageVolumeClazz.getMethod("isPrimary")
val isEmulated = storageVolumeClazz.getMethod("isEmulated")
val result = getVolumeList?.invoke(mStorageManager)
val length = Array.getLength(result)
for (i in 0 until length) {
val storageVolumeElement = Array.get(result, i)
//String uuid = (String) getUuid.invoke(storageVolumeElement);
val mounted =
Environment.MEDIA_MOUNTED == getState.invoke(storageVolumeElement) || Environment.MEDIA_MOUNTED_READ_ONLY == getState.invoke(
storageVolumeElement
)
//if the media is not mounted, we need not get the volume details
if (!mounted) continue
//Primary storage is already handled.
if (isPrimary.invoke(storageVolumeElement) as Boolean &&
isEmulated.invoke(storageVolumeElement) as Boolean) {
continue
}
val uuid = getUuid.invoke(storageVolumeElement) as String
if (uuid == type) {
return File(getPath.invoke(storageVolumeElement).toString() + "/" + split[1])
}
}
} catch (ex: Exception) {
ex.printStackTrace()
}
}
return null
} else if ("com.android.providers.downloads.documents" == authority) {
val id = DocumentsContract.getDocumentId(this)
if (!TextUtils.isEmpty(id)) {
try {
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
java.lang.Long.valueOf(id)
)
return Ktx.app.getFileFromUri(contentUri, "1_1")
} catch (e: NumberFormatException) {
if (id.startsWith("raw:")) {
return File(id.substring(4))
}
}
}
return null
} else if ("com.android.providers.media.documents" == authority) {
val docId = DocumentsContract.getDocumentId(this)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
val contentUri: Uri
contentUri = when (type) {
"image" -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
"video" -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
"audio" -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
else -> {
return null
}
}
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
return Ktx.app.getFileFromUri(contentUri, selection, selectionArgs)
} else if (ContentResolver.SCHEME_CONTENT == scheme) {
return Ktx.app.getFileFromUri(this)
} else {
return null
}
} else if (ContentResolver.SCHEME_CONTENT == scheme) run {
return Ktx.app.getFileFromUri(this)
} else return null
}
private fun Context.getFileFromUri(
uri: Uri,
selection: String? = null,
selectionArgs: kotlin.Array<String>? = null
): File? {
val cursor = contentResolver.query(
uri, arrayOf("_data"), selection, selectionArgs, null
)
if (cursor == null) {
return null
}
try {
return if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndex("_data")
if (columnIndex > -1) {
File(cursor.getString(columnIndex))
} else {
null
}
} else {
null
}
} catch (e: Exception) {
return null
} finally {
cursor.close()
}
}