Skip to content

Commit

Permalink
feat: Provide Intent access for Android pickers
Browse files Browse the repository at this point in the history
  • Loading branch information
jp-weber committed Mar 13, 2024
1 parent 8fdab6e commit 14d4923
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 1 deletion.
13 changes: 13 additions & 0 deletions doc/articles/features/windows-storage-pickers.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,19 @@ The `SuggestedStartLocation` property has no effect on certain Android devices,

The `FileSavePicker` API, which uses `ACTION_CREATE_DOCUMENT` on Android, has various limitations. To allow for the best possible compatibility across different Android versions, you should always add your file type extension to `FileTypeChoices`, and, if possible, provide only one such file type. In addition, if the `SuggestedFileName` or the user-typed file name matches an existing file, the resulting file will be renamed with `(1)` in the name, e.g., `test.txt` will become `test (1).txt` and the existing file will not be overwritten. However, if the user explicitly taps an existing file in the file browser, the system will show a dialog allowing the app to overwrite the existing file. This inconsistent behavior is caused by Android itself, so there is, unfortunately, no way to work around it from our side. See [this issue](https://issuetracker.google.com/issues/37136466) for more information.

If you want to have further influence on the pickers and, for example, create permanent access to the file for the `FileOpenPicker` (flag with GrantPersistableUriPermission), you can do this with the `FilePickerHelper`.

```csharp
FileOpenPicker fileOpenPicker = new FileOpenPicker
{
SuggestedStartLocation = PickerLocationId.ComputerFolder
};
var intent = new Android.Content.Intent(Android.Content.Intent.ActionOpenDocument);
intent.AddFlags(Android.Content.ActivityFlags.GrantPersistableUriPermission);
FilePickerHelper.RegisterOnBeforeStartActivity(fileOpenPicker, intent);
var result = await fileOpenPicker.PickSingleFileAsync();
```

## iOS

iOS does not offer a built-in `FileSavePicker` experience. Luckily, it is possible to implement this functionality, for example, using a combination of a `FolderPicker` and `ContentDialog`.
Expand Down
17 changes: 16 additions & 1 deletion src/Uno.UWP/Storage/Pickers/FileOpenPicker.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public partial class FileOpenPicker
private const string AnyWildcard = "*/*";
private const string ImageWildcard = "image/*";
private const string VideoWildcard = "video/*";
private ActivityFlags _activityFlags;

internal static bool TryHandleIntent(Intent intent, Result resultCode)
{
Expand Down Expand Up @@ -73,11 +74,22 @@ Intent GetIntent()
// apps related to Photos and Videos to be suggested on the picker.
var intent = new Intent(Intent.ActionGetContent);
intent.AddCategory(Intent.CategoryOpenable);
// additional flags are added
if (_activityFlags != 0)
{
intent.AddFlags(_activityFlags);
}

return intent;
}
var openDocumentIntent = new Intent(Intent.ActionOpenDocument);
// additional flags are added
if (_activityFlags != 0)
{
openDocumentIntent.AddFlags(_activityFlags);
}

return new Intent(Intent.ActionOpenDocument);
return openDocumentIntent;
}

var intent = GetIntent();
Expand Down Expand Up @@ -234,5 +246,8 @@ private string GetMimeType()

return mimeTypes.ToArray();
}

internal void RegisterOnBeforeStartActivity(Intent intent)
=> _activityFlags = intent.Flags;
}
}
22 changes: 22 additions & 0 deletions src/Uno.UWP/Storage/Pickers/FilePickerHelper.Android.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Android.App;
using Android.Content;

namespace Windows.Storage.Pickers
{
/// <summary>
/// Enables the user to extend the flags of the used intent
/// </summary>
public static class FilePickerHelper
{
public static void RegisterOnBeforeStartActivity(FileOpenPicker picker, Intent intent)
=> picker.RegisterOnBeforeStartActivity(intent);

public static void RegisterOnBeforeStartActivity(FileSavePicker picker, Intent intent)
=> picker.RegisterOnBeforeStartActivity(intent);
}
}
9 changes: 9 additions & 0 deletions src/Uno.UWP/Storage/Pickers/FileSavePicker.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public partial class FileSavePicker
{
private const string XmlCorrectMimeToActionCreateDocument = "application/xhtml+xml";
private const string XmlIncorrectMimeToActionCreateDocument = "application/xml";
private ActivityFlags _activityFlags;

private async Task<StorageFile?> PickSaveFileTaskAsync(CancellationToken token)
{
Expand All @@ -30,6 +31,11 @@ public partial class FileSavePicker

var intent = new Intent(action);
intent.AddCategory(Intent.CategoryOpenable);
// additional flags are added
if (_activityFlags != 0)
{
intent.AddFlags(_activityFlags);
}
var mimeTypes = GetMimeTypes();
this.AdjustInvalidMimeTypes(mimeTypes);

Expand Down Expand Up @@ -109,4 +115,7 @@ private string[] GetMimeTypes()
AdjustInvalidMimeTypes(mimes);
return mimes ?? Array.Empty<string>();
}

internal void RegisterOnBeforeStartActivity(Intent intent)
=> _activityFlags = intent.Flags;
}

0 comments on commit 14d4923

Please sign in to comment.