diff --git a/src/Android/Avalonia.Android/AndroidDispatcherImpl.cs b/src/Android/Avalonia.Android/AndroidDispatcherImpl.cs index 8ee5f2a8f0..275916da52 100644 --- a/src/Android/Avalonia.Android/AndroidDispatcherImpl.cs +++ b/src/Android/Avalonia.Android/AndroidDispatcherImpl.cs @@ -37,7 +37,7 @@ namespace Avalonia.Android _wakeupSignaler = new Runnable(() => { }); _queue = Looper.MyQueue(); Looper.MyQueue().AddIdleHandler(new IdleHandler(this)); - CanQueryPendingInput = OperatingSystem.IsAndroidVersionAtLeast(23); + CanQueryPendingInput = Build.VERSION.SdkInt >= BuildVersionCodes.M; } public event Action? Timer; @@ -57,7 +57,7 @@ namespace Avalonia.Android { if (s_isUIThread.HasValue) return s_isUIThread.Value; - var uiThread = OperatingSystem.IsAndroidVersionAtLeast(23) + var uiThread = Build.VERSION.SdkInt >= BuildVersionCodes.M ? _mainLooper.IsCurrentThread : _mainLooper.Thread.Equals(Java.Lang.Thread.CurrentThread()); diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index 2fb849ee0d..c21cca2dd6 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/Android/Avalonia.Android/AvaloniaAccessHelper.cs b/src/Android/Avalonia.Android/AvaloniaAccessHelper.cs index 0b5a7e03c4..d3f38af0b8 100644 --- a/src/Android/Avalonia.Android/AvaloniaAccessHelper.cs +++ b/src/Android/Avalonia.Android/AvaloniaAccessHelper.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; -using Android.Content.PM; using Android.OS; using AndroidX.Core.View.Accessibility; using AndroidX.CustomView.Widget; @@ -13,6 +13,7 @@ using Java.Lang; namespace Avalonia.Android { + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] internal class AvaloniaAccessHelper : ExploreByTouchHelper { private const string AUTOMATION_PROVIDER_NAMESPACE = "Avalonia.Automation.Provider"; @@ -96,9 +97,11 @@ namespace Avalonia.Android } }; - Type peerType = peer.GetType(); - IEnumerable providerTypes = peerType.GetInterfaces() +#pragma warning disable IL2075 + IEnumerable providerTypes = peer.GetType().GetInterfaces() .Where(x => x.Namespace!.StartsWith(AUTOMATION_PROVIDER_NAMESPACE)); +#pragma warning restore IL2075 + foreach (Type providerType in providerTypes) { if (s_providerTypeInitializers.TryGetValue(providerType.FullName!, out NodeInfoProviderInitializer? ctor)) diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs index fa3484f058..261cc72bb4 100644 --- a/src/Android/Avalonia.Android/AvaloniaActivity.cs +++ b/src/Android/Avalonia.Android/AvaloniaActivity.cs @@ -131,7 +131,7 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity base.OnResume(); // Android only respects LayoutInDisplayCutoutMode value if it has been set once before window becomes visible. - if (OperatingSystem.IsAndroidVersionAtLeast(28) && Window is { Attributes: { } attributes }) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)28 && Window is { Attributes: { } attributes }) { attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges; } diff --git a/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs b/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs index 8a3685b65e..1ff6ea0db7 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs @@ -73,7 +73,7 @@ namespace Avalonia.Android.Platform _displaysEdgeToEdge = _displayEdgeToEdgePreference; - if (OperatingSystem.IsAndroidVersionAtLeast(28) && Window.Attributes is { } attributes) + if (Build.VERSION.SdkInt >= BuildVersionCodes.P && Window.Attributes is { } attributes) { attributes.LayoutInDisplayCutoutMode = _displayEdgeToEdgePreference ? LayoutInDisplayCutoutMode.ShortEdges : LayoutInDisplayCutoutMode.Default; } @@ -127,7 +127,7 @@ namespace Avalonia.Android.Platform WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars() | WindowInsetsCompat.Type.DisplayCutout() : 0); - return new Thickness(inset.Left / renderScaling, + return new Thickness(inset!.Left / renderScaling, inset.Top / renderScaling, inset.Right / renderScaling, inset.Bottom / renderScaling); @@ -145,9 +145,9 @@ namespace Avalonia.Android.Platform if (insets != null) { - var navbarInset = insets.GetInsets(WindowInsetsCompat.Type.NavigationBars()).Bottom; + var navbarInset = insets.GetInsets(WindowInsetsCompat.Type.NavigationBars())?.Bottom ?? 0; - var height = Math.Max((float)((insets.GetInsets(WindowInsetsCompat.Type.Ime()).Bottom - navbarInset) / _topLevel.RenderScaling), 0); + var height = Math.Max((float)((insets.GetInsets(WindowInsetsCompat.Type.Ime())!.Bottom - navbarInset) / _topLevel.RenderScaling), 0); return new Rect(0, _topLevel.ClientSize.Height - SafeAreaPadding.Bottom - height, _topLevel.ClientSize.Width, height); } @@ -156,7 +156,7 @@ namespace Avalonia.Android.Platform } } - public WindowInsetsCompat OnApplyWindowInsets(View v, WindowInsetsCompat insets) + public WindowInsetsCompat? OnApplyWindowInsets(View? v, WindowInsetsCompat? insets) { insets = ViewCompat.OnApplyWindowInsets(v, insets); NotifySafeAreaChanged(SafeAreaPadding); @@ -166,15 +166,15 @@ namespace Avalonia.Android.Platform _previousRect = OccludedRect; } - State = insets.IsVisible(WindowInsetsCompat.Type.Ime()) ? InputPaneState.Open : InputPaneState.Closed; + State = insets?.IsVisible(WindowInsetsCompat.Type.Ime()) == true ? InputPaneState.Open : InputPaneState.Closed; // Workaround for weird inset values for android 11 if(Build.VERSION.SdkInt == BuildVersionCodes.R) { - var imeInset = insets.GetInsets(WindowInsetsCompat.Type.Ime()); + var imeInset = insets!.GetInsets(WindowInsetsCompat.Type.Ime()); if(_previousImeInset == default) _previousImeInset = imeInset; - if(imeInset.Bottom != _previousImeInset.Bottom) + if(imeInset!.Bottom != _previousImeInset!.Bottom) { NotifyStateChanged(State, _previousRect, OccludedRect, TimeSpan.Zero, null); } @@ -285,7 +285,7 @@ namespace Avalonia.Android.Platform if (_isDisplayEdgeToEdgeForced) { // Allow having fully transparent navbars when on api level 35 - if (OperatingSystem.IsAndroidVersionAtLeast(35)) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)35) Window.NavigationBarContrastEnforced = _systemBarColor != Colors.Transparent; return; } @@ -319,18 +319,18 @@ namespace Avalonia.Android.Platform SystemBarColor = _systemBarColor; } - public override WindowInsetsAnimationCompat.BoundsCompat OnStart(WindowInsetsAnimationCompat animation, WindowInsetsAnimationCompat.BoundsCompat bounds) + public override WindowInsetsAnimationCompat.BoundsCompat? OnStart(WindowInsetsAnimationCompat? animation, WindowInsetsAnimationCompat.BoundsCompat? bounds) { - if ((animation.TypeMask & WindowInsetsCompat.Type.Ime()) != 0) + if ((animation!.TypeMask & WindowInsetsCompat.Type.Ime()) != 0) { var insets = ViewCompat.GetRootWindowInsets(Window.DecorView); if (insets != null) { - var navbarInset = insets.GetInsets(WindowInsetsCompat.Type.NavigationBars()).Bottom; - var height = Math.Max(0, (float)((bounds.LowerBound.Bottom - navbarInset) / _topLevel.RenderScaling)); + var navbarInset = insets.GetInsets(WindowInsetsCompat.Type.NavigationBars())!.Bottom; + var height = Math.Max(0, (float)((bounds!.LowerBound!.Bottom - navbarInset) / _topLevel.RenderScaling)); var upperRect = new Rect(0, _topLevel.ClientSize.Height - SafeAreaPadding.Bottom - height, _topLevel.ClientSize.Width, height); - height = Math.Max(0, (float)((bounds.UpperBound.Bottom - navbarInset) / _topLevel.RenderScaling)); + height = Math.Max(0, (float)((bounds.UpperBound!.Bottom - navbarInset) / _topLevel.RenderScaling)); var lowerRect = new Rect(0, _topLevel.ClientSize.Height - SafeAreaPadding.Bottom - height, _topLevel.ClientSize.Width, height); var duration = TimeSpan.FromMilliseconds(animation.DurationMillis); @@ -344,7 +344,7 @@ namespace Avalonia.Android.Platform return base.OnStart(animation, bounds); } - public override WindowInsetsCompat OnProgress(WindowInsetsCompat insets, IList runningAnimations) + public override WindowInsetsCompat? OnProgress(WindowInsetsCompat? insets, IList? runningAnimations) { return insets; } diff --git a/src/Android/Avalonia.Android/Platform/AndroidPlatformSettings.cs b/src/Android/Avalonia.Android/Platform/AndroidPlatformSettings.cs index 3963a88203..16888033be 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidPlatformSettings.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidPlatformSettings.cs @@ -1,6 +1,7 @@ using System; using Android.Content; using Android.Content.Res; +using Android.OS; using Android.Provider; using Avalonia.Platform; using Color = Avalonia.Media.Color; @@ -36,7 +37,7 @@ internal class AndroidPlatformSettings : DefaultPlatformSettings _ => throw new ArgumentOutOfRangeException() }; - if (OperatingSystem.IsAndroidVersionAtLeast(31)) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)31) { // See https://developer.android.com/reference/android/R.color var accent1 = context.Resources.GetColor(17170494, context.Theme); // Resource.Color.SystemAccent1500 @@ -52,7 +53,7 @@ internal class AndroidPlatformSettings : DefaultPlatformSettings AccentColor3 = new Color(accent3.A, accent3.R, accent3.G, accent3.B), }; } - else if (OperatingSystem.IsAndroidVersionAtLeast(23)) + else if (Build.VERSION.SdkInt >= (BuildVersionCodes)23) { // See https://developer.android.com/reference/android/R.attr var array = context.Theme?.ObtainStyledAttributes(new[] { 16843829 }); // Resource.Attribute.ColorAccent diff --git a/src/Android/Avalonia.Android/Platform/AndroidScreens.cs b/src/Android/Avalonia.Android/Platform/AndroidScreens.cs index 95d2530edc..082b66a69c 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidScreens.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidScreens.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using Android.Content; using Android.Hardware.Display; +using Android.OS; using Android.Runtime; using Android.Util; using Android.Views; @@ -23,7 +24,7 @@ internal class AndroidScreen(Display display) : PlatformScreen(new PlatformHandl var rotation = display.Rotation; IsPrimary = display.DisplayId == Display.DefaultDisplay; - if (OperatingSystem.IsAndroidVersionAtLeast(30)) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)30) { var metricsCalc = WindowMetricsCalculator.Companion.OrCreate; // a display context is guaranteed to be created for a display on API 30 and above, but we fallback to the app context if OEM messes up @@ -33,7 +34,7 @@ internal class AndroidScreen(Display display) : PlatformScreen(new PlatformHandl Bounds = new(metrics.Bounds.Left, metrics.Bounds.Top, metrics.Bounds.Width(), metrics.Bounds.Height()); var inset = metrics.WindowInsets.GetInsets(WindowInsetsCompat.Type.SystemBars()); - WorkingArea = new(Bounds.X + inset.Left, + WorkingArea = new(Bounds.X + inset!.Left, Bounds.Y + inset.Top, Bounds.Width - (inset.Left + inset.Right), Bounds.Height - (inset.Top + inset.Bottom)); @@ -103,7 +104,7 @@ internal sealed class AndroidScreens : ScreensBase, IDis return displays; } - if (OperatingSystem.IsAndroidVersionAtLeast(30) && _context.Display is { } defaultDisplay) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)30 && _context.Display is { } defaultDisplay) { return [defaultDisplay]; } diff --git a/src/Android/Avalonia.Android/Platform/PlatformSupport.cs b/src/Android/Avalonia.Android/Platform/PlatformSupport.cs index feff497f61..e1f1580d1b 100644 --- a/src/Android/Avalonia.Android/Platform/PlatformSupport.cs +++ b/src/Android/Avalonia.Android/Platform/PlatformSupport.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Android.App; using Android.Content.PM; +using Android.OS; namespace Avalonia.Android.Platform; @@ -19,7 +20,7 @@ internal static class PlatformSupport throw new InvalidOperationException("Main activity must implement IActivityResultHandler interface."); } - if (!OperatingSystem.IsAndroidVersionAtLeast(23)) + if (Build.VERSION.SdkInt < (BuildVersionCodes)23) { return true; } diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 26e1fe9ea0..23966a303f 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -4,6 +4,7 @@ using Android.App; using Android.Content; using Android.Graphics; using Android.Graphics.Drawables; +using Android.OS; using Android.Runtime; using Android.Text; using Android.Views; @@ -193,7 +194,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform // Workaround issue #9230 on where screen remains gray after splash screen. // base.DispatchDraw should punch a hole into the canvas so the surface // can be seen below, but it does not. - if (OperatingSystem.IsAndroidVersionAtLeast(29)) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)29) { // Android 10+ does this (BlendMode was new) var paint = new Paint(); @@ -327,7 +328,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform if (level == WindowTransparencyLevel.None) { - if (OperatingSystem.IsAndroidVersionAtLeast(30)) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)30) { activity.SetTranslucent(false); } @@ -336,7 +337,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform } else if (level == WindowTransparencyLevel.Transparent) { - if (OperatingSystem.IsAndroidVersionAtLeast(30)) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)30) { activity.SetTranslucent(true); SetBlurBehind(activity, 0); @@ -345,7 +346,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform } else if (level == WindowTransparencyLevel.Blur) { - if (OperatingSystem.IsAndroidVersionAtLeast(31)) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)31) { activity.SetTranslucent(true); SetBlurBehind(activity, 120); @@ -358,7 +359,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform } // If we get here, we didn't find a supported level. Use the default of None. - if (OperatingSystem.IsAndroidVersionAtLeast(30)) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)30) { activity.SetTranslucent(false); } @@ -416,9 +417,9 @@ namespace Avalonia.Android.Platform.SkiaPlatform if (level == WindowTransparencyLevel.None) return true; if (level == WindowTransparencyLevel.Transparent) - return OperatingSystem.IsAndroidVersionAtLeast(30); + return Build.VERSION.SdkInt >= (BuildVersionCodes)30; if (level == WindowTransparencyLevel.Blur) - return OperatingSystem.IsAndroidVersionAtLeast(31); + return Build.VERSION.SdkInt >= (BuildVersionCodes)31; return false; } @@ -429,7 +430,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform else activity.Window?.AddFlags(WindowManagerFlags.BlurBehind); - if (OperatingSystem.IsAndroidVersionAtLeast(31) && activity.Window?.Attributes is { } attr) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)31 && activity.Window?.Attributes is { } attr) { attr.BlurBehindRadius = radius; activity.Window.Attributes = attr; diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs index 58fc59f804..c6ae65ef28 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.Versioning; +using Android.OS; using Android.Views; using Avalonia.Android.Platform.Input; using Avalonia.Android.Platform.SkiaPlatform; @@ -43,7 +44,9 @@ namespace Avalonia.Android.Platform.Specific.Helpers private bool? DispatchKeyEventInternal(KeyEvent e, out bool callBase) { - var unicodeTextInput = OperatingSystem.IsAndroidVersionAtLeast(29) ? null : UnicodeTextInput(e); +#pragma warning disable CA1422 // Validate platform compatibility + var unicodeTextInput = Build.VERSION.SdkInt >= (BuildVersionCodes)29 ? null : UnicodeTextInput(e); +#pragma warning restore CA1422 // Validate platform compatibility var inputRoot = _view.InputRoot; if ((e.Action == KeyEventActions.Multiple && unicodeTextInput == null) diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs index 183604bbea..93ae778c88 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; - +using Android.OS; using Android.Views; using Avalonia.Android.Platform.SkiaPlatform; @@ -146,10 +146,12 @@ namespace Avalonia.Android.Platform.Specific.Helpers { modifiers |= RawInputModifiers.XButton2MouseButton; } - if (OperatingSystem.IsAndroidVersionAtLeast(23) && buttonState.HasAnyFlag(MotionEventButtonState.StylusPrimary)) +#pragma warning disable CA1416 // Validate platform compatibility + if (Build.VERSION.SdkInt >= (BuildVersionCodes)23 && buttonState.HasAnyFlag(MotionEventButtonState.StylusPrimary)) { modifiers |= RawInputModifiers.PenBarrelButton; } +#pragma warning restore CA1416 // Validate platform compatibility return modifiers; } diff --git a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs index cdbab13701..12094bd033 100644 --- a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs +++ b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Android; using Android.App; using Android.Content; +using Android.OS; using Android.Provider; using Android.Webkit; using Avalonia.Logging; @@ -411,7 +412,7 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF private bool IsVirtualFile(Context context, AndroidUri uri) { - if (!OperatingSystem.IsAndroidVersionAtLeast(24)) + if (Build.VERSION.SdkInt < (BuildVersionCodes)24) return false; if (!DocumentsContract.IsDocumentUri(context, uri)) @@ -540,7 +541,7 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF { AndroidUri? movedUri = null; - if (OperatingSystem.IsAndroidVersionAtLeast(24)) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)24) { try { diff --git a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs index 54d6afad43..480bca0530 100644 --- a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs +++ b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Android; using Android.App; using Android.Content; +using Android.OS; using Android.Provider; using Avalonia.Platform.Storage; using Avalonia.Platform.Storage.FileIO; @@ -25,11 +26,11 @@ internal class AndroidStorageProvider : IStorageProvider _activity = activity; } - public bool CanOpen => OperatingSystem.IsAndroidVersionAtLeast(19); + public bool CanOpen => Build.VERSION.SdkInt >= (BuildVersionCodes)19; - public bool CanSave => OperatingSystem.IsAndroidVersionAtLeast(19); + public bool CanSave => Build.VERSION.SdkInt >= (BuildVersionCodes)19; - public bool CanPickFolder => OperatingSystem.IsAndroidVersionAtLeast(21); + public bool CanPickFolder => Build.VERSION.SdkInt >= (BuildVersionCodes)21; public Task OpenFolderBookmarkAsync(string bookmark) { @@ -270,7 +271,7 @@ internal class AndroidStorageProvider : IStorageProvider private static Intent TryAddExtraInitialUri(Intent intent, IStorageFolder? folder) { - if (OperatingSystem.IsAndroidVersionAtLeast(26) + if (Build.VERSION.SdkInt >= (BuildVersionCodes)26 && (folder as AndroidStorageItem)?.Uri is { } uri) { return intent.PutExtra(DocumentsContract.ExtraInitialUri, uri); diff --git a/src/Avalonia.Base/Compatibility/OperatingSystem.cs b/src/Avalonia.Base/Compatibility/OperatingSystem.cs index ad5fe0246a..e4851d894e 100644 --- a/src/Avalonia.Base/Compatibility/OperatingSystem.cs +++ b/src/Avalonia.Base/Compatibility/OperatingSystem.cs @@ -6,12 +6,13 @@ namespace Avalonia.Compatibility internal sealed class OperatingSystemEx { #if NET6_0_OR_GREATER + private const string BionicRuntimeIdentifierPrefix = "linux-bionic-"; public static bool IsWindows() => OperatingSystem.IsWindows(); public static bool IsMacOS() => OperatingSystem.IsMacOS(); public static bool IsMacCatalyst() => OperatingSystem.IsMacCatalyst(); - public static bool IsLinux() => OperatingSystem.IsLinux(); + public static bool IsLinux() => OperatingSystem.IsLinux() && !RuntimeInformation.RuntimeIdentifier.StartsWith(BionicRuntimeIdentifierPrefix); public static bool IsFreeBSD() => OperatingSystem.IsFreeBSD(); - public static bool IsAndroid() => OperatingSystem.IsAndroid(); + public static bool IsAndroid() => OperatingSystem.IsAndroid() || (OperatingSystem.IsLinux() && RuntimeInformation.RuntimeIdentifier.StartsWith(BionicRuntimeIdentifierPrefix)); public static bool IsIOS() => OperatingSystem.IsIOS(); public static bool IsTvOS() => OperatingSystem.IsTvOS(); public static bool IsBrowser() => OperatingSystem.IsBrowser();