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

Commit

Permalink
Extract magic strings into constants
Browse files Browse the repository at this point in the history
- Mime types
- Extensions
- Changed property type of ShareMultipleFilesRequest.Files to be a List<T> for consistency
  • Loading branch information
mattleibow committed Dec 1, 2020
1 parent 4e3d487 commit aa03503
Show file tree
Hide file tree
Showing 14 changed files with 170 additions and 60 deletions.
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
12 changes: 6 additions & 6 deletions Xamarin.Essentials/FilePicker/FilePicker.android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,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 Down Expand Up @@ -69,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 } }
});
}
}
15 changes: 8 additions & 7 deletions Xamarin.Essentials/FilePicker/FilePicker.ios.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,7 @@ static Task<IEnumerable<FileResult>> 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<FileResult>());
tcs.TrySetResult(GetFiles(urls));
}
catch (Exception ex)
{
Expand All @@ -63,9 +59,14 @@ static Task<IEnumerable<FileResult>> PlatformPickAsync(PickOptions options, bool
return tcs.Task;
}

static IEnumerable<FileResult> GetFiles(NSUrl[] urls) =>
urls?.Length > 0
? urls.Select(url => new UIDocumentFileResult(url))
: Enumerable.Empty<FileResult>();

class PickerDelegate : UIDocumentPickerDelegate
{
public Action<IEnumerable<NSUrl>> PickHandler { get; set; }
public Action<NSUrl[]> PickHandler { get; set; }

public override void WasCancelled(UIDocumentPickerViewController controller)
=> PickHandler?.Invoke(null);
Expand All @@ -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<NSUrl> { url });
=> PickHandler?.Invoke(new NSUrl[] { url });
}

class PickerPresentationControllerDelegate : UIAdaptivePresentationControllerDelegate
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 } }
});
}
}
58 changes: 36 additions & 22 deletions Xamarin.Essentials/FileSystem/FileSystem.android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -35,7 +56,7 @@ static Task<Stream> 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();

Expand All @@ -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
Expand All @@ -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))
Expand All @@ -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}'");

Expand All @@ -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;
Expand All @@ -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}'");

Expand All @@ -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]
Expand All @@ -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}'");

Expand All @@ -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;
}
}
Expand All @@ -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}'");
Expand Down Expand Up @@ -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];
Expand Down
2 changes: 1 addition & 1 deletion Xamarin.Essentials/FileSystem/FileSystem.ios.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ internal UIImageFileResult(UIImage image)
{
uiImage = image;

FullPath = Guid.NewGuid().ToString() + ".png";
FullPath = Guid.NewGuid().ToString() + FileSystem.Extensions.Png;
FileName = FullPath;
}

Expand Down
Loading

0 comments on commit aa03503

Please sign in to comment.