diff --git a/src/Core/src/PublicAPI/net-android/PublicAPI.Shipped.txt b/src/Core/src/PublicAPI/net-android/PublicAPI.Shipped.txt index 226d36e0fbd4..fb2a9618b044 100644 --- a/src/Core/src/PublicAPI/net-android/PublicAPI.Shipped.txt +++ b/src/Core/src/PublicAPI/net-android/PublicAPI.Shipped.txt @@ -3161,7 +3161,6 @@ virtual Microsoft.Maui.Handlers.ViewHandler.Connect virtual Microsoft.Maui.Handlers.ViewHandler.DisconnectHandler(TPlatformView! platformView) -> void virtual Microsoft.Maui.Handlers.ViewHandler.SetVirtualView(Microsoft.Maui.IView! view) -> void virtual Microsoft.Maui.ImageSourceService.LoadDrawableAsync(Microsoft.Maui.IImageSource! imageSource, Android.Widget.ImageView! imageView, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! -virtual Microsoft.Maui.MauiAppCompatActivity.AllowFragmentRestore.get -> bool virtual Microsoft.Maui.MauiViewGroup.InputTransparent.get -> bool virtual Microsoft.Maui.MauiViewGroup.InputTransparent.set -> void virtual Microsoft.Maui.MauiViewGroup.MeasureAndLayout(int widthMeasureSpec, int heightMeasureSpec, int l, int t, int r, int b) -> void diff --git a/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt index 407a0a48dafc..665ab59c8777 100644 --- a/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt +++ b/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt @@ -28,3 +28,4 @@ static Microsoft.Maui.Platform.WebViewExtensions.UpdateUserAgent(this Android.We Microsoft.Maui.WeakEventManager.HandleEvent(object? sender, object? args, string! eventName) -> void static Microsoft.Maui.SizeRequest.operator !=(Microsoft.Maui.SizeRequest left, Microsoft.Maui.SizeRequest right) -> bool static Microsoft.Maui.SizeRequest.operator ==(Microsoft.Maui.SizeRequest left, Microsoft.Maui.SizeRequest right) -> bool +virtual Microsoft.Maui.MauiAppCompatActivity.AllowFragmentRestore.get -> bool diff --git a/src/Essentials/samples/Samples/Platforms/Android/MainActivity.cs b/src/Essentials/samples/Samples/Platforms/Android/MainActivity.cs index c2140a85ae5b..be3e72becbfe 100644 --- a/src/Essentials/samples/Samples/Platforms/Android/MainActivity.cs +++ b/src/Essentials/samples/Samples/Platforms/Android/MainActivity.cs @@ -17,8 +17,6 @@ public class MainActivity : MauiAppCompatActivity protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); - - Microsoft.Maui.ApplicationModel.Platform.Init(this, bundle); Microsoft.Maui.ApplicationModel.Platform.ActivityStateChanged += Platform_ActivityStateChanged; } diff --git a/src/Essentials/samples/Samples/ViewModel/MediaPickerViewModel.cs b/src/Essentials/samples/Samples/ViewModel/MediaPickerViewModel.cs index 1664e7004d7b..561947446920 100644 --- a/src/Essentials/samples/Samples/ViewModel/MediaPickerViewModel.cs +++ b/src/Essentials/samples/Samples/ViewModel/MediaPickerViewModel.cs @@ -2,12 +2,14 @@ using System.IO; using System.Threading.Tasks; using System.Windows.Input; +using Microsoft.Maui.ApplicationModel; using Microsoft.Maui.Controls; using Microsoft.Maui.Media; using Microsoft.Maui.Storage; namespace Samples.ViewModel { +#pragma warning disable CS0618 public class MediaPickerViewModel : BaseViewModel { string photoPath; @@ -77,6 +79,8 @@ async void DoCapturePhoto() { try { + if(await Permissions.RequestAsync() != PermissionStatus.Granted) + return; var photo = await MediaPicker.CapturePhotoAsync(); await LoadPhotoAsync(photo); @@ -173,4 +177,5 @@ public override void OnDisappearing() base.OnDisappearing(); } } +#pragma warning restore CS0618 } diff --git a/src/Essentials/src/Essentials.csproj b/src/Essentials/src/Essentials.csproj index 4c0542d4d7db..8bc5736fc03c 100644 --- a/src/Essentials/src/Essentials.csproj +++ b/src/Essentials/src/Essentials.csproj @@ -37,6 +37,8 @@ + + diff --git a/src/Essentials/src/FileSystem/FileSystem.android.cs b/src/Essentials/src/FileSystem/FileSystem.android.cs index 8327da20eea1..975c260c25a6 100644 --- a/src/Essentials/src/FileSystem/FileSystem.android.cs +++ b/src/Essentials/src/FileSystem/FileSystem.android.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Android.App; using Android.Webkit; +using Microsoft.Maui.ApplicationModel; namespace Microsoft.Maui.Storage { @@ -55,7 +56,7 @@ internal FileBase(Java.IO.File file) { } - string PlatformGetContentType(string extension) => + internal string PlatformGetContentType(string extension) => MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension.TrimStart('.')); void PlatformInit(FileBase file) @@ -68,4 +69,32 @@ internal virtual Task PlatformOpenReadAsync() return Task.FromResult(stream); } } + + public partial class MediaFileResult + { + readonly Android.Net.Uri _uri; + readonly string _tempFilePath; + + internal MediaFileResult(string fileName, Android.Net.Uri uri, string tempFilePath = null) + { + _tempFilePath = tempFilePath; + _uri = uri; + NameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); + Extension = Path.GetExtension(fileName).TrimStart('.'); + ContentType = PlatformGetContentType(Extension); + Type = GetFileType(ContentType); + FileName = GetFileName(NameWithoutExtension, Extension); + } + + internal override Task PlatformOpenReadAsync() + => Task.FromResult(Platform.AppContext.ContentResolver!.OpenInputStream(_uri)); + + void PlatformDispose() + { + if (!string.IsNullOrWhiteSpace(_tempFilePath) && File.Exists(_tempFilePath)) + File.Delete(_tempFilePath); + + _uri?.Dispose(); + } + } } diff --git a/src/Essentials/src/FileSystem/FileSystem.ios.cs b/src/Essentials/src/FileSystem/FileSystem.ios.cs index ac35614f8510..79fb4dddc289 100644 --- a/src/Essentials/src/FileSystem/FileSystem.ios.cs +++ b/src/Essentials/src/FileSystem/FileSystem.ios.cs @@ -4,8 +4,10 @@ using System.Linq; using System.Threading.Tasks; using Foundation; -using Photos; +using ImageIO; using UIKit; +using OldUTType = MobileCoreServices.UTType; +using UTTypes = UniformTypeIdentifiers.UTTypes; namespace Microsoft.Maui.Storage { @@ -158,68 +160,134 @@ protected override void Dispose(bool disposing) } } - class UIDocumentFileResult : FileResult + class UIDocumentFileResult : MediaFileResult { - internal UIDocumentFileResult(NSUrl url) - : base() + UIDocument document; + NSUrl assetUrl; + + internal UIDocumentFileResult(NSUrl assetUrl, string fileName) { - var doc = new UIDocument(url); - FullPath = doc.FileUrl?.Path; - FileName = doc.LocalizedName ?? Path.GetFileName(FullPath); + this.assetUrl = assetUrl; + document = new UIDocument(assetUrl); + Extension = document.FileUrl.PathExtension!; + ContentType = GetMIMEType(document.FileType); + NameWithoutExtension = !string.IsNullOrWhiteSpace(fileName) + ? Path.GetFileNameWithoutExtension(fileName) + : null; + Type = GetFileType(ContentType); + FileName = GetFileName(NameWithoutExtension, Extension); } internal override Task PlatformOpenReadAsync() - { - Stream fileStream = File.OpenRead(FullPath); + => Task.FromResult(File.OpenRead(document.FileUrl.Path!)); - return Task.FromResult(fileStream); + protected internal override void PlatformDispose() + { + document?.Dispose(); + document = null; + assetUrl?.Dispose(); + assetUrl = null; + base.PlatformDispose(); } } - class UIImageFileResult : FileResult + class UIImageFileResult : MediaFileResult { - readonly UIImage uiImage; - NSData data; + UIImage img; + NSDictionary metadata; + NSMutableData imgWithMetadata; - internal UIImageFileResult(UIImage image) - : base() + internal UIImageFileResult(UIImage img, NSDictionary metadata, string name) { - uiImage = image; - - FullPath = Guid.NewGuid().ToString() + FileExtensions.Png; - FileName = FullPath; + this.img = img; + this.metadata = metadata; + NameWithoutExtension = name; +#pragma warning disable CA1422 + ContentType = GetMIMEType(OldUTType.JPEG); + Extension = GetExtension(OldUTType.JPEG); +#pragma warning restore CA1422 + Type = GetFileType(ContentType); + FileName = GetFileName(NameWithoutExtension, Extension); } internal override Task PlatformOpenReadAsync() { - data ??= uiImage.AsPNG(); + imgWithMetadata ??= GetImageWithMeta(); + return Task.FromResult(imgWithMetadata?.AsStream()); + } - return Task.FromResult(data.AsStream()); + public NSMutableData GetImageWithMeta() + { + if (img == null || metadata == null) + return null; + + using var source = CGImageSource.FromData(img.AsJPEG()); + var destData = new NSMutableData(); + using var destination = CGImageDestination.Create(destData, source.TypeIdentifier, 1, null); + destination.AddImage(source, 0, metadata); + destination.Close(); + DisposeSources(); + return destData; + } + + protected internal override void PlatformDispose() + { + imgWithMetadata?.Dispose(); + imgWithMetadata = null; + DisposeSources(); + base.PlatformDispose(); + } + + void DisposeSources() + { + img?.Dispose(); + img = null; + metadata?.Dispose(); + metadata = null; } } - class PHAssetFileResult : FileResult + class PHPickerFileResult : MediaFileResult { - readonly PHAsset phAsset; + readonly string identifier; + NSItemProvider provider; - internal PHAssetFileResult(NSUrl url, PHAsset asset, string originalFilename) - : base() + internal PHPickerFileResult(NSItemProvider provider) { - phAsset = asset; + this.provider = provider; + NameWithoutExtension = provider?.SuggestedName; + + identifier = GetIdentifier(provider?.RegisteredTypeIdentifiers); - FullPath = url?.AbsoluteString; - FileName = originalFilename; + if (string.IsNullOrWhiteSpace(identifier)) + return; + + Extension = GetExtension(identifier); + ContentType = GetMIMEType(identifier); + Type = GetFileType(ContentType); + FileName = GetFileName(NameWithoutExtension, Extension); } - [System.Runtime.Versioning.UnsupportedOSPlatform("ios13.0")] - internal override Task PlatformOpenReadAsync() - { - var tcsStream = new TaskCompletionSource(); + internal override async Task PlatformOpenReadAsync() + => (await provider?.LoadDataRepresentationAsync(identifier))?.AsStream(); - PHImageManager.DefaultManager.RequestImageData(phAsset, null, new PHImageDataHandler((data, str, orientation, dict) => - tcsStream.TrySetResult(data.AsStream()))); + protected internal override void PlatformDispose() + { + provider?.Dispose(); + provider = null; + base.PlatformDispose(); + } - return tcsStream.Task; + private string GetIdentifier(string[] identifiers) + { + if (!(identifiers?.Length > 0)) + return null; + + if (identifiers.Any(i => i.StartsWith(UTTypes.LivePhoto.Identifier)) && identifiers.Contains(UTTypes.Jpeg.Identifier)) + return identifiers.FirstOrDefault(i => i == UTTypes.Jpeg.Identifier); + if (identifiers.Contains(UTTypes.QuickTimeMovie.Identifier)) + return identifiers.FirstOrDefault(i => i == UTTypes.QuickTimeMovie.Identifier); + return identifiers.FirstOrDefault(); } } } diff --git a/src/Essentials/src/FileSystem/FileSystem.ios.tvos.watchos.macos.cs b/src/Essentials/src/FileSystem/FileSystem.ios.tvos.watchos.macos.cs index eaa83c5485b6..9a03c6ccd316 100644 --- a/src/Essentials/src/FileSystem/FileSystem.ios.tvos.watchos.macos.cs +++ b/src/Essentials/src/FileSystem/FileSystem.ios.tvos.watchos.macos.cs @@ -1,7 +1,11 @@ using System; using System.IO; +using System.Linq; using System.Threading.Tasks; using Foundation; +using OldUTType = MobileCoreServices.UTType; +using UTType = UniformTypeIdentifiers.UTType; +using UTTypes = UniformTypeIdentifiers.UTTypes; namespace Microsoft.Maui.Storage { @@ -78,7 +82,33 @@ void PlatformInit(FileBase file) { } +#pragma warning disable CA1422 + internal static string GetExtension(string identifier) + => UTTypeISSupported() + ? UTType.CreateFromIdentifier(identifier)!.PreferredFilenameExtension + : OldUTType.CopyAllTags(identifier, OldUTType.TagClassFilenameExtension)?.FirstOrDefault(); + + internal static string GetMIMEType(string identifier) + => UTTypeISSupported() + ? UTType.CreateFromIdentifier(identifier)!.PreferredMimeType + : OldUTType.CopyAllTags(identifier, OldUTType.TagClassMIMEType)?.FirstOrDefault(); +#pragma warning restore CA1422 + + static bool UTTypeISSupported() + => OperatingSystem.IsIOSVersionAtLeast(14) + || OperatingSystem.IsMacOSVersionAtLeast(11) + || OperatingSystem.IsMacCatalystVersionAtLeast(14) + || OperatingSystem.IsWatchOSVersionAtLeast(14) + || OperatingSystem.IsTvOSVersionAtLeast(14) + || OperatingSystem.IsWatchOSVersionAtLeast(7); + internal virtual Task PlatformOpenReadAsync() => Task.FromResult((Stream)File.OpenRead(FullPath)); } + + public partial class MediaFileResult + { + /// + protected internal virtual void PlatformDispose() { } + } } diff --git a/src/Essentials/src/FileSystem/FileSystem.netstandard.cs b/src/Essentials/src/FileSystem/FileSystem.netstandard.cs index bf1431a05a54..27f62e5fedd2 100644 --- a/src/Essentials/src/FileSystem/FileSystem.netstandard.cs +++ b/src/Essentials/src/FileSystem/FileSystem.netstandard.cs @@ -33,4 +33,10 @@ internal virtual Task PlatformOpenReadAsync() void PlatformInit(FileBase file) => throw ExceptionUtils.NotSupportedOrImplementedException; } + + public partial class MediaFileResult + { + /// + protected internal virtual void PlatformDispose() { } + } } diff --git a/src/Essentials/src/FileSystem/FileSystem.shared.cs b/src/Essentials/src/FileSystem/FileSystem.shared.cs index 6461323cd3be..8f42d53d34d7 100644 --- a/src/Essentials/src/FileSystem/FileSystem.shared.cs +++ b/src/Essentials/src/FileSystem/FileSystem.shared.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Threading.Tasks; +using Microsoft.Maui.Media; namespace Microsoft.Maui.Storage { @@ -354,4 +355,52 @@ public FileResult(FileBase file) { } } + + /// + /// Describes and allows to open a media file + /// + public partial class MediaFileResult : FileResult, IDisposable + { + internal MediaFileResult() + { + } + + /// + /// Returns the file name without extension. Can return an null or empty value + /// + public string? NameWithoutExtension { get; protected set; } + + /// + /// Returns the file extension without a dot (eg:, "png"). + /// + public string? Extension { get; protected set; } + + /// + /// Returns the file type. Can return an null value. + /// + public MediaFileType? Type { get; protected set; } + + internal MediaFileType? GetFileType(string contentType) + { + if (string.IsNullOrWhiteSpace(contentType)) + return null; + if (ContentType.StartsWith("image")) + return MediaFileType.Image; + if (ContentType.StartsWith("video")) + return MediaFileType.Video; + + return null; + } + + internal string GetFileName(string? name, string? ex) + { + if (!string.IsNullOrWhiteSpace(ex)) + ex = $".{ex}"; + return (string.IsNullOrWhiteSpace(name) ? "mediaFile" : name) + ex; + } + + /// + public void Dispose() + => PlatformDispose(); + } } \ No newline at end of file diff --git a/src/Essentials/src/FileSystem/FileSystem.tizen.cs b/src/Essentials/src/FileSystem/FileSystem.tizen.cs index 5d96213e93f6..891ac8b7e028 100644 --- a/src/Essentials/src/FileSystem/FileSystem.tizen.cs +++ b/src/Essentials/src/FileSystem/FileSystem.tizen.cs @@ -60,4 +60,17 @@ internal virtual async Task PlatformOpenReadAsync() return Task.FromResult(stream).Result; } } + + public partial class MediaFileResult + { + internal MediaFileResult(FileResult file) : base(file) + { + + } + + void PlatformDispose() + { + + } + } } diff --git a/src/Essentials/src/FileSystem/FileSystem.uwp.cs b/src/Essentials/src/FileSystem/FileSystem.uwp.cs index 9719ed661fef..0d18e7957835 100644 --- a/src/Essentials/src/FileSystem/FileSystem.uwp.cs +++ b/src/Essentials/src/FileSystem/FileSystem.uwp.cs @@ -105,4 +105,17 @@ internal FileResult(IStorageFile file) { } } + + public partial class MediaFileResult + { + internal MediaFileResult(IStorageFile file) + : base(file) + { + } + + void PlatformDispose() + { + + } + } } diff --git a/src/Essentials/src/MediaGallery/MediaFileType.shared.cs b/src/Essentials/src/MediaGallery/MediaFileType.shared.cs new file mode 100644 index 000000000000..7d671eabaa15 --- /dev/null +++ b/src/Essentials/src/MediaGallery/MediaFileType.shared.cs @@ -0,0 +1,17 @@ +namespace Microsoft.Maui.Media +{ + /// + /// Enumeration media files + /// + public enum MediaFileType + { + /// + /// image/* + /// + Image, + /// + /// video/* + /// + Video, + } +} \ No newline at end of file diff --git a/src/Essentials/src/MediaGallery/MediaFilesResult.shared.cs b/src/Essentials/src/MediaGallery/MediaFilesResult.shared.cs new file mode 100644 index 000000000000..87c3f387af14 --- /dev/null +++ b/src/Essentials/src/MediaGallery/MediaFilesResult.shared.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using Microsoft.Maui.Storage; + +namespace Microsoft.Maui.Media +{ + /// + /// Describes the result of the methods + /// + public sealed class MediaFilesResult + { + internal MediaFilesResult(IEnumerable files) + => Files = files; + + /// + /// User-selected media files. Can return an null or empty value + /// + public IEnumerable Files { get; } + } +} + diff --git a/src/Essentials/src/MediaGallery/MediaGallery.android.cs b/src/Essentials/src/MediaGallery/MediaGallery.android.cs new file mode 100644 index 000000000000..bc1aef9016e8 --- /dev/null +++ b/src/Essentials/src/MediaGallery/MediaGallery.android.cs @@ -0,0 +1,314 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Android.App; +using Android.Content; +using Android.Content.PM; +using Android.Provider; +using Android.Webkit; +using AndroidX.Activity.Result; +using AndroidX.Activity.Result.Contract; +using AndroidX.Core.App; +using Microsoft.Maui.ApplicationModel; +using Microsoft.Maui.Storage; +using Environment = Android.OS.Environment; +using File = Java.IO.File; +using Path = System.IO.Path; +using Stream = System.IO.Stream; +using Uri = Android.Net.Uri; +#if ANDROID30_0_OR_GREATER +using MediaColumns = Android.Provider.MediaStore.IMediaColumns; +#elif MONOANDROID10_0 +global using MediaColumns = Android.Provider.MediaStore.MediaColumns; +#endif + +namespace Microsoft.Maui.Media +{ + partial class MediaGalleryImplementation : IMediaGallery + { + static TaskCompletionSource TcsPick; + + public bool IsSupported => OperatingSystem.IsAndroidVersionAtLeast(21); + + public bool CheckCaptureSupport(MediaFileType type) + { + if (!IsSupported || !(Platform.AppContext?.PackageManager?.HasSystemFeature(PackageManager.FeatureCameraAny) ?? false)) + return false; + using var intent = GetCameraIntent(type); + return PlatformUtils.IsIntentSupported(intent); + } + + public MultiPickingBehaviour GetMultiPickingBehaviour() + => ActionPickImagesIsSupported() + ? MultiPickingBehaviour.Limit + : MultiPickingBehaviour.UnLimit; + + async Task> PlatformCaptureAsync(MediaFileType type, CancellationToken token = default) + { + string tempFilePath = string.Empty, fileName = string.Empty; + Uri outputUri = null; + var res = await StartIntentAsync(GetIntent, token); + return res.ResultCode == (int)Result.Ok && System.IO.File.Exists(tempFilePath) + ? new[] { new MediaFileResult(fileName, outputUri, tempFilePath) } + : null; + + Intent GetIntent(Context context) + { + var intent = GetCameraIntent(type); + + fileName = $"{GetNewImageName()}.jpg"; + tempFilePath = GetFilePath(fileName); + using var file = new File(tempFilePath); + if (!file.Exists()) + file.CreateNewFile(); + outputUri = FileProvider.GetUriForFile(file); + intent.PutExtra(MediaStore.ExtraOutput, outputUri); + return intent; + } + } + + async Task> PlatformPickAsync(MediaPickRequest request, CancellationToken token = default) + { + var res = await StartIntentAsync(_ => GetPickerIntent(request), token); + return GetFilesFromIntent(res.Intent); + } + + async Task PlatformSaveAsync(MediaFileType type, byte[] data, string fileName) + { + using var ms = new MemoryStream(data); + await SaveAsync(type, ms, fileName).ConfigureAwait(false); + } + + async Task PlatformSaveAsync(MediaFileType type, string filePath) + { + await using var fileStream = System.IO.File.OpenRead(filePath); + await SaveAsync(type, fileStream, Path.GetFileName(filePath)).ConfigureAwait(false); + } + + async Task PlatformSaveAsync(MediaFileType type, Stream fileStream, string fileName) + { + var albumName = AppInfo.Name; + + var context = Platform.AppContext; + + var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); + var extension = Path.GetExtension(fileName).ToLower(); + var newFileName = $"{GetNewImageName(DateTime.Now, fileNameWithoutExtension)}{extension}"; + + using var values = new ContentValues(); + + values.Put(MediaColumns.DateAdded, DateTimeOffset.UtcNow.ToUnixTimeSeconds()); + values.Put(MediaColumns.Title, fileNameWithoutExtension); + values.Put(MediaColumns.DisplayName, newFileName); + + var mimeType = MimeTypeMap.Singleton!.GetMimeTypeFromExtension(extension.Replace(".", string.Empty, StringComparison.Ordinal)); + if (!string.IsNullOrWhiteSpace(mimeType)) + values.Put(MediaColumns.MimeType, mimeType); + + using var externalContentUri = type == MediaFileType.Image + ? MediaStore.Images.Media.ExternalContentUri + : MediaStore.Video.Media.ExternalContentUri; + + var relativePath = type == MediaFileType.Image + ? Environment.DirectoryPictures + : Environment.DirectoryMovies; + + if (OperatingSystem.IsAndroidVersionAtLeast(29)) + { + values.Put(MediaColumns.RelativePath, Path.Combine(relativePath!, albumName)); + values.Put(MediaColumns.IsPending, true); + + using var uri = context.ContentResolver!.Insert(externalContentUri!, values); + await using var stream = context.ContentResolver.OpenOutputStream(uri!); + await fileStream.CopyToAsync(stream!); + stream.Close(); + + values.Put(MediaColumns.IsPending, false); + context.ContentResolver.Update(uri, values, null, null); + } + else + { +#pragma warning disable CS0618 // Type or member is obsolete + using var directory = new File(Environment.GetExternalStoragePublicDirectory(relativePath), albumName); + + directory.Mkdirs(); + using var file = new File(directory, newFileName); + + await using var fileOutputStream = System.IO.File.Create(file.AbsolutePath); + await fileStream.CopyToAsync(fileOutputStream); + fileOutputStream.Close(); + + values.Put(MediaColumns.Data, file.AbsolutePath); + context.ContentResolver!.Insert(externalContentUri!, values); + + using var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile); + mediaScanIntent.SetData(Uri.FromFile(file)); + context.SendBroadcast(mediaScanIntent); +#pragma warning restore CS0618 // Type or member is obsolete + } + } + + public async Task StartIntentAsync(Func getIntent, CancellationToken token = default) + { + token.ThrowIfCancellationRequested(); + + try + { + TcsPick = new (TaskCreationOptions.RunContinuationsAsynchronously); + CancelTaskIfRequested(token, TcsPick, false); + + if (token.CanBeCanceled) + { + token.Register(() => + { + var tcs = TcsPick; + Platform.CurrentActivity?.FinishActivity(Platform.MediaPickerActivityLauncher!.GetHashCode()); + tcs?.TrySetCanceled(token); + }); + } + + Platform.MediaPickerActivityLauncher?.Launch(new ActivityResultContractIntent(getIntent)); + + return await TcsPick.Task.ConfigureAwait(false); + } + finally + { + TcsPick = null; + } + } + + internal static void OnActivityResult(ActivityResultContractResult result) + => TcsPick.TrySetResult(result); + + static Intent GetPickerIntent(MediaPickRequest request) + { +#if ANDROID33_0_OR_GREATER + if (ActionPickImagesIsSupported()) + return GetPickerActionPickImagesIntent(request); +#endif + return GetPickerActionGetContentIntent(request); + } + + static Intent GetPickerActionGetContentIntent(MediaPickRequest request) + { + var mimeTypes = request.Types.Select(GetMimeType).ToArray(); + var intent = new Intent(Intent.ActionGetContent); + + intent.SetType(string.Join(", ", mimeTypes)); + intent.PutExtra(Intent.ExtraMimeTypes, mimeTypes); + intent.AddCategory(Intent.CategoryOpenable); + intent.PutExtra(Intent.ExtraLocalOnly, true); + intent.PutExtra(Intent.ExtraAllowMultiple, request.SelectionLimit > 1); + + if (!string.IsNullOrWhiteSpace(request.Title)) + intent.PutExtra(Intent.ExtraTitle, request.Title); + return intent; + } + + static bool ActionPickImagesIsSupported() + { +#if ANDROID33_0_OR_GREATER +#pragma warning disable CA1416 + if (OperatingSystem.IsAndroidVersionAtLeast(33)) + return true; + if (OperatingSystem.IsAndroidVersionAtLeast(30)) + return Android.OS.Ext.SdkExtensions.GetExtensionVersion(30) >= 2; +#pragma warning restore CA1416 +#endif + return false; + } + +#if ANDROID33_0_OR_GREATER +#pragma warning disable CA1416 + static Intent GetPickerActionPickImagesIntent(MediaPickRequest request) + { + var intent = new Intent(MediaStore.ActionPickImages); + if (request.SelectionLimit > 1) + intent.PutExtra(MediaStore.ExtraPickImagesMax, request.SelectionLimit); + if(request.Types.Length == 1) + intent.SetType(GetMimeType(request.Types[0])); + return intent; + } +#pragma warning restore CA1416 +#endif + + static Intent GetCameraIntent(MediaFileType type) + => new(type switch + { + MediaFileType.Video => MediaStore.ActionVideoCapture, + _ => MediaStore.ActionImageCapture, + }); + + static void CancelTaskIfRequested(CancellationToken token, TaskCompletionSource tcs, bool needThrow = true) + { + if (!token.IsCancellationRequested) + return; + tcs?.TrySetCanceled(token); + if (needThrow) + token.ThrowIfCancellationRequested(); + } + + static IEnumerable GetFilesFromIntent(Intent intent) + { + var clipCount = intent?.ClipData?.ItemCount ?? 0; + var data = intent?.Data; + + if (data != null && !(clipCount > 1)) + { + var res = GetFileResult(data); + if (res != null) + yield return res; + } + else if (clipCount > 0) + { + for (var i = 0; i < clipCount; i++) + { + var item = intent!.ClipData!.GetItemAt(i); + var res = GetFileResult(item!.Uri); + if (res != null) + yield return res; + } + } + } + + static MediaFileResult GetFileResult(Uri uri) + { + var name = QueryContentResolverColumn(uri, MediaColumns.DisplayName); + return string.IsNullOrWhiteSpace(name) + ? null + : new MediaFileResult(name, uri); + } + + static string QueryContentResolverColumn(Uri contentUri, string columnName) + { + try + { + using var cursor = Platform.AppContext?.ContentResolver? + .Query(contentUri, new[] { columnName }, null, null, null); + + if (cursor?.MoveToFirst() ?? false) + { + var columnIndex = cursor.GetColumnIndex(columnName); + if (columnIndex != -1) + return cursor.GetString(columnIndex); + } + return null; + } + catch + { + return null; + } + } + } + + class MediaGalleryActivityResultCallback : CommonActivityResultCallback + { + internal MediaGalleryActivityResultCallback() + : base(MediaGalleryImplementation.OnActivityResult) + { + } + } +} diff --git a/src/Essentials/src/MediaGallery/MediaGallery.ios.cs b/src/Essentials/src/MediaGallery/MediaGallery.ios.cs new file mode 100644 index 000000000000..87ed48c32238 --- /dev/null +++ b/src/Essentials/src/MediaGallery/MediaGallery.ios.cs @@ -0,0 +1,336 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Foundation; +using Microsoft.Maui.ApplicationModel; +using Microsoft.Maui.Devices; +using Microsoft.Maui.Graphics.Platform; +using Microsoft.Maui.Storage; +using MobileCoreServices; +using Photos; +using PhotosUI; +using UIKit; + +namespace Microsoft.Maui.Media +{ + partial class MediaGalleryImplementation + { + UIViewController pickerRef; + UIViewController cameraRef; + + public bool IsSupported => OperatingSystem.IsIOSVersionAtLeast(11); + + public bool CheckCaptureSupport(MediaFileType type) + => UIImagePickerController.IsSourceTypeAvailable(UIImagePickerControllerSourceType.Camera); + + public async Task> PlatformCaptureAsync(MediaFileType type, CancellationToken token = default) + { + var tcs = new TaskCompletionSource>(TaskCreationOptions.RunContinuationsAsynchronously); + CancelTaskIfRequested(token, tcs, false); + + await MainThread.InvokeOnMainThreadAsync(() => + { + CancelTaskIfRequested(token, tcs, false); + + cameraRef = new UIImagePickerController + { + SourceType = UIImagePickerControllerSourceType.Camera, + AllowsEditing = false, + Delegate = new PhotoPickerDelegate(tcs), + CameraCaptureMode = UIImagePickerControllerCameraCaptureMode.Photo, + }; + + CancelTaskIfRequested(token, tcs, false); + var vc = Platform.GetCurrentUIViewController(); + + ConfigureController(cameraRef, tcs); + + + CancelTaskIfRequested(token, tcs, false); + vc.PresentViewController(cameraRef, true, () => PresentViewControllerHandler(cameraRef, token, tcs)); + }); + + return await tcs.Task.ConfigureAwait(false); + } + + public async Task> PlatformPickAsync(MediaPickRequest request, CancellationToken token = default) + { + token.ThrowIfCancellationRequested(); + + try + { + var isVideo = request.Types.Contains(MediaFileType.Video); + var isImage = request.Types.Contains(MediaFileType.Image); + + var tcs = new TaskCompletionSource>(TaskCreationOptions.RunContinuationsAsynchronously); + + CancelTaskIfRequested(token, tcs); + + await MainThread.InvokeOnMainThreadAsync(() => + { + CancelTaskIfRequested(token, tcs); + + if (OperatingSystem.IsIOSVersionAtLeast(14)) + { + var config = new PHPickerConfiguration(); + config.SelectionLimit = request.SelectionLimit; + + if (!(isVideo && isImage)) + config.Filter = isVideo + ? PHPickerFilter.VideosFilter + : PHPickerFilter.ImagesFilter; + + pickerRef = new PHPickerViewController(config) + { + Delegate = new PHPickerDelegate(tcs), + }; + } + else + { +#pragma warning disable CA1422 + var sourceType = UIImagePickerControllerSourceType.PhotoLibrary; + + if (!UIImagePickerController.IsSourceTypeAvailable(sourceType)) + throw new FeatureNotSupportedException(); + + var availableTypes = UIImagePickerController.AvailableMediaTypes(sourceType); + isVideo = isVideo && availableTypes.Contains(UTType.Movie); + isImage = isImage && availableTypes.Contains(UTType.Image); + if (!(isVideo || isImage)) + throw new FeatureNotSupportedException(); + + pickerRef = new UIImagePickerController + { + SourceType = sourceType, + AllowsEditing = false, + Delegate = new PhotoPickerDelegate(tcs), + MediaTypes = isVideo && isImage + ? new string[] { UTType.Movie, UTType.Image } + : new string[] { isVideo ? UTType.Movie : UTType.Image }, + }; +#pragma warning restore CA1422 + } + + CancelTaskIfRequested(token, tcs); + var vc = Platform.GetCurrentUIViewController(); + + if (DeviceInfo.Idiom == DeviceIdiom.Tablet) + { + pickerRef.ModalPresentationStyle = request.PresentationSourceBounds != Graphics.Rect.Zero + ? UIModalPresentationStyle.Popover + : UIModalPresentationStyle.PageSheet; + + if (pickerRef.PopoverPresentationController != null) + { + pickerRef.PopoverPresentationController.SourceView = vc.View!; + pickerRef.PopoverPresentationController.SourceRect = request.PresentationSourceBounds.AsCGRect(); + } + } + + ConfigureController(pickerRef, tcs); + + CancelTaskIfRequested(token, tcs); + + vc!.PresentViewController(pickerRef, true, () => PresentViewControllerHandler(pickerRef, token, tcs)); + }); + + CancelTaskIfRequested(token, tcs, false); + return await tcs.Task.ConfigureAwait(false); + } + finally + { + pickerRef?.Dispose(); + pickerRef = null; + } + } + + public MultiPickingBehaviour GetMultiPickingBehaviour() + => OperatingSystem.IsIOSVersionAtLeast(14) + ? MultiPickingBehaviour.Limit + : MultiPickingBehaviour.AlwaysSingle; + + public async Task PlatformSaveAsync(MediaFileType type, Stream fileStream, string fileName) + { + string filePath = null; + + try + { + filePath = GetFilePath(fileName); + using var stream = File.Create(filePath); + await fileStream.CopyToAsync(stream); + stream.Close(); + + await PlatformSaveAsync(type, filePath).ConfigureAwait(false); + } + finally + { + DeleteFile(filePath); + } + } + + public async Task PlatformSaveAsync(MediaFileType type, byte[] data, string fileName) + { + string filePath = null; + + try + { + filePath = GetFilePath(fileName); + await File.WriteAllBytesAsync(filePath, data); + + await PlatformSaveAsync(type, filePath).ConfigureAwait(false); + } + finally + { + DeleteFile(filePath); + } + } + + public Task PlatformSaveAsync(MediaFileType type, string filePath) + { + using var fileUri = new NSUrl(filePath); + + return PhotoLibraryPerformChanges(() => + { + using var request = type == MediaFileType.Video + ? PHAssetChangeRequest.FromVideo(fileUri!) + : PHAssetChangeRequest.FromImage(fileUri!); + }); + } + + + static async Task PhotoLibraryPerformChanges(Action action) + { + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + PHPhotoLibrary.SharedPhotoLibrary.PerformChanges( + () => + { + try + { + action.Invoke(); + } + catch (Exception ex) + { + tcs.TrySetResult(ex); + } + }, + (success, error) => + tcs.TrySetResult(error != null ? new NSErrorException(error) : null)); + + var exception = await tcs.Task; + if (exception != null) + throw exception; + } + + static void ConfigureController(UIViewController controller, TaskCompletionSource> tcs) + { + if (controller.PresentationController != null) + controller.PresentationController.Delegate = new UIPresentationControllerDelegate(() => tcs?.TrySetResult(null)); + } + + static void CancelTaskIfRequested(CancellationToken token, TaskCompletionSource> tcs, bool needThrow = true) + { + if (!token.IsCancellationRequested) + return; + tcs?.TrySetCanceled(token); + if (needThrow) + token.ThrowIfCancellationRequested(); + } + + static void PresentViewControllerHandler(UIViewController controller, CancellationToken token, TaskCompletionSource> tcs) + { + if (!token.CanBeCanceled) + return; + + token.Register( + () => MainThread.BeginInvokeOnMainThread( + () => controller?.DismissViewController(true, + () => tcs?.TrySetCanceled(token)))); + } + + + class PHPickerDelegate : PHPickerViewControllerDelegate + { + readonly TaskCompletionSource> tcs; + + internal PHPickerDelegate(TaskCompletionSource> tcs) + => this.tcs = tcs; + + public override void DidFinishPicking(PHPickerViewController picker, PHPickerResult[] results) + { + picker.DismissViewController(true, null); + tcs?.TrySetResult(results?.Length > 0 ? ConvertPickerResults(results) : null); + } + + static IEnumerable ConvertPickerResults(PHPickerResult[] results) + => results + .Select(res => res.ItemProvider) + .Where(provider => provider != null && provider.RegisteredTypeIdentifiers?.Length > 0) + .Select(provider => new PHPickerFileResult(provider)) + .ToArray(); + } + + class PhotoPickerDelegate : UIImagePickerControllerDelegate + { + readonly TaskCompletionSource> tcs; + + internal PhotoPickerDelegate(TaskCompletionSource> tcs) + => this.tcs = tcs; + + public override void FinishedPickingMedia(UIImagePickerController picker, NSDictionary info) + { + picker.DismissViewController(true, null); + var result = ConvertPickerResults(info); + tcs.TrySetResult(result == null ? null : new MediaFileResult[] { result }); + } + + public override void Canceled(UIImagePickerController picker) + { + picker.DismissViewController(true, null); + tcs?.TrySetResult(null); + } + + MediaFileResult ConvertPickerResults(NSDictionary info) + { + if (info == null) + return null; + + var assetUrl = (info.ValueForKey(UIImagePickerController.ImageUrl) + ?? info.ValueForKey(UIImagePickerController.MediaURL)) as NSUrl; + + var path = assetUrl?.Path; + + if (!string.IsNullOrWhiteSpace(path) && File.Exists(path)) + return new UIDocumentFileResult(assetUrl, GetOriginalName(info)); + + assetUrl?.Dispose(); + var img = info.ValueForKey(UIImagePickerController.OriginalImage) as UIImage; + var meta = info.ValueForKey(UIImagePickerController.MediaMetadata) as NSDictionary; + + if (img != null && meta != null) + return new UIImageFileResult(img, meta, GetNewImageName()); + + return null; + } + + string GetOriginalName(NSDictionary info) + { +#pragma warning disable CA1422 + if (PHPhotoLibrary.AuthorizationStatus != PHAuthorizationStatus.Authorized + || !info.ContainsKey(UIImagePickerController.PHAsset)) + return null; + + using var asset = info.ValueForKey(UIImagePickerController.PHAsset) as PHAsset; + + return asset != null + ? PHAssetResource.GetAssetResources(asset)?.FirstOrDefault()?.OriginalFilename + : null; +#pragma warning restore CA1422 + } + } + + } +} diff --git a/src/Essentials/src/MediaGallery/MediaGallery.netstandard.watchos.tvos.cs b/src/Essentials/src/MediaGallery/MediaGallery.netstandard.watchos.tvos.cs new file mode 100644 index 000000000000..e923cea6003b --- /dev/null +++ b/src/Essentials/src/MediaGallery/MediaGallery.netstandard.watchos.tvos.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Maui.ApplicationModel; +using Microsoft.Maui.Storage; + +namespace Microsoft.Maui.Media +{ + partial class MediaGalleryImplementation + { + public bool IsSupported => false; + + public bool CheckCaptureSupport(MediaFileType type) => throw new NotImplementedInReferenceAssemblyException(); + + public Task> PlatformCaptureAsync(MediaFileType type, CancellationToken token = default) + => throw new NotImplementedInReferenceAssemblyException(); + + public Task> PlatformPickAsync(MediaPickRequest request, CancellationToken token = default) + => throw new NotImplementedInReferenceAssemblyException(); + + public MultiPickingBehaviour GetMultiPickingBehaviour() + => throw new NotImplementedInReferenceAssemblyException(); + + public Task PlatformSaveAsync(MediaFileType type, Stream fileStream, string fileName) + => throw new NotImplementedInReferenceAssemblyException(); + + public Task PlatformSaveAsync(MediaFileType type, byte[] data, string fileName) + => throw new NotImplementedInReferenceAssemblyException(); + + public Task PlatformSaveAsync(MediaFileType type, string filePath) + => throw new NotImplementedInReferenceAssemblyException(); + } +} diff --git a/src/Essentials/src/MediaGallery/MediaGallery.shared.cs b/src/Essentials/src/MediaGallery/MediaGallery.shared.cs new file mode 100644 index 000000000000..7b903c620386 --- /dev/null +++ b/src/Essentials/src/MediaGallery/MediaGallery.shared.cs @@ -0,0 +1,247 @@ +#nullable enable +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Maui.ApplicationModel; +using Microsoft.Maui.Storage; + +namespace Microsoft.Maui.Media +{ + /// + /// Performs operations with media files. + /// + public interface IMediaGallery + { + /// + /// Gets a value indicating whether is supported on this platform. + /// + bool IsSupported { get; } + + /// + /// Gets a value indicating whether capturing media is supported on this device. + /// + /// Media file type use for capture + /// + bool CheckCaptureSupport(MediaFileType type); + + /// + /// Opens the camera to take a photo or video. + /// + /// Media file type use for capture + /// A token that can be used for cancelling the operation. + /// A object containing details of the captured photo. + Task CaptureAsync(MediaFileType type, CancellationToken token = default); + + /// + /// Opens media files Picker + /// + /// + /// + /// Media files selected by a user. + Task PickAsync(int selectionLimit = 1, params MediaFileType[] types); + + /// Media file request to pick. + /// A token that can be used for cancelling the operation. + /// + Task PickAsync(MediaPickRequest request, CancellationToken token = default); + + /// + /// + /// + /// + MultiPickingBehaviour GetMultiPickingBehaviour(); + + /// + /// Saves a media file with metadata + /// + /// Type of media file to save. + /// The stream to output the file to. + /// The name of the saved file including the extension. + /// A task representing the asynchronous save operation. + Task SaveAsync(MediaFileType type, Stream fileStream, string fileName); + + /// + /// + /// + /// + /// A byte array to save to the file. + /// + /// + Task SaveAsync(MediaFileType type, byte[] data, string fileName); + + /// + /// + /// + /// + /// Full path to a local file. + /// + Task SaveAsync(MediaFileType type, string filePath); + } + + /// + public static class MediaGallery + { + static IMediaGallery? DefaultImplementation; + + /// + public static bool CheckCaptureSupport(MediaFileType type) + => Default.CheckCaptureSupport(type); + + /// + public static Task CaptureAsync(MediaFileType type, CancellationToken token = default) + => Default.CaptureAsync(type, token); + + /// + public static Task PickAsync(int selectionLimit = 1, params MediaFileType[] types) + => Default.PickAsync(selectionLimit, types); + + /// + public static Task PickAsync(MediaPickRequest request, CancellationToken token = default) + => Default.PickAsync(request, token); + + /// + public static MultiPickingBehaviour GetMultiPickingBehaviour() + => Default.GetMultiPickingBehaviour(); + + /// + public static Task SaveAsync(MediaFileType type, Stream fileStream, string fileName) + => Default.SaveAsync(type, fileStream, fileName); + + /// + public static Task SaveAsync(MediaFileType type, byte[] data, string fileName) + => Default.SaveAsync(type, data, fileName); + + /// + public static Task SaveAsync(MediaFileType type, string filePath) + => Default.SaveAsync(type, filePath); + + /// + /// Provides the default implementation for static usage of this API. + /// + public static IMediaGallery Default => + DefaultImplementation ??= new MediaGalleryImplementation(); + + internal static void SetDefault(IMediaGallery? implementation) => + DefaultImplementation = implementation; + } + + + partial class MediaGalleryImplementation : IMediaGallery + { + const string cacheDir = "MediaGalleryCacheDir"; + + public async Task CaptureAsync(MediaFileType type, CancellationToken token = default) + { + await CheckPossibilityCamera(type); + return new MediaFilesResult(await PlatformCaptureAsync(type, token)); + } + + public Task PickAsync(int selectionLimit = 1, params MediaFileType[] types) + => PickAsync(new MediaPickRequest(null, selectionLimit, default, types), default); + + public async Task PickAsync(MediaPickRequest? request, CancellationToken token = default) + { + CheckSupport(); + + if (request == null) + throw new ArgumentNullException(nameof(request)); + + return new MediaFilesResult(await PlatformPickAsync(request, token).ConfigureAwait(false)); + } + + public async Task SaveAsync(MediaFileType type, Stream fileStream, string fileName) + { + await CheckPossibilitySave(); + if (fileStream == null) + throw new ArgumentNullException(nameof(fileStream)); + CheckFileName(fileName); + + await PlatformSaveAsync(type, fileStream, fileName).ConfigureAwait(false); + } + + public async Task SaveAsync(MediaFileType type, byte[] data, string fileName) + { + await CheckPossibilitySave(); + if (!(data?.Length > 0)) + throw new ArgumentNullException(nameof(data)); + CheckFileName(fileName); + + await PlatformSaveAsync(type, data, fileName).ConfigureAwait(false); + } + + public async Task SaveAsync(MediaFileType type, string filePath) + { + await CheckPossibilitySave(); + if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath)) + throw new ArgumentException(nameof(filePath)); + + await PlatformSaveAsync(type, filePath).ConfigureAwait(false); + } + + async Task CheckPossibilitySave() + { + CheckSupport(); + var status = await Permissions.CheckStatusAsync(); + + if (status != PermissionStatus.Granted) + throw new PermissionException($"{nameof(Permissions.Camera)} permission was not granted: {status}"); + } + + async Task CheckPossibilityCamera(MediaFileType type) + { + CheckSupport(); + if (!CheckCaptureSupport(type)) + throw new FeatureNotSupportedException(); + + + var status = await Permissions.CheckStatusAsync(); + + if (status != PermissionStatus.Granted) + throw new PermissionException($"{nameof(Permissions.Camera)} permission was not granted: {status}"); + } + + void CheckSupport() + { + if (!IsSupported) + throw new NotImplementedInReferenceAssemblyException(); + } + + static void CheckFileName(string fileName) + { + if (string.IsNullOrWhiteSpace(fileName)) + throw new ArgumentNullException(nameof(fileName)); + } + + static string GetNewImageName(string? imgName = null) + => GetNewImageName(DateTime.Now, imgName); + + static string GetNewImageName(DateTime val, string? imgName = null) + => $"{imgName ?? "IMG"}_{val:yyyyMMdd_HHmmss}"; + + static string GetMimeType(MediaFileType type) + => type switch + { + MediaFileType.Image => FileMimeTypes.ImageAll, + MediaFileType.Video => FileMimeTypes.VideoAll, + _ => string.Empty, + }; + + static void DeleteFile(string filePath) + { + if (!string.IsNullOrWhiteSpace(filePath) && File.Exists(filePath)) + File.Delete(filePath); + } + + static string GetFilePath(string fileName) + { + fileName = fileName.Trim(); + var dirPath = Path.Combine(FileSystem.CacheDirectory, cacheDir); + var filePath = Path.Combine(dirPath, fileName); + + if (!Directory.Exists(dirPath)) + Directory.CreateDirectory(dirPath); + return filePath; + } + } +} diff --git a/src/Essentials/src/MediaGallery/MediaGallery.tizen.cs b/src/Essentials/src/MediaGallery/MediaGallery.tizen.cs new file mode 100644 index 000000000000..afeac478eec3 --- /dev/null +++ b/src/Essentials/src/MediaGallery/MediaGallery.tizen.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Maui.ApplicationModel; +using Microsoft.Maui.Devices; +using Microsoft.Maui.Storage; + +namespace Microsoft.Maui.Media +{ + partial class MediaGalleryImplementation + { + public bool IsSupported => false; + + public bool CheckCaptureSupport(MediaFileType type) => true; + + public Task> PlatformCaptureAsync(MediaFileType type, CancellationToken token = default) + { + Permissions.EnsureDeclared(); + + await Permissions.EnsureGrantedAsync(); + + var tcs = new TaskCompletionSource(); + + var appControl = new AppControl(); + appControl.Operation = type == MediaFileType.Image ? AppControlOperations.ImageCapture : AppControlOperations.VideoCapture; + appControl.LaunchMode = AppControlLaunchMode.Group; + + var appId = AppControl.GetMatchedApplicationIds(appControl)?.FirstOrDefault(); + + if (!string.IsNullOrEmpty(appId)) + appControl.ApplicationId = appId; + + AppControl.SendLaunchRequest(appControl, (request, reply, result) => + { + if (result == AppControlReplyResult.Succeeded && reply.ExtraData.Count() > 0) + { + var file = reply.ExtraData.Get>(AppControlData.Selected)?.FirstOrDefault(); + tcs.TrySetResult(new FileResult(file)); + } + else + { + tcs.TrySetCanceled(); + } + }); + + var res = await tcs.Task + return res == null ? null : new[] { new MediaFileResult(res) }; + ; + } + + public Task> PlatformPickAsync(MediaPickRequest request, CancellationToken token = default) + { + List defaultTypes = new(); + + if (request.Types.Contains(MediaFileType.Image)) + defaultTypes.AddRange(FilePickerFileType.Images.Value); + if (request.Types.Contains(MediaFileType.Video)) + defaultTypes.AddRange(FilePickerFileType.Videos.Value); + + var res = await FilePicker.PickAsync(new PickOptions + { + PickerTitle = options?.Title, + FileTypes = new FilePickerFileType( + new Dictionary>() { DevicePlatform.Tizen, defaultTypes }) + }); + return res == null ? null : new[] { new MediaFileResult(res) }; + } + + public MultiPickingBehaviour GetMultiPickingBehaviour() + => throw new NotImplementedInReferenceAssemblyException(); + + public Task PlatformSaveAsync(MediaFileType type, Stream fileStream, string fileName) + => throw new NotImplementedInReferenceAssemblyException(); + + public Task PlatformSaveAsync(MediaFileType type, byte[] data, string fileName) + => throw new NotImplementedInReferenceAssemblyException(); + + public Task PlatformSaveAsync(MediaFileType type, string filePath) + => throw new NotImplementedInReferenceAssemblyException(); + + } +} diff --git a/src/Essentials/src/MediaPicker/MediaPicker.uwp.cs b/src/Essentials/src/MediaGallery/MediaGallery.uwp.cs similarity index 59% rename from src/Essentials/src/MediaPicker/MediaPicker.uwp.cs rename to src/Essentials/src/MediaGallery/MediaGallery.uwp.cs index 468da31870a1..ce70a2f8b38c 100644 --- a/src/Essentials/src/MediaPicker/MediaPicker.uwp.cs +++ b/src/Essentials/src/MediaGallery/MediaGallery.uwp.cs @@ -4,7 +4,11 @@ // - https://github.com/richardrigutins using System; +using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Threading; using System.Threading.Tasks; using Microsoft.Maui.ApplicationModel; using Microsoft.Maui.Storage; @@ -18,64 +22,103 @@ namespace Microsoft.Maui.Media { - partial class MediaPickerImplementation : IMediaPicker + partial class MediaGalleryImplementation { - public bool IsCaptureSupported - => true; + public bool IsSupported => true; - public Task PickPhotoAsync(MediaPickerOptions options) - => PickAsync(options, true); + public bool CheckCaptureSupport(MediaFileType type) => true; - public Task PickVideoAsync(MediaPickerOptions options) - => PickAsync(options, false); + public async Task> PlatformCaptureAsync(MediaFileType type, CancellationToken token = default) + { + var captureUi = new WinUICameraCaptureUI(); + var photo = type == MediaFileType.Image; + + if (photo) + captureUi.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Jpeg; + else + captureUi.VideoSettings.Format = CameraCaptureUIVideoFormat.Mp4; + + var file = await captureUi.CaptureFileAsync(photo ? CameraCaptureUIMode.Photo : CameraCaptureUIMode.Video); - public async Task PickAsync(MediaPickerOptions options, bool photo) + if (file != null) + return new[] { new MediaFileResult(file) }; + return null; + } + + public async Task> PlatformPickAsync(MediaPickRequest request, CancellationToken token = default) { var picker = new FileOpenPicker(); var hwnd = WindowStateManager.Default.GetActiveWindowHandle(true); WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd); - var defaultTypes = photo ? FilePickerFileType.Images.Value : FilePickerFileType.Videos.Value; + List defaultTypes = new(); + + if (request.Types.Contains(MediaFileType.Image)) + defaultTypes.AddRange(FilePickerFileType.Images.Value); + if (request.Types.Contains(MediaFileType.Video)) + defaultTypes.AddRange(FilePickerFileType.Videos.Value); // set picker properties foreach (var filter in defaultTypes.Select(t => t.TrimStart('*'))) picker.FileTypeFilter.Add(filter); - picker.SuggestedStartLocation = photo ? PickerLocationId.PicturesLibrary : PickerLocationId.VideosLibrary; + picker.SuggestedStartLocation = request.Types.Contains(MediaFileType.Image) ? PickerLocationId.PicturesLibrary : PickerLocationId.VideosLibrary; picker.ViewMode = PickerViewMode.Thumbnail; - // show the picker - var result = await picker.PickSingleFileAsync(); + if (request.SelectionLimit > 1) + { + var result = await picker.PickMultipleFilesAsync(); + return result?.Select(a => new MediaFileResult(a)); + } + else + { + var result = await picker.PickSingleFileAsync(); - // cancelled - if (result is null) - return null; + if (result == null) + return null; - // picked - return new FileResult(result); + return new[] { new MediaFileResult(result) }; + } } + + public MultiPickingBehaviour GetMultiPickingBehaviour() + => MultiPickingBehaviour.UnLimit; - public Task CapturePhotoAsync(MediaPickerOptions options) - => CaptureAsync(options, true); - - public Task CaptureVideoAsync(MediaPickerOptions options) - => CaptureAsync(options, false); + public async Task PlatformSaveAsync(MediaFileType type, Stream fileStream, string fileName) + { + var file = await GetStorageFile(type, fileName); + using var stream = await file.OpenStreamForWriteAsync(); + await fileStream.CopyToAsync(stream); + stream.Close(); + } - public async Task CaptureAsync(MediaPickerOptions options, bool photo) + public async Task PlatformSaveAsync(MediaFileType type, byte[] data, string fileName) { - var captureUi = new WinUICameraCaptureUI(); + var file = await GetStorageFile(type, fileName); + var buffer = WindowsRuntimeBuffer.Create(data, 0, data.Length, data.Length); + await FileIO.WriteBufferAsync(file, buffer); + } - if (photo) - captureUi.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Jpeg; - else - captureUi.VideoSettings.Format = CameraCaptureUIVideoFormat.Mp4; + public async Task PlatformSaveAsync(MediaFileType type, string filePath) + { + using var fileStream = File.OpenRead(filePath); + await PlatformSaveAsync(type, fileStream, Path.GetFileName(filePath)); + } - var file = await captureUi.CaptureFileAsync(photo ? CameraCaptureUIMode.Photo : CameraCaptureUIMode.Video); + static async Task GetStorageFile(MediaFileType type, string fileName) + { + var albumFolder = await GetAlbumFolder(type, AppInfo.Name); + return await albumFolder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName); + } - if (file is not null) - return new FileResult(file); + static async Task GetAlbumFolder(MediaFileType type, string albumName) + { + var mediaFolder = type == MediaFileType.Image + ? KnownFolders.PicturesLibrary + : KnownFolders.VideosLibrary; - return null; + var folder = (await mediaFolder.GetFoldersAsync())?.FirstOrDefault(a => a.Name == albumName); + return folder ?? await mediaFolder.CreateFolderAsync(albumName); } class WinUICameraCaptureUI diff --git a/src/Essentials/src/MediaGallery/MediaPickRequest.shared.cs b/src/Essentials/src/MediaGallery/MediaPickRequest.shared.cs new file mode 100644 index 000000000000..b0bd7807572b --- /dev/null +++ b/src/Essentials/src/MediaGallery/MediaPickRequest.shared.cs @@ -0,0 +1,50 @@ +using System.Linq; +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Media +{ + /// + /// Request for picking a media file + /// + public record MediaPickRequest + { + /// + /// + /// + /// + /// + public MediaPickRequest( + string title = null, + int selectionLimit = 1, + Rect presentationSourceBounds = default, + params MediaFileType[] types) + { + Title = title; + SelectionLimit = selectionLimit > 0 ? selectionLimit : 1; + PresentationSourceBounds = presentationSourceBounds; + Types = types?.Length > 0 + ? types.Distinct().ToArray() + : new[] { MediaFileType.Image, MediaFileType.Video }; + } + + /// + /// Gets or sets the title that is displayed when picking media. Only for Android below API 33 + /// + public string Title { get; } + + /// + /// Maximum count of files to pick. On Android below API 33 the option just sets multiple pick allowed. + /// + public int SelectionLimit { get; } + + /// + /// Gets or sets the source rectangle to display the Picker UI from. This is only used on iPad currently. + /// + public Rect PresentationSourceBounds { get; } + + /// + /// Media file types available for picking. + /// + public MediaFileType[] Types { get; } + } +} \ No newline at end of file diff --git a/src/Essentials/src/MediaGallery/MultiPickingBehaviour.shared.cs b/src/Essentials/src/MediaGallery/MultiPickingBehaviour.shared.cs new file mode 100644 index 000000000000..87cd498608c1 --- /dev/null +++ b/src/Essentials/src/MediaGallery/MultiPickingBehaviour.shared.cs @@ -0,0 +1,21 @@ +namespace Microsoft.Maui.Media +{ + /// + /// Describes the behavior of a device ui when multi-picking files + /// + public enum MultiPickingBehaviour + { + /// + /// Сan select only one file at a time + /// + AlwaysSingle, + /// + /// Can select limited count of files + /// + Limit, + /// + /// Can select unlimited count of files + /// + UnLimit, + } +} \ No newline at end of file diff --git a/src/Essentials/src/MediaPicker/MediaPicker.android.cs b/src/Essentials/src/MediaPicker/MediaPicker.android.cs deleted file mode 100644 index 2818d328078f..000000000000 --- a/src/Essentials/src/MediaPicker/MediaPicker.android.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Threading.Tasks; -using Android.App; -using Android.Content; -using Android.Content.PM; -using Android.Provider; -using Microsoft.Maui.ApplicationModel; -using Microsoft.Maui.Storage; -using AndroidUri = Android.Net.Uri; - -namespace Microsoft.Maui.Media -{ - partial class MediaPickerImplementation : IMediaPicker - { - public bool IsCaptureSupported - => Application.Context.PackageManager.HasSystemFeature(PackageManager.FeatureCameraAny); - - public Task PickPhotoAsync(MediaPickerOptions options) - => PickAsync(options, true); - - public Task PickVideoAsync(MediaPickerOptions options) - => PickAsync(options, false); - - public async Task PickAsync(MediaPickerOptions options, bool photo) - { - var intent = new Intent(Intent.ActionGetContent); - intent.SetType(photo ? FileMimeTypes.ImageAll : FileMimeTypes.VideoAll); - - var pickerIntent = Intent.CreateChooser(intent, options?.Title); - - try - { - string path = null; - void OnResult(Intent intent) - { - // 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. - - path = FileSystemUtils.EnsurePhysicalPath(intent.Data); - } - - await IntermediateActivity.StartAsync(pickerIntent, PlatformUtils.requestCodeMediaPicker, onResult: OnResult); - - return new FileResult(path); - } - catch (OperationCanceledException) - { - return null; - } - } - - public Task CapturePhotoAsync(MediaPickerOptions options) - => CaptureAsync(options, true); - - public Task CaptureVideoAsync(MediaPickerOptions options) - => CaptureAsync(options, false); - - public async Task CaptureAsync(MediaPickerOptions options, bool photo) - { - if (!IsCaptureSupported) - throw new FeatureNotSupportedException(); - - await Permissions.EnsureGrantedAsync(); - // StorageWrite no longer exists starting from Android API 33 - if (!OperatingSystem.IsAndroidVersionAtLeast(33)) - await Permissions.EnsureGrantedAsync(); - - - var capturePhotoIntent = new Intent(photo ? MediaStore.ActionImageCapture : MediaStore.ActionVideoCapture); - - if (!PlatformUtils.IsIntentSupported(capturePhotoIntent)) - throw new FeatureNotSupportedException($"Either there was no camera on the device or '{capturePhotoIntent.Action}' was not added to the element in the app's manifest file. See more: https://developer.android.com/about/versions/11/privacy/package-visibility"); - - capturePhotoIntent.AddFlags(ActivityFlags.GrantReadUriPermission); - capturePhotoIntent.AddFlags(ActivityFlags.GrantWriteUriPermission); - - try - { - var activity = ActivityStateManager.Default.GetCurrentActivity(true); - - // Create the temporary file - var ext = photo - ? FileExtensions.Jpg - : FileExtensions.Mp4; - var fileName = Guid.NewGuid().ToString("N") + ext; - var tmpFile = FileSystemUtils.GetTemporaryFile(Application.Context.CacheDir, fileName); - - // Set up the content:// uri - AndroidUri outputUri = null; - void OnCreate(Intent intent) - { - // Android requires that using a file provider to get a content:// uri for a file to be called - // from within the context of the actual activity which may share that uri with another intent - // it launches. - - outputUri ??= FileProvider.GetUriForFile(tmpFile); - - intent.PutExtra(MediaStore.ExtraOutput, outputUri); - } - - // Start the capture process - await IntermediateActivity.StartAsync(capturePhotoIntent, PlatformUtils.requestCodeMediaCapture, OnCreate); - - // Return the file that we just captured - return new FileResult(tmpFile.AbsolutePath); - } - catch (OperationCanceledException) - { - return null; - } - } - } -} diff --git a/src/Essentials/src/MediaPicker/MediaPicker.ios.cs b/src/Essentials/src/MediaPicker/MediaPicker.ios.cs deleted file mode 100644 index b2dbd36c1e6c..000000000000 --- a/src/Essentials/src/MediaPicker/MediaPicker.ios.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Foundation; -using Microsoft.Maui.ApplicationModel; -using Microsoft.Maui.Devices; -using Microsoft.Maui.Storage; -using MobileCoreServices; -using Photos; -using UIKit; - -namespace Microsoft.Maui.Media -{ - partial class MediaPickerImplementation : IMediaPicker - { - static UIImagePickerController picker; - - public bool IsCaptureSupported - => UIImagePickerController.IsSourceTypeAvailable(UIImagePickerControllerSourceType.Camera); - - public Task PickPhotoAsync(MediaPickerOptions options) - => PhotoAsync(options, true, true); - - public Task CapturePhotoAsync(MediaPickerOptions options) - { - if (!IsCaptureSupported) - throw new FeatureNotSupportedException(); - - return PhotoAsync(options, true, false); - } - - public Task PickVideoAsync(MediaPickerOptions options) - => PhotoAsync(options, false, true); - - public Task CaptureVideoAsync(MediaPickerOptions options) - { - if (!IsCaptureSupported) - throw new FeatureNotSupportedException(); - - return PhotoAsync(options, false, false); - } - - public async Task PhotoAsync(MediaPickerOptions options, bool photo, bool pickExisting) - { -#pragma warning disable CA1416 // TODO: UIImagePickerControllerSourceType.PhotoLibrary, UTType.Image, UTType.Movie is supported on ios version 14 and above -#pragma warning disable CA1422 // Validate platform compatibility - var sourceType = pickExisting ? UIImagePickerControllerSourceType.PhotoLibrary : UIImagePickerControllerSourceType.Camera; - var mediaType = photo ? UTType.Image : UTType.Movie; -#pragma warning restore CA1422 // Validate platform compatibility -#pragma warning restore CA1416 - - if (!UIImagePickerController.IsSourceTypeAvailable(sourceType)) - throw new FeatureNotSupportedException(); - if (!UIImagePickerController.AvailableMediaTypes(sourceType).Contains(mediaType)) - throw new FeatureNotSupportedException(); - - if (!photo && !pickExisting) - await Permissions.EnsureGrantedAsync(); - - // Check if picking existing or not and ensure permission accordingly as they can be set independently from each other - if (pickExisting && !OperatingSystem.IsIOSVersionAtLeast(11, 0)) -#pragma warning disable CA1416 // TODO: Permissions.Photos is supported on ios version 14 and above - await Permissions.EnsureGrantedAsync(); -#pragma warning restore CA1416 - - if (!pickExisting) - await Permissions.EnsureGrantedAsync(); - - var vc = WindowStateManager.Default.GetCurrentUIViewController(true); - - picker = new UIImagePickerController(); - picker.SourceType = sourceType; - picker.MediaTypes = new string[] { mediaType }; - picker.AllowsEditing = false; - if (!photo && !pickExisting) - picker.CameraCaptureMode = UIImagePickerControllerCameraCaptureMode.Video; - - if (!string.IsNullOrWhiteSpace(options?.Title)) - picker.Title = options.Title; - - if (DeviceInfo.Current.Idiom == DeviceIdiom.Tablet && picker.PopoverPresentationController != null && vc.View != null) - picker.PopoverPresentationController.SourceRect = vc.View.Bounds; - - var tcs = new TaskCompletionSource(picker); - picker.Delegate = new PhotoPickerDelegate - { - CompletedHandler = async info => - { - GetFileResult(info, tcs); - await vc.DismissViewControllerAsync(true); - } - }; - - if (picker.PresentationController != null) - { - picker.PresentationController.Delegate = - new UIPresentationControllerDelegate(() => GetFileResult(null, tcs)); - } - - await vc.PresentViewControllerAsync(picker, true); - - var result = await tcs.Task; - - picker?.Dispose(); - picker = null; - - return result; - } - - static void GetFileResult(NSDictionary info, TaskCompletionSource tcs) - { - try - { - tcs.TrySetResult(DictionaryToMediaFile(info)); - } - catch (Exception ex) - { - tcs.TrySetException(ex); - } - } - - static FileResult DictionaryToMediaFile(NSDictionary info) - { - if (info == null) - return null; - - PHAsset phAsset = null; - NSUrl assetUrl = null; - - if (OperatingSystem.IsIOSVersionAtLeast(11, 0)) - { - assetUrl = info[UIImagePickerController.ImageUrl] as NSUrl; - - // Try the MediaURL sometimes used for videos - if (assetUrl == null) - assetUrl = info[UIImagePickerController.MediaURL] as NSUrl; - - if (assetUrl != null) - { - if (!assetUrl.Scheme.Equals("assets-library", StringComparison.OrdinalIgnoreCase)) - return new UIDocumentFileResult(assetUrl); -#pragma warning disable CA1416 // TODO: 'UIImagePickerController.PHAsset' is only supported on: 'ios' from version 11.0 to 14.0 -#pragma warning disable CA1422 // Validate platform compatibility - phAsset = info.ValueForKey(UIImagePickerController.PHAsset) as PHAsset; -#pragma warning restore CA1422 // Validate platform compatibility -#pragma warning restore CA1416 - } - } - -#if !MACCATALYST -#pragma warning disable CA1416 // TODO: 'UIImagePickerController.ReferenceUrl' is unsupported on 'ios' 11.0 and later -#pragma warning disable CA1422 // Validate platform compatibility - if (phAsset == null) - { - assetUrl = info[UIImagePickerController.ReferenceUrl] as NSUrl; - - if (assetUrl != null) - phAsset = PHAsset.FetchAssets(new NSUrl[] { assetUrl }, null)?.LastObject as PHAsset; - } -#pragma warning restore CA1422 // Validate platform compatibility -#pragma warning restore CA1416 // 'PHAsset.FetchAssets(NSUrl[], PHFetchOptions?)' is unsupported on 'ios' 11.0 and later -#endif - - if (phAsset == null || assetUrl == null) - { - var img = info.ValueForKey(UIImagePickerController.OriginalImage) as UIImage; - - if (img != null) - return new UIImageFileResult(img); - } - - if (phAsset == null || assetUrl == null) - return null; -#pragma warning disable CA1416 // https://github.com/xamarin/xamarin-macios/issues/14619 -#pragma warning disable CA1422 // Validate platform compatibility - string originalFilename = PHAssetResource.GetAssetResources(phAsset).FirstOrDefault()?.OriginalFilename; -#pragma warning restore CA1422 // Validate platform compatibility -#pragma warning restore CA1416 - return new PHAssetFileResult(assetUrl, phAsset, originalFilename); - } - - class PhotoPickerDelegate : UIImagePickerControllerDelegate - { - public Action CompletedHandler { get; set; } - - public override void FinishedPickingMedia(UIImagePickerController picker, NSDictionary info) => - CompletedHandler?.Invoke(info); - - public override void Canceled(UIImagePickerController picker) => - CompletedHandler?.Invoke(null); - } - } -} diff --git a/src/Essentials/src/MediaPicker/MediaPicker.macos.cs b/src/Essentials/src/MediaPicker/MediaPicker.macos.cs deleted file mode 100644 index b3d0c7371962..000000000000 --- a/src/Essentials/src/MediaPicker/MediaPicker.macos.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace Microsoft.Maui.Media -{ - partial class MediaPickerImplementation : IMediaPicker - { - public bool PlatformIsCaptureSupported - => false; - - public async Task PlatformPickPhotoAsync(MediaPickerOptions options) - => new FileResult(await FilePicker.PickAsync(new PickOptions - { - FileTypes = FilePickerFileType.Images - })); - - public Task PlatformCapturePhotoAsync(MediaPickerOptions options) - => PlatformPickPhotoAsync(options); - - public async Task PlatformPickVideoAsync(MediaPickerOptions options) - => new FileResult(await FilePicker.PickAsync(new PickOptions - { - FileTypes = FilePickerFileType.Videos - })); - - public Task PlatformCaptureVideoAsync(MediaPickerOptions options) - => PlatformPickVideoAsync(options); - } -} diff --git a/src/Essentials/src/MediaPicker/MediaPicker.netstandard.watchos.tvos.cs b/src/Essentials/src/MediaPicker/MediaPicker.netstandard.watchos.tvos.cs deleted file mode 100644 index 437f65d1f2d4..000000000000 --- a/src/Essentials/src/MediaPicker/MediaPicker.netstandard.watchos.tvos.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.Maui.ApplicationModel; -using Microsoft.Maui.Storage; - -namespace Microsoft.Maui.Media -{ - partial class MediaPickerImplementation : IMediaPicker - { - public bool IsCaptureSupported => - throw new NotImplementedInReferenceAssemblyException(); - - public Task PickPhotoAsync(MediaPickerOptions options) => - throw new NotImplementedInReferenceAssemblyException(); - - public Task CapturePhotoAsync(MediaPickerOptions options) => - throw new NotImplementedInReferenceAssemblyException(); - - public Task PickVideoAsync(MediaPickerOptions options) => - throw new NotImplementedInReferenceAssemblyException(); - - public Task CaptureVideoAsync(MediaPickerOptions options) => - throw new NotImplementedInReferenceAssemblyException(); - } -} diff --git a/src/Essentials/src/MediaPicker/MediaPicker.shared.cs b/src/Essentials/src/MediaPicker/MediaPicker.shared.cs index 803b4bbf01bf..68e16d74a8cf 100644 --- a/src/Essentials/src/MediaPicker/MediaPicker.shared.cs +++ b/src/Essentials/src/MediaPicker/MediaPicker.shared.cs @@ -1,6 +1,8 @@ #nullable enable +using System; +using System.ComponentModel; +using System.Linq; using System.Threading.Tasks; -using Microsoft.Maui.ApplicationModel; using Microsoft.Maui.Storage; namespace Microsoft.Maui.Media @@ -8,11 +10,13 @@ namespace Microsoft.Maui.Media /// /// The MediaPicker API lets a user pick or take a photo or video on the device. /// + [EditorBrowsable(EditorBrowsableState.Never), Obsolete(MediaPicker.ObsoleteMessage)] public interface IMediaPicker { /// /// Gets a value indicating whether capturing media is supported on this device. /// + [Obsolete(MediaPicker.ObsoleteMessage)] bool IsCaptureSupported { get; } /// @@ -20,38 +24,46 @@ public interface IMediaPicker /// /// Pick options to use. /// A object containing details of the picked photo. - Task PickPhotoAsync(MediaPickerOptions? options = null); + [Obsolete(MediaPicker.ObsoleteMessage)] + Task PickPhotoAsync(MediaPickerOptions? options = null); /// /// Opens the camera to take a photo. /// /// Pick options to use. /// A object containing details of the captured photo. - Task CapturePhotoAsync(MediaPickerOptions? options = null); + [Obsolete(MediaPicker.ObsoleteMessage)] + Task CapturePhotoAsync(MediaPickerOptions? options = null); /// /// Opens the media browser to select a video. /// /// Pick options to use. /// A object containing details of the picked video. - Task PickVideoAsync(MediaPickerOptions? options = null); + [Obsolete(MediaPicker.ObsoleteMessage)] + Task PickVideoAsync(MediaPickerOptions? options = null); /// /// Opens the camera to take a video. /// /// Pick options to use. /// A object containing details of the captured video. - Task CaptureVideoAsync(MediaPickerOptions? options = null); + [Obsolete(MediaPicker.ObsoleteMessage)] + Task CaptureVideoAsync(MediaPickerOptions? options = null); } /// /// The MediaPicker API lets a user pick or take a photo or video on the device. /// + [EditorBrowsable(EditorBrowsableState.Never), Obsolete(MediaPicker.ObsoleteMessage)] public static class MediaPicker { + internal const string ObsoleteMessage = "Use MediaGallery"; + /// /// Gets a value indicating whether capturing media is supported on this device. /// + [Obsolete(MediaPicker.ObsoleteMessage)] public static bool IsCaptureSupported => Default.IsCaptureSupported; @@ -60,7 +72,8 @@ public static class MediaPicker /// /// Pick options to use. /// A object containing details of the picked photo. - public static Task PickPhotoAsync(MediaPickerOptions? options = null) => + [Obsolete(MediaPicker.ObsoleteMessage)] + public static Task PickPhotoAsync(MediaPickerOptions? options = null) => Default.PickPhotoAsync(options); /// @@ -68,7 +81,8 @@ public static Task PickPhotoAsync(MediaPickerOptions? options = null /// /// Pick options to use. /// A object containing details of the captured photo. - public static Task CapturePhotoAsync(MediaPickerOptions? options = null) => + [Obsolete(MediaPicker.ObsoleteMessage)] + public static Task CapturePhotoAsync(MediaPickerOptions? options = null) => Default.CapturePhotoAsync(options); /// @@ -76,7 +90,8 @@ public static Task CapturePhotoAsync(MediaPickerOptions? options = n /// /// Pick options to use. /// A object containing details of the picked video. - public static Task PickVideoAsync(MediaPickerOptions? options = null) => + [Obsolete(MediaPicker.ObsoleteMessage)] + public static Task PickVideoAsync(MediaPickerOptions? options = null) => Default.PickVideoAsync(options); /// @@ -84,7 +99,8 @@ public static Task PickVideoAsync(MediaPickerOptions? options = null /// /// Pick options to use. /// A object containing details of the captured video. - public static Task CaptureVideoAsync(MediaPickerOptions? options = null) => + [Obsolete(MediaPicker.ObsoleteMessage)] + public static Task CaptureVideoAsync(MediaPickerOptions? options = null) => Default.CaptureVideoAsync(options); static IMediaPicker? defaultImplementation; @@ -92,9 +108,11 @@ public static Task CaptureVideoAsync(MediaPickerOptions? options = n /// /// Provides the default implementation for static usage of this API. /// + [Obsolete(MediaPicker.ObsoleteMessage)] public static IMediaPicker Default => defaultImplementation ??= new MediaPickerImplementation(); + [Obsolete(MediaPicker.ObsoleteMessage)] internal static void SetDefault(IMediaPicker? implementation) => defaultImplementation = implementation; } @@ -102,12 +120,53 @@ internal static void SetDefault(IMediaPicker? implementation) => /// /// Pick options for picking media from the device. /// + [EditorBrowsable(EditorBrowsableState.Never), Obsolete(MediaPicker.ObsoleteMessage)] public class MediaPickerOptions { /// /// Gets or sets the title that is displayed when picking media. /// /// This title is not guaranteed to be shown on all operating systems. + [Obsolete(MediaPicker.ObsoleteMessage)] public string? Title { get; set; } } + + [EditorBrowsable(EditorBrowsableState.Never), Obsolete(MediaPicker.ObsoleteMessage)] + class MediaPickerImplementation : IMediaPicker + { + [Obsolete(MediaPicker.ObsoleteMessage)] + public bool IsCaptureSupported + => MediaGallery.CheckCaptureSupport(MediaFileType.Image) + && MediaGallery.CheckCaptureSupport(MediaFileType.Video); + + [Obsolete(MediaPicker.ObsoleteMessage)] + public async Task PickPhotoAsync(MediaPickerOptions? options) + { + var res = await MediaGallery.PickAsync( + new(options?.Title, 1, default, MediaFileType.Image)); + return res?.Files?.FirstOrDefault(); + } + + [Obsolete(MediaPicker.ObsoleteMessage)] + public async Task PickVideoAsync(MediaPickerOptions? options) + { + var res = await MediaGallery.PickAsync( + new(options?.Title, 1, default, MediaFileType.Video)); + return res?.Files?.FirstOrDefault(); + } + + [Obsolete(MediaPicker.ObsoleteMessage)] + public async Task CapturePhotoAsync(MediaPickerOptions? options) + { + var res = await MediaGallery.CaptureAsync(MediaFileType.Image); + return res?.Files?.FirstOrDefault(); + } + + [Obsolete(MediaPicker.ObsoleteMessage)] + public async Task CaptureVideoAsync(MediaPickerOptions? options) + { + var res = await MediaGallery.CaptureAsync(MediaFileType.Video); + return res?.Files?.FirstOrDefault(); + } + } } diff --git a/src/Essentials/src/MediaPicker/MediaPicker.tizen.cs b/src/Essentials/src/MediaPicker/MediaPicker.tizen.cs deleted file mode 100644 index feeda4f4e552..000000000000 --- a/src/Essentials/src/MediaPicker/MediaPicker.tizen.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Maui.ApplicationModel; -using Microsoft.Maui.Storage; -using Tizen.Applications; - -namespace Microsoft.Maui.Media -{ - partial class MediaPickerImplementation : IMediaPicker - { - public bool IsCaptureSupported - => true; - - public async Task PickPhotoAsync(MediaPickerOptions options) - => await FilePicker.PickAsync(new PickOptions - { - PickerTitle = options?.Title, - FileTypes = FilePickerFileType.Images - }); - - public Task CapturePhotoAsync(MediaPickerOptions options) - => MediaAsync(options, true); - - public async Task PickVideoAsync(MediaPickerOptions options) - => await FilePicker.PickAsync(new PickOptions - { - PickerTitle = options?.Title, - FileTypes = FilePickerFileType.Videos - }); - - public Task CaptureVideoAsync(MediaPickerOptions options) - => MediaAsync(options, false); - - public async Task MediaAsync(MediaPickerOptions options, bool photo) - { - Permissions.EnsureDeclared(); - - await Permissions.EnsureGrantedAsync(); - - var tcs = new TaskCompletionSource(); - - var appControl = new AppControl(); - appControl.Operation = photo ? AppControlOperations.ImageCapture : AppControlOperations.VideoCapture; - appControl.LaunchMode = AppControlLaunchMode.Group; - - var appId = AppControl.GetMatchedApplicationIds(appControl)?.FirstOrDefault(); - - if (!string.IsNullOrEmpty(appId)) - appControl.ApplicationId = appId; - - AppControl.SendLaunchRequest(appControl, (request, reply, result) => - { - if (result == AppControlReplyResult.Succeeded && reply.ExtraData.Count() > 0) - { - var file = reply.ExtraData.Get>(AppControlData.Selected)?.FirstOrDefault(); - tcs.TrySetResult(new FileResult(file)); - } - else - { - tcs.TrySetCanceled(); - } - }); - - return await tcs.Task; - } - } -} diff --git a/src/Essentials/src/Permissions/Permissions.android.cs b/src/Essentials/src/Permissions/Permissions.android.cs index 4d745cdf5eec..26832b2f81c2 100644 --- a/src/Essentials/src/Permissions/Permissions.android.cs +++ b/src/Essentials/src/Permissions/Permissions.android.cs @@ -487,5 +487,13 @@ public partial class Vibrate : BasePlatformPermission public override (string androidPermission, bool isRuntime)[] RequiredPermissions => new (string, bool)[] { (Manifest.Permission.Vibrate, false) }; } + + public partial class SaveMediaPermission : BasePlatformPermission + { + public override (string androidPermission, bool isRuntime)[] RequiredPermissions + => (int)Build.VERSION.SdkInt >= 29 + ? Array.Empty<(string, bool)>() + : new (string, bool)[] { (Manifest.Permission.WriteExternalStorage, true) }; + } } } diff --git a/src/Essentials/src/Permissions/Permissions.ios.cs b/src/Essentials/src/Permissions/Permissions.ios.cs index fb2a1661f08f..eeb6084a3bc0 100644 --- a/src/Essentials/src/Permissions/Permissions.ios.cs +++ b/src/Essentials/src/Permissions/Permissions.ios.cs @@ -5,7 +5,9 @@ using AddressBook; using AVFoundation; using MediaPlayer; +using Photos; using Speech; +using UIKit; namespace Microsoft.Maui.ApplicationModel { @@ -316,5 +318,52 @@ internal static Task RequestSpeechPermission() } #pragma warning restore CA1416 } + + + public partial class SaveMediaPermission : BasePlatformPermission + { +#pragma warning disable CA1422 + /// + protected override Func> RequiredInfoPlistKeys => + () => OperatingSystem.IsIOSVersionAtLeast(14) + ? new[] { "NSPhotoLibraryAddUsageDescription" } + : new[] { "NSPhotoLibraryUsageDescription" }; + + /// + public override Task CheckStatusAsync() + { + EnsureDeclared(); + var auth = OperatingSystem.IsIOSVersionAtLeast(14) + ? PHPhotoLibrary.GetAuthorizationStatus(PHAccessLevel.AddOnly) + : PHPhotoLibrary.AuthorizationStatus; + + return Task.FromResult(Convert(auth)); + } + + /// + public override async Task RequestAsync() + { + var status = await CheckStatusAsync(); + if (status == PermissionStatus.Granted) + return status; + + var auth = OperatingSystem.IsIOSVersionAtLeast(14) + ? await PHPhotoLibrary.RequestAuthorizationAsync(PHAccessLevel.AddOnly) + : await PHPhotoLibrary.RequestAuthorizationAsync(); + + return Convert(auth); + } + + PermissionStatus Convert(PHAuthorizationStatus status) + => status switch + { + PHAuthorizationStatus.Authorized => PermissionStatus.Granted, + PHAuthorizationStatus.Limited => PermissionStatus.Granted, + PHAuthorizationStatus.Denied => PermissionStatus.Denied, + PHAuthorizationStatus.Restricted => PermissionStatus.Restricted, + _ => PermissionStatus.Unknown, + }; +#pragma warning restore CA1422 + } } } diff --git a/src/Essentials/src/Permissions/Permissions.netstandard.cs b/src/Essentials/src/Permissions/Permissions.netstandard.cs index 78da5bf1d41f..abb3f10a7afd 100644 --- a/src/Essentials/src/Permissions/Permissions.netstandard.cs +++ b/src/Essentials/src/Permissions/Permissions.netstandard.cs @@ -132,5 +132,9 @@ public partial class StorageWrite : BasePlatformPermission public partial class Vibrate : BasePlatformPermission { } + + public partial class SaveMediaPermission : BasePlatformPermission + { + } } } diff --git a/src/Essentials/src/Permissions/Permissions.shared.cs b/src/Essentials/src/Permissions/Permissions.shared.cs index df4b3852391b..5d80648a4262 100644 --- a/src/Essentials/src/Permissions/Permissions.shared.cs +++ b/src/Essentials/src/Permissions/Permissions.shared.cs @@ -293,5 +293,12 @@ public partial class StorageWrite public partial class Vibrate { } + + /// + /// Permission "NSPhotoLibraryAddUsageDescription" for iOS and "WRITE_EXTERNAL_STORAGE" for Android above 10 + /// + public partial class SaveMediaPermission + { + } } } diff --git a/src/Essentials/src/Permissions/Permissions.tizen.cs b/src/Essentials/src/Permissions/Permissions.tizen.cs index 9d33b770da8f..51cd9decc662 100644 --- a/src/Essentials/src/Permissions/Permissions.tizen.cs +++ b/src/Essentials/src/Permissions/Permissions.tizen.cs @@ -242,5 +242,9 @@ public partial class Vibrate : BasePlatformPermission public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges => new[] { ("http://tizen.org/privilege/haptic", false) }; } + + public partial class SaveMediaPermission : BasePlatformPermission + { + } } } diff --git a/src/Essentials/src/Permissions/Permissions.uwp.cs b/src/Essentials/src/Permissions/Permissions.uwp.cs index a05a59534ad2..afde7ec111e6 100644 --- a/src/Essentials/src/Permissions/Permissions.uwp.cs +++ b/src/Essentials/src/Permissions/Permissions.uwp.cs @@ -232,5 +232,9 @@ public partial class StorageWrite : BasePlatformPermission public partial class Vibrate : BasePlatformPermission { } + + public partial class SaveMediaPermission : BasePlatformPermission + { + } } } diff --git a/src/Essentials/src/Platform/ActivityResultCallback.android.cs b/src/Essentials/src/Platform/ActivityResultCallback.android.cs new file mode 100644 index 000000000000..05e2d0d0e603 --- /dev/null +++ b/src/Essentials/src/Platform/ActivityResultCallback.android.cs @@ -0,0 +1,55 @@ +using System; +using Android.Content; +using AndroidX.Activity.Result; +using AndroidX.Activity.Result.Contract; +using Object = Java.Lang.Object; + +namespace Microsoft.Maui.ApplicationModel +{ + class ActivityResultContractIntent : Object + { + public ActivityResultContractIntent(Func getIntent) => GetIntent = getIntent; + + public Func GetIntent { get; } + } + + class ActivityResultContractResult : Object + { + public ActivityResultContractResult(int resultCode, Intent intent) + { + ResultCode = resultCode; + Intent = intent; + } + + internal int ResultCode { get; } + internal Intent Intent { get; } + } + + class CommonActivityResultContract : ActivityResultContract + { + internal Intent CreateIntent(Context context, ActivityResultContractIntent input) + => input!.GetIntent.Invoke(context); + + public override Intent CreateIntent(Context context, Object input) + => CreateIntent(context, input as ActivityResultContractIntent); + + public override Object ParseResult(int resultCode, Intent intent) + => new ActivityResultContractResult(resultCode, intent); + } + + class CommonActivityResultCallback : Object, IActivityResultCallback + { + Action _action; + + public CommonActivityResultCallback(Action action) + { + _action = action; + } + + public void OnActivityResult(Object p0) + => OnActivityResult(p0 as ActivityResultContractResult); + + void OnActivityResult(ActivityResultContractResult result) + => _action?.Invoke(result); + } +} diff --git a/src/Essentials/src/Platform/Platform.shared.cs b/src/Essentials/src/Platform/Platform.shared.cs index 6ef20cb0544d..9bd1b9b6af68 100644 --- a/src/Essentials/src/Platform/Platform.shared.cs +++ b/src/Essentials/src/Platform/Platform.shared.cs @@ -3,7 +3,11 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Maui.Authentication; -using Microsoft.Maui.Devices.Sensors; +using Microsoft.Maui.Media; +#if ANDROID +using AndroidX.Activity.Result; +using AndroidX.AppCompat.App; +#endif namespace Microsoft.Maui.ApplicationModel { @@ -29,13 +33,14 @@ public static class Intent /// public static Android.Content.Context AppContext => Android.App.Application.Context; + public static ActivityResultLauncher? MediaPickerActivityLauncher; + // ActivityStateManager /// public static Android.App.Activity? CurrentActivity => ActivityStateManager.Default.GetCurrentActivity(); - /// public static event EventHandler? ActivityStateChanged { @@ -52,8 +57,16 @@ public static void Init(Android.App.Application application) => ActivityStateManager.Default.Init(application); /// - public static void Init(Android.App.Activity activity, Android.OS.Bundle? bundle) => + public static void Init(Android.App.Activity activity, Android.OS.Bundle? bundle) + { ActivityStateManager.Default.Init(activity, bundle); + if (activity is AppCompatActivity appCompatActivity) + { + MediaPickerActivityLauncher = appCompatActivity.RegisterForActivityResult( + new CommonActivityResultContract(), + new MediaGalleryActivityResultCallback()); + } + } // Permissions diff --git a/src/Essentials/src/Platform/PlatformUtils.android.cs b/src/Essentials/src/Platform/PlatformUtils.android.cs index aabcc96addfe..78543fefb982 100644 --- a/src/Essentials/src/Platform/PlatformUtils.android.cs +++ b/src/Essentials/src/Platform/PlatformUtils.android.cs @@ -2,15 +2,12 @@ using Android.App; using Android.Content; using Android.Content.PM; -using Android.OS; namespace Microsoft.Maui.ApplicationModel { static class PlatformUtils { internal const int requestCodeFilePicker = 11001; - internal const int requestCodeMediaPicker = 11002; - internal const int requestCodeMediaCapture = 11003; internal const int requestCodePickContact = 11004; internal const int requestCodeStart = 12000; diff --git a/src/Essentials/src/PublicAPI/net-android/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net-android/PublicAPI.Shipped.txt index 6f7b5adebfa2..2d398bc6e43b 100644 --- a/src/Essentials/src/PublicAPI/net-android/PublicAPI.Shipped.txt +++ b/src/Essentials/src/PublicAPI/net-android/PublicAPI.Shipped.txt @@ -767,11 +767,7 @@ Microsoft.Maui.Devices.Sensors.SensorSpeed.UI = 1 -> Microsoft.Maui.Devices.Sens Microsoft.Maui.Devices.Vibration Microsoft.Maui.Devices.VibrationExtensions Microsoft.Maui.Media.IMediaPicker -Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IMediaPicker.IsCaptureSupported.get -> bool -Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IPlatformScreenshot Microsoft.Maui.Media.IPlatformScreenshot.CaptureAsync(Android.App.Activity! activity) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IPlatformScreenshot.CaptureAsync(Android.Views.View! view) -> System.Threading.Tasks.Task! @@ -835,7 +831,6 @@ Microsoft.Maui.Storage.FileBase.ContentType.set -> void Microsoft.Maui.Storage.FileBase.FileBase(Microsoft.Maui.Storage.FileBase! file) -> void Microsoft.Maui.Storage.FileBase.FileName.get -> string! Microsoft.Maui.Storage.FileBase.FileName.set -> void -Microsoft.Maui.Storage.FileBase.FullPath.get -> string! Microsoft.Maui.Storage.FileBase.OpenReadAsync() -> System.Threading.Tasks.Task! Microsoft.Maui.Storage.FilePicker Microsoft.Maui.Storage.FilePickerFileType @@ -1162,12 +1157,8 @@ static Microsoft.Maui.Devices.Vibration.Vibrate() -> void static Microsoft.Maui.Devices.Vibration.Vibrate(double duration) -> void static Microsoft.Maui.Devices.Vibration.Vibrate(System.TimeSpan duration) -> void static Microsoft.Maui.Devices.VibrationExtensions.Vibrate(this Microsoft.Maui.Devices.IVibration! vibration, double duration) -> void -static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.MediaPicker.Default.get -> Microsoft.Maui.Media.IMediaPicker! static Microsoft.Maui.Media.MediaPicker.IsCaptureSupported.get -> bool -static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.CaptureAsync() -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.Default.get -> Microsoft.Maui.Media.IScreenshot! static Microsoft.Maui.Media.Screenshot.IsCaptureSupported.get -> bool diff --git a/src/Essentials/src/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-android/PublicAPI.Unshipped.txt index f4e82ef15b8e..8a993aa5bdd8 100644 --- a/src/Essentials/src/PublicAPI/net-android/PublicAPI.Unshipped.txt +++ b/src/Essentials/src/PublicAPI/net-android/PublicAPI.Unshipped.txt @@ -1,8 +1,56 @@ #nullable enable +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.SaveMediaPermission() -> void Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void +Microsoft.Maui.Media.IMediaGallery +Microsoft.Maui.Media.IMediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +Microsoft.Maui.Media.IMediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.IMediaGallery.IsSupported.get -> bool +Microsoft.Maui.Media.IMediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.MediaFilesResult +Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Image = 0 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Video = 1 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaGallery +Microsoft.Maui.Media.MediaPickRequest +Microsoft.Maui.Media.MediaPickRequest.PresentationSourceBounds.get -> Microsoft.Maui.Graphics.Rect +Microsoft.Maui.Media.MediaPickRequest.SelectionLimit.get -> int +Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.AlwaysSingle = 0 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.Limit = 1 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.UnLimit = 2 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Storage.FileBase.FullPath.get -> string! +Microsoft.Maui.Storage.MediaFileResult +Microsoft.Maui.Storage.MediaFileResult.Dispose() -> void +Microsoft.Maui.Storage.MediaFileResult.Extension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.NameWithoutExtension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.Type.get -> Microsoft.Maui.Media.MediaFileType? +static Microsoft.Maui.ApplicationModel.Platform.MediaPickerActivityLauncher -> AndroidX.Activity.Result.ActivityResultLauncher? +static Microsoft.Maui.Media.MediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +static Microsoft.Maui.Media.MediaGallery.Default.get -> Microsoft.Maui.Media.IMediaGallery! +static Microsoft.Maui.Media.MediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +static Microsoft.Maui.Media.MediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! ~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri ~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void *REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task! @@ -38,3 +86,8 @@ static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.Even static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task! static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void *REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer! +~Microsoft.Maui.Media.MediaFilesResult.Files.get -> System.Collections.Generic.IEnumerable +~Microsoft.Maui.Media.MediaPickRequest.MediaPickRequest(string title = null, int selectionLimit = 1, Microsoft.Maui.Graphics.Rect presentationSourceBounds = default(Microsoft.Maui.Graphics.Rect), params Microsoft.Maui.Media.MediaFileType[] types) -> void +~Microsoft.Maui.Media.MediaPickRequest.Title.get -> string +~Microsoft.Maui.Media.MediaPickRequest.Types.get -> Microsoft.Maui.Media.MediaFileType[] +~override Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.RequiredPermissions.get -> (string androidPermission, bool isRuntime)[] diff --git a/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Shipped.txt index 7b0a8619e9a4..ea1be2314294 100644 --- a/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Shipped.txt +++ b/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Shipped.txt @@ -766,11 +766,7 @@ Microsoft.Maui.Devices.Sensors.SensorSpeed.UI = 1 -> Microsoft.Maui.Devices.Sens Microsoft.Maui.Devices.Vibration Microsoft.Maui.Devices.VibrationExtensions Microsoft.Maui.Media.IMediaPicker -Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IMediaPicker.IsCaptureSupported.get -> bool -Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IPlatformScreenshot Microsoft.Maui.Media.IPlatformScreenshot.CaptureAsync(CoreAnimation.CALayer! layer, bool skipChildren) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IPlatformScreenshot.CaptureAsync(UIKit.UIView! view) -> System.Threading.Tasks.Task! @@ -835,7 +831,6 @@ Microsoft.Maui.Storage.FileBase.ContentType.set -> void Microsoft.Maui.Storage.FileBase.FileBase(Microsoft.Maui.Storage.FileBase! file) -> void Microsoft.Maui.Storage.FileBase.FileName.get -> string! Microsoft.Maui.Storage.FileBase.FileName.set -> void -Microsoft.Maui.Storage.FileBase.FullPath.get -> string! Microsoft.Maui.Storage.FileBase.OpenReadAsync() -> System.Threading.Tasks.Task! Microsoft.Maui.Storage.FilePicker Microsoft.Maui.Storage.FilePickerFileType @@ -1161,12 +1156,8 @@ static Microsoft.Maui.Devices.Vibration.Vibrate() -> void static Microsoft.Maui.Devices.Vibration.Vibrate(double duration) -> void static Microsoft.Maui.Devices.Vibration.Vibrate(System.TimeSpan duration) -> void static Microsoft.Maui.Devices.VibrationExtensions.Vibrate(this Microsoft.Maui.Devices.IVibration! vibration, double duration) -> void -static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.MediaPicker.Default.get -> Microsoft.Maui.Media.IMediaPicker! static Microsoft.Maui.Media.MediaPicker.IsCaptureSupported.get -> bool -static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.CaptureAsync() -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.Default.get -> Microsoft.Maui.Media.IScreenshot! static Microsoft.Maui.Media.Screenshot.IsCaptureSupported.get -> bool diff --git a/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt index f4e82ef15b8e..be9854fd0122 100644 --- a/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt +++ b/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt @@ -1,8 +1,55 @@ #nullable enable +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.SaveMediaPermission() -> void Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void +Microsoft.Maui.Media.IMediaGallery +Microsoft.Maui.Media.IMediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +Microsoft.Maui.Media.IMediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.IMediaGallery.IsSupported.get -> bool +Microsoft.Maui.Media.IMediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.MediaFilesResult +Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Image = 0 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Video = 1 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaGallery +Microsoft.Maui.Media.MediaPickRequest +Microsoft.Maui.Media.MediaPickRequest.PresentationSourceBounds.get -> Microsoft.Maui.Graphics.Rect +Microsoft.Maui.Media.MediaPickRequest.SelectionLimit.get -> int +Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.AlwaysSingle = 0 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.Limit = 1 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.UnLimit = 2 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Storage.FileBase.FullPath.get -> string! +Microsoft.Maui.Storage.MediaFileResult +Microsoft.Maui.Storage.MediaFileResult.Dispose() -> void +Microsoft.Maui.Storage.MediaFileResult.Extension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.NameWithoutExtension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.Type.get -> Microsoft.Maui.Media.MediaFileType? +static Microsoft.Maui.Media.MediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +static Microsoft.Maui.Media.MediaGallery.Default.get -> Microsoft.Maui.Media.IMediaGallery! +static Microsoft.Maui.Media.MediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +static Microsoft.Maui.Media.MediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! ~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri ~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void *REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task! @@ -38,3 +85,10 @@ static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.Even static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task! static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void *REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer! +~Microsoft.Maui.Media.MediaFilesResult.Files.get -> System.Collections.Generic.IEnumerable +~Microsoft.Maui.Media.MediaPickRequest.MediaPickRequest(string title = null, int selectionLimit = 1, Microsoft.Maui.Graphics.Rect presentationSourceBounds = default(Microsoft.Maui.Graphics.Rect), params Microsoft.Maui.Media.MediaFileType[] types) -> void +~Microsoft.Maui.Media.MediaPickRequest.Title.get -> string +~Microsoft.Maui.Media.MediaPickRequest.Types.get -> Microsoft.Maui.Media.MediaFileType[] +~override Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.CheckStatusAsync() -> System.Threading.Tasks.Task +~override Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.RequestAsync() -> System.Threading.Tasks.Task +~override Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.RequiredInfoPlistKeys.get -> System.Func> diff --git a/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Shipped.txt index 7b0a8619e9a4..ea1be2314294 100644 --- a/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Shipped.txt +++ b/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Shipped.txt @@ -766,11 +766,7 @@ Microsoft.Maui.Devices.Sensors.SensorSpeed.UI = 1 -> Microsoft.Maui.Devices.Sens Microsoft.Maui.Devices.Vibration Microsoft.Maui.Devices.VibrationExtensions Microsoft.Maui.Media.IMediaPicker -Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IMediaPicker.IsCaptureSupported.get -> bool -Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IPlatformScreenshot Microsoft.Maui.Media.IPlatformScreenshot.CaptureAsync(CoreAnimation.CALayer! layer, bool skipChildren) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IPlatformScreenshot.CaptureAsync(UIKit.UIView! view) -> System.Threading.Tasks.Task! @@ -835,7 +831,6 @@ Microsoft.Maui.Storage.FileBase.ContentType.set -> void Microsoft.Maui.Storage.FileBase.FileBase(Microsoft.Maui.Storage.FileBase! file) -> void Microsoft.Maui.Storage.FileBase.FileName.get -> string! Microsoft.Maui.Storage.FileBase.FileName.set -> void -Microsoft.Maui.Storage.FileBase.FullPath.get -> string! Microsoft.Maui.Storage.FileBase.OpenReadAsync() -> System.Threading.Tasks.Task! Microsoft.Maui.Storage.FilePicker Microsoft.Maui.Storage.FilePickerFileType @@ -1161,12 +1156,8 @@ static Microsoft.Maui.Devices.Vibration.Vibrate() -> void static Microsoft.Maui.Devices.Vibration.Vibrate(double duration) -> void static Microsoft.Maui.Devices.Vibration.Vibrate(System.TimeSpan duration) -> void static Microsoft.Maui.Devices.VibrationExtensions.Vibrate(this Microsoft.Maui.Devices.IVibration! vibration, double duration) -> void -static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.MediaPicker.Default.get -> Microsoft.Maui.Media.IMediaPicker! static Microsoft.Maui.Media.MediaPicker.IsCaptureSupported.get -> bool -static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.CaptureAsync() -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.Default.get -> Microsoft.Maui.Media.IScreenshot! static Microsoft.Maui.Media.Screenshot.IsCaptureSupported.get -> bool diff --git a/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt index f4e82ef15b8e..be9854fd0122 100644 --- a/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt +++ b/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt @@ -1,8 +1,55 @@ #nullable enable +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.SaveMediaPermission() -> void Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void +Microsoft.Maui.Media.IMediaGallery +Microsoft.Maui.Media.IMediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +Microsoft.Maui.Media.IMediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.IMediaGallery.IsSupported.get -> bool +Microsoft.Maui.Media.IMediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.MediaFilesResult +Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Image = 0 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Video = 1 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaGallery +Microsoft.Maui.Media.MediaPickRequest +Microsoft.Maui.Media.MediaPickRequest.PresentationSourceBounds.get -> Microsoft.Maui.Graphics.Rect +Microsoft.Maui.Media.MediaPickRequest.SelectionLimit.get -> int +Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.AlwaysSingle = 0 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.Limit = 1 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.UnLimit = 2 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Storage.FileBase.FullPath.get -> string! +Microsoft.Maui.Storage.MediaFileResult +Microsoft.Maui.Storage.MediaFileResult.Dispose() -> void +Microsoft.Maui.Storage.MediaFileResult.Extension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.NameWithoutExtension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.Type.get -> Microsoft.Maui.Media.MediaFileType? +static Microsoft.Maui.Media.MediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +static Microsoft.Maui.Media.MediaGallery.Default.get -> Microsoft.Maui.Media.IMediaGallery! +static Microsoft.Maui.Media.MediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +static Microsoft.Maui.Media.MediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! ~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri ~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void *REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task! @@ -38,3 +85,10 @@ static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.Even static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task! static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void *REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer! +~Microsoft.Maui.Media.MediaFilesResult.Files.get -> System.Collections.Generic.IEnumerable +~Microsoft.Maui.Media.MediaPickRequest.MediaPickRequest(string title = null, int selectionLimit = 1, Microsoft.Maui.Graphics.Rect presentationSourceBounds = default(Microsoft.Maui.Graphics.Rect), params Microsoft.Maui.Media.MediaFileType[] types) -> void +~Microsoft.Maui.Media.MediaPickRequest.Title.get -> string +~Microsoft.Maui.Media.MediaPickRequest.Types.get -> Microsoft.Maui.Media.MediaFileType[] +~override Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.CheckStatusAsync() -> System.Threading.Tasks.Task +~override Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.RequestAsync() -> System.Threading.Tasks.Task +~override Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.RequiredInfoPlistKeys.get -> System.Func> diff --git a/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Shipped.txt index ade1aa1609b9..eabd6af46b9b 100644 --- a/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Shipped.txt +++ b/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Shipped.txt @@ -726,11 +726,7 @@ Microsoft.Maui.Devices.Sensors.SensorSpeed.UI = 1 -> Microsoft.Maui.Devices.Sens Microsoft.Maui.Devices.Vibration Microsoft.Maui.Devices.VibrationExtensions Microsoft.Maui.Media.IMediaPicker -Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IMediaPicker.IsCaptureSupported.get -> bool -Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IPlatformScreenshot Microsoft.Maui.Media.IPlatformScreenshot.CaptureAsync(Microsoft.UI.Xaml.UIElement! element) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IPlatformScreenshot.CaptureAsync(Microsoft.UI.Xaml.Window! window) -> System.Threading.Tasks.Task! @@ -1110,12 +1106,8 @@ static Microsoft.Maui.Devices.Vibration.Vibrate() -> void static Microsoft.Maui.Devices.Vibration.Vibrate(double duration) -> void static Microsoft.Maui.Devices.Vibration.Vibrate(System.TimeSpan duration) -> void static Microsoft.Maui.Devices.VibrationExtensions.Vibrate(this Microsoft.Maui.Devices.IVibration! vibration, double duration) -> void -static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.MediaPicker.Default.get -> Microsoft.Maui.Media.IMediaPicker! static Microsoft.Maui.Media.MediaPicker.IsCaptureSupported.get -> bool -static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.CaptureAsync() -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.Default.get -> Microsoft.Maui.Media.IScreenshot! static Microsoft.Maui.Media.Screenshot.IsCaptureSupported.get -> bool diff --git a/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt index f4e82ef15b8e..bd79ea3ad676 100644 --- a/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt +++ b/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt @@ -1,8 +1,54 @@ #nullable enable +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.SaveMediaPermission() -> void Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void +Microsoft.Maui.Media.IMediaGallery +Microsoft.Maui.Media.IMediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +Microsoft.Maui.Media.IMediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.IMediaGallery.IsSupported.get -> bool +Microsoft.Maui.Media.IMediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.MediaFilesResult +Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Image = 0 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Video = 1 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaGallery +Microsoft.Maui.Media.MediaPickRequest +Microsoft.Maui.Media.MediaPickRequest.PresentationSourceBounds.get -> Microsoft.Maui.Graphics.Rect +Microsoft.Maui.Media.MediaPickRequest.SelectionLimit.get -> int +Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.AlwaysSingle = 0 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.Limit = 1 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.UnLimit = 2 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Storage.MediaFileResult +Microsoft.Maui.Storage.MediaFileResult.Dispose() -> void +Microsoft.Maui.Storage.MediaFileResult.Extension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.NameWithoutExtension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.Type.get -> Microsoft.Maui.Media.MediaFileType? +static Microsoft.Maui.Media.MediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +static Microsoft.Maui.Media.MediaGallery.Default.get -> Microsoft.Maui.Media.IMediaGallery! +static Microsoft.Maui.Media.MediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +static Microsoft.Maui.Media.MediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! ~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri ~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void *REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task! @@ -38,3 +84,7 @@ static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.Even static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task! static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void *REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer! +~Microsoft.Maui.Media.MediaFilesResult.Files.get -> System.Collections.Generic.IEnumerable +~Microsoft.Maui.Media.MediaPickRequest.MediaPickRequest(string title = null, int selectionLimit = 1, Microsoft.Maui.Graphics.Rect presentationSourceBounds = default(Microsoft.Maui.Graphics.Rect), params Microsoft.Maui.Media.MediaFileType[] types) -> void +~Microsoft.Maui.Media.MediaPickRequest.Title.get -> string +~Microsoft.Maui.Media.MediaPickRequest.Types.get -> Microsoft.Maui.Media.MediaFileType[] diff --git a/src/Essentials/src/PublicAPI/net/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net/PublicAPI.Shipped.txt index 5659395d0778..becc71df5a25 100644 --- a/src/Essentials/src/PublicAPI/net/PublicAPI.Shipped.txt +++ b/src/Essentials/src/PublicAPI/net/PublicAPI.Shipped.txt @@ -711,11 +711,7 @@ Microsoft.Maui.Devices.Sensors.SensorSpeed.UI = 1 -> Microsoft.Maui.Devices.Sens Microsoft.Maui.Devices.Vibration Microsoft.Maui.Devices.VibrationExtensions Microsoft.Maui.Media.IMediaPicker -Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IMediaPicker.IsCaptureSupported.get -> bool -Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IPlatformScreenshot Microsoft.Maui.Media.IScreenshot Microsoft.Maui.Media.IScreenshot.CaptureAsync() -> System.Threading.Tasks.Task! @@ -1085,12 +1081,8 @@ static Microsoft.Maui.Devices.Vibration.Vibrate() -> void static Microsoft.Maui.Devices.Vibration.Vibrate(double duration) -> void static Microsoft.Maui.Devices.Vibration.Vibrate(System.TimeSpan duration) -> void static Microsoft.Maui.Devices.VibrationExtensions.Vibrate(this Microsoft.Maui.Devices.IVibration! vibration, double duration) -> void -static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.MediaPicker.Default.get -> Microsoft.Maui.Media.IMediaPicker! static Microsoft.Maui.Media.MediaPicker.IsCaptureSupported.get -> bool -static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.CaptureAsync() -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.Default.get -> Microsoft.Maui.Media.IScreenshot! static Microsoft.Maui.Media.Screenshot.IsCaptureSupported.get -> bool diff --git a/src/Essentials/src/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net/PublicAPI.Unshipped.txt index f4e82ef15b8e..bd79ea3ad676 100644 --- a/src/Essentials/src/PublicAPI/net/PublicAPI.Unshipped.txt +++ b/src/Essentials/src/PublicAPI/net/PublicAPI.Unshipped.txt @@ -1,8 +1,54 @@ #nullable enable +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.SaveMediaPermission() -> void Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void +Microsoft.Maui.Media.IMediaGallery +Microsoft.Maui.Media.IMediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +Microsoft.Maui.Media.IMediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.IMediaGallery.IsSupported.get -> bool +Microsoft.Maui.Media.IMediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.MediaFilesResult +Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Image = 0 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Video = 1 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaGallery +Microsoft.Maui.Media.MediaPickRequest +Microsoft.Maui.Media.MediaPickRequest.PresentationSourceBounds.get -> Microsoft.Maui.Graphics.Rect +Microsoft.Maui.Media.MediaPickRequest.SelectionLimit.get -> int +Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.AlwaysSingle = 0 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.Limit = 1 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.UnLimit = 2 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Storage.MediaFileResult +Microsoft.Maui.Storage.MediaFileResult.Dispose() -> void +Microsoft.Maui.Storage.MediaFileResult.Extension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.NameWithoutExtension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.Type.get -> Microsoft.Maui.Media.MediaFileType? +static Microsoft.Maui.Media.MediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +static Microsoft.Maui.Media.MediaGallery.Default.get -> Microsoft.Maui.Media.IMediaGallery! +static Microsoft.Maui.Media.MediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +static Microsoft.Maui.Media.MediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! ~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri ~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void *REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task! @@ -38,3 +84,7 @@ static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.Even static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task! static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void *REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer! +~Microsoft.Maui.Media.MediaFilesResult.Files.get -> System.Collections.Generic.IEnumerable +~Microsoft.Maui.Media.MediaPickRequest.MediaPickRequest(string title = null, int selectionLimit = 1, Microsoft.Maui.Graphics.Rect presentationSourceBounds = default(Microsoft.Maui.Graphics.Rect), params Microsoft.Maui.Media.MediaFileType[] types) -> void +~Microsoft.Maui.Media.MediaPickRequest.Title.get -> string +~Microsoft.Maui.Media.MediaPickRequest.Types.get -> Microsoft.Maui.Media.MediaFileType[] diff --git a/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Shipped.txt index 5659395d0778..334f39a2c23c 100644 --- a/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Shipped.txt +++ b/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Shipped.txt @@ -711,11 +711,7 @@ Microsoft.Maui.Devices.Sensors.SensorSpeed.UI = 1 -> Microsoft.Maui.Devices.Sens Microsoft.Maui.Devices.Vibration Microsoft.Maui.Devices.VibrationExtensions Microsoft.Maui.Media.IMediaPicker -Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IMediaPicker.IsCaptureSupported.get -> bool -Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! Microsoft.Maui.Media.IPlatformScreenshot Microsoft.Maui.Media.IScreenshot Microsoft.Maui.Media.IScreenshot.CaptureAsync() -> System.Threading.Tasks.Task! @@ -777,7 +773,6 @@ Microsoft.Maui.Storage.FileBase.ContentType.set -> void Microsoft.Maui.Storage.FileBase.FileBase(Microsoft.Maui.Storage.FileBase! file) -> void Microsoft.Maui.Storage.FileBase.FileName.get -> string! Microsoft.Maui.Storage.FileBase.FileName.set -> void -Microsoft.Maui.Storage.FileBase.FullPath.get -> string! Microsoft.Maui.Storage.FileBase.OpenReadAsync() -> System.Threading.Tasks.Task! Microsoft.Maui.Storage.FilePicker Microsoft.Maui.Storage.FilePickerFileType @@ -1085,12 +1080,6 @@ static Microsoft.Maui.Devices.Vibration.Vibrate() -> void static Microsoft.Maui.Devices.Vibration.Vibrate(double duration) -> void static Microsoft.Maui.Devices.Vibration.Vibrate(System.TimeSpan duration) -> void static Microsoft.Maui.Devices.VibrationExtensions.Vibrate(this Microsoft.Maui.Devices.IVibration! vibration, double duration) -> void -static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.Default.get -> Microsoft.Maui.Media.IMediaPicker! -static Microsoft.Maui.Media.MediaPicker.IsCaptureSupported.get -> bool -static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! -static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.CaptureAsync() -> System.Threading.Tasks.Task! static Microsoft.Maui.Media.Screenshot.Default.get -> Microsoft.Maui.Media.IScreenshot! static Microsoft.Maui.Media.Screenshot.IsCaptureSupported.get -> bool diff --git a/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt index f4e82ef15b8e..e7ce6b3ef28b 100644 --- a/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt +++ b/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt @@ -1,8 +1,57 @@ #nullable enable +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission +Microsoft.Maui.ApplicationModel.Permissions.SaveMediaPermission.SaveMediaPermission() -> void Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder? Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void +Microsoft.Maui.Media.IMediaGallery +Microsoft.Maui.Media.IMediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +Microsoft.Maui.Media.IMediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.IMediaGallery.IsSupported.get -> bool +Microsoft.Maui.Media.IMediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.IMediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +Microsoft.Maui.Media.MediaFilesResult +Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Image = 0 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaFileType.Video = 1 -> Microsoft.Maui.Media.MediaFileType +Microsoft.Maui.Media.MediaGallery +Microsoft.Maui.Media.MediaPickRequest +Microsoft.Maui.Media.MediaPickRequest.PresentationSourceBounds.get -> Microsoft.Maui.Graphics.Rect +Microsoft.Maui.Media.MediaPickRequest.SelectionLimit.get -> int +Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.AlwaysSingle = 0 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.Limit = 1 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Media.MultiPickingBehaviour.UnLimit = 2 -> Microsoft.Maui.Media.MultiPickingBehaviour +Microsoft.Maui.Storage.FileBase.FullPath.get -> string! +Microsoft.Maui.Storage.MediaFileResult +Microsoft.Maui.Storage.MediaFileResult.Dispose() -> void +Microsoft.Maui.Storage.MediaFileResult.Extension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.NameWithoutExtension.get -> string? +Microsoft.Maui.Storage.MediaFileResult.Type.get -> Microsoft.Maui.Media.MediaFileType? +static Microsoft.Maui.Media.MediaGallery.CaptureAsync(Microsoft.Maui.Media.MediaFileType type, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.CheckCaptureSupport(Microsoft.Maui.Media.MediaFileType type) -> bool +static Microsoft.Maui.Media.MediaGallery.Default.get -> Microsoft.Maui.Media.IMediaGallery! +static Microsoft.Maui.Media.MediaGallery.GetMultiPickingBehaviour() -> Microsoft.Maui.Media.MultiPickingBehaviour +static Microsoft.Maui.Media.MediaGallery.PickAsync(int selectionLimit = 1, params Microsoft.Maui.Media.MediaFileType[]! types) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.PickAsync(Microsoft.Maui.Media.MediaPickRequest! request, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, byte[]! data, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, string! filePath) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaGallery.SaveAsync(Microsoft.Maui.Media.MediaFileType type, System.IO.Stream! fileStream, string! fileName) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CapturePhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.CaptureVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.Default.get -> Microsoft.Maui.Media.IMediaPicker! +static Microsoft.Maui.Media.MediaPicker.IsCaptureSupported.get -> bool +static Microsoft.Maui.Media.MediaPicker.PickPhotoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! +static Microsoft.Maui.Media.MediaPicker.PickVideoAsync(Microsoft.Maui.Media.MediaPickerOptions? options = null) -> System.Threading.Tasks.Task! ~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri ~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void *REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task! @@ -38,3 +87,7 @@ static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.Even static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task! static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void *REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer! +~Microsoft.Maui.Media.MediaFilesResult.Files.get -> System.Collections.Generic.IEnumerable +~Microsoft.Maui.Media.MediaPickRequest.MediaPickRequest(string title = null, int selectionLimit = 1, Microsoft.Maui.Graphics.Rect presentationSourceBounds = default(Microsoft.Maui.Graphics.Rect), params Microsoft.Maui.Media.MediaFileType[] types) -> void +~Microsoft.Maui.Media.MediaPickRequest.Title.get -> string +~Microsoft.Maui.Media.MediaPickRequest.Types.get -> Microsoft.Maui.Media.MediaFileType[]