-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[Issue-Resolver] Fix Android drawable mutation crash in controls #33265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Prevents crashes on Android caused by modifying shared drawables without mutation in ActivityIndicator, Entry, Switch, and SearchBar. Adds safe drawable mutation helpers in DrawableExtensions and updates all affected controls to use them. Includes comprehensive UI and stress tests to verify the fix and prevent regressions.
|
Hey there @@kubaflo! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR extends the fix from PR #33071 to address Android drawable mutation crashes across multiple controls (ActivityIndicator, Entry, Switch, and SearchBar). The root cause is modifying shared Android Drawable resources without calling Mutate() first, which causes race conditions and crashes in large applications with many screens.
Key Changes:
- Introduces centralized safe drawable mutation helper methods in
DrawableExtensions.cs - Applies the fix pattern to ActivityIndicator, Entry clear button, Switch track/thumb, and SearchBar icon drawables
- Adds comprehensive UI tests with stress testing for rapid color changes (50 iterations)
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
DrawableExtensions.cs |
Adds internal safe mutation helper methods: SafeSetTint, SafeSetColorFilter, and SafeClearColorFilter with overloads for different parameter types |
ActivityIndicatorExtensions.cs |
Updates UpdateColor() to use safe drawable mutation when changing IndeterminateDrawable color filter |
EditTextExtensions.cs |
Updates UpdateClearButtonColor() to use safe drawable mutation and properly reassign the mutated drawable |
SwitchExtensions.cs |
Updates UpdateTrackColor() and UpdateThumbColor() to use safe drawable mutation for track and thumb drawables |
SearchViewExtensions.cs |
Updates search icon and cancel button tinting to use safe mutation helpers |
Issue33070.cs |
Adds 5 NUnit test methods covering individual controls and stress test with 50 rapid color changes |
Issue33070.xaml |
Creates comprehensive test page UI with all affected controls and stress test section |
Issue33070.xaml.cs |
Implements event handlers for color changes with exception handling and status reporting |
| { | ||
| aSwitch.ThumbDrawable?.SetColorFilter(thumbColor, FilterMode.SrcAtop); | ||
| aSwitch.ThumbDrawable = aSwitch.ThumbDrawable.SafeSetColorFilter(thumbColor.ToPlatform(), FilterMode.SrcAtop); | ||
| } |
Copilot
AI
Dec 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The UpdateThumbColor method is missing the else branch to clear the color filter when thumbColor is null. This is inconsistent with UpdateTrackColor which properly handles the null case. When thumbColor is set to null, the color filter should be cleared to restore the default appearance.
| } | |
| } | |
| else | |
| { | |
| aSwitch.ThumbDrawable = aSwitch.ThumbDrawable.SafeClearColorFilter(); | |
| } |
This is a follow up for #33070 that the issue-resolver agent suggested
Pull Request: Fix Android Drawable Mutation Crashes
Title:
[Android] Fix drawable mutation crash in ActivityIndicator, Entry, Switch, and SearchBarFixes: #33070
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!
Summary
Fixes Android crashes caused by modifying shared Drawables without calling
Mutate()first. PR #33071 fixed this issue in SearchBar, but the same pattern existed in ActivityIndicator, Entry/Editor clear button, and Switch controls. This PR applies the same defensive fix pattern across all affected controls and adds comprehensive UI tests.Quick verification:
📋 Click to expand full PR details
Root Cause
Android shares Drawable resources across multiple views for memory efficiency. Modifying a shared drawable without calling
Mutate()first causes race conditions and crashes, particularly in large applications with many screens. The crash occurs when:R.drawable.abc_ic_clear_material)SetTint()orSetColorFilter()) without mutationExample crash from #33070:
This is the exact same crash pattern fixed in PR #33071 for SearchBar.
Solution
Created centralized safe drawable mutation helper methods in
DrawableExtensions.csthat follow Android's recommended pattern:Key principle: Always call
Mutate()before modifying any drawable property, then reassign the mutated drawable back to the view.Files Changed:
DrawableExtensions.cs- Added safe mutation helper methods:SafeSetTint(ImageView, Color)- Safely tints ImageView's drawableSafeSetTint(Drawable, Color)- Safely tints a drawableSafeSetColorFilter(Drawable, Color, FilterMode)- Safely applies color filterSafeClearColorFilter(Drawable)- Safely clears color filterActivityIndicatorExtensions.cs- FixedUpdateColor():EditTextExtensions.cs- FixedUpdateClearButtonColor():SwitchExtensions.cs- FixedUpdateTrackColor()andUpdateThumbColor():SearchViewExtensions.cs- Applied same fix as PR Fix Android crash when changing shared Drawable tint on Searchbar #33071:Testing
Test Page: Issue33070.xaml
Created comprehensive test page with:
Before Fix (Crash Risk)
Without the fix, rapid color changes in large apps with many screens would cause crashes:
After Fix (Safe)
With the fix, even 50 rapid consecutive color changes complete successfully:
Edge Cases Tested
Platforms Tested
Test Coverage
NUnit Tests (
TestCases.Shared.Tests/Tests/Issues/Issue33070.cs)5 comprehensive test methods:
ActivityIndicatorColorChangeShouldNotCrash()UITestCategories.ActivityIndicatorEntryTextColorChangeShouldNotCrash()UITestCategories.EntrySwitchColorChangeShouldNotCrash()UITestCategories.SwitchSearchBarColorChangeShouldNotCrash()UITestCategories.SearchBarRapidColorChangesShouldNotCrash()⭐ Stress TestUITestCategories.ActivityIndicatorTest Execution
Breaking Changes
None. All changes are internal implementation details:
DrawableExtensionsare markedinternalAdditional Context
Why This Matters
This crash is particularly problematic in production apps because:
Android Documentation Reference
From Android Drawable.mutate() docs:
Related Issues
Reviewer Checklist
Mutate()before modification