diff --git a/src/BlazorWebView/src/Maui/Android/BlazorWebChromeClient.cs b/src/BlazorWebView/src/Maui/Android/BlazorWebChromeClient.cs
index b0f60b0a5686..8384723132d0 100644
--- a/src/BlazorWebView/src/Maui/Android/BlazorWebChromeClient.cs
+++ b/src/BlazorWebView/src/Maui/Android/BlazorWebChromeClient.cs
@@ -45,7 +45,7 @@ private static async Task CallFilePickerAsync(IValueCallback filePathCallback, F
var pickOptions = GetPickOptions(fileChooserParams);
var fileResults = fileChooserParams?.Mode == ChromeFileChooserMode.OpenMultiple ?
await FilePicker.PickMultipleAsync(pickOptions) :
- new[] { await FilePicker.PickAsync(pickOptions) };
+ new[] { (await FilePicker.PickAsync(pickOptions))! };
if (fileResults?.All(f => f is null) ?? true)
{
diff --git a/src/Controls/samples/Controls.Sample/Pages/Others/RenderViewPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Others/RenderViewPage.xaml
index 4337a5a2aa87..86e8da3cc224 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Others/RenderViewPage.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Others/RenderViewPage.xaml
@@ -9,10 +9,9 @@
+ RadioButtonGroup.SelectedValue="{Binding Selection}">
-
diff --git a/src/Controls/samples/Controls.Sample/Pages/Others/RenderViewPage.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Others/RenderViewPage.xaml.cs
index 1c091d0bbc82..ac5b917a90d6 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Others/RenderViewPage.xaml.cs
+++ b/src/Controls/samples/Controls.Sample/Pages/Others/RenderViewPage.xaml.cs
@@ -1,125 +1,112 @@
#nullable enable
-
using System;
-using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
+using System.Threading.Tasks;
+using Maui.Controls.Sample.ViewModels.Base;
using Microsoft.Maui;
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Devices;
-using Microsoft.Maui.Platform;
using Microsoft.Maui.ApplicationModel.DataTransfer;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Media;
+using Microsoft.Maui.Storage;
namespace Maui.Controls.Sample.Pages
{
public partial class RenderViewPage
{
- Stopwatch stopwatch = new Stopwatch();
- RenderBindingModel vm;
+ readonly Stopwatch stopwatch = new Stopwatch();
+ readonly RenderBindingModel vm;
+
MemoryStream? imageStream;
- byte[]? byteStream;
public RenderViewPage()
{
InitializeComponent();
- this.BindingContext = this.vm = new RenderBindingModel();
-
+ BindingContext = vm = new RenderBindingModel();
}
- private async void RenderWindow_Clicked(object sender, System.EventArgs e)
+ async void RenderWindow_Clicked(object sender, EventArgs e)
{
Reset();
- RenderedView? renderImage = null;
- var window = this.GetParentWindow() as IWindow;
stopwatch.Start();
- try
- {
- if (window is not null)
- {
- renderImage = await window.RenderAsImage(vm.RenderType);
- }
- }
- catch (System.Exception ex)
- {
- System.Diagnostics.Debug.WriteLine(ex.Message);
- }
+ var renderImage = await Window.CaptureAsync();
+
stopwatch.Stop();
- RenderView(renderImage);
+ await RenderView(renderImage);
}
- private async void RenderButton_Clicked(object sender, System.EventArgs e)
+ async void RenderButton_Clicked(object sender, EventArgs e)
{
Reset();
- RenderedView? renderImage = null;
stopwatch.Start();
- try
- {
- renderImage = await this.RenderButton.RenderAsImage(vm.RenderType);
-
- }
- catch (System.Exception ex)
- {
- System.Diagnostics.Debug.WriteLine(ex.Message);
- }
+
+ var renderImage = await RenderButton.CaptureAsync();
+
stopwatch.Stop();
- RenderView(renderImage);
+ await RenderView(renderImage);
}
- private async void RenderViewSaved_Clicked(object sender, System.EventArgs e)
+ async void RenderViewSaved_Clicked(object sender, EventArgs e)
{
- if (byteStream is not null)
+ if (imageStream is not null)
{
var extension = vm.RenderType switch
{
- RenderType.JPEG => "jpg",
- RenderType.PNG => "png",
- RenderType.BMP => "bmp",
- _ => "jpg",
+ ScreenshotFormat.Jpeg => ".jpg",
+ ScreenshotFormat.Png => ".png",
+ _ => ".jpg",
};
- string fileName = $"{System.IO.Path.GetTempFileName()}.{extension}";
- string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), fileName);
- File.WriteAllBytes(filePath, byteStream);
- await Share.RequestAsync(new ShareFileRequest() { Title = fileName, File = new ShareFile(filePath) });
+
+ var fileName = Path.GetTempFileName() + extension;
+ var filePath = Path.Combine(FileSystem.CacheDirectory, fileName);
+
+ File.WriteAllBytes(filePath, imageStream.ToArray());
+
+ await Share.RequestAsync(new ShareFileRequest
+ {
+ Title = fileName,
+ File = new ShareFile(filePath)
+ });
}
}
- private void RenderView(RenderedView? renderImage)
+ async Task RenderView(IScreenshotResult? renderImage)
{
- if (renderImage?.Render is not null)
+ if (renderImage is not null)
{
- try
- {
- byteStream = renderImage.Render;
- imageStream = new MemoryStream(renderImage.Render);
- this.TestImage.Source = ImageSource.FromStream(() => imageStream);
- }
- catch (System.Exception ex)
- {
- System.Diagnostics.Debug.WriteLine(ex.Message);
- }
+ imageStream = new MemoryStream();
+ await renderImage.CopyToAsync(imageStream, vm.RenderType);
+ imageStream.Position = 0;
+
+ TestImage.Source = ImageSource.FromStream(() => imageStream);
}
- this.StopwatchTime.Text = stopwatch.Elapsed.ToString();
- this.RenderStats.Text = $"Type: {renderImage?.RenderType}; Size: {SizeInBytes(renderImage?.Render)}";
+
+ StopwatchTime.Text = stopwatch.Elapsed.ToString();
+ RenderStats.Text = $"Size: {SizeInBytes(imageStream)}";
}
- private void Reset()
+ void Reset()
{
stopwatch.Reset();
+
StopwatchTime.Text = string.Empty;
RenderStats.Text = string.Empty;
- this.TestImage.Source = null;
+
+ TestImage.Source = null;
}
- private string SizeInBytes(byte[]? array)
+ static string SizeInBytes(Stream? stream)
{
- if (array is null)
- return string.Empty;
+ if (stream is null)
+ return "";
+
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
- double len = System.Convert.ToDouble(array.Length);
+
+ double len = stream.Length;
int order = 0;
while (len >= 1024D && order < sizes.Length - 1)
{
@@ -131,36 +118,19 @@ private string SizeInBytes(byte[]? array)
}
}
- public class RenderBindingModel : INotifyPropertyChanged
+ public class RenderBindingModel : BaseViewModel
{
- private string? _selection;
-
- public event PropertyChangedEventHandler? PropertyChanged;
-
- void OnPropertyChanged(string propertyName)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
+ string? _selection;
public string? Selection
{
get => _selection;
- set
- {
- _selection = value;
- OnPropertyChanged(nameof(Selection));
- }
+ set => SetProperty(ref _selection, value);
}
- public RenderType RenderType
- {
- get
- {
- if (_selection is null)
- return RenderType.JPEG;
-
- return (RenderType)System.Enum.Parse(typeof(RenderType), _selection);
- }
- }
+ public ScreenshotFormat RenderType =>
+ Enum.TryParse(Selection, out var format)
+ ? format
+ : ScreenshotFormat.Jpeg;
}
}
\ No newline at end of file
diff --git a/src/Controls/tests/Core.UnitTests/MockDeviceDisplay.cs b/src/Controls/tests/Core.UnitTests/MockDeviceDisplay.cs
index f1773ecbc126..e13a7e72caad 100644
--- a/src/Controls/tests/Core.UnitTests/MockDeviceDisplay.cs
+++ b/src/Controls/tests/Core.UnitTests/MockDeviceDisplay.cs
@@ -13,7 +13,7 @@ internal class MockDeviceDisplay : IDeviceDisplay
public event EventHandler? MainDisplayInfoChanged;
- public DisplayInfo GetMainDisplayInfo() => _mainDisplayInfo;
+ public DisplayInfo MainDisplayInfo => _mainDisplayInfo;
public void UpdateMainDisplayInfo(DisplayInfo displayInfo)
{
diff --git a/src/Core/src/Fonts/FontRegistrar.Windows.cs b/src/Core/src/Fonts/FontRegistrar.Windows.cs
index 5b2fffa0b871..c1fce16d546a 100644
--- a/src/Core/src/Fonts/FontRegistrar.Windows.cs
+++ b/src/Core/src/Fonts/FontRegistrar.Windows.cs
@@ -9,19 +9,19 @@ public partial class FontRegistrar : IFontRegistrar
{
string? LoadNativeAppFont(string font, string filename, string? alias)
{
- if (FileSystemImplementation.AppPackageFileExists(filename))
+ if (FileSystemUtils.AppPackageFileExists(filename))
return $"ms-appx:///{filename}";
var packagePath = Path.Combine("Assets", filename);
- if (FileSystemImplementation.AppPackageFileExists(packagePath))
+ if (FileSystemUtils.AppPackageFileExists(packagePath))
return $"ms-appx:///Assets/{filename}";
packagePath = Path.Combine("Fonts", filename);
- if (FileSystemImplementation.AppPackageFileExists(packagePath))
+ if (FileSystemUtils.AppPackageFileExists(packagePath))
return $"ms-appx:///Fonts/{filename}";
packagePath = Path.Combine("Assets", "Fonts", filename);
- if (FileSystemImplementation.AppPackageFileExists(packagePath))
+ if (FileSystemUtils.AppPackageFileExists(packagePath))
return $"ms-appx:///Assets/Fonts/{filename}";
// TODO: check other folders as well
diff --git a/src/Core/src/Hosting/EssentialsMauiAppBuilderExtensions.cs b/src/Core/src/Hosting/EssentialsMauiAppBuilderExtensions.cs
index 0acc78d22e5a..f79dcec33bde 100644
--- a/src/Core/src/Hosting/EssentialsMauiAppBuilderExtensions.cs
+++ b/src/Core/src/Hosting/EssentialsMauiAppBuilderExtensions.cs
@@ -64,7 +64,7 @@ internal static MauiAppBuilder UseEssentials(this MauiAppBuilder builder)
life.AddWindows(windows => windows
.OnPlatformMessage((window, args) =>
{
- ApplicationModel.Platform.NewWindowProc(args.Hwnd, args.MessageId, args.WParam, args.LParam);
+ ApplicationModel.Platform.OnWindowMessage(args.Hwnd, args.MessageId, args.WParam, args.LParam);
})
.OnActivated((window, args) =>
{
diff --git a/src/Core/src/ImageSources/StreamImageSourceService/StreamImageSourceService.Windows.cs b/src/Core/src/ImageSources/StreamImageSourceService/StreamImageSourceService.Windows.cs
index 6036773c2903..142211b7671b 100644
--- a/src/Core/src/ImageSources/StreamImageSourceService/StreamImageSourceService.Windows.cs
+++ b/src/Core/src/ImageSources/StreamImageSourceService/StreamImageSourceService.Windows.cs
@@ -28,7 +28,7 @@ public partial class StreamImageSourceService
var image = new BitmapImage();
- using var ras = stream.AsRandomAccessStream();
+ var ras = stream.AsRandomAccessStream();
await image.SetSourceAsync(ras);
var result = new ImageSourceServiceResult(image);
diff --git a/src/Core/src/Platform/Android/ViewExtensions.cs b/src/Core/src/Platform/Android/ViewExtensions.cs
index 30da167d527b..e91ed9f7b7bc 100644
--- a/src/Core/src/Platform/Android/ViewExtensions.cs
+++ b/src/Core/src/Platform/Android/ViewExtensions.cs
@@ -307,50 +307,6 @@ public static void RemoveFromParent(this AView view)
PlatformInterop.RemoveFromParent(view);
}
- public static Task RenderAsBMP(this IView view)
- {
- var platformView = view?.ToPlatform();
- if (platformView == null)
- return Task.FromResult(null);
-
- return Task.FromResult(platformView.RenderAsBMP());
- }
-
- public static Task RenderAsPNG(this IView view)
- {
- var platformView = view?.ToPlatform();
- if (platformView == null)
- return Task.FromResult(null);
-
- return platformView.RenderAsPNG();
- }
-
- public static Task RenderAsJPEG(this IView view)
- {
- var platformView = view?.ToPlatform();
- if (platformView == null)
- return Task.FromResult(null);
-
- return platformView.RenderAsJPEG();
- }
-
- public static Task RenderAsImage(this AView view, RenderType type)
- {
- return type switch
- {
- RenderType.JPEG => view.RenderAsJPEG(),
- RenderType.PNG => view.RenderAsPNG(),
- RenderType.BMP => Task.FromResult(view.RenderAsBMP()),
- _ => throw new NotImplementedException()
- };
- }
-
- public static Task RenderAsPNG(this AView view)
- => Task.FromResult(view.RenderAsImage(Android.Graphics.Bitmap.CompressFormat.Png));
-
- public static Task RenderAsJPEG(this AView view)
- => Task.FromResult(view.RenderAsImage(Android.Graphics.Bitmap.CompressFormat.Jpeg));
-
internal static Rect GetPlatformViewBounds(this IView view)
{
var platformView = view?.ToPlatform();
diff --git a/src/Core/src/Platform/Android/WindowExtensions.cs b/src/Core/src/Platform/Android/WindowExtensions.cs
deleted file mode 100644
index da89a68484ce..000000000000
--- a/src/Core/src/Platform/Android/WindowExtensions.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading.Tasks;
-using Android.App;
-using Android.Views;
-using Microsoft.Maui.Devices;
-using Microsoft.Maui.Media;
-
-namespace Microsoft.Maui.Platform
-{
- public static partial class WindowExtensions
- {
- public static async Task RenderAsImage(this IWindow window, RenderType type)
- {
- if (window.Handler?.PlatformView is not Activity activity)
- return null;
-
- if (activity?.Window?.DecorView?.RootView is not View rootView)
- return null;
-
- var image = type switch
- {
- RenderType.JPEG => await rootView.RenderAsJPEG(),
- RenderType.PNG => await rootView.RenderAsPNG(),
- RenderType.BMP => rootView.RenderAsBMP(),
- _ => throw new NotImplementedException(),
- };
-
- return new RenderedView(image, type);
- }
- }
-}
diff --git a/src/Core/src/Platform/Standard/ViewExtensions.cs b/src/Core/src/Platform/Standard/ViewExtensions.cs
index cb0a1a7a152b..1d3721937541 100644
--- a/src/Core/src/Platform/Standard/ViewExtensions.cs
+++ b/src/Core/src/Platform/Standard/ViewExtensions.cs
@@ -58,15 +58,6 @@ public static void UpdateMinimumWidth(this object platformView, IView view) { }
public static void UpdateMaximumWidth(this object platformView, IView view) { }
- public static System.Threading.Tasks.Task RenderAsBMP(this IView view)
- => System.Threading.Tasks.Task.FromResult(null);
-
- public static System.Threading.Tasks.Task RenderAsPNG(this IView view)
- => System.Threading.Tasks.Task.FromResult(null);
-
- public static System.Threading.Tasks.Task RenderAsJPEG(this IView view)
- => System.Threading.Tasks.Task.FromResult(null);
-
internal static Graphics.Rect GetPlatformViewBounds(this IView view) => view.Frame;
internal static System.Numerics.Matrix4x4 GetViewTransform(this IView view) => new System.Numerics.Matrix4x4();
diff --git a/src/Core/src/Platform/Standard/WindowExtensions.cs b/src/Core/src/Platform/Standard/WindowExtensions.cs
deleted file mode 100644
index c3a4942cc811..000000000000
--- a/src/Core/src/Platform/Standard/WindowExtensions.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Microsoft.Maui.Platform
-{
- public static partial class WindowExtensions
- {
- public static Task RenderAsImage(this IWindow window, RenderType type)
- {
- return Task.FromResult(null);
- }
- }
-}
diff --git a/src/Core/src/Platform/ViewExtensions.cs b/src/Core/src/Platform/ViewExtensions.cs
index 909d534b5751..b78a073cad4e 100644
--- a/src/Core/src/Platform/ViewExtensions.cs
+++ b/src/Core/src/Platform/ViewExtensions.cs
@@ -2,6 +2,9 @@
using System.Numerics;
using Microsoft.Maui.Graphics;
using System.Threading.Tasks;
+using Microsoft.Maui.Media;
+using System.IO;
+
#if NETSTANDARD || (NET6_0 && !IOS && !ANDROID)
using IPlatformViewHandler = Microsoft.Maui.IViewHandler;
#endif
@@ -19,7 +22,7 @@
using ParentView = System.Object;
#endif
-namespace Microsoft.Maui
+namespace Microsoft.Maui.Platform
{
///
public static partial class ViewExtensions
@@ -37,19 +40,6 @@ public static partial class ViewExtensions
public static IPlatformViewHandler ToHandler(this IView view, IMauiContext context) =>
(IPlatformViewHandler)ElementExtensions.ToHandler(view, context);
- public static async Task RenderAsImage(this IView view, RenderType type)
- {
- byte[]? image = type switch
- {
- RenderType.PNG => await view.RenderAsPNG(),
- RenderType.JPEG => await view.RenderAsJPEG(),
- RenderType.BMP => await view.RenderAsBMP(),
- _ => throw new NotImplementedException(),
- };
-
- return new RenderedView(image, type);
- }
-
internal static T? GetParentOfType(this ParentView? view)
where T : class
{
@@ -113,6 +103,5 @@ internal static Task OnLoadedAsync(this PlatformView platformView, TimeSpan? tim
return taskCompletionSource.Task.WaitAsync(timeOut.Value);
}
#endif
-
}
}
diff --git a/src/Core/src/Platform/WindowExtensions.cs b/src/Core/src/Platform/WindowExtensions.cs
index 0409fed9136d..d981843aabbb 100644
--- a/src/Core/src/Platform/WindowExtensions.cs
+++ b/src/Core/src/Platform/WindowExtensions.cs
@@ -1,4 +1,15 @@
using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.Maui.Media;
+
+#if __IOS__ || MACCATALYST
+using PlatformView = UIKit.UIWindow;
+#elif MONOANDROID
+using PlatformView = Android.App.Activity;
+#elif WINDOWS
+using PlatformView = Microsoft.UI.Xaml.Window;
+#endif
namespace Microsoft.Maui.Platform
{
diff --git a/src/Core/src/Platform/Windows/MauiWinUIWindow.cs b/src/Core/src/Platform/Windows/MauiWinUIWindow.cs
index abb7aa1479c3..9d7620e99f0e 100644
--- a/src/Core/src/Platform/Windows/MauiWinUIWindow.cs
+++ b/src/Core/src/Platform/Windows/MauiWinUIWindow.cs
@@ -1,7 +1,6 @@
using System;
-using System.Runtime.InteropServices;
-using Microsoft.Maui.LifecycleEvents;
using Microsoft.Maui.Devices;
+using Microsoft.Maui.LifecycleEvents;
using WinRT;
namespace Microsoft.Maui
diff --git a/src/Core/src/Platform/Windows/ViewExtensions.cs b/src/Core/src/Platform/Windows/ViewExtensions.cs
index 0514b5a2eb49..b9ee3405a296 100644
--- a/src/Core/src/Platform/Windows/ViewExtensions.cs
+++ b/src/Core/src/Platform/Windows/ViewExtensions.cs
@@ -1,7 +1,6 @@
#nullable enable
-using System;
-using System.Numerics;
using System.Linq;
+using System.Numerics;
using System.Threading.Tasks;
using Microsoft.Maui.Devices;
using Microsoft.Maui.Graphics;
@@ -97,7 +96,7 @@ public static void UpdateOpacity(this FrameworkElement platformView, IView view)
platformView.Opacity = view.Visibility == Visibility.Hidden ? 0 : view.Opacity;
}
- public static void UpdateBackground(this ContentPanel platformView, IBorderStroke border)
+ public static void UpdateBackground(this ContentPanel platformView, IBorderStroke border)
{
var hasBorder = border.Shape != null && border.Stroke != null;
@@ -105,7 +104,7 @@ public static void UpdateBackground(this ContentPanel platformView, IBorderStrok
{
platformView?.UpdateBorderBackground(border);
}
- else if(border is IView v)
+ else if (border is IView v)
{
platformView?.UpdatePlatformViewBackground(v);
}
@@ -116,7 +115,7 @@ public static void UpdateBackground(this FrameworkElement platformView, IView vi
platformView?.UpdatePlatformViewBackground(view);
}
- public static void UpdateFlowDirection(this FrameworkElement platformView, IView view)
+ public static void UpdateFlowDirection(this FrameworkElement platformView, IView view)
{
var flowDirection = view.FlowDirection;
switch (flowDirection)
@@ -220,8 +219,8 @@ public static void UpdateMaximumWidth(this FrameworkElement platformView, IView
internal static void UpdateBorderBackground(this FrameworkElement platformView, IBorderStroke border)
{
- if(border is IView v)
- (platformView as ContentPanel)?.UpdateBackground(v.Background);
+ if (border is IView v)
+ (platformView as ContentPanel)?.UpdateBackground(v.Background);
if (platformView is Control control)
control.UpdateBackground((Paint?)null);
@@ -250,50 +249,6 @@ internal static void UpdatePlatformViewBackground(this LayoutPanel layoutPanel,
layoutPanel.UpdateInputTransparent(layout.InputTransparent, layout?.Background?.ToPlatform());
}
- public static async Task RenderAsBMP(this IView view)
- {
- var platformView = view?.ToPlatform();
- if (platformView == null)
- return null;
-
- return await platformView.RenderAsBMP();
- }
-
- public static async Task RenderAsPNG(this IView view)
- {
- var platformView = view?.ToPlatform();
- if (platformView == null)
- return null;
-
- return await platformView.RenderAsPNG();
- }
-
- public static async Task RenderAsJPEG(this IView view)
- {
- var platformView = view?.ToPlatform();
- if (platformView == null)
- return null;
-
- return await platformView.RenderAsJPEG();
- }
-
- public static Task RenderAsImage(this FrameworkElement view, RenderType type)
- {
- return type switch
- {
- RenderType.JPEG => view.RenderAsJPEG(),
- RenderType.PNG => view.RenderAsPNG(),
- RenderType.BMP => view.RenderAsBMP(),
- _ => throw new NotImplementedException()
- };
- }
-
- public static Task RenderAsBMP(this FrameworkElement view) => view != null ? view.RenderAsBMPAsync() : Task.FromResult(null);
-
- public static Task RenderAsPNG(this FrameworkElement view) => view != null ? view.RenderAsPNGAsync() : Task.FromResult(null);
-
- public static Task RenderAsJPEG(this FrameworkElement view) => view != null ? view.RenderAsJPEGAsync() : Task.FromResult(null);
-
internal static Matrix4x4 GetViewTransform(this IView view)
{
var platformView = view?.ToPlatform();
@@ -342,7 +297,7 @@ internal static Rect GetPlatformViewBounds(this FrameworkElement platformView)
return new Rect();
}
- internal static Graphics.Rect GetBoundingBox(this IView view)
+ internal static Graphics.Rect GetBoundingBox(this IView view)
=> view.ToPlatform().GetBoundingBox();
internal static Graphics.Rect GetBoundingBox(this FrameworkElement? platformView)
@@ -425,7 +380,7 @@ internal static void UnfocusControl(Control control)
ContainingPage.IsTabStop = wasTabStop;
}
}
-
+
internal static IWindow? GetHostedWindow(this IView? view)
=> GetHostedWindow(view?.Handler?.PlatformView as FrameworkElement);
@@ -438,7 +393,7 @@ internal static void UnfocusControl(Control control)
return null;
var windows = WindowExtensions.GetWindows();
- foreach(var window in windows)
+ foreach (var window in windows)
{
if (window.Handler?.PlatformView is Microsoft.UI.Xaml.Window win)
{
@@ -446,14 +401,14 @@ internal static void UnfocusControl(Control control)
return window;
}
}
-
+
return null;
}
-
+
public static void UpdateInputTransparent(this FrameworkElement nativeView, IViewHandler handler, IView view)
{
if (nativeView is UIElement element)
- {
+ {
element.IsHitTestVisible = !view.InputTransparent;
}
}
diff --git a/src/Core/src/Platform/Windows/WindowExtensions.cs b/src/Core/src/Platform/Windows/WindowExtensions.cs
index 4cac690c3e94..ae5acc41ad3b 100644
--- a/src/Core/src/Platform/Windows/WindowExtensions.cs
+++ b/src/Core/src/Platform/Windows/WindowExtensions.cs
@@ -1,6 +1,6 @@
using System;
-using System.Threading.Tasks;
using Microsoft.Maui.Devices;
+using System.Threading.Tasks;
using Microsoft.Maui.Media;
using WinRT.Interop;
@@ -60,24 +60,5 @@ public static float GetDisplayDensity(this UI.Xaml.Window platformWindow)
var windowId = UI.Win32Interop.GetWindowIdFromWindow(hwnd);
return UI.Windowing.AppWindow.GetFromWindowId(windowId);
}
-
- public static async Task RenderAsImage(this IWindow window, RenderType type)
- {
- if (window.Handler?.PlatformView is not UI.Xaml.Window win)
- return null;
-
- if (win.Content is not UI.Xaml.FrameworkElement element)
- return null;
-
- var image = type switch
- {
- RenderType.JPEG => await element.RenderAsJPEGAsync(),
- RenderType.PNG => await element.RenderAsPNGAsync(),
- RenderType.BMP => await element.RenderAsBMPAsync(),
- _ => throw new NotImplementedException(),
- };
-
- return new RenderedView(image, type);
- }
}
}
\ No newline at end of file
diff --git a/src/Core/src/Platform/iOS/ViewExtensions.cs b/src/Core/src/Platform/iOS/ViewExtensions.cs
index c15a6492ff8b..607465bfeb77 100644
--- a/src/Core/src/Platform/iOS/ViewExtensions.cs
+++ b/src/Core/src/Platform/iOS/ViewExtensions.cs
@@ -333,71 +333,6 @@ public static void ClearSubviews(this UIView view)
}
}
- public static Task RenderAsBMP(this IView view)
- {
- (UIView? platformView, bool skipChildren) = view.GetPlatformRenderBase();
- if (platformView is null)
- return Task.FromResult(null);
-
- return platformView.RenderAsBMP(skipChildren);
- }
-
- public static Task RenderAsPNG(this IView view)
- {
- (UIView? platformView, bool skipChildren) = view.GetPlatformRenderBase();
- if (platformView is null)
- return Task.FromResult(null);
-
- return platformView.RenderAsPNG(skipChildren);
- }
-
- public static Task RenderAsJPEG(this IView view)
- {
- (UIView? platformView, bool skipChildren) = view.GetPlatformRenderBase();
- if (platformView is null)
- return Task.FromResult(null);
-
- return platformView.RenderAsJPEG(skipChildren);
- }
-
- public static Task RenderAsImage(this UIView view, RenderType type, bool skipChildren = true)
- {
- return type switch
- {
- RenderType.JPEG => view.RenderAsJPEG(skipChildren),
- RenderType.PNG => view.RenderAsPNG(skipChildren),
- RenderType.BMP => view.RenderAsBMP(skipChildren),
- _ => throw new NotImplementedException()
- };
- }
-
- public static Task RenderAsBMP(this UIWindow window, bool skipChildren = false)
- => Task.FromResult(window?.RenderAsBmp(window.Layer, UIScreen.MainScreen.Scale, skipChildren));
-
- public static Task RenderAsPNG(this UIWindow window, bool skipChildren = false)
- => Task.FromResult(window?.RenderAsPng(window.Layer, UIScreen.MainScreen.Scale, skipChildren));
-
- public static Task RenderAsJPEG(this UIWindow window, bool skipChildren = false)
- => Task.FromResult(window?.RenderAsJpeg(window.Layer, UIScreen.MainScreen.Scale, skipChildren));
-
- public static Task RenderAsBMP(this UIView view, bool skipChildren = true)
- => Task.FromResult(view?.Window?.RenderAsBmp(view.Layer, UIScreen.MainScreen.Scale, skipChildren));
-
- public static Task RenderAsPNG(this UIView view, bool skipChildren = true)
- => Task.FromResult(view?.Window?.RenderAsPng(view.Layer, UIScreen.MainScreen.Scale, skipChildren));
-
- public static Task RenderAsJPEG(this UIView view, bool skipChildren = true)
- => Task.FromResult(view?.Window?.RenderAsJpeg(view.Layer, UIScreen.MainScreen.Scale, skipChildren));
-
- static (UIView? View, bool SkipChildren) GetPlatformRenderBase(this IView view)
- {
- var platformView = view?.ToPlatform();
- if (platformView == null)
- return (null, false);
- var skipChildren = !(view is IView && !(view is ILayout));
- return (platformView, skipChildren);
- }
-
internal static Rect GetPlatformViewBounds(this IView view)
{
var platformView = view?.ToPlatform();
diff --git a/src/Core/src/Platform/iOS/WindowExtensions.cs b/src/Core/src/Platform/iOS/WindowExtensions.cs
index 5f8328595366..591d6a31556d 100644
--- a/src/Core/src/Platform/iOS/WindowExtensions.cs
+++ b/src/Core/src/Platform/iOS/WindowExtensions.cs
@@ -29,21 +29,5 @@ public static partial class WindowExtensions
public static float GetDisplayDensity(this UIWindow uiWindow) =>
(float)(uiWindow.Screen?.Scale ?? new nfloat(1.0f));
-
- public static async Task RenderAsImage(this IWindow window, RenderType type)
- {
- if (window?.ToPlatform() is not UIWindow win)
- return null;
-
- var image = type switch
- {
- RenderType.JPEG => await win.RenderAsJPEG(),
- RenderType.PNG => await win.RenderAsPNG(),
- RenderType.BMP => await win.RenderAsBMP(),
- _ => throw new NotImplementedException(),
- };
-
- return new RenderedView(image, type);
- }
}
}
diff --git a/src/Core/src/ViewExtensions.cs b/src/Core/src/ViewExtensions.cs
new file mode 100644
index 000000000000..8655de37b805
--- /dev/null
+++ b/src/Core/src/ViewExtensions.cs
@@ -0,0 +1,48 @@
+using Microsoft.Maui.Graphics;
+using System.Threading.Tasks;
+using Microsoft.Maui.Media;
+using System.IO;
+#if NETSTANDARD || (NET6_0 && !IOS && !ANDROID)
+using IPlatformViewHandler = Microsoft.Maui.IViewHandler;
+#endif
+#if IOS || MACCATALYST
+using PlatformView = UIKit.UIView;
+using ParentView = UIKit.UIView;
+#elif ANDROID
+using PlatformView = Android.Views.View;
+using ParentView = Android.Views.IViewParent;
+#elif WINDOWS
+using PlatformView = Microsoft.UI.Xaml.FrameworkElement;
+using ParentView = Microsoft.UI.Xaml.DependencyObject;
+#else
+using PlatformView = System.Object;
+using ParentView = System.Object;
+using System;
+#endif
+
+namespace Microsoft.Maui
+{
+ public static partial class ViewExtensions
+ {
+ public static Task CaptureAsync(this IView view)
+ {
+#if PLATFORM
+ if (view?.ToPlatform() is not PlatformView platformView)
+ return Task.FromResult(null);
+
+ if (!Screenshot.Default.IsCaptureSupported)
+ return Task.FromResult(null);
+
+ return CaptureAsync(platformView);
+#else
+ return Task.FromResult(null);
+#endif
+ }
+
+
+#if PLATFORM
+ async static Task CaptureAsync(PlatformView window) =>
+ await Screenshot.Default.CaptureAsync(window);
+#endif
+ }
+}
diff --git a/src/Core/src/VisualDiagnostics/RenderedView.cs b/src/Core/src/VisualDiagnostics/RenderedView.cs
deleted file mode 100644
index 2f0278cbdbc3..000000000000
--- a/src/Core/src/VisualDiagnostics/RenderedView.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Microsoft.Maui
-{
- public class RenderedView
- {
- public RenderedView(byte[]? render, RenderType renderType)
- {
- this.Render = render;
- this.RenderType = renderType;
- }
-
- public byte[]? Render { get; }
-
- public RenderType RenderType { get; }
- }
-
- public enum RenderType
- {
- JPEG,
- PNG,
- BMP,
- }
-}
diff --git a/src/Core/src/VisualDiagnostics/VisualDiagnostics.cs b/src/Core/src/VisualDiagnostics/VisualDiagnostics.cs
index 366b390c8ee7..47ebc0b1c8cc 100644
--- a/src/Core/src/VisualDiagnostics/VisualDiagnostics.cs
+++ b/src/Core/src/VisualDiagnostics/VisualDiagnostics.cs
@@ -3,7 +3,10 @@
using System;
using System.ComponentModel;
+using System.IO;
using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Microsoft.Maui.Media;
namespace Microsoft.Maui
{
@@ -66,5 +69,40 @@ static void OnVisualTreeChanged(VisualTreeChangeEventArgs e)
{
VisualTreeChanged?.Invoke(e.Parent, e);
}
+
+ public static async Task CaptureAsPngAsync(IView view)
+ {
+ var result = await view.CaptureAsync();
+ return await ScreenshotResultToArray(result, ScreenshotFormat.Png, 100);
+ }
+
+ public static async Task CaptureAsJpegAsync(IView view, int quality = 80)
+ {
+ var result = await view.CaptureAsync();
+ return await ScreenshotResultToArray(result, ScreenshotFormat.Jpeg, quality);
+ }
+
+ public static async Task CaptureAsPngAsync(IWindow window)
+ {
+ var result = await window.CaptureAsync();
+ return await ScreenshotResultToArray(result, ScreenshotFormat.Png, 100);
+ }
+
+ public static async Task CaptureAsJpegAsync(IWindow window, int quality = 80)
+ {
+ var result = await window.CaptureAsync();
+ return await ScreenshotResultToArray(result, ScreenshotFormat.Jpeg, quality);
+ }
+
+ static async Task ScreenshotResultToArray(IScreenshotResult? result, ScreenshotFormat format, int quality)
+ {
+ if (result is null)
+ return null;
+
+ using var ms = new MemoryStream();
+ await result.CopyToAsync(ms, format, quality);
+
+ return ms.ToArray();
+ }
}
}
diff --git a/src/Core/src/WindowExtensions.cs b/src/Core/src/WindowExtensions.cs
new file mode 100644
index 000000000000..5502c210e457
--- /dev/null
+++ b/src/Core/src/WindowExtensions.cs
@@ -0,0 +1,37 @@
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.Maui.Media;
+#if __IOS__ || MACCATALYST
+using PlatformView = UIKit.UIWindow;
+#elif MONOANDROID
+using PlatformView = Android.App.Activity;
+#elif WINDOWS
+using PlatformView = Microsoft.UI.Xaml.Window;
+#endif
+
+namespace Microsoft.Maui
+{
+ public static partial class WindowExtensions
+ {
+ public static Task CaptureAsync(this IWindow window)
+ {
+#if PLATFORM
+ if (window?.Handler?.PlatformView is not PlatformView platformView)
+ return Task.FromResult(null);
+
+ if (!Screenshot.Default.IsCaptureSupported)
+ return Task.FromResult(null);
+
+ return CaptureAsync(platformView);
+#else
+ return Task.FromResult(null);
+#endif
+ }
+
+
+#if PLATFORM
+ async static Task CaptureAsync(PlatformView window) =>
+ await Screenshot.Default.CaptureAsync(window);
+#endif
+ }
+}
diff --git a/src/Core/tests/DeviceTests/Handlers/HandlerTestBaseOfT.Tests.cs b/src/Core/tests/DeviceTests/Handlers/HandlerTestBaseOfT.Tests.cs
index b63859cdd959..1026b0be1040 100644
--- a/src/Core/tests/DeviceTests/Handlers/HandlerTestBaseOfT.Tests.cs
+++ b/src/Core/tests/DeviceTests/Handlers/HandlerTestBaseOfT.Tests.cs
@@ -1,15 +1,14 @@
+using System.IO;
using System.Threading.Tasks;
using Microsoft.Maui.DeviceTests.Stubs;
using Microsoft.Maui.Graphics;
+using Microsoft.Maui.Media;
using Xunit;
namespace Microsoft.Maui.DeviceTests
{
public abstract partial class HandlerTestBase
{
- protected async Task GetRenderedView(IViewHandler viewHandler, RenderType type) =>
- await (viewHandler.VirtualView).RenderAsImage(type);
-
[Fact(DisplayName = "Automation Id is set correctly")]
[InlineData()]
public async Task SetAutomationId()
@@ -220,10 +219,9 @@ public async Task ReturnsNonEmptyPlatformViewTransforms(int size)
, Skip = "iOS and Windows can't render elements to images from test runner. It's missing the required root windows."
#endif
)]
- [InlineData(RenderType.JPEG)]
- [InlineData(RenderType.PNG)]
- [InlineData(RenderType.BMP)]
- public async Task RendersAsImage(RenderType type)
+ [InlineData(ScreenshotFormat.Jpeg)]
+ [InlineData(ScreenshotFormat.Png)]
+ public async Task RendersAsImage(ScreenshotFormat type)
{
var view = new TStub()
{
@@ -231,9 +229,12 @@ public async Task RendersAsImage(RenderType type)
Width = 100,
};
- var result = await (await GetValueAsync(view, handler => GetRenderedView(handler, type)));
+ var result = await GetValueAsync(view, handler => handler.VirtualView.CaptureAsync());
Assert.NotNull(result);
- Assert.NotNull(result?.Render);
+
+ using var stream = await result.OpenReadAsync(type);
+
+ Assert.True(stream.Length > 0);
}
}
}
diff --git a/src/Core/tests/DeviceTests/Handlers/HandlerTestBaseOfT.cs b/src/Core/tests/DeviceTests/Handlers/HandlerTestBaseOfT.cs
index fa685c5ace26..110580abf59f 100644
--- a/src/Core/tests/DeviceTests/Handlers/HandlerTestBaseOfT.cs
+++ b/src/Core/tests/DeviceTests/Handlers/HandlerTestBaseOfT.cs
@@ -48,6 +48,15 @@ protected Task GetValueAsync(IView view, Func
});
}
+ protected Task GetValueAsync(IView view, Func> func)
+ {
+ return InvokeOnMainThreadAsync(async () =>
+ {
+ var handler = CreateHandler(view);
+ return await func(handler);
+ });
+ }
+
protected Task SetValueAsync(IView view, TValue value, Action func)
{
return InvokeOnMainThreadAsync(() =>
diff --git a/src/Essentials/samples/Samples/View/ScreenshotPage.xaml b/src/Essentials/samples/Samples/View/ScreenshotPage.xaml
index f06e3908979c..2d998fad675e 100644
--- a/src/Essentials/samples/Samples/View/ScreenshotPage.xaml
+++ b/src/Essentials/samples/Samples/View/ScreenshotPage.xaml
@@ -9,23 +9,20 @@
-
+
-
+
-
+
-
+
\ No newline at end of file
diff --git a/src/Essentials/src/Accelerometer/Accelerometer.android.cs b/src/Essentials/src/Accelerometer/Accelerometer.android.cs
index 77684dfb02a5..8f175b2a8633 100644
--- a/src/Essentials/src/Accelerometer/Accelerometer.android.cs
+++ b/src/Essentials/src/Accelerometer/Accelerometer.android.cs
@@ -1,33 +1,40 @@
+#nullable enable
+using System;
+using Android.App;
+using Android.Content;
using Android.Hardware;
-using Android.Runtime;
-using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class AccelerometerImplementation
+ partial class AccelerometerImplementation
{
- public bool IsSupported =>
- Platform.SensorManager?.GetDefaultSensor(SensorType.Accelerometer) != null;
+ static SensorManager? _sensorManager;
+ static Sensor? _accelerometer;
- AccelerometerListener listener;
- Sensor accelerometer;
+ static SensorManager? SensorManager =>
+ _sensorManager ??= Application.Context.GetSystemService(Context.SensorService) as SensorManager;
+
+ static Sensor? Sensor =>
+ _accelerometer ??= SensorManager?.GetDefaultSensor(SensorType.Accelerometer);
+
+ public bool IsSupported => Sensor is not null;
+
+ AccelerometerListener? _listener;
void PlatformStart(SensorSpeed sensorSpeed)
{
+ _listener = new AccelerometerListener(OnChanged);
+
var delay = sensorSpeed.ToPlatform();
- listener = new AccelerometerListener(this);
- accelerometer = Platform.SensorManager.GetDefaultSensor(SensorType.Accelerometer);
- Platform.SensorManager.RegisterListener(listener, accelerometer, delay);
+ SensorManager!.RegisterListener(_listener, Sensor, delay);
}
void PlatformStop()
{
- if (listener == null || accelerometer == null)
- return;
+ SensorManager!.UnregisterListener(_listener, Sensor);
- Platform.SensorManager.UnregisterListener(listener, accelerometer);
- listener.Dispose();
- listener = null;
+ _listener!.Dispose();
+ _listener = null;
}
}
@@ -36,24 +43,25 @@ class AccelerometerListener : Java.Lang.Object, ISensorEventListener
// acceleration due to gravity
const double gravity = 9.81;
- AccelerometerImplementation _accelerometer;
-
- internal AccelerometerListener(AccelerometerImplementation accelerometer)
+ public AccelerometerListener(Action changeHandler)
{
- _accelerometer = accelerometer;
+ ChangeHandler = changeHandler;
}
- void ISensorEventListener.OnAccuracyChanged(Sensor sensor, [GeneratedEnum] SensorStatus accuracy)
+ public readonly Action ChangeHandler;
+
+ void ISensorEventListener.OnAccuracyChanged(Sensor? sensor, SensorStatus accuracy)
{
}
- void ISensorEventListener.OnSensorChanged(SensorEvent e)
+ void ISensorEventListener.OnSensorChanged(SensorEvent? e)
{
- if ((e?.Values?.Count ?? 0) < 3)
+ var values = e?.Values ?? Array.Empty();
+ if (values.Count < 3)
return;
- var data = new AccelerometerData(e.Values[0] / gravity, e.Values[1] / gravity, e.Values[2] / gravity);
- _accelerometer.OnChanged(data);
+ var data = new AccelerometerData(values[0] / gravity, values[1] / gravity, values[2] / gravity);
+ ChangeHandler?.Invoke(data);
}
}
}
diff --git a/src/Essentials/src/Accelerometer/Accelerometer.ios.watchos.cs b/src/Essentials/src/Accelerometer/Accelerometer.ios.watchos.cs
index b3c7054a49f1..4e0d62815c18 100644
--- a/src/Essentials/src/Accelerometer/Accelerometer.ios.watchos.cs
+++ b/src/Essentials/src/Accelerometer/Accelerometer.ios.watchos.cs
@@ -1,19 +1,24 @@
+#nullable enable
using CoreMotion;
using Foundation;
using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class AccelerometerImplementation
+ partial class AccelerometerImplementation
{
+ static CMMotionManager? motionManager;
+
+ static CMMotionManager MotionManager =>
+ motionManager ??= new CMMotionManager();
+
public bool IsSupported =>
- Platform.MotionManager?.AccelerometerAvailable ?? false;
+ MotionManager.AccelerometerAvailable;
void PlatformStart(SensorSpeed sensorSpeed)
{
- var manager = Platform.MotionManager;
- manager.AccelerometerUpdateInterval = sensorSpeed.ToPlatform();
- manager.StartAccelerometerUpdates(Platform.GetCurrentQueue(), DataUpdated);
+ MotionManager.AccelerometerUpdateInterval = sensorSpeed.ToPlatform();
+ MotionManager.StartAccelerometerUpdates(NSOperationQueue.CurrentQueue ?? new NSOperationQueue(), DataUpdated);
}
void DataUpdated(CMAccelerometerData data, NSError error)
@@ -27,6 +32,6 @@ void DataUpdated(CMAccelerometerData data, NSError error)
}
void PlatformStop() =>
- Platform.MotionManager?.StopAccelerometerUpdates();
+ MotionManager.StopAccelerometerUpdates();
}
}
diff --git a/src/Essentials/src/Accelerometer/Accelerometer.netstandard.tvos.macos.cs b/src/Essentials/src/Accelerometer/Accelerometer.netstandard.tvos.macos.cs
index 9560db797da5..1c14dbf06373 100644
--- a/src/Essentials/src/Accelerometer/Accelerometer.netstandard.tvos.macos.cs
+++ b/src/Essentials/src/Accelerometer/Accelerometer.netstandard.tvos.macos.cs
@@ -3,7 +3,7 @@
namespace Microsoft.Maui.Devices.Sensors
{
///
- public partial class AccelerometerImplementation
+ partial class AccelerometerImplementation
{
public bool IsSupported =>
throw ExceptionUtils.NotSupportedOrImplementedException;
diff --git a/src/Essentials/src/Accelerometer/Accelerometer.shared.cs b/src/Essentials/src/Accelerometer/Accelerometer.shared.cs
index fc2ccd101374..ac2e35ef88f1 100644
--- a/src/Essentials/src/Accelerometer/Accelerometer.shared.cs
+++ b/src/Essentials/src/Accelerometer/Accelerometer.shared.cs
@@ -1,6 +1,5 @@
#nullable enable
using System;
-using System.ComponentModel;
using System.Numerics;
using Microsoft.Maui.ApplicationModel;
@@ -9,66 +8,52 @@ namespace Microsoft.Maui.Devices.Sensors
public interface IAccelerometer
{
event EventHandler? ReadingChanged;
+
event EventHandler? ShakeDetected;
+
bool IsSupported { get; }
+
bool IsMonitoring { get; }
+
void Start(SensorSpeed sensorSpeed);
+
void Stop();
}
///
- public static partial class Accelerometer
+ public static class Accelerometer
{
public static event EventHandler ReadingChanged
{
- add => Current.ReadingChanged += value;
- remove => Current.ReadingChanged -= value;
+ add => Default.ReadingChanged += value;
+ remove => Default.ReadingChanged -= value;
}
public static event EventHandler ShakeDetected
{
- add => Current.ShakeDetected += value;
- remove => Current.ShakeDetected -= value;
+ add => Default.ShakeDetected += value;
+ remove => Default.ShakeDetected -= value;
}
- internal static bool IsSupported => Current.IsSupported;
+ public static bool IsSupported
+ => Default.IsSupported;
///
- public static bool IsMonitoring => Current.IsMonitoring;
+ public static bool IsMonitoring => Default.IsMonitoring;
///
- public static void Start(SensorSpeed sensorSpeed)
- {
- if (!Current.IsSupported)
- throw new FeatureNotSupportedException();
-
- if (Current.IsMonitoring)
- throw new InvalidOperationException("Accelerometer has already been started.");
-
- Current.Start(sensorSpeed);
- }
+ public static void Start(SensorSpeed sensorSpeed) => Default.Start(sensorSpeed);
///
- public static void Stop()
- {
- if (!Current.IsSupported)
- throw new FeatureNotSupportedException();
+ public static void Stop() => Default.Stop();
- if (!Current.IsMonitoring)
- return;
+ static IAccelerometer? defaultImplementation;
- Current.Stop();
- }
-
- static IAccelerometer? currentImplementation;
+ public static IAccelerometer Default =>
+ defaultImplementation ??= new AccelerometerImplementation();
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static IAccelerometer Current =>
- currentImplementation ??= new AccelerometerImplementation();
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static void SetCurrent(IAccelerometer? implementation) =>
- currentImplementation = implementation;
+ internal static void SetDefault(IAccelerometer? implementation) =>
+ defaultImplementation = implementation;
}
///
@@ -109,7 +94,7 @@ public bool Equals(AccelerometerData other) =>
left.Equals(right);
public static bool operator !=(AccelerometerData left, AccelerometerData right) =>
- !left.Equals(right);
+ !left.Equals(right);
///
public override int GetHashCode() =>
@@ -121,11 +106,8 @@ public override string ToString() =>
$"{nameof(Acceleration.Y)}: {Acceleration.Y}, " +
$"{nameof(Acceleration.Z)}: {Acceleration.Z}";
}
-}
-namespace Microsoft.Maui.Devices.Sensors
-{
- public partial class AccelerometerImplementation : IAccelerometer
+ partial class AccelerometerImplementation : IAccelerometer
{
const double accelerationThreshold = 169;
@@ -143,6 +125,12 @@ public partial class AccelerometerImplementation : IAccelerometer
public void Start(SensorSpeed sensorSpeed)
{
+ if (!IsSupported)
+ throw new FeatureNotSupportedException();
+
+ if (IsMonitoring)
+ throw new InvalidOperationException("Accelerometer has already been started.");
+
IsMonitoring = true;
useSyncContext = sensorSpeed == SensorSpeed.Default || sensorSpeed == SensorSpeed.UI;
@@ -159,6 +147,12 @@ public void Start(SensorSpeed sensorSpeed)
public void Stop()
{
+ if (!IsSupported)
+ throw new FeatureNotSupportedException();
+
+ if (!IsMonitoring)
+ return;
+
IsMonitoring = false;
try
diff --git a/src/Essentials/src/Accelerometer/Accelerometer.tizen.cs b/src/Essentials/src/Accelerometer/Accelerometer.tizen.cs
index a0a5965064bc..d0054512a9cd 100644
--- a/src/Essentials/src/Accelerometer/Accelerometer.tizen.cs
+++ b/src/Essentials/src/Accelerometer/Accelerometer.tizen.cs
@@ -3,7 +3,7 @@
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class AccelerometerImplementation
+ partial class AccelerometerImplementation
{
internal static TizenAccelerometer DefaultSensor =>
(TizenAccelerometer)Platform.GetDefaultSensor(SensorType.Accelerometer);
diff --git a/src/Essentials/src/Accelerometer/Accelerometer.uwp.cs b/src/Essentials/src/Accelerometer/Accelerometer.uwp.cs
index fdd04254e6de..6ad719be2a94 100644
--- a/src/Essentials/src/Accelerometer/Accelerometer.uwp.cs
+++ b/src/Essentials/src/Accelerometer/Accelerometer.uwp.cs
@@ -3,7 +3,7 @@
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class AccelerometerImplementation
+ partial class AccelerometerImplementation
{
// keep around a reference so we can stop this same instance
WindowsAccelerometer sensor;
diff --git a/src/Essentials/src/AppActions/AppActions.android.cs b/src/Essentials/src/AppActions/AppActions.android.cs
index 0769707138fa..ef942df8252b 100755
--- a/src/Essentials/src/AppActions/AppActions.android.cs
+++ b/src/Essentials/src/AppActions/AppActions.android.cs
@@ -1,6 +1,8 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Graphics.Drawables;
@@ -8,11 +10,11 @@
namespace Microsoft.Maui.ApplicationModel
{
- public partial class AppActionsImplementation : IAppActions
+ class AppActionsImplementation : IAppActions, IPlatformAppActions
{
- public string Type => "XE_APP_ACTION_TYPE";
- public bool IsSupported
- => Platform.HasApiLevelNMr1;
+ public const string IntentAction = "ACTION_XE_APP_ACTION";
+
+ public bool IsSupported => OperatingSystem.IsAndroidVersionAtLeast(25);
public Task> GetAsync()
{
@@ -20,9 +22,12 @@ public Task> GetAsync()
throw new FeatureNotSupportedException();
#if __ANDROID_25__
- return Task.FromResult(Platform.ShortcutManager.DynamicShortcuts.Select(s => s.ToAppAction()));
+ if (Application.Context.GetSystemService(Context.ShortcutService) is not ShortcutManager manager)
+ throw new FeatureNotSupportedException();
+
+ return Task.FromResult(manager.DynamicShortcuts.Select(s => s.ToAppAction()));
#else
- return Task.FromResult < IEnumerable < AppAction >> (null);
+ return Task.FromResult>(null);
#endif
}
@@ -32,19 +37,33 @@ public Task SetAsync(IEnumerable actions)
throw new FeatureNotSupportedException();
#if __ANDROID_25__
+ if (Application.Context.GetSystemService(Context.ShortcutService) is not ShortcutManager manager)
+ throw new FeatureNotSupportedException();
+
using var list = new JavaList(actions.Select(a => a.ToShortcutInfo()));
- Platform.ShortcutManager.SetDynamicShortcuts(list);
+ manager.SetDynamicShortcuts(list);
#endif
return Task.CompletedTask;
}
- public Task SetAsync(params AppAction[] actions)
- {
- return SetAsync(actions);
+ public event EventHandler AppActionActivated;
+
+ public void OnResume(Intent intent) =>
+ OnNewIntent(intent);
+
+ public void OnNewIntent(Intent intent)
+ {
+ if (intent?.Action == IntentAction)
+ {
+ var appAction = intent.ToAppAction();
+
+ if (!string.IsNullOrEmpty(appAction?.Id))
+ AppActionActivated?.Invoke(null, new AppActionEventArgs(appAction));
+ }
}
}
- internal static partial class AppActionsExtensions
+ static partial class AppActionsExtensions
{
internal static AppAction ToAppAction(this ShortcutInfo shortcutInfo) =>
new AppAction(shortcutInfo.Id, shortcutInfo.ShortLabel, shortcutInfo.LongLabel);
@@ -60,10 +79,12 @@ internal static AppAction ToAppAction(this Intent intent)
intent.GetStringExtra(extraAppActionTitle),
intent.GetStringExtra(extraAppActionSubtitle),
intent.GetStringExtra(extraAppActionIcon));
-
+
internal static ShortcutInfo ToShortcutInfo(this AppAction action)
{
- var shortcut = new ShortcutInfo.Builder(Platform.AppContext, action.Id)
+ var context = Application.Context;
+
+ var shortcut = new ShortcutInfo.Builder(context, action.Id)
.SetShortLabel(action.Title);
if (!string.IsNullOrWhiteSpace(action.Subtitle))
@@ -73,13 +94,13 @@ internal static ShortcutInfo ToShortcutInfo(this AppAction action)
if (!string.IsNullOrWhiteSpace(action.Icon))
{
- var iconResId = Platform.AppContext.Resources.GetIdentifier(action.Icon, "drawable", Platform.AppContext.PackageName);
+ var iconResId = context.Resources.GetIdentifier(action.Icon, "drawable", context.PackageName);
- shortcut.SetIcon(Icon.CreateWithResource(Platform.AppContext, iconResId));
+ shortcut.SetIcon(Icon.CreateWithResource(context, iconResId));
}
- var intent = new Intent(Platform.Intent.ActionAppAction);
- intent.SetPackage(Platform.AppContext.PackageName);
+ var intent = new Intent(AppActionsImplementation.IntentAction);
+ intent.SetPackage(context.PackageName);
intent.SetFlags(ActivityFlags.ClearTop | ActivityFlags.SingleTop);
intent.PutExtra(extraAppActionId, action.Id);
intent.PutExtra(extraAppActionTitle, action.Title);
@@ -90,5 +111,5 @@ internal static ShortcutInfo ToShortcutInfo(this AppAction action)
return shortcut.Build();
}
- }
+ }
}
diff --git a/src/Essentials/src/AppActions/AppActions.ios.cs b/src/Essentials/src/AppActions/AppActions.ios.cs
index 3a6d87d09597..9eb640b5e758 100755
--- a/src/Essentials/src/AppActions/AppActions.ios.cs
+++ b/src/Essentials/src/AppActions/AppActions.ios.cs
@@ -1,18 +1,17 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Foundation;
-using ObjCRuntime;
using UIKit;
namespace Microsoft.Maui.ApplicationModel
{
- public partial class AppActionsImplementation : IAppActions
+ partial class AppActionsImplementation : IAppActions, IPlatformAppActions
{
- public string Type => "XE_APP_ACTION_TYPE";
+ public const string ShortcutType = "XE_APP_ACTION_TYPE";
- public bool IsSupported
- => true;
+ public bool IsSupported => true;
public Task> GetAsync()
{
@@ -32,13 +31,20 @@ public Task SetAsync(IEnumerable actions)
return Task.CompletedTask;
}
- public Task SetAsync(params AppAction[] actions)
- {
- return SetAsync(actions.AsEnumerable());
+ public event EventHandler AppActionActivated;
+
+ public void PerformActionForShortcutItem(UIApplication application, UIApplicationShortcutItem shortcutItem, UIOperationHandler completionHandler)
+ {
+ if (shortcutItem.Type == ShortcutType)
+ {
+ var appAction = shortcutItem.ToAppAction();
+
+ AppActionActivated?.Invoke(null, new AppActionEventArgs(appAction));
+ }
}
}
- internal static partial class AppActionsExtensions
+ static partial class AppActionsExtensions
{
internal static AppAction ToAppAction(this UIApplicationShortcutItem shortcutItem)
{
@@ -70,12 +76,11 @@ internal static UIApplicationShortcutItem ToShortcutItem(this AppAction action)
}
return new UIApplicationShortcutItem(
- action.Type,
+ AppActionsImplementation.ShortcutType,
action.Title,
action.Subtitle,
action.Icon != null ? UIApplicationShortcutIcon.FromTemplateImageName(action.Icon) : null,
new NSDictionary(keys.ToArray(), values.ToArray()));
}
-
}
}
diff --git a/src/Essentials/src/AppActions/AppActions.netstandard.tvos.watchos.macos.tizen.cs b/src/Essentials/src/AppActions/AppActions.netstandard.tvos.watchos.macos.tizen.cs
index a0055c43fbb3..5cf70db8debc 100755
--- a/src/Essentials/src/AppActions/AppActions.netstandard.tvos.watchos.macos.tizen.cs
+++ b/src/Essentials/src/AppActions/AppActions.netstandard.tvos.watchos.macos.tizen.cs
@@ -5,11 +5,10 @@
namespace Microsoft.Maui.ApplicationModel
{
///
- public partial class AppActionsImplementation : IAppActions
+ partial class AppActionsImplementation : IAppActions
{
- public string Type => "XE_APP_ACTION_TYPE";
- public bool IsSupported
- => throw ExceptionUtils.NotSupportedOrImplementedException;
+ public bool IsSupported =>
+ throw ExceptionUtils.NotSupportedOrImplementedException;
public Task> GetAsync() =>
throw ExceptionUtils.NotSupportedOrImplementedException;
@@ -17,7 +16,8 @@ public Task> GetAsync() =>
public Task SetAsync(IEnumerable actions) =>
throw ExceptionUtils.NotSupportedOrImplementedException;
- public Task SetAsync(params AppAction[] actions) =>
- throw ExceptionUtils.NotSupportedOrImplementedException;
+#pragma warning disable CS0067 // The event is never used
+ public event EventHandler AppActionActivated;
+#pragma warning restore CS0067 // The event is never used
}
}
diff --git a/src/Essentials/src/AppActions/AppActions.shared.cs b/src/Essentials/src/AppActions/AppActions.shared.cs
index 8147af16c8e7..feead4ab00f0 100755
--- a/src/Essentials/src/AppActions/AppActions.shared.cs
+++ b/src/Essentials/src/AppActions/AppActions.shared.cs
@@ -1,7 +1,7 @@
+#nullable enable
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
-using System.ComponentModel;
namespace Microsoft.Maui.ApplicationModel
{
@@ -9,23 +9,31 @@ public interface IAppActions
{
bool IsSupported { get; }
- string Type { get; }
+ Task> GetAsync();
- Task> GetAsync ();
- Task SetAsync (IEnumerable actions);
+ Task SetAsync(IEnumerable actions);
- Task SetAsync (params AppAction[] actions);
+ event EventHandler? AppActionActivated;
+ }
+
+ public interface IPlatformAppActions
+ {
+#if WINDOWS
+ Task OnLaunched(UI.Xaml.LaunchActivatedEventArgs e);
+#elif IOS || MACCATALYST
+ void PerformActionForShortcutItem(UIKit.UIApplication application, UIKit.UIApplicationShortcutItem shortcutItem, UIKit.UIOperationHandler completionHandler);
+#elif ANDROID
+ void OnNewIntent(Android.Content.Intent? intent);
+ void OnResume(Android.Content.Intent? intent);
+#endif
}
///
- public static partial class AppActions
+ public static class AppActions
{
- internal static bool IsSupported
+ public static bool IsSupported
=> Current.IsSupported;
- internal static string Type
- => Current.Type;
-
///
public static Task> GetAsync()
=> Current.GetAsync();
@@ -38,24 +46,45 @@ public static Task SetAsync(params AppAction[] actions)
public static Task SetAsync(IEnumerable actions)
=> Current.SetAsync(actions);
- public static event EventHandler OnAppAction;
-
- internal static void InvokeOnAppAction(object sender, AppAction appAction)
- => OnAppAction?.Invoke(sender, new AppActionEventArgs(appAction));
+ ///
+ public static event EventHandler? OnAppAction
+ {
+ add => Current.AppActionActivated += value;
+ remove => Current.AppActionActivated -= value;
+ }
-#nullable enable
static IAppActions? currentImplementation;
-#nullable disable
- [EditorBrowsable(EditorBrowsableState.Never)]
public static IAppActions Current =>
currentImplementation ??= new AppActionsImplementation();
- [EditorBrowsable(EditorBrowsableState.Never)]
-#nullable enable
- public static void SetCurrent(IAppActions? implementation) =>
+ internal static void SetCurrent(IAppActions? implementation) =>
currentImplementation = implementation;
-#nullable disable
+ }
+
+ public static partial class AppActionsExtensions
+ {
+ static IPlatformAppActions AsPlatform(this IAppActions appActions)
+ {
+ if (appActions is not IPlatformAppActions platform)
+ throw new PlatformNotSupportedException("This implementation of IAppActions does not implement IPlatformAppActions.");
+
+ return platform;
+ }
+
+#if WINDOWS
+ public static Task OnLaunched(this IAppActions appActions, UI.Xaml.LaunchActivatedEventArgs e) =>
+ appActions.AsPlatform().OnLaunched(e);
+#elif IOS || MACCATALYST
+ public static void PerformActionForShortcutItem(this IAppActions appActions, UIKit.UIApplication application, UIKit.UIApplicationShortcutItem shortcutItem, UIKit.UIOperationHandler completionHandler) =>
+ appActions.AsPlatform().PerformActionForShortcutItem(application, shortcutItem, completionHandler);
+#elif ANDROID
+ public static void OnNewIntent(this IAppActions appActions, Android.Content.Intent? intent) =>
+ appActions.AsPlatform().OnNewIntent(intent);
+
+ public static void OnResume(this IAppActions appActions, Android.Content.Intent? intent) =>
+ appActions.AsPlatform().OnResume(intent);
+#endif
}
///
@@ -73,7 +102,7 @@ public AppActionEventArgs(AppAction appAction)
public class AppAction
{
///
- public AppAction(string id, string title, string subtitle = null, string icon = null)
+ public AppAction(string id, string title, string? subtitle = null, string? icon = null)
{
Id = id ?? throw new ArgumentNullException(nameof(id));
Title = title ?? throw new ArgumentNullException(nameof(title));
@@ -81,18 +110,16 @@ public AppAction(string id, string title, string subtitle = null, string icon =
Subtitle = subtitle;
Icon = icon;
}
- public string Type => "XE_APP_ACTION_TYPE";
///
public string Title { get; set; }
///
- public string Subtitle { get; set; }
+ public string? Subtitle { get; set; }
///
public string Id { get; set; }
- internal string Icon { get; set; }
-
+ internal string? Icon { get; set; }
}
}
diff --git a/src/Essentials/src/AppActions/AppActions.uwp.cs b/src/Essentials/src/AppActions/AppActions.uwp.cs
index 474beac44869..0295be5bf8f2 100755
--- a/src/Essentials/src/AppActions/AppActions.uwp.cs
+++ b/src/Essentials/src/AppActions/AppActions.uwp.cs
@@ -4,58 +4,13 @@
using System.Text;
using System.Threading.Tasks;
using Windows.UI.StartScreen;
-
-#if WINDOWS_UWP
-using Windows.ApplicationModel.Activation;
-#elif WINDOWS
using Microsoft.UI.Xaml;
-#endif
-
-namespace Microsoft.Maui.ApplicationModel
-{
- public static partial class AppActions
- {
- public static string IconDirectory { get; set; } = "";
-
- public static string IconExtension { get; set; } = "png";
-
- internal static async Task OnLaunched(LaunchActivatedEventArgs e)
- {
- var args = e?.Arguments;
-#if !WINDOWS_UWP
- if (string.IsNullOrEmpty(args))
- {
- var cliArgs = Environment.GetCommandLineArgs();
- if (cliArgs?.Length > 1)
- args = cliArgs[1];
- }
-#endif
-
- if (args?.StartsWith(AppActionsExtensions.AppActionPrefix) ?? false)
- {
- var id = AppActionsExtensions.ArgumentsToId(args);
-
- if (!string.IsNullOrEmpty(id))
- {
- var actions = await AppActions.GetAsync();
- var appAction = actions.FirstOrDefault(a => a.Id == id);
-
- if (appAction != null)
- InvokeOnAppAction(null, appAction);
- }
- }
- }
- }
-}
namespace Microsoft.Maui.ApplicationModel
{
- public class AppActionsImplementation : IAppActions
+ class AppActionsImplementation : IAppActions, IPlatformAppActions
{
- public string Type => "XE_APP_ACTION_TYPE";
-
- public bool IsSupported
- => true;
+ public bool IsSupported => true;
public async Task> GetAsync()
{
@@ -88,16 +43,43 @@ public async Task SetAsync(IEnumerable actions)
await jumpList.SaveAsync();
}
- public Task SetAsync(params AppAction[] actions)
- {
- return SetAsync(actions.AsEnumerable());
+ public event EventHandler AppActionActivated;
+
+ public async Task OnLaunched(LaunchActivatedEventArgs e)
+ {
+ var args = e?.Arguments;
+#if !WINDOWS_UWP
+ if (string.IsNullOrEmpty(args))
+ {
+ var cliArgs = Environment.GetCommandLineArgs();
+ if (cliArgs?.Length > 1)
+ args = cliArgs[1];
+ }
+#endif
+
+ if (args?.StartsWith(AppActionsExtensions.AppActionPrefix) ?? false)
+ {
+ var id = AppActionsExtensions.ArgumentsToId(args);
+
+ if (!string.IsNullOrEmpty(id))
+ {
+ var actions = await GetAsync();
+ var appAction = actions.FirstOrDefault(a => a.Id == id);
+
+ if (appAction != null)
+ AppActionActivated?.Invoke(null, new AppActionEventArgs(appAction));
+ }
+ }
}
}
- internal static class AppActionsExtensions
+ static partial class AppActionsExtensions
{
internal const string AppActionPrefix = "XE_APP_ACTIONS-";
+ internal const string iconDirectory = "";
+ internal const string iconExtension = ".png";
+
internal static string ArgumentsToId(this string arguments)
{
if (arguments?.StartsWith(AppActionPrefix) ?? false)
@@ -119,11 +101,11 @@ internal static JumpListItem ToJumpListItem(this AppAction action)
if (!string.IsNullOrEmpty(action.Icon))
{
- var dir = AppActions.IconDirectory.Trim('/', '\\').Replace('\\', '/');
+ var dir = iconDirectory?.Trim('/', '\\').Replace('\\', '/');
if (!string.IsNullOrEmpty(dir))
dir += "/";
- var ext = AppActions.IconExtension;
+ var ext = iconExtension;
if (!string.IsNullOrEmpty(ext) && !ext.StartsWith("."))
ext = "." + ext;
diff --git a/src/Essentials/src/AppInfo/AppInfo.android.cs b/src/Essentials/src/AppInfo/AppInfo.android.cs
index 5a2434a7048a..759918af81e5 100644
--- a/src/Essentials/src/AppInfo/AppInfo.android.cs
+++ b/src/Essentials/src/AppInfo/AppInfo.android.cs
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
+using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Content.Res;
@@ -8,16 +9,16 @@
namespace Microsoft.Maui.ApplicationModel
{
- public class AppInfoImplementation : IAppInfo
+ class AppInfoImplementation : IAppInfo
{
- public string PackageName => Platform.AppContext.PackageName;
+ public string PackageName => Application.Context.PackageName;
public string Name
{
get
{
- var applicationInfo = Platform.AppContext.ApplicationInfo;
- var packageManager = Platform.AppContext.PackageManager;
+ var applicationInfo = Application.Context.ApplicationInfo;
+ var packageManager = Application.Context.PackageManager;
return applicationInfo.LoadLabel(packageManager);
}
}
@@ -28,8 +29,8 @@ public string VersionString
{
get
{
- var pm = Platform.AppContext.PackageManager;
- var packageName = Platform.AppContext.PackageName;
+ var pm = Application.Context.PackageManager;
+ var packageName = Application.Context.PackageName;
using (var info = pm.GetPackageInfo(packageName, PackageInfoFlags.MetaData))
{
return info.VersionName;
@@ -41,8 +42,8 @@ public string BuildString
{
get
{
- var pm = Platform.AppContext.PackageManager;
- var packageName = Platform.AppContext.PackageName;
+ var pm = Application.Context.PackageManager;
+ var packageName = Application.Context.PackageName;
using (var info = pm.GetPackageInfo(packageName, PackageInfoFlags.MetaData))
{
#if __ANDROID_28__
@@ -58,7 +59,7 @@ public string BuildString
public void ShowSettingsUI()
{
- var context = Platform.GetCurrentActivity(false) ?? Platform.AppContext;
+ var context = ActivityStateManager.Default.GetCurrentActivity(false) ?? Application.Context;
var settingsIntent = new Intent();
settingsIntent.SetAction(global::Android.Provider.Settings.ActionApplicationDetailsSettings);
@@ -68,7 +69,7 @@ public void ShowSettingsUI()
var flags = ActivityFlags.NewTask | ActivityFlags.NoHistory | ActivityFlags.ExcludeFromRecents;
#if __ANDROID_24__
- if (Platform.HasApiLevelN)
+ if (OperatingSystem.IsAndroidVersionAtLeast(24))
flags |= ActivityFlags.LaunchAdjacent;
#endif
settingsIntent.SetFlags(flags);
@@ -77,7 +78,7 @@ public void ShowSettingsUI()
}
public AppTheme RequestedTheme
- => (Platform.AppContext.Resources.Configuration.UiMode & UiMode.NightMask) switch
+ => (Application.Context.Resources.Configuration.UiMode & UiMode.NightMask) switch
{
UiMode.NightYes => AppTheme.Dark,
UiMode.NightNo => AppTheme.Light,
@@ -93,7 +94,7 @@ public LayoutDirection RequestedLayoutDirection
if (!OperatingSystem.IsAndroidVersionAtLeast(17))
return LayoutDirection.LeftToRight;
- var config = Platform.AppContext.Resources?.Configuration;
+ var config = Application.Context.Resources?.Configuration;
if (config == null)
return LayoutDirection.Unknown;
diff --git a/src/Essentials/src/AppInfo/AppInfo.ios.tvos.watchos.macos.cs b/src/Essentials/src/AppInfo/AppInfo.ios.tvos.watchos.macos.cs
index 1baf2bae1317..3854698f4e96 100644
--- a/src/Essentials/src/AppInfo/AppInfo.ios.tvos.watchos.macos.cs
+++ b/src/Essentials/src/AppInfo/AppInfo.ios.tvos.watchos.macos.cs
@@ -11,7 +11,7 @@
namespace Microsoft.Maui.ApplicationModel
{
- public class AppInfoImplementation : IAppInfo
+ class AppInfoImplementation : IAppInfo
{
public AppPackagingModel PackagingModel => AppPackagingModel.Packaged;
@@ -26,21 +26,21 @@ public class AppInfoImplementation : IAppInfo
public string BuildString => GetBundleValue("CFBundleVersion");
string GetBundleValue(string key)
- => NSBundle.MainBundle.ObjectForInfoDictionary(key)?.ToString();
+ => NSBundle.MainBundle.ObjectForInfoDictionary(key)?.ToString();
#if __IOS__ || __TVOS__
public async void ShowSettingsUI()
- => await Launcher.OpenAsync(UIApplication.OpenSettingsUrlString);
+ => await Launcher.Default.OpenAsync(UIApplication.OpenSettingsUrlString);
#elif __MACOS__
- public void ShowSettingsUI()
- {
- MainThread.BeginInvokeOnMainThread(() =>
- {
- var prefsApp = ScriptingBridge.SBApplication.FromBundleIdentifier("com.apple.systempreferences");
- prefsApp.SendMode = ScriptingBridge.AESendMode.NoReply;
- prefsApp.Activate();
- });
- }
+ public void ShowSettingsUI()
+ {
+ MainThread.BeginInvokeOnMainThread(() =>
+ {
+ var prefsApp = ScriptingBridge.SBApplication.FromBundleIdentifier("com.apple.systempreferences");
+ prefsApp.SendMode = ScriptingBridge.AESendMode.NoReply;
+ prefsApp.Activate();
+ });
+ }
#else
public void ShowSettingsUI() =>
throw new FeatureNotSupportedException();
@@ -55,7 +55,7 @@ public AppTheme RequestedTheme
return AppTheme.Unspecified;
var traits =
- MainThread.InvokeOnMainThread(() => Platform.GetCurrentUIViewController()?.TraitCollection) ??
+ MainThread.InvokeOnMainThread(() => WindowStateManager.Default.GetCurrentUIViewController()?.TraitCollection) ??
UITraitCollection.CurrentTraitCollection;
var uiStyle = traits.UserInterfaceStyle;
@@ -69,8 +69,8 @@ public AppTheme RequestedTheme
}
}
#elif __MACOS__
- public AppTheme RequestedTheme
- {
+ public AppTheme RequestedTheme
+ {
get
{
if (OperatingSystem.IsMacOSVersionAtLeast(10, 14))
@@ -89,7 +89,7 @@ public AppTheme RequestedTheme
}
return AppTheme.Light;
}
- }
+ }
#else
public AppTheme RequestedTheme =>
AppTheme.Unspecified;
@@ -100,7 +100,7 @@ public LayoutDirection RequestedLayoutDirection
{
get
{
- var currentWindow = Platform.GetCurrentWindow(false);
+ var currentWindow = WindowStateManager.Default.GetCurrentUIWindow(false);
UIUserInterfaceLayoutDirection layoutDirection =
currentWindow?.EffectiveUserInterfaceLayoutDirection ??
UIApplication.SharedApplication.UserInterfaceLayoutDirection;
diff --git a/src/Essentials/src/AppInfo/AppInfo.netstandard.cs b/src/Essentials/src/AppInfo/AppInfo.netstandard.cs
index c4e1cfd2728c..eb5c47ac0eec 100644
--- a/src/Essentials/src/AppInfo/AppInfo.netstandard.cs
+++ b/src/Essentials/src/AppInfo/AppInfo.netstandard.cs
@@ -1,7 +1,7 @@
namespace Microsoft.Maui.ApplicationModel
{
///
- public class AppInfoImplementation : IAppInfo
+ class AppInfoImplementation : IAppInfo
{
public string PackageName => throw ExceptionUtils.NotSupportedOrImplementedException;
diff --git a/src/Essentials/src/AppInfo/AppInfo.shared.cs b/src/Essentials/src/AppInfo/AppInfo.shared.cs
index 84bea1b0dd7d..89905c90ebda 100644
--- a/src/Essentials/src/AppInfo/AppInfo.shared.cs
+++ b/src/Essentials/src/AppInfo/AppInfo.shared.cs
@@ -1,6 +1,5 @@
#nullable enable
using System;
-using System.ComponentModel;
namespace Microsoft.Maui.ApplicationModel
{
@@ -55,12 +54,10 @@ public static class AppInfo
static IAppInfo? currentImplementation;
- [EditorBrowsable(EditorBrowsableState.Never)]
public static IAppInfo Current =>
currentImplementation ??= new AppInfoImplementation();
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static void SetCurrent(IAppInfo? implementation) =>
+ internal static void SetCurrent(IAppInfo? implementation) =>
currentImplementation = implementation;
}
diff --git a/src/Essentials/src/AppInfo/AppInfo.tizen.cs b/src/Essentials/src/AppInfo/AppInfo.tizen.cs
index da056883c599..c0d8f0595259 100644
--- a/src/Essentials/src/AppInfo/AppInfo.tizen.cs
+++ b/src/Essentials/src/AppInfo/AppInfo.tizen.cs
@@ -3,7 +3,7 @@
namespace Microsoft.Maui.ApplicationModel
{
- public class AppInfoImplementation
+ class AppInfoImplementation
{
public string PackageName
=> Application.Current.ApplicationInfo.PackageId;
diff --git a/src/Essentials/src/AppInfo/AppInfo.uwp.cs b/src/Essentials/src/AppInfo/AppInfo.uwp.cs
index fc5911ebd58e..25ddf08ac84f 100644
--- a/src/Essentials/src/AppInfo/AppInfo.uwp.cs
+++ b/src/Essentials/src/AppInfo/AppInfo.uwp.cs
@@ -9,28 +9,13 @@
namespace Microsoft.Maui.ApplicationModel
{
- public class AppInfoImplementation : IAppInfo
+ class AppInfoImplementation : IAppInfo
{
- static Lazy _isPackagedAppLazy = new Lazy(() =>
- {
- try
- {
- if (Package.Current != null)
- return true;
- }
- catch
- {
- // no-op
- }
-
- return false;
- });
-
public string PackageName => Package.Current.Id.Name;
public string Name => Package.Current.DisplayName;
- public System.Version Version => Utils.ParseVersion(VersionString);
+ public Version Version => Utils.ParseVersion(VersionString);
public string VersionString
{
@@ -50,11 +35,31 @@ public void ShowSettingsUI() =>
public AppTheme RequestedTheme =>
Application.Current.RequestedTheme == ApplicationTheme.Dark ? AppTheme.Dark : AppTheme.Light;
- public AppPackagingModel PackagingModel => _isPackagedAppLazy.Value
+ public AppPackagingModel PackagingModel => AppInfoUtils.IsPackagedApp
? AppPackagingModel.Packaged
: AppPackagingModel.Unpackaged;
public LayoutDirection RequestedLayoutDirection =>
CultureInfo.CurrentCulture.TextInfo.IsRightToLeft ? LayoutDirection.RightToLeft : LayoutDirection.LeftToRight;
}
+
+ static class AppInfoUtils
+ {
+ static readonly Lazy _isPackagedAppLazy = new Lazy(() =>
+ {
+ try
+ {
+ if (Package.Current != null)
+ return true;
+ }
+ catch
+ {
+ // no-op
+ }
+
+ return false;
+ });
+
+ public static bool IsPackagedApp => _isPackagedAppLazy.Value;
+ }
}
\ No newline at end of file
diff --git a/src/Essentials/src/AssemblyInfo/AssemblyInfo.shared.cs b/src/Essentials/src/AssemblyInfo/AssemblyInfo.shared.cs
index 6a926f0034cb..5420acffa342 100644
--- a/src/Essentials/src/AssemblyInfo/AssemblyInfo.shared.cs
+++ b/src/Essentials/src/AssemblyInfo/AssemblyInfo.shared.cs
@@ -12,3 +12,5 @@
[assembly: InternalsVisibleTo("CommunityToolkit.Maui.UnitTests")]
[assembly: InternalsVisibleTo("CommunityToolkit.Maui.Markup")]
[assembly: InternalsVisibleTo("CommunityToolkit.Maui.Markup.UnitTests")]
+[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Core.UnitTests")]
+[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Xaml.UnitTests")]
diff --git a/src/Essentials/src/Barometer/Barometer.android.cs b/src/Essentials/src/Barometer/Barometer.android.cs
index 6096860ed0d5..b8c6125603c8 100644
--- a/src/Essentials/src/Barometer/Barometer.android.cs
+++ b/src/Essentials/src/Barometer/Barometer.android.cs
@@ -1,37 +1,37 @@
+#nullable enable
using System;
+using Android.App;
+using Android.Content;
using Android.Hardware;
-using Android.Runtime;
-using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class BarometerImplementation : IBarometer
+ partial class BarometerImplementation : IBarometer
{
- Sensor DefaultBarometer
- => Platform.SensorManager?.GetDefaultSensor(SensorType.Pressure);
-
- Sensor barometer;
- BarometerListener listener;
+ static SensorManager? _sensorManager;
+ static Sensor? _sensor;
- bool PlatformIsSupported
- => DefaultBarometer != null;
+ static SensorManager? SensorManager =>
+ _sensorManager ??= Application.Context.GetSystemService(Context.SensorService) as SensorManager;
+
+ static Sensor? Sensor =>
+ _sensor ??= SensorManager?.GetDefaultSensor(SensorType.Pressure);
+
+ public bool IsSupported => Sensor is not null;
+
+ BarometerListener? _listener;
void PlatformStart(SensorSpeed sensorSpeed)
{
- listener = new BarometerListener(RaiseReadingChanged);
- barometer = DefaultBarometer;
- Platform.SensorManager.RegisterListener(listener, barometer, sensorSpeed.ToPlatform());
+ _listener = new BarometerListener(RaiseReadingChanged);
+ SensorManager!.RegisterListener(_listener, Sensor, sensorSpeed.ToPlatform());
}
void PlatformStop()
{
- if (listener == null)
- return;
-
- Platform.SensorManager.UnregisterListener(listener, barometer);
- listener.Dispose();
- listener = null;
- barometer = null;
+ SensorManager!.UnregisterListener(_listener, Sensor);
+ _listener!.Dispose();
+ _listener = null;
}
}
@@ -44,16 +44,17 @@ public BarometerListener(Action changeHandler)
public readonly Action ChangeHandler;
- void ISensorEventListener.OnAccuracyChanged(Sensor sensor, [GeneratedEnum] SensorStatus accuracy)
+ void ISensorEventListener.OnAccuracyChanged(Sensor? sensor, SensorStatus accuracy)
{
}
- void ISensorEventListener.OnSensorChanged(SensorEvent e)
+ void ISensorEventListener.OnSensorChanged(SensorEvent? e)
{
- if ((e?.Values?.Count ?? 0) <= 0)
+ var values = e?.Values ?? Array.Empty();
+ if (values.Count < 1)
return;
- ChangeHandler?.Invoke(new BarometerData(e.Values[0]));
+ ChangeHandler?.Invoke(new BarometerData(values[0]));
}
}
}
diff --git a/src/Essentials/src/Barometer/Barometer.ios.watchos.cs b/src/Essentials/src/Barometer/Barometer.ios.watchos.cs
index 475f5bcc40d4..d8f304795531 100644
--- a/src/Essentials/src/Barometer/Barometer.ios.watchos.cs
+++ b/src/Essentials/src/Barometer/Barometer.ios.watchos.cs
@@ -1,22 +1,21 @@
using System;
using CoreMotion;
using Foundation;
-using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Media;
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class BarometerImplementation : IBarometer
+ partial class BarometerImplementation : IBarometer
{
CMAltimeter altitudeManager;
- bool PlatformIsSupported
+ public bool IsSupported
=> CMAltimeter.IsRelativeAltitudeAvailable;
void PlatformStart(SensorSpeed sensorSpeed)
{
altitudeManager = new CMAltimeter();
- altitudeManager.StartRelativeAltitudeUpdates(Platform.GetCurrentQueue(), LocationManagerUpdatedHeading);
+ altitudeManager.StartRelativeAltitudeUpdates(NSOperationQueue.CurrentQueue ?? new NSOperationQueue(), LocationManagerUpdatedHeading);
void LocationManagerUpdatedHeading(CMAltitudeData e, NSError error)
{
diff --git a/src/Essentials/src/Barometer/Barometer.netstandard.tvos.macos.cs b/src/Essentials/src/Barometer/Barometer.netstandard.tvos.macos.cs
index 2393f0a3c3d1..8242e2fc889d 100644
--- a/src/Essentials/src/Barometer/Barometer.netstandard.tvos.macos.cs
+++ b/src/Essentials/src/Barometer/Barometer.netstandard.tvos.macos.cs
@@ -3,7 +3,7 @@
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class BarometerImplementation : IBarometer
+ partial class BarometerImplementation : IBarometer
{
void PlatformStart(SensorSpeed sensorSpeed)
=> throw ExceptionUtils.NotSupportedOrImplementedException;
@@ -11,7 +11,7 @@ void PlatformStart(SensorSpeed sensorSpeed)
void PlatformStop()
=> throw ExceptionUtils.NotSupportedOrImplementedException;
- bool PlatformIsSupported
+ public bool IsSupported
=> throw ExceptionUtils.NotSupportedOrImplementedException;
}
}
diff --git a/src/Essentials/src/Barometer/Barometer.shared.cs b/src/Essentials/src/Barometer/Barometer.shared.cs
index 1eee601c9b07..d2cb900160a2 100644
--- a/src/Essentials/src/Barometer/Barometer.shared.cs
+++ b/src/Essentials/src/Barometer/Barometer.shared.cs
@@ -1,5 +1,5 @@
+#nullable enable
using System;
-using System.ComponentModel;
using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Devices.Sensors
@@ -10,11 +10,9 @@ public interface IBarometer
bool IsMonitoring { get; }
- SensorSpeed SensorSpeed { get; }
-
void Start(SensorSpeed sensorSpeed);
- event EventHandler ReadingChanged;
+ event EventHandler? ReadingChanged;
void Stop();
}
@@ -24,37 +22,31 @@ public static class Barometer
{
public static event EventHandler ReadingChanged
{
- add => Current.ReadingChanged += value;
- remove => Current.ReadingChanged -= value;
+ add => Default.ReadingChanged += value;
+ remove => Default.ReadingChanged -= value;
}
- public static bool IsSupported => Current.IsSupported;
+ public static bool IsSupported => Default.IsSupported;
///
- public static bool IsMonitoring
- => Current.IsMonitoring;
+ public static bool IsMonitoring
+ => Default.IsMonitoring;
///
public static void Start(SensorSpeed sensorSpeed)
- => Current.Start(sensorSpeed);
+ => Default.Start(sensorSpeed);
///
public static void Stop()
- => Current.Stop();
+ => Default.Stop();
-#nullable enable
- static IBarometer? currentImplementation;
-#nullable disable
+ static IBarometer? defaultImplementation;
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static IBarometer Current =>
- currentImplementation ??= new BarometerImplementation();
+ public static IBarometer Default =>
+ defaultImplementation ??= new BarometerImplementation();
- [EditorBrowsable(EditorBrowsableState.Never)]
-#nullable enable
- public static void SetCurrent(IBarometer? implementation) =>
- currentImplementation = implementation;
-#nullable disable
+ internal static void SetDefault(IBarometer? implementation) =>
+ defaultImplementation = implementation;
}
///
@@ -85,7 +77,7 @@ public BarometerData(double pressure) =>
!left.Equals(right);
///
- public override bool Equals(object obj) =>
+ public override bool Equals(object? obj) =>
(obj is BarometerData data) && Equals(data);
///
@@ -99,24 +91,18 @@ public override int GetHashCode() =>
///
public override string ToString() => $"{nameof(PressureInHectopascals)}: {PressureInHectopascals}";
}
-}
-namespace Microsoft.Maui.Devices.Sensors
-{
- public partial class BarometerImplementation : IBarometer
+ partial class BarometerImplementation : IBarometer
{
bool UseSyncContext => SensorSpeed == SensorSpeed.Default || SensorSpeed == SensorSpeed.UI;
#pragma warning disable CS0067
- public event EventHandler ReadingChanged;
+ public event EventHandler? ReadingChanged;
#pragma warning restore CS0067
- public bool IsSupported
- => PlatformIsSupported;
-
public bool IsMonitoring { get; private set; }
- public SensorSpeed SensorSpeed { get; private set; } = SensorSpeed.Default;
+ SensorSpeed SensorSpeed { get; set; } = SensorSpeed.Default;
void RaiseReadingChanged(BarometerData reading)
{
@@ -130,7 +116,7 @@ void RaiseReadingChanged(BarometerData reading)
public void Start(SensorSpeed sensorSpeed)
{
- if (!PlatformIsSupported)
+ if (!IsSupported)
throw new FeatureNotSupportedException();
if (IsMonitoring)
diff --git a/src/Essentials/src/Barometer/Barometer.tizen.cs b/src/Essentials/src/Barometer/Barometer.tizen.cs
index f27cf277da1d..fd4f95478a2e 100644
--- a/src/Essentials/src/Barometer/Barometer.tizen.cs
+++ b/src/Essentials/src/Barometer/Barometer.tizen.cs
@@ -4,9 +4,9 @@
namespace Microsoft.Maui.Devices.Sensors
{
- public class BarometerImplementation : IBarometer
+ class BarometerImplementation : IBarometer
{
- bool PlatformIsSupported
+ public bool IsSupported
=> TizenBarometerSensor.IsSupported;
TizenBarometerSensor DefaultSensor
diff --git a/src/Essentials/src/Barometer/Barometer.uwp.cs b/src/Essentials/src/Barometer/Barometer.uwp.cs
index d4403b65cb2f..862a93a5627f 100644
--- a/src/Essentials/src/Barometer/Barometer.uwp.cs
+++ b/src/Essentials/src/Barometer/Barometer.uwp.cs
@@ -4,13 +4,13 @@
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class BarometerImplementation : IBarometer
+ partial class BarometerImplementation : IBarometer
{
WinBarometer sensor;
WinBarometer DefaultBarometer => WinBarometer.GetDefault();
- bool PlatformIsSupported =>
+ public bool IsSupported =>
DefaultBarometer != null;
void PlatformStart(SensorSpeed sensorSpeed)
diff --git a/src/Essentials/src/Battery/Battery.android.cs b/src/Essentials/src/Battery/Battery.android.cs
index d3d01985a16e..53b781210088 100755
--- a/src/Essentials/src/Battery/Battery.android.cs
+++ b/src/Essentials/src/Battery/Battery.android.cs
@@ -1,26 +1,32 @@
using System;
+using Android.App;
using Android.Content;
using Android.OS;
using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Devices
{
- public partial class BatteryImplementation : IBattery
+ partial class BatteryImplementation : IBattery
{
+ static PowerManager powerManager;
+
+ static PowerManager PowerManager =>
+ powerManager ??= Application.Context.GetSystemService(Context.PowerService) as PowerManager;
+
BatteryBroadcastReceiver batteryReceiver;
EnergySaverBroadcastReceiver powerReceiver;
- public void StartEnergySaverListeners()
+ void StartEnergySaverListeners()
{
- powerReceiver = new EnergySaverBroadcastReceiver(Battery.OnEnergySaverChanged);
- Platform.AppContext.RegisterReceiver(powerReceiver, new IntentFilter(PowerManager.ActionPowerSaveModeChanged));
+ powerReceiver = new EnergySaverBroadcastReceiver(OnEnergySaverChanged);
+ Application.Context.RegisterReceiver(powerReceiver, new IntentFilter(PowerManager.ActionPowerSaveModeChanged));
}
- public void StopEnergySaverListeners()
+ void StopEnergySaverListeners()
{
try
{
- Platform.AppContext.UnregisterReceiver(powerReceiver);
+ Application.Context.UnregisterReceiver(powerReceiver);
}
catch (Java.Lang.IllegalArgumentException)
{
@@ -34,24 +40,24 @@ public EnergySaverStatus EnergySaverStatus
{
get
{
- var status = Platform.PowerManager?.IsPowerSaveMode ?? false;
+ var status = PowerManager?.IsPowerSaveMode ?? false;
return status ? EnergySaverStatus.On : EnergySaverStatus.Off;
}
}
- public void StartBatteryListeners()
+ void StartBatteryListeners()
{
Permissions.EnsureDeclared();
- batteryReceiver = new BatteryBroadcastReceiver(Battery.OnBatteryInfoChanged);
- Platform.AppContext.RegisterReceiver(batteryReceiver, new IntentFilter(Intent.ActionBatteryChanged));
+ batteryReceiver = new BatteryBroadcastReceiver(OnBatteryInfoChanged);
+ Application.Context.RegisterReceiver(batteryReceiver, new IntentFilter(Intent.ActionBatteryChanged));
}
- public void StopBatteryListeners()
+ void StopBatteryListeners()
{
try
{
- Platform.AppContext.UnregisterReceiver(batteryReceiver);
+ Application.Context.UnregisterReceiver(batteryReceiver);
}
catch (Java.Lang.IllegalArgumentException)
{
@@ -68,7 +74,7 @@ public double ChargeLevel
Permissions.EnsureDeclared();
using (var filter = new IntentFilter(Intent.ActionBatteryChanged))
- using (var battery = Platform.AppContext.RegisterReceiver(null, filter))
+ using (var battery = Application.Context.RegisterReceiver(null, filter))
{
var level = battery.GetIntExtra(BatteryManager.ExtraLevel, -1);
var scale = battery.GetIntExtra(BatteryManager.ExtraScale, -1);
@@ -88,7 +94,7 @@ public BatteryState State
Permissions.EnsureDeclared();
using (var filter = new IntentFilter(Intent.ActionBatteryChanged))
- using (var battery = Platform.AppContext.RegisterReceiver(null, filter))
+ using (var battery = Application.Context.RegisterReceiver(null, filter))
{
var status = battery.GetIntExtra(BatteryManager.ExtraStatus, -1);
switch (status)
@@ -115,7 +121,7 @@ public BatteryPowerSource PowerSource
Permissions.EnsureDeclared();
using (var filter = new IntentFilter(Intent.ActionBatteryChanged))
- using (var battery = Platform.AppContext.RegisterReceiver(null, filter))
+ using (var battery = Application.Context.RegisterReceiver(null, filter))
{
var chargePlug = battery.GetIntExtra(BatteryManager.ExtraPlugged, -1);
diff --git a/src/Essentials/src/Battery/Battery.ios.watchos.cs b/src/Essentials/src/Battery/Battery.ios.watchos.cs
index f8f70a47ad81..5bc354f995a2 100755
--- a/src/Essentials/src/Battery/Battery.ios.watchos.cs
+++ b/src/Essentials/src/Battery/Battery.ios.watchos.cs
@@ -10,7 +10,7 @@
namespace Microsoft.Maui.Devices
{
- public partial class BatteryImplementation : IBattery
+ partial class BatteryImplementation : IBattery
{
#if !__WATCHOS__
NSObject levelObserver;
@@ -19,27 +19,27 @@ public partial class BatteryImplementation : IBattery
NSObject saverStatusObserver;
- public void StartEnergySaverListeners()
+ void StartEnergySaverListeners()
{
saverStatusObserver = NSNotificationCenter.DefaultCenter.AddObserver(NSProcessInfo.PowerStateDidChangeNotification, PowerChangedNotification);
}
- public void StopEnergySaverListeners()
+ void StopEnergySaverListeners()
{
saverStatusObserver?.Dispose();
saverStatusObserver = null;
}
void PowerChangedNotification(NSNotification notification)
- => MainThread.BeginInvokeOnMainThread(Battery.OnEnergySaverChanged);
+ => PlatformUtils.BeginInvokeOnMainThread(OnEnergySaverChanged);
public EnergySaverStatus EnergySaverStatus =>
NSProcessInfo.ProcessInfo?.LowPowerModeEnabled == true ? EnergySaverStatus.On : EnergySaverStatus.Off;
- public void StartBatteryListeners()
+ void StartBatteryListeners()
{
#if __WATCHOS__
- throw new FeatureNotSupportedException();
+ throw new FeatureNotSupportedException();
#else
UIDevice.CurrentDevice.BatteryMonitoringEnabled = true;
levelObserver = UIDevice.Notifications.ObserveBatteryLevelDidChange(BatteryInfoChangedNotification);
@@ -47,10 +47,10 @@ public void StartBatteryListeners()
#endif
}
- public void StopBatteryListeners()
+ void StopBatteryListeners()
{
#if __WATCHOS__
- throw new FeatureNotSupportedException();
+ throw new FeatureNotSupportedException();
#else
UIDevice.CurrentDevice.BatteryMonitoringEnabled = false;
levelObserver?.Dispose();
@@ -61,7 +61,7 @@ public void StopBatteryListeners()
}
void BatteryInfoChangedNotification(object sender, NSNotificationEventArgs args)
- => MainThread.BeginInvokeOnMainThread(Battery.OnBatteryInfoChanged);
+ => PlatformUtils.BeginInvokeOnMainThread(OnBatteryInfoChanged);
public double ChargeLevel
{
diff --git a/src/Essentials/src/Battery/Battery.macos.cs b/src/Essentials/src/Battery/Battery.macos.cs
index f0446b4e97be..b1b5a042bdc1 100755
--- a/src/Essentials/src/Battery/Battery.macos.cs
+++ b/src/Essentials/src/Battery/Battery.macos.cs
@@ -3,17 +3,17 @@
namespace Microsoft.Maui.Devices
{
- public partial class BatteryImplementation : IBattery
+ partial class BatteryImplementation : IBattery
{
CFRunLoopSource powerSourceNotification;
- public void StartBatteryListeners()
+ void StartBatteryListeners()
{
powerSourceNotification = IOKit.CreatePowerSourceNotification(PowerSourceNotification);
CFRunLoop.Current.AddSource(powerSourceNotification, CFRunLoop.ModeDefault);
}
- public void StopBatteryListeners()
+ void StopBatteryListeners()
{
if (powerSourceNotification != null)
{
@@ -22,7 +22,7 @@ public void StopBatteryListeners()
}
}
- public void PowerSourceNotification()
+ void PowerSourceNotification()
=> MainThread.BeginInvokeOnMainThread(OnBatteryInfoChanged);
public double ChargeLevel => IOKit.GetInternalBatteryChargeLevel();
@@ -31,11 +31,11 @@ public void PowerSourceNotification()
public BatteryPowerSource PowerSource => IOKit.GetProvidingPowerSource();
- public void StartEnergySaverListeners()
+ void StartEnergySaverListeners()
{
}
- public void StopEnergySaverListeners()
+ void StopEnergySaverListeners()
{
}
diff --git a/src/Essentials/src/Battery/Battery.netstandard.tvos.cs b/src/Essentials/src/Battery/Battery.netstandard.tvos.cs
index bd88fd30cdb7..456fd4af9677 100755
--- a/src/Essentials/src/Battery/Battery.netstandard.tvos.cs
+++ b/src/Essentials/src/Battery/Battery.netstandard.tvos.cs
@@ -3,12 +3,12 @@
namespace Microsoft.Maui.Devices
{
///
- public partial class BatteryImplementation : IBattery
+ partial class BatteryImplementation : IBattery
{
- public void StartBatteryListeners() =>
+ void StartBatteryListeners() =>
throw ExceptionUtils.NotSupportedOrImplementedException;
- public void StopBatteryListeners() =>
+ void StopBatteryListeners() =>
throw ExceptionUtils.NotSupportedOrImplementedException;
public double ChargeLevel =>
@@ -20,10 +20,10 @@ public void StopBatteryListeners() =>
public BatteryPowerSource PowerSource =>
throw ExceptionUtils.NotSupportedOrImplementedException;
- public void StartEnergySaverListeners() =>
+ void StartEnergySaverListeners() =>
throw ExceptionUtils.NotSupportedOrImplementedException;
- public void StopEnergySaverListeners() =>
+ void StopEnergySaverListeners() =>
throw ExceptionUtils.NotSupportedOrImplementedException;
public EnergySaverStatus EnergySaverStatus =>
diff --git a/src/Essentials/src/Battery/Battery.shared.cs b/src/Essentials/src/Battery/Battery.shared.cs
index ab3c5dd3c7d3..d7b05409af76 100755
--- a/src/Essentials/src/Battery/Battery.shared.cs
+++ b/src/Essentials/src/Battery/Battery.shared.cs
@@ -1,5 +1,5 @@
+#nullable enable
using System;
-using System.ComponentModel;
namespace Microsoft.Maui.Devices
{
@@ -13,103 +13,107 @@ public interface IBattery
EnergySaverStatus EnergySaverStatus { get; }
- void StartEnergySaverListeners();
-
- void StopEnergySaverListeners();
-
- void StartBatteryListeners();
+ event EventHandler BatteryInfoChanged;
- void StopBatteryListeners();
+ event EventHandler EnergySaverStatusChanged;
}
///
- public static partial class Battery
+ public static class Battery
{
- static event EventHandler BatteryInfoChangedInternal;
-
- static event EventHandler EnergySaverStatusChangedInternal;
-
- // a cache so that events aren't fired unnecessarily
- // this is mainly an issue on Android, but we can stiil do this everywhere
- static double currentLevel;
- static BatteryPowerSource currentSource;
- static BatteryState currentState;
-
///
- public static double ChargeLevel => Current.ChargeLevel;
+ public static double ChargeLevel => Default.ChargeLevel;
///
- public static BatteryState State => Current.State;
+ public static BatteryState State => Default.State;
///
- public static BatteryPowerSource PowerSource => Current.PowerSource;
+ public static BatteryPowerSource PowerSource => Default.PowerSource;
///
- public static EnergySaverStatus EnergySaverStatus => Current.EnergySaverStatus;
+ public static EnergySaverStatus EnergySaverStatus => Default.EnergySaverStatus;
+ ///
public static event EventHandler BatteryInfoChanged
+ {
+ add => Default.BatteryInfoChanged += value;
+ remove => Default.BatteryInfoChanged -= value;
+ }
+
+ ///
+ public static event EventHandler EnergySaverStatusChanged
+ {
+ add => Default.EnergySaverStatusChanged += value;
+ remove => Default.EnergySaverStatusChanged -= value;
+ }
+
+ static IBattery? defaultImplementation;
+
+ public static IBattery Default =>
+ defaultImplementation ??= new BatteryImplementation();
+
+ internal static void SetDefault(IBattery? implementation) =>
+ defaultImplementation = implementation;
+ }
+
+ partial class BatteryImplementation : IBattery
+ {
+ event EventHandler? BatteryInfoChangedInternal;
+
+ event EventHandler? EnergySaverStatusChangedInternal;
+
+ public event EventHandler BatteryInfoChanged
{
add
{
- var wasRunning = BatteryInfoChangedInternal != null;
-
+ if (BatteryInfoChangedInternal == null)
+ StartBatteryListeners();
BatteryInfoChangedInternal += value;
-
- if (!wasRunning && BatteryInfoChangedInternal != null)
- {
- SetCurrent();
- Current.StartBatteryListeners();
- }
}
-
remove
{
- var wasRunning = BatteryInfoChangedInternal != null;
-
BatteryInfoChangedInternal -= value;
-
- if (wasRunning && BatteryInfoChangedInternal == null)
- Current.StopBatteryListeners();
+ if (BatteryInfoChangedInternal == null)
+ StopBatteryListeners();
}
}
- public static event EventHandler EnergySaverStatusChanged
+ public event EventHandler EnergySaverStatusChanged
{
add
{
- var wasRunning = EnergySaverStatusChangedInternal != null;
-
+ if (EnergySaverStatusChangedInternal == null)
+ StartEnergySaverListeners();
EnergySaverStatusChangedInternal += value;
-
- if (!wasRunning && EnergySaverStatusChangedInternal != null)
- Current.StartEnergySaverListeners();
}
-
remove
{
- var wasRunning = EnergySaverStatusChangedInternal != null;
-
EnergySaverStatusChangedInternal -= value;
-
- if (wasRunning && EnergySaverStatusChangedInternal == null)
- Current.StopEnergySaverListeners();
+ if (EnergySaverStatusChangedInternal == null)
+ StopEnergySaverListeners();
}
}
- static void SetCurrent()
+ // a cache so that events aren't fired unnecessarily
+ // this is mainly an issue on Android, but we can stiil do this everywhere
+ static double currentLevel;
+ static BatteryPowerSource currentSource;
+ static BatteryState currentState;
+
+ void SetCurrent()
{
- currentLevel = Battery.ChargeLevel;
- currentSource = Battery.PowerSource;
- currentState = Battery.State;
+ currentLevel = ChargeLevel;
+ currentSource = PowerSource;
+ currentState = State;
}
- internal static void OnBatteryInfoChanged(double level, BatteryState state, BatteryPowerSource source)
+ void OnBatteryInfoChanged(double level, BatteryState state, BatteryPowerSource source)
=> OnBatteryInfoChanged(new BatteryInfoChangedEventArgs(level, state, source));
- internal static void OnBatteryInfoChanged()
+ void OnBatteryInfoChanged()
=> OnBatteryInfoChanged(ChargeLevel, State, PowerSource);
- internal static void OnBatteryInfoChanged(BatteryInfoChangedEventArgs e)
+ void OnBatteryInfoChanged(BatteryInfoChangedEventArgs e)
{
if (currentLevel != e.ChargeLevel || currentSource != e.PowerSource || currentState != e.State)
{
@@ -118,29 +122,14 @@ internal static void OnBatteryInfoChanged(BatteryInfoChangedEventArgs e)
}
}
- internal static void OnEnergySaverChanged()
+ void OnEnergySaverChanged()
=> OnEnergySaverChanged(EnergySaverStatus);
- internal static void OnEnergySaverChanged(EnergySaverStatus saverStatus)
+ void OnEnergySaverChanged(EnergySaverStatus saverStatus)
=> OnEnergySaverChanged(new EnergySaverStatusChangedEventArgs(saverStatus));
- internal static void OnEnergySaverChanged(EnergySaverStatusChangedEventArgs e)
+ void OnEnergySaverChanged(EnergySaverStatusChangedEventArgs e)
=> EnergySaverStatusChangedInternal?.Invoke(null, e);
-
-
-#nullable enable
- static IBattery? currentImplementation;
-#nullable disable
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static IBattery Current =>
- currentImplementation ??= new BatteryImplementation();
-
- [EditorBrowsable(EditorBrowsableState.Never)]
-#nullable enable
- public static void SetCurrent(IBattery? implementation) =>
- currentImplementation = implementation;
-#nullable disable
}
///
diff --git a/src/Essentials/src/Battery/Battery.tizen.cs b/src/Essentials/src/Battery/Battery.tizen.cs
index db11cca14107..8631755f5423 100755
--- a/src/Essentials/src/Battery/Battery.tizen.cs
+++ b/src/Essentials/src/Battery/Battery.tizen.cs
@@ -3,26 +3,26 @@
namespace Microsoft.Maui.Devices
{
- public partial class BatteryImplementation : IBattery
+ partial class BatteryImplementation : IBattery
{
void OnChanged(object sender, object e)
=> MainThread.BeginInvokeOnMainThread(OnBatteryInfoChanged);
- public void StartBatteryListeners()
+ void StartBatteryListeners()
{
TizenBattery.PercentChanged += OnChanged;
TizenBattery.ChargingStateChanged += OnChanged;
TizenBattery.LevelChanged += OnChanged;
}
- public void StopBatteryListeners()
+ void StopBatteryListeners()
{
TizenBattery.PercentChanged -= OnChanged;
TizenBattery.ChargingStateChanged -= OnChanged;
TizenBattery.LevelChanged -= OnChanged;
}
- public double PlatformChargeLevel
+ public double ChargeLevel
{
get
{
@@ -50,10 +50,10 @@ public BatteryPowerSource PowerSource
}
}
- public void StartEnergySaverListeners()
+ void StartEnergySaverListeners()
=> throw new FeatureNotSupportedException("This API is not currently supported on Tizen.");
- public void StopEnergySaverListeners()
+ void StopEnergySaverListeners()
=> throw new FeatureNotSupportedException("This API is not currently supported on Tizen.");
public EnergySaverStatus EnergySaverStatus
diff --git a/src/Essentials/src/Battery/Battery.uwp.cs b/src/Essentials/src/Battery/Battery.uwp.cs
index e505b90692e1..fddfeb293da2 100755
--- a/src/Essentials/src/Battery/Battery.uwp.cs
+++ b/src/Essentials/src/Battery/Battery.uwp.cs
@@ -3,16 +3,16 @@
namespace Microsoft.Maui.Devices
{
- public partial class BatteryImplementation : IBattery
+ partial class BatteryImplementation : IBattery
{
- public void StartEnergySaverListeners() =>
+ void StartEnergySaverListeners() =>
PowerManager.EnergySaverStatusChanged += ReportEnergySaverUpdated;
- public void StopEnergySaverListeners() =>
+ void StopEnergySaverListeners() =>
PowerManager.EnergySaverStatusChanged -= ReportEnergySaverUpdated;
void ReportEnergySaverUpdated(object sender, object e)
- => MainThread.BeginInvokeOnMainThread(Battery.OnEnergySaverChanged);
+ => MainThread.BeginInvokeOnMainThread(OnEnergySaverChanged);
public void StartBatteryListeners() =>
DefaultBattery.ReportUpdated += ReportUpdated;
@@ -20,8 +20,8 @@ public void StartBatteryListeners() =>
public void StopBatteryListeners() =>
DefaultBattery.ReportUpdated -= ReportUpdated;
- void ReportUpdated(object sender, object e)
- => MainThread.BeginInvokeOnMainThread(Battery.OnBatteryInfoChanged);
+ void ReportUpdated(object sender, object e)
+ => MainThread.BeginInvokeOnMainThread(OnBatteryInfoChanged);
global::Windows.Devices.Power.Battery DefaultBattery =>
global::Windows.Devices.Power.Battery.AggregateBattery;
diff --git a/src/Essentials/src/Browser/Browser.android.cs b/src/Essentials/src/Browser/Browser.android.cs
index 98aa70b24718..50998d41d5dd 100755
--- a/src/Essentials/src/Browser/Browser.android.cs
+++ b/src/Essentials/src/Browser/Browser.android.cs
@@ -1,12 +1,14 @@
+#nullable enable
using System;
using System.Threading.Tasks;
+using Android.App;
using Android.Content;
using AndroidX.Browser.CustomTabs;
using AndroidUri = Android.Net.Uri;
namespace Microsoft.Maui.ApplicationModel
{
- public partial class BrowserImplementation : IBrowser
+ partial class BrowserImplementation : IBrowser
{
public Task OpenAsync(Uri uri, BrowserLaunchOptions options)
{
@@ -15,123 +17,78 @@ public Task OpenAsync(Uri uri, BrowserLaunchOptions options)
switch (options.LaunchMode)
{
case BrowserLaunchMode.SystemPreferred:
- var tabsBuilder = new CustomTabsIntent.Builder();
- tabsBuilder.SetShowTitle(true);
- if (options.PreferredToolbarColor != null)
+ LaunchChromeTabs(options, nativeUri);
+ break;
+ case BrowserLaunchMode.External:
+ LaunchExternalBrowser(options, nativeUri);
+ break;
+ }
+
+ return Task.FromResult(true);
+ }
+
+ static void LaunchChromeTabs(BrowserLaunchOptions options, AndroidUri? nativeUri)
+ {
+ var tabsBuilder = new CustomTabsIntent.Builder();
+ tabsBuilder.SetShowTitle(true);
#pragma warning disable CS0618 // Type or member is obsolete
- tabsBuilder.SetToolbarColor(options.PreferredToolbarColor.ToInt());
+ if (options.PreferredToolbarColor != null)
+ tabsBuilder.SetToolbarColor(options.PreferredToolbarColor.ToInt());
#pragma warning restore CS0618 // Type or member is obsolete
- if (options.TitleMode != BrowserTitleMode.Default)
- tabsBuilder.SetShowTitle(options.TitleMode == BrowserTitleMode.Show);
+ if (options.TitleMode != BrowserTitleMode.Default)
+ tabsBuilder.SetShowTitle(options.TitleMode == BrowserTitleMode.Show);
- var tabsIntent = tabsBuilder.Build();
- ActivityFlags? tabsFlags = null;
+ var tabsIntent = tabsBuilder.Build();
+ ActivityFlags? tabsFlags = null;
- Context context = Platform.GetCurrentActivity(false);
+ Context? context = ActivityStateManager.Default.GetCurrentActivity(false);
- if (context == null)
- {
- context = Platform.AppContext;
+ if (context == null)
+ {
+ context = Application.Context;
- // If using ApplicationContext we need to set ClearTop/NewTask (See #225)
- tabsFlags = ActivityFlags.ClearTop | ActivityFlags.NewTask;
- }
+ // If using ApplicationContext we need to set ClearTop/NewTask (See #225)
+ tabsFlags = ActivityFlags.ClearTop | ActivityFlags.NewTask;
+ }
#if __ANDROID_24__
- if (Platform.HasApiLevelN && options.HasFlag(BrowserLaunchFlags.LaunchAdjacent))
- {
- if (tabsFlags.HasValue)
- tabsFlags |= ActivityFlags.LaunchAdjacent | ActivityFlags.NewTask;
- else
- tabsFlags = ActivityFlags.LaunchAdjacent | ActivityFlags.NewTask;
- }
-#endif
-
- // Check if there's flags specified to use
+ if (OperatingSystem.IsAndroidVersionAtLeast(24))
+ {
+ if (options.HasFlag(BrowserLaunchFlags.LaunchAdjacent))
+ {
if (tabsFlags.HasValue)
- tabsIntent.Intent.SetFlags(tabsFlags.Value);
-
- tabsIntent.LaunchUrl(context, nativeUri);
-
- break;
- case BrowserLaunchMode.External:
- var intent = new Intent(Intent.ActionView, nativeUri);
- var flags = ActivityFlags.ClearTop | ActivityFlags.NewTask;
-#if __ANDROID_24__
- if (Platform.HasApiLevelN && options.HasFlag(BrowserLaunchFlags.LaunchAdjacent))
- flags |= ActivityFlags.LaunchAdjacent;
+ tabsFlags |= ActivityFlags.LaunchAdjacent | ActivityFlags.NewTask;
+ else
+ tabsFlags = ActivityFlags.LaunchAdjacent | ActivityFlags.NewTask;
+ }
+ }
#endif
- intent.SetFlags(flags);
-
- if (!Platform.IsIntentSupported(intent))
- throw new FeatureNotSupportedException();
- Platform.AppContext.StartActivity(intent);
- break;
- }
+ // Check if there's flags specified to use
+ if (tabsFlags.HasValue)
+ tabsIntent.Intent.SetFlags(tabsFlags.Value);
- return Task.FromResult(true);
+ tabsIntent.LaunchUrl(context, nativeUri);
}
- public Task OpenAsync(string uri)
+ static void LaunchExternalBrowser(BrowserLaunchOptions options, AndroidUri? nativeUri)
{
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
+ var intent = new Intent(Intent.ActionView, nativeUri);
+ var flags = ActivityFlags.ClearTop | ActivityFlags.NewTask;
- public Task OpenAsync(string uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(string uri, BrowserLaunchOptions options)
- {
- return OpenAsync(new Uri(uri), options);
- }
+#if __ANDROID_24__
+ if (OperatingSystem.IsAndroidVersionAtLeast(24))
+ {
+ if (options.HasFlag(BrowserLaunchFlags.LaunchAdjacent))
+ flags |= ActivityFlags.LaunchAdjacent;
+ }
+#endif
+ intent.SetFlags(flags);
- public Task OpenAsync(Uri uri)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
+ if (!PlatformUtils.IsIntentSupported(intent))
+ throw new FeatureNotSupportedException();
- public Task OpenAsync(Uri uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
+ Application.Context.StartActivity(intent);
}
}
}
diff --git a/src/Essentials/src/Browser/Browser.ios.cs b/src/Essentials/src/Browser/Browser.ios.cs
index 4151817c4ee5..836c54bf8d9d 100755
--- a/src/Essentials/src/Browser/Browser.ios.cs
+++ b/src/Essentials/src/Browser/Browser.ios.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using System.Threading.Tasks;
using Foundation;
@@ -8,99 +9,43 @@
namespace Microsoft.Maui.ApplicationModel
{
- public partial class BrowserImplementation : IBrowser
+ partial class BrowserImplementation : IBrowser
{
public async Task OpenAsync(Uri uri, BrowserLaunchOptions options)
{
switch (options.LaunchMode)
{
case BrowserLaunchMode.SystemPreferred:
- var nativeUrl = new NSUrl(uri.AbsoluteUri);
- var sfViewController = new SFSafariViewController(nativeUrl, false);
- var vc = Platform.GetCurrentViewController();
-
- if (options.PreferredToolbarColor != null)
- sfViewController.PreferredBarTintColor = options.PreferredToolbarColor.AsUIColor();
-
- if (options.PreferredControlColor != null)
- sfViewController.PreferredControlTintColor = options.PreferredControlColor.AsUIColor();
-
- if (sfViewController.PopoverPresentationController != null)
- sfViewController.PopoverPresentationController.SourceView = vc.View;
-
- if (options.HasFlag(BrowserLaunchFlags.PresentAsFormSheet))
- sfViewController.ModalPresentationStyle = UIModalPresentationStyle.FormSheet;
- else if (options.HasFlag(BrowserLaunchFlags.PresentAsPageSheet))
- sfViewController.ModalPresentationStyle = UIModalPresentationStyle.PageSheet;
-
- await vc.PresentViewControllerAsync(sfViewController, true);
+ await LaunchSafariViewController(uri, options);
break;
case BrowserLaunchMode.External:
- return await Launcher.OpenAsync(uri);
+ return await Launcher.Default.OpenAsync(uri);
}
return true;
}
- public Task OpenAsync(string uri)
+ private static async Task LaunchSafariViewController(Uri uri, BrowserLaunchOptions options)
{
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
+ var nativeUrl = new NSUrl(uri.AbsoluteUri);
+ var sfViewController = new SFSafariViewController(nativeUrl, false);
+ var vc = WindowStateManager.Default.GetCurrentUIViewController(true)!;
- public Task OpenAsync(string uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(string uri, BrowserLaunchOptions options)
- {
- return OpenAsync(new Uri(uri), options);
- }
+ if (options.PreferredToolbarColor != null)
+ sfViewController.PreferredBarTintColor = options.PreferredToolbarColor.AsUIColor();
- public Task OpenAsync(Uri uri)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
+ if (options.PreferredControlColor != null)
+ sfViewController.PreferredControlTintColor = options.PreferredControlColor.AsUIColor();
- public Task OpenAsync(Uri uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
+ if (sfViewController.PopoverPresentationController != null)
+ sfViewController.PopoverPresentationController.SourceView = vc.View!;
+
+ if (options.HasFlag(BrowserLaunchFlags.PresentAsFormSheet))
+ sfViewController.ModalPresentationStyle = UIModalPresentationStyle.FormSheet;
+ else if (options.HasFlag(BrowserLaunchFlags.PresentAsPageSheet))
+ sfViewController.ModalPresentationStyle = UIModalPresentationStyle.PageSheet;
+
+ await vc.PresentViewControllerAsync(sfViewController, true);
}
}
}
diff --git a/src/Essentials/src/Browser/Browser.macos.cs b/src/Essentials/src/Browser/Browser.macos.cs
index b67a85da8bd1..18121cc912b3 100755
--- a/src/Essentials/src/Browser/Browser.macos.cs
+++ b/src/Essentials/src/Browser/Browser.macos.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using System.Threading.Tasks;
using AppKit;
@@ -5,70 +6,9 @@
namespace Microsoft.Maui.ApplicationModel
{
- public partial class BrowserImplementation : IBrowser
+ partial class BrowserImplementation : IBrowser
{
static Task OpenAsync(Uri uri, BrowserLaunchOptions options) =>
Task.FromResult(NSWorkspace.SharedWorkspace.OpenUrl(new NSUrl(uri.AbsoluteUri)));
-
- public Task OpenAsync(string uri)
- {
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(string uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(string uri, BrowserLaunchOptions options)
- {
- return OpenAsync(new Uri(uri), options);
- }
-
- public Task OpenAsync(Uri uri)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(Uri uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
}
}
diff --git a/src/Essentials/src/Browser/Browser.netstandard.tvos.watchos.cs b/src/Essentials/src/Browser/Browser.netstandard.tvos.watchos.cs
index 446f600d1fb2..1480311e3cde 100755
--- a/src/Essentials/src/Browser/Browser.netstandard.tvos.watchos.cs
+++ b/src/Essentials/src/Browser/Browser.netstandard.tvos.watchos.cs
@@ -1,73 +1,13 @@
+#nullable enable
using System;
using System.Threading.Tasks;
namespace Microsoft.Maui.ApplicationModel
{
///
- public partial class BrowserImplementation : IBrowser
+ partial class BrowserImplementation : IBrowser
{
public Task OpenAsync(Uri uri, BrowserLaunchOptions options) =>
throw ExceptionUtils.NotSupportedOrImplementedException;
-
- public Task OpenAsync(string uri)
- {
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(string uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(string uri, BrowserLaunchOptions options)
- {
- return OpenAsync(new Uri(uri), options);
- }
-
- public Task OpenAsync(Uri uri)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(Uri uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
}
}
diff --git a/src/Essentials/src/Browser/Browser.shared.cs b/src/Essentials/src/Browser/Browser.shared.cs
index bf0c7d08fb9e..067337f44fd4 100755
--- a/src/Essentials/src/Browser/Browser.shared.cs
+++ b/src/Essentials/src/Browser/Browser.shared.cs
@@ -1,86 +1,59 @@
+#nullable enable
using System;
using System.Threading.Tasks;
-using System.ComponentModel;
-
namespace Microsoft.Maui.ApplicationModel
{
public interface IBrowser
{
- Task OpenAsync(string uri);
-
- Task OpenAsync(string uri, BrowserLaunchMode launchMode);
-
- Task OpenAsync(string uri, BrowserLaunchOptions options);
-
- Task OpenAsync(Uri uri);
-
- Task OpenAsync(Uri uri, BrowserLaunchMode launchMode);
-
Task OpenAsync(Uri uri, BrowserLaunchOptions options);
}
///
- public static partial class Browser
+ public static class Browser
{
///
- public static Task OpenAsync(string uri) =>
- Current.OpenAsync(uri, BrowserLaunchMode.SystemPreferred);
+ public static Task OpenAsync(string uri) => Default.OpenAsync(uri);
///
- public static Task OpenAsync(string uri, BrowserLaunchMode launchMode) =>
- Current.OpenAsync(uri, new BrowserLaunchOptions()
- {
- LaunchMode = launchMode
- });
+ public static Task OpenAsync(string uri, BrowserLaunchMode launchMode) => Default.OpenAsync(uri, launchMode);
///
- public static Task OpenAsync(string uri, BrowserLaunchOptions options)
- {
- if (string.IsNullOrWhiteSpace(uri))
- {
- throw new ArgumentNullException(nameof(uri), $"Uri cannot be empty.");
- }
-
- return Current.OpenAsync(new Uri(uri), options);
- }
+ public static Task OpenAsync(string uri, BrowserLaunchOptions options) => Default.OpenAsync(uri, options);
///
- public static Task OpenAsync(Uri uri) =>
- Current.OpenAsync(uri, BrowserLaunchMode.SystemPreferred);
+ public static Task OpenAsync(Uri uri) => Default.OpenAsync(uri);
///
- public static Task OpenAsync(Uri uri, BrowserLaunchMode launchMode) =>
- Current.OpenAsync(uri, new BrowserLaunchOptions()
- {
- LaunchMode = launchMode
- });
+ public static Task OpenAsync(Uri uri, BrowserLaunchMode launchMode) => Default.OpenAsync(uri, launchMode);
///
- public static Task OpenAsync(Uri uri, BrowserLaunchOptions options) =>
- Current.OpenAsync(EscapeUri(uri), options);
+ public static Task OpenAsync(Uri uri, BrowserLaunchOptions options) => Default.OpenAsync(uri, options);
- internal static Uri EscapeUri(Uri uri)
- {
- if (uri == null)
- throw new ArgumentNullException(nameof(uri));
+ static IBrowser? defaultImplementation;
- var idn = new global::System.Globalization.IdnMapping();
- return new Uri(uri.Scheme + "://" + idn.GetAscii(uri.Authority) + uri.PathAndQuery + uri.Fragment);
- }
+ public static IBrowser Default =>
+ defaultImplementation ??= new BrowserImplementation();
-#nullable enable
- static IBrowser? currentImplementation;
-#nullable disable
+ internal static void SetDefault(IBrowser? implementation) =>
+ defaultImplementation = implementation;
+ }
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static IBrowser Current =>
- currentImplementation ??= new BrowserImplementation();
+ public static class BrowserExtensions
+ {
+ public static Task OpenAsync(this IBrowser browser, string uri) =>
+ browser.OpenAsync(new Uri(uri), new BrowserLaunchOptions());
- [EditorBrowsable(EditorBrowsableState.Never)]
-#nullable enable
- public static void SetCurrent(IBrowser? implementation) =>
- currentImplementation = implementation;
-#nullable disable
+ public static Task OpenAsync(this IBrowser browser, string uri, BrowserLaunchMode launchMode) =>
+ browser.OpenAsync(new Uri(uri), new BrowserLaunchOptions { LaunchMode = launchMode });
+
+ public static Task OpenAsync(this IBrowser browser, string uri, BrowserLaunchOptions options) =>
+ browser.OpenAsync(new Uri(uri), options);
+
+ public static Task OpenAsync(this IBrowser browser, Uri uri) =>
+ browser.OpenAsync(uri, new BrowserLaunchOptions());
+
+ public static Task OpenAsync(this IBrowser browser, Uri uri, BrowserLaunchMode launchMode) =>
+ browser.OpenAsync(uri, new BrowserLaunchOptions { LaunchMode = launchMode });
}
}
diff --git a/src/Essentials/src/Browser/Browser.tizen.cs b/src/Essentials/src/Browser/Browser.tizen.cs
index bb400fcc96f8..ae06dc054beb 100755
--- a/src/Essentials/src/Browser/Browser.tizen.cs
+++ b/src/Essentials/src/Browser/Browser.tizen.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using System.Linq;
using System.Threading.Tasks;
@@ -5,7 +6,7 @@
namespace Microsoft.Maui.ApplicationModel
{
- public partial class BrowserImplementation : IBrowser
+ partial class BrowserImplementation : IBrowser
{
public Task PlatformOpenAsync(Uri uri, BrowserLaunchOptions launchMode)
{
@@ -27,66 +28,5 @@ public Task PlatformOpenAsync(Uri uri, BrowserLaunchOptions launchMode)
return Task.FromResult(hasMatches);
}
-
- public Task OpenAsync(string uri)
- {
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(string uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(string uri, BrowserLaunchOptions options)
- {
- return OpenAsync(new Uri(uri), options);
- }
-
- public Task OpenAsync(Uri uri)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(Uri uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
}
}
diff --git a/src/Essentials/src/Browser/Browser.uwp.cs b/src/Essentials/src/Browser/Browser.uwp.cs
index 904ff3c0b597..01f9b4ae0ee8 100755
--- a/src/Essentials/src/Browser/Browser.uwp.cs
+++ b/src/Essentials/src/Browser/Browser.uwp.cs
@@ -1,72 +1,12 @@
+#nullable enable
using System;
using System.Threading.Tasks;
namespace Microsoft.Maui.ApplicationModel
{
- public partial class BrowserImplementation : IBrowser
+ partial class BrowserImplementation : IBrowser
{
public Task OpenAsync(Uri uri, BrowserLaunchOptions options) =>
global::Windows.System.Launcher.LaunchUriAsync(uri).AsTask();
-
- public Task OpenAsync(string uri)
- {
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(string uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- new Uri(uri),
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(string uri, BrowserLaunchOptions options)
- {
- return OpenAsync(new Uri(uri), options);
- }
-
- public Task OpenAsync(Uri uri)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = BrowserLaunchMode.SystemPreferred,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
-
- public Task OpenAsync(Uri uri, BrowserLaunchMode launchMode)
- {
- return OpenAsync
- (
- uri,
- new BrowserLaunchOptions
- {
- Flags = BrowserLaunchFlags.None,
- LaunchMode = launchMode,
- TitleMode = BrowserTitleMode.Default
- }
- );
- }
}
}
diff --git a/src/Essentials/src/Browser/BrowserLaunchMode.shared.cs b/src/Essentials/src/Browser/BrowserLaunchMode.shared.cs
index 28dfe788bc49..e044819dba37 100755
--- a/src/Essentials/src/Browser/BrowserLaunchMode.shared.cs
+++ b/src/Essentials/src/Browser/BrowserLaunchMode.shared.cs
@@ -1,3 +1,4 @@
+#nullable enable
namespace Microsoft.Maui.ApplicationModel
{
///
diff --git a/src/Essentials/src/Browser/BrowserLaunchOptions.shared.cs b/src/Essentials/src/Browser/BrowserLaunchOptions.shared.cs
index 6c72348e84b3..c59046d5d3f6 100755
--- a/src/Essentials/src/Browser/BrowserLaunchOptions.shared.cs
+++ b/src/Essentials/src/Browser/BrowserLaunchOptions.shared.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using Microsoft.Maui.Graphics;
@@ -7,10 +8,10 @@ namespace Microsoft.Maui.ApplicationModel
public class BrowserLaunchOptions
{
///
- public Color PreferredToolbarColor { get; set; }
+ public Color? PreferredToolbarColor { get; set; }
///
- public Color PreferredControlColor { get; set; }
+ public Color? PreferredControlColor { get; set; }
///
public BrowserLaunchMode LaunchMode { get; set; } = BrowserLaunchMode.SystemPreferred;
@@ -21,8 +22,7 @@ public class BrowserLaunchOptions
///
public BrowserLaunchFlags Flags { get; set; } = BrowserLaunchFlags.None;
- internal bool HasFlag(BrowserLaunchFlags flag)
- => Flags.HasFlag(flag);
+ internal bool HasFlag(BrowserLaunchFlags flag) => Flags.HasFlag(flag);
}
///
diff --git a/src/Essentials/src/Browser/BrowserTitleMode.shared.cs b/src/Essentials/src/Browser/BrowserTitleMode.shared.cs
index 51512bd51268..3729bf8a363a 100755
--- a/src/Essentials/src/Browser/BrowserTitleMode.shared.cs
+++ b/src/Essentials/src/Browser/BrowserTitleMode.shared.cs
@@ -1,3 +1,4 @@
+#nullable enable
namespace Microsoft.Maui.ApplicationModel
{
///
diff --git a/src/Essentials/src/Clipboard/Clipboard.android.cs b/src/Essentials/src/Clipboard/Clipboard.android.cs
index e5a5d78faa84..79b3973447b5 100644
--- a/src/Essentials/src/Clipboard/Clipboard.android.cs
+++ b/src/Essentials/src/Clipboard/Clipboard.android.cs
@@ -1,37 +1,56 @@
-using System;
+#nullable enable
using System.Threading.Tasks;
+using Android.App;
using Android.Content;
using static Android.Content.ClipboardManager;
namespace Microsoft.Maui.ApplicationModel.DataTransfer
{
- public partial class ClipboardImplementation : IClipboard
+ partial class ClipboardImplementation : IClipboard
{
- static readonly Lazy clipboardListener
- = new Lazy(() => new ClipboardChangeListener());
+ static ClipboardManager? clipboardManager;
- public Task SetTextAsync(string text)
+ static ClipboardManager? ClipboardManager =>
+ clipboardManager ??= Application.Context.GetSystemService(Context.ClipboardService) as ClipboardManager;
+
+ ClipboardChangeListener? clipboardListener;
+
+ ClipboardChangeListener ClipboardListener =>
+ clipboardListener ??= new ClipboardChangeListener(this);
+
+ public Task SetTextAsync(string? text)
{
- Platform.ClipboardManager.PrimaryClip = ClipData.NewPlainText("Text", text);
+ if (ClipboardManager is not null)
+ ClipboardManager.PrimaryClip = ClipData.NewPlainText("Text", text ?? string.Empty);
+
return Task.CompletedTask;
}
- public bool HasText
- => Platform.ClipboardManager.HasPrimaryClip && !string.IsNullOrEmpty(Platform.ClipboardManager.PrimaryClip?.GetItemAt(0)?.Text);
+ public bool HasText =>
+ ClipboardManager is not null &&
+ ClipboardManager.HasPrimaryClip &&
+ !string.IsNullOrEmpty(ClipboardManager.PrimaryClip?.GetItemAt(0)?.Text);
- public Task GetTextAsync()
- => Task.FromResult(Platform.ClipboardManager.PrimaryClip?.GetItemAt(0)?.Text);
+ public Task GetTextAsync() =>
+ Task.FromResult(ClipboardManager?.PrimaryClip?.GetItemAt(0)?.Text);
- public void StartClipboardListeners()
- => Platform.ClipboardManager.AddPrimaryClipChangedListener(clipboardListener.Value);
+ void StartClipboardListeners()
+ => ClipboardManager?.AddPrimaryClipChangedListener(ClipboardListener);
- public void StopClipboardListeners()
- => Platform.ClipboardManager.RemovePrimaryClipChangedListener(clipboardListener.Value);
+ void StopClipboardListeners()
+ => ClipboardManager?.RemovePrimaryClipChangedListener(ClipboardListener);
}
class ClipboardChangeListener : Java.Lang.Object, IOnPrimaryClipChangedListener
{
+ ClipboardImplementation clipboard;
+
+ public ClipboardChangeListener(ClipboardImplementation clipboard)
+ {
+ this.clipboard = clipboard;
+ }
+
void IOnPrimaryClipChangedListener.OnPrimaryClipChanged() =>
- Clipboard.ClipboardChangedInternal();
+ clipboard.OnClipboardContentChanged();
}
}
diff --git a/src/Essentials/src/Clipboard/Clipboard.ios.cs b/src/Essentials/src/Clipboard/Clipboard.ios.cs
index 6da11555afed..cd0c6858b212 100644
--- a/src/Essentials/src/Clipboard/Clipboard.ios.cs
+++ b/src/Essentials/src/Clipboard/Clipboard.ios.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using System.Threading.Tasks;
using Foundation;
@@ -6,33 +7,36 @@
namespace Microsoft.Maui.ApplicationModel.DataTransfer
{
- public partial class ClipboardImplementation : IClipboard
+ partial class ClipboardImplementation : IClipboard
{
- public Task SetTextAsync(string text)
+ NSObject? observer;
+
+ public Task SetTextAsync(string? text)
{
UIPasteboard.General.String = text;
return Task.CompletedTask;
}
- NSObject observer;
-
public bool HasText
=> UIPasteboard.General.HasStrings;
- public Task GetTextAsync()
+ public Task GetTextAsync()
=> Task.FromResult(UIPasteboard.General.String);
- public void StartClipboardListeners()
+ void StartClipboardListeners()
{
observer = NSNotificationCenter.DefaultCenter.AddObserver(
UIPasteboard.ChangedNotification,
ClipboardChangedObserver);
}
- public void StopClipboardListeners()
- => NSNotificationCenter.DefaultCenter.RemoveObserver(observer);
+ void StopClipboardListeners()
+ {
+ if (observer is not null)
+ NSNotificationCenter.DefaultCenter.RemoveObserver(observer);
+ }
public void ClipboardChangedObserver(NSNotification notification)
- => Clipboard.ClipboardChangedInternal();
+ => OnClipboardContentChanged();
}
}
diff --git a/src/Essentials/src/Clipboard/Clipboard.macos.cs b/src/Essentials/src/Clipboard/Clipboard.macos.cs
index cd2936990d41..d1e3ed0b66b7 100644
--- a/src/Essentials/src/Clipboard/Clipboard.macos.cs
+++ b/src/Essentials/src/Clipboard/Clipboard.macos.cs
@@ -5,7 +5,7 @@
namespace Microsoft.Maui.ApplicationModel.DataTransfer
{
- public partial class ClipboardImplementation : IClipboard
+ partial class ClipboardImplementation : IClipboard
{
readonly string pasteboardType = NSPasteboard.NSPasteboardTypeString;
readonly string[] pasteboardTypes = { pasteboardType };
@@ -32,10 +32,10 @@ string GetPasteboardText()
new ObjCRuntime.Class[] { new ObjCRuntime.Class(typeof(NSString)) },
null)?[0]?.ToString();
- internal void StartClipboardListeners()
+ void StartClipboardListeners()
=> throw ExceptionUtils.NotSupportedOrImplementedException;
- internal void StopClipboardListeners()
+ void StopClipboardListeners()
=> throw ExceptionUtils.NotSupportedOrImplementedException;
}
}
diff --git a/src/Essentials/src/Clipboard/Clipboard.netstandard.tvos.watchos.tizen.cs b/src/Essentials/src/Clipboard/Clipboard.netstandard.tvos.watchos.tizen.cs
index 5c1ec0e1cd7d..f4a678bd5dd9 100644
--- a/src/Essentials/src/Clipboard/Clipboard.netstandard.tvos.watchos.tizen.cs
+++ b/src/Essentials/src/Clipboard/Clipboard.netstandard.tvos.watchos.tizen.cs
@@ -1,23 +1,24 @@
+#nullable enable
using System.Threading.Tasks;
namespace Microsoft.Maui.ApplicationModel.DataTransfer
{
///
- public partial class ClipboardImplementation : IClipboard
+ partial class ClipboardImplementation : IClipboard
{
- public Task SetTextAsync(string text)
+ public Task SetTextAsync(string? text)
=> throw ExceptionUtils.NotSupportedOrImplementedException;
public bool HasText
=> throw ExceptionUtils.NotSupportedOrImplementedException;
- public Task GetTextAsync()
+ public Task GetTextAsync()
=> throw ExceptionUtils.NotSupportedOrImplementedException;
- public void StartClipboardListeners()
+ void StartClipboardListeners()
=> throw ExceptionUtils.NotSupportedOrImplementedException;
- public void StopClipboardListeners()
+ void StopClipboardListeners()
=> throw ExceptionUtils.NotSupportedOrImplementedException;
}
}
diff --git a/src/Essentials/src/Clipboard/Clipboard.shared.cs b/src/Essentials/src/Clipboard/Clipboard.shared.cs
index 58facfbb2f51..492271fbb47e 100644
--- a/src/Essentials/src/Clipboard/Clipboard.shared.cs
+++ b/src/Essentials/src/Clipboard/Clipboard.shared.cs
@@ -1,6 +1,6 @@
+#nullable enable
using System;
using System.Threading.Tasks;
-using System.ComponentModel;
namespace Microsoft.Maui.ApplicationModel.DataTransfer
{
@@ -8,71 +8,65 @@ public interface IClipboard
{
bool HasText { get; }
- Task SetTextAsync(string text);
-
- Task GetTextAsync();
+ Task SetTextAsync(string? text);
- void StartClipboardListeners();
+ Task GetTextAsync();
- void StopClipboardListeners();
+ event EventHandler ClipboardContentChanged;
}
///
- public static partial class Clipboard
+ public static class Clipboard
{
///
- public static Task SetTextAsync(string text)
- => Current.SetTextAsync(text ?? string.Empty);
+ public static Task SetTextAsync(string? text)
+ => Default.SetTextAsync(text ?? string.Empty);
///
public static bool HasText
- => Current.HasText;
+ => Default.HasText;
///
- public static Task GetTextAsync()
- => Current.GetTextAsync();
+ public static Task GetTextAsync()
+ => Default.GetTextAsync();
+ ///
public static event EventHandler ClipboardContentChanged
+ {
+ add => Default.ClipboardContentChanged += value;
+ remove => Default.ClipboardContentChanged -= value;
+ }
+
+ static IClipboard? defaultImplementation;
+
+ public static IClipboard Default =>
+ defaultImplementation ??= new ClipboardImplementation();
+
+ internal static void SetDefault(IClipboard? implementation) =>
+ defaultImplementation = implementation;
+ }
+
+ partial class ClipboardImplementation : IClipboard
+ {
+ event EventHandler? ClipboardContentChangedInternal;
+
+ public event EventHandler ClipboardContentChanged
{
add
{
- var wasRunning = ClipboardContentChangedInternal != null;
-
+ if (ClipboardContentChangedInternal == null)
+ StartClipboardListeners();
ClipboardContentChangedInternal += value;
-
- if (!wasRunning && ClipboardContentChangedInternal != null)
- {
- Current.StartClipboardListeners();
- }
}
-
remove
{
- var wasRunning = ClipboardContentChangedInternal != null;
-
ClipboardContentChangedInternal -= value;
-
- if (wasRunning && ClipboardContentChangedInternal == null)
- Current.StopClipboardListeners();
+ if (ClipboardContentChangedInternal == null)
+ StopClipboardListeners();
}
}
- static event EventHandler ClipboardContentChangedInternal;
-
- internal static void ClipboardChangedInternal() => ClipboardContentChangedInternal?.Invoke(null, EventArgs.Empty);
-
-#nullable enable
- static IClipboard? currentImplementation;
-#nullable disable
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static IClipboard Current =>
- currentImplementation ??= new ClipboardImplementation();
-
- [EditorBrowsable(EditorBrowsableState.Never)]
-#nullable enable
- public static void SetCurrent(IClipboard? implementation) =>
- currentImplementation = implementation;
-#nullable disable
+ internal void OnClipboardContentChanged() =>
+ ClipboardContentChangedInternal?.Invoke(this, EventArgs.Empty);
}
}
diff --git a/src/Essentials/src/Clipboard/Clipboard.uwp.cs b/src/Essentials/src/Clipboard/Clipboard.uwp.cs
index 32a95fa4022e..6b1194e3595d 100644
--- a/src/Essentials/src/Clipboard/Clipboard.uwp.cs
+++ b/src/Essentials/src/Clipboard/Clipboard.uwp.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
@@ -6,9 +7,9 @@
namespace Microsoft.Maui.ApplicationModel.DataTransfer
{
- public partial class ClipboardImplementation : IClipboard
+ partial class ClipboardImplementation : IClipboard
{
- public Task SetTextAsync(string text)
+ public Task SetTextAsync(string? text)
{
var dataPackage = new DataPackage();
dataPackage.SetText(text);
@@ -19,20 +20,20 @@ public Task SetTextAsync(string text)
public bool HasText
=> WindowsClipboard.GetContent().Contains(StandardDataFormats.Text);
- public Task GetTextAsync()
+ public Task GetTextAsync()
{
var clipboardContent = WindowsClipboard.GetContent();
return clipboardContent.Contains(StandardDataFormats.Text)
? clipboardContent.GetTextAsync().AsTask()
- : Task.FromResult(null);
+ : Task.FromResult(null);
}
- public void StartClipboardListeners()
+ void StartClipboardListeners()
=> WindowsClipboard.ContentChanged += ClipboardChangedEventListener;
- public void StopClipboardListeners()
+ void StopClipboardListeners()
=> WindowsClipboard.ContentChanged -= ClipboardChangedEventListener;
- public void ClipboardChangedEventListener(object sender, object val) => Clipboard.ClipboardChangedInternal();
+ public void ClipboardChangedEventListener(object? sender, object val) => OnClipboardContentChanged();
}
}
diff --git a/src/Essentials/src/Compass/Compass.android.cs b/src/Essentials/src/Compass/Compass.android.cs
index 82c4f2ed6c87..e4812170e1be 100644
--- a/src/Essentials/src/Compass/Compass.android.cs
+++ b/src/Essentials/src/Compass/Compass.android.cs
@@ -1,28 +1,35 @@
using System;
+using Android.App;
+using Android.Content;
using Android.Hardware;
-using Android.Runtime;
-using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class CompassImplementation : ICompass
+ partial class CompassImplementation : ICompass
{
- bool PlatformIsSupported =>
- Platform.SensorManager?.GetDefaultSensor(SensorType.Accelerometer) != null &&
- Platform.SensorManager?.GetDefaultSensor(SensorType.MagneticField) != null;
+ static SensorManager _sensorManager;
+ static Sensor _accelerometer;
+ static Sensor _magnetic;
+
+ static SensorManager SensorManager =>
+ _sensorManager ??= Application.Context.GetSystemService(Context.SensorService) as SensorManager;
+
+ static Sensor Accelerometer =>
+ _accelerometer ??= SensorManager?.GetDefaultSensor(SensorType.Accelerometer);
+
+ static Sensor MagneticField =>
+ _magnetic ??= SensorManager?.GetDefaultSensor(SensorType.MagneticField);
+
+ bool PlatformIsSupported => Accelerometer is not null && MagneticField is not null;
SensorListener listener;
- Sensor magnetometer;
- Sensor accelerometer;
void PlatformStart(SensorSpeed sensorSpeed, bool applyLowPassFilter)
{
var delay = sensorSpeed.ToPlatform();
- accelerometer = Platform.SensorManager.GetDefaultSensor(SensorType.Accelerometer);
- magnetometer = Platform.SensorManager.GetDefaultSensor(SensorType.MagneticField);
- listener = new SensorListener(accelerometer.Name, magnetometer.Name, delay, applyLowPassFilter, RaiseReadingChanged);
- Platform.SensorManager.RegisterListener(listener, accelerometer, delay);
- Platform.SensorManager.RegisterListener(listener, magnetometer, delay);
+ listener = new SensorListener(Accelerometer.Name, MagneticField.Name, delay, applyLowPassFilter, RaiseReadingChanged);
+ SensorManager.RegisterListener(listener, Accelerometer, delay);
+ SensorManager.RegisterListener(listener, MagneticField, delay);
}
void PlatformStop()
@@ -30,8 +37,8 @@ void PlatformStop()
if (listener == null)
return;
- Platform.SensorManager.UnregisterListener(listener, accelerometer);
- Platform.SensorManager.UnregisterListener(listener, magnetometer);
+ SensorManager.UnregisterListener(listener, Accelerometer);
+ SensorManager.UnregisterListener(listener, MagneticField);
listener.Dispose();
listener = null;
}
diff --git a/src/Essentials/src/Compass/Compass.ios.cs b/src/Essentials/src/Compass/Compass.ios.cs
index 7c42bb5aa657..9526784d0b1a 100644
--- a/src/Essentials/src/Compass/Compass.ios.cs
+++ b/src/Essentials/src/Compass/Compass.ios.cs
@@ -2,7 +2,7 @@
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class CompassImplementation : ICompass, IPlatformCompass
+ partial class CompassImplementation : ICompass, IPlatformCompass
{
// The angular distance is measured relative to the last delivered heading event. Align with UWP numbers
internal const double FastestFilter = .01;
diff --git a/src/Essentials/src/Compass/Compass.netstandard.tvos.watchos.macos.cs b/src/Essentials/src/Compass/Compass.netstandard.tvos.watchos.macos.cs
index 15571eca7c59..c156867fb708 100644
--- a/src/Essentials/src/Compass/Compass.netstandard.tvos.watchos.macos.cs
+++ b/src/Essentials/src/Compass/Compass.netstandard.tvos.watchos.macos.cs
@@ -2,7 +2,7 @@
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class CompassImplementation : ICompass
+ partial class CompassImplementation : ICompass
{
bool PlatformIsSupported => throw ExceptionUtils.NotSupportedOrImplementedException;
diff --git a/src/Essentials/src/Compass/Compass.shared.cs b/src/Essentials/src/Compass/Compass.shared.cs
index 7b6d9e744162..27b46c9ba646 100644
--- a/src/Essentials/src/Compass/Compass.shared.cs
+++ b/src/Essentials/src/Compass/Compass.shared.cs
@@ -1,5 +1,5 @@
+#nullable enable
using System;
-using System.ComponentModel;
using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Devices.Sensors
@@ -10,12 +10,10 @@ public interface ICompass
bool IsMonitoring { get; }
- SensorSpeed SensorSpeed { get; }
-
void Start(SensorSpeed sensorSpeed);
void Start(SensorSpeed sensorSpeed, bool applyLowPassFilter);
-
+
void Stop();
event EventHandler ReadingChanged;
@@ -29,7 +27,7 @@ public interface IPlatformCompass
}
///
- public static partial class Compass
+ public static class Compass
{
public static event EventHandler ReadingChanged
{
@@ -37,15 +35,16 @@ public static event EventHandler ReadingChanged
remove => Current.ReadingChanged -= value;
}
- ///
- public static bool IsSupported
+ public static bool IsSupported
=> Current.IsSupported;
+ ///
public static bool IsMonitoring
=> Current.IsMonitoring;
///
- public static void Start(SensorSpeed sensorSpeed) => Start(sensorSpeed, true);
+ public static void Start(SensorSpeed sensorSpeed)
+ => Start(sensorSpeed, true);
///
public static void Start(SensorSpeed sensorSpeed, bool applyLowPassFilter)
@@ -72,19 +71,28 @@ public static bool ShouldDisplayHeadingCalibration
}
#endif
-#nullable enable
- static ICompass? currentImplementation;
-#nullable disable
+ static ICompass Current => Devices.Sensors.Compass.Default;
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static ICompass Current =>
- currentImplementation ??= new CompassImplementation();
+ static ICompass? defaultImplementation;
- [EditorBrowsable(EditorBrowsableState.Never)]
-#nullable enable
- public static void SetCurrent(ICompass? implementation) =>
- currentImplementation = implementation;
-#nullable disable
+ public static ICompass Default =>
+ defaultImplementation ??= new CompassImplementation();
+
+ internal static void SetDefault(ICompass? implementation) =>
+ defaultImplementation = implementation;
+ }
+
+ public static class CompassExtensions
+ {
+#if IOS || MACCATALYST
+ public static void SetShouldDisplayHeadingCalibration(this ICompass compass, bool shouldDisplay)
+ {
+ if (compass is IPlatformCompass platform)
+ {
+ platform.ShouldDisplayHeadingCalibration = shouldDisplay;
+ }
+ }
+#endif
}
///
@@ -109,7 +117,7 @@ public CompassData(double headingMagneticNorth) =>
public double HeadingMagneticNorth { get; }
///
- public override bool Equals(object obj) =>
+ public override bool Equals(object? obj) =>
(obj is CompassData data) && Equals(data);
///
@@ -130,22 +138,19 @@ public override int GetHashCode() =>
public override string ToString() =>
$"{nameof(HeadingMagneticNorth)}: {HeadingMagneticNorth}";
}
-}
-namespace Microsoft.Maui.Devices.Sensors
-{
- public partial class CompassImplementation : ICompass
+ partial class CompassImplementation : ICompass
{
bool UseSyncContext => SensorSpeed == SensorSpeed.Default || SensorSpeed == SensorSpeed.UI;
- public event EventHandler ReadingChanged;
+ public event EventHandler? ReadingChanged;
public bool IsSupported
=> PlatformIsSupported;
public bool IsMonitoring { get; private set; }
- public SensorSpeed SensorSpeed { get; private set; }
+ SensorSpeed SensorSpeed { get; set; }
public void Start(SensorSpeed sensorSpeed) => Start(sensorSpeed, true);
@@ -158,7 +163,7 @@ public void Start(SensorSpeed sensorSpeed, bool applyLowPassFilter)
throw new InvalidOperationException("Compass has already been started.");
IsMonitoring = true;
-
+
try
{
diff --git a/src/Essentials/src/Compass/Compass.tizen.cs b/src/Essentials/src/Compass/Compass.tizen.cs
index a3ce5ea7fad6..97f081d4b18f 100644
--- a/src/Essentials/src/Compass/Compass.tizen.cs
+++ b/src/Essentials/src/Compass/Compass.tizen.cs
@@ -3,7 +3,7 @@
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class CompassImplementation : ICompass
+ partial class CompassImplementation : ICompass
{
static TizenCompass DefaultSensor =>
(TizenCompass)Platform.GetDefaultSensor(SensorType.Compass);
diff --git a/src/Essentials/src/Compass/Compass.uwp.cs b/src/Essentials/src/Compass/Compass.uwp.cs
index a1111651d101..456aa8b53b32 100644
--- a/src/Essentials/src/Compass/Compass.uwp.cs
+++ b/src/Essentials/src/Compass/Compass.uwp.cs
@@ -4,7 +4,7 @@
namespace Microsoft.Maui.Devices.Sensors
{
- public partial class CompassImplementation : ICompass
+ partial class CompassImplementation : ICompass
{
// Magic numbers from https://docs.microsoft.com/en-us/uwp/api/windows.devices.sensors.compass.reportinterval#Windows_Devices_Sensors_Compass_ReportInterval
internal const uint FastestInterval = 8;
diff --git a/src/Essentials/src/Connectivity/Connectivity.android.cs b/src/Essentials/src/Connectivity/Connectivity.android.cs
index 92ed0aa731a3..1726762b7a2d 100644
--- a/src/Essentials/src/Connectivity/Connectivity.android.cs
+++ b/src/Essentials/src/Connectivity/Connectivity.android.cs
@@ -1,30 +1,37 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using Android.App;
using Android.Content;
using Android.Net;
-using Android.OS;
using Microsoft.Maui.ApplicationModel;
using Debug = System.Diagnostics.Debug;
namespace Microsoft.Maui.Networking
{
- public partial class ConnectivityImplementation : IConnectivity
+ partial class ConnectivityImplementation : IConnectivity
{
- static ConnectivityBroadcastReceiver conectivityReceiver;
- static Intent connectivityIntent = new Intent(Platform.EssentialsConnectivityChanged);
- static EssentialsNetworkCallback networkCallback;
+ public const string ConnectivityChangedAction = "com.maui.essentials.ESSENTIALS_CONNECTIVITY_CHANGED";
+ static Intent connectivityIntent = new Intent(ConnectivityChangedAction);
- public void StartListeners()
+ static ConnectivityManager connectivityManager;
+
+ static ConnectivityManager ConnectivityManager =>
+ connectivityManager ??= Application.Context.GetSystemService(Context.ConnectivityService) as ConnectivityManager;
+
+ ConnectivityBroadcastReceiver conectivityReceiver;
+ EssentialsNetworkCallback networkCallback;
+
+ void StartListeners()
{
Permissions.EnsureDeclared();
var filter = new IntentFilter();
- if (Platform.HasApiLevelN)
+ if (OperatingSystem.IsAndroidVersionAtLeast(24))
{
RegisterNetworkCallback();
- filter.AddAction(Platform.EssentialsConnectivityChanged);
+ filter.AddAction(ConnectivityChangedAction);
}
else
{
@@ -33,12 +40,12 @@ public void StartListeners()
#pragma warning restore CS0618 // Type or member is obsolete
}
- conectivityReceiver = new ConnectivityBroadcastReceiver(Connectivity.OnConnectivityChanged);
+ conectivityReceiver = new ConnectivityBroadcastReceiver(OnConnectivityChanged);
- Platform.AppContext.RegisterReceiver(conectivityReceiver, filter);
+ Application.Context.RegisterReceiver(conectivityReceiver, filter);
}
- public void StopListeners()
+ void StopListeners()
{
if (conectivityReceiver == null)
return;
@@ -54,21 +61,23 @@ public void StopListeners()
try
{
- Platform.AppContext.UnregisterReceiver(conectivityReceiver);
+ Application.Context.UnregisterReceiver(conectivityReceiver);
}
catch (Java.Lang.IllegalArgumentException)
{
Debug.WriteLine("Connectivity receiver already unregistered. Disposing of it.");
}
+
conectivityReceiver.Dispose();
conectivityReceiver = null;
}
+
void RegisterNetworkCallback()
{
- if (!Platform.HasApiLevelN)
+ if (!OperatingSystem.IsAndroidVersionAtLeast(24))
return;
- var manager = Platform.ConnectivityManager;
+ var manager = ConnectivityManager;
if (manager == null)
return;
@@ -79,10 +88,10 @@ void RegisterNetworkCallback()
void UnregisterNetworkCallback()
{
- if (!Platform.HasApiLevelN)
+ if (!OperatingSystem.IsAndroidVersionAtLeast(24))
return;
- var manager = Platform.ConnectivityManager;
+ var manager = ConnectivityManager;
if (manager == null || networkCallback == null)
return;
@@ -94,17 +103,23 @@ void UnregisterNetworkCallback()
class EssentialsNetworkCallback : ConnectivityManager.NetworkCallback
{
- public override void OnAvailable(Network network) => Platform.AppContext.SendBroadcast(connectivityIntent);
+ public override void OnAvailable(Network network) =>
+ Application.Context.SendBroadcast(connectivityIntent);
- public override void OnLost(Network network) => Platform.AppContext.SendBroadcast(connectivityIntent);
+ public override void OnLost(Network network) =>
+ Application.Context.SendBroadcast(connectivityIntent);
- public override void OnCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) => Platform.AppContext.SendBroadcast(connectivityIntent);
+ public override void OnCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) =>
+ Application.Context.SendBroadcast(connectivityIntent);
- public override void OnUnavailable() => Platform.AppContext.SendBroadcast(connectivityIntent);
+ public override void OnUnavailable() =>
+ Application.Context.SendBroadcast(connectivityIntent);
- public override void OnLinkPropertiesChanged(Network network, LinkProperties linkProperties) => Platform.AppContext.SendBroadcast(connectivityIntent);
+ public override void OnLinkPropertiesChanged(Network network, LinkProperties linkProperties) =>
+ Application.Context.SendBroadcast(connectivityIntent);
- public override void OnLosing(Network network, int maxMsToLive) => Platform.AppContext.SendBroadcast(connectivityIntent);
+ public override void OnLosing(Network network, int maxMsToLive) =>
+ Application.Context.SendBroadcast(connectivityIntent);
}
static NetworkAccess IsBetterAccess(NetworkAccess currentAccess, NetworkAccess newAccess) =>
@@ -119,7 +134,7 @@ public NetworkAccess NetworkAccess
try
{
var currentAccess = NetworkAccess.None;
- var manager = Platform.ConnectivityManager;
+ var manager = ConnectivityManager;
#pragma warning disable CS0618 // Type or member is obsolete
var networks = manager.GetAllNetworks();
@@ -204,7 +219,7 @@ public IEnumerable ConnectionProfiles
{
Permissions.EnsureDeclared();
- var manager = Platform.ConnectivityManager;
+ var manager = ConnectivityManager;
#pragma warning disable CS0618 // Type or member is obsolete
var networks = manager.GetAllNetworks();
#pragma warning restore CS0618 // Type or member is obsolete
@@ -296,7 +311,7 @@ public ConnectivityBroadcastReceiver(Action onChanged) =>
public override async void OnReceive(Context context, Intent intent)
{
#pragma warning disable CS0618 // Type or member is obsolete
- if (intent.Action != ConnectivityManager.ConnectivityAction && intent.Action != Platform.EssentialsConnectivityChanged)
+ if (intent.Action != ConnectivityManager.ConnectivityAction && intent.Action != ConnectivityImplementation.ConnectivityChangedAction)
#pragma warning restore CS0618 // Type or member is obsolete
return;
diff --git a/src/Essentials/src/Connectivity/Connectivity.ios.tvos.macos.cs b/src/Essentials/src/Connectivity/Connectivity.ios.tvos.macos.cs
index f2ef1387ee6f..0375bed85658 100644
--- a/src/Essentials/src/Connectivity/Connectivity.ios.tvos.macos.cs
+++ b/src/Essentials/src/Connectivity/Connectivity.ios.tvos.macos.cs
@@ -6,7 +6,7 @@
namespace Microsoft.Maui.Networking
{
- public partial class ConnectivityImplementation : IConnectivity
+ partial class ConnectivityImplementation : IConnectivity
{
#if !(MACCATALYST || MACOS)
// TODO: Use NWPathMonitor on > iOS 12
@@ -19,18 +19,18 @@ public partial class ConnectivityImplementation : IConnectivity
static ReachabilityListener listener;
- public void StartListeners()
+ void StartListeners()
{
listener = new ReachabilityListener();
- listener.ReachabilityChanged += Connectivity.OnConnectivityChanged;
+ listener.ReachabilityChanged += OnConnectivityChanged;
}
- public void StopListeners()
+ void StopListeners()
{
if (listener == null)
return;
- listener.ReachabilityChanged -= Connectivity.OnConnectivityChanged;
+ listener.ReachabilityChanged -= OnConnectivityChanged;
listener.Dispose();
listener = null;
}
diff --git a/src/Essentials/src/Connectivity/Connectivity.netstandard.watchos.cs b/src/Essentials/src/Connectivity/Connectivity.netstandard.watchos.cs
index 07efc6260f9f..540d56d30a0f 100644
--- a/src/Essentials/src/Connectivity/Connectivity.netstandard.watchos.cs
+++ b/src/Essentials/src/Connectivity/Connectivity.netstandard.watchos.cs
@@ -4,7 +4,7 @@
namespace Microsoft.Maui.Networking
{
///
- public partial class ConnectivityImplementation : IConnectivity
+ partial class ConnectivityImplementation : IConnectivity
{
public NetworkAccess NetworkAccess =>
throw ExceptionUtils.NotSupportedOrImplementedException;
@@ -12,10 +12,10 @@ public partial class ConnectivityImplementation : IConnectivity
public IEnumerable ConnectionProfiles =>
throw ExceptionUtils.NotSupportedOrImplementedException;
- public void StartListeners() =>
+ void StartListeners() =>
throw ExceptionUtils.NotSupportedOrImplementedException;
- public void StopListeners() =>
+ void StopListeners() =>
throw ExceptionUtils.NotSupportedOrImplementedException;
}
}
diff --git a/src/Essentials/src/Connectivity/Connectivity.shared.cs b/src/Essentials/src/Connectivity/Connectivity.shared.cs
index 0732fe824750..4bdc7661fd39 100644
--- a/src/Essentials/src/Connectivity/Connectivity.shared.cs
+++ b/src/Essentials/src/Connectivity/Connectivity.shared.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
+using Microsoft.Maui.Networking;
using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Networking
@@ -12,66 +13,78 @@ public interface IConnectivity
NetworkAccess NetworkAccess { get; }
- void StartListeners();
-
- void StopListeners();
+ event EventHandler ConnectivityChanged;
}
+#nullable enable
///
- public static partial class Connectivity
+ public static class Connectivity
{
- static event EventHandler ConnectivityChangedInternal;
-
- // a cache so that events aren't fired unnecessarily
- // this is mainly an issue on Android, but we can stiil do this everywhere
- static NetworkAccess currentAccess;
- static List currentProfiles;
-
///
public static NetworkAccess NetworkAccess => Current.NetworkAccess;
///
public static IEnumerable ConnectionProfiles => Current.ConnectionProfiles.Distinct();
+ ///
public static event EventHandler ConnectivityChanged
{
- add
- {
- var wasRunning = ConnectivityChangedInternal != null;
+ add => Current.ConnectivityChanged += value;
+ remove => Current.ConnectivityChanged -= value;
+ }
- ConnectivityChangedInternal += value;
+ static IConnectivity? currentImplementation;
+
+ public static IConnectivity Current =>
+ currentImplementation ??= new ConnectivityImplementation();
+
+ internal static void SetCurrent(IConnectivity? implementation) =>
+ currentImplementation = implementation;
+ }
+#nullable disable
+
+ ///
+ partial class ConnectivityImplementation : IConnectivity
+ {
+ event EventHandler ConnectivityChangedInternal;
- if (!wasRunning && ConnectivityChangedInternal != null)
+ // a cache so that events aren't fired unnecessarily
+ // this is mainly an issue on Android, but we can stiil do this everywhere
+ NetworkAccess currentAccess;
+ List currentProfiles;
+
+ public event EventHandler ConnectivityChanged
+ {
+ add
+ {
+ if (ConnectivityChangedInternal is null)
{
SetCurrent();
- Current.StartListeners();
+ StartListeners();
}
+ ConnectivityChangedInternal += value;
}
-
remove
{
- var wasRunning = ConnectivityChangedInternal != null;
-
ConnectivityChangedInternal -= value;
-
- if (wasRunning && ConnectivityChangedInternal == null)
- Current.StopListeners();
+ if (ConnectivityChangedInternal is null)
+ StopListeners();
}
}
- static void SetCurrent()
+ void SetCurrent()
{
currentAccess = NetworkAccess;
currentProfiles = new List(ConnectionProfiles);
}
- internal static void OnConnectivityChanged(NetworkAccess access, IEnumerable profiles)
+ void OnConnectivityChanged(NetworkAccess access, IEnumerable profiles)
=> OnConnectivityChanged(new ConnectivityChangedEventArgs(access, profiles));
- internal static void OnConnectivityChanged()
+ void OnConnectivityChanged()
=> OnConnectivityChanged(NetworkAccess, ConnectionProfiles);
- internal static void OnConnectivityChanged(ConnectivityChangedEventArgs e)
+ void OnConnectivityChanged(ConnectivityChangedEventArgs e)
{
if (currentAccess != e.NetworkAccess || !currentProfiles.SequenceEqual(e.ConnectionProfiles))
{
@@ -79,20 +92,6 @@ internal static void OnConnectivityChanged(ConnectivityChangedEventArgs e)
MainThread.BeginInvokeOnMainThread(() => ConnectivityChangedInternal?.Invoke(null, e));
}
}
-
-#nullable enable
- static IConnectivity? currentImplementation;
-#nullable disable
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static IConnectivity Current =>
- currentImplementation ??= new ConnectivityImplementation();
-
- [EditorBrowsable(EditorBrowsableState.Never)]
-#nullable enable
- public static void SetCurrent(IConnectivity? implementation) =>
- currentImplementation = implementation;
-#nullable disable
}
///
diff --git a/src/Essentials/src/Connectivity/Connectivity.tizen.cs b/src/Essentials/src/Connectivity/Connectivity.tizen.cs
index 0c73053a66c8..259f6faa803b 100644
--- a/src/Essentials/src/Connectivity/Connectivity.tizen.cs
+++ b/src/Essentials/src/Connectivity/Connectivity.tizen.cs
@@ -3,16 +3,16 @@
namespace Microsoft.Maui.Networking
{
- public partial class ConnectivityImplementation : IConnectivity
+ partial class ConnectivityImplementation : IConnectivity
{
- static IList profiles = new List();
+ IList profiles = new List();
- internal static void OnChanged(object sender, object e)
+ void OnChanged(object sender, object e)
{
GetProfileListAsync();
}
- internal static async void GetProfileListAsync()
+ async void GetProfileListAsync()
{
var list = await ConnectionProfileManager.GetProfileListAsync(ProfileListType.Connected);
profiles.Clear();
@@ -66,14 +66,14 @@ public IEnumerable ConnectionProfiles
}
}
- public void StartListeners()
+ void StartListeners()
{
Permissions.EnsureDeclared();
ConnectionManager.ConnectionTypeChanged += OnChanged;
GetProfileListAsync();
}
- public void StopListeners()
+ void StopListeners()
{
ConnectionManager.ConnectionTypeChanged -= OnChanged;
}
diff --git a/src/Essentials/src/Connectivity/Connectivity.uwp.cs b/src/Essentials/src/Connectivity/Connectivity.uwp.cs
index c09da8d70d5a..84dedc99e84d 100644
--- a/src/Essentials/src/Connectivity/Connectivity.uwp.cs
+++ b/src/Essentials/src/Connectivity/Connectivity.uwp.cs
@@ -5,16 +5,16 @@
namespace Microsoft.Maui.Networking
{
- public partial class ConnectivityImplementation : IConnectivity
+ partial class ConnectivityImplementation : IConnectivity
{
- public void StartListeners() =>
- NetworkInformation.NetworkStatusChanged += NetworkStatusChanged;
+ void StartListeners() =>
+ NetworkInformation.NetworkStatusChanged += NetworkStatusChanged;
- static void NetworkStatusChanged(object sender) =>
- Connectivity.OnConnectivityChanged();
+ void StopListeners() =>
+ NetworkInformation.NetworkStatusChanged -= NetworkStatusChanged;
- public void StopListeners() =>
- NetworkInformation.NetworkStatusChanged -= NetworkStatusChanged;
+ void NetworkStatusChanged(object sender) =>
+ OnConnectivityChanged();
public NetworkAccess NetworkAccess
{
diff --git a/src/Essentials/src/Contacts/Contacts.android.cs b/src/Essentials/src/Contacts/Contacts.android.cs
index be04b97b4239..5f1cd535ea4b 100644
--- a/src/Essentials/src/Contacts/Contacts.android.cs
+++ b/src/Essentials/src/Contacts/Contacts.android.cs
@@ -2,6 +2,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Android.App;
using Android.Content;
using Android.Database;
using Android.Provider;
@@ -10,7 +11,7 @@
namespace Microsoft.Maui.ApplicationModel.Communication
{
- public class ContactsImplementation : IContacts
+ class ContactsImplementation : IContacts
{
const string idCol = ContactsContract.Contacts.InterfaceConsts.Id;
const string displayNameCol = ContactsContract.Contacts.InterfaceConsts.DisplayName;
@@ -21,11 +22,11 @@ public class ContactsImplementation : IContacts
public async Task PickContactAsync()
{
var intent = new Intent(Intent.ActionPick, ContactsContract.Contacts.ContentUri);
- var result = await IntermediateActivity.StartAsync(intent, Platform.requestCodePickContact).ConfigureAwait(false);
+ var result = await IntermediateActivity.StartAsync(intent, PlatformUtils.requestCodePickContact).ConfigureAwait(false);
if (result?.Data == null)
return null;
- using var cursor = Platform.ContentResolver.Query(result?.Data, null, null, null, null);
+ using var cursor = Application.Context.ContentResolver.Query(result?.Data, null, null, null, null);
if (cursor?.MoveToFirst() != true)
return null;
@@ -34,7 +35,7 @@ public async Task PickContactAsync()
public Task> GetAllAsync(CancellationToken cancellationToken)
{
- var cursor = Platform.ContentResolver.Query(ContactsContract.Contacts.ContentUri, null, null, null, null);
+ var cursor = Application.Context.ContentResolver.Query(ContactsContract.Contacts.ContentUri, null, null, null, null);
return Task.FromResult(GetEnumerable());
IEnumerable GetEnumerable()
@@ -72,7 +73,7 @@ static IEnumerable GetNumbers(string id)
.AppendQueryParameter(ContactsContract.RemoveDuplicateEntries, "1")
.Build();
- var cursor = Platform.ContentResolver.Query(uri, null, $"{contactIdCol}=?", new[] { id }, null);
+ var cursor = Application.Context.ContentResolver.Query(uri, null, $"{contactIdCol}=?", new[] { id }, null);
return ReadCursorItems(cursor, CommonDataKinds.Phone.Number);
}
@@ -84,7 +85,7 @@ static IEnumerable GetEmails(string id)
.AppendQueryParameter(ContactsContract.RemoveDuplicateEntries, "1")
.Build();
- var cursor = Platform.ContentResolver.Query(uri, null, $"{contactIdCol}=?", new[] { id }, null);
+ var cursor = Application.Context.ContentResolver.Query(uri, null, $"{contactIdCol}=?", new[] { id }, null);
return ReadCursorItems(cursor, CommonDataKinds.Email.Address);
}
@@ -109,7 +110,7 @@ static IEnumerable ReadCursorItems(ICursor cursor, string dataKey)
var selection = $"{mimetypeCol}=? AND {contactIdCol}=?";
var selectionArgs = new string[] { StructuredName.ContentItemType, id };
- using var cursor = Platform.ContentResolver.Query(
+ using var cursor = Application.Context.ContentResolver.Query(
ContactsContract.Data.ContentUri,
null,
selection,
diff --git a/src/Essentials/src/Contacts/Contacts.ios.macos.cs b/src/Essentials/src/Contacts/Contacts.ios.macos.cs
index 59445510e7ca..9211a6bd93ee 100644
--- a/src/Essentials/src/Contacts/Contacts.ios.macos.cs
+++ b/src/Essentials/src/Contacts/Contacts.ios.macos.cs
@@ -10,17 +10,15 @@
namespace Microsoft.Maui.ApplicationModel.Communication
{
- public class ContactsImplementation : IContacts
+ class ContactsImplementation : IContacts
{
#if __MACOS__
- static Task PlatformPickContactAsync() => throw ExceptionUtils.NotSupportedOrImplementedException;
-
+ public Task PickContactAsync() =>
+ throw ExceptionUtils.NotSupportedOrImplementedException;
#elif __IOS__
public Task PickContactAsync()
{
- var uiView = Platform.GetCurrentViewController();
- if (uiView == null)
- throw new ArgumentNullException($"The View Controller can't be null.");
+ var vc = WindowStateManager.Default.GetCurrentUIViewController(true);
var source = new TaskCompletionSource();
@@ -42,15 +40,15 @@ public Task PickContactAsync()
if (picker.PresentationController != null)
{
picker.PresentationController.Delegate =
- new Platform.UIPresentationControllerDelegate(() => source?.TrySetResult(null));
+ new UIPresentationControllerDelegate(() => source?.TrySetResult(null));
}
- uiView.PresentViewController(picker, true, null);
+ vc.PresentViewController(picker, true, null);
return source.Task;
}
-
#endif
+
public Task> GetAllAsync(CancellationToken cancellationToken)
{
var keys = new[]
diff --git a/src/Essentials/src/Contacts/Contacts.netstandard.tvos.watchos.cs b/src/Essentials/src/Contacts/Contacts.netstandard.tvos.watchos.cs
index d23e54c3dce7..17d8af73fc6e 100644
--- a/src/Essentials/src/Contacts/Contacts.netstandard.tvos.watchos.cs
+++ b/src/Essentials/src/Contacts/Contacts.netstandard.tvos.watchos.cs
@@ -5,10 +5,12 @@
namespace Microsoft.Maui.ApplicationModel.Communication
{
///
- public class ContactsImplementation : IContacts
+ class ContactsImplementation : IContacts
{
- public Task PickContactAsync() => throw ExceptionUtils.NotSupportedOrImplementedException;
+ public Task PickContactAsync() =>
+ throw ExceptionUtils.NotSupportedOrImplementedException;
- public Task> GetAllAsync(CancellationToken cancellationToken) => throw ExceptionUtils.NotSupportedOrImplementedException;
+ public Task> GetAllAsync(CancellationToken cancellationToken) =>
+ throw ExceptionUtils.NotSupportedOrImplementedException;
}
}
diff --git a/src/Essentials/src/Contacts/Contacts.shared.cs b/src/Essentials/src/Contacts/Contacts.shared.cs
index bfe8f1bbe932..0c9062944819 100644
--- a/src/Essentials/src/Contacts/Contacts.shared.cs
+++ b/src/Essentials/src/Contacts/Contacts.shared.cs
@@ -1,42 +1,34 @@
#nullable enable
using System.Collections.Generic;
-using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.Maui.Devices;
namespace Microsoft.Maui.ApplicationModel.Communication
{
public interface IContacts
{
- Task PickContactAsync();
+ Task PickContactAsync();
+
Task> GetAllAsync(CancellationToken cancellationToken = default);
}
+
///
public static class Contacts
{
///
- public static async Task PickContactAsync()
- {
- // iOS does not require permissions for the picker
- if (DeviceInfo.Platform != DevicePlatform.iOS)
- await Permissions.EnsureGrantedAsync();
-
- return await Current.PickContactAsync();
- }
+ public static Task PickContactAsync() =>
+ Default.PickContactAsync();
///
- public static Task> GetAllAsync(CancellationToken cancellationToken = default)
- => Current.GetAllAsync(cancellationToken);
+ public static Task> GetAllAsync(CancellationToken cancellationToken = default) =>
+ Default.GetAllAsync(cancellationToken);
- static IContacts? currentImplementation;
+ static IContacts? defaultImplementation;
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static IContacts Current =>
- currentImplementation ??= new ContactsImplementation();
+ public static IContacts Default =>
+ defaultImplementation ??= new ContactsImplementation();
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static void SetCurrent(IContacts? implementation) =>
- currentImplementation = implementation;
+ internal static void SetDefault(IContacts? implementation) =>
+ defaultImplementation = implementation;
}
}
diff --git a/src/Essentials/src/Contacts/Contacts.tizen.cs b/src/Essentials/src/Contacts/Contacts.tizen.cs
index 32e1722bb70c..699c28ee8dad 100644
--- a/src/Essentials/src/Contacts/Contacts.tizen.cs
+++ b/src/Essentials/src/Contacts/Contacts.tizen.cs
@@ -11,7 +11,7 @@
namespace Microsoft.Maui.ApplicationModel.Communication
{
- public static partial class Contacts
+ static partial class Contacts
{
static ContactsManager manager = new ContactsManager();
diff --git a/src/Essentials/src/Contacts/Contacts.uwp.cs b/src/Essentials/src/Contacts/Contacts.uwp.cs
index 6c2ff6022317..a58de49e0978 100644
--- a/src/Essentials/src/Contacts/Contacts.uwp.cs
+++ b/src/Essentials/src/Contacts/Contacts.uwp.cs
@@ -7,7 +7,7 @@
namespace Microsoft.Maui.ApplicationModel.Communication
{
- public class ContactsImplementation:IContacts
+ class ContactsImplementation : IContacts
{
public async Task PickContactAsync()
{
diff --git a/src/Essentials/src/DeviceDisplay/DeviceDisplay.android.cs b/src/Essentials/src/DeviceDisplay/DeviceDisplay.android.cs
index 82b3d60abd71..40d3f20d814f 100644
--- a/src/Essentials/src/DeviceDisplay/DeviceDisplay.android.cs
+++ b/src/Essentials/src/DeviceDisplay/DeviceDisplay.android.cs
@@ -2,9 +2,9 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
+using Android.App;
using Android.Content;
using Android.Content.Res;
-using Android.Provider;
using Android.Runtime;
using Android.Util;
using Android.Views;
@@ -12,32 +12,27 @@
namespace Microsoft.Maui.Devices
{
- public class DeviceDisplayImplementation : IDeviceDisplay
+ partial class DeviceDisplayImplementation
{
OrientationEventListener? orientationListener;
- public event EventHandler? MainDisplayInfoChanged;
-
- public bool KeepScreenOn
+ protected override bool GetKeepScreenOn()
{
- get
- {
- var window = Platform.GetCurrentActivity(true)?.Window;
- var flags = window?.Attributes?.Flags ?? 0;
- return flags.HasFlag(WindowManagerFlags.KeepScreenOn);
- }
+ var window = ActivityStateManager.Default.GetCurrentActivity(true)?.Window;
+ var flags = window?.Attributes?.Flags ?? 0;
+ return flags.HasFlag(WindowManagerFlags.KeepScreenOn);
+ }
- set
- {
- var window = Platform.GetCurrentActivity(true)?.Window;
- if (value)
- window?.AddFlags(WindowManagerFlags.KeepScreenOn);
- else
- window?.ClearFlags(WindowManagerFlags.KeepScreenOn);
- }
+ protected override void SetKeepScreenOn(bool keepScreenOn)
+ {
+ var window = ActivityStateManager.Default.GetCurrentActivity(true)?.Window;
+ if (keepScreenOn)
+ window?.AddFlags(WindowManagerFlags.KeepScreenOn);
+ else
+ window?.ClearFlags(WindowManagerFlags.KeepScreenOn);
}
- public DisplayInfo GetMainDisplayInfo()
+ protected override DisplayInfo GetMainDisplayInfo()
{
using var displayMetrics = new DisplayMetrics();
var display = GetDefaultDisplay();
@@ -50,34 +45,25 @@ public DisplayInfo GetMainDisplayInfo()
height: displayMetrics?.HeightPixels ?? 0,
density: displayMetrics?.Density ?? 0,
orientation: CalculateOrientation(),
- rotation: CalculateRotation(),
+ rotation: CalculateRotation(display),
rate: display?.RefreshRate ?? 0);
}
- public void StartScreenMetricsListeners()
+ protected override void StartScreenMetricsListeners()
{
- orientationListener = new Listener(Platform.AppContext, OnScreenMetricsChanged);
+ orientationListener = new Listener(Application.Context, OnMainDisplayInfoChanged);
orientationListener.Enable();
}
- public void StopScreenMetricsListeners()
+ protected override void StopScreenMetricsListeners()
{
orientationListener?.Disable();
orientationListener?.Dispose();
orientationListener = null;
}
- void OnScreenMetricsChanged()
- {
- var metrics = GetMainDisplayInfo();
- MainDisplayInfoChanged?.Invoke(this, new DisplayInfoChangedEventArgs(metrics));
- }
-
- DisplayRotation CalculateRotation()
- {
- var display = GetDefaultDisplay();
-
- return display?.Rotation switch
+ static DisplayRotation CalculateRotation(Display? display) =>
+ display?.Rotation switch
{
SurfaceOrientation.Rotation270 => DisplayRotation.Rotation270,
SurfaceOrientation.Rotation180 => DisplayRotation.Rotation180,
@@ -85,24 +71,21 @@ DisplayRotation CalculateRotation()
SurfaceOrientation.Rotation0 => DisplayRotation.Rotation0,
_ => DisplayRotation.Unknown,
};
- }
- DisplayOrientation CalculateOrientation()
- {
- return Platform.AppContext.Resources?.Configuration?.Orientation switch
+ static DisplayOrientation CalculateOrientation() =>
+ Application.Context.Resources?.Configuration?.Orientation switch
{
Orientation.Landscape => DisplayOrientation.Landscape,
Orientation.Portrait => DisplayOrientation.Portrait,
Orientation.Square => DisplayOrientation.Portrait,
_ => DisplayOrientation.Unknown
};
- }
- Display? GetDefaultDisplay()
+ static Display? GetDefaultDisplay()
{
try
{
- using var service = Platform.AppContext.GetSystemService(Context.WindowService);
+ using var service = Application.Context.GetSystemService(Context.WindowService);
using var windowManager = service?.JavaCast();
return windowManager?.DefaultDisplay;
}
diff --git a/src/Essentials/src/DeviceDisplay/DeviceDisplay.ios.cs b/src/Essentials/src/DeviceDisplay/DeviceDisplay.ios.cs
index b4de256c4da8..92feec4234de 100644
--- a/src/Essentials/src/DeviceDisplay/DeviceDisplay.ios.cs
+++ b/src/Essentials/src/DeviceDisplay/DeviceDisplay.ios.cs
@@ -1,83 +1,65 @@
#nullable enable
using System;
using Foundation;
-using ObjCRuntime;
using UIKit;
namespace Microsoft.Maui.Devices
{
- public class DeviceDisplayImplementation : IDeviceDisplay
+ partial class DeviceDisplayImplementation : IDeviceDisplay
{
NSObject? observer;
- public event EventHandler? MainDisplayInfoChanged;
+ protected override bool GetKeepScreenOn() => UIApplication.SharedApplication.IdleTimerDisabled;
- public bool KeepScreenOn
- {
- get => UIApplication.SharedApplication.IdleTimerDisabled;
- set => UIApplication.SharedApplication.IdleTimerDisabled = value;
- }
+ protected override void SetKeepScreenOn(bool keepScreenOn) => UIApplication.SharedApplication.IdleTimerDisabled = keepScreenOn;
- public DisplayInfo GetMainDisplayInfo()
+ protected override DisplayInfo GetMainDisplayInfo()
{
var bounds = UIScreen.MainScreen.Bounds;
var scale = UIScreen.MainScreen.Scale;
+ var rate = (OperatingSystem.IsIOSVersionAtLeast(10, 3) || OperatingSystem.IsTvOSVersionAtLeast(10, 3))
+ ? UIScreen.MainScreen.MaximumFramesPerSecond
+ : 0;
+
return new DisplayInfo(
width: bounds.Width * scale,
height: bounds.Height * scale,
density: scale,
orientation: CalculateOrientation(),
rotation: CalculateRotation(),
- rate: (OperatingSystem.IsIOSVersionAtLeast(10, 3) || OperatingSystem.IsTvOSVersionAtLeast(10, 3)) ? UIScreen.MainScreen.MaximumFramesPerSecond : 0);
+ rate: rate);
}
- public void StartScreenMetricsListeners()
+ protected override void StartScreenMetricsListeners()
{
var notificationCenter = NSNotificationCenter.DefaultCenter;
var notification = UIApplication.DidChangeStatusBarOrientationNotification;
- observer = notificationCenter.AddObserver(notification, OnScreenMetricsChanged);
+ observer = notificationCenter.AddObserver(notification, OnMainDisplayInfoChanged);
}
- public void StopScreenMetricsListeners()
+ protected override void StopScreenMetricsListeners()
{
observer?.Dispose();
observer = null;
}
- void OnScreenMetricsChanged(NSNotification obj)
- {
- var metrics = GetMainDisplayInfo();
- MainDisplayInfoChanged?.Invoke(this, new DisplayInfoChangedEventArgs(metrics));
- }
-
- DisplayOrientation CalculateOrientation()
- {
- var orientation = UIApplication.SharedApplication.StatusBarOrientation;
+ void OnMainDisplayInfoChanged(NSNotification obj) =>
+ OnMainDisplayInfoChanged();
- if (orientation.IsLandscape())
- return DisplayOrientation.Landscape;
+ static DisplayOrientation CalculateOrientation() =>
+ UIApplication.SharedApplication.StatusBarOrientation.IsLandscape()
+ ? DisplayOrientation.Landscape
+ : DisplayOrientation.Portrait;
- return DisplayOrientation.Portrait;
- }
-
- DisplayRotation CalculateRotation()
- {
- var orientation = UIApplication.SharedApplication.StatusBarOrientation;
-
- switch (orientation)
+ static DisplayRotation CalculateRotation() =>
+ UIApplication.SharedApplication.StatusBarOrientation switch
{
- case UIInterfaceOrientation.Portrait:
- return DisplayRotation.Rotation0;
- case UIInterfaceOrientation.PortraitUpsideDown:
- return DisplayRotation.Rotation180;
- case UIInterfaceOrientation.LandscapeLeft:
- return DisplayRotation.Rotation270;
- case UIInterfaceOrientation.LandscapeRight:
- return DisplayRotation.Rotation90;
- }
-
- return DisplayRotation.Unknown;
- }
+ UIInterfaceOrientation.Portrait => DisplayRotation.Rotation0,
+ UIInterfaceOrientation.PortraitUpsideDown => DisplayRotation.Rotation180,
+ UIInterfaceOrientation.LandscapeLeft => DisplayRotation.Rotation270,
+ UIInterfaceOrientation.LandscapeRight => DisplayRotation.Rotation90,
+ _ => DisplayRotation.Unknown,
+ };
}
}
diff --git a/src/Essentials/src/DeviceDisplay/DeviceDisplay.macos.cs b/src/Essentials/src/DeviceDisplay/DeviceDisplay.macos.cs
index 6d75cafab30b..9fc518b0563e 100644
--- a/src/Essentials/src/DeviceDisplay/DeviceDisplay.macos.cs
+++ b/src/Essentials/src/DeviceDisplay/DeviceDisplay.macos.cs
@@ -6,38 +6,30 @@
namespace Microsoft.Maui.Devices
{
- public class DeviceDisplayImplementation : IDeviceDisplay
+ class DeviceDisplayImplementation : IDeviceDisplay
{
uint keepScreenOnId = 0;
NSObject? screenMetricsObserver;
- public event EventHandler? MainDisplayInfoChanged;
+ protected override bool GetKeepScreenOn() => keepScreenOnId != 0;
- public bool KeepScreenOn
+ protected override void SetKeepScreenOn(bool keepScreenOn)
{
- get
+ if (KeepScreenOn == value)
+ return;
+
+ if (keepScreenOn)
{
- return keepScreenOnId != 0;
+ IOKit.PreventUserIdleDisplaySleep("KeepScreenOn", out keepScreenOnId);
}
-
- set
+ else
{
- if (KeepScreenOn == value)
- return;
-
- if (value)
- {
- IOKit.PreventUserIdleDisplaySleep("KeepScreenOn", out keepScreenOnId);
- }
- else
- {
- if (IOKit.AllowUserIdleDisplaySleep(keepScreenOnId))
- keepScreenOnId = 0;
- }
+ if (IOKit.AllowUserIdleDisplaySleep(keepScreenOnId))
+ keepScreenOnId = 0;
}
}
- public DisplayInfo GetMainDisplayInfo()
+ protected override DisplayInfo GetMainDisplayInfo()
{
var mainScreen = NSScreen.MainScreen;
var frame = mainScreen.Frame;
@@ -61,23 +53,19 @@ public DisplayInfo GetMainDisplayInfo()
rate: (float)refreshRate);
}
- public void StartScreenMetricsListeners()
+ protected override void StartScreenMetricsListeners()
{
- if (screenMetricsObserver == null)
- {
- screenMetricsObserver = NSNotificationCenter.DefaultCenter.AddObserver(NSApplication.DidChangeScreenParametersNotification, OnDidChangeScreenParameters);
- }
+ screenMetricsObserver ??= NSNotificationCenter.DefaultCenter.AddObserver(
+ NSApplication.DidChangeScreenParametersNotification, OnDidChangeScreenParameters);
}
- public void StopScreenMetricsListeners()
+ protected override void StopScreenMetricsListeners()
{
screenMetricsObserver?.Dispose();
+ screenMetricsObserver = null;
}
- public void OnDidChangeScreenParameters(NSNotification notification)
- {
- var metrics = GetMainDisplayInfo();
- MainDisplayInfoChanged?.Invoke(this, new DisplayInfoChangedEventArgs(metrics));
- }
+ void OnDidChangeScreenParameters(NSNotification notification) =>
+ OnMainDisplayInfoChanged();
}
}
diff --git a/src/Essentials/src/DeviceDisplay/DeviceDisplay.netstandard.tvos.watchos.cs b/src/Essentials/src/DeviceDisplay/DeviceDisplay.netstandard.tvos.watchos.cs
index 57cf43b32e7b..9c3c2fbe7cf3 100644
--- a/src/Essentials/src/DeviceDisplay/DeviceDisplay.netstandard.tvos.watchos.cs
+++ b/src/Essentials/src/DeviceDisplay/DeviceDisplay.netstandard.tvos.watchos.cs
@@ -1,22 +1,17 @@
#nullable enable
-using System;
namespace Microsoft.Maui.Devices
{
- public class DeviceDisplayImplementation : IDeviceDisplay
+ partial class DeviceDisplayImplementation
{
- public event EventHandler? MainDisplayInfoChanged
- {
- add { }
- remove { }
- }
+ protected override bool GetKeepScreenOn() => false;
- public bool KeepScreenOn { get => false; set { } }
+ protected override void SetKeepScreenOn(bool keepScreenOn) { }
- public DisplayInfo GetMainDisplayInfo() => default;
+ protected override DisplayInfo GetMainDisplayInfo() => default;
- public void StartScreenMetricsListeners() { }
+ protected override void StartScreenMetricsListeners() { }
- public void StopScreenMetricsListeners() { }
+ protected override void StopScreenMetricsListeners() { }
}
}
diff --git a/src/Essentials/src/DeviceDisplay/DeviceDisplay.shared.cs b/src/Essentials/src/DeviceDisplay/DeviceDisplay.shared.cs
index ca110ad0b3fd..30b104457c79 100644
--- a/src/Essentials/src/DeviceDisplay/DeviceDisplay.shared.cs
+++ b/src/Essentials/src/DeviceDisplay/DeviceDisplay.shared.cs
@@ -1,147 +1,133 @@
#nullable enable
using System;
-using System.ComponentModel;
namespace Microsoft.Maui.Devices
{
- ///
- public static partial class DeviceDisplay
+ public interface IDeviceDisplay
{
-#if WINDOWS
- internal const float BaseLogicalDpi = 96.0f;
-#elif ANDROID
- internal const float BaseLogicalDpi = 160.0f;
-#endif
+ bool KeepScreenOn { get; set; }
+
+ DisplayInfo MainDisplayInfo { get; }
+
+ event EventHandler MainDisplayInfoChanged;
+ }
+
+ ///
+ public class DisplayInfoChangedEventArgs : EventArgs
+ {
+ ///
+ public DisplayInfoChangedEventArgs(DisplayInfo displayInfo) =>
+ DisplayInfo = displayInfo;
- static readonly object locker = new object();
- static IDeviceDisplay currentImplementation;
+ ///
+ public DisplayInfo DisplayInfo { get; }
+ }
- static DeviceDisplay()
+ ///
+ public static class DeviceDisplay
+ {
+ ///
+ public static bool KeepScreenOn
{
- currentImplementation = new DeviceDisplayImplementation();
- currentImplementation.MainDisplayInfoChanged += OnMainDisplayInfoChanged;
+ get => Current.KeepScreenOn;
+ set => Current.KeepScreenOn = value;
}
- ///
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static IDeviceDisplay Current => currentImplementation;
+ ///
+ public static DisplayInfo MainDisplayInfo => Current.MainDisplayInfo;
- ///
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static void SetCurrent(IDeviceDisplay? implementation)
+ ///
+ public static event EventHandler MainDisplayInfoChanged
{
- lock (locker)
- {
- if (currentImplementation == implementation)
- return;
+ add => Current.MainDisplayInfoChanged += value;
+ remove => Current.MainDisplayInfoChanged -= value;
+ }
- var newImplementation = implementation ?? new DeviceDisplayImplementation();
+#if WINDOWS
+ internal const float BaseLogicalDpi = 96.0f;
+#elif ANDROID
+ internal const float BaseLogicalDpi = 160.0f;
+#endif
- var oldImplementation = currentImplementation;
- currentImplementation = newImplementation;
+ static IDeviceDisplay? currentImplementation;
- if (oldImplementation is not null)
- {
- oldImplementation.MainDisplayInfoChanged -= OnMainDisplayInfoChanged;
-
- var wasAlwaysOn = oldImplementation.KeepScreenOn;
- if (wasAlwaysOn)
- {
- oldImplementation.KeepScreenOn = false;
- newImplementation.KeepScreenOn = true;
- }
-
- var wasRunning = MainDisplayInfoChangedInternal != null;
- if (wasRunning)
- {
- oldImplementation.StopScreenMetricsListeners();
- newImplementation.StartScreenMetricsListeners();
- }
- }
+ public static IDeviceDisplay Current =>
+ currentImplementation ??= new DeviceDisplayImplementation();
- newImplementation.MainDisplayInfoChanged += OnMainDisplayInfoChanged;
+ ///
+ internal static void SetCurrent(IDeviceDisplay? implementation) =>
+ currentImplementation = implementation;
+ }
- SetCurrent(newImplementation.GetMainDisplayInfo());
- }
- }
+ sealed partial class DeviceDisplayImplementation : DeviceDisplayImplementationBase
+ {
+ }
- static event EventHandler? MainDisplayInfoChangedInternal;
+ abstract class DeviceDisplayImplementationBase : IDeviceDisplay
+ {
+ event EventHandler? MainDisplayInfoChangedInternal;
- static DisplayInfo currentMetrics;
+ DisplayInfo _currentMetrics;
- ///
- public static bool KeepScreenOn
+ public DisplayInfo MainDisplayInfo => GetMainDisplayInfo();
+
+ public bool KeepScreenOn
{
- get => Current.KeepScreenOn;
- set => Current.KeepScreenOn = value;
+ get => GetKeepScreenOn();
+ set => SetKeepScreenOn(value);
}
- ///
- public static DisplayInfo MainDisplayInfo => Current.GetMainDisplayInfo();
-
- static void SetCurrent(DisplayInfo metrics) =>
- currentMetrics = new DisplayInfo(metrics.Width, metrics.Height, metrics.Density, metrics.Orientation, metrics.Rotation, metrics.RefreshRate);
-
- public static event EventHandler MainDisplayInfoChanged
+ public event EventHandler MainDisplayInfoChanged
{
add
{
- var wasRunning = MainDisplayInfoChangedInternal != null;
-
- MainDisplayInfoChangedInternal += value;
-
- if (!wasRunning && MainDisplayInfoChangedInternal != null)
+ if (MainDisplayInfoChangedInternal is null)
{
- SetCurrent(Current.GetMainDisplayInfo());
- Current.StartScreenMetricsListeners();
+ SetCurrent(MainDisplayInfo);
+ StartScreenMetricsListeners();
}
+ MainDisplayInfoChangedInternal += value;
}
-
remove
{
- var wasRunning = MainDisplayInfoChangedInternal != null;
-
+ var wasStopped = MainDisplayInfoChangedInternal is null;
MainDisplayInfoChangedInternal -= value;
-
- if (wasRunning && MainDisplayInfoChangedInternal == null)
- Current.StopScreenMetricsListeners();
+ if (!wasStopped && MainDisplayInfoChangedInternal is null)
+ StopScreenMetricsListeners();
}
}
- static void OnMainDisplayInfoChanged(object? sender, DisplayInfoChangedEventArgs e) =>
- OnMainDisplayInfoChanged(e);
+ void SetCurrent(DisplayInfo metrics) =>
+ _currentMetrics = new DisplayInfo(
+ metrics.Width, metrics.Height,
+ metrics.Density,
+ metrics.Orientation,
+ metrics.Rotation,
+ metrics.RefreshRate);
- static void OnMainDisplayInfoChanged(DisplayInfoChangedEventArgs e)
+ protected void OnMainDisplayInfoChanged(DisplayInfoChangedEventArgs e)
{
- if (!currentMetrics.Equals(e.DisplayInfo))
+ if (!_currentMetrics.Equals(e.DisplayInfo))
{
SetCurrent(e.DisplayInfo);
MainDisplayInfoChangedInternal?.Invoke(null, e);
}
}
- }
-
- ///
- public class DisplayInfoChangedEventArgs : EventArgs
- {
- ///
- public DisplayInfoChangedEventArgs(DisplayInfo displayInfo) =>
- DisplayInfo = displayInfo;
- ///
- public DisplayInfo DisplayInfo { get; }
- }
+ protected void OnMainDisplayInfoChanged()
+ {
+ var metrics = GetMainDisplayInfo();
+ OnMainDisplayInfoChanged(new DisplayInfoChangedEventArgs(metrics));
+ }
- public interface IDeviceDisplay
- {
- bool KeepScreenOn { get; set; }
+ protected abstract DisplayInfo GetMainDisplayInfo();
- void StartScreenMetricsListeners();
+ protected abstract bool GetKeepScreenOn();
- void StopScreenMetricsListeners();
+ protected abstract void SetKeepScreenOn(bool keepScreenOn);
- DisplayInfo GetMainDisplayInfo();
+ protected abstract void StartScreenMetricsListeners();
- event EventHandler MainDisplayInfoChanged;
+ protected abstract void StopScreenMetricsListeners();
}
-}
+}
\ No newline at end of file
diff --git a/src/Essentials/src/DeviceDisplay/DeviceDisplay.tizen.cs b/src/Essentials/src/DeviceDisplay/DeviceDisplay.tizen.cs
index 1c332e8da51c..4dec01f1d577 100644
--- a/src/Essentials/src/DeviceDisplay/DeviceDisplay.tizen.cs
+++ b/src/Essentials/src/DeviceDisplay/DeviceDisplay.tizen.cs
@@ -4,7 +4,7 @@
namespace Microsoft.Maui.Devices
{
- public class DeviceDisplayImplementation : IDeviceDisplay
+ partial class DeviceDisplayImplementation
{
[DllImport("libcapi-system-device.so.0", EntryPoint = "device_power_request_lock")]
static extern void RequestKeepScreenOn(int type = 1, int timeout = 0);
@@ -14,22 +14,18 @@ public class DeviceDisplayImplementation : IDeviceDisplay
bool keepScreenOn = false;
- public event EventHandler? MainDisplayInfoChanged;
+ protected override bool GetKeepScreenOn() => keepScreenOn;
- public bool KeepScreenOn
+ protected override void SetKeepScreenOn(bool keepScreenOn)
{
- get => keepScreenOn;
- set
- {
- if (value)
- RequestKeepScreenOn();
- else
- ReleaseKeepScreenOn();
- keepScreenOn = value;
- }
+ if (keepScreenOn)
+ RequestKeepScreenOn();
+ else
+ ReleaseKeepScreenOn();
+ this.keepScreenOn = keepScreenOn;
}
- public DisplayInfo GetMainDisplayInfo()
+ protected override DisplayInfo GetMainDisplayInfo()
{
var display = Platform.MainWindow;
return new DisplayInfo(
@@ -64,20 +60,17 @@ static DisplayRotation GetRotation()
};
}
- public void StartScreenMetricsListeners()
+ protected override void StartScreenMetricsListeners()
{
Platform.MainWindow.RotationChanged += OnRotationChanged;
}
- public void StopScreenMetricsListeners()
+ protected override void StopScreenMetricsListeners()
{
Platform.MainWindow.RotationChanged -= OnRotationChanged;
}
- void OnRotationChanged(object s, EventArgs e)
- {
- var metrics = GetMainDisplayInfo();
- MainDisplayInfoChanged?.Invoke(this, new DisplayInfoChangedEventArgs(metrics));
- }
+ void OnRotationChanged(object s, EventArgs e) =>
+ OnMainDisplayInfoChanged();
}
}
diff --git a/src/Essentials/src/DeviceDisplay/DeviceDisplay.uwp.cs b/src/Essentials/src/DeviceDisplay/DeviceDisplay.uwp.cs
index 20d46d13732d..01e5c6b46623 100644
--- a/src/Essentials/src/DeviceDisplay/DeviceDisplay.uwp.cs
+++ b/src/Essentials/src/DeviceDisplay/DeviceDisplay.uwp.cs
@@ -3,48 +3,43 @@
using System.Runtime.InteropServices;
using Microsoft.Maui.ApplicationModel;
using Microsoft.UI.Windowing;
+using Microsoft.UI.Xaml;
using Windows.Graphics.Display;
-using Windows.Graphics.Display.Core;
using Windows.System.Display;
namespace Microsoft.Maui.Devices
{
- public class DeviceDisplayImplementation : IDeviceDisplay
+ partial class DeviceDisplayImplementation
{
readonly object locker = new object();
DisplayRequest? displayRequest;
- public event EventHandler? MainDisplayInfoChanged;
-
- public bool KeepScreenOn
+ protected override bool GetKeepScreenOn()
{
- get
+ lock (locker)
{
- lock (locker)
- {
- return displayRequest != null;
- }
+ return displayRequest != null;
}
+ }
- set
+ protected override void SetKeepScreenOn(bool keepScreenOn)
+ {
+ lock (locker)
{
- lock (locker)
+ if (keepScreenOn)
{
- if (value)
+ if (displayRequest == null)
{
- if (displayRequest == null)
- {
- displayRequest = new DisplayRequest();
- displayRequest.RequestActive();
- }
+ displayRequest = new DisplayRequest();
+ displayRequest.RequestActive();
}
- else
+ }
+ else
+ {
+ if (displayRequest != null)
{
- if (displayRequest != null)
- {
- displayRequest.RequestRelease();
- displayRequest = null;
- }
+ displayRequest.RequestRelease();
+ displayRequest = null;
}
}
}
@@ -84,17 +79,15 @@ static DisplayRotation CalculateRotation(DisplayOrientations native, DisplayOrie
return DisplayRotation.Unknown;
}
-#if WINDOWS
-
AppWindow? _currentAppWindowListeningTo;
- public DisplayInfo GetMainDisplayInfo()
+
+ protected override DisplayInfo GetMainDisplayInfo()
{
- if (Platform.CurrentWindow == null)
+ if (WindowStateManager.Default.GetActiveAppWindow(false) is not AppWindow appWindow)
return new DisplayInfo();
- var appWindow = Platform.CurrentAppWindow;
- var windowHandler = Platform.CurrentWindowHandle;
- var mi = GetDisplay(windowHandler);
+ var windowHandle = UI.Win32Interop.GetWindowFromWindowId(appWindow.Id);
+ var mi = GetDisplay(windowHandle);
if (mi == null)
return new DisplayInfo();
@@ -109,7 +102,7 @@ public DisplayInfo GetMainDisplayInfo()
var w = vDevMode.dmPelsWidth;
var h = vDevMode.dmPelsHeight;
- var dpi = GetDpiForWindow(windowHandler) / DeviceDisplay.BaseLogicalDpi;
+ var dpi = GetDpiForWindow(windowHandle) / DeviceDisplay.BaseLogicalDpi;
return new DisplayInfo(
width: perpendicular ? h : w,
@@ -137,27 +130,24 @@ public DisplayInfo GetMainDisplayInfo()
return null;
}
- public void StartScreenMetricsListeners()
+ protected override void StartScreenMetricsListeners()
{
MainThread.BeginInvokeOnMainThread(() =>
{
- Platform.CurrentWindowDisplayChanged += OnWindowDisplayChanged;
- Platform.CurrentWindowChanged += OnCurrentWindowChanged;
+ WindowStateManager.Default.ActiveWindowDisplayChanged += OnWindowDisplayChanged;
+ WindowStateManager.Default.ActiveWindowChanged += OnCurrentWindowChanged;
- if (Platform.CurrentWindow != null)
- {
- _currentAppWindowListeningTo = Platform.CurrentAppWindow;
- _currentAppWindowListeningTo.Changed += OnAppWindowChanged;
- }
+ _currentAppWindowListeningTo = WindowStateManager.Default.GetActiveAppWindow(true)!;
+ _currentAppWindowListeningTo.Changed += OnAppWindowChanged;
});
}
- public void StopScreenMetricsListeners()
+ protected override void StopScreenMetricsListeners()
{
MainThread.BeginInvokeOnMainThread(() =>
{
- Platform.CurrentWindowChanged -= OnCurrentWindowChanged;
- Platform.CurrentWindowDisplayChanged -= OnWindowDisplayChanged;
+ WindowStateManager.Default.ActiveWindowChanged -= OnCurrentWindowChanged;
+ WindowStateManager.Default.ActiveWindowDisplayChanged -= OnWindowDisplayChanged;
if (_currentAppWindowListeningTo != null)
_currentAppWindowListeningTo.Changed -= OnAppWindowChanged;
@@ -169,27 +159,17 @@ public void StopScreenMetricsListeners()
void OnCurrentWindowChanged(object? sender, EventArgs e)
{
if (_currentAppWindowListeningTo != null)
- {
_currentAppWindowListeningTo.Changed -= OnAppWindowChanged;
- }
- _currentAppWindowListeningTo = Platform.CurrentAppWindow;
+ _currentAppWindowListeningTo = WindowStateManager.Default.GetActiveAppWindow(true)!;
_currentAppWindowListeningTo.Changed += OnAppWindowChanged;
}
- void OnWindowDisplayChanged(object? sender, EventArgs e)
- {
- WindowDisplayPropertiesChanged();
- }
-
- void WindowDisplayPropertiesChanged()
- {
- var metrics = GetMainDisplayInfo();
- MainDisplayInfoChanged?.Invoke(this, new DisplayInfoChangedEventArgs(metrics));
- }
+ void OnWindowDisplayChanged(object? sender, EventArgs e) =>
+ OnMainDisplayInfoChanged();
void OnAppWindowChanged(AppWindow sender, AppWindowChangedEventArgs args) =>
- WindowDisplayPropertiesChanged();
+ OnMainDisplayInfoChanged();
static DisplayRotation CalculateRotation(DEVMODE devMode, AppWindow appWindow)
{
@@ -339,85 +319,5 @@ struct DEVMODE
public int dmPanningWidth;
public int dmPanningHeight;
}
-#elif WINDOWS_UWP
- public DisplayInfo GetMainDisplayInfo() =>
- GetMainDisplayInfo(null);
-
- DisplayInfo GetMainDisplayInfo(DisplayInformation? di = null)
- {
- di ??= DisplayInformation.GetForCurrentView();
-
- var rotation = CalculateRotation(di);
- var perpendicular =
- rotation == DisplayRotation.Rotation90 ||
- rotation == DisplayRotation.Rotation270;
-
- var w = di.ScreenWidthInRawPixels;
- var h = di.ScreenHeightInRawPixels;
-
- var hdi = HdmiDisplayInformation.GetForCurrentView();
- var hdm = hdi?.GetCurrentDisplayMode();
-
- return new DisplayInfo(
- width: perpendicular ? h : w,
- height: perpendicular ? w : h,
- density: di.LogicalDpi / DeviceDisplay.BaseLogicalDpi,
- orientation: CalculateOrientation(di),
- rotation: rotation,
- rate: (float)(hdm?.RefreshRate ?? 0));
- }
-
- public void StartScreenMetricsListeners()
- {
- MainThread.BeginInvokeOnMainThread(() =>
- {
- var di = DisplayInformation.GetForCurrentView();
-
- di.DpiChanged += OnDisplayInformationChanged;
- di.OrientationChanged += OnDisplayInformationChanged;
- });
- }
-
- public void StopScreenMetricsListeners()
- {
- MainThread.BeginInvokeOnMainThread(() =>
- {
- var di = DisplayInformation.GetForCurrentView();
-
- di.DpiChanged -= OnDisplayInformationChanged;
- di.OrientationChanged -= OnDisplayInformationChanged;
- });
- }
-
- void OnDisplayInformationChanged(DisplayInformation di, object args)
- {
- var metrics = GetMainDisplayInfo(di);
- MainDisplayInfoChanged?.Invoke(this, new DisplayInfoChangedEventArgs(metrics));
- }
-
- DisplayOrientation CalculateOrientation(DisplayInformation di)
- {
- switch (di.CurrentOrientation)
- {
- case DisplayOrientations.Landscape:
- case DisplayOrientations.LandscapeFlipped:
- return DisplayOrientation.Landscape;
- case DisplayOrientations.Portrait:
- case DisplayOrientations.PortraitFlipped:
- return DisplayOrientation.Portrait;
- }
-
- return DisplayOrientation.Unknown;
- }
-
- static DisplayRotation CalculateRotation(DisplayInformation di)
- {
- var native = di.NativeOrientation;
- var current = di.CurrentOrientation;
-
- return CalculateRotation(native, current);
- }
- }
-#endif
}
}
diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.android.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.android.cs
index 32d507028a90..95b4756bde01 100644
--- a/src/Essentials/src/DeviceInfo/DeviceInfo.android.cs
+++ b/src/Essentials/src/DeviceInfo/DeviceInfo.android.cs
@@ -7,7 +7,7 @@
namespace Microsoft.Maui.Devices
{
- public class DeviceInfoImplementation : IDeviceInfo
+ class DeviceInfoImplementation : IDeviceInfo
{
const int tabletCrossover = 600;
@@ -41,7 +41,7 @@ public DeviceIdiom Idiom
var currentIdiom = DeviceIdiom.Unknown;
// first try UIModeManager
- using var uiModeManager = UiModeManager.FromContext(ApplicationModel.Platform.AppContext);
+ using var uiModeManager = UiModeManager.FromContext(Application.Context);
try
{
@@ -56,7 +56,7 @@ public DeviceIdiom Idiom
// then try Configuration
if (currentIdiom == DeviceIdiom.Unknown)
{
- var configuration = ApplicationModel.Platform.AppContext.Resources?.Configuration;
+ var configuration = Application.Context.Resources?.Configuration;
if (configuration != null)
{
var minWidth = configuration.SmallestScreenWidthDp;
@@ -66,7 +66,7 @@ public DeviceIdiom Idiom
else
{
// start clutching at straws
- using var metrics = ApplicationModel.Platform.AppContext.Resources?.DisplayMetrics;
+ using var metrics = Application.Context.Resources?.DisplayMetrics;
if (metrics != null)
{
var minSize = Math.Min(metrics.WidthPixels, metrics.HeightPixels);
@@ -127,10 +127,10 @@ public DeviceType DeviceType
static string GetSystemSetting(string name, bool isGlobal = false)
{
- if (isGlobal && ApplicationModel.Platform.HasApiLevelNMr1)
- return Settings.Global.GetString(ApplicationModel.Platform.AppContext.ContentResolver, name);
+ if (isGlobal && OperatingSystem.IsAndroidVersionAtLeast(25))
+ return Settings.Global.GetString(Application.Context.ContentResolver, name);
else
- return Settings.System.GetString(ApplicationModel.Platform.AppContext.ContentResolver, name);
+ return Settings.System.GetString(Application.Context.ContentResolver, name);
}
}
}
diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.ios.tvos.watchos.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.ios.tvos.watchos.cs
index f5e3bf1e8041..69b653ee6bef 100644
--- a/src/Essentials/src/DeviceInfo/DeviceInfo.ios.tvos.watchos.cs
+++ b/src/Essentials/src/DeviceInfo/DeviceInfo.ios.tvos.watchos.cs
@@ -12,7 +12,7 @@
namespace Microsoft.Maui.Devices
{
- public class DeviceInfoImplementation : IDeviceInfo
+ class DeviceInfoImplementation : IDeviceInfo
{
public string Model
{
@@ -20,7 +20,7 @@ public string Model
{
try
{
- return ApplicationModel.Platform.GetSystemLibraryProperty("hw.machine");
+ return PlatformUtils.GetSystemLibraryProperty("hw.machine");
}
catch (Exception)
{
diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.macos.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.macos.cs
index 29b6beeab6c0..c1378060a7c6 100644
--- a/src/Essentials/src/DeviceInfo/DeviceInfo.macos.cs
+++ b/src/Essentials/src/DeviceInfo/DeviceInfo.macos.cs
@@ -5,7 +5,7 @@
namespace Microsoft.Maui.Devices
{
- public class DeviceInfoImplementation : IDeviceInfo
+ class DeviceInfoImplementation : IDeviceInfo
{
[DllImport(Constants.SystemConfigurationLibrary)]
static extern IntPtr SCDynamicStoreCopyComputerName(IntPtr store, IntPtr encoding);
diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.netstandard.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.netstandard.cs
index 07e46a53c62a..0d0828a016aa 100644
--- a/src/Essentials/src/DeviceInfo/DeviceInfo.netstandard.cs
+++ b/src/Essentials/src/DeviceInfo/DeviceInfo.netstandard.cs
@@ -3,7 +3,7 @@
namespace Microsoft.Maui.Devices
{
- public class DeviceInfoImplementation : IDeviceInfo
+ class DeviceInfoImplementation : IDeviceInfo
{
public string Model => throw ExceptionUtils.NotSupportedOrImplementedException;
diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.shared.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.shared.cs
index 7b1cc3241c9d..0784e7e2ef16 100644
--- a/src/Essentials/src/DeviceInfo/DeviceInfo.shared.cs
+++ b/src/Essentials/src/DeviceInfo/DeviceInfo.shared.cs
@@ -1,23 +1,41 @@
#nullable enable
using System;
-using System.ComponentModel;
namespace Microsoft.Maui.Devices
{
- ///
- public static class DeviceInfo
+ ///
+ public enum DeviceType
{
- static IDeviceInfo? currentImplementation;
+ ///
+ Unknown = 0,
+ ///
+ Physical = 1,
+ ///
+ Virtual = 2
+ }
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static IDeviceInfo Current =>
- currentImplementation ??= new DeviceInfoImplementation();
+ public interface IDeviceInfo
+ {
+ string Model { get; }
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static void SetCurrent(IDeviceInfo? implementation) =>
- currentImplementation = implementation;
+ string Manufacturer { get; }
+
+ string Name { get; }
+
+ string VersionString { get; }
+
+ Version Version { get; }
+ DevicePlatform Platform { get; }
+
+ DeviceIdiom Idiom { get; }
+
+ DeviceType DeviceType { get; }
+ }
+ ///
+ public static class DeviceInfo
+ {
///
public static string Model => Current.Model;
@@ -41,35 +59,13 @@ public static void SetCurrent(IDeviceInfo? implementation) =>
///
public static DeviceType DeviceType => Current.DeviceType;
- }
-
- ///
- public enum DeviceType
- {
- ///
- Unknown = 0,
- ///
- Physical = 1,
- ///
- Virtual = 2
- }
-
- public interface IDeviceInfo
- {
- string Model { get; }
-
- string Manufacturer { get; }
-
- string Name { get; }
-
- string VersionString { get; }
-
- Version Version { get; }
- DevicePlatform Platform { get; }
+ static IDeviceInfo? currentImplementation;
- DeviceIdiom Idiom { get; }
+ public static IDeviceInfo Current =>
+ currentImplementation ??= new DeviceInfoImplementation();
- DeviceType DeviceType { get; }
+ internal static void SetCurrent(IDeviceInfo? implementation) =>
+ currentImplementation = implementation;
}
}
diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.tizen.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.tizen.cs
index 5ea08556b915..79e9e8eb8df9 100644
--- a/src/Essentials/src/DeviceInfo/DeviceInfo.tizen.cs
+++ b/src/Essentials/src/DeviceInfo/DeviceInfo.tizen.cs
@@ -1,20 +1,18 @@
-using Plat = Microsoft.Maui.Essentials.Platform;
-
namespace Microsoft.Maui.Devices
{
- public class DeviceInfoImplementation : IDeviceInfo
+ class DeviceInfoImplementation : IDeviceInfo
{
public string Model
- => Plat.GetSystemInfo("model_name");
+ => Platform.GetSystemInfo("model_name");
public string Manufacturer
- => Plat.GetSystemInfo("manufacturer");
+ => Platform.GetSystemInfo("manufacturer");
public string Name
- => Plat.GetSystemInfo("device_name");
+ => Platform.GetSystemInfo("device_name");
public string VersionString
- => Plat.GetFeatureInfo("platform.version");
+ => Platform.GetFeatureInfo("platform.version");
public Version Version => Utils.ParseVersion(VersionString);
@@ -45,9 +43,9 @@ public DeviceType DeviceType
{
get
{
- var arch = Plat.GetFeatureInfo("platform.core.cpu.arch");
- var armv7 = Plat.GetFeatureInfo("platform.core.cpu.arch.armv7");
- var x86 = Plat.GetFeatureInfo("platform.core.cpu.arch.x86");
+ var arch = Platform.GetFeatureInfo("platform.core.cpu.arch");
+ var armv7 = Platform.GetFeatureInfo("platform.core.cpu.arch.armv7");
+ var x86 = Platform.GetFeatureInfo("platform.core.cpu.arch.x86");
if (arch != null && arch.Equals("armv7") && armv7 && !x86)
return DeviceType.Physical;
diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs
index d10105359f5d..317223b6052b 100644
--- a/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs
+++ b/src/Essentials/src/DeviceInfo/DeviceInfo.uwp.cs
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using Microsoft.Maui.ApplicationModel;
using Windows.Security.ExchangeActiveSyncProvisioning;
using Windows.System.Profile;
@@ -7,7 +8,7 @@
namespace Microsoft.Maui.Devices
{
- public class DeviceInfoImplementation : IDeviceInfo
+ class DeviceInfoImplementation : IDeviceInfo
{
readonly EasClientDeviceInformation deviceInfo;
DeviceIdiom currentIdiom;
@@ -68,19 +69,9 @@ public DeviceIdiom Idiom
break;
case "Windows.Universal":
case "Windows.Desktop":
- {
- try
- {
- var currentHandle = ApplicationModel.Platform.CurrentWindowHandle;
- var settings = UIViewSettingsInterop.GetForWindow(currentHandle);
- var uiMode = settings.UserInteractionMode;
- currentIdiom = uiMode == UserInteractionMode.Mouse ? DeviceIdiom.Desktop : DeviceIdiom.Tablet;
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"Unable to get device . {ex.Message}");
- }
- }
+ currentIdiom = GetIsInTabletMode()
+ ? DeviceIdiom.Tablet
+ : DeviceIdiom.Desktop;
break;
case "Windows.Xbox":
case "Windows.Team":
@@ -119,5 +110,18 @@ public DeviceType DeviceType
return currentType;
}
}
+
+ static readonly int SM_CONVERTIBLESLATEMODE = 0x2003;
+ static readonly int SM_TABLETPC = 0x56;
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ static extern int GetSystemMetrics(int nIndex);
+
+ static bool GetIsInTabletMode()
+ {
+ var supportsTablet = GetSystemMetrics(SM_TABLETPC) != 0;
+ var inTabletMode = GetSystemMetrics(SM_CONVERTIBLESLATEMODE) != 0;
+ return inTabletMode && supportsTablet;
+ }
}
}
diff --git a/src/Essentials/src/Email/Email.android.cs b/src/Essentials/src/Email/Email.android.cs
index 2a64e1662489..7d1be6283d35 100644
--- a/src/Essentials/src/Email/Email.android.cs
+++ b/src/Essentials/src/Email/Email.android.cs
@@ -1,51 +1,38 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
+using Android.App;
using Android.Content;
using Android.OS;
using Android.Text;
-using Android.Webkit;
using Microsoft.Maui.Storage;
using Uri = Android.Net.Uri;
namespace Microsoft.Maui.ApplicationModel.Communication
{
- public partial class EmailImplementation : IEmail
+ partial class EmailImplementation : IEmail
{
static EmailMessage testEmail =>
- new ("Testing Microsoft.Maui.Essentials", "This is a test email.", "Microsoft.Maui.Essentials@example.org");
+ new("Testing Microsoft.Maui.Essentials", "This is a test email.", "Microsoft.Maui.Essentials@example.org");
public bool IsComposeSupported
- => Platform.IsIntentSupported(CreateIntent(testEmail));
+ => PlatformUtils.IsIntentSupported(CreateIntent(testEmail));
- public Task ComposeAsync(EmailMessage message)
+ Task PlatformComposeAsync(EmailMessage message)
{
var intent = CreateIntent(message);
var flags = ActivityFlags.ClearTop | ActivityFlags.NewTask;
#if __ANDROID_24__
- if (Platform.HasApiLevelN)
+ if (OperatingSystem.IsAndroidVersionAtLeast(24))
flags |= ActivityFlags.LaunchAdjacent;
#endif
intent.SetFlags(flags);
- Platform.AppContext.StartActivity(intent);
+ Application.Context.StartActivity(intent);
return Task.FromResult(true);
}
- public Task ComposeAsync(string subject, string body, params string[] to)
- => ComposeAsync(
- new EmailMessage()
- {
- Subject = subject,
- Body = body,
- To = to.ToList()
- });
-
- public Task ComposeAsync()
- => ComposeAsync(null);
-
static Intent CreateIntent(EmailMessage message)
{
var action = (message?.Attachments?.Count ?? 0) switch
@@ -59,7 +46,7 @@ static Intent CreateIntent(EmailMessage message)
if (action == Intent.ActionSendto)
intent.SetData(Uri.Parse("mailto:"));
else
- intent.SetType(FileSystem.MimeTypes.EmailMessage);
+ intent.SetType(FileMimeTypes.EmailMessage);
if (!string.IsNullOrEmpty(message?.Body))
{
@@ -67,7 +54,7 @@ static Intent CreateIntent(EmailMessage message)
{
ISpanned html;
#if __ANDROID_24__
- if (Platform.HasApiLevelN)
+ if (OperatingSystem.IsAndroidVersionAtLeast(24))
{
html = Html.FromHtml(message.Body, FromHtmlOptions.ModeLegacy);
}
@@ -99,7 +86,7 @@ static Intent CreateIntent(EmailMessage message)
var uris = new List();
foreach (var attachment in message.Attachments)
{
- uris.Add(Platform.GetShareableFileUri(attachment));
+ uris.Add(FileSystemUtils.GetShareableFileUri(attachment));
}
if (uris.Count > 1)
diff --git a/src/Essentials/src/Email/Email.ios.cs b/src/Essentials/src/Email/Email.ios.cs
index 2f228c52d70a..0bf45338c2d7 100644
--- a/src/Essentials/src/Email/Email.ios.cs
+++ b/src/Essentials/src/Email/Email.ios.cs
@@ -1,26 +1,24 @@
using System.IO;
using System.Threading.Tasks;
-using System.Linq;
using Foundation;
+using UIKit;
#if !(MACCATALYST || MACOS)
using MessageUI;
#endif
-using ObjCRuntime;
-using UIKit;
namespace Microsoft.Maui.ApplicationModel.Communication
{
- public partial class EmailImplementation : IEmail
+ partial class EmailImplementation : IEmail
{
public bool IsComposeSupported =>
#if !(MACCATALYST || MACOS)
MFMailComposeViewController.CanSendMail ||
- MainThread.InvokeOnMainThread(() => UIApplication.SharedApplication.CanOpenUrl(NSUrl.FromString("mailto:")));
+ MainThread.InvokeOnMainThread(() => UIApplication.SharedApplication.CanOpenUrl(NSUrl.FromString("mailto:")));
#else
false;
#endif
- public Task ComposeAsync(EmailMessage message)
+ Task PlatformComposeAsync(EmailMessage message)
{
#if !(MACCATALYST || MACOS)
if (MFMailComposeViewController.CanSendMail)
@@ -32,24 +30,11 @@ public Task ComposeAsync(EmailMessage message)
#endif
}
- public Task ComposeAsync(string subject, string body, params string[] to)
- => ComposeAsync(
- new EmailMessage()
- {
- Subject = subject,
- Body = body,
- To = to.ToList()
- });
-
- public Task ComposeAsync()
- => ComposeAsync(null);
-
-
- internal Task ComposeWithMailCompose(EmailMessage message)
+ Task ComposeWithMailCompose(EmailMessage message)
{
#if !(MACCATALYST || MACOS)
// do this first so we can throw as early as possible
- var parentController = Platform.GetCurrentViewController();
+ var parentController = WindowStateManager.Default.GetCurrentUIViewController(true);
// create the controller
var controller = new MFMailComposeViewController();
@@ -87,7 +72,7 @@ internal Task ComposeWithMailCompose(EmailMessage message)
if (controller.PresentationController != null)
{
controller.PresentationController.Delegate =
- new Platform.UIPresentationControllerDelegate(() => tcs.TrySetResult(false));
+ new UIPresentationControllerDelegate(() => tcs.TrySetResult(false));
}
parentController.PresentViewController(controller, true, null);
@@ -98,11 +83,11 @@ internal Task ComposeWithMailCompose(EmailMessage message)
#endif
}
- internal async Task ComposeWithUrl(EmailMessage message)
+ Task ComposeWithUrl(EmailMessage message)
{
- var url = Email.GetMailToUri(message);
+ var url = GetMailToUri(message);
var nsurl = NSUrl.FromString(url);
- await Launcher.OpenAsync(nsurl);
+ return Launcher.Default.OpenAsync(nsurl);
}
}
}
diff --git a/src/Essentials/src/Email/Email.macos.cs b/src/Essentials/src/Email/Email.macos.cs
index 45f371a26340..d87771b88082 100644
--- a/src/Essentials/src/Email/Email.macos.cs
+++ b/src/Essentials/src/Email/Email.macos.cs
@@ -4,12 +4,12 @@
namespace Microsoft.Maui.ApplicationModel.Communication
{
- public partial class EmailImplementation : IEmail
+ partial class EmailImplementation : IEmail
{
public bool IsComposeSupported =>
MainThread.InvokeOnMainThread(() => NSWorkspace.SharedWorkspace.UrlForApplication(NSUrl.FromString("mailto:")) != null);
- public Task ComposeAsync(EmailMessage message)
+ Task PlatformComposeAsync(EmailMessage message)
{
var url = GetMailToUri(message);
diff --git a/src/Essentials/src/Email/Email.netstandard.tvos.watchos.cs b/src/Essentials/src/Email/Email.netstandard.tvos.watchos.cs
index b117dc243722..4fe873391a93 100644
--- a/src/Essentials/src/Email/Email.netstandard.tvos.watchos.cs
+++ b/src/Essentials/src/Email/Email.netstandard.tvos.watchos.cs
@@ -3,27 +3,12 @@
namespace Microsoft.Maui.ApplicationModel.Communication
{
///
- public partial class EmailImplementation : IEmail
+ partial class EmailImplementation : IEmail
{
public bool IsComposeSupported =>
throw ExceptionUtils.NotSupportedOrImplementedException;
- public Task ComposeAsync(EmailMessage message) =>
- throw ExceptionUtils.NotSupportedOrImplementedException;
-
- public Task ComposeAsync(string subject, string body, params string[] to)
- => throw ExceptionUtils.NotSupportedOrImplementedException;
-
- public Task ComposeAsync() =>
- throw ExceptionUtils.NotSupportedOrImplementedException;
- }
-
-#if NETSTANDARD || NET6_0
- ///
- public partial class EmailAttachment
- {
- string PlatformGetContentType(string extension) =>
+ Task PlatformComposeAsync(EmailMessage message) =>
throw ExceptionUtils.NotSupportedOrImplementedException;
}
-#endif
}
diff --git a/src/Essentials/src/Email/Email.shared.cs b/src/Essentials/src/Email/Email.shared.cs
index 762346faeae1..e22454a24621 100644
--- a/src/Essentials/src/Email/Email.shared.cs
+++ b/src/Essentials/src/Email/Email.shared.cs
@@ -1,8 +1,8 @@
+#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-using System.ComponentModel;
using Microsoft.Maui.Storage;
namespace Microsoft.Maui.ApplicationModel.Communication
@@ -10,44 +10,39 @@ namespace Microsoft.Maui.ApplicationModel.Communication
public interface IEmail
{
bool IsComposeSupported { get; }
-
- Task ComposeAsync();
-
- Task ComposeAsync(string subject, string body, params string[] to);
- Task ComposeAsync(EmailMessage message);
+ Task ComposeAsync(EmailMessage? message);
}
- ///
- public static partial class Email
+ public static class EmailExtensions
{
- ///
- public static Task ComposeAsync()
- => ComposeAsync(null);
+ public static Task ComposeAsync(this IEmail email) =>
+ email.ComposeAsync(null);
- ///
- public static Task ComposeAsync(string subject, string body, params string[] to)
- => ComposeAsync(new EmailMessage(subject, body, to));
+ public static Task ComposeAsync(this IEmail email, string subject, string body, params string[] to) =>
+ email.ComposeAsync(new EmailMessage(subject, body, to));
+ }
- ///
- public static Task ComposeAsync(EmailMessage message)
+ partial class EmailImplementation : IEmail
+ {
+ public Task ComposeAsync(EmailMessage? message)
{
- if (!Current.IsComposeSupported)
+ if (!IsComposeSupported)
throw new FeatureNotSupportedException();
- return Current.ComposeAsync(message);
+ return PlatformComposeAsync(message);
}
- internal static string GetMailToUri(EmailMessage message)
+ static string GetMailToUri(EmailMessage message)
{
if (message != null && message.BodyFormat != EmailBodyFormat.PlainText)
throw new FeatureNotSupportedException("Only EmailBodyFormat.PlainText is supported if no email account is set up.");
var parts = new List();
if (!string.IsNullOrEmpty(message?.Body))
- parts.Add("body=" + Uri.EscapeDataString(message.Body));
+ parts.Add("body=" + Uri.EscapeDataString(message!.Body));
if (!string.IsNullOrEmpty(message?.Subject))
- parts.Add("subject=" + Uri.EscapeDataString(message.Subject));
+ parts.Add("subject=" + Uri.EscapeDataString(message!.Subject));
if (message?.Cc?.Count > 0)
parts.Add("cc=" + Uri.EscapeDataString(string.Join(",", message.Cc)));
if (message?.Bcc?.Count > 0)
@@ -63,20 +58,30 @@ internal static string GetMailToUri(EmailMessage message)
return uri;
}
+ }
-#nullable enable
- static IEmail? currentImplementation;
-#nullable disable
+ ///
+ public static class Email
+ {
+ ///
+ public static Task ComposeAsync() =>
+ Default.ComposeAsync();
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static IEmail Current =>
- currentImplementation ??= new EmailImplementation();
+ ///
+ public static Task ComposeAsync(string subject, string body, params string[] to) =>
+ Default.ComposeAsync(subject, body, to);
- [EditorBrowsable(EditorBrowsableState.Never)]
-#nullable enable
- public static void SetCurrent(IEmail? implementation) =>
- currentImplementation = implementation;
-#nullable disable
+ ///
+ public static Task ComposeAsync(EmailMessage message) =>
+ Default.ComposeAsync(message);
+
+ static IEmail? defaultImplementation;
+
+ public static IEmail Default =>
+ defaultImplementation ??= new EmailImplementation();
+
+ internal static void SetDefault(IEmail? implementation) =>
+ defaultImplementation = implementation;
}
///
@@ -96,25 +101,25 @@ public EmailMessage(string subject, string body, params string[] to)
}
///
- public string Subject { get; set; }
+ public string? Subject { get; set; }
///
- public string Body { get; set; }
+ public string? Body { get; set; }
///
public EmailBodyFormat BodyFormat { get; set; }
///
- public List To { get; set; } = new List();
+ public List? To { get; set; } = new List