Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 0 additions & 51 deletions .github/instructions/common-testing-patterns.md
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot revert changes to this file

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes to this file were already reverted in commit fe1649f.

Original file line number Diff line number Diff line change
Expand Up @@ -106,57 +106,6 @@ echo "Simulator is booted and ready"

---

### Android Emulator Startup with Error Checking

**Used in**: Investigation work

**Pattern**:
```bash
# Clean up any existing emulator processes
pkill -9 qemu-system-x86_64 2>/dev/null || true
pkill -9 emulator 2>/dev/null || true
sleep 2

# Restart adb server
adb kill-server && sleep 1 && adb start-server && sleep 2

# Start emulator (must run from SDK emulator directory to find dependencies)
cd $ANDROID_HOME/emulator && ./emulator -avd Nexus_5X_API_30 -no-snapshot-load -no-audio -no-boot-anim &

# Wait for device to appear
echo "Waiting for device to appear..."
adb wait-for-device

# Wait for boot to complete
echo "Waiting for boot to complete..."
until [ "$(adb shell getprop sys.boot_completed 2>/dev/null)" = "1" ]; do
sleep 2
echo -n "."
done
echo ""

# Get device UDID
export DEVICE_UDID=$(adb devices | grep -v "List" | grep "device" | awk '{print $1}' | head -1)

# Verify device is ready
if [ -z "$DEVICE_UDID" ]; then
echo "❌ ERROR: Emulator started but device not found"
exit 1
fi

# Check API level
API_LEVEL=$(adb shell getprop ro.build.version.sdk)
echo "✅ Emulator ready: $DEVICE_UDID (API $API_LEVEL)"
```

**When to use**: Starting Android emulator for testing

**Critical detail**: The emulator command must be run from `$ANDROID_HOME/emulator` directory. Running from other directories causes "Qt library not found" and "qemu-system not found" errors.

**Available emulators**: List with `emulator -list-avds`

---

## 3. Build Patterns

### Sandbox App Build (iOS)
Expand Down
10 changes: 10 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue32526.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<Shell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Maui.Controls.Sample.Issues"
x:Class="Maui.Controls.Sample.Issues.Issue32526"
Title="Issue32526">

<ShellContent ContentTemplate="{DataTemplate local:Issue32526MainPage}" />

</Shell>
79 changes: 79 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue32526.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 32526, "Shell content page title position incorrect/clipped", PlatformAffected.Android)]
public partial class Issue32526 : Shell
{
public Issue32526()
{
InitializeComponent();
}
}

public class Issue32526MainPage : ContentPage
{
public Issue32526MainPage()
{
Title = "MainPage";

// Add a top label on the main page to compare position with the second page
var topLabel = new Label
{
Text = "Top Label - Page 1",
AutomationId = "TopLabelPage1",
BackgroundColor = Colors.LightBlue,
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Start,
Padding = 10
};

var button = new Button
{
Text = "Navigate to Page 2",
AutomationId = "NavigateButton"
};

button.Clicked += async (s, e) =>
{
await Navigation.PushAsync(new Issue32526NewPage());
};

Content = new VerticalStackLayout
{
Spacing = 10,
Children =
{
topLabel,
button
}
};
}
}

public class Issue32526NewPage : ContentPage
{
public Issue32526NewPage()
{
Title = "Page 2";

// Add a label at the top to help verify that content is positioned correctly
// If SafeAreaEdges is not working, content will be clipped under the toolbar
var topLabel = new Label
{
Text = "Top Label - Page 2",
AutomationId = "TopLabelPage2",
BackgroundColor = Colors.Yellow,
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Start,
Padding = 10
};

Content = new VerticalStackLayout
{
Spacing = 10,
Children =
{
topLabel
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue32526 : _IssuesUITest
{
public Issue32526(TestDevice device) : base(device) { }

public override string Issue => "Shell content page title position incorrect/clipped";

[Test]
[Category(UITestCategories.Shell)]
public void ShellNavigationPageTitleNotClipped()
{
// Wait for the main page to load
App.WaitForElement("NavigateButton");
App.WaitForElement("TopLabelPage1");

// Get the position of the top label on Page 1
var topLabelPage1 = App.FindElement("TopLabelPage1");
var rectPage1 = topLabelPage1.GetRect();

// Navigate to the new page
App.Tap("NavigateButton");

// Wait for the second page to appear
App.WaitForElement("TopLabelPage2");

// Get the position of the top label on Page 2
var topLabelPage2 = App.FindElement("TopLabelPage2");
var rectPage2 = topLabelPage2.GetRect();

// The top labels should be at the same Y position on both pages
// If SafeAreaEdges is broken on the second page, the label will be clipped under the toolbar
// and positioned differently than on the first page
Assert.That(rectPage2.Y, Is.EqualTo(rectPage1.Y).Within(5),
$"Top label on Page 2 (Y={rectPage2.Y}) should be at the same position as Page 1 (Y={rectPage1.Y})");

// Both labels should be below the toolbar (not at Y=0 or negative)
Assert.That(rectPage1.Y, Is.GreaterThan(0),
$"Top label on Page 1 should be below the toolbar (Y={rectPage1.Y})");
Assert.That(rectPage2.Y, Is.GreaterThan(0),
$"Top label on Page 2 should be below the toolbar (Y={rectPage2.Y})");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
using Android.Views;
using AndroidX.AppCompat.Widget;
using AndroidX.CoordinatorLayout.Widget;
using AndroidX.Core.View;
using AndroidX.DrawerLayout.Widget;
using AndroidX.Fragment.App;
using Google.Android.Material.AppBar;
using Microsoft.Extensions.Logging;
using AView = Android.Views.View;

namespace Microsoft.Maui.Platform
Expand Down Expand Up @@ -83,7 +85,25 @@ internal void Connect(IView? view, IMauiContext? mauiContext = null)
}

_rootView = navigationLayout;
}
}

if(!OperatingSystem.IsAndroidVersionAtLeast(30))
{
// Dispatches insets to all children recursively (for API < 30)
// This implements Google's workaround for the API 28-29 bug where
// one child consuming insets blocks all siblings from receiving them.
// Based on: https://android-review.googlesource.com/c/platform/frameworks/support/+/3310617
if (_rootView is null)
{
_mauiContext?.CreateLogger<NavigationRootManager>()?.LogWarning(
"NavigationRootManager: _rootView is null when attempting to install compat insets dispatch. " +
"This may cause incorrect window insets behavior on API < 30.");
}
else
{
ViewGroupCompat.InstallCompatInsetsDispatch(_rootView);
}
}

// if the incoming view is a Drawer Layout then the Drawer Layout
// will be the root view and internally handle all if its view management
Expand Down
Loading