From aa035033e98af09c0d2d9b88c31efc254545dd09 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Tue, 1 Dec 2020 15:51:23 +0200 Subject: [PATCH] Extract magic strings into constants - Mime types - Extensions - Changed property type of ShareMultipleFilesRequest.Files to be a List for consistency --- Tests/FileSystem_Tests.cs | 21 ++++++ Xamarin.Essentials/Email/Email.android.cs | 2 +- .../FilePicker/FilePicker.android.cs | 12 ++-- .../FilePicker/FilePicker.ios.cs | 15 ++-- .../FilePicker/FilePicker.tizen.cs | 12 ++-- .../FilePicker/FilePicker.uwp.cs | 15 ++-- .../FileSystem/FileSystem.android.cs | 58 +++++++++------ .../FileSystem/FileSystem.ios.cs | 2 +- .../FileSystem/FileSystem.shared.cs | 71 ++++++++++++++++++- Xamarin.Essentials/Launcher/Launcher.tizen.cs | 2 +- .../MediaPicker/MediaPicker.android.cs | 6 +- Xamarin.Essentials/Share/Share.android.cs | 7 +- Xamarin.Essentials/Share/Share.shared.cs | 5 +- Xamarin.Essentials/Sms/Sms.android.cs | 2 +- 14 files changed, 170 insertions(+), 60 deletions(-) diff --git a/Tests/FileSystem_Tests.cs b/Tests/FileSystem_Tests.cs index 5851f66b7..f88e3460e 100644 --- a/Tests/FileSystem_Tests.cs +++ b/Tests/FileSystem_Tests.cs @@ -17,5 +17,26 @@ public async Task OpenAppPackageFileAsync_Fail_On_NetStandard() { await Assert.ThrowsAsync(() => 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); + } } } diff --git a/Xamarin.Essentials/Email/Email.android.cs b/Xamarin.Essentials/Email/Email.android.cs index 23cb0f792..be96d1e48 100644 --- a/Xamarin.Essentials/Email/Email.android.cs +++ b/Xamarin.Essentials/Email/Email.android.cs @@ -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)) { diff --git a/Xamarin.Essentials/FilePicker/FilePicker.android.cs b/Xamarin.Essentials/FilePicker/FilePicker.android.cs index d63ace555..dc83fc0ca 100644 --- a/Xamarin.Essentials/FilePicker/FilePicker.android.cs +++ b/Xamarin.Essentials/FilePicker/FilePicker.android.cs @@ -19,7 +19,7 @@ static async Task> 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(); @@ -69,31 +69,31 @@ public partial class FilePickerFileType static FilePickerFileType PlatformImageFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.Android, new[] { "image/png", "image/jpeg" } } + { DevicePlatform.Android, new[] { FileSystem.MimeTypes.ImagePng, FileSystem.MimeTypes.ImageJpg } } }); static FilePickerFileType PlatformPngFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.Android, new[] { "image/png" } } + { DevicePlatform.Android, new[] { FileSystem.MimeTypes.ImagePng } } }); static FilePickerFileType PlatformJpegFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.Android, new[] { "image/jpeg" } } + { DevicePlatform.Android, new[] { FileSystem.MimeTypes.ImageJpg } } }); static FilePickerFileType PlatformVideoFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.Android, new[] { "video/*" } } + { DevicePlatform.Android, new[] { FileSystem.MimeTypes.VideoAll } } }); static FilePickerFileType PlatformPdfFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.Android, new[] { "application/pdf" } } + { DevicePlatform.Android, new[] { FileSystem.MimeTypes.Pdf } } }); } } diff --git a/Xamarin.Essentials/FilePicker/FilePicker.ios.cs b/Xamarin.Essentials/FilePicker/FilePicker.ios.cs index 1df5787a7..ddbb5af68 100644 --- a/Xamarin.Essentials/FilePicker/FilePicker.ios.cs +++ b/Xamarin.Essentials/FilePicker/FilePicker.ios.cs @@ -34,11 +34,7 @@ static Task> PlatformPickAsync(PickOptions options, bool { try { - // there was a cancellation - if (urls?.Any() ?? false) - tcs.TrySetResult(urls.Select(url => new UIDocumentFileResult(url))); - else - tcs.TrySetResult(Enumerable.Empty()); + tcs.TrySetResult(GetFiles(urls)); } catch (Exception ex) { @@ -63,9 +59,14 @@ static Task> PlatformPickAsync(PickOptions options, bool return tcs.Task; } + static IEnumerable GetFiles(NSUrl[] urls) => + urls?.Length > 0 + ? urls.Select(url => new UIDocumentFileResult(url)) + : Enumerable.Empty(); + class PickerDelegate : UIDocumentPickerDelegate { - public Action> PickHandler { get; set; } + public Action PickHandler { get; set; } public override void WasCancelled(UIDocumentPickerViewController controller) => PickHandler?.Invoke(null); @@ -74,7 +75,7 @@ public override void DidPickDocument(UIDocumentPickerViewController controller, => PickHandler?.Invoke(urls); public override void DidPickDocument(UIDocumentPickerViewController controller, NSUrl url) - => PickHandler?.Invoke(new List { url }); + => PickHandler?.Invoke(new NSUrl[] { url }); } class PickerPresentationControllerDelegate : UIAdaptivePresentationControllerDelegate diff --git a/Xamarin.Essentials/FilePicker/FilePicker.tizen.cs b/Xamarin.Essentials/FilePicker/FilePicker.tizen.cs index 0b444805b..e68439f92 100644 --- a/Xamarin.Essentials/FilePicker/FilePicker.tizen.cs +++ b/Xamarin.Essentials/FilePicker/FilePicker.tizen.cs @@ -24,7 +24,7 @@ static async Task> 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(); @@ -51,31 +51,31 @@ public partial class FilePickerFileType static FilePickerFileType PlatformImageFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.Tizen, new[] { "image/*" } }, + { DevicePlatform.Tizen, new[] { FileSystem.MimeTypes.ImageAll } }, }); static FilePickerFileType PlatformPngFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.Tizen, new[] { "image/png" } } + { DevicePlatform.Tizen, new[] { FileSystem.MimeTypes.ImagePng } } }); static FilePickerFileType PlatformJpegFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.Tizen, new[] { "image/jpeg" } } + { DevicePlatform.Tizen, new[] { FileSystem.MimeTypes.ImageJpg } } }); static FilePickerFileType PlatformVideoFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.Tizen, new[] { "video/*" } } + { DevicePlatform.Tizen, new[] { FileSystem.MimeTypes.VideoAll } } }); static FilePickerFileType PlatformPdfFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.Tizen, new[] { "application/pdf" } } + { DevicePlatform.Tizen, new[] { FileSystem.MimeTypes.Pdf } } }); } } diff --git a/Xamarin.Essentials/FilePicker/FilePicker.uwp.cs b/Xamarin.Essentials/FilePicker/FilePicker.uwp.cs index 3e8653f30..ae440472e 100644 --- a/Xamarin.Essentials/FilePicker/FilePicker.uwp.cs +++ b/Xamarin.Essentials/FilePicker/FilePicker.uwp.cs @@ -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; } } @@ -67,31 +68,31 @@ public partial class FilePickerFileType static FilePickerFileType PlatformImageFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.UWP, new[] { "*.png", "*.jpg", "*.jpeg", "*.gif", "*.bmp" } } + { DevicePlatform.UWP, FileSystem.Extensions.AllImage } }); static FilePickerFileType PlatformPngFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.UWP, new[] { "*.png" } } + { DevicePlatform.UWP, new[] { FileSystem.Extensions.Png } } }); static FilePickerFileType PlatformJpegFileType() => new FilePickerFileType(new Dictionary> { - { DevicePlatform.UWP, new[] { "*.jpg", "*.jpeg" } } + { DevicePlatform.UWP, FileSystem.Extensions.AllJpeg } }); static FilePickerFileType PlatformVideoFileType() => new FilePickerFileType(new Dictionary> { - { 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.UWP, new[] { "*.pdf" } } + { DevicePlatform.UWP, new[] { FileSystem.Extensions.Pdf } } }); } } diff --git a/Xamarin.Essentials/FileSystem/FileSystem.android.cs b/Xamarin.Essentials/FileSystem/FileSystem.android.cs index 55acb3bf4..e771a2ac7 100644 --- a/Xamarin.Essentials/FileSystem/FileSystem.android.cs +++ b/Xamarin.Essentials/FileSystem/FileSystem.android.cs @@ -10,6 +10,27 @@ namespace Xamarin.Essentials { public partial class FileSystem { + internal const string EssentialsFolderHash = "2203693cc04e0be7f4f024d5f9499e13"; + + const string storageTypePrimary = "primary"; + const string storageTypeRaw = "raw"; + const string storageTypeImage = "image"; + const string storageTypeVideo = "video"; + const string storageTypeAudio = "audio"; + static readonly string[] contentUriPrefixes = + { + "content://downloads/public_downloads", + "content://downloads/my_downloads", + "content://downloads/all_downloads", + }; + + internal const string UriSchemeFile = "file"; + internal const string UriSchemeContent = "content"; + + internal const string UriAuthorityExternalStorage = "com.android.externalstorage.documents"; + internal const string UriAuthorityDownloads = "com.android.providers.downloads.documents"; + internal const string UriAuthorityMedia = "com.android.providers.media.documents"; + static string PlatformCacheDirectory => Platform.AppContext.CacheDir.AbsolutePath; @@ -35,7 +56,7 @@ static Task PlatformOpenAppPackageFileAsync(string filename) internal static Java.IO.File GetEssentialsTemporaryFile(Java.IO.File root, string fileName) { // create the directory for all Essentials files - var rootDir = new Java.IO.File(root, "2203693cc04e0be7f4f024d5f9499e13"); + var rootDir = new Java.IO.File(root, EssentialsFolderHash); rootDir.Mkdirs(); rootDir.DeleteOnExit(); @@ -54,7 +75,7 @@ internal static Java.IO.File GetEssentialsTemporaryFile(Java.IO.File root, strin internal static string EnsurePhysicalPath(AndroidUri uri) { // if this is a file, use that - if (uri.Scheme.Equals("file", StringComparison.OrdinalIgnoreCase)) + if (uri.Scheme.Equals(UriSchemeFile, StringComparison.OrdinalIgnoreCase)) return uri.Path; // try resolve using the content provider @@ -79,13 +100,13 @@ static string ResolvePhysicalPath(AndroidUri uri) return resolved; } - if (uri.Scheme.Equals("content", StringComparison.OrdinalIgnoreCase)) + if (uri.Scheme.Equals(UriSchemeContent, StringComparison.OrdinalIgnoreCase)) { var resolved = ResolveContentPath(uri); if (File.Exists(resolved)) return resolved; } - else if (uri.Scheme.Equals("file", StringComparison.OrdinalIgnoreCase)) + else if (uri.Scheme.Equals(UriSchemeFile, StringComparison.OrdinalIgnoreCase)) { var resolved = uri.Path; if (File.Exists(resolved)) @@ -105,7 +126,7 @@ static string ResolveDocumentPath(AndroidUri uri) if (docIdParts == null || docIdParts.Length == 0) return null; - if (uri.Authority.Equals("com.android.externalstorage.documents", StringComparison.OrdinalIgnoreCase)) + if (uri.Authority.Equals(UriAuthorityExternalStorage, StringComparison.OrdinalIgnoreCase)) { Debug.WriteLine($"Resolving external storage URI: '{uri}'"); @@ -115,7 +136,7 @@ static string ResolveDocumentPath(AndroidUri uri) var uriPath = docIdParts[1]; // This is the internal "external" memory, NOT the SD Card - if (storageType.Equals("primary", StringComparison.OrdinalIgnoreCase)) + if (storageType.Equals(storageTypePrimary, StringComparison.OrdinalIgnoreCase)) { #pragma warning disable CS0618 // Type or member is obsolete var root = global::Android.OS.Environment.ExternalStorageDirectory.Path; @@ -127,7 +148,7 @@ static string ResolveDocumentPath(AndroidUri uri) // TODO: support other types, such as actual SD Cards } } - else if (uri.Authority.Equals("com.android.providers.downloads.documents", StringComparison.OrdinalIgnoreCase)) + else if (uri.Authority.Equals(UriAuthorityDownloads, StringComparison.OrdinalIgnoreCase)) { Debug.WriteLine($"Resolving downloads URI: '{uri}'"); @@ -138,17 +159,10 @@ static string ResolveDocumentPath(AndroidUri uri) var storageType = docIdParts[0]; var uriPath = docIdParts[1]; - if (storageType.Equals("raw", StringComparison.OrdinalIgnoreCase)) + if (storageType.Equals(storageTypeRaw, StringComparison.OrdinalIgnoreCase)) return uriPath; } - var contentUriPrefixes = new[] - { - "content://downloads/public_downloads", - "content://downloads/my_downloads", - "content://downloads/all_downloads", - }; - // ID could be "###" or "msf:###" var fileId = docIdParts.Length == 2 ? docIdParts[1] @@ -163,7 +177,7 @@ static string ResolveDocumentPath(AndroidUri uri) return filePath; } } - else if (uri.Authority.Equals("com.android.providers.media.documents", StringComparison.OrdinalIgnoreCase)) + else if (uri.Authority.Equals(UriAuthorityMedia, StringComparison.OrdinalIgnoreCase)) { Debug.WriteLine($"Resolving media URI: '{uri}'"); @@ -173,14 +187,14 @@ static string ResolveDocumentPath(AndroidUri uri) var uriPath = docIdParts[1]; AndroidUri contentUri = null; - if (storageType.Equals("image", StringComparison.OrdinalIgnoreCase)) + if (storageType.Equals(storageTypeImage, StringComparison.OrdinalIgnoreCase)) contentUri = MediaStore.Images.Media.ExternalContentUri; - else if (storageType.Equals("video", StringComparison.OrdinalIgnoreCase)) + else if (storageType.Equals(storageTypeVideo, StringComparison.OrdinalIgnoreCase)) contentUri = MediaStore.Video.Media.ExternalContentUri; - else if (storageType.Equals("audio", StringComparison.OrdinalIgnoreCase)) + else if (storageType.Equals(storageTypeAudio, StringComparison.OrdinalIgnoreCase)) contentUri = MediaStore.Audio.Media.ExternalContentUri; - if (contentUri != null && GetDataFilePath(contentUri, "_id=?", new[] { uriPath }) is string filePath) + if (contentUri != null && GetDataFilePath(contentUri, $"{MediaStore.MediaColumns.Id}=?", new[] { uriPath }) is string filePath) return filePath; } } @@ -206,7 +220,7 @@ static string ResolveContentPath(AndroidUri uri) static string CacheContentFile(AndroidUri uri) { - if (!uri.Scheme.Equals("content", StringComparison.OrdinalIgnoreCase)) + if (!uri.Scheme.Equals(UriSchemeContent, StringComparison.OrdinalIgnoreCase)) return null; Debug.WriteLine($"Copying content URI to local cache: '{uri}'"); @@ -261,7 +275,7 @@ static bool IsVirtualFile(AndroidUri uri) static Stream GetVirtualFileStream(AndroidUri uri, out string extension) { - var mimeTypes = Platform.ContentResolver.GetStreamTypes(uri, "*/*"); + var mimeTypes = Platform.ContentResolver.GetStreamTypes(uri, FileSystem.MimeTypes.All); if (mimeTypes?.Length >= 1) { var mimeType = mimeTypes[0]; diff --git a/Xamarin.Essentials/FileSystem/FileSystem.ios.cs b/Xamarin.Essentials/FileSystem/FileSystem.ios.cs index f88dcb849..cd53f0d8b 100644 --- a/Xamarin.Essentials/FileSystem/FileSystem.ios.cs +++ b/Xamarin.Essentials/FileSystem/FileSystem.ios.cs @@ -45,7 +45,7 @@ internal UIImageFileResult(UIImage image) { uiImage = image; - FullPath = Guid.NewGuid().ToString() + ".png"; + FullPath = Guid.NewGuid().ToString() + FileSystem.Extensions.Png; FileName = FullPath; } diff --git a/Xamarin.Essentials/FileSystem/FileSystem.shared.cs b/Xamarin.Essentials/FileSystem/FileSystem.shared.cs index 6e6c4c4ab..ad0106dd6 100644 --- a/Xamarin.Essentials/FileSystem/FileSystem.shared.cs +++ b/Xamarin.Essentials/FileSystem/FileSystem.shared.cs @@ -14,11 +14,77 @@ public static string AppDataDirectory public static Task OpenAppPackageFileAsync(string filename) => PlatformOpenAppPackageFileAsync(filename); + + internal static class MimeTypes + { + internal const string All = "*/*"; + + internal const string ImageAll = "image/*"; + internal const string ImagePng = "image/png"; + internal const string ImageJpg = "image/jpeg"; + + internal const string VideoAll = "video/*"; + + internal const string EmailMessage = "message/rfc822"; + + internal const string Pdf = "application/pdf"; + + internal const string TextPlain = "text/plain"; + + internal const string OctetStream = "application/octet-stream"; + } + + internal static class Extensions + { + internal const string Png = ".png"; + internal const string Jpg = ".jpg"; + internal const string Jpeg = ".jpeg"; + internal const string Gif = ".gif"; + internal const string Bmp = ".bmp"; + + internal const string Avi = ".avi"; + internal const string Flv = ".flv"; + internal const string Gifv = ".gifv"; + internal const string Mp4 = ".mp4"; + internal const string M4v = ".m4v"; + internal const string Mpg = ".mpg"; + internal const string Mpeg = ".mpeg"; + internal const string Mp2 = ".mp2"; + internal const string Mkv = ".mkv"; + internal const string Mov = ".mov"; + internal const string Qt = ".qt"; + internal const string Wmv = ".wmv"; + + internal const string Pdf = ".pdf"; + + internal static string[] AllImage => + new[] { Png, Jpg, Jpeg, Gif, Bmp }; + + internal static string[] AllJpeg => + new[] { Jpg, Jpeg }; + + internal static string[] AllVideo => + new[] { Mp4, Mov, Avi, Wmv, M4v, Mpg, Mpeg, Mp2, Mkv, Flv, Gifv, Qt }; + + internal static string Clean(string extension, bool trimLeadingPeriod = false) + { + if (string.IsNullOrWhiteSpace(extension)) + return string.Empty; + + extension = extension.TrimStart('*'); + extension = extension.TrimStart('.'); + + if (!trimLeadingPeriod) + extension = "." + extension; + + return extension; + } + } } public abstract partial class FileBase { - internal const string DefaultContentType = "application/octet-stream"; + internal const string DefaultContentType = FileSystem.MimeTypes.OctetStream; string contentType; @@ -76,7 +142,8 @@ internal string GetContentType() if (!string.IsNullOrWhiteSpace(content)) return content; } - return "application/octet-stream"; + + return DefaultContentType; } string fileName; diff --git a/Xamarin.Essentials/Launcher/Launcher.tizen.cs b/Xamarin.Essentials/Launcher/Launcher.tizen.cs index ccaa0ee79..f66f43a0f 100644 --- a/Xamarin.Essentials/Launcher/Launcher.tizen.cs +++ b/Xamarin.Essentials/Launcher/Launcher.tizen.cs @@ -45,7 +45,7 @@ static Task PlatformOpenAsync(OpenFileRequest request) var appControl = new AppControl { Operation = AppControlOperations.View, - Mime = "*/*", + Mime = FileSystem.MimeTypes.All, Uri = "file://" + request.File.FullPath, }; diff --git a/Xamarin.Essentials/MediaPicker/MediaPicker.android.cs b/Xamarin.Essentials/MediaPicker/MediaPicker.android.cs index cbf765e09..76e51ab15 100644 --- a/Xamarin.Essentials/MediaPicker/MediaPicker.android.cs +++ b/Xamarin.Essentials/MediaPicker/MediaPicker.android.cs @@ -25,7 +25,7 @@ static async Task PlatformPickAsync(MediaPickerOptions options, bool await Permissions.RequestAsync(); var intent = new Intent(Intent.ActionGetContent); - intent.SetType(photo ? "image/*" : "video/*"); + intent.SetType(photo ? FileSystem.MimeTypes.ImageAll : FileSystem.MimeTypes.VideoAll); var pickerIntent = Intent.CreateChooser(intent, options?.Title); @@ -75,7 +75,9 @@ static async Task PlatformCaptureAsync(MediaPickerOptions options, b var activity = Platform.GetCurrentActivity(true); // Create the temporary file - var ext = photo ? ".jpg" : ".mp4"; + var ext = photo + ? FileSystem.Extensions.Jpg + : FileSystem.Extensions.Mp4; var fileName = Guid.NewGuid().ToString("N") + ext; var tmpFile = FileSystem.GetEssentialsTemporaryFile(Platform.AppContext.CacheDir, fileName); diff --git a/Xamarin.Essentials/Share/Share.android.cs b/Xamarin.Essentials/Share/Share.android.cs index afc95bcc1..1c0d9641d 100644 --- a/Xamarin.Essentials/Share/Share.android.cs +++ b/Xamarin.Essentials/Share/Share.android.cs @@ -23,7 +23,7 @@ static Task PlatformRequestAsync(ShareTextRequest request) } var intent = new Intent(Intent.ActionSend); - intent.SetType("text/plain"); + intent.SetType(FileSystem.MimeTypes.TextPlain); intent.PutExtra(Intent.ExtraText, string.Join(System.Environment.NewLine, items)); if (!string.IsNullOrWhiteSpace(request.Subject)) @@ -46,7 +46,10 @@ static Task PlatformRequestAsync(ShareMultipleFilesRequest request) foreach (var file in request.Files) contentUris.Add(Platform.GetShareableFileUri(file)); - intent.SetType(request.Files.Count() > 1 ? "*/*" : request.Files.FirstOrDefault().ContentType); + var type = request.Files.Count > 1 + ? FileSystem.MimeTypes.All + : request.Files.FirstOrDefault().ContentType; + intent.SetType(type); intent.SetFlags(ActivityFlags.GrantReadUriPermission); intent.PutParcelableArrayListExtra(Intent.ExtraStream, contentUris); diff --git a/Xamarin.Essentials/Share/Share.shared.cs b/Xamarin.Essentials/Share/Share.shared.cs index a264401d6..ab6fc5ba3 100644 --- a/Xamarin.Essentials/Share/Share.shared.cs +++ b/Xamarin.Essentials/Share/Share.shared.cs @@ -116,7 +116,8 @@ public ShareMultipleFilesRequest() { } - public ShareMultipleFilesRequest(IEnumerable files) => Files = files; + public ShareMultipleFilesRequest(IEnumerable files) => + Files = files.ToList(); public ShareMultipleFilesRequest(IEnumerable files) : this(ConvertList(files)) @@ -131,7 +132,7 @@ public ShareMultipleFilesRequest(string title, IEnumerable files) { } - public IEnumerable Files { get; set; } + public List Files { get; set; } public static explicit operator ShareMultipleFilesRequest(ShareFileRequest request) { diff --git a/Xamarin.Essentials/Sms/Sms.android.cs b/Xamarin.Essentials/Sms/Sms.android.cs index f0667c1b7..966619772 100644 --- a/Xamarin.Essentials/Sms/Sms.android.cs +++ b/Xamarin.Essentials/Sms/Sms.android.cs @@ -44,7 +44,7 @@ static Intent CreateIntent(string body, List recipients) if (!string.IsNullOrWhiteSpace(packageName)) { intent = new Intent(Intent.ActionSend); - intent.SetType("text/plain"); + intent.SetType(FileSystem.MimeTypes.TextPlain); intent.PutExtra(Intent.ExtraText, body); intent.SetPackage(packageName);