diff --git a/Directory.Build.props b/Directory.Build.props index f124456eab1..c6ed387d66a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -8,7 +8,7 @@ false False - 12 + 14.0 true true true diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml index fbf22358ed5..f5864e85cf0 100644 --- a/api/Avalonia.nupkg.xml +++ b/api/Avalonia.nupkg.xml @@ -1,4 +1,4 @@ - + @@ -181,4 +181,4 @@ baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll - \ No newline at end of file + diff --git a/azure-pipelines-integrationtests.yml b/azure-pipelines-integrationtests.yml index b34def779f8..89b6a3ac533 100644 --- a/azure-pipelines-integrationtests.yml +++ b/azure-pipelines-integrationtests.yml @@ -5,13 +5,13 @@ jobs: steps: - task: UseDotNet@2 - displayName: 'Use .NET 6.0 Runtime' + displayName: 'Use .NET 8.0 Runtime' inputs: packageType: runtime - version: 6.0.x + version: 8.0.x - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true @@ -31,11 +31,10 @@ jobs: pkill IntegrationTestApp sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer ./build.sh CompileNative - sudo xcode-select -s /Applications/Xcode_14.3.app/Contents/Developer rm -rf $(osascript -e "POSIX path of (path to application id \"net.avaloniaui.avalonia.integrationtestapp\")") pkill IntegrationTestApp ./samples/IntegrationTestApp/bundle.sh - open -n ./samples/IntegrationTestApp/bin/Debug/net8.0/osx-$arch/publish/IntegrationTestApp.app + open -n ./samples/IntegrationTestApp/bin/Debug/net10.0/osx-$arch/publish/IntegrationTestApp.app pkill IntegrationTestApp displayName: 'Build IntegrationTestApp' @@ -57,17 +56,17 @@ jobs: - job: Windows pool: - vmImage: 'windows-2022' + vmImage: 'windows-2025' steps: - task: UseDotNet@2 - displayName: 'Use .NET 6.0 Runtime' + displayName: 'Use .NET 8.0 Runtime' inputs: packageType: runtime - version: 6.0.x + version: 8.0.x - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 956bcde6d7b..06da4bcd2b6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -2,12 +2,12 @@ jobs: - job: GetPRNumber pool: - vmImage: 'ubuntu-22.04' + vmImage: 'ubuntu-24.04' variables: SolutionDir: '$(Build.SourcesDirectory)' steps: - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true @@ -23,16 +23,16 @@ jobs: - job: Linux pool: - vmImage: 'ubuntu-22.04' + vmImage: 'ubuntu-24.04' steps: - task: UseDotNet@2 - displayName: 'Use .NET 6.0 Runtime' + displayName: 'Use .NET 8.0 Runtime' inputs: packageType: runtime - version: 6.0.x + version: 8.0.x - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true @@ -62,16 +62,16 @@ jobs: variables: SolutionDir: '$(Build.SourcesDirectory)' pool: - vmImage: 'macos-13' + vmImage: 'macos-15' steps: - task: UseDotNet@2 - displayName: 'Use .NET 6.0 Runtime' + displayName: 'Use .NET 8.0 Runtime' inputs: packageType: runtime - version: 6.0.x + version: 8.0.x - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true @@ -95,11 +95,11 @@ jobs: inputs: actions: 'build' scheme: '' - sdk: 'macosx14.2' + sdk: 'macosx26.0' configuration: 'Release' xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' xcodeVersion: 'specifyPath' # Options: 8, 9, default, specifyPath - xcodeDeveloperDir: '/Applications/Xcode_15.2.app/Contents/Developer' + xcodeDeveloperDir: '/Applications/Xcode_26.0.app/Contents/Developer' args: '-derivedDataPath ./' - task: CmdLine@2 @@ -134,18 +134,18 @@ jobs: - job: Windows pool: - vmImage: 'windows-2022' + vmImage: 'windows-2025' variables: SolutionDir: '$(Build.SourcesDirectory)' steps: - task: UseDotNet@2 - displayName: 'Use .NET 6.0 Runtime' + displayName: 'Use .NET 8.0 Runtime' inputs: packageType: runtime - version: 6.0.x + version: 8.0.x - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true @@ -160,7 +160,7 @@ jobs: displayName: 'Install Nuke' inputs: script: | - dotnet tool install --global Nuke.GlobalTool --version 6.2.1 + dotnet tool install --global Nuke.GlobalTool --version 9.0.4 - task: CmdLine@2 displayName: 'Run Nuke' diff --git a/build/Base.props b/build/Base.props index 0e667f105b9..ab5853fcfa9 100644 --- a/build/Base.props +++ b/build/Base.props @@ -1,12 +1,8 @@  - - - - - - - + - + + + diff --git a/build/Moq.props b/build/Moq.props index 357f0c9a5f6..fc659f7f5fc 100644 --- a/build/Moq.props +++ b/build/Moq.props @@ -1,5 +1,5 @@  - + diff --git a/build/TargetFrameworks.props b/build/TargetFrameworks.props index f14a3876fff..96541e7ecf5 100644 --- a/build/TargetFrameworks.props +++ b/build/TargetFrameworks.props @@ -1,17 +1,17 @@ - net8.0 + net10.0 $(AvsCurrentTargetFramework)-windows $(AvsCurrentTargetFramework)-macos - $(AvsCurrentTargetFramework)-android34.0 - $(AvsCurrentTargetFramework)-maccatalyst17.0 - $(AvsCurrentTargetFramework)-ios17.0 - $(AvsCurrentTargetFramework)-tvos17.0 + $(AvsCurrentTargetFramework)-android36.0 + $(AvsCurrentTargetFramework)-maccatalyst26.0 + $(AvsCurrentTargetFramework)-ios26.0 + $(AvsCurrentTargetFramework)-tvos26.0 $(AvsCurrentTargetFramework)-browser - net6.0 - net6.0-windows + net8.0 + net8.0-windows @@ -20,7 +20,7 @@ 13.0 13.0 13.1 - 21.0 + 24.0 10.15 diff --git a/build/UnitTests.NetCore.targets b/build/UnitTests.NetCore.targets index 42da8e4ab17..19b2253f4ff 100644 --- a/build/UnitTests.NetCore.targets +++ b/build/UnitTests.NetCore.targets @@ -3,7 +3,4 @@ false true - - - - \ No newline at end of file + diff --git a/build/XUnit.props b/build/XUnit.props index b4e9708ecde..4b00869d5b6 100644 --- a/build/XUnit.props +++ b/build/XUnit.props @@ -8,7 +8,7 @@ - + $(MSBuildThisFileDirectory)\avalonia.snk diff --git a/external/XamlX b/external/XamlX index 83567b8a50b..99a49740bd6 160000 --- a/external/XamlX +++ b/external/XamlX @@ -1 +1 @@ -Subproject commit 83567b8a50bbf612a0b1420a3dc6d8e8ebee2399 +Subproject commit 99a49740bd6a587b1852337764741ec280e201d6 diff --git a/global.json b/global.json index f496cffc503..7fed696458a 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.411", + "version": "10.0.100-rc.2.25502.107", "rollForward": "latestFeature" }, "msbuild-sdks": { diff --git a/nukebuild/ApiDiffHelper.cs b/nukebuild/ApiDiffHelper.cs index 1d1f1b1b320..4a516305576 100644 --- a/nukebuild/ApiDiffHelper.cs +++ b/nukebuild/ApiDiffHelper.cs @@ -326,25 +326,11 @@ public static async Task DownloadAndExtractPackagesAsync( var frameworkDiffs = new List(); - // Handle frameworks that exist only in the current package. - foreach (var framework in currentFolderNames.Keys.Except(baselineFolderNames.Keys)) - { - var folderName = currentFolderNames[framework]; - Directory.CreateDirectory(baselineFolderPath / folderName); - baselineFolderNames.Add(framework, folderName); - } - - // Handle frameworks that exist only for the baseline package. - foreach (var framework in baselineFolderNames.Keys.Except(currentFolderNames.Keys)) - { - var folderName = baselineFolderNames[framework]; - Directory.CreateDirectory(currentFolderPath / folderName); - currentFolderNames.Add(framework, folderName); - } - foreach (var (framework, currentFolderName) in currentFolderNames) { - var baselineFolderName = baselineFolderNames[framework]; + // Ignore new frameworks that didn't exist in the baseline package. Empty folders make the ApiDiff tool crash. + if (!baselineFolderNames.TryGetValue(framework, out var baselineFolderName)) + continue; frameworkDiffs.Add(new FrameworkDiffInfo( framework, diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index b0d8106d325..4117ac29089 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -240,11 +240,11 @@ void RunCoreTest(string projectName, Action runTest) var tfm = fw; if (tfm == "$(AvsCurrentTargetFramework)") { - tfm = "net8.0"; + tfm = "net10.0"; } if (tfm == "$(AvsLegacyTargetFrameworks)") { - tfm = "net6.0"; + tfm = "net8.0"; } if (tfm.StartsWith("net4") @@ -414,13 +414,13 @@ void DoMemoryTest() ApiDiffHelper.MergePackageMarkdownDiffFiles(outputFolderPath, baselineDisplay, currentDisplay); }); - + Target RunTests => _ => _ .DependsOn(RunCoreLibsTests) .DependsOn(RunRenderTests) .DependsOn(RunToolsTests) - .DependsOn(RunHtmlPreviewerTests) - .DependsOn(RunLeakTests); + .DependsOn(RunHtmlPreviewerTests); + //.DependsOn(RunLeakTests); // dotMemory Unit doesn't support modern .NET versions, see https://youtrack.jetbrains.com/issue/DMU-300/ Target Package => _ => _ .DependsOn(RunTests) diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index 2ea83ead719..2dba75782b4 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -21,8 +21,8 @@ - - + + diff --git a/packages/Avalonia/AvaloniaPrivateApis.targets b/packages/Avalonia/AvaloniaPrivateApis.targets index 5f69187d923..47219535cc9 100644 --- a/packages/Avalonia/AvaloniaPrivateApis.targets +++ b/packages/Avalonia/AvaloniaPrivateApis.targets @@ -13,7 +13,7 @@ - net6.0 + net8.0 netstandard2.0 diff --git a/packages/Avalonia/AvaloniaSingleProject.targets b/packages/Avalonia/AvaloniaSingleProject.targets index a776f12a7df..25125b26e44 100644 --- a/packages/Avalonia/AvaloniaSingleProject.targets +++ b/packages/Avalonia/AvaloniaSingleProject.targets @@ -98,7 +98,7 @@ 13.0 10.15 13.1 - 21.0 + 24.0 6.5 diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj index 958725eed5b..f60ba69395e 100644 --- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj +++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj @@ -26,7 +26,7 @@ - + diff --git a/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj b/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj index 2950028e687..763ab26cabf 100644 --- a/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj +++ b/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj b/samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj index 0a1329e2e3a..954ed20d99b 100644 --- a/samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj +++ b/samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj @@ -5,7 +5,7 @@ manual $(AvsCurrentMacCatalystTargetFramework) - 14.0 + 15.0 true diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props index 3a61d3fff97..169239237f1 100644 --- a/samples/Directory.Build.props +++ b/samples/Directory.Build.props @@ -4,7 +4,7 @@ false $(MSBuildThisFileDirectory)..\src\tools\Avalonia.Designer.HostApp\bin\Debug\netstandard2.0\Avalonia.Designer.HostApp.dll false - 12 + 14.0 $(NoWarn);CS8002 diff --git a/samples/IntegrationTestApp/bundle.sh b/samples/IntegrationTestApp/bundle.sh index 2b480723c2a..6f49bdbee36 100755 --- a/samples/IntegrationTestApp/bundle.sh +++ b/samples/IntegrationTestApp/bundle.sh @@ -9,4 +9,4 @@ arch="arm64" fi dotnet restore -r osx-$arch -dotnet msbuild -t:BundleApp -p:RuntimeIdentifier=osx-$arch +dotnet msbuild -t:BundleApp -p:RuntimeIdentifier=osx-$arch -p:SelfContained=true diff --git a/samples/XEmbedSample/XEmbedSample.csproj b/samples/XEmbedSample/XEmbedSample.csproj index 01ea7432db0..a6e754692db 100644 --- a/samples/XEmbedSample/XEmbedSample.csproj +++ b/samples/XEmbedSample/XEmbedSample.csproj @@ -1,20 +1,20 @@ - - Exe - net6.0 - enable - enable - true - + + Exe + $(AvsCurrentTargetFramework) + enable + enable + true + - - - + + + - - - - + + + + diff --git a/src/Android/Avalonia.Android/Automation/ToggleNodeInfoProvider.cs b/src/Android/Avalonia.Android/Automation/ToggleNodeInfoProvider.cs index 907bd2e3a0b..24ce3fa120e 100644 --- a/src/Android/Avalonia.Android/Automation/ToggleNodeInfoProvider.cs +++ b/src/Android/Avalonia.Android/Automation/ToggleNodeInfoProvider.cs @@ -1,5 +1,4 @@ -using System.Reflection; -using Android.OS; +using Android.OS; using AndroidX.Core.View.Accessibility; using AndroidX.CustomView.Widget; using Avalonia.Automation.Peers; @@ -9,8 +8,6 @@ namespace Avalonia.Android.Automation { internal class ToggleNodeInfoProvider : NodeInfoProvider { - private PropertyInfo? _checkedProperty; - public ToggleNodeInfoProvider(ExploreByTouchHelper owner, AutomationPeer peer, int virtualViewId) : base(owner, peer, virtualViewId) { @@ -35,25 +32,12 @@ public override void PopulateNodeInfo(AccessibilityNodeInfoCompat nodeInfo) nodeInfo.Clickable = true; IToggleProvider provider = GetProvider(); - - _checkedProperty ??= nodeInfo.GetType().GetProperty(nameof(nodeInfo.Checked)); - if (_checkedProperty?.PropertyType == typeof(int)) - { - // Needed for Xamarin.AndroidX.Core 1.17+ - _checkedProperty.SetValue(this, - provider.ToggleState switch - { - ToggleState.On => 1, - ToggleState.Indeterminate => 2, - _ => 0 - }); - } - else if (_checkedProperty?.PropertyType == typeof(bool)) + nodeInfo.Checked = provider.ToggleState switch { - // Needed for Xamarin.AndroidX.Core < 1.17 - _checkedProperty.SetValue(this, provider.ToggleState == ToggleState.On); - } - + ToggleState.On => 1, + ToggleState.Indeterminate => 2, + _ => 0 + }; nodeInfo.Checkable = true; } } diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index 2fb849ee0de..97acf3d012c 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 0b5a7e03c41..faacff7554e 100644 --- a/src/Android/Avalonia.Android/AvaloniaAccessHelper.cs +++ b/src/Android/Avalonia.Android/AvaloniaAccessHelper.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using Android.Content.PM; using Android.OS; using AndroidX.Core.View.Accessibility; using AndroidX.CustomView.Widget; @@ -15,20 +13,6 @@ namespace Avalonia.Android { internal class AvaloniaAccessHelper : ExploreByTouchHelper { - private const string AUTOMATION_PROVIDER_NAMESPACE = "Avalonia.Automation.Provider"; - - private static readonly IReadOnlyDictionary - s_providerTypeInitializers = new Dictionary() - { - { typeof(IExpandCollapseProvider).FullName!, (owner, peer, id) => new ExpandCollapseNodeInfoProvider(owner, peer, id) }, - { typeof(IInvokeProvider).FullName!, (owner, peer, id) => new InvokeNodeInfoProvider(owner, peer, id) }, - { typeof(IRangeValueProvider).FullName!, (owner, peer, id) => new RangeValueNodeInfoProvider(owner, peer, id) }, - { typeof(IScrollProvider).FullName!, (owner, peer, id) => new ScrollNodeInfoProvider(owner, peer, id) }, - { typeof(ISelectionItemProvider).FullName!, (owner, peer, id) => new SelectionItemNodeInfoProvider(owner, peer, id) }, - { typeof(IToggleProvider).FullName!, (owner, peer, id) => new ToggleNodeInfoProvider(owner, peer, id) }, - { typeof(IValueProvider).FullName!, (owner, peer, id) => new ValueNodeInfoProvider(owner, peer, id) }, - }; - private readonly Dictionary _peers; private readonly Dictionary _peerIds; @@ -96,17 +80,20 @@ private HashSet GetOrCreateNodeInfoProvidersFromPeer(Automati } }; - Type peerType = peer.GetType(); - IEnumerable providerTypes = peerType.GetInterfaces() - .Where(x => x.Namespace!.StartsWith(AUTOMATION_PROVIDER_NAMESPACE)); - foreach (Type providerType in providerTypes) - { - if (s_providerTypeInitializers.TryGetValue(providerType.FullName!, out NodeInfoProviderInitializer? ctor)) - { - INodeInfoProvider nodeInfoProvider = ctor(this, peer, peerViewId); - nodeInfoProviders.Add(nodeInfoProvider); - } - } + if (peer is IExpandCollapseProvider) + nodeInfoProviders.Add(new ExpandCollapseNodeInfoProvider(this, peer, peerViewId)); + if (peer is IInvokeProvider) + nodeInfoProviders.Add(new InvokeNodeInfoProvider(this, peer, peerViewId)); + if (peer is IRangeValueProvider) + nodeInfoProviders.Add(new RangeValueNodeInfoProvider(this, peer, peerViewId)); + if (peer is IScrollProvider) + nodeInfoProviders.Add(new ScrollNodeInfoProvider(this, peer, peerViewId)); + if (peer is ISelectionItemProvider) + nodeInfoProviders.Add(new SelectionItemNodeInfoProvider(this, peer, peerViewId)); + if (peer is IToggleProvider) + nodeInfoProviders.Add(new ToggleNodeInfoProvider(this, peer, peerViewId)); + if (peer is IValueProvider) + nodeInfoProviders.Add(new ValueNodeInfoProvider(this, peer, peerViewId)); } virtualViewId = peerViewId; @@ -151,9 +138,9 @@ protected override bool OnPerformActionForVirtualView(int virtualViewId, int act .Aggregate(false, (a, b) => a | b); } - protected override void OnPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat nodeInfo) + protected override void OnPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat? nodeInfo) { - if (!_peers.TryGetValue(virtualViewId, out AutomationPeer? peer)) + if (nodeInfo is null || !_peers.TryGetValue(virtualViewId, out AutomationPeer? peer)) { return; // BAIL!! No work to be done } diff --git a/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs b/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs index 8a3685b65e2..4a4159965c0 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs @@ -127,10 +127,13 @@ public Thickness SafeAreaPadding WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars() | WindowInsetsCompat.Type.DisplayCutout() : 0); - return new Thickness(inset.Left / renderScaling, - inset.Top / renderScaling, - inset.Right / renderScaling, - inset.Bottom / renderScaling); + if (inset is not null) + { + return new Thickness(inset.Left / renderScaling, + inset.Top / renderScaling, + inset.Right / renderScaling, + inset.Bottom / renderScaling); + } } return default; @@ -145,9 +148,10 @@ public Rect OccludedRect if (insets != null) { - var navbarInset = insets.GetInsets(WindowInsetsCompat.Type.NavigationBars()).Bottom; + var navbarInset = insets.GetInsets(WindowInsetsCompat.Type.NavigationBars())?.Bottom ?? 0; + var imeInset = insets.GetInsets(WindowInsetsCompat.Type.Ime())?.Bottom ?? 0; - var height = Math.Max((float)((insets.GetInsets(WindowInsetsCompat.Type.Ime()).Bottom - navbarInset) / _topLevel.RenderScaling), 0); + var height = Math.Max((float)((imeInset - navbarInset) / _topLevel.RenderScaling), 0); return new Rect(0, _topLevel.ClientSize.Height - SafeAreaPadding.Bottom - height, _topLevel.ClientSize.Width, height); } @@ -156,7 +160,7 @@ public Rect OccludedRect } } - public WindowInsetsCompat OnApplyWindowInsets(View v, WindowInsetsCompat insets) + public WindowInsetsCompat? OnApplyWindowInsets(View? v, WindowInsetsCompat? insets) { insets = ViewCompat.OnApplyWindowInsets(v, insets); NotifySafeAreaChanged(SafeAreaPadding); @@ -166,15 +170,14 @@ public WindowInsetsCompat OnApplyWindowInsets(View v, WindowInsetsCompat insets) _previousRect = OccludedRect; } - State = insets.IsVisible(WindowInsetsCompat.Type.Ime()) ? InputPaneState.Open : InputPaneState.Closed; + State = insets is not null && insets.IsVisible(WindowInsetsCompat.Type.Ime()) ? 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()); - if(_previousImeInset == default) - _previousImeInset = imeInset; - if(imeInset.Bottom != _previousImeInset.Bottom) + var imeInset = insets?.GetInsets(WindowInsetsCompat.Type.Ime()); + _previousImeInset ??= imeInset; + if ((imeInset?.Bottom ?? 0) != (_previousImeInset?.Bottom ?? 0)) { NotifyStateChanged(State, _previousRect, OccludedRect, TimeSpan.Zero, null); } @@ -319,18 +322,18 @@ internal void ApplyStatusBarState() 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 is not null && bounds is not null && (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 ?? 0; + var height = Math.Max(0, (float)(((bounds.LowerBound?.Bottom ?? 0) - 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 ?? 0) - 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 +347,7 @@ public override WindowInsetsAnimationCompat.BoundsCompat OnStart(WindowInsetsAni 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/AndroidScreens.cs b/src/Android/Avalonia.Android/Platform/AndroidScreens.cs index 95d2530edc4..3f1f9bf44e4 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidScreens.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidScreens.cs @@ -32,11 +32,18 @@ public void Refresh(Context context) var metrics = metricsCalc.ComputeMaximumWindowMetrics(displayContext); 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, - Bounds.Y + inset.Top, - Bounds.Width - (inset.Left + inset.Right), - Bounds.Height - (inset.Top + inset.Bottom)); + var windowInsets = new WindowInsetsCompat.Builder().Build(); + if (windowInsets?.GetInsets(WindowInsetsCompat.Type.SystemBars()) is { } inset) + { + WorkingArea = new(Bounds.X + inset.Left, + Bounds.Y + inset.Top, + Bounds.Width - (inset.Left + inset.Right), + Bounds.Height - (inset.Top + inset.Bottom)); + } + else + { + WorkingArea = Bounds; + } if (context.Resources?.Configuration is { } config) { diff --git a/src/Avalonia.Base/Data/Core/BindingExpression.cs b/src/Avalonia.Base/Data/Core/BindingExpression.cs index ca29dd6ffa4..a51ee5bf8a5 100644 --- a/src/Avalonia.Base/Data/Core/BindingExpression.cs +++ b/src/Avalonia.Base/Data/Core/BindingExpression.cs @@ -190,6 +190,9 @@ public override void UpdateTarget() /// The null target value. /// Whether to allow reflection for target type conversion. [RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)] +#if NET8_0_OR_GREATER + [RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif internal static BindingExpression Create( TIn source, Expression> expression, diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs index f6c692e6859..dd8c0e1a63d 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs @@ -7,6 +7,9 @@ namespace Avalonia.Data.Core.ExpressionNodes.Reflection; [RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)] +#if NET8_0_OR_GREATER +[RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif internal sealed class DynamicPluginStreamNode : ExpressionNode { private IDisposable? _subscription; diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ExpressionTreeIndexerNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ExpressionTreeIndexerNode.cs index e720aa6e693..dfb83fb10d9 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ExpressionTreeIndexerNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ExpressionTreeIndexerNode.cs @@ -16,6 +16,9 @@ internal sealed class ExpressionTreeIndexerNode : CollectionNodeBase, ISettableN private readonly Delegate _getDelegate; private readonly Delegate _firstArgumentDelegate; +#if NET8_0_OR_GREATER + [RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif public ExpressionTreeIndexerNode(IndexExpression expression) { var valueParameter = Expression.Parameter(expression.Type); diff --git a/src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs b/src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs index 39d6ffcab66..19817321451 100644 --- a/src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs +++ b/src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs @@ -11,6 +11,9 @@ namespace Avalonia.Data.Core.Parsers; [RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)] +#if NET8_0_OR_GREATER +[RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif internal class BindingExpressionVisitor : ExpressionVisitor { private static readonly PropertyInfo AvaloniaObjectIndexer; diff --git a/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs b/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs index 5c2d9aaddf5..520c345ad5f 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs @@ -28,6 +28,7 @@ public static class BindingPlugins new ObservableStreamPlugin(), }; + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "We're checking if dynamic code is supported.")] static BindingPlugins() { // When building with AOT, don't create ReflectionMethodAccessorPlugin instance. diff --git a/src/Avalonia.Base/Data/Core/Plugins/ReflectionMethodAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/ReflectionMethodAccessorPlugin.cs index e295fc60669..f9a4587ca63 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/ReflectionMethodAccessorPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/ReflectionMethodAccessorPlugin.cs @@ -7,6 +7,9 @@ namespace Avalonia.Data.Core.Plugins { [RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)] +#if NET8_0_OR_GREATER + [RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif internal class ReflectionMethodAccessorPlugin : IPropertyAccessorPlugin { private readonly Dictionary<(Type, string), MethodInfo?> _methodLookup = @@ -81,6 +84,9 @@ internal class ReflectionMethodAccessorPlugin : IPropertyAccessorPlugin return found; } +#if NET8_0_OR_GREATER + [RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif private sealed class Accessor : PropertyAccessorBase { public Accessor(WeakReference reference, MethodInfo method) diff --git a/src/Avalonia.Base/Diagnostics/TrimmingMessages.cs b/src/Avalonia.Base/Diagnostics/TrimmingMessages.cs index ce9c9e187b7..930ff4202bc 100644 --- a/src/Avalonia.Base/Diagnostics/TrimmingMessages.cs +++ b/src/Avalonia.Base/Diagnostics/TrimmingMessages.cs @@ -9,11 +9,13 @@ internal static class TrimmingMessages public const string TypeConversionRequiresUnreferencedCodeMessage = "Conversion methods are required for type conversion, including op_Implicit, op_Explicit, Parse and TypeConverter."; public const string ReflectionBindingRequiresUnreferencedCodeMessage = "BindingExpression and ReflectionBinding heavily use reflection. Consider using CompiledBindings instead."; + public const string ReflectionBindingRequiresDynamicCodeMessage = "BindingExpression and ReflectionBinding require dynamic code. Consider using CompiledBindings instead."; public const string ReflectionBindingSupressWarningMessage = "BindingExpression and ReflectionBinding internal heavily use reflection."; public const string CompiledBindingSafeSupressWarningMessage = "CompiledBinding preserves members used in the expression tree."; public const string ExpressionNodeRequiresUnreferencedCodeMessage = "ExpressionNode might require unreferenced code."; + public const string ExpressionNodeRequiresDynamicCodeMessage = "ExpressionNode requires dynamic code."; public const string ExpressionSafeSupressWarningMessage = "Typed Expressions preserves members used in the expression tree."; public const string SelectorsParseRequiresUnreferencedCodeMessage = "Selectors runtime parser might require unreferenced code. Consider using stronly typed selectors factory with 'new Style(s => s.OfType