[iOS] Fix Picker CharacterSpacing lost after item selection when Title is set#34974
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://github.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34974Or
iex "& { $(irm https://github.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34974" |
There was a problem hiding this comment.
Pull request overview
Fixes an iOS/MacCatalyst regression where Picker.CharacterSpacing is lost after an item is selected when Title is set, by re-applying kerning after the native text is assigned.
Changes:
- Re-apply
CharacterSpacingafterplatformPicker.Textis set during selection updates (both programmatic and “Done” selection paths). - Add an iOS device test to validate
CharacterSpacingis preserved acrossSelectedIndexupdates.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/Core/tests/DeviceTests/Handlers/Picker/PickerHandlerTests.iOS.cs | Adds a device test asserting character spacing is preserved when SelectedIndex changes programmatically. |
| src/Core/src/Platform/iOS/PickerExtensions.cs | Ensures UpdatePicker always re-applies character spacing after setting Text. |
| src/Core/src/Handlers/Picker/PickerHandler.iOS.cs | Re-applies character spacing after assigning Text in the “Done button” selection flow. |
kubaflo
left a comment
There was a problem hiding this comment.
Could you please try the ai's suggestions?
…ability (#35133) <!-- 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! > **Depends on #35136** (pipeline category detection — should merge first) ## What this does Two things: ### 1. UI test category detection in PR review During the PR review workflow, Step 0.5 detects which UI test categories the PR impacts and writes the result to the AI summary comment. This gives reviewers visibility into which UI tests are relevant. **Detection** reuses the 3-tier script from #35136 (test attributes → source paths → AI reasoning). **AI summary** shows a new 🧪 UI Tests section with detected categories before the gate section. ### 2. Gate reliability fixes Multiple fixes to make the gate (`verify-tests-fail.ps1`) more deterministic: | Fix | Problem it solves | |-----|-------------------| | **Absolute path resolution** | Gate scripts not found on Linux CI agents (`Resolve-Path`, `GetFullPath`) | | **File existence check** | Instant cryptic failure when verify script is missing — now logs clear error | | **3x retry on ENV ERROR** | Emulator timeouts, ADB failures, app crashes — transient issues that pass on retry | | **Strip bad report blocks** | Old verify script produces `Passed: False` with empty counts — stripped instead of shown | | **Gate log in fallback** | When report is missing, shows last 20 lines of gate output instead of just `❌ FAILED / Platform: IOS` | ## Files | File | Changes | |------|---------| | `.github/scripts/Review-PR.ps1` | Step 0.5 category detection + all 5 gate fixes | | `.github/scripts/post-ai-summary-comment.ps1` | Add `uitests` phase to render detected categories | | `.github/pr-review/pr-preflight.md` | Step 7: AI identifies impacted UI test categories | ## Validation — PR reviewer builds (Apr 26) 10 builds against real PRs — all succeeded ✅. Category detection shown in AI summary comment. | PR | Categories Detected | Build | AI Summary | |----|-------------------|-------|------------| | #35037 (WebView theme) | `ViewBaseTests,WebView` | [13940071](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940071) | [comment](#35037 (comment)) | | #35031 (Shell memory leak) | `Shell` | [13940072](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940072) | [comment](#35031 (comment)) | | #35020 (XAML Hot Reload) | _(none — XAML only)_ | [13940073](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940073) | ✅ Shows "No UI test categories" | | #35008 (Shell SearchHandler) | `Shell` | [13940074](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940074) | ✅ | | #34997 (RadioButton gradient) | `RadioButton,ViewBaseTests` | [13940075](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940075) | ✅ | | #34980 (DatePicker rotation) | `ViewBaseTests` | [13940076](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940076) | ✅ | | #34974 (Picker CharacterSpacing) | `ViewBaseTests` | [13940077](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940077) | ✅ | | #34923 (SwipeView threshold) | `SwipeView,ViewBaseTests` | [13940078](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940078) | ✅ | | #34907 (CollectionView ScrollTo) | `CollectionView` | [13940079](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940079) | ✅ | | #34845 (RefreshView binding) | `RefreshView,ViewBaseTests` | [13940080](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940080) | ✅ | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 1 findings
See inline comments for details.
🤖 AI Summary
📊 Review Session —
|
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
📱 PickerHandlerTests (SelectedIndexDoesNotAffectCharacterSpacing, SelectingItemWithDoneDoesNotAffectCharacterSpacing) Category=Picker |
✅ FAIL — 445s | ❌ FAIL — 204s |
🔴 Without fix — 📱 PickerHandlerTests (SelectedIndexDoesNotAffectCharacterSpacing, SelectingItemWithDoneDoesNotAffectCharacterSpacing): FAIL ✅ · 445s
(truncated to last 15,000 chars)
LoopRunSpecific + 572
�[40m�[37mdbug�[39m�[22m�[49m: frame #7: 0x0000000195484c78 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 212
�[40m�[37mdbug�[39m�[22m�[49m: frame #8: 0x00000001954f83a4 Foundation`-[NSRunLoop(NSRunLoop) runUntilDate:] + 100
�[40m�[37mdbug�[39m�[22m�[49m: frame #9: 0x00000001008baf28 mlaunch`xamarin_dyn_objc_msgSend + 160
�[40m�[37mdbug�[39m�[22m�[49m: frame #10: 0x0000000103fede14
�[40m�[37mdbug�[39m�[22m�[49m: frame #11: 0x0000000104353468
�[40m�[37mdbug�[39m�[22m�[49m: frame #12: 0x0000000103fe7824
�[40m�[37mdbug�[39m�[22m�[49m: frame #13: 0x0000000103f810b4
�[40m�[37mdbug�[39m�[22m�[49m: frame #14: 0x000000010379cd54
�[40m�[37mdbug�[39m�[22m�[49m: frame #15: 0x0000000102644c04 libcoreclr.dylib`CallDescrWorkerInternal + 132
�[40m�[37mdbug�[39m�[22m�[49m: frame #16: 0x00000001024c2d30 libcoreclr.dylib`MethodDescCallSite::CallTargetWorker(unsigned long long const*, unsigned long long*, int) + 836
�[40m�[37mdbug�[39m�[22m�[49m: frame #17: 0x00000001023c9350 libcoreclr.dylib`RunMain(MethodDesc*, short, int*, PtrArray**) + 648
�[40m�[37mdbug�[39m�[22m�[49m: frame #18: 0x00000001023c9688 libcoreclr.dylib`Assembly::ExecuteMainMethod(PtrArray**, int) + 264
�[40m�[37mdbug�[39m�[22m�[49m: frame #19: 0x00000001023f129c libcoreclr.dylib`CorHost2::ExecuteAssembly(unsigned int, char16_t const*, int, char16_t const**, unsigned int*) + 640
�[40m�[37mdbug�[39m�[22m�[49m: frame #20: 0x00000001023b7650 libcoreclr.dylib`coreclr_execute_assembly + 232
�[40m�[37mdbug�[39m�[22m�[49m: frame #21: 0x00000001008b6140 mlaunch`mono_jit_exec + 204
�[40m�[37mdbug�[39m�[22m�[49m: frame #22: 0x00000001008b9ecc mlaunch`xamarin_main + 884
�[40m�[37mdbug�[39m�[22m�[49m: frame #23: 0x00000001008bb1f4 mlaunch`main + 64
�[40m�[37mdbug�[39m�[22m�[49m: frame #24: 0x0000000193a2ab98 dyld`start + 6076
�[40m�[37mdbug�[39m�[22m�[49m: thread #2
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193dc6b6c libsystem_pthread.dylib`start_wqthread
�[40m�[37mdbug�[39m�[22m�[49m: thread #3
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8b8b0 libsystem_kernel.dylib`__workq_kernreturn + 8
�[40m�[37mdbug�[39m�[22m�[49m: thread #4
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d89c34 libsystem_kernel.dylib`mach_msg2_trap + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193d9c3a0 libsystem_kernel.dylib`mach_msg2_internal + 76
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000193d92764 libsystem_kernel.dylib`mach_msg_overwrite + 484
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x0000000193d89fa8 libsystem_kernel.dylib`mach_msg + 24
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x00000001023b52f4 libcoreclr.dylib`MachMessage::Receive(unsigned int) + 80
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x00000001023b461c libcoreclr.dylib`SEHExceptionThread(void*) + 164
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #5, name = '.NET SynchManager'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8fd04 libsystem_kernel.dylib`kevent + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x00000001023a9304 libcoreclr.dylib`CorUnix::CPalSynchronizationManager::ReadBytesFromProcessPipe(int, unsigned char*, int) + 484
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x00000001023a89f0 libcoreclr.dylib`CorUnix::CPalSynchronizationManager::WorkerThread(void*) + 164
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x00000001023b20fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #6, name = '.NET EventPipe'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d92498 libsystem_kernel.dylib`poll + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x00000001026a4e90 libcoreclr.dylib`ds_ipc_poll(_DiagnosticsIpcPollHandle*, unsigned long, unsigned int, void (*)(char const*, unsigned int)) + 172
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000102752bb0 libcoreclr.dylib`ds_ipc_stream_factory_get_next_available_stream(void (*)(char const*, unsigned int)) + 756
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x0000000102750a68 libcoreclr.dylib`server_thread(void*) + 372
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x00000001023b20fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #7, name = '.NET DebugPipe'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8a678 libsystem_kernel.dylib`__open + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193d956a4 libsystem_kernel.dylib`open + 64
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x00000001026a5a84 libcoreclr.dylib`TwoWayPipe::WaitForConnection() + 40
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x00000001026a0578 libcoreclr.dylib`DbgTransportSession::TransportWorker() + 232
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x000000010269f5c8 libcoreclr.dylib`DbgTransportSession::TransportWorkerStatic(void*) + 40
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x00000001023b20fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #8, name = '.NET Debugger'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8d3cc libsystem_kernel.dylib`__psynch_cvwait + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193dcc09c libsystem_pthread.dylib`_pthread_cond_wait + 984
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x00000001023a6f6c libcoreclr.dylib`CorUnix::CPalSynchronizationManager::ThreadNativeWait(CorUnix::_ThreadNativeWaitData*, unsigned int, CorUnix::ThreadWakeupReason*, unsigned int*) + 320
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x00000001023a6bec libcoreclr.dylib`CorUnix::CPalSynchronizationManager::BlockThread(CorUnix::CPalThread*, unsigned int, bool, bool, CorUnix::ThreadWakeupReason*, unsigned int*) + 380
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x00000001023ab0cc libcoreclr.dylib`CorUnix::InternalWaitForMultipleObjectsEx(CorUnix::CPalThread*, unsigned int, void* const*, int, unsigned int, int, int) + 1600
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x000000010269dda8 libcoreclr.dylib`DebuggerRCThread::MainLoop() + 228
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x000000010269dc70 libcoreclr.dylib`DebuggerRCThread::ThreadProc() + 256
�[40m�[37mdbug�[39m�[22m�[49m: frame #7: 0x000000010269da24 libcoreclr.dylib`DebuggerRCThread::ThreadProcStatic(void*) + 56
�[40m�[37mdbug�[39m�[22m�[49m: frame #8: 0x00000001023b20fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #9: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #9
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8d3cc libsystem_kernel.dylib`__psynch_cvwait + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193dcc09c libsystem_pthread.dylib`_pthread_cond_wait + 984
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x00000001023a6f6c libcoreclr.dylib`CorUnix::CPalSynchronizationManager::ThreadNativeWait(CorUnix::_ThreadNativeWaitData*, unsigned int, CorUnix::ThreadWakeupReason*, unsigned int*) + 320
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x00000001023a6bec libcoreclr.dylib`CorUnix::CPalSynchronizationManager::BlockThread(CorUnix::CPalThread*, unsigned int, bool, bool, CorUnix::ThreadWakeupReason*, unsigned int*) + 380
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x00000001023ab0cc libcoreclr.dylib`CorUnix::InternalWaitForMultipleObjectsEx(CorUnix::CPalThread*, unsigned int, void* const*, int, unsigned int, int, int) + 1600
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x00000001024f8078 libcoreclr.dylib`FinalizerThread::WaitForFinalizerEvent(CLREvent*) + 240
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x00000001024f81d8 libcoreclr.dylib`FinalizerThread::FinalizerThreadWorker(void*) + 264
�[40m�[37mdbug�[39m�[22m�[49m: frame #7: 0x0000000102495fa8 libcoreclr.dylib`ManagedThreadBase_DispatchOuter(ManagedThreadCallState*) + 248
�[40m�[37mdbug�[39m�[22m�[49m: frame #8: 0x000000010249648c libcoreclr.dylib`ManagedThreadBase::FinalizerBase(void (*)(void*)) + 36
�[40m�[37mdbug�[39m�[22m�[49m: frame #9: 0x00000001024f8350 libcoreclr.dylib`FinalizerThread::FinalizerThreadStart(void*) + 88
�[40m�[37mdbug�[39m�[22m�[49m: frame #10: 0x00000001023b20fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #11: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #10, name = '.NET SigHandler'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8a7dc libsystem_kernel.dylib`read + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000100a48e98 libSystem.Native.dylib`SignalHandlerLoop + 96
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #11
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8fd04 libsystem_kernel.dylib`kevent + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000100a474a4 libSystem.Native.dylib`SystemNative_WaitForSocketEvents + 80
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x00000001040fca8c
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x00000001040fc7cc
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x00000001040fc3b4
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x0000000103fe1430
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x0000000103fe11e0
�[40m�[37mdbug�[39m�[22m�[49m: frame #7: 0x0000000103fe1108
�[40m�[37mdbug�[39m�[22m�[49m: frame #8: 0x0000000102644c04 libcoreclr.dylib`CallDescrWorkerInternal + 132
�[40m�[37mdbug�[39m�[22m�[49m: frame #9: 0x00000001024c2988 libcoreclr.dylib`DispatchCallSimple(unsigned long*, unsigned int, unsigned long long, unsigned int) + 268
�[40m�[37mdbug�[39m�[22m�[49m: frame #10: 0x00000001024d4c6c libcoreclr.dylib`ThreadNative::KickOffThread_Worker(void*) + 148
�[40m�[37mdbug�[39m�[22m�[49m: frame #11: 0x0000000102495fa8 libcoreclr.dylib`ManagedThreadBase_DispatchOuter(ManagedThreadCallState*) + 248
�[40m�[37mdbug�[39m�[22m�[49m: frame #12: 0x000000010249645c libcoreclr.dylib`ManagedThreadBase::KickOff(void (*)(void*), void*) + 32
�[40m�[37mdbug�[39m�[22m�[49m: frame #13: 0x00000001024d4d44 libcoreclr.dylib`ThreadNative::KickOffThread(void*) + 172
�[40m�[37mdbug�[39m�[22m�[49m: frame #14: 0x00000001023b20fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #15: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #12
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d89c34 libsystem_kernel.dylib`mach_msg2_trap + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193d9c3a0 libsystem_kernel.dylib`mach_msg2_internal + 76
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000193d92764 libsystem_kernel.dylib`mach_msg_overwrite + 484
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x0000000193d89fa8 libsystem_kernel.dylib`mach_msg + 24
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x0000000193eb6c0c CoreFoundation`__CFRunLoopServiceMachPort + 160
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x0000000193eb5528 CoreFoundation`__CFRunLoopRun + 1208
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x0000000193eb49e8 CoreFoundation`CFRunLoopRunSpecific + 572
�[40m�[37mdbug�[39m�[22m�[49m: frame #7: 0x0000000195484c78 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 212
�[40m�[37mdbug�[39m�[22m�[49m: frame #8: 0x00000001008baf28 mlaunch`xamarin_dyn_objc_msgSend + 160
�[40m�[37mdbug�[39m�[22m�[49m: frame #9: 0x00000001043489e4
�[40m�[37mdbug�[39m�[22m�[49m: frame #10: 0x00000001043488a8
�[40m�[37mdbug�[39m�[22m�[49m: frame #11: 0x00000001043486dc
�[40m�[37mdbug�[39m�[22m�[49m: frame #12: 0x0000000104345660
�[40m�[37mdbug�[39m�[22m�[49m: frame #13: 0x0000000103fe13d8
�[40m�[37mdbug�[39m�[22m�[49m: frame #14: 0x0000000103fe11e0
�[40m�[37mdbug�[39m�[22m�[49m: frame #15: 0x0000000103fe1108
�[40m�[37mdbug�[39m�[22m�[49m: frame #16: 0x0000000102644c04 libcoreclr.dylib`CallDescrWorkerInternal + 132
�[40m�[37mdbug�[39m�[22m�[49m: frame #17: 0x00000001024c2988 libcoreclr.dylib`DispatchCallSimple(unsigned long*, unsigned int, unsigned long long, unsigned int) + 268
�[40m�[37mdbug�[39m�[22m�[49m: frame #18: 0x00000001024d4c6c libcoreclr.dylib`ThreadNative::KickOffThread_Worker(void*) + 148
�[40m�[37mdbug�[39m�[22m�[49m: frame #19: 0x0000000102495fa8 libcoreclr.dylib`ManagedThreadBase_DispatchOuter(ManagedThreadCallState*) + 248
�[40m�[37mdbug�[39m�[22m�[49m: frame #20: 0x000000010249645c libcoreclr.dylib`ManagedThreadBase::KickOff(void (*)(void*), void*) + 32
�[40m�[37mdbug�[39m�[22m�[49m: frame #21: 0x00000001024d4d44 libcoreclr.dylib`ThreadNative::KickOffThread(void*) + 172
�[40m�[37mdbug�[39m�[22m�[49m: frame #22: 0x00000001023b20fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #23: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #13, name = 'com.apple.CFSocket.private'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d94c2c libsystem_kernel.dylib`__select + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193edca80 CoreFoundation`__CFSocketManager + 704
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #14
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000000000000
�[40m�[37mdbug�[39m�[22m�[49m: (lldb) detach
�[40m�[37mdbug�[39m�[22m�[49m: Process 9393 detached
�[40m�[37mdbug�[39m�[22m�[49m: (lldb) quit
�[40m�[37mdbug�[39m�[22m�[49m: 9393 Execution timed out after 60 seconds and the process was killed.
�[40m�[37mdbug�[39m�[22m�[49m: Process mlaunch exited with 137
�[40m�[37mdbug�[39m�[22m�[49m: Failed to list crash reports from device.
�[40m�[37mdbug�[39m�[22m�[49m: Test run started but crashed and no test results were reported
�[40m�[37mdbug�[39m�[22m�[49m: No crash reports, waiting 30 seconds for the crash report service...
�[41m�[30mfail�[39m�[22m�[49m: Application test run crashed
Failed to launch the application, please try again. If the problem persists, try rebooting MacOS
�[40m�[32minfo�[39m�[22m�[49m: Uninstalling the application 'com.microsoft.maui.core.devicetests' from 'iPhone 11 Pro'
�[40m�[37mdbug�[39m�[22m�[49m:
�[40m�[37mdbug�[39m�[22m�[49m: Running /Applications/Xcode_26.1.1.app/Contents/Developer/usr/bin/simctl
�[40m�[37mdbug�[39m�[22m�[49m: An error was encountered processing the command (domain=com.apple.CoreSimulator.SimError, code=405):
�[40m�[37mdbug�[39m�[22m�[49m: Unable to lookup in current state: Shutdown
�[40m�[37mdbug�[39m�[22m�[49m: Process simctl exited with 149
�[41m�[30mfail�[39m�[22m�[49m: Failed to uninstall the app bundle! Check logs for more details!
XHarness exit code: 83 (APP_LAUNCH_FAILURE)
Passed: 0
Failed: 0
Tests completed with exit code: 83
🟢 With fix — 📱 PickerHandlerTests (SelectedIndexDoesNotAffectCharacterSpacing, SelectingItemWithDoneDoesNotAffectCharacterSpacing): FAIL ❌ · 204s
(truncated to last 15,000 chars)
�[40m�[37mdbug�[39m�[22m�[49m: frame #14: 0x000000010529cd54
�[40m�[37mdbug�[39m�[22m�[49m: frame #15: 0x00000001041a0c04 libcoreclr.dylib`CallDescrWorkerInternal + 132
�[40m�[37mdbug�[39m�[22m�[49m: frame #16: 0x000000010401ed30 libcoreclr.dylib`MethodDescCallSite::CallTargetWorker(unsigned long long const*, unsigned long long*, int) + 836
�[40m�[37mdbug�[39m�[22m�[49m: frame #17: 0x0000000103f25350 libcoreclr.dylib`RunMain(MethodDesc*, short, int*, PtrArray**) + 648
�[40m�[37mdbug�[39m�[22m�[49m: frame #18: 0x0000000103f25688 libcoreclr.dylib`Assembly::ExecuteMainMethod(PtrArray**, int) + 264
�[40m�[37mdbug�[39m�[22m�[49m: frame #19: 0x0000000103f4d29c libcoreclr.dylib`CorHost2::ExecuteAssembly(unsigned int, char16_t const*, int, char16_t const**, unsigned int*) + 640
�[40m�[37mdbug�[39m�[22m�[49m: frame #20: 0x0000000103f13650 libcoreclr.dylib`coreclr_execute_assembly + 232
�[40m�[37mdbug�[39m�[22m�[49m: frame #21: 0x0000000102506140 mlaunch`mono_jit_exec + 204
�[40m�[37mdbug�[39m�[22m�[49m: frame #22: 0x0000000102509ecc mlaunch`xamarin_main + 884
�[40m�[37mdbug�[39m�[22m�[49m: frame #23: 0x000000010250b1f4 mlaunch`main + 64
�[40m�[37mdbug�[39m�[22m�[49m: frame #24: 0x0000000193a2ab98 dyld`start + 6076
�[40m�[37mdbug�[39m�[22m�[49m: thread #2
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8b8b0 libsystem_kernel.dylib`__workq_kernreturn + 8
�[40m�[37mdbug�[39m�[22m�[49m: thread #3
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d89c34 libsystem_kernel.dylib`mach_msg2_trap + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193d9c3a0 libsystem_kernel.dylib`mach_msg2_internal + 76
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000193d92764 libsystem_kernel.dylib`mach_msg_overwrite + 484
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x0000000193d89fa8 libsystem_kernel.dylib`mach_msg + 24
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x0000000103f112f4 libcoreclr.dylib`MachMessage::Receive(unsigned int) + 80
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x0000000103f1061c libcoreclr.dylib`SEHExceptionThread(void*) + 164
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #4, name = '.NET SynchManager'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8fd04 libsystem_kernel.dylib`kevent + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000103f05304 libcoreclr.dylib`CorUnix::CPalSynchronizationManager::ReadBytesFromProcessPipe(int, unsigned char*, int) + 484
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000103f049f0 libcoreclr.dylib`CorUnix::CPalSynchronizationManager::WorkerThread(void*) + 164
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x0000000103f0e0fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #5, name = '.NET EventPipe'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d92498 libsystem_kernel.dylib`poll + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000104200e90 libcoreclr.dylib`ds_ipc_poll(_DiagnosticsIpcPollHandle*, unsigned long, unsigned int, void (*)(char const*, unsigned int)) + 172
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x00000001042aebb0 libcoreclr.dylib`ds_ipc_stream_factory_get_next_available_stream(void (*)(char const*, unsigned int)) + 756
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x00000001042aca68 libcoreclr.dylib`server_thread(void*) + 372
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x0000000103f0e0fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #6, name = '.NET DebugPipe'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8a678 libsystem_kernel.dylib`__open + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193d956a4 libsystem_kernel.dylib`open + 64
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000104201a84 libcoreclr.dylib`TwoWayPipe::WaitForConnection() + 40
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x00000001041fc578 libcoreclr.dylib`DbgTransportSession::TransportWorker() + 232
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x00000001041fb5c8 libcoreclr.dylib`DbgTransportSession::TransportWorkerStatic(void*) + 40
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x0000000103f0e0fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #7, name = '.NET Debugger'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8d3cc libsystem_kernel.dylib`__psynch_cvwait + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193dcc09c libsystem_pthread.dylib`_pthread_cond_wait + 984
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000103f02f6c libcoreclr.dylib`CorUnix::CPalSynchronizationManager::ThreadNativeWait(CorUnix::_ThreadNativeWaitData*, unsigned int, CorUnix::ThreadWakeupReason*, unsigned int*) + 320
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x0000000103f02bec libcoreclr.dylib`CorUnix::CPalSynchronizationManager::BlockThread(CorUnix::CPalThread*, unsigned int, bool, bool, CorUnix::ThreadWakeupReason*, unsigned int*) + 380
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x0000000103f070cc libcoreclr.dylib`CorUnix::InternalWaitForMultipleObjectsEx(CorUnix::CPalThread*, unsigned int, void* const*, int, unsigned int, int, int) + 1600
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x00000001041f9da8 libcoreclr.dylib`DebuggerRCThread::MainLoop() + 228
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x00000001041f9c70 libcoreclr.dylib`DebuggerRCThread::ThreadProc() + 256
�[40m�[37mdbug�[39m�[22m�[49m: frame #7: 0x00000001041f9a24 libcoreclr.dylib`DebuggerRCThread::ThreadProcStatic(void*) + 56
�[40m�[37mdbug�[39m�[22m�[49m: frame #8: 0x0000000103f0e0fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #9: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #8
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8d3cc libsystem_kernel.dylib`__psynch_cvwait + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193dcc09c libsystem_pthread.dylib`_pthread_cond_wait + 984
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000103f02f6c libcoreclr.dylib`CorUnix::CPalSynchronizationManager::ThreadNativeWait(CorUnix::_ThreadNativeWaitData*, unsigned int, CorUnix::ThreadWakeupReason*, unsigned int*) + 320
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x0000000103f02bec libcoreclr.dylib`CorUnix::CPalSynchronizationManager::BlockThread(CorUnix::CPalThread*, unsigned int, bool, bool, CorUnix::ThreadWakeupReason*, unsigned int*) + 380
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x0000000103f070cc libcoreclr.dylib`CorUnix::InternalWaitForMultipleObjectsEx(CorUnix::CPalThread*, unsigned int, void* const*, int, unsigned int, int, int) + 1600
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x0000000104054078 libcoreclr.dylib`FinalizerThread::WaitForFinalizerEvent(CLREvent*) + 240
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x00000001040541d8 libcoreclr.dylib`FinalizerThread::FinalizerThreadWorker(void*) + 264
�[40m�[37mdbug�[39m�[22m�[49m: frame #7: 0x0000000103ff1fa8 libcoreclr.dylib`ManagedThreadBase_DispatchOuter(ManagedThreadCallState*) + 248
�[40m�[37mdbug�[39m�[22m�[49m: frame #8: 0x0000000103ff248c libcoreclr.dylib`ManagedThreadBase::FinalizerBase(void (*)(void*)) + 36
�[40m�[37mdbug�[39m�[22m�[49m: frame #9: 0x0000000104054350 libcoreclr.dylib`FinalizerThread::FinalizerThreadStart(void*) + 88
�[40m�[37mdbug�[39m�[22m�[49m: frame #10: 0x0000000103f0e0fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #11: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #9, name = '.NET SigHandler'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8a7dc libsystem_kernel.dylib`read + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x00000001025c4e98 libSystem.Native.dylib`SignalHandlerLoop + 96
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #10
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8fd04 libsystem_kernel.dylib`kevent + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x00000001025c34a4 libSystem.Native.dylib`SystemNative_WaitForSocketEvents + 80
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000105bfca9c
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x0000000105bfc6f4
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x0000000105bfc43c
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x0000000105ae14c0
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x0000000105ae1218
�[40m�[37mdbug�[39m�[22m�[49m: frame #7: 0x0000000105ae1140
�[40m�[37mdbug�[39m�[22m�[49m: frame #8: 0x00000001041a0c04 libcoreclr.dylib`CallDescrWorkerInternal + 132
�[40m�[37mdbug�[39m�[22m�[49m: frame #9: 0x000000010401e988 libcoreclr.dylib`DispatchCallSimple(unsigned long*, unsigned int, unsigned long long, unsigned int) + 268
�[40m�[37mdbug�[39m�[22m�[49m: frame #10: 0x0000000104030c6c libcoreclr.dylib`ThreadNative::KickOffThread_Worker(void*) + 148
�[40m�[37mdbug�[39m�[22m�[49m: frame #11: 0x0000000103ff1fa8 libcoreclr.dylib`ManagedThreadBase_DispatchOuter(ManagedThreadCallState*) + 248
�[40m�[37mdbug�[39m�[22m�[49m: frame #12: 0x0000000103ff245c libcoreclr.dylib`ManagedThreadBase::KickOff(void (*)(void*), void*) + 32
�[40m�[37mdbug�[39m�[22m�[49m: frame #13: 0x0000000104030d44 libcoreclr.dylib`ThreadNative::KickOffThread(void*) + 172
�[40m�[37mdbug�[39m�[22m�[49m: frame #14: 0x0000000103f0e0fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #15: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #11
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d89c34 libsystem_kernel.dylib`mach_msg2_trap + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193d9c3a0 libsystem_kernel.dylib`mach_msg2_internal + 76
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000193d92764 libsystem_kernel.dylib`mach_msg_overwrite + 484
�[40m�[37mdbug�[39m�[22m�[49m: frame #3: 0x0000000193d89fa8 libsystem_kernel.dylib`mach_msg + 24
�[40m�[37mdbug�[39m�[22m�[49m: frame #4: 0x0000000193eb6c0c CoreFoundation`__CFRunLoopServiceMachPort + 160
�[40m�[37mdbug�[39m�[22m�[49m: frame #5: 0x0000000193eb5528 CoreFoundation`__CFRunLoopRun + 1208
�[40m�[37mdbug�[39m�[22m�[49m: frame #6: 0x0000000193eb49e8 CoreFoundation`CFRunLoopRunSpecific + 572
�[40m�[37mdbug�[39m�[22m�[49m: frame #7: 0x0000000195484c78 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 212
�[40m�[37mdbug�[39m�[22m�[49m: frame #8: 0x000000010250af28 mlaunch`xamarin_dyn_objc_msgSend + 160
�[40m�[37mdbug�[39m�[22m�[49m: frame #9: 0x0000000105c49bd4
�[40m�[37mdbug�[39m�[22m�[49m: frame #10: 0x0000000105c49a98
�[40m�[37mdbug�[39m�[22m�[49m: frame #11: 0x0000000105c498cc
�[40m�[37mdbug�[39m�[22m�[49m: frame #12: 0x0000000105c464c8
�[40m�[37mdbug�[39m�[22m�[49m: frame #13: 0x0000000105ae1468
�[40m�[37mdbug�[39m�[22m�[49m: frame #14: 0x0000000105ae1218
�[40m�[37mdbug�[39m�[22m�[49m: frame #15: 0x0000000105ae1140
�[40m�[37mdbug�[39m�[22m�[49m: frame #16: 0x00000001041a0c04 libcoreclr.dylib`CallDescrWorkerInternal + 132
�[40m�[37mdbug�[39m�[22m�[49m: frame #17: 0x000000010401e988 libcoreclr.dylib`DispatchCallSimple(unsigned long*, unsigned int, unsigned long long, unsigned int) + 268
�[40m�[37mdbug�[39m�[22m�[49m: frame #18: 0x0000000104030c6c libcoreclr.dylib`ThreadNative::KickOffThread_Worker(void*) + 148
�[40m�[37mdbug�[39m�[22m�[49m: frame #19: 0x0000000103ff1fa8 libcoreclr.dylib`ManagedThreadBase_DispatchOuter(ManagedThreadCallState*) + 248
�[40m�[37mdbug�[39m�[22m�[49m: frame #20: 0x0000000103ff245c libcoreclr.dylib`ManagedThreadBase::KickOff(void (*)(void*), void*) + 32
�[40m�[37mdbug�[39m�[22m�[49m: frame #21: 0x0000000104030d44 libcoreclr.dylib`ThreadNative::KickOffThread(void*) + 172
�[40m�[37mdbug�[39m�[22m�[49m: frame #22: 0x0000000103f0e0fc libcoreclr.dylib`CorUnix::CPalThread::ThreadEntry(void*) + 364
�[40m�[37mdbug�[39m�[22m�[49m: frame #23: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: thread #12
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d8b8b0 libsystem_kernel.dylib`__workq_kernreturn + 8
�[40m�[37mdbug�[39m�[22m�[49m: thread #13, name = 'com.apple.CFSocket.private'
�[40m�[37mdbug�[39m�[22m�[49m: frame #0: 0x0000000193d94c2c libsystem_kernel.dylib`__select + 8
�[40m�[37mdbug�[39m�[22m�[49m: frame #1: 0x0000000193edca80 CoreFoundation`__CFSocketManager + 704
�[40m�[37mdbug�[39m�[22m�[49m: frame #2: 0x0000000193dcbbc8 libsystem_pthread.dylib`_pthread_start + 136
�[40m�[37mdbug�[39m�[22m�[49m: (lldb) detach
�[40m�[37mdbug�[39m�[22m�[49m: Process 10711 detached
�[40m�[37mdbug�[39m�[22m�[49m: (lldb) quit
�[40m�[37mdbug�[39m�[22m�[49m: 10711 Execution timed out after 60 seconds and the process was killed.
�[40m�[37mdbug�[39m�[22m�[49m: Failed to get ExitCode: System.InvalidOperationException: Process must exit before requested information can be determined.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.get_ExitCode()
at Microsoft.DotNet.XHarness.Common.Execution.ProcessManager.RunAsyncInternal(Process process, ILog log, ILog stdout, ILog stderr, Action`2 kill, Func`3 getChildProcessIds, Nullable`1 timeout, Dictionary`2 environmentVariables, Nullable`1 cancellationToken, Nullable`1 diagnostics) in /_/src/Microsoft.DotNet.XHarness.Common/Execution/ProcessManager.cs:line 359
�[40m�[37mdbug�[39m�[22m�[49m: Failed to list crash reports from device.
�[40m�[37mdbug�[39m�[22m�[49m: Test run started but crashed and no test results were reported
�[40m�[37mdbug�[39m�[22m�[49m: No crash reports, waiting 30 seconds for the crash report service...
�[40m�[37mdbug�[39m�[22m�[49m: Found 1 new crash report(s)
�[40m�[37mdbug�[39m�[22m�[49m: - Adding /Users/cloudtest/Library/Logs/DiagnosticReports/Microsoft.Maui.Core.DeviceTests-2026-05-03-060520.ips
�[40m�[37mdbug�[39m�[22m�[49m: Successfully copied Microsoft.Maui.Core.DeviceTests-2026-05-03-060520.ips
�[41m�[30mfail�[39m�[22m�[49m: Application test run crashed
Failed to launch the application, please try again. If the problem persists, try rebooting MacOS
�[40m�[32minfo�[39m�[22m�[49m: Uninstalling the application 'com.microsoft.maui.core.devicetests' from 'iPhone 11 Pro'
�[40m�[37mdbug�[39m�[22m�[49m:
�[40m�[37mdbug�[39m�[22m�[49m: Running /Applications/Xcode_26.1.1.app/Contents/Developer/usr/bin/simctl
�[40m�[37mdbug�[39m�[22m�[49m: Process simctl exited with 0
�[40m�[32minfo�[39m�[22m�[49m: Application 'com.microsoft.maui.core.devicetests' was uninstalled successfully
XHarness exit code: 83 (APP_LAUNCH_FAILURE)
Passed: 40
Failed: 8
Tests completed with exit code: 83
⚠️ Failure Details
- ❌ PickerHandlerTests (SelectedIndexDoesNotAffectCharacterSpacing, SelectingItemWithDoneDoesNotAffectCharacterSpacing) FAILED with fix (should pass)
Device tests: 8 of 48 failed
📁 Fix files reverted (3 files)
eng/pipelines/ci-copilot.ymlsrc/Core/src/Handlers/Picker/PickerHandler.iOS.cssrc/Core/src/Platform/iOS/PickerExtensions.cs
🧪 UI Tests — Category Detection
Detected UI test categories: ViewBaseTests
🔍 Regression Cross-Reference
🔍 Regression Cross-Reference
🟢 No regression risks detected. No labeled bug-fix PRs in the last 6 months touched the modified files.
🔍 Pre-Flight — Context & Validation
Issue: #34971 - [iOS] Picker loses CharacterSpacing after item selection when Title is set
PR: #34974 - [iOS] Fix Picker CharacterSpacing lost after item selection when Title is set
Platforms Affected: iOS, MacCatalyst
Files Changed: 2 implementation, 1 test
Key Findings
- Regression introduced by PR [iOS] Fixed picker title's color #20205: iOS Picker applies CharacterSpacing via
AttributedPlaceholderfor title text. When the user selects an item,platformPicker.Text = selectedItemassigns a plain string, which causes iOS to internally create a kern-freeNSAttributedString, discarding the kern that was set on the placeholder. - Fix adds
UpdateCharacterSpacingcall after text assignment in two code paths:UpdatePickerFromPickerSource(Done-button path) andPickerExtensions.UpdatePicker(programmatic SelectedIndex path). - Gate ❌ FAILED — the new device tests did not pass as expected.
- Two inline review comments were resolved: using array initializer instead of
List<string>and adding the "Done button" test path. SelectingItemWithDoneDoesNotAffectCharacterSpacingtest (.iOS.cs) accessesUIPickerViewandInputAccessoryViewwhich are null/unset on MacCatalyst — will throwNullReferenceExceptionon MacCatalyst builds.
Code Review Summary
Verdict: NEEDS_CHANGES
Confidence: High
Errors: 0 | Warnings: 1 | Suggestions: 1
Key code review findings:
⚠️ src/Core/tests/DeviceTests/Handlers/Picker/PickerHandlerTests.iOS.cs:96—SelectingItemWithDoneDoesNotAffectCharacterSpacingaccessesmauiPicker.UIPickerView(null on MacCatalyst) andTapDoneOnInputAccessoryViewasserts a non-nullUIToolbarInputAccessoryView (never set on MacCatalyst). File compiles for both iOS and MacCatalyst — wrap with#if !MACCATALYST.- 💡
src/Core/src/Handlers/Picker/PickerHandler.iOS.cs:428—OnEditinghandler also setsplatformView.Textwithout re-applying CharacterSpacing (pre-existing gap, not introduced by this PR).
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #34974 | Call UpdateCharacterSpacing after platformPicker.Text assignment in two code paths |
❌ FAILED (Gate) | PickerHandler.iOS.cs, PickerExtensions.cs, PickerHandlerTests.iOS.cs |
Gate failed; MacCatalyst test crash likely |
🔬 Code Review — Deep Analysis
Code Review — PR #34974
Independent Assessment
What this changes: Two UpdateCharacterSpacing calls are added at points where a plain-string assignment to UITextField.Text previously erased NSAttributedString kern attributes. One call is in UpdatePickerFromPickerSource (the Done-button path in PickerHandler.iOS.cs) and one in PickerExtensions.UpdatePicker (the programmatic SelectedIndex change path).
Inferred motivation: iOS's UITextField internally constructs a new, kern-free NSAttributedString whenever a plain string is assigned to .Text. If CharacterSpacing was previously applied via AttributedPlaceholder (for the title), that kern is lost the moment the user selects an item. Re-calling UpdateCharacterSpacing immediately after the text assignment restores the kern attribute on the resulting AttributedText.
Is the approach sound? Yes — UpdateCharacterSpacing (TextFieldExtensions.cs:131) is idempotent, null-safe (bails out if AttributedText is null), and also re-applies kern to AttributedPlaceholder, so the no-selection (selectedIndex == -1) path is correctly covered too. The approach is identical to how DatePickerExtensions and TimePickerExtensions already handle the same issue.
Reconciliation with PR Narrative
Author claims: Regression from PR #20205 caused CharacterSpacing to be silently lost after selection; fix adds UpdateCharacterSpacing in two code paths.
Agreement: Full agreement. The root cause analysis is accurate. The two fix locations match the code paths I identified from first principles.
Findings
⚠️ Warning — SelectingItemWithDoneDoesNotAffectCharacterSpacing test crashes on MacCatalyst
PickerHandlerTests.iOS.cs uses the .iOS.cs extension which compiles for both iOS and MacCatalyst. The new test at line 96 directly accesses:
var pickerView = mauiPicker.UIPickerView; // null on MacCatalyst — CreatePlatformView passes null
var model = (PickerSource)pickerView.Model; // NullReferenceException on MacCatalystAnd TapDoneOnInputAccessoryView asserts InputAccessoryView is a non-null UIToolbar — but InputAccessoryView is never set in the #if MACCATALYST branch of CreatePlatformView.
The established convention for this exact scenario is a file-level #if !MACCATALYST guard — both TimePickerHandlerTests.iOS.cs and DatePickerHandlerTests.iOS.cs begin with exactly this guard. The simplest fix is to wrap the affected test and helper with #if !MACCATALYST:
#if !MACCATALYST
[Theory(DisplayName = "Selecting An Item With Done Keeps CharacterSpacing")]
...
public async Task SelectingItemWithDoneDoesNotAffectCharacterSpacing(...) { ... }
void TapDoneOnInputAccessoryView(MauiPicker mauiPicker) { ... }
#endifNote: SelectedIndexDoesNotAffectCharacterSpacing (the other new test, line 67) does not access UIPickerView directly and uses only null-safe calls through MapSelectedIndex → UpdatePicker, so it is MacCatalyst-safe and needs no guard.
💡 Suggestion — OnEditing is a remaining kern gap (pre-existing, not introduced by this PR)
MauiPickerProxy.OnEditing (line 428 in handler file) also does platformView.Text = virtualView.GetItem(selectedIndex) without re-applying character spacing. This is the EditingChanged handler whose purpose is to prevent actual keyboard input from sticking. It's pre-existing and wouldn't be triggered in normal picker usage, but if it ever fires (e.g., on a device with an unexpected hardware keyboard), kern would be temporarily lost until the next mapper call. Consider adding platformView.UpdateCharacterSpacing(virtualView) there as well for completeness.
Devil's Advocate
- Could the double
UpdateCharacterSpacingcall inUpdatePickercause a performance issue? No — it's two NSAttributedString attribute reads/writes on the main thread during a user-initiated selection. Negligible. - Could the fix cause a regression when
CharacterSpacingis 0 (the default)? No —WithCharacterSpacing(0)removes the kern attribute (equivalent to not having one), so default-spacing pickers are unaffected. - Could
UpdateCharacterSpacingcause problems whenAttributedTextis null (no item selected)? No — the null-conditionaltextField.AttributedText?.WithCharacterSpacing(...)returns null and the assignment is skipped; the placeholder path still works correctly. - Is the MacCatalyst production code path (
FinishSelectItem→UpdatePickerFromPickerSource) covered? Yes, the fix is in shared non-guarded code, so both iOS and MacCatalyst benefit.
Verdict: NEEDS_CHANGES
Confidence: High
Summary: The production fix is correct, minimal, and consistent with established patterns in the codebase. However, SelectingItemWithDoneDoesNotAffectCharacterSpacing will crash with a NullReferenceException on MacCatalyst because .iOS.cs files compile for both targets and the test accesses UIPickerView and InputAccessoryView which are only set on iOS. A #if !MACCATALYST guard around that test and its helper is all that's needed before merge.
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix-1 (claude-opus-4.6) | helper atomically constructs NSAttributedString with KerningAdjustment; covers UpdatePicker + UpdatePickerFromPickerSource + OnEditing | PASS | PickerExtensions.cs, PickerHandler.iOS.cs |
Fixes OnEditing gap too |
| 2 | try-fix-2 (claude-sonnet-4.6) | MauiPicker stores CharacterSpacing internally; re-applies kern after Text assignment at two callsites | PASS | PickerHandler.iOS.cs, PickerExtensions.cs |
Avoids virtual view traversal |
| 3 | try-fix-3 (gpt-5.3-codex) | Mapper-ordering: route selection through MapSelectedIndex then call FAIL | PickerHandler.iOS.cs, PickerHandlerTests.iOS.cs |
APP_LAUNCH_FAILURE on final iteration | MapCharacterSpacing |
| 4 | try-fix-4 (gemini/sonnet) | via direct AttributedText assignment (bypasses Text setter entirely when CharacterSpacing != 0); covers all 3 paths | PASS | PickerExtensions.cs, PickerHandler.iOS.cs |
Most direct avoids read-modify-write unreliability |
| PR | PR #34974 | Call UpdateCharacterSpacing after Text assignment in UpdatePickerFromPickerSource + FAILED (Gate) | PickerHandler.iOS.cs, PickerExtensions.cs, PickerHandlerTests.iOS.cs |
Gate failed; MacCatalyst test crash | UpdatePicker |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 2 | NO NEW IDEAS | Try-fix-1 covers the atomic NSAttributedString approach fully |
| claude-sonnet-4.6 | 2 | NO NEW IDEAS | Try-fix-2 covers the cached CharacterSpacing approach fully |
| gpt-5.3-codex | 2 | NO NEW IDEAS | Try-fix-3 exhausted mapper-ordering; no new viable angle |
| gemini/sonnet | 2 | NO NEW IDEAS | Try-fix-4 covers direct AttributedText assignment fully |
Exhausted: Yes
Selected Fix: pr-plus- PR's production fix is correct; adding #if !MACCATALYSTguard fixes the MacCatalyst test crash. Alternativelytry-fix-1ortry-fix-4 provide a more robust atomic fix that also covers the OnEditing gap.reviewer
📋 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | ✅ COMPLETE | Issue #34971 — iOS Picker CharacterSpacing lost after item selection |
| Code Review | NEEDS_CHANGES (high) | 0 errors, 1 warning, 1 suggestion — MacCatalyst test crash |
| Gate | ❌ FAILED | ios — tests did not behave as expected |
| Try-Fix | ✅ COMPLETE | 4 attempts: 3 passing (try-fix-1, 2, 4), 1 failing (try-fix-3) |
| Report | ✅ COMPLETE |
Code Review Impact on Try-Fix
The code review SelectingItemWithDoneDoesNotAffectCharacterSpacing crashing on MacCatalyst (.iOS.cs compiles for both platforms, UIPickerView is null on MacCatalyst) was included as a hint to all four try-fix models. Try-fix-4 explicitly addressed this by adding #if !MACCATALYST guards. The OnEditing gap identified in the code review was addressed by try-fix-1 and try-fix-4, which covered all three text-assignment paths. The code review verdict (NEEDS_CHANGES) triggered the hard gate — REQUEST CHANGES recommendation is required regardless of try-fix results.
Summary
The PR's production logic is correct — calling UpdateCharacterSpacing after plain text assignment is sound. However, the Gate ❌ FAILED and code review found a MacCatalyst test crash (SelectingItemWithDoneDoesNotAffectCharacterSpacing dereferences null UIPickerView on MacCatalyst). Try-fix exploration identified a more robust alternative (try-fix-1) that atomically constructs NSAttributedString with KerningAdjustment, covering all three text-assignment paths (including the OnEditing gap the PR misses), and passed all regression tests.
Root Cause
iOS strips kern attributes from UITextField.AttributedText whenever a plain string is assigned to UITextField.Text. The regression was introduced by PR #20205, which moved CharacterSpacing application to AttributedPlaceholder (for title text). When the user selects an item, platformPicker.Text = selectedItem causes iOS to internally replace AttributedText with a kern-free NSAttributedString, discarding the kern from the placeholder entirely.
Fix Quality
PR's fix: Correct approach but uses read-modify-write (Text = x; UpdateCharacterSpacing()) which depends on AttributedText being reliably readable after Text = assignment — this is fragile. Also misses the OnEditing handler gap, and has a MacCatalyst test crash.
try-fix-1 (WINNER): Uses SetTextWithCharacterSpacing helper that atomically constructs NSAttributedString with KerningAdjustment and directly assigns to AttributedText — bypassing the fragile read-back. Covers all 3 paths. ✅ Passed all tests.
try-fix-2: Also passes but adds state (CharacterSpacing) to MauiPicker — more complex than necessary.
try-fix-3: ❌ Failed — mapper-ordering strategy doesn't cover the Done-button path.
try-fix-4: Passes with same approach as try-fix-1, confirms the atomic NSAttributedString approach is correct.
Selected Fix: try-fix-1 — atomically constructs NSAttributedString with kern, covers all paths, passes all tests. An alternative pr-plus-reviewer (PR fix + #if !MACCATALYST guard) is acceptable if the team prefers a minimal patch, but try-fix-1 is more robust.
MauiBot
left a comment
There was a problem hiding this comment.
🤖 Automated review — alternative fix proposed
The expert-reviewer evaluation compared the PR fix against #1 automatically generated candidates and selected try-fix-1 as the strongest fix.
Why: try-fix-1 passed all 4 regression tests empirically using a SetTextWithCharacterSpacing helper that atomically constructs NSAttributedString with KerningAdjustment instead of the PR's fragile read-modify-write pattern. It also covers the OnEditing handler gap the PR missed and avoids the MacCatalyst test crash entirely.
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-1`)
diff --git a/src/Core/src/Handlers/Picker/PickerHandler.iOS.cs b/src/Core/src/Handlers/Picker/PickerHandler.iOS.cs
index a54299d290..11fe557578 100644
--- a/src/Core/src/Handlers/Picker/PickerHandler.iOS.cs
+++ b/src/Core/src/Handlers/Picker/PickerHandler.iOS.cs
@@ -255,7 +255,7 @@ namespace Microsoft.Maui.Handlers
if (VirtualView == null || PlatformView == null || pickerSource == null)
return;
- PlatformView.Text = VirtualView.GetItem(pickerSource.SelectedIndex);
+ PlatformView.SetTextWithCharacterSpacing(VirtualView.GetItem(pickerSource.SelectedIndex), VirtualView.CharacterSpacing);
VirtualView.SelectedIndex = pickerSource.SelectedIndex;
}
@@ -423,7 +423,7 @@ namespace Microsoft.Maui.Handlers
// Reset the TextField's Text so it appears as if typing with a keyboard does not work.
var selectedIndex = virtualView.SelectedIndex;
- platformView.Text = virtualView.GetItem(selectedIndex);
+ platformView.SetTextWithCharacterSpacing(virtualView.GetItem(selectedIndex), virtualView.CharacterSpacing);
// Also clears the undo stack (undo/redo possible on iPads)
platformView.UndoManager?.RemoveAllActions();
diff --git a/src/Core/src/Platform/iOS/PickerExtensions.cs b/src/Core/src/Platform/iOS/PickerExtensions.cs
index c2de04d1fd..13e429ae28 100644
--- a/src/Core/src/Platform/iOS/PickerExtensions.cs
+++ b/src/Core/src/Platform/iOS/PickerExtensions.cs
@@ -1,6 +1,7 @@
#nullable enable
using System;
using Foundation;
+using UIKit;
namespace Microsoft.Maui.Platform
{
@@ -36,18 +37,45 @@ namespace Microsoft.Maui.Platform
platformPicker.UpdateAttributedPlaceholder(new NSAttributedString(picker.Title ?? string.Empty, null, picker?.TitleColor?.ToPlatform()));
}
+ /// <summary>
+ /// Sets text on a picker using AttributedText with kern to avoid iOS clearing
+ /// character spacing when plain Text is assigned.
+ /// </summary>
+ /// <remarks>
+ /// Unlike UpdateCharacterSpacing (which reads back AttributedText and adds kern),
+ /// this creates a fresh NSAttributedString to work around an iOS issue where
+ /// reading AttributedText immediately after setting Text doesn't reliably
+ /// preserve kern in all handler lifecycle contexts.
+ /// </remarks>
+ internal static void SetTextWithCharacterSpacing(this MauiPicker platformPicker, string text, double characterSpacing)
+ {
+ if (characterSpacing == 0)
+ {
+ platformPicker.Text = text;
+ return;
+ }
+
+ var attributes = new UIKit.UIStringAttributes
+ {
+ KerningAdjustment = (float)characterSpacing
+ };
+ platformPicker.AttributedText = new NSAttributedString(text ?? string.Empty, attributes);
+ }
+
internal static void UpdatePicker(this MauiPicker platformPicker, IPicker picker, int? newSelectedIndex = null)
{
var selectedIndex = newSelectedIndex ?? picker.SelectedIndex;
if (selectedIndex != -1)
{
- platformPicker.Text = picker.GetItem(selectedIndex);
+ platformPicker.SetTextWithCharacterSpacing(picker.GetItem(selectedIndex), picker.CharacterSpacing);
}
else
{
platformPicker.Text = null;
platformPicker.UpdatePickerTitle(picker);
+ // Applies character spacing to the placeholder when no item is selected
+ platformPicker.UpdateCharacterSpacing(picker);
}
var pickerView = platformPicker.UIPickerView;
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
Root Cause
Description of Change
Issues Fixed
Fixes #34971
Validated the behaviour in the following platforms
Output
Before.mov
After.mov