Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 10.3.8
### Android
- Restores the ms[df] URI handling logic in FileUtils.kt to fix file selection returning null on some devices. fixes [#1922](https://github.com/miguelpruivo/flutter_file_picker/issues/1922), fixes [#1916](https://github.com/miguelpruivo/flutter_file_picker/issues/1916)

## 10.3.7
### Android
- Fixed an issue where file type filtering was not being applied correctly, now only displaying files that match the selected MIME types. [#1906](https://github.com/miguelpruivo/flutter_file_picker/pull/1906)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ object FileUtils {
uri,
DocumentsContract.getTreeDocumentId(uri)
)
val dirPath = getFullPathFromTreeUri(uri)
val dirPath = getFullPathFromTreeUri(uri, activity)
if (dirPath != null) {
finishWithSuccess(dirPath)
} else {
Expand Down Expand Up @@ -131,6 +131,14 @@ object FileUtils {
}
}

/**
* Creates and launches an intent for the given file type.
*
* This method is responsible for creating the appropriate intent based on the [type] of file
* that is requested to be picked.
*
* This may be either a directory, a regular file, or a gallery pick.
*/
fun FilePickerDelegate.startFileExplorer() {
val intent: Intent

Expand All @@ -142,7 +150,8 @@ object FileUtils {
if (type == "dir") {
intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
} else {
if (type != "*/*") {
if (type == "image/*") {
// Use ACTION_PICK for images to allow using the Gallery app, which provides a better UX for image selection.
intent = Intent(Intent.ACTION_PICK)
val uri = (Environment.getExternalStorageDirectory().path + File.separator).toUri()
intent.setDataAndType(uri, type)
Expand All @@ -159,7 +168,12 @@ object FileUtils {
intent.putExtra(Intent.EXTRA_MIME_TYPES, allowedExtensions)
}
} else {
intent = Intent(Intent.ACTION_GET_CONTENT).apply {
// Use ACTION_OPEN_DOCUMENT to allow selecting files from any document provider (SAF).
// We prefer ACTION_OPEN_DOCUMENT over ACTION_GET_CONTENT because it offers persistent
// access to the files via URI permissions, which is crucial for some use cases
// (e.g. caching, repeated access). ACTION_GET_CONTENT is more suitable for
// "importing" content and might not provide a persistent URI.
intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = [email protected]
if (!allowedExtensions.isNullOrEmpty()) {
Expand All @@ -186,6 +200,16 @@ object FileUtils {
}
}

/**
* Called by the plugin to start a new file explorer activity.
*
* @param type The file types that will be selectable.
* @param isMultipleSelection Whether multiple files can be selected.
* @param withData Whether the file data should be loaded into memory.
* @param allowedExtensions The allowed file extensions for custom file types.
* @param compressionQuality The compression quality for images.
* @param result The result channel to send the file picking result to.
*/
fun FilePickerDelegate?.startFileExplorer(
type: String?,
isMultipleSelection: Boolean?,
Expand Down Expand Up @@ -413,7 +437,7 @@ object FileUtils {
try {
context.contentResolver.openInputStream(originalImageUri).use { imageStream ->
val compressFormat = getCompressFormat(context, originalImageUri)
val compressedFile = createImageFile(context, originalImageUri, compressFormat)
val compressedFile = createImageFile(context, compressFormat)
val originalBitmap = BitmapFactory.decodeStream(imageStream)
// Compress and save the image
val fileOutputStream = FileOutputStream(compressedFile)
Expand All @@ -429,7 +453,7 @@ object FileUtils {
}

@Throws(IOException::class)
private fun createImageFile(context: Context, uri: Uri, compressFormat: Bitmap.CompressFormat): File {
private fun createImageFile(context: Context, compressFormat: Bitmap.CompressFormat): File {
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val imageFileName = "IMAGE_" + timeStamp + "_"
val storageDir = context.cacheDir
Expand Down Expand Up @@ -557,7 +581,7 @@ object FileUtils {
}

@JvmStatic
fun getFullPathFromTreeUri(treeUri: Uri?): String? {
fun getFullPathFromTreeUri(treeUri: Uri?, context: Context): String? {
if (treeUri == null) {
return null
}
Expand All @@ -569,6 +593,14 @@ object FileUtils {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path
if (docId == "downloads") {
return extPath
} else if (docId.matches("^ms[df]:.*".toRegex())) {
// Handle "msf:" (Media Store File) and "msd:" (Media Store Directory) prefixes.
// These are commonly seen on Android 10+ (API 29+) when selecting files from the
// "Downloads" category in the system picker.
// Note that this does not happen on all devices.
// Example URI: content://com.android.providers.downloads.documents/document/msf:1000000033
val fileName = getFileName(treeUri, context)
return "$extPath/$fileName"
} else if (docId.startsWith("raw:")) {
return docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()[1]
Expand All @@ -580,13 +612,13 @@ object FileUtils {
var volumePath = getPathFromTreeUri(treeUri)

if (volumePath.endsWith(File.separator)) {
volumePath = volumePath.substring(0, volumePath.length - 1)
volumePath = volumePath.dropLast(1)
}

var documentPath = getDocumentPathFromTreeUri(treeUri)

if (documentPath.endsWith(File.separator)) {
documentPath = documentPath.substring(0, documentPath.length - 1)
documentPath = documentPath.dropLast(1)
}
return if (documentPath.isNotEmpty()) {
if (volumePath.endsWith(documentPath)) {
Expand Down Expand Up @@ -623,4 +655,4 @@ object FileUtils {

file.delete()
}
}
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: A package that allows you to use a native file explorer to pick sin
homepage: https://github.com/miguelpruivo/plugins_flutter_file_picker
repository: https://github.com/miguelpruivo/flutter_file_picker
issue_tracker: https://github.com/miguelpruivo/flutter_file_picker/issues
version: 10.3.7
version: 10.3.8

dependencies:
flutter:
Expand Down
Loading