diff --git a/.github/skills/find-reviewable-pr/scripts/query-reviewable-prs.ps1 b/.github/skills/find-reviewable-pr/scripts/query-reviewable-prs.ps1 index c9fa57bcb647..dfa6b3d4e4d9 100644 --- a/.github/skills/find-reviewable-pr/scripts/query-reviewable-prs.ps1 +++ b/.github/skills/find-reviewable-pr/scripts/query-reviewable-prs.ps1 @@ -1219,14 +1219,18 @@ function Format-Markdown-Output { $title = $rawTitle.Replace('|', '\|') $link = "[#$($pr.Number)]($($pr.URL))" $turnCol = "$($pr.TurnIcon) $($pr.TurnDetail)" + # Wrap author handles in backticks so GitHub renders them as inline code + # rather than as @mentions — this issue is for MAUI team triage tracking, + # not a notification firehose to every PR author each day. + $author = "``@$($pr.Author)``" if ($showMilestone -and $showTurn) { - [void]$md.AppendLine("| $link | $title | @$($pr.Author) | $($pr.Milestone) | $turnCol | $($pr.Platform) | $($pr.Age)d |") + [void]$md.AppendLine("| $link | $title | $author | $($pr.Milestone) | $turnCol | $($pr.Platform) | $($pr.Age)d |") } elseif ($showMilestone) { - [void]$md.AppendLine("| $link | $title | @$($pr.Author) | $($pr.Milestone) | $($pr.Platform) | $($pr.Age)d | $($pr.Updated)d ago |") + [void]$md.AppendLine("| $link | $title | $author | $($pr.Milestone) | $($pr.Platform) | $($pr.Age)d | $($pr.Updated)d ago |") } elseif ($showTurn) { - [void]$md.AppendLine("| $link | $title | @$($pr.Author) | $turnCol | $($pr.Platform) | $($pr.Age)d |") + [void]$md.AppendLine("| $link | $title | $author | $turnCol | $($pr.Platform) | $($pr.Age)d |") } else { - [void]$md.AppendLine("| $link | $title | @$($pr.Author) | $($pr.Platform) | $($pr.Age)d | $($pr.Updated)d ago |") + [void]$md.AppendLine("| $link | $title | $author | $($pr.Platform) | $($pr.Age)d | $($pr.Updated)d ago |") } } [void]$md.AppendLine("") diff --git a/.github/workflows/pr-review-queue.yml b/.github/workflows/pr-review-queue.yml index f41baf1872a5..4f3f500fa614 100644 --- a/.github/workflows/pr-review-queue.yml +++ b/.github/workflows/pr-review-queue.yml @@ -20,7 +20,9 @@ concurrency: jobs: generate-report: runs-on: ubuntu-latest - if: github.event_name != 'pull_request' + # Guard: only run in dotnet/maui — prevents the scheduled run from firing + # in forks and pinging fork owners with duplicate queue issues. + if: github.repository_owner == 'dotnet' && github.event_name != 'pull_request' permissions: contents: read issues: write @@ -86,7 +88,7 @@ jobs: # Dry-run on PRs: validate the script works without creating issues validate: runs-on: ubuntu-latest - if: github.event_name == 'pull_request' + if: github.repository_owner == 'dotnet' && github.event_name == 'pull_request' permissions: contents: read pull-requests: read diff --git a/eng/pipelines/ci-copilot.yml b/eng/pipelines/ci-copilot.yml index ebce013b91ea..8ee93ed66321 100644 --- a/eng/pipelines/ci-copilot.yml +++ b/eng/pipelines/ci-copilot.yml @@ -124,7 +124,10 @@ stages: skipAndroidPlatformApis: true onlyAndroidPlatformDefaultApis: true skipAndroidEmulatorImages: ${{ ne(parameters.Platform, 'android') }} - skipAndroidCreateAvds: ${{ ne(parameters.Platform, 'android') }} + # AVD is created by the inline 'Create AVD and boot Android Emulator' script below + # with specific config (playstore image variant, partition shrink, ADB key pre-auth) + # that ProvisionAndroidSdkAvdCreateAvds doesn't replicate. + skipAndroidCreateAvds: true androidEmulatorApiLevel: '30' skipSimulatorSetup: ${{ or(eq(parameters.Platform, 'android'), eq(parameters.Platform, 'windows'), eq(parameters.Platform, 'catalyst')) }} skipCertificates: true @@ -871,7 +874,10 @@ stages: skipAndroidPlatformApis: true onlyAndroidPlatformDefaultApis: true skipAndroidEmulatorImages: ${{ ne(parameters.Platform, 'android') }} - skipAndroidCreateAvds: ${{ ne(parameters.Platform, 'android') }} + # AVD is created by the inline 'Create AVD and boot Android Emulator' script below + # with specific config (playstore image variant, partition shrink, ADB key pre-auth) + # that ProvisionAndroidSdkAvdCreateAvds doesn't replicate. + skipAndroidCreateAvds: true androidEmulatorApiLevel: '30' skipSimulatorSetup: ${{ or(eq(parameters.Platform, 'android'), eq(parameters.Platform, 'windows'), eq(parameters.Platform, 'catalyst')) }} skipCertificates: true diff --git a/eng/pipelines/common/variables.yml b/eng/pipelines/common/variables.yml index 8dee742a2525..d878b0ddb12c 100644 --- a/eng/pipelines/common/variables.yml +++ b/eng/pipelines/common/variables.yml @@ -15,6 +15,15 @@ variables: value: 26.0.1 - name: POWERSHELL_VERSION value: 7.4.0 +# Workaround for PowerShell/PowerShell#20802 (open since Nov 2023): +# pwsh 7.4.x intermittently aborts at startup on macOS with +# 'Call to procargs failed with errno 5' +# because AttemptExecPwshLogin() races on sysctl(KERN_PROCARGS2). +# Setting __PWSH_LOGIN_CHECKED makes pwsh short-circuit the login-shell +# detection that triggers the racy syscall (see Program.cs in PowerShell repo). +# Hit on internal dnceng dotnet-maui build 2990586 (release/11.0.1xx-preview5). +- name: __PWSH_LOGIN_CHECKED + value: '1' # Localization variables - name: LocBranchPrefix value: 'loc-hb' diff --git a/src/Controls/src/Core/Platform/Android/InnerGestureListener.cs b/src/Controls/src/Core/Platform/Android/InnerGestureListener.cs index 98170f751ced..7db911369caf 100644 --- a/src/Controls/src/Core/Platform/Android/InnerGestureListener.cs +++ b/src/Controls/src/Core/Platform/Android/InnerGestureListener.cs @@ -63,7 +63,7 @@ public InnerGestureListener( bool HasAnyGestures() { - return (_panGestureHandler?.HasAnyGestures() ?? false) || (_tapGestureHandler?.HasAnyGestures() ?? false) || (_swipeGestureHandler?.HasAnyGestures() ?? false); + return (_panGestureHandler?.HasAnyGestures() ?? false) || (_tapGestureHandler?.HasAnyGestures() ?? false) || (_swipeGestureHandler?.HasAnyGestures() ?? false) || (_dragAndDropGestureHandler?.HasAnyDragGestures() ?? false); } // This is needed because GestureRecognizer callbacks can be delayed several hundred milliseconds diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue35752.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue35752.cs new file mode 100644 index 000000000000..9847213af94b --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue35752.cs @@ -0,0 +1,80 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 35752, "Android DragGestureRecognizer DragStarting fires prematurely on tap", PlatformAffected.Android)] +public class Issue35752 : TestContentPage +{ + protected override void Init() + { + var statusLabel = new Label + { + Text = "Ready", + AutomationId = "StatusLabel" + }; + + var dragCountLabel = new Label + { + Text = "0", + AutomationId = "DragStartCount" + }; + + int dragStartCount = 0; + + var dragRecognizer = new DragGestureRecognizer(); + dragRecognizer.DragStarting += (s, e) => + { + dragStartCount++; + dragCountLabel.Text = dragStartCount.ToString(); + statusLabel.Text = "DragStarting fired"; + }; + + var dragBox = new Label + { + HeightRequest = 100, + WidthRequest = 200, + BackgroundColor = Colors.Blue, + AutomationId = "DragBox", + Text = "Drag Me", + TextColor = Colors.White, + HorizontalTextAlignment = TextAlignment.Center, + VerticalTextAlignment = TextAlignment.Center, + GestureRecognizers = { dragRecognizer } + }; + + var dropRecognizer = new DropGestureRecognizer(); + var dropBox = new Label + { + HeightRequest = 100, + WidthRequest = 200, + BackgroundColor = Colors.Green, + AutomationId = "DropBox", + Text = "Drop Here", + TextColor = Colors.White, + HorizontalTextAlignment = TextAlignment.Center, + VerticalTextAlignment = TextAlignment.Center, + GestureRecognizers = { dropRecognizer } + }; + + var instructions = new Label + { + Text = "Quick tap the blue box - DragStarting should NOT fire. " + + "Long press or drag it - DragStarting SHOULD fire.", + AutomationId = "TestLoaded" + }; + + Content = new VerticalStackLayout + { + Spacing = 20, + Padding = new Thickness(20), + Children = + { + instructions, + dragBox, + dropBox, + new Label { Text = "Status:" }, + statusLabel, + new Label { Text = "DragStart count:" }, + dragCountLabel + } + }; + } +} diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35752.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35752.cs new file mode 100644 index 000000000000..254de90239ab --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35752.cs @@ -0,0 +1,36 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue35752 : _IssuesUITest +{ + public override string Issue => "Android DragGestureRecognizer DragStarting fires prematurely on tap"; + + public Issue35752(TestDevice device) + : base(device) + { } + + [Test] + [Category(UITestCategories.DragAndDrop)] + public void DragStartingShouldNotFireOnTapButShouldFireOnDrag() + { + App.WaitForElement("TestLoaded"); + + App.Tap("DragBox"); + + Thread.Sleep(600); + + var dragCount = App.WaitForElement("DragStartCount").GetText(); + Assert.That(dragCount, Is.EqualTo("0"), + "DragStarting should not fire on a quick tap"); + + // Initiate drag - DragStarting SHOULD fire + App.DragAndDrop("DragBox", "DropBox"); + + dragCount = App.WaitForElement("DragStartCount").GetText(); + Assert.That(dragCount, Is.EqualTo("1"), + "DragStarting should fire when drag is initiated"); + } +}