Skip to content
14 changes: 0 additions & 14 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,20 +200,6 @@ git commit -m "Fix: Description of the change"
- `.github/instructions/android.instructions.md` - Android handler implementation
- `.github/instructions/xaml-unittests.instructions.md` - XAML unit test guidelines

### Opening PRs

All PRs are required to have this at the top of the description:

```
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you!
```

Always put that at the top, without the block quotes. Without it, users will NOT be able to try the PR and your work will have been in vain!



## Custom Agents and Skills

Expand Down
15 changes: 2 additions & 13 deletions .github/skills/pr-finalize/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,10 @@ Examples:
## Description Requirements

PR description should:
1. Start with the required NOTE block (so users can test PR artifacts)
2. Include the base sections from `.github/PULL_REQUEST_TEMPLATE.md` ("Description of Change" and "Issues Fixed"). The skill adds additional structured fields (Root cause, Fix, Key insight, etc.) as recommended enhancements for better agent context.
3. Match the actual implementation
1. Include the base sections from `.github/PULL_REQUEST_TEMPLATE.md` ("Description of Change" and "Issues Fixed"). The skill adds additional structured fields (Root cause, Fix, Key insight, etc.) as recommended enhancements for better agent context.
2. Match the actual implementation

```markdown
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you!

### Description of Change
[Must match actual implementation]

Expand Down Expand Up @@ -229,11 +223,6 @@ Example: "Before: Safe area applied by default (opt-out). After: Only views impl
Use structured template only when existing description is inadequate:

```markdown
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you!

### Root Cause

[Why the bug occurred - be specific about the code path]
Expand Down
4 changes: 0 additions & 4 deletions .github/skills/pr-finalize/references/complete-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ This example shows a PR description optimized for future agent success.

## Description
```markdown
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you!

### Root Cause

In `MauiView.GetAdjustedSafeAreaInsets()` on iOS, views that don't implement `ISafeAreaView` or `ISafeAreaView2` (such as `ContentPresenter`, `Border`) were falling through to return `baseSafeArea`. This applied full device safe area insets to views that never opted into safe area handling, causing double-padding when used inside ControlTemplates.
Expand Down
2 changes: 2 additions & 0 deletions eng/pipelines/common/ui-tests-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ steps:
- task: PublishBuildArtifacts@1
condition: always()
displayName: publish artifacts
inputs:
artifactName: drop-$(System.StageName)-$(System.JobName)-$(System.JobAttempt)

# Enable Notification Center re-enabled only for catalyst
- ${{ if eq(parameters.platform, 'catalyst')}}:
Expand Down
2 changes: 1 addition & 1 deletion eng/pipelines/common/ui-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ parameters:
- 'Cells,CheckBox,ContextActions,CustomRenderers,DatePicker,Dispatcher,DisplayAlert,DisplayPrompt,DragAndDrop'
- 'CollectionView'
- 'Entry'
- 'Editor,Effects,FlyoutPage,Focus,Fonts,Frame,Gestures,GraphicsView'
- 'Editor,Effects,Essentials,FlyoutPage,Focus,Fonts,Frame,Gestures,GraphicsView'
- 'Image,ImageButton,IndicatorView,InputTransparent,IsEnabled,IsVisible'
- 'Label'
- 'Layout'
Expand Down
50 changes: 50 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue32989.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Essentials;

namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 32989, "Exception thrown on .NET 10 Windows when calling Permissions.CheckStatusAsync<Permissions.Microphone>()", PlatformAffected.UWP)]
public class Issue32989 : ContentPage
{
Label statusLabel;

public Issue32989()
{
var titleLabel = new Label
{
Text = "Test microphone permission in unpackaged apps",
FontSize = 18,
HorizontalOptions = LayoutOptions.Center
};

var checkPermissionButton = new Button
{
Text = "Check Microphone Permission",
AutomationId = "CheckPermissionButton"
};
checkPermissionButton.Clicked += OnCheckPermissionClicked;

statusLabel = new Label
{
Text = "Status: Not checked",
FontSize = 16,
HorizontalOptions = LayoutOptions.Center,
AutomationId = "StatusLabel"
};

Content = new StackLayout
{
Padding = 20,
Spacing = 20,
Children = { titleLabel, checkPermissionButton, statusLabel }
};
}

async void OnCheckPermissionClicked(object sender, EventArgs e)
{
statusLabel.Text = "Checking...";
var status = await Permissions.CheckStatusAsync<Permissions.Microphone>();
statusLabel.Text = "Test Passed";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#if WINDOWS //This is a Windows-specific issue
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;
public class Issue32989 : _IssuesUITest
{
public override string Issue => "Exception thrown on .NET 10 Windows when calling Permissions.CheckStatusAsync<Permissions.Microphone>()";

public Issue32989(TestDevice device) : base(device) { }

[Test]
[Category(UITestCategories.Essentials)]
public void MicrophonePermissionCheckDoesNotCrash()
{
App.WaitForElement("CheckPermissionButton");
App.Tap("CheckPermissionButton");
// Verify that the status was updated (permission check completed)
var statusText = App.FindElement("StatusLabel").GetText();
Assert.That(statusText, Is.EqualTo("Test Passed"));
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ internal static class UITestCategories
public const string GraphicsView = "GraphicsView";
public const string Fonts = "Fonts";
public const string SafeAreaEdges = "SafeAreaEdges";
public const string Essentials = "Essentials";
public const string Material3 = "Material3";
}
}
22 changes: 18 additions & 4 deletions src/Essentials/src/Permissions/Permissions.windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,12 @@ public partial class Microphone : BasePlatformPermission
/// <inheritdoc/>
public override Task<PermissionStatus> CheckStatusAsync()
{
EnsureDeclared();
// For packaged apps, ensure manifest declaration is present
if (AppInfoUtils.IsPackagedApp)
{
EnsureDeclared();
}

return Task.FromResult(CheckStatus() switch
{
DeviceAccessStatus.Allowed => PermissionStatus.Granted,
Expand All @@ -193,13 +198,22 @@ public override Task<PermissionStatus> CheckStatusAsync()
/// <inheritdoc/>
public override async Task<PermissionStatus> RequestAsync()
{
EnsureDeclared();

// If already explicitly allowed, return that
// Check status first - if already allowed, return early
var status = CheckStatus();
if (status == DeviceAccessStatus.Allowed)
return PermissionStatus.Granted;

// For packaged apps, ensure manifest declaration is present
if (AppInfoUtils.IsPackagedApp)
{
EnsureDeclared();
}

return await TryRequestPermissionAsync();
}

async Task<PermissionStatus> TryRequestPermissionAsync()
{
try
{
var settings = new MediaCaptureInitializationSettings
Expand Down
Loading