Skip to content
This repository has been archived by the owner on May 15, 2024. It is now read-only.

Rework the "picker" results to correctly manage files #1555

Merged
merged 4 commits into from
Dec 2, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions Samples/Samples.Android/Properties/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,35 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<queries>
<!-- Email -->
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
<!-- Browser -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
</intent>
<!-- Browser -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<!-- Sms -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="smsto" />
</intent>
<!-- PhoneDialer -->
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<!-- MediaPicker -->
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be added to documentation :)

<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
Expand Down
5 changes: 3 additions & 2 deletions Samples/Samples/ViewModel/ShareViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System.Collections.Generic;
using System.IO;
using System.Windows.Input;
using Samples.Helpers;
using Xamarin.Essentials;
Expand Down Expand Up @@ -157,7 +158,7 @@ async void OnFilesRequest(Xamarin.Forms.View element)
await Share.RequestAsync(new ShareMultipleFilesRequest
{
Title = ShareFilesTitle,
Files = new ShareFile[] { new ShareFile(file1), new ShareFile(file2) },
Files = new List<ShareFile> { new ShareFile(file1), new ShareFile(file2) },
PresentationSourceBounds = GetRectangle(element)
});
}
Expand Down
21 changes: 21 additions & 0 deletions Tests/FileSystem_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,26 @@ public async Task OpenAppPackageFileAsync_Fail_On_NetStandard()
{
await Assert.ThrowsAsync<NotImplementedInReferenceAssemblyException>(() => FileSystem.OpenAppPackageFileAsync("filename.txt"));
}

[Theory]
[InlineData(null, "")]
[InlineData("", "")]
[InlineData(".", ".")]
[InlineData(".txt", ".txt")]
[InlineData("*.txt", ".txt")]
[InlineData("*.*", ".*")]
[InlineData("txt", ".txt")]
[InlineData("test.txt", ".test.txt")]
[InlineData("test.", ".test.")]
[InlineData("....txt", ".txt")]
[InlineData("******txt", ".txt")]
[InlineData("******.txt", ".txt")]
[InlineData("******.......txt", ".txt")]
public void Extensions_Clean_Correctly_Cleans_Extensions(string input, string output)
{
var cleaned = FileSystem.Extensions.Clean(input);

Assert.Equal(output, cleaned);
}
}
}
2 changes: 1 addition & 1 deletion Xamarin.Essentials/Email/Email.android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static Intent CreateIntent(EmailMessage message)
if (action == Intent.ActionSendto)
intent.SetData(Uri.Parse("mailto:"));
else
intent.SetType("message/rfc822");
intent.SetType(FileSystem.MimeTypes.EmailMessage);

if (!string.IsNullOrEmpty(message?.Body))
{
Expand Down
48 changes: 26 additions & 22 deletions Xamarin.Essentials/FilePicker/FilePicker.android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Provider;

namespace Xamarin.Essentials
{
Expand All @@ -22,7 +19,7 @@ static async Task<IEnumerable<FileResult>> PlatformPickAsync(PickOptions options
var action = Intent.ActionOpenDocument;

var intent = new Intent(action);
intent.SetType("*/*");
intent.SetType(FileSystem.MimeTypes.All);
intent.PutExtra(Intent.ExtraAllowMultiple, allowMultiple);

var allowedTypes = options?.FileTypes?.Value?.ToArray();
Expand All @@ -33,23 +30,30 @@ static async Task<IEnumerable<FileResult>> PlatformPickAsync(PickOptions options

try
{
var result = await IntermediateActivity.StartAsync(pickerIntent, Platform.requestCodeFilePicker);
var resultList = new List<FileResult>();

var clipData = new List<global::Android.Net.Uri>();

if (result.ClipData == null)
void OnResult(Intent intent)
{
clipData.Add(result.Data);
}
else
{
for (var i = 0; i < result.ClipData.ItemCount; i++)
clipData.Add(result.ClipData.GetItemAt(i).Uri);
// The uri returned is only temporary and only lives as long as the Activity that requested it,
// so this means that it will always be cleaned up by the time we need it because we are using
// an intermediate activity.

if (intent.ClipData == null)
{
var path = FileSystem.EnsurePhysicalPath(intent.Data);
resultList.Add(new FileResult(path));
}
else
{
for (var i = 0; i < intent.ClipData.ItemCount; i++)
{
var uri = intent.ClipData.GetItemAt(i).Uri;
var path = FileSystem.EnsurePhysicalPath(uri);
resultList.Add(new FileResult(path));
}
}
}

foreach (var contentUri in clipData)
resultList.Add(new FileResult(contentUri));
await IntermediateActivity.StartAsync(pickerIntent, Platform.requestCodeFilePicker, onResult: OnResult);

return resultList;
}
Expand All @@ -65,31 +69,31 @@ public partial class FilePickerFileType
static FilePickerFileType PlatformImageFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.Android, new[] { "image/png", "image/jpeg" } }
{ DevicePlatform.Android, new[] { FileSystem.MimeTypes.ImagePng, FileSystem.MimeTypes.ImageJpg } }
});

static FilePickerFileType PlatformPngFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.Android, new[] { "image/png" } }
{ DevicePlatform.Android, new[] { FileSystem.MimeTypes.ImagePng } }
});

static FilePickerFileType PlatformJpegFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.Android, new[] { "image/jpeg" } }
{ DevicePlatform.Android, new[] { FileSystem.MimeTypes.ImageJpg } }
});

static FilePickerFileType PlatformVideoFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.Android, new[] { "video/*" } }
{ DevicePlatform.Android, new[] { FileSystem.MimeTypes.VideoAll } }
});

static FilePickerFileType PlatformPdfFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.Android, new[] { "application/pdf" } }
{ DevicePlatform.Android, new[] { FileSystem.MimeTypes.Pdf } }
});
}
}
12 changes: 4 additions & 8 deletions Xamarin.Essentials/FilePicker/FilePicker.ios.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ static Task<IEnumerable<FileResult>> PlatformPickAsync(PickOptions options, bool
{
try
{
// there was a cancellation
tcs.TrySetResult(GetFileResults(urls));
}
catch (Exception ex)
Expand Down Expand Up @@ -72,13 +71,10 @@ static Task<IEnumerable<FileResult>> PlatformPickAsync(PickOptions options, bool
return tcs.Task;
}

static IEnumerable<FileResult> GetFileResults(NSUrl[] urls)
{
if (urls?.Length > 0)
return urls.Select(url => new UIDocumentFileResult(url));
else
return Enumerable.Empty<FileResult>();
}
static IEnumerable<FileResult> GetFileResults(NSUrl[] urls) =>
urls?.Length > 0
? urls.Select(url => new UIDocumentFileResult(url))
: Enumerable.Empty<FileResult>();

class PickerDelegate : UIDocumentPickerDelegate
{
Expand Down
12 changes: 6 additions & 6 deletions Xamarin.Essentials/FilePicker/FilePicker.tizen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ static async Task<IEnumerable<FileResult>> PlatformPickAsync(PickOptions options
appControl.LaunchMode = AppControlLaunchMode.Single;

var fileType = options?.FileTypes?.Value?.FirstOrDefault();
appControl.Mime = fileType ?? "*/*";
appControl.Mime = fileType ?? FileSystem.MimeTypes.All;

var fileResults = new List<FileResult>();

Expand All @@ -51,31 +51,31 @@ public partial class FilePickerFileType
static FilePickerFileType PlatformImageFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.Tizen, new[] { "image/*" } },
{ DevicePlatform.Tizen, new[] { FileSystem.MimeTypes.ImageAll } },
});

static FilePickerFileType PlatformPngFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.Tizen, new[] { "image/png" } }
{ DevicePlatform.Tizen, new[] { FileSystem.MimeTypes.ImagePng } }
});

static FilePickerFileType PlatformJpegFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.Tizen, new[] { "image/jpeg" } }
{ DevicePlatform.Tizen, new[] { FileSystem.MimeTypes.ImageJpg } }
});

static FilePickerFileType PlatformVideoFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.Tizen, new[] { "video/*" } }
{ DevicePlatform.Tizen, new[] { FileSystem.MimeTypes.VideoAll } }
});

static FilePickerFileType PlatformPdfFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.Tizen, new[] { "application/pdf" } }
{ DevicePlatform.Tizen, new[] { FileSystem.MimeTypes.Pdf } }
});
}
}
15 changes: 8 additions & 7 deletions Xamarin.Essentials/FilePicker/FilePicker.uwp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ static void SetFileTypes(PickOptions options, FileOpenPicker picker)
{
foreach (var type in options.FileTypes.Value)
{
if (type.StartsWith(".") || type.StartsWith("*."))
var ext = FileSystem.Extensions.Clean(type);
if (!string.IsNullOrWhiteSpace(ext))
{
picker.FileTypeFilter.Add(type.TrimStart('*'));
picker.FileTypeFilter.Add(ext);
hasAtLeastOneType = true;
}
}
Expand All @@ -67,31 +68,31 @@ public partial class FilePickerFileType
static FilePickerFileType PlatformImageFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.UWP, new[] { "*.png", "*.jpg", "*.jpeg", "*.gif", "*.bmp" } }
{ DevicePlatform.UWP, FileSystem.Extensions.AllImage }
});

static FilePickerFileType PlatformPngFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.UWP, new[] { "*.png" } }
{ DevicePlatform.UWP, new[] { FileSystem.Extensions.Png } }
});

static FilePickerFileType PlatformJpegFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.UWP, new[] { "*.jpg", "*.jpeg" } }
{ DevicePlatform.UWP, FileSystem.Extensions.AllJpeg }
});

static FilePickerFileType PlatformVideoFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.UWP, new[] { "*.mp4", "*.mov", "*.avi", "*.wmv", "*.m4v", "*.mpg", "*.mpeg", "*.mp2", "*.mkv", "*.flv", "*.gifv", "*.qt" } }
{ DevicePlatform.UWP, FileSystem.Extensions.AllVideo }
});

static FilePickerFileType PlatformPdfFileType() =>
new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.UWP, new[] { "*.pdf" } }
{ DevicePlatform.UWP, new[] { FileSystem.Extensions.Pdf } }
});
}
}
Loading