From 652131ce0dbe2b7e2257cf2c623167f1dfff2379 Mon Sep 17 00:00:00 2001 From: lfeng Date: Mon, 17 Aug 2026 10:00:23 +0000 Subject: [PATCH] [Android] Fix TryGetFileFromPathAsync/TryGetFolderFromPathAsync returning null for content:// URI (#21986) * [Android] Fix TryGetFileFromPathAsync/TryGetFolderFromPathAsync returning null for content:// URI * [Android] Add URI scheme constants in AndroidStorageProvider --- Directory.Packages.props | 1 + .../Avalonia.Android/Avalonia.Android.csproj | 1 + .../Storage/AndroidStorageProvider.cs | 67 +++++++++++++++++-- 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index d38cb33b28..983d369fab 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -69,6 +69,7 @@ + diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index befdcbcd5e..e22990d18c 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs index e55689f93d..66e56f3d6b 100644 --- a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs +++ b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs @@ -7,6 +7,7 @@ using Android; using Android.App; using Android.Content; using Android.Provider; +using AndroidX.DocumentFile.Provider; using Avalonia.Platform.Storage; using Avalonia.Platform.Storage.FileIO; using AndroidUri = Android.Net.Uri; @@ -18,6 +19,8 @@ namespace Avalonia.Android.Platform.Storage; internal class AndroidStorageProvider : IStorageProvider { public static ReadOnlySpan AndroidKey => "android"u8; + private const string ContentUriScheme = "content"; + private const string FileUriScheme = "file"; private readonly Activity _activity; public AndroidStorageProvider(Activity activity) @@ -62,10 +65,29 @@ internal class AndroidStorageProvider : IStorageProvider // to read or write files in your application-specific directories [...]" // Consequently, we don't try to check for that permission here anymore. - var javaFile = new JavaFile(androidUriPath); - if (javaFile.Exists() && javaFile.IsFile) + if (filePath.Scheme == FileUriScheme && androidUri.Path is not null) { - return new BclStorageFile(new System.IO.FileInfo(javaFile.AbsolutePath)); + var javaFile = new JavaFile(androidUri.Path); + if (javaFile.Exists() && javaFile.IsFile) + { + return new BclStorageFile(new System.IO.FileInfo(javaFile.AbsolutePath)); + } + return null; + } + else if (filePath.Scheme == ContentUriScheme && _activity.ContentResolver is not null) + { + try + { + using var stream = _activity.ContentResolver.OpenInputStream(androidUri); + if (stream is not null) + { + return new AndroidStorageFile(_activity, androidUri); + } + } + catch (Exception) + { + return null; + } } return null; @@ -89,10 +111,43 @@ internal class AndroidStorageProvider : IStorageProvider return null; } - var javaFile = new JavaFile(androidUriPath); - if (javaFile.Exists() && javaFile.IsDirectory) + if (folderPath.Scheme == FileUriScheme && androidUri.Path is not null) + { + var javaFile = new JavaFile(androidUri.Path); + if (javaFile.Exists() && javaFile.IsDirectory) + { + return new BclStorageFolder(new System.IO.DirectoryInfo(javaFile.AbsolutePath)); + } + return null; + } + else if (folderPath.Scheme == ContentUriScheme) { - return new BclStorageFolder(new System.IO.DirectoryInfo(javaFile.AbsolutePath)); + try + { + if (OperatingSystem.IsAndroidVersionAtLeast(21)) + { + if (DocumentsContract.IsTreeUri(androidUri)) + { + var docId = DocumentsContract.GetTreeDocumentId(androidUri); + if (!string.IsNullOrEmpty(docId)) + { + return new AndroidStorageFolder(_activity, androidUri, false); + } + } + else + { + var documentFile = DocumentFile.FromSingleUri(_activity, androidUri); + if (documentFile is not null && documentFile.Exists() && documentFile.IsDirectory) + { + return new AndroidStorageFolder(_activity, androidUri, false); + } + } + } + } + catch (Exception) + { + return null; + } } return null;