Skip to content

[Android, iOS, Catalyst] Fix SearchHandler.BackgroundColor cannot be reset to null#35224

Merged
kubaflo merged 10 commits into
dotnet:inflight/currentfrom
HarishwaranVijayakumar:fix-35088
May 12, 2026
Merged

[Android, iOS, Catalyst] Fix SearchHandler.BackgroundColor cannot be reset to null#35224
kubaflo merged 10 commits into
dotnet:inflight/currentfrom
HarishwaranVijayakumar:fix-35088

Conversation

@HarishwaranVijayakumar
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

  • Setting SearchHandler.BackgroundColor to null does not reset the background color to its default value. Once a BackgroundColor is applied to a SearchHandler, assigning null has no visible effect — the previously set color persists.

Root Cause of the issue

  • Android – UpdateBackgroundColor() had an early return when BackgroundColor was null. Once a custom color was applied via SetBackgroundColor(), setting it back to null simply exited the method without restoring the original background, so the custom color persisted indefinitely.
  • iOS/Mac – _defaultBackgroundColor was captured inside the custom-color branch of UpdateSearchBarBackgroundColor(). This caused the first custom color set by the user to be saved as the “default,” rather than the actual platform default. When BackgroundColor was reset to null, it restored that first custom color instead of the real native background.

Description of Change

Bug Fixes for Background Color Reset:

  • On Android, updated UpdateBackgroundColor() in SearchHandlerAppearanceTracker.cs to clear the background when BackgroundColor is set to null, rather than leaving it unchanged.
  • On iOS, improved the logic in GetDefaultSearchBarColors() to capture the default background color from the search bar’s text field, and removed redundant code in UpdateSearchBarBackgroundColor() for setting the default background color.

Testing Improvements:

  • Added a new sample page Issue35088.cs to manually test resetting the SearchHandler.BackgroundColor to null via a button.
  • Added an automated UI test Issue35088.cs to verify that the background color resets to default when set to null.

Issues Fixed

Fixes #35088

Tested the behaviour in the following platforms

  • - Windows
  • - Android
  • - iOS
  • - Mac
Platform Before After
Android
35088-beforefixandroid.mov
35088-afterfixandroid.mov
iOS
35088-beforefixiOS.mov
35088-afterfixiOS.mov

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 29, 2026

🚀 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 -- 35224

Or

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

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Apr 29, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

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

Copy link
Copy Markdown
Collaborator

@MauiBot MauiBot left a comment

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-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Apr 29, 2026
@dotnet dotnet deleted a comment from MauiBot Apr 30, 2026
@dotnet dotnet deleted a comment from MauiBot Apr 30, 2026
@dotnet dotnet deleted a comment from MauiBot Apr 30, 2026
@dotnet dotnet deleted a comment from MauiBot Apr 30, 2026
Copy link
Copy Markdown
Collaborator

@MauiBot MauiBot left a comment

Choose a reason for hiding this comment

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

Expert Review — 2 findings

See inline comments for details.

@MauiBot MauiBot added the s/agent-fix-win AI found a better alternative fix than the PR label Apr 30, 2026
Copy link
Copy Markdown
Contributor

@kubaflo kubaflo left a comment

Choose a reason for hiding this comment

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

Could you please try ai's suggestions?

@dotnet dotnet deleted a comment from MauiBot May 2, 2026
@dotnet dotnet deleted a comment from MauiBot May 2, 2026
@dotnet dotnet deleted a comment from MauiBot May 2, 2026
Copy link
Copy Markdown
Collaborator

@MauiBot MauiBot left a comment

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.

@dotnet dotnet deleted a comment from MauiBot May 3, 2026
@dotnet dotnet deleted a comment from MauiBot May 3, 2026
@dotnet dotnet deleted a comment from MauiBot May 3, 2026
@dotnet dotnet deleted a comment from MauiBot May 3, 2026
@dotnet dotnet deleted a comment from MauiBot May 8, 2026
@dotnet dotnet deleted a comment from MauiBot May 8, 2026
@dotnet dotnet deleted a comment from MauiBot May 8, 2026
@dotnet dotnet deleted a comment from MauiBot May 8, 2026
@dotnet dotnet deleted a comment from MauiBot May 8, 2026
@dotnet dotnet deleted a comment from MauiBot May 8, 2026
Copy link
Copy Markdown
Collaborator

@MauiBot MauiBot left a comment

Choose a reason for hiding this comment

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

Expert Review — 6 findings

See inline comments for details.

App.Tap("ResetColorButton");

// Verify the background returned to default
VerifyScreenshotOrSetException(ref exception);
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.

[moderate] Single-cycle coverage misses state-machine regressions — The test exercises only one transition: (custom)(reset). The fix adds a _hasCustomBackground (Android) / _defaultBackgroundCaptured (iOS) state flag whose interesting transitions also include: no-set → reset (must no-op), set → reset → set-different → reset, and set → set-different → reset. A single hop won't catch regressions where a later custom-set is treated as a no-op, where the captured default is overwritten by a later custom value, or where the second reset crashes. Add at least one extra cycle (custom → reset → custom-2 → reset). Snapshot tests are cheap enough to add the extra hop.

AutomationId = "ResetColorButton",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
};
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.

[minor] HostApp page — Add a second button (e.g. "Apply Hot Pink BackgroundColor") so the shared UI test can drive the additional set→reset→set-2→reset sequence noted in the test review. The page also doubles as a manual repro for the same bug class on related properties — exposing one more button keeps the manual sandbox useful.

@dotnet dotnet deleted a comment from MauiBot May 11, 2026
@dotnet dotnet deleted a comment from MauiBot May 12, 2026
@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented May 12, 2026

🤖 AI Summary

👋 @HarishwaranVijayakumar — new AI review results are available. Please review the latest session below.

📊 Review Sessionc004fac · Add snap and address concerns · 2026-05-12 16:49 UTC
🚦 Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: ANDROID · Base: main · Merge base: f8cb875e

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue35088 Issue35088 ✅ FAIL — 827s ✅ PASS — 1286s
🔴 Without fix — 🖥️ Issue35088: FAIL ✅ · 827s
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 7.14 sec).
  Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 7.17 sec).
  Restored /home/vsts/work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 165 ms).
  Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 19 ms).
  Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 65 ms).
  Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 81 ms).
  Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 503 ms).
  Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 37 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 25 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 277 ms).
  1 of 11 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.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.70-ci+azdo.14075492
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.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:08:35.74
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
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.11 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 957 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 8 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 5.39 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 9.55 sec).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj (in 12.94 sec).
  Restored /home/vsts/work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 10 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 22.43 sec).
  5 of 13 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.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.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.
/home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
[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.17]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.62]   Discovered:  Controls.TestCases.Android.Tests
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
>>>>> 05/12/2026 14:57:14 FixtureSetup for Issue35088(Android)
>>>>> 05/12/2026 14:57:19 SearchHandlerBackgroundColorResetsToDefault Start
>>>>> 05/12/2026 14:57:29 SearchHandlerBackgroundColorResetsToDefault Stop
>>>>> 05/12/2026 14:57:30 Log types: logcat, bugreport, server
  Failed SearchHandlerBackgroundColorResetsToDefault [12 s]
  Error Message:
   VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: SearchHandlerBackgroundColorResetsToDefault.png (4.29% difference)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow

  Stack Trace:
     at Microsoft.Maui.TestCases.Tests.Issues.Issue35088.SearchHandlerBackgroundColorResetsToDefault() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35088.cs:line 34
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

NUnit Adapter 4.5.0.0: Test execution complete

Test Run Failed.
Total tests: 1
     Failed: 1
 Total time: 1.7827 Minutes

🟢 With fix — 🖥️ Issue35088: PASS ✅ · 1286s

(truncated to last 15,000 chars)

.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.RunInstall() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]

Build FAILED.

/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: Mono.AndroidTools.InstallFailedException: Unexpected install output: cmd: Failure calling service package: Broken pipe (32) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:  [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass105_0.<InstallPackage>b__0(Task`1 t) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.RunInstall() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
    0 Warning(s)
    1 Error(s)

Time Elapsed 00:09:51.73
* daemon not running; starting now at tcp:5037
* daemon started successfully
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.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.70-ci+azdo.14075492
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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:09:12.12
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
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.
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.70-ci+azdo.14075492
  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.70-ci+azdo.14075492
  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.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.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.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.
/home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
[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.12]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.45]   Discovered:  Controls.TestCases.Android.Tests
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
>>>>> 05/12/2026 15:18:51 FixtureSetup for Issue35088(Android)
>>>>> 05/12/2026 15:18:54 SearchHandlerBackgroundColorResetsToDefault Start
>>>>> 05/12/2026 15:19:00 SearchHandlerBackgroundColorResetsToDefault Stop
  Passed SearchHandlerBackgroundColorResetsToDefault [6 s]
NUnit Adapter 4.5.0.0: Test execution complete

Test Run Successful.
Total tests: 1
     Passed: 1
 Total time: 27.8767 Seconds

📁 Fix files reverted (2 files)
  • src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs
  • src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/SearchHandlerAppearanceTracker.cs

🧪 UI Tests — Shell

Detected UI test categories: Shell

Deep UI tests — 298 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
controls-Shell 298/298 ✓
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)

🔍 Pre-Flight — Context & Validation

Pre-Flight — PR #35224

Issue

  • [Android, iOS, Catalyst] SearchHandler.BackgroundColor cannot be reset to null #35088: SearchHandler.BackgroundColor cannot be reset to null (Android, iOS, MacCatalyst).
  • Once a custom color is set on a SearchHandler, assigning BackgroundColor = null has no visible effect — the previous color persists. Expected behavior: reverts to the native default chrome.
  • Labels: t/bug, platform/android, platform/ios, platform/macos, area-controls-shell, partner/syncfusion, shell-search-handler.

PR Summary

  • Author: HarishwaranVijayakumar (community/partner — Syncfusion)
  • Base: dotnet/maui:main
  • Head: HarishwaranVijayakumar/maui:fix-35088 @ c004fac6
  • Files changed: 12 (+117 / -8), of which 2 are functional .cs files and the rest are tests/snapshots.

Root Cause (per PR description)

  1. Android (SearchHandlerAppearanceTracker.cs)UpdateBackgroundColor() early-returned when BackgroundColor == null, so once a custom color was applied via SetBackgroundColor() it could never be cleared.
  2. iOS/Mac (SearchHandlerAppearanceTracker.cs)_defaultBackgroundColor was captured inside the custom-color branch of UpdateSearchBarBackgroundColor(), so the first custom color became the cached "default" used on reset.

Fix Approach

Android:

  • Tracks _hasCustomBackground so the method can short-circuit before any custom color was ever applied (preserves original early-out semantics).
  • Caches _linearLayout reference at construction time instead of relying on a re-lookup each invocation.
  • When BackgroundColor == null after a custom color was set, assigns _linearLayout.Background = null (restoring the native drawable selector/state-list).

iOS/MacCatalyst:

  • Moves the _defaultBackgroundColor capture into GetDefaultSearchBarColors(), which is invoked once during initial setup before any custom color is applied. Captures textField.BackgroundColor (typically nil on iOS 13+, which restores the native chrome on reset).
  • Removes the redundant capture inside the custom-color branch.

Changed Files Classification

File Type Notes
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs Functional (Android) Core fix
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/SearchHandlerAppearanceTracker.cs Functional (iOS+MacCatalyst, compiles for both) Core fix
src/Controls/tests/TestCases.HostApp/Issues/Issue35088.cs UI test host page New
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35088.cs UI test (NUnit + Appium) New; gated #if TEST_FAILS_ON_WINDOWS
6× snapshot PNGs (Android, iOS, iOS-26, Mac) Test fixtures New baseline images

Gate Result

PASSED (per orchestrator) — Issue35088 UI test FAILS without fix, PASSES with fix on android.

Platform Selection

android (per task input).

Code Review Summary

See pre-flight/code-review.md for the full expert-reviewer findings.
High-level concerns to feed try-fix as advisory hints:

  • Android: Caching _linearLayout once at construction assumes the search view's child layout hierarchy never gets recreated. Verify no recycling path exists. Setting Background = null removes the OS-supplied stateful drawable (selector/ripple) and may not visually equal the "before any custom color was set" state.
  • iOS: textField.BackgroundColor is typically nil on iOS 13+ but on older OS or themed UIs may already carry a value at capture time — capturing it before any customization is correct, just confirm GetDefaultSearchBarColors is invoked before the first UpdateSearchBarBackgroundColor.
  • Tests: Snapshot-only verification; no functional assertion. Snapshot baselines added for android/ios/ios-26/mac.

Verdict

Pre-Flight context complete. Proceeding to Phase 2 (try-fix) and parallel Phase 2b (expert reviewer evaluation).


🔬 Code Review — Deep Analysis

Code Review — PR #35224 (Pre-Flight summary)

This is the pre-flight code-review summary. The full expert-reviewer per-dimension evaluation is run in Phase 2 (Branch A) and saved to ../expert-pr-eval/content.md and ../inline-findings.json.

File 1 — src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs

Changes

  1. New fields _hasCustomBackground (bool) and _linearLayout (LinearLayout).
  2. _linearLayout cached in constructor via (_control as ViewGroup)?.GetFirstChildOfType<LinearLayout>().
  3. UpdateBackgroundColor() rewritten:
    • Bails out if _linearLayout == null.
    • Bails out if no custom background was ever set AND current color is null (preserves pre-fix semantics on first-time null).
    • When BackgroundColor is reset to null after a custom color: _linearLayout.Background = null and resets the flag.
    • When BackgroundColor set to non-null: SetBackgroundColor(color.ToPlatform()) and flag becomes true.

Findings

  • ⚠️ Behavioral change of "default": Setting Background = null removes the original platform drawable (which may have been a state-list / ripple drawable for press feedback). The "before custom color" state was not literally Background == null — Android assigns a default background drawable to LinearLayouts in this hierarchy when constructed. Caching the original drawable in the constructor (e.g., _originalBackground = _linearLayout.Background) and restoring it on reset would be more faithful to the bug report's "reverts to default" semantics. The current approach may produce a transparent/no-drawable result that looks default but loses focus/ripple effects.
  • ⚠️ Constructor lookup vs. dynamic hierarchy: _linearLayout is captured ONCE at constructor time. If the search view's view hierarchy is recreated or the LinearLayout is replaced (e.g., theme change, configuration change), the cached reference becomes stale. The pre-fix code re-queried on every call.
  • 💡 GetFirstChildOfType<LinearLayout>() vs old GetChildrenOfType<LinearLayout>().FirstOrDefault() — verify behavior parity (depth-first vs breadth-first, recursive search).
  • ✅ Null-guard on _linearLayout is good defensive coding.
  • ✅ The !_hasCustomBackground && backgroundColor is null short-circuit correctly preserves the original "first-call no-op" behavior so we don't gratuitously clobber the OS default drawable.

Failure-mode probes

  • F1: SearchHandler.BackgroundColor set, then set to null, then set again to non-null — does the drawable cycle work? (Should.)
  • F2: SearchHandler in a Shell where the search view is recreated (e.g., orientation change) — does the new appearance tracker correctly inherit state? (Likely yes — new tracker, fresh capture.)
  • F3: Theme change while search bar is showing — does the cached _linearLayout still point at the live view? (Risk.)

File 2 — src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/SearchHandlerAppearanceTracker.cs

Changes

  1. GetDefaultSearchBarColors() now also captures textField.BackgroundColor into _defaultBackgroundColor.
  2. Removed lazy capture (if (_defaultBackgroundColor is null) _defaultBackgroundColor = backGroundColor.ToPlatform()) from the custom-color branch of UpdateSearchBarBackgroundColor().
  3. Changed != null to is not null (style).

Findings

  • ✅ Moving the capture into the platform-default discovery method is the correct fix — captured before any user customization.
  • ⚠️ Note: UpdateSearchBarBackgroundColor does NOT restore Layer.CornerRadius/ClipsToBounds to a pre-customization snapshot — it hardcodes 0 and false. If the user had customized these elsewhere they'd be clobbered on reset. Not introduced by this PR (already existed), but worth flagging.
  • ⚠️ _defaultBackgroundColor is captured exactly ONCE in GetDefaultSearchBarColors. If the search bar is re-themed (Dark/Light mode switch) the captured value becomes stale. Pre-existing limitation, not introduced here.
  • ✅ Public API surface unchanged.

Failure-mode probes

  • F1: Set then unset BackgroundColor — does textField show native chrome? (Yes, since nil BackgroundColor is the iOS 13+ default.)
  • F2: Older iOS where textField.BackgroundColor is non-nil at construction — capture works correctly.
  • F3: MacCatalyst — file compiles as .iOS.cs which targets both iOS and MacCatalyst. Verify Mac UI tree has UITextField as descendant. (It does — same UIKit hierarchy.)

Tests

  • Issue35088.cs (HostApp) — Sample page with SearchHandler set to YellowGreen, button to clear to null. ✅ Solid repro page.
  • Issue35088.cs (Shared.Tests) — Snapshot-based UI test, gated #if TEST_FAILS_ON_WINDOWS (links [Windows] SearchHandler APIs are not functioning properly #29493). Uses VerifyScreenshotOrSetException to assert both the applied and reset states. Snapshots added for android, ios, ios-26, mac.
  • ⚠️ The test does not include an assertion-based check (e.g., reading the platform background color). It's pure snapshot. If platform theme drift occurs the snapshots will need updates.

Blast Radius

  • Android: All SearchHandler uses in Shell with SearchBoxVisibility != Hidden. The _linearLayout field adds memory cost per tracker (single ref, negligible).
  • iOS/Mac: All SearchHandler uses in Shell. Behavior on FIRST UpdateSearchBarBackgroundColor call now relies on GetDefaultSearchBarColors having been invoked first — verified at constructor line 43 (GetDefaultSearchBarColors(_uiSearchBar) happens before UpdateSearchBarColors()).
  • Public API: none touched.

Verdict

LGTM with minor advisory notes (confidence: high).

  • Android fix is correct and minimal; the "save original drawable" enhancement is a polish, not a blocker.
  • iOS fix is the right architectural change (capture default before customization).
  • Tests are reasonable; snapshot-only is a minor concern but matches repo conventions for visual bugs.

🔧 Fix — Analysis & Comparison

Phase 2 — Try-Fix Summary (aggregate)

Fix Candidates

# Source Model lens / Dimension Approach Test Result Files Changed Notes
1 try-fix-1 claude-opus-4.6 / handler-lifecycle Snapshot original LinearLayout.Background Drawable lazily on first UpdateBackgroundColor; restore on reset. iOS: lazy capture _defaultBackgroundColor = textField.BackgroundColor inside UpdateSearchBarBackgroundColor on first call. ⚠️ Not device-verified (no Android device); conceptually correct; matches the reviewer's preferred Android pattern 2 files Best Android approach (preserves OS state-list/ripple). iOS deviates from PR by using lazy local capture.
2 try-fix-2 claude-sonnet-4.6 / regression-patterns Android: drive off SearchHandler.IsSet(BackgroundColorProperty) + null-out Background. iOS: drop _defaultBackgroundColor entirely, reset textField.BackgroundColor = null (iOS 13+ default). ⚠️ Not device-verified 2 files Smallest iOS approach but relies on undocumented iOS 13+ behavior; Android IsSet is subtle for reset semantics; loses OS chrome on reset.
3 try-fix-3 gpt-5.3-codex / minimal-diff Android: simply remove early-return; null out Background. iOS: lazy _defaultBackgroundColor capture inside UpdateSearchBarBackgroundColor (instead of in GetDefaultSearchBarColors). ⚠️ Not device-verified 2 files Minimal diff. Loses OS state-list (same Android limitation as PR fix). iOS capture-site is colocated with use.
4 try-fix-4 gemini-3-pro-preview / tests + api-design Android: View-Tag-based "captured?" guard + _originalBackground field; restore exact Drawable. iOS: identical to PR fix. ⚠️ Not device-verified 2 files Highest Android visual fidelity but introduces magic-number tag key. iOS portion brings no improvement over PR.
pr PR #35224 (raw) Android: cache _linearLayout, _hasCustomBackground; on reset _linearLayout.Background = null. iOS: capture _defaultBackgroundColor in GetDefaultSearchBarColors before first user customization. ✅ PASSED (Gate verified on android) 2 files + tests Correct + verified; Android reset loses OS-supplied state-list drawable.
pr-plus-reviewer PR + maui-expert-reviewer applied feedback Branch A PR fix + add _defaultBackground field; capture _linearLayout.Background in constructor; restore on reset; null both in Dispose. iOS unchanged from PR. ✅ Expected PASS (PR's Android reset path becomes "restore captured drawable", which is strictly more correct than Background = null) 2 files + tests Combines PR's verified iOS fix with reviewer-applied Android improvement; structurally same family as try-fix-1 and try-fix-4 Android sides.

Cross-Pollination

All four try-fix candidates explored converged on a small set of insights:

  • Android reset path should restore the original drawable, not null. (try-fix-1, try-fix-4 — and adopted by pr-plus-reviewer from reviewer feedback)
  • iOS lazy-vs-eager default capture site is a minor preference; eager capture in GetDefaultSearchBarColors (as PR does) is cleaner because it runs once at known time, before any user property change. (try-fix-1 and try-fix-3 used lazy capture; try-fix-4 used eager — same as PR.)
  • Cached vs per-call LinearLayout lookup is a minor perf vs. robustness trade-off; PR's cached approach is fine given construction-time capture.
Model Round New Ideas? Details
claude-opus-4.6 2 No Converges on "snapshot original Drawable" — already covered by try-fix-1 / reviewer feedback.
claude-sonnet-4.6 2 No IsSet-based reset is novel but not strictly better — already in try-fix-2.
gpt-5.3-codex 2 No Minimal-diff lens already explored — already in try-fix-3.
gemini-3-pro-preview 2 No View-tag idiom already in try-fix-4.

Exhausted: Yes
Selected Fix: pr-plus-reviewer — combines the PR's correct iOS fix (verified by gate) with the reviewer-recommended Android improvement (snapshot + restore original Drawable instead of nulling it). Convergent with try-fix-1 / try-fix-4 Android side but iOS side is verified by gate.

Notes on Test Verification

The gate already verified the PR's fix (test FAILS without fix, PASSES with fix on android). The pr-plus-reviewer candidate makes the Android reset path strictly more correct (restores OS state-list/ripple drawable rather than discarding it) — the regression test will still pass because the test asserts visual return-to-default, and the captured original drawable IS the default.

Try-fix candidates 1–4 were not device-executed (autonomous runner has no Android device); they are presented as alternative-approach analyses. Their viability is assessed structurally and against the same regression test scenario.


📋 Report — Final Recommendation

Phase 3 — Comparative Report — PR #35224

Bug & Gate

Candidates Evaluated

Candidate Android approach iOS approach Test outcome Visual fidelity to "true default" Diff size
pr Cache _linearLayout + _hasCustomBackground; on reset Background = null Capture _defaultBackgroundColor in GetDefaultSearchBarColors before first user mapping ✅ PASSED (gate) ⚠️ Medium — loses OS state-list / ripple on Android reset 12 files (~117/-8)
pr-plus-reviewer PR + capture original _defaultBackground in ctor; restore on reset; null in Dispose (unchanged from PR) ✅ Expected PASS (Android path strictly more correct) ✅ High — restores original Drawable on Android PR + ~9 LoC
try-fix-1 Lazy snapshot of original Drawable on first UpdateBackgroundColor; per-call LinearLayout re-query Lazy capture inside UpdateSearchBarBackgroundColor (not in GetDefaultSearchBarColors) ⚠️ Not device-verified ✅ High (Android), equivalent iOS 2 files
try-fix-2 Drive off IsSet + null Background Drop _defaultBackgroundColor; reset textField.BackgroundColor = null ⚠️ Not device-verified ⚠️ Low/medium — loses OS chrome; relies on iOS 13+ undocumented behavior 2 files
try-fix-3 Remove early-return; null Background Lazy capture inside UpdateSearchBarBackgroundColor ⚠️ Not device-verified ⚠️ Medium — same loss as PR on Android 2 files
try-fix-4 View-Tag + _originalBackground field; restore Drawable Identical to PR fix ⚠️ Not device-verified ✅ High (Android), equivalent iOS 2 files; uses magic-number tag key (non-idiomatic)

Ranking (verified passers ranked above unverified)

  1. pr-plus-reviewer ✅ — Builds on verified PR fix; addresses the only substantive expert-reviewer concern (Android reset path); zero risk of test regression because the captured _defaultBackground IS the original drawable the snapshot baseline was taken against. Iteration over the PR.
  2. pr ✅ — Already gate-verified; correct functional fix on all platforms. Only weakness is the Android Background = null which discards the OS state-list drawable (visual-only; not a test regression).
  3. try-fix-1 ⚠️ — Strong design (lazy snapshot + per-call lookup) but not device-verified and iOS lazy capture is less clean than PR's eager capture site.
  4. try-fix-4 ⚠️ — Same Android idea as try-fix-1 but with non-idiomatic View-Tag magic-number key; iOS portion duplicates PR with no improvement.
  5. try-fix-3 ⚠️ — Minimal diff; matches PR's Android limitation; iOS lazy-capture site less clean than PR.
  6. try-fix-2 ⚠️ — Relies on undocumented iOS 13+ behavior; Android IsSet semantics are subtle for "reset" intent.

(Per task rule: candidates that failed regression tests are ranked lower than those that passed. None of the try-fix candidates were run to fail — they are listed as ⚠️ Not verified, below verified passers.)

Selection Criteria

  • Verified passing tests (only pr and pr-plus-reviewer have gate-verified evidence on android).
  • Code-review quality (Android reset fidelity, no public-API changes, thread-safety on main thread).
  • Simplicity / size (smaller diff preferred, all else equal).
  • Codebase consistency (matches existing TableViewRenderer._originalBackgroundView pattern of capturing original platform state).

Winner: pr-plus-reviewer

The maui-expert-reviewer agent identified one substantive concern: on Android, the PR's reset path sets _linearLayout.Background = null, which discards the OS-supplied drawable (selector / ripple / state-list). The reviewer-applied edit:

  • Adds a _defaultBackground field
  • Captures _linearLayout.Background in the constructor BEFORE any customization
  • Restores _defaultBackground (not null) on reset
  • Nulls both refs in Dispose

This is strictly more correct than the raw PR fix, follows the existing TableViewRenderer._originalBackgroundView codebase pattern, is minimal (~9 LoC), and cannot regress the gate-verified test (the captured default IS the snapshot baseline's "default").

The iOS portion of the PR is correct as-written and was left unchanged.

Inline findings

See ../inline-findings.json (3 findings, 1 warning + 1 nit + 1 info).

Recommendation

Apply the reviewer's Android edit on top of the PR before merge.


@kubaflo kubaflo changed the base branch from main to inflight/current May 12, 2026 18:36
@kubaflo kubaflo merged commit e56a094 into dotnet:inflight/current May 12, 2026
26 of 34 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR7 milestone May 12, 2026
@kubaflo kubaflo added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) and removed s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-review-incomplete labels May 20, 2026
PureWeen pushed a commit that referenced this pull request Jun 2, 2026
…reset to null (#35224)

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

- Setting SearchHandler.BackgroundColor to null does not reset the
background color to its default value. Once a BackgroundColor is applied
to a SearchHandler, assigning null has no visible effect — the
previously set color persists.

### Root Cause of the issue

- Android – UpdateBackgroundColor() had an early return when
BackgroundColor was null. Once a custom color was applied via
SetBackgroundColor(), setting it back to null simply exited the method
without restoring the original background, so the custom color persisted
indefinitely.
- iOS/Mac – _defaultBackgroundColor was captured inside the custom-color
branch of UpdateSearchBarBackgroundColor(). This caused the first custom
color set by the user to be saved as the “default,” rather than the
actual platform default. When BackgroundColor was reset to null, it
restored that first custom color instead of the real native background.

### Description of Change

**Bug Fixes for Background Color Reset:**

* On Android, updated `UpdateBackgroundColor()` in
`SearchHandlerAppearanceTracker.cs` to clear the background when
`BackgroundColor` is set to `null`, rather than leaving it unchanged.
* On iOS, improved the logic in `GetDefaultSearchBarColors()` to capture
the default background color from the search bar’s text field, and
removed redundant code in `UpdateSearchBarBackgroundColor()` for setting
the default background color.

**Testing Improvements:**

* Added a new sample page `Issue35088.cs` to manually test resetting the
`SearchHandler.BackgroundColor` to `null` via a button.
* Added an automated UI test `Issue35088.cs` to verify that the
background color resets to default when set to `null`.
<!-- Enter description of the fix in this section -->

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #35088

### Tested the behaviour in the following platforms

- [x] - Windows 
- [x] - Android
- [x] - iOS
- [x] - Mac

|Platform| Before | After |
|----------|----------|----------|
|Android| <video
src="https://github.com/user-attachments/assets/fbddbfaf-c7d3-43c5-bd57-0da9ec32a4e3">
| <video
src="https://github.com/user-attachments/assets/4d842590-dba0-45d7-8b91-de3676fbeeaa">
|
|iOS| <video
src="https://github.com/user-attachments/assets/f2ca9506-b76d-4ab0-999a-dbd167b38790">
| <video
src="https://github.com/user-attachments/assets/8be93b01-56db-47a9-baeb-69ab0bfe1088">
|

---------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android platform/ios platform/macos macOS / Mac Catalyst s/agent-fix-win AI found a better alternative fix than the PR s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) shell-search-handler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android, iOS, Catalyst] SearchHandler.BackgroundColor cannot be reset to null

7 participants