根据 uri 获取文件
This commit is contained in:
parent
53a549013f
commit
b3d578339d
|
|
@ -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>
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue