diff --git a/eng/devices/android.cake b/eng/devices/android.cake index bcff0ec7b055..4279bdde432d 100644 --- a/eng/devices/android.cake +++ b/eng/devices/android.cake @@ -152,14 +152,17 @@ Teardown(context => return; //stop and cleanup the emulator + Information("AdbEmuKill"); AdbEmuKill(adbSettings); System.Threading.Thread.Sleep(5000); // kill the process if it has not already exited + Information("emulatorProcess.Kill()"); try { emulatorProcess.Kill(); } catch { } + Information("AndroidAvdDelete"); // delete the AVD try { AndroidAvdDelete(ANDROID_AVD, avdSettings); } catch { } diff --git a/eng/pipelines/common/device-tests-steps.yml b/eng/pipelines/common/device-tests-steps.yml index 25520ce7450b..080cd6689477 100644 --- a/eng/pipelines/common/device-tests-steps.yml +++ b/eng/pipelines/common/device-tests-steps.yml @@ -55,9 +55,30 @@ steps: - pwsh: ./build.ps1 --target=dotnet-buildtasks --configuration="Release" displayName: 'Build the MSBuild Tasks' - - pwsh: ./build.ps1 -Script eng/devices/${{ parameters.platform }}.cake --project="${{ parameters.path }}" --device=${{ parameters.device }} --packageid=${{ parameters.windowsPackageId }} --results="$(TestResultsDirectory)" --binlog="$(LogDirectory)" ${{ parameters.cakeArgs }} + - pwsh: | + $platformName = 'Windows' + if ($IsMacOS) { + $platformName = 'Mac' + } elseif ($IsLinux) { + $platformName = 'Linux' + } + Write-Host "Platform.Name: ${platformName}" + Write-Host "##vso[task.setvariable variable=Platform.Name]${platformName}" + displayName: 'Set Platform.Name' + + - pwsh: | + ./build.ps1 -Script eng/devices/${{ parameters.platform }}.cake --project="${{ parameters.path }}" --device=${{ parameters.device }} --packageid=${{ parameters.windowsPackageId }} --results="$(TestResultsDirectory)" --binlog="$(LogDirectory)" ${{ parameters.cakeArgs }} + displayName: $(Agent.JobName) + workingDirectory: ${{ parameters.checkoutDirectory }} + condition: and(succeeded(), ne(variables['Platform.Name'], 'Mac')) + retryCountOnTaskFailure: 2 + + - bash: | + # Execute the powershell script from a bash shell on Mac to avoid interference between powershell processes that lead to this error: The STDIO streams did not close within 10 seconds of the exit event from process '/usr/local/bin/pwsh'. This may indicate a child process inherited the STDIO streams and has not yet exited. + pwsh ./build.ps1 -Script eng/devices/${{ parameters.platform }}.cake --project="${{ parameters.path }}" --device=${{ parameters.device }} --packageid=${{ parameters.windowsPackageId }} --results="$(TestResultsDirectory)" --binlog="$(LogDirectory)" ${{ parameters.cakeArgs }} displayName: $(Agent.JobName) workingDirectory: ${{ parameters.checkoutDirectory }} + condition: and(succeeded(), eq(variables['Platform.Name'], 'Mac')) retryCountOnTaskFailure: 2 - task: PublishTestResults@2 diff --git a/eng/pipelines/common/device-tests.yml b/eng/pipelines/common/device-tests.yml index d15d26d2bc4a..a73f8b399cc7 100644 --- a/eng/pipelines/common/device-tests.yml +++ b/eng/pipelines/common/device-tests.yml @@ -29,7 +29,7 @@ stages: clean: all displayName: "Android emulator tests" pool: ${{ parameters.androidPool }} - timeoutInMinutes: 240 + timeoutInMinutes: 60 strategy: matrix: # create all the variables used for the matrix diff --git a/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.iOS.cs index 62ca5e6e41e9..e3febaa3780f 100644 --- a/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.iOS.cs +++ b/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.iOS.cs @@ -1,8 +1,12 @@ using System; using System.Threading.Tasks; using Microsoft.Maui.Graphics; +using Microsoft.Maui.Graphics.Platform; using Microsoft.Maui.Handlers; using Microsoft.Maui.Platform; +using Microsoft.Maui.Controls; +using System.Reflection; +using Xunit; namespace Microsoft.Maui.DeviceTests { @@ -10,5 +14,37 @@ public partial class BoxViewTests { MauiShapeView GetNativeBoxView(ShapeViewHandler boxViewHandler) => boxViewHandler.PlatformView; + + [Fact(DisplayName = "ShapeView Parts Keep Around")] + public async Task ShapeViewPartsKeepAround() + { + var boxView = new BoxView() + { + HeightRequest = 100, + WidthRequest = 200 + }; + + await AttachAndRun(boxView, async handler => + { + var shapeView = GetNativeBoxView(handler); + var renderer = (DirectRenderer)shapeView.Renderer; + + GC.Collect(); + GC.WaitForPendingFinalizers(); + await Task.Yield(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + await Task.Yield(); + + Assert.NotNull(shapeView.Renderer); + Assert.NotNull(shapeView.Drawable); + Assert.NotNull(renderer.Drawable); + + var flags = BindingFlags.NonPublic | BindingFlags.Instance; + var graphicsView = renderer.GetType().GetField("_graphicsView", flags)?.GetValue(renderer) as PlatformGraphicsView; + Assert.NotNull(graphicsView); + }); + } } } \ No newline at end of file diff --git a/src/Core/src/Graphics/ShapeDrawable.cs b/src/Core/src/Graphics/ShapeDrawable.cs index 4d15fbe4d5ae..c9157a3f87d5 100644 --- a/src/Core/src/Graphics/ShapeDrawable.cs +++ b/src/Core/src/Graphics/ShapeDrawable.cs @@ -1,9 +1,11 @@ -using System.Numerics; +using System; +using System.Numerics; namespace Microsoft.Maui.Graphics { public class ShapeDrawable : IDrawable { + WeakReference? _shapeView; public ShapeDrawable() { @@ -14,7 +16,21 @@ public ShapeDrawable(IShapeView? shape) UpdateShapeView(shape); } - internal IShapeView? ShapeView { get; set; } + internal IShapeView? ShapeView + { + get => _shapeView is not null && _shapeView.TryGetTarget(out var d) ? d : null; + set + { + if (value is null) + { + _shapeView = null; + return; + } + + _shapeView = new(value); + } + } + internal WindingMode WindingMode { get; set; } internal Matrix3x2? RenderTransform { get; set; } diff --git a/src/Core/tests/DeviceTests.Shared/HandlerTests/TestBase.cs b/src/Core/tests/DeviceTests.Shared/HandlerTests/TestBase.cs index 3909ed83df0e..28563dfe4a47 100644 --- a/src/Core/tests/DeviceTests.Shared/HandlerTests/TestBase.cs +++ b/src/Core/tests/DeviceTests.Shared/HandlerTests/TestBase.cs @@ -36,6 +36,7 @@ protected static async Task WaitForGC() await Task.Delay(10); GC.Collect(); GC.WaitForPendingFinalizers(); + await Task.Delay(10); } } } diff --git a/src/Core/tests/DeviceTests/Memory/MemoryTestTypes.cs b/src/Core/tests/DeviceTests/Memory/MemoryTestTypes.cs index a01c466b4b57..0d9e7a88c878 100644 --- a/src/Core/tests/DeviceTests/Memory/MemoryTestTypes.cs +++ b/src/Core/tests/DeviceTests/Memory/MemoryTestTypes.cs @@ -9,7 +9,9 @@ public class MemoryTestTypes : IEnumerable { public IEnumerator GetEnumerator() { +#if !ANDROID yield return new object[] { (typeof(DatePickerStub), typeof(DatePickerHandler)) }; +#endif yield return new object[] { (typeof(EditorStub), typeof(EditorHandler)) }; yield return new object[] { (typeof(EntryStub), typeof(EntryHandler)) }; yield return new object[] { (typeof(SearchBarStub), typeof(SearchBarHandler)) }; diff --git a/src/Graphics/src/Graphics/Platforms/iOS/PlatformGraphicsView.cs b/src/Graphics/src/Graphics/Platforms/iOS/PlatformGraphicsView.cs index ceced303c01a..7b06c147e910 100644 --- a/src/Graphics/src/Graphics/Platforms/iOS/PlatformGraphicsView.cs +++ b/src/Graphics/src/Graphics/Platforms/iOS/PlatformGraphicsView.cs @@ -8,9 +8,9 @@ namespace Microsoft.Maui.Graphics.Platform [Register(nameof(PlatformGraphicsView))] public class PlatformGraphicsView : UIView { - private WeakReference _renderer; + private IGraphicsRenderer _renderer; private CGColorSpace _colorSpace; - private WeakReference _drawable; + private IDrawable _drawable; private CGRect _lastBounds; public PlatformGraphicsView(CGRect frame, IDrawable drawable = null, IGraphicsRenderer renderer = null) : base(frame) @@ -34,34 +34,32 @@ public PlatformGraphicsView(IntPtr aPtr) : base(aPtr) public IGraphicsRenderer Renderer { - get => _renderer is not null && _renderer.TryGetTarget(out var r) ? r : null; + get => _renderer; set { - var renderer = Renderer; - if (renderer != null) + if (_renderer != null) { - renderer.Drawable = null; - renderer.GraphicsView = null; - renderer.Dispose(); + _renderer.Drawable = null; + _renderer.GraphicsView = null; + _renderer.Dispose(); } - renderer = value ?? new DirectRenderer(); - _renderer = new(renderer); + _renderer = value ?? new DirectRenderer(); - renderer.GraphicsView = this; - renderer.Drawable = Drawable; + _renderer.GraphicsView = this; + _renderer.Drawable = Drawable; var bounds = Bounds; - renderer.SizeChanged((float)bounds.Width, (float)bounds.Height); + _renderer.SizeChanged((float)bounds.Width, (float)bounds.Height); } } public IDrawable Drawable { - get => _drawable is not null && _drawable.TryGetTarget(out var d) ? d : null; + get => _drawable; set { - _drawable = new(value); + _drawable = value; if (Renderer is IGraphicsRenderer renderer) { renderer.Drawable = value;