Browse Source

Android - Query date modified for android storage folder (#20860)

* query date modified for android storage folder

* fix comments

* Update src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
pull/20953/head
Emmanuel Hansen 5 days ago
committed by GitHub
parent
commit
14b591b488
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 109
      src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs

109
src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs

@ -12,6 +12,7 @@ using Avalonia.Logging;
using Avalonia.Platform.Storage;
using Avalonia.Platform.Storage.FileIO;
using Java.Lang;
using static Android.Provider.DocumentsContract;
using AndroidUri = Android.Net.Uri;
using Exception = System.Exception;
using JavaFile = Java.IO.File;
@ -38,7 +39,7 @@ internal abstract class AndroidStorageItem : IStorageBookmarkItem
protected Activity Activity => _activity ?? throw new ObjectDisposedException(nameof(AndroidStorageItem));
public virtual string Name => GetColumnValue(Activity, Uri, DocumentsContract.Document.ColumnDisplayName)
public virtual string Name => GetColumnValue(Activity, Uri, Document.ColumnDisplayName)
?? GetColumnValue(Activity, Uri, MediaStore.IMediaColumns.DisplayName)
?? Uri.PathSegments?.LastOrDefault()?.Split("/", StringSplitOptions.RemoveEmptyEntries).LastOrDefault() ?? string.Empty;
@ -98,7 +99,7 @@ internal abstract class AndroidStorageItem : IStorageBookmarkItem
return null;
}
if(_parent != null)
if (_parent != null)
{
return _parent;
}
@ -106,8 +107,8 @@ internal abstract class AndroidStorageItem : IStorageBookmarkItem
using var javaFile = new JavaFile(Uri.Path!);
// Java file represents files AND directories. Don't be confused.
if (javaFile.ParentFile is {} parentFile
&& AndroidUri.FromFile(parentFile) is {} androidUri)
if (javaFile.ParentFile is { } parentFile
&& AndroidUri.FromFile(parentFile) is { } androidUri)
{
return new AndroidStorageFolder(Activity, androidUri, false);
}
@ -138,8 +139,8 @@ internal abstract class AndroidStorageItem : IStorageBookmarkItem
public static IStorageItem CreateItem(Activity activity, AndroidUri uri)
{
var mimeType = GetColumnValue(activity, uri, DocumentsContract.Document.ColumnMimeType);
if (mimeType == DocumentsContract.Document.MimeTypeDir)
var mimeType = GetColumnValue(activity, uri, Document.ColumnMimeType);
if (mimeType == Document.MimeTypeDir)
{
return new AndroidStorageFolder(activity, uri, false);
}
@ -160,8 +161,8 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
{
var mimeType = MimeTypeMap.Singleton?.GetMimeTypeFromExtension(MimeTypeMap.GetFileExtensionFromUrl(name)) ?? "application/octet-stream";
var treeUri = GetTreeUri().treeUri;
var newFile = DocumentsContract.CreateDocument(Activity.ContentResolver!, treeUri!, mimeType, name);
if(newFile == null)
var newFile = CreateDocument(Activity.ContentResolver!, treeUri!, mimeType, name);
if (newFile == null)
{
return Task.FromResult<IStorageFile?>(null);
}
@ -172,7 +173,7 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
public Task<IStorageFolder?> CreateFolderAsync(string name)
{
var treeUri = GetTreeUri().treeUri;
var newFolder = DocumentsContract.CreateDocument(Activity.ContentResolver!, treeUri!, DocumentsContract.Document.MimeTypeDir, name);
var newFolder = CreateDocument(Activity.ContentResolver!, treeUri!, Document.MimeTypeDir, name);
if (newFolder == null)
{
return Task.FromResult<IStorageFolder?>(null);
@ -197,24 +198,76 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
{
await foreach (var file in storageFolder.GetItemsAsync())
{
if(file is AndroidStorageFolder folder)
if (file is AndroidStorageFolder folder)
{
await DeleteContents(folder);
}
else if(file is AndroidStorageFile storageFile)
else if (file is AndroidStorageFile storageFile)
{
await storageFile.DeleteAsync();
}
}
var treeUri = GetTreeUri().treeUri;
DocumentsContract.DeleteDocument(Activity.ContentResolver!, treeUri!);
DeleteDocument(Activity.ContentResolver!, treeUri!);
}
}
public override Task<StorageItemProperties> GetBasicPropertiesAsync()
{
return Task.FromResult(new StorageItemProperties());
DateTimeOffset? dateModified = null;
AndroidUri? queryUri = null;
try
{
try
{
// When Uri is a tree URI, use its document id to build a document URI.
var folderId = GetTreeDocumentId(Uri);
queryUri = BuildDocumentUriUsingTree(Uri, folderId);
}
catch (UnsupportedOperationException)
{
// For non-root items, Uri may already be a document URI; use it directly.
queryUri = Uri;
}
if (queryUri != null)
{
var projection = new[]
{
Document.ColumnLastModified
};
using var cursor = Activity.ContentResolver!.Query(queryUri, projection, null, null, null);
if (cursor?.MoveToFirst() == true)
{
try
{
var columnIndex = cursor.GetColumnIndex(Document.ColumnLastModified);
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, "Directory LastModified metadata reader failed: '{Exception}'", ex);
}
}
}
}
catch (Exception ex)
{
// Data may not be available for this item or the URI may not be in the expected shape.
Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?
.Log(this, "Directory basic properties metadata unavailable: '{Exception}'", ex);
}
return Task.FromResult(new StorageItemProperties(null, null, dateModified));
}
public async IAsyncEnumerable<IStorageItem> GetItemsAsync()
@ -234,8 +287,8 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
var projection = new[]
{
DocumentsContract.Document.ColumnDocumentId,
DocumentsContract.Document.ColumnMimeType
Document.ColumnDocumentId,
Document.ColumnMimeType
};
if (childrenUri != null)
{
@ -247,8 +300,8 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
var mime = cursor.GetString(1);
var id = cursor.GetString(0);
bool isDirectory = mime == DocumentsContract.Document.MimeTypeDir;
var uri = DocumentsContract.BuildDocumentUriUsingTree(root, id);
bool isDirectory = mime == Document.MimeTypeDir;
var uri = BuildDocumentUriUsingTree(root, id);
if (uri == null)
{
@ -313,9 +366,9 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
var projection = new[]
{
DocumentsContract.Document.ColumnDocumentId,
DocumentsContract.Document.ColumnMimeType,
DocumentsContract.Document.ColumnDisplayName
Document.ColumnDocumentId,
Document.ColumnMimeType,
Document.ColumnDisplayName
};
if (childrenUri != null)
@ -334,13 +387,13 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
continue;
}
bool mineDirectory = mime == DocumentsContract.Document.MimeTypeDir;
bool mineDirectory = mime == Document.MimeTypeDir;
if (isDirectory != mineDirectory)
{
return null;
}
var uri = DocumentsContract.BuildDocumentUriUsingTree(root, id);
var uri = BuildDocumentUriUsingTree(root, id);
if (uri == null)
{
return null;
@ -370,8 +423,8 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
private (AndroidUri root, AndroidUri? treeUri) GetTreeUri()
{
var root = PermissionRoot ?? Uri;
var folderId = root != Uri ? DocumentsContract.GetDocumentId(Uri) : DocumentsContract.GetTreeDocumentId(Uri);
return (root, DocumentsContract.BuildChildDocumentsUriUsingTree(root, folderId));
var folderId = root != Uri ? GetDocumentId(Uri) : GetTreeDocumentId(Uri);
return (root, BuildChildDocumentsUriUsingTree(root, folderId));
}
}
@ -419,10 +472,10 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF
if (!OperatingSystem.IsAndroidVersionAtLeast(24))
return false;
if (!DocumentsContract.IsDocumentUri(context, uri))
if (!IsDocumentUri(context, uri))
return false;
var value = GetColumnValue(context, uri, DocumentsContract.Document.ColumnFlags);
var value = GetColumnValue(context, uri, Document.ColumnFlags);
if (!string.IsNullOrEmpty(value) && int.TryParse(value, out var flagsInt))
{
var flags = (DocumentContractFlags)flagsInt;
@ -530,7 +583,7 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF
if (Activity != null)
{
DocumentsContract.DeleteDocument(Activity.ContentResolver!, Uri);
DeleteDocument(Activity.ContentResolver!, Uri);
}
}
@ -553,7 +606,7 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF
storageFolder.Uri is { } targetParentUri &&
await GetParentAsync() is AndroidStorageFolder parentFolder)
{
movedUri = DocumentsContract.MoveDocument(contentResolver, Uri, parentFolder.Uri, targetParentUri);
movedUri = MoveDocument(contentResolver, Uri, parentFolder.Uri, targetParentUri);
}
}
catch (Exception)

Loading…
Cancel
Save