Skip to content

[Android] Fix crash in Label FormattedText span position recalculation with MaxLines/TailTruncation - #35964

Merged
kubaflo merged 4 commits into
dotnet:inflight/currentfrom
Shalini-Ashokan:fix-35755
Jun 19, 2026
Merged

[Android] Fix crash in Label FormattedText span position recalculation with MaxLines/TailTruncation#35964
kubaflo merged 4 commits into
dotnet:inflight/currentfrom
Shalini-Ashokan:fix-35755

Conversation

@Shalini-Ashokan

Copy link
Copy Markdown
Contributor

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 from this PR and let us know in a comment if this change resolves your issue. Thank you!

Issue Details

Android app crashes when a Label uses FormattedText + MaxLines + TailTruncation with long text.

Root Cause

MaxLines shows only part of the text, but old code still reads positions from the full text.So Android gets an invalid text position and throws IndexOutOfBoundsException.

Description of Change

Added a safety check to use only valid visible text positions. If a span is outside visible range, it is skipped/clamped, so no crash.

Validated the behavior in the following platforms

  • Android
  • Windows
  • iOS
  • Mac

Issues Fixed

Fixes #35755

Output ScreenShot

Before After
35755-BeforeFix.mov
35755-AfterFix.mov

@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35964

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35964"

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Jun 17, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Hey there @@Shalini-Ashokan! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@dotnet-policy-service dotnet-policy-service Bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Jun 17, 2026
@kubaflo

kubaflo commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer -p android

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jun 17, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 3 findings

See inline comments for details.

@MauiBot MauiBot added s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Jun 17, 2026
MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 17, 2026
@kubaflo

kubaflo commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer -p android

@github-actions github-actions Bot added s/agent-review-in-progress AI review is currently running for this PR and removed s/agent-review-in-progress AI review is currently running for this PR labels Jun 18, 2026
@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jun 18, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI Review Summary

@Shalini-Ashokan — new AI review results are available based on this last commit: c9948f8. To request a fresh review after new comments or commits, comment /review rerun.

Gate Passed Code Review Needs Changes Confidence Low Platform Android

Review Sessions — click to expand
Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: ANDROID · Base: main · Merge base: 32d494c2

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue35755 Issue35755 ✅ FAIL — 1544s ✅ PASS — 618s
🔴 Without fix — 🖥️ Issue35755: FAIL ✅ · 1544s
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 521 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 6.4 sec).
  Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 5.95 sec).
  Restored /home/vsts/work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 266 ms).
  Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 23 ms).
  Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 52 ms).
  Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 36 ms).
  Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 1.21 sec).
  Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 39 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 959 ms).
  1 of 11 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:11:22.78
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 1.06 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 1.01 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 6 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 1.74 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 3.53 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 8.9 sec).
  Restored /home/vsts/work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 23 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj (in 2.05 sec).
  5 of 13 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 06/18/2026 22:32:10 FixtureSetup for Issue35755(Android)
>>>>> 06/18/2026 22:32:13 FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash Start
>>>>> 06/18/2026 22:32:32 FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash Stop
>>>>> 06/18/2026 22:32:32 Log types: logcat, bugreport, server
>>>>> 06/18/2026 22:32:33 FixtureSetup for FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash
>>>>> 06/18/2026 22:32:41 Log types: logcat, bugreport, server
  Failed FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash [29 s]
  Error Message:
   The app was expected to be running still, investigate as possible crash
TearDown : The app was expected to be running still, investigate as possible crash
  Stack Trace:
     at UITest.Appium.NUnit.UITestBase.UITestBaseTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 159
   at UITest.Appium.NUnit.UITestBase.TestTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 45

--TearDown
   at UITest.Appium.NUnit.UITestBase.UITestBaseTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 159
   at UITest.Appium.NUnit.UITestBase.TestTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 45

1)    at UITest.Appium.NUnit.UITestBase.UITestBaseTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 159
   at UITest.Appium.NUnit.UITestBase.TestTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 45


NUnit Adapter 4.5.0.0: Test execution complete
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.14]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.54]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35755.trx

Total tests: 1
     Failed: 1
Test Run Failed.
 Total time: 10.9807 Minutes
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35755.trx

🟢 With fix — 🖥️ Issue35755: PASS ✅ · 618s
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:08:12.92
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 06/18/2026 22:43:13 FixtureSetup for Issue35755(Android)
>>>>> 06/18/2026 22:43:15 FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash Start
>>>>> 06/18/2026 22:43:18 FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash Stop
  Passed FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash [3 s]
NUnit Adapter 4.5.0.0: Test execution complete
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.16]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.69]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35755.trx

Test Run Successful.
Total tests: 1
     Passed: 1
 Total time: 16.6064 Seconds
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35755.trx

📁 Fix files reverted (1 files)
  • src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs

UI Tests — Label

Detected UI test categories: Label

Deep UI tests — 97 passed, 0 failed across 1 category on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
Label 97/99 ✓
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)

Pre-Flight — Context & Validation

Issue: #35755 - IndexOutOfBoundsException in RecalculateSpanPositions when a Label uses FormattedText, MaxLines, and TailTruncation
PR: #35964 - Local review branch pr-review-35964
Platforms Affected: Android
Files Changed: 1 implementation, 2 test

Key Findings

  • PR changes Android FormattedStringExtensions.RecalculateSpanPositions so span-region calculation does not ask Android Layout for line bounds beyond the visible/laid-out tail when formatted text is ellipsized by MaxLines + TailTruncation.
  • Gate evidence already exists and was not re-run: Issue35755 fails without the fix and passes with the PR fix on Android.
  • GitHub issue/PR narrative, comments, prior review surfaces, and required-check status were unavailable because gh is unauthenticated in this environment; local diff and existing gate artifacts were used instead.
  • Impacted UI test category: Label.

Code Review Summary

Verdict: NEEDS_CHANGES
Confidence: low
Errors: 1 | Warnings: 0 | Suggestions: 0

Key code review findings:

  • src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs:174 — Hidden tail spans skipped after truncation can retain stale ISpatialElement.Region values from a previous wider layout.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #35964 Clamp span offsets to the last laid-out line and skip spans that start after the visible layout end. ✅ PASSED (Gate) FormattedStringExtensions.cs, Issue35755 UI test files Original PR; code review flagged stale-region risk for skipped spans.

Code Review — Deep Analysis

Code Review — PR #35964

Independent Assessment

What this changes: Android Label formatted-span region recalculation now clamps span processing to the visible Layout range when MaxLines/tail truncation ellipsizes text, preventing GetLineForOffset from being called past the laid-out tail. Adds an Android issue page and UI test.

Inferred motivation: Fix IndexOutOfBoundsException for formatted labels with MaxLines and TailTruncation.

Reconciliation with PR Narrative

Author claims: Unavailable — gh requires authentication.
Agreement/disagreement: Local diff supports the inferred crash-fix intent.

Prior Review Reconciliation

GitHub review surfaces unavailable due missing gh auth:

  • top-level reviews: unavailable
  • inline review comments: unavailable
  • PR issue comments: unavailable

Blast Radius Assessment

  • Runs for all instances: Yes, for Android formatted Label layout recalculation.
  • Startup impact: No.
  • Static/shared state: No.

CI Status

  • Required-check result: unavailable
  • Classification: undetermined — gh pr checks --required failed with auth error.
  • Action taken: confidence capped low; no LGTM. git diff --check origin/main...HEAD passed.

Findings

❌ Error — Hidden tail spans can keep stale gesture regions

src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs:174

When a span starts at/after layoutEndOffset, the new continue skips recalculation but does not clear that Span's existing ISpatialElement.Region. If the same formatted label was previously laid out wide enough for the span to be visible, then later narrowed or truncated, hit-testing can still find the stale region and invoke gestures for text that is no longer visible. Clear the span region before continuing.

Failure-Mode Probing

  • Label first visible, then narrowed: skipped tail spans retain old regions.
  • Initial layout already truncated: default region likely contains nothing, so no stale hit target.
  • Empty/no layout lines: guarded by lastLayoutLine < 0.
  • Handler reconnect/layout repeat: no subscriptions added by this change.

Verdict: NEEDS_CHANGES

Confidence: low — GitHub narrative, prior reviews, and CI were unavailable due authentication.
Summary: The crash fix is directionally sound, but skipped ellipsized spans should clear stale hit-test regions before merge.


Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix-1 Line-bounded iteration guard: keep original span offsets but restrict rectangle generation to actual Layout.LineCount bounds. ❌ FAIL 1 file App still crashed after tap; bounding GetLineBounds is too late because hidden offsets still enter earlier Layout APIs.
2 try-fix-2 Visible-line intersection scan: iterate laid-out lines and intersect span ranges with each line's visible range. ✅ PASS 1 file Robust and clears hidden regions, but scans each visible line for each span.
3 try-fix-3 Ellipsis-aware visible intervals: precompute line visible ranges using TailTruncation ellipsis metadata and process spans with a monotonic line cursor. ✅ PASS 1 file Addresses stale hidden regions and avoids repeated full-line scans; relies on Android ellipsis metadata semantics.
PR PR #35964 Clamp span offsets to the last laid-out line and skip spans starting after the visible layout end. ✅ PASSED (Gate) 3 files Original PR; pre-flight code review flagged stale hidden-span region risk.

Cross-Pollination

Model/Reviewer Round New Ideas? Details
maui-expert-reviewer 1 Yes Proposed line-bounded guard, visible-line intersection, and ellipsis-aware visible cutoff alternatives.
maui-expert-reviewer 2 Yes After try-fix-1 failed and try-fix-2 passed, recommended an ellipsis-aware visible-interval candidate with a monotonic line cursor.

Iteration Narrative

  • try-fix-1 failed. It proved that guarding only the final line-bound iteration does not prevent the original crash path; hidden offsets must be filtered before offset-to-line/layout APIs are used.
  • try-fix-2 passed. It is the most defensive algorithm because it only calls line APIs with known-valid line indexes and resets hidden spans to empty regions.
  • try-fix-3 passed. It is the strongest alternative candidate because it preserves try-fix-2's hidden-span safety, directly uses Android ellipsis metadata, and avoids full line scanning for every span.

Exhausted: Yes — the meaningfully different approaches were offset-loop bounding, visible-line scanning, and ellipsis-aware visible intervals. Remaining variations would be small reshuffles of those strategies.

Selected Fix: Candidate #3 — it passes the Android regression test and is demonstrably stronger than the PR fix on the stale-region concern identified by code review. Candidate #2 is a lower-concept-risk backup if maintainers prefer avoiding ellipsis metadata, at the cost of more repeated scanning.


Report — Final Recommendation

Comparative Fix Report — PR #35964

Candidates

Rank Candidate Regression result Assessment
1 try-fix-3 ✅ PASS Best overall. It precomputes Android visible intervals, trims tail-truncated lines using ellipsis metadata, intersects spans against laid-out visible ranges, avoids hidden-offset Layout lookups, and naturally clears hidden spans by assigning an empty region.
2 try-fix-2 ✅ PASS Correct and defensive. It never converts hidden offsets to line indexes and clears hidden spans, but it scans every visible line for every span, making it less efficient than try-fix-3.
3 pr-plus-reviewer ✅ Expected PASS from PR gate + non-invasive reviewer fix Better than the raw PR because it clears fully hidden skipped spans. It remains narrower than the try-fix candidates because it keeps the PR's layout-end clamping model rather than computing explicit visible intervals for every line.
4 pr ✅ PASS Fixes the reported crash, but failed expert review because skipped hidden tail spans can retain stale hit-test regions from a previous wider layout.
5 try-fix-1 ❌ FAIL Ranked below all passing candidates as required. It bounded only the final line-bound iteration; hidden offsets still reached earlier Android layout APIs and the regression still crashed.

Key comparison

The raw PR and pr-plus-reviewer are minimal fixes around the original offset-to-line algorithm. pr-plus-reviewer addresses the expert reviewer's actionable stale-region feedback, but the approach still reasons from a single layoutEndOffset and clamps span endpoints afterward.

try-fix-2 and try-fix-3 are more robust because they invert the algorithm: they only inspect actual laid-out lines and then intersect spans with visible line ranges. try-fix-3 is preferred over try-fix-2 because it keeps that safety property while avoiding a full line scan for every span and handling tail-truncation visibility with Android ellipsis metadata.

Winner

Winner: try-fix-3

try-fix-3 passed the Android regression test, addresses the expert reviewer's stale-region concern, avoids the failed hidden-offset path proven by try-fix-1, and is more efficient than try-fix-2. Because it is not the submitted PR fix, winner.json includes its unified diff as the required candidate diff.


Future Action — alternative fix proposed (try-fix-3)

Automated review — alternative fix proposed

The expert-reviewer evaluation compared the PR fix against automatically generated candidates and selected try-fix-3 as the strongest fix.

Why: try-fix-3 passed the Android regression test, avoids hidden-offset Android Layout calls, clears hidden span regions by assigning empty regions, and is more efficient than the other passing visible-line scan candidate. It ranks above the raw PR and pr-plus-reviewer because it addresses the stale-region issue and computes span regions from explicit visible line intervals.

Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.

Candidate diff (try-fix-3)
diff --git a/src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs b/src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs
index f60a47dc86..268aeb073e 100644
--- a/src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs
+++ b/src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs
@@ -126,6 +126,24 @@ namespace Microsoft.Maui.Controls.Platform
 			if (layout == null)
 				return;
 
+			var lineCount = layout.LineCount;
+			if (lineCount <= 0)
+				return;
+
+			var lineStarts = new int[lineCount];
+			var lineVisibleEnds = new int[lineCount];
+			for (var line = 0; line < lineCount; line++)
+			{
+				var lineStart = layout.GetLineStart(line);
+				var visibleEnd = layout.GetLineVisibleEnd(line);
+
+				if (element.LineBreakMode == LineBreakMode.TailTruncation && layout.GetEllipsisCount(line) > 0)
+					visibleEnd = Math.Min(visibleEnd, lineStart + layout.GetEllipsisStart(line));
+
+				lineStarts[line] = lineStart;
+				lineVisibleEnds[line] = Math.Max(lineStart, visibleEnd);
+			}
+
 			int next = 0;
 			int count = 0;
 
@@ -136,6 +154,7 @@ namespace Microsoft.Maui.Controls.Platform
 #pragma warning disable CA1416
 			var strlen = spannableString.Length();
 #pragma warning restore CA1416
+			var firstCandidateLine = 0;
 
 			for (int i = 0; i < strlen; i = next)
 			{
@@ -163,30 +182,30 @@ namespace Microsoft.Maui.Controls.Platform
 				var spanStartOffset = spannableString.GetSpanStart(startSpan);
 				var spanEndOffset = spannableString.GetSpanEnd(endSpan);
 
-				var spanStartLine = layout.GetLineForOffset(spanStartOffset);
-				var spanEndLine = layout.GetLineForOffset(spanEndOffset);
+				while (firstCandidateLine < lineCount && lineVisibleEnds[firstCandidateLine] <= spanStartOffset)
+					firstCandidateLine++;
 
 				// Go through all lines that are affected by the span and calculate a rectangle for each
 				List<Graphics.Rect> spanRectangles = new List<Graphics.Rect>();
-				for (var curLine = spanStartLine; curLine <= spanEndLine; curLine++)
+				for (var curLine = firstCandidateLine; curLine < lineCount && lineStarts[curLine] < spanEndOffset; curLine++)
 				{
+					var lineStartOffset = lineStarts[curLine];
+					var lineVisibleEndOffset = lineVisibleEnds[curLine];
+					if (lineVisibleEndOffset <= lineStartOffset)
+						continue;
+
+					var startOffset = Math.Max(spanStartOffset, lineStartOffset);
+					var endOffset = Math.Min(spanEndOffset, lineVisibleEndOffset);
+					if (endOffset <= startOffset)
+						continue;
+
 					global::Android.Graphics.Rect bounds = new global::Android.Graphics.Rect();
 					layout.GetLineBounds(curLine, bounds);
 
 					var lineHeight = bounds.Height();
-					var lineStartOffset = layout.GetLineStart(curLine);
 
-					// Retrieve the offset of the last visible character on the current line.
-					// The method `GetLineVisibleEnd(curLine)` returns the position right after the last visible character on the line.
-					// To get the exact offset of the last visible character, subtract 1 from this position.
-					var lineVisibleEndOffset = layout.GetLineVisibleEnd(curLine) - 1;
-
-					var startOffset = (curLine == spanStartLine) ? spanStartOffset : lineStartOffset;
 					var spanStartX = (int)layout.GetPrimaryHorizontal(startOffset);
-
-					var endOffset = (curLine == spanEndLine) ? spanEndOffset : lineVisibleEndOffset;
-					var validEndOffset = System.Math.Min(endOffset, layout.GetLineEnd(curLine));
-					var spanEndX = (int)layout.GetSecondaryHorizontal(validEndOffset);
+					var spanEndX = (int)layout.GetSecondaryHorizontal(endOffset);
 
 					var spanWidth = spanEndX - spanStartX;
 					var spanLeftX = spanStartX;

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 18, 2026
@sheiksyedm
sheiksyedm marked this pull request as ready for review June 19, 2026 09:33
@sheiksyedm

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 2 pipeline(s).

@Shalini-Ashokan

Copy link
Copy Markdown
Contributor Author

AI Review Summary

@Shalini-Ashokan — new AI review results are available based on this last commit: c9948f8. To request a fresh review after new comments or commits, comment /review rerun.

Gate Passed Code Review Needs Changes Confidence Low Platform Android

Review Sessions — click to expand

Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: ANDROID · Base: main · Merge base: 32d494c2

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue35755 Issue35755 ✅ FAIL — 1544s ✅ PASS — 618s
🔴 Without fix — 🖥️ Issue35755: FAIL ✅ · 1544s

  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 521 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 6.4 sec).
  Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 5.95 sec).
  Restored /home/vsts/work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 266 ms).
  Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 23 ms).
  Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 52 ms).
  Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 36 ms).
  Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 1.21 sec).
  Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 39 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 959 ms).
  1 of 11 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:11:22.78
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 1.06 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 1.01 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 6 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 1.74 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 3.53 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 8.9 sec).
  Restored /home/vsts/work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 23 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj (in 2.05 sec).
  5 of 13 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 06/18/2026 22:32:10 FixtureSetup for Issue35755(Android)
>>>>> 06/18/2026 22:32:13 FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash Start
>>>>> 06/18/2026 22:32:32 FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash Stop
>>>>> 06/18/2026 22:32:32 Log types: logcat, bugreport, server
>>>>> 06/18/2026 22:32:33 FixtureSetup for FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash
>>>>> 06/18/2026 22:32:41 Log types: logcat, bugreport, server
  Failed FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash [29 s]
  Error Message:
   The app was expected to be running still, investigate as possible crash
TearDown : The app was expected to be running still, investigate as possible crash
  Stack Trace:
     at UITest.Appium.NUnit.UITestBase.UITestBaseTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 159
   at UITest.Appium.NUnit.UITestBase.TestTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 45

--TearDown
   at UITest.Appium.NUnit.UITestBase.UITestBaseTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 159
   at UITest.Appium.NUnit.UITestBase.TestTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 45

1)    at UITest.Appium.NUnit.UITestBase.UITestBaseTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 159
   at UITest.Appium.NUnit.UITestBase.TestTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 45


NUnit Adapter 4.5.0.0: Test execution complete
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.14]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.54]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35755.trx

Total tests: 1
     Failed: 1
Test Run Failed.
 Total time: 10.9807 Minutes
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35755.trx

🟢 With fix — 🖥️ Issue35755: PASS ✅ · 618s

  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:08:12.92
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14422121
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 06/18/2026 22:43:13 FixtureSetup for Issue35755(Android)
>>>>> 06/18/2026 22:43:15 FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash Start
>>>>> 06/18/2026 22:43:18 FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash Stop
  Passed FormattedTextWithMaxLinesAndTailTruncationShouldNotCrash [3 s]
NUnit Adapter 4.5.0.0: Test execution complete
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.16]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.69]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35755.trx

Test Run Successful.
Total tests: 1
     Passed: 1
 Total time: 16.6064 Seconds
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35755.trx

📁 Fix files reverted (1 files)

  • src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs

UI Tests — Label

Detected UI test categories: Label

Deep UI tests — 97 passed, 0 failed across 1 category on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
Label 97/99 ✓ —
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)
Pre-Flight — Context & Validation

Issue: #35755 - IndexOutOfBoundsException in RecalculateSpanPositions when a Label uses FormattedText, MaxLines, and TailTruncation PR: #35964 - Local review branch pr-review-35964 Platforms Affected: Android Files Changed: 1 implementation, 2 test

Key Findings

  • PR changes Android FormattedStringExtensions.RecalculateSpanPositions so span-region calculation does not ask Android Layout for line bounds beyond the visible/laid-out tail when formatted text is ellipsized by MaxLines + TailTruncation.
  • Gate evidence already exists and was not re-run: Issue35755 fails without the fix and passes with the PR fix on Android.
  • GitHub issue/PR narrative, comments, prior review surfaces, and required-check status were unavailable because gh is unauthenticated in this environment; local diff and existing gate artifacts were used instead.
  • Impacted UI test category: Label.

Code Review Summary

Verdict: NEEDS_CHANGES Confidence: low Errors: 1 | Warnings: 0 | Suggestions: 0

Key code review findings:

  • src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs:174 — Hidden tail spans skipped after truncation can retain stale ISpatialElement.Region values from a previous wider layout.

Fix Candidates

Source Approach Test Result Files Changed Notes

PR PR #35964 Clamp span offsets to the last laid-out line and skip spans that start after the visible layout end. ✅ PASSED (Gate) FormattedStringExtensions.cs, Issue35755 UI test files Original PR; code review flagged stale-region risk for skipped spans.
Code Review — Deep Analysis

Code Review — PR #35964

Independent Assessment

What this changes: Android Label formatted-span region recalculation now clamps span processing to the visible Layout range when MaxLines/tail truncation ellipsizes text, preventing GetLineForOffset from being called past the laid-out tail. Adds an Android issue page and UI test.

Inferred motivation: Fix IndexOutOfBoundsException for formatted labels with MaxLines and TailTruncation.

Reconciliation with PR Narrative

Author claims: Unavailable — gh requires authentication. Agreement/disagreement: Local diff supports the inferred crash-fix intent.

Prior Review Reconciliation

GitHub review surfaces unavailable due missing gh auth:

  • top-level reviews: unavailable
  • inline review comments: unavailable
  • PR issue comments: unavailable

Blast Radius Assessment

  • Runs for all instances: Yes, for Android formatted Label layout recalculation.
  • Startup impact: No.
  • Static/shared state: No.

CI Status

  • Required-check result: unavailable
  • Classification: undetermined — gh pr checks --required failed with auth error.
  • Action taken: confidence capped low; no LGTM. git diff --check origin/main...HEAD passed.

Findings

❌ Error — Hidden tail spans can keep stale gesture regions

src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs:174

When a span starts at/after layoutEndOffset, the new continue skips recalculation but does not clear that Span's existing ISpatialElement.Region. If the same formatted label was previously laid out wide enough for the span to be visible, then later narrowed or truncated, hit-testing can still find the stale region and invoke gestures for text that is no longer visible. Clear the span region before continuing.

Failure-Mode Probing

  • Label first visible, then narrowed: skipped tail spans retain old regions.
  • Initial layout already truncated: default region likely contains nothing, so no stale hit target.
  • Empty/no layout lines: guarded by lastLayoutLine < 0.
  • Handler reconnect/layout repeat: no subscriptions added by this change.

Verdict: NEEDS_CHANGES

Confidence: low — GitHub narrative, prior reviews, and CI were unavailable due authentication. Summary: The crash fix is directionally sound, but skipped ellipsized spans should clear stale hit-test regions before merge.

Fix — Analysis & Comparison

Fix Candidates

Source Approach Test Result Files Changed Notes

1 try-fix-1 Line-bounded iteration guard: keep original span offsets but restrict rectangle generation to actual Layout.LineCount bounds. ❌ FAIL 1 file App still crashed after tap; bounding GetLineBounds is too late because hidden offsets still enter earlier Layout APIs.
2 try-fix-2 Visible-line intersection scan: iterate laid-out lines and intersect span ranges with each line's visible range. ✅ PASS 1 file Robust and clears hidden regions, but scans each visible line for each span.
3 try-fix-3 Ellipsis-aware visible intervals: precompute line visible ranges using TailTruncation ellipsis metadata and process spans with a monotonic line cursor. ✅ PASS 1 file Addresses stale hidden regions and avoids repeated full-line scans; relies on Android ellipsis metadata semantics.
PR PR #35964 Clamp span offsets to the last laid-out line and skip spans starting after the visible layout end. ✅ PASSED (Gate) 3 files Original PR; pre-flight code review flagged stale hidden-span region risk.

Cross-Pollination

Model/Reviewer Round New Ideas? Details
maui-expert-reviewer 1 Yes Proposed line-bounded guard, visible-line intersection, and ellipsis-aware visible cutoff alternatives.
maui-expert-reviewer 2 Yes After try-fix-1 failed and try-fix-2 passed, recommended an ellipsis-aware visible-interval candidate with a monotonic line cursor.

Iteration Narrative

  • try-fix-1 failed. It proved that guarding only the final line-bound iteration does not prevent the original crash path; hidden offsets must be filtered before offset-to-line/layout APIs are used.
  • try-fix-2 passed. It is the most defensive algorithm because it only calls line APIs with known-valid line indexes and resets hidden spans to empty regions.
  • try-fix-3 passed. It is the strongest alternative candidate because it preserves try-fix-2's hidden-span safety, directly uses Android ellipsis metadata, and avoids full line scanning for every span.

Exhausted: Yes — the meaningfully different approaches were offset-loop bounding, visible-line scanning, and ellipsis-aware visible intervals. Remaining variations would be small reshuffles of those strategies.

Selected Fix: Candidate #3 — it passes the Android regression test and is demonstrably stronger than the PR fix on the stale-region concern identified by code review. Candidate #2 is a lower-concept-risk backup if maintainers prefer avoiding ellipsis metadata, at the cost of more repeated scanning.

Report — Final Recommendation

Comparative Fix Report — PR #35964

Candidates

Rank Candidate Regression result Assessment
1 try-fix-3 ✅ PASS Best overall. It precomputes Android visible intervals, trims tail-truncated lines using ellipsis metadata, intersects spans against laid-out visible ranges, avoids hidden-offset Layout lookups, and naturally clears hidden spans by assigning an empty region.
2 try-fix-2 ✅ PASS Correct and defensive. It never converts hidden offsets to line indexes and clears hidden spans, but it scans every visible line for every span, making it less efficient than try-fix-3.
3 pr-plus-reviewer ✅ Expected PASS from PR gate + non-invasive reviewer fix Better than the raw PR because it clears fully hidden skipped spans. It remains narrower than the try-fix candidates because it keeps the PR's layout-end clamping model rather than computing explicit visible intervals for every line.
4 pr ✅ PASS Fixes the reported crash, but failed expert review because skipped hidden tail spans can retain stale hit-test regions from a previous wider layout.
5 try-fix-1 ❌ FAIL Ranked below all passing candidates as required. It bounded only the final line-bound iteration; hidden offsets still reached earlier Android layout APIs and the regression still crashed.

Key comparison

The raw PR and pr-plus-reviewer are minimal fixes around the original offset-to-line algorithm. pr-plus-reviewer addresses the expert reviewer's actionable stale-region feedback, but the approach still reasons from a single layoutEndOffset and clamps span endpoints afterward.

try-fix-2 and try-fix-3 are more robust because they invert the algorithm: they only inspect actual laid-out lines and then intersect spans with visible line ranges. try-fix-3 is preferred over try-fix-2 because it keeps that safety property while avoiding a full line scan for every span and handling tail-truncation visibility with Android ellipsis metadata.

Winner

Winner: try-fix-3

try-fix-3 passed the Android regression test, addresses the expert reviewer's stale-region concern, avoids the failed hidden-offset path proven by try-fix-1, and is more efficient than try-fix-2. Because it is not the submitted PR fix, winner.json includes its unified diff as the required candidate diff.

Future Action — alternative fix proposed (try-fix-3)

try-fix-3 rewrites working code unnecessarily. It removes a safety guard that can cause crashes on OEM devices and always allocates two int[] arrays, even for non-truncated labels. This can lead to memory leak issues.

@kubaflo
kubaflo changed the base branch from main to inflight/current June 19, 2026 13:22
@kubaflo
kubaflo merged commit 71e7d79 into dotnet:inflight/current Jun 19, 2026
156 of 165 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR9 milestone Jun 19, 2026
PureWeen pushed a commit that referenced this pull request Jun 22, 2026
…n with MaxLines/TailTruncation (#35964)

<!-- 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!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->


### Issue Details
Android app crashes when a Label uses FormattedText + MaxLines +
TailTruncation with long text.

### Root Cause
MaxLines shows only part of the text, but old code still reads positions
from the full text.So Android gets an invalid text position and throws
IndexOutOfBoundsException.

### Description of Change
Added a safety check to use only valid visible text positions. If a span
is outside visible range, it is skipped/clamped, so no crash.

Validated the behavior in the following platforms
 
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac
 
### Issues Fixed
  
Fixes #35755

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/ff85b136-8472-47c6-8ade-d4cbf185065c"
>| <video
src="https://github.com/user-attachments/assets/9a971d43-4b8c-4f73-8641-f0fd1cc897da">|
kubaflo pushed a commit that referenced this pull request Jun 25, 2026
…n with MaxLines/TailTruncation (#35964)

<!-- 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!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->


### Issue Details
Android app crashes when a Label uses FormattedText + MaxLines +
TailTruncation with long text.

### Root Cause
MaxLines shows only part of the text, but old code still reads positions
from the full text.So Android gets an invalid text position and throws
IndexOutOfBoundsException.

### Description of Change
Added a safety check to use only valid visible text positions. If a span
is outside visible range, it is skipped/clamped, so no crash.

Validated the behavior in the following platforms
 
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac
 
### Issues Fixed
  
Fixes #35755

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/ff85b136-8472-47c6-8ade-d4cbf185065c"
>| <video
src="https://github.com/user-attachments/assets/9a971d43-4b8c-4f73-8641-f0fd1cc897da">|
kubaflo pushed a commit that referenced this pull request Jul 3, 2026
…n with MaxLines/TailTruncation (#35964)

<!-- 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!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->


### Issue Details
Android app crashes when a Label uses FormattedText + MaxLines +
TailTruncation with long text.

### Root Cause
MaxLines shows only part of the text, but old code still reads positions
from the full text.So Android gets an invalid text position and throws
IndexOutOfBoundsException.

### Description of Change
Added a safety check to use only valid visible text positions. If a span
is outside visible range, it is skipped/clamped, so no crash.

Validated the behavior in the following platforms
 
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac
 
### Issues Fixed
  
Fixes #35755

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/ff85b136-8472-47c6-8ade-d4cbf185065c"
>| <video
src="https://github.com/user-attachments/assets/9a971d43-4b8c-4f73-8641-f0fd1cc897da">|
@kubaflo kubaflo mentioned this pull request Jul 6, 2026
kubaflo pushed a commit that referenced this pull request Jul 6, 2026
…n with MaxLines/TailTruncation (#35964)

<!-- 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!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->


### Issue Details
Android app crashes when a Label uses FormattedText + MaxLines +
TailTruncation with long text.

### Root Cause
MaxLines shows only part of the text, but old code still reads positions
from the full text.So Android gets an invalid text position and throws
IndexOutOfBoundsException.

### Description of Change
Added a safety check to use only valid visible text positions. If a span
is outside visible range, it is skipped/clamped, so no crash.

Validated the behavior in the following platforms
 
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac
 
### Issues Fixed
  
Fixes #35755

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/ff85b136-8472-47c6-8ade-d4cbf185065c"
>| <video
src="https://github.com/user-attachments/assets/9a971d43-4b8c-4f73-8641-f0fd1cc897da">|
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…n with MaxLines/TailTruncation (#35964)

<!-- 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!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->


### Issue Details
Android app crashes when a Label uses FormattedText + MaxLines +
TailTruncation with long text.

### Root Cause
MaxLines shows only part of the text, but old code still reads positions
from the full text.So Android gets an invalid text position and throws
IndexOutOfBoundsException.

### Description of Change
Added a safety check to use only valid visible text positions. If a span
is outside visible range, it is skipped/clamped, so no crash.

Validated the behavior in the following platforms
 
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac
 
### Issues Fixed
  
Fixes #35755

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/ff85b136-8472-47c6-8ade-d4cbf185065c"
>| <video
src="https://github.com/user-attachments/assets/9a971d43-4b8c-4f73-8641-f0fd1cc897da">|
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…n with MaxLines/TailTruncation (#35964)

<!-- 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!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->


### Issue Details
Android app crashes when a Label uses FormattedText + MaxLines +
TailTruncation with long text.

### Root Cause
MaxLines shows only part of the text, but old code still reads positions
from the full text.So Android gets an invalid text position and throws
IndexOutOfBoundsException.

### Description of Change
Added a safety check to use only valid visible text positions. If a span
is outside visible range, it is skipped/clamped, so no crash.

Validated the behavior in the following platforms
 
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac
 
### Issues Fixed
  
Fixes #35755

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/ff85b136-8472-47c6-8ade-d4cbf185065c"
>| <video
src="https://github.com/user-attachments/assets/9a971d43-4b8c-4f73-8641-f0fd1cc897da">|
kubaflo pushed a commit that referenced this pull request Jul 10, 2026
…n with MaxLines/TailTruncation (#35964)

<!-- 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!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->


### Issue Details
Android app crashes when a Label uses FormattedText + MaxLines +
TailTruncation with long text.

### Root Cause
MaxLines shows only part of the text, but old code still reads positions
from the full text.So Android gets an invalid text position and throws
IndexOutOfBoundsException.

### Description of Change
Added a safety check to use only valid visible text positions. If a span
is outside visible range, it is skipped/clamped, so no crash.

Validated the behavior in the following platforms
 
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac
 
### Issues Fixed
  
Fixes #35755

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/ff85b136-8472-47c6-8ade-d4cbf185065c"
>| <video
src="https://github.com/user-attachments/assets/9a971d43-4b8c-4f73-8641-f0fd1cc897da">|
kubaflo pushed a commit that referenced this pull request Jul 15, 2026
…n with MaxLines/TailTruncation (#35964)

<!-- 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!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->


### Issue Details
Android app crashes when a Label uses FormattedText + MaxLines +
TailTruncation with long text.

### Root Cause
MaxLines shows only part of the text, but old code still reads positions
from the full text.So Android gets an invalid text position and throws
IndexOutOfBoundsException.

### Description of Change
Added a safety check to use only valid visible text positions. If a span
is outside visible range, it is skipped/clamped, so no crash.

Validated the behavior in the following platforms
 
- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac
 
### Issues Fixed
  
Fixes #35755

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/ff85b136-8472-47c6-8ade-d4cbf185065c"
>| <video
src="https://github.com/user-attachments/assets/9a971d43-4b8c-4f73-8641-f0fd1cc897da">|
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 20, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-label Label, Span community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android] IndexOutOfBoundsException in RecalculateSpanPositions when Label uses FormattedText + MaxLines + TailTruncation

5 participants