package com.convenient.android.lib import android.content.Intent import android.net.Uri import android.os.Bundle import android.os.Environment import android.os.Environment.getExternalStorageDirectory import android.provider.DocumentsContract import android.util.Log import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import com.convenient.android.common.base.viewbinding.BaseBindingActivity import com.convenient.android.common.config.MyPdfBaseModule import com.convenient.android.common.extension.* import com.convenient.android.common.media.MediaBean import com.convenient.android.common.media.config.MediaQueryConfig import com.convenient.android.common.media.config.MediaSortOrder import com.convenient.android.common.media.config.MediaSortType import com.convenient.android.common.media.scan.FileStore import com.convenient.android.common.media.scan.MediaStore import com.convenient.android.common.utils.date.DateUtils import com.convenient.android.lib.databinding.ActivityMediaSampleBinding import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File class MediaSampleActivity : BaseBindingActivity(ActivityMediaSampleBinding::inflate) { private var dir: String? = "" val chooseDirLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { it.data?.data?.let { val filepath = resolveContentUri(it) spSave("dir", filepath) dir = filepath binding.tvQueryDir.text = filepath } } enum class QueryMode { FILE, MEDIA_STORE } private var queryMode: MutableStateFlow = MutableStateFlow(QueryMode.FILE) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) MyPdfBaseModule.init(application, true, "1") binding = ActivityMediaSampleBinding.inflate(layoutInflater) setContentView(binding.root) dir = spGetString("dir") binding.tvQueryDir.text = dir setViewsClick( { when (it) { binding.btnQueryFromFiles -> { queryMode.value = QueryMode.FILE query() } binding.btnQueryFromMediaStore -> { queryMode.value = QueryMode.MEDIA_STORE query() } binding.btnChooseDir -> { chooseDir() } } }, binding.btnQueryFromFiles, binding.btnQueryFromMediaStore, binding.btnChooseDir ) lifecycleScope.launch { queryMode.collect { binding.tvQueryType.text = when (it) { QueryMode.MEDIA_STORE -> "MediaStore" QueryMode.FILE -> "File" } } } } private fun chooseDir() { chooseDirLauncher.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { }) } private fun getConfig(): MediaQueryConfig = MediaQueryConfig().also { it.supportMimeTypes = listOf("pdf") it.recursively = true it.order = MediaSortOrder.ASC it.sortType = MediaSortType.SIZE it.includeFolder = false it.ignoreChildFiles = mutableListOf( // File(dir, "新建文件夹/"), // File(dir, "Child/Kotlin 语言文档.pdf") // File("/storage/emulated/0/17PDF/") ) }.also { config -> lifecycleScope.launch(Dispatchers.Main) { binding.tvFileType.text = config.supportMimeTypes.toString() binding.tvQueryIgnoreChildDir.text = config.includeFolder.toString() binding.tvQueryRecursively.text = config.recursively.toString() val builder = StringBuilder() config.ignoreChildFiles.forEach { builder.append(it.absolutePath).append("\n") } binding.tvQueryIgnoreChildFiles.text = builder } } private fun query() { lifecycleScope.launch(Dispatchers.Main) { // dir = "" val data = when (queryMode.value) { QueryMode.FILE -> { queryFromFile() } else -> { queryFromMediaStore() } } val mimeTypes = data.map { it.extension }.distinct() binding.tvResultCount.text = data.size.toString() binding.tvResultFileTypes.text = mimeTypes.toString() for (datum in data) { Log.e("Media", "名称:${datum.mediaPath}, ${DateUtils.getFormatDate(datum.lastModified, "MM-dd HH:mm:ss")},--:${datum.mediaPath.toFile()?.lengthToFitMemorySize()}") } } } private suspend fun queryFromFile(): List = withContext(Dispatchers.IO) { FileStore.query(dir ?: Environment.getExternalStorageDirectory().absolutePath, getConfig()) } private suspend fun queryFromMediaStore(): List = withContext(Dispatchers.IO) { MediaStore.query(dir = dir ?: "", config = getConfig()) } fun resolveContentUri(uri: Uri): String { val docUri = DocumentsContract.buildDocumentUriUsingTree(uri, DocumentsContract.getTreeDocumentId(uri)) val docCursor = contentResolver.query(docUri, null, null, null, null) var str: String = "" // get a string of the form : primary:Audiobooks or 1407-1105:Audiobooks while (docCursor!!.moveToNext()) { str = docCursor.getString(0) if (str.matches(Regex(".*:.*"))) break //Maybe useless } docCursor.close() val split = str.split(":") val base: File = if (split[0] == "primary") getExternalStorageDirectory() else File("/storage/${split[0]}") if (!base.isDirectory) throw Exception("'$uri' cannot be resolved in a valid path") return File(base, split[1]).canonicalPath } }