Skip to content

Commit

Permalink
Fix folder picker on android
Browse files Browse the repository at this point in the history
  • Loading branch information
maxkatz6 committed Jun 12, 2022
1 parent 8e35dc4 commit 3e02b2f
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 82 deletions.
143 changes: 81 additions & 62 deletions src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
using Android.Provider;
using Avalonia.Logging;
using Avalonia.Platform.Storage;
using Java.Lang;
using AndroidUri = Android.Net.Uri;
using Exception = System.Exception;
using JavaFile = Java.IO.File;

namespace Avalonia.Android.Platform.Storage;
Expand Down Expand Up @@ -43,66 +45,8 @@ public bool TryGetUri([NotNullWhen(true)] out Uri? uri)
return true;
}

public Task<StorageItemProperties> GetBasicPropertiesAsync()
{
ulong? size = null;
DateTimeOffset? itemDate = null;
DateTimeOffset? dateModified = null;

var projection = new[]
{
MediaStore.IMediaColumns.Size,
MediaStore.IMediaColumns.DateAdded,
MediaStore.IMediaColumns.DateModified
};
using var cursor = Context.ContentResolver!.Query(Uri, projection, null, null, null);

if (cursor?.MoveToFirst() == true)
{
try
{
var columnIndex = cursor.GetColumnIndex(MediaStore.IMediaColumns.Size);
if (columnIndex != -1)
{
size = (ulong)cursor.GetLong(columnIndex);
}
}
catch (Exception ex)
{
Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?
.Log(this, "File Size metadata reader failed: '{Exception}'", ex);
}
try
{
var columnIndex = cursor.GetColumnIndex(MediaStore.IMediaColumns.DateAdded);
if (columnIndex != -1)
{
itemDate = DateTimeOffset.FromUnixTimeMilliseconds(cursor.GetLong(columnIndex));
}
}
catch (Exception ex)
{
Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?
.Log(this, "File DateAdded metadata reader failed: '{Exception}'", ex);
}
try
{
var columnIndex = cursor.GetColumnIndex(MediaStore.IMediaColumns.DateModified);
if (columnIndex != -1)
{
dateModified = DateTimeOffset.FromUnixTimeMilliseconds(cursor.GetLong(columnIndex));
}
}
catch (Exception ex)
{
Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?
.Log(this, "File DateAdded metadata reader failed: '{Exception}'", ex);
}
}

return Task.FromResult(new StorageItemProperties(size, itemDate, dateModified));
}

public abstract Task<StorageItemProperties> GetBasicPropertiesAsync();

protected string? GetColumnValue(Context context, AndroidUri contentUri, string column, string? selection = null, string[]? selectionArgs = null)
{
try
Expand Down Expand Up @@ -144,6 +88,11 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
public AndroidStorageFolder(Context context, AndroidUri uri) : base(context, uri)
{
}

public override Task<StorageItemProperties> GetBasicPropertiesAsync()
{
return Task.FromResult(new StorageItemProperties());
}
}

internal class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkFile
Expand All @@ -157,10 +106,10 @@ public AndroidStorageFile(Context context, AndroidUri uri) : base(context, uri)
public bool CanOpenWrite => true;

public Task<Stream> OpenRead() => Task.FromResult(OpenContentStream(Context, Uri, false)
?? throw new InvalidOperationException("Failed to open content stream"));
?? throw new InvalidOperationException("Failed to open content stream"));

public Task<Stream> OpenWrite() => Task.FromResult(OpenContentStream(Context, Uri, true)
?? throw new InvalidOperationException("Failed to open content stream"));
?? throw new InvalidOperationException("Failed to open content stream"));

private Stream? OpenContentStream(Context context, AndroidUri uri, bool isOutput)
{
Expand Down Expand Up @@ -209,4 +158,74 @@ private bool IsVirtualFile(Context context, AndroidUri uri)

return null;
}

public override Task<StorageItemProperties> GetBasicPropertiesAsync()
{
ulong? size = null;
DateTimeOffset? itemDate = null;
DateTimeOffset? dateModified = null;

try
{
var projection = new[]
{
MediaStore.IMediaColumns.Size, MediaStore.IMediaColumns.DateAdded,
MediaStore.IMediaColumns.DateModified
};
using var cursor = Context.ContentResolver!.Query(Uri, projection, null, null, null);

if (cursor?.MoveToFirst() == true)
{
try
{
var columnIndex = cursor.GetColumnIndex(MediaStore.IMediaColumns.Size);
if (columnIndex != -1)
{
size = (ulong)cursor.GetLong(columnIndex);
}
}
catch (Exception ex)
{
Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?
.Log(this, "File Size metadata reader failed: '{Exception}'", ex);
}

try
{
var columnIndex = cursor.GetColumnIndex(MediaStore.IMediaColumns.DateAdded);
if (columnIndex != -1)
{
var longValue = cursor.GetLong(columnIndex);
itemDate = longValue > 0 ? DateTimeOffset.FromUnixTimeMilliseconds(longValue) : null;
}
}
catch (Exception ex)
{
Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?
.Log(this, "File DateAdded metadata reader failed: '{Exception}'", ex);
}

try
{
var columnIndex = cursor.GetColumnIndex(MediaStore.IMediaColumns.DateModified);
if (columnIndex != -1)
{
var longValue = cursor.GetLong(columnIndex);
dateModified = longValue > 0 ? DateTimeOffset.FromUnixTimeMilliseconds(longValue) : null;
}
}
catch (Exception ex)
{
Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?
.Log(this, "File DateAdded metadata reader failed: '{Exception}'", ex);
}
}
}
catch (UnsupportedOperationException)
{
// It's not possible to get parameters of some files/folders.
}

return Task.FromResult(new StorageItemProperties(size, itemDate, dateModified));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,16 @@ internal class AndroidStorageProvider : IStorageProvider
private readonly AvaloniaActivity _activity;
private int _lastRequestCode = 20000;

private bool? _canOpen, _canSave, _canPickFolder;

public AndroidStorageProvider(AvaloniaActivity activity)
{
_activity = activity;
}

public bool CanOpen => _canOpen
??= OperatingSystem.IsAndroidVersionAtLeast(19) && new Intent(Intent.ActionOpenDocument)
.AddCategory(Intent.CategoryOpenable)
.SetType(FilePickerFileTypes.All.MimeTypes![0])
.ResolveActivity(_activity.PackageManager!) is not null;
public bool CanOpen => OperatingSystem.IsAndroidVersionAtLeast(19);

public bool CanSave => _canSave
??= OperatingSystem.IsAndroidVersionAtLeast(19) && new Intent(Intent.ActionCreateDocument)
.AddCategory(Intent.CategoryOpenable)
.SetType(FilePickerFileTypes.All.MimeTypes![0])
.ResolveActivity(_activity.PackageManager!) is not null;
public bool CanSave => OperatingSystem.IsAndroidVersionAtLeast(19);

public bool CanPickFolder => _canPickFolder
??= OperatingSystem.IsAndroidVersionAtLeast(21) && new Intent(Intent.ActionOpenDocumentTree)
.AddCategory(Intent.CategoryOpenable)
.SetType(FilePickerFileTypes.All.MimeTypes![0])
.ResolveActivity(_activity.PackageManager!) is not null;
public bool CanPickFolder => OperatingSystem.IsAndroidVersionAtLeast(21);

public Task<IStorageBookmarkFolder?> OpenFolderBookmarkAsync(string bookmark)
{
Expand All @@ -62,7 +48,6 @@ public async Task<IReadOnlyList<IStorageFile>> OpenFilePickerAsync(FilePickerOpe
var intent = new Intent(Intent.ActionOpenDocument)
.AddCategory(Intent.CategoryOpenable)
.PutExtra(Intent.ExtraAllowMultiple, options.AllowMultiple)
.PutExtra(DocumentsContract.ExtraInitialUri, options.AllowMultiple)
.SetType(FilePickerFileTypes.All.MimeTypes![0]);
if (mimeTypes.Length > 0)
{
Expand Down Expand Up @@ -112,7 +97,6 @@ public async Task<IReadOnlyList<IStorageFile>> OpenFilePickerAsync(FilePickerOpe
public async Task<IStorageFolder?> OpenFolderPickerAsync(FolderPickerOpenOptions options)
{
var intent = new Intent(Intent.ActionOpenDocumentTree)
.AddCategory(Intent.CategoryOpenable);
if (TryGetInitialUri(options.SuggestedStartLocation) is { } initialUri)
{
intent = intent.PutExtra(DocumentsContract.ExtraInitialUri, initialUri);
Expand Down Expand Up @@ -185,4 +169,4 @@ void OnActivityResult(int requestCode, Result resultCode, Intent data)

return null;
}
}
}

0 comments on commit 3e02b2f

Please sign in to comment.