[iOS And Windows] Fix Entry IsPassword ignored when Keyboard is set to Password - #36677
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36677Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36677" |
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
|
Hey there @@SyedAbdulAzeemSF4852! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines: Successfully started running 2 pipeline(s). |
This comment has been minimized.
This comment has been minimized.
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines: Successfully started running 2 pipeline(s). |
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@SyedAbdulAzeemSF4852 — new AI review results are available based on this last commit:
c14b71c.
🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix
Gate Result: ✅ PASSED
Platform: WINDOWS · Base: main · Merge base: 997d875b
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
📱 EntryHandlerTests (PasswordKeyboardRespectsIsPasswordFalseInitially, PasswordKeyboardIsPasswordToggleWorksCorrectly) Category=Entry |
✅ FAIL — 363s | ✅ PASS — 215s |
🔴 Without fix — 📱 EntryHandlerTests (PasswordKeyboardRespectsIsPasswordFalseInitially, PasswordKeyboardIsPasswordToggleWorksCorrectly): FAIL ✅ · 363s
(no coded error found; showing last 1200 chars)
fying `x:SuppressXamlTrimWarnings=True` within the closest element. If not, the property path might be trimmed and will not be AOT compatible. [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net10.0-windows10.0.19041.0]
Platform\Windows\TabbedPage\TabbedPageStyle.xaml(13,13): XamlCompiler warning WMC1510: Ensure the property path is trimming and AOT compatible by making use of 'Compiled Bindings (x:bind)' if possible or by specifying the 'x:DataType' directive with the respective binding data context and marking the type declaration with the 'WinRT.GeneratedBindableCustomProperty' attribute or the 'Microsoft.UI.Xaml.Data.Bindable' attribute. If you are unable to do either but can ensure the data type is attributed correctly, then you can also suppress the warning by specifying `x:SuppressXamlTrimWarnings=True` within the closest element. If not, the property path might be trimmed and will not be AOT compatible. [D:\a\1\s\src\Controls\src\Core\Controls.Core.csproj::TargetFramework=net10.0-windows10.0.19041.0]
90 Warning(s)
0 Error(s)
Time Elapsed 00:03:34.44
Passed: 0
Failed: 2
Skipped: 0
Total: 2
Tests completed with exit code: 1
🟢 With fix — 📱 EntryHandlerTests (PasswordKeyboardRespectsIsPasswordFalseInitially, PasswordKeyboardIsPasswordToggleWorksCorrectly): PASS ✅ · 215s
(no coded error found; showing last 1200 chars)
ou can also suppress the warning by specifying `x:SuppressXamlTrimWarnings=True` within the closest element. If not, the property path might be trimmed and will not be AOT compatible. [D:\a\1\s\src\Core\src\Core.csproj::TargetFramework=net10.0-windows10.0.19041.0]
Platform\Windows\Styles\WindowRootViewStyle.xaml(31,17): XamlCompiler warning WMC1510: Ensure the property path is trimming and AOT compatible by making use of 'Compiled Bindings (x:bind)' if possible or by specifying the 'x:DataType' directive with the respective binding data context and marking the type declaration with the 'WinRT.GeneratedBindableCustomProperty' attribute or the 'Microsoft.UI.Xaml.Data.Bindable' attribute. If you are unable to do either but can ensure the data type is attributed correctly, then you can also suppress the warning by specifying `x:SuppressXamlTrimWarnings=True` within the closest element. If not, the property path might be trimmed and will not be AOT compatible. [D:\a\1\s\src\Core\src\Core.csproj::TargetFramework=net10.0-windows10.0.19041.0]
11 Warning(s)
0 Error(s)
Time Elapsed 00:02:41.90
Passed: 2
Failed: 0
Skipped: 0
Total: 2
Tests completed successfully
📁 Fix files reverted (2 files)
src/Core/src/Platform/Windows/MauiPasswordTextBox.cssrc/Core/src/Platform/iOS/KeyboardExtensions.cs
📱 UI Tests — Entry,ViewBaseTests
Detected UI test categories: Entry,ViewBaseTests
✅ Deep UI tests — 216 passed, 0 failed across 2 categories on platform-pool agent (replaces in-process counts above).
🧪 UI Test Execution Results (deep, platform pool)
| Category | Tests | Snapshot diffs |
|---|---|---|
Entry |
101/102 ✓ | — |
ViewBaseTests |
115/115 ✓ | — |
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs) |
📋 Pre-Flight — Context & Validation
Issue: #35650 - Entry IsPassword ignored when Keyboard is Password
PR: #36677 - [iOS And Windows] Fix Entry IsPassword ignored when Keyboard is set to Password
Platforms Affected: iOS, MacCatalyst, Windows
Files Changed: 2 implementation, 1 test
Key Findings
- PR removes iOS secure-entry behavior from shared
KeyboardExtensions.ApplyKeyboard(Keyboard.Password), which affects Editor/SearchBar as well as Entry. - Windows PR fix removes
MauiPasswordTextBoxInputScope callback entirely; this is scoped to Entry's platform view but changes how password input scopes can drive masking internally. - Gate already passed: the two Entry device tests fail without the fix and pass with the PR fix on Windows.
Code Review Summary
Verdict: NEEDS_CHANGES
Confidence: low
Errors: 1 | Warnings: 0 | Suggestions: 0
Key code review findings:
- ✗
src/Core/src/Platform/iOS/KeyboardExtensions.cs:43-46— RemovingSetSecureTextEntry(true)from the shared keyboard helper regresses non-Entry iOS/MacCatalyst consumers ofKeyboard.Password.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #36677 | Remove iOS shared SetSecureTextEntry(true) and remove Windows InputScope password callback |
✅ PASSED (Gate) | KeyboardExtensions.cs, MauiPasswordTextBox.cs, tests |
Original PR; passes Entry gate but code review found iOS blast-radius concern |
🔬 Code Review — Deep Analysis
Code Review — PR #36677
Independent Assessment
What this changes: Makes Entry.IsPassword control masking when Keyboard=Password on iOS/MacCatalyst and Windows; adds non-Android device tests for the false initial state and false→true→false toggling.
Inferred motivation: Prevent Keyboard.Password from overriding an explicit IsPassword=false.
Reconciliation with PR Narrative
Author claims: iOS/Windows ignore IsPassword=false when Keyboard=Password; Android is tracked separately.
Agreement/disagreement: The Windows change is scoped to Entry. The iOS change is broader than the PR narrative because it changes the shared KeyboardExtensions.ApplyKeyboard path used by Entry, Editor, and SearchBar.
Prior Review Reconciliation
No prior ❌ Error findings found. I checked top-level review bodies, inline review comments, and PR issue comments via public GitHub API. Existing MauiBot review had warnings/suggestions and CI/test markers, but no unresolved ❌ code-review Error findings.
Blast Radius Assessment
- Runs for all instances: No for Windows; yes for all iOS/MacCatalyst controls that use
ApplyKeyboard(Keyboard.Password). - Startup impact: No.
- Static/shared state: No new static/shared state.
- Handler/platform impact: Yes — platform text-input behavior, max confidence medium before CI; CI/auth gaps cap to low.
CI Status
- Required-check result: undetermined via required-check API;
gh pr checks --requiredfailed because GitHub CLI is unauthenticated. - Public check-runs:
maui-prsuccess,maui-pr-devicetestssuccess,maui-pr-uitestsfailure, Build Analysis failure,pre_activationfailure. - Classification: red/undetermined. Public Build Analysis points to likely unrelated UI/infra failures, but required-check status could not be verified.
- Action taken: invoked
azdo-build-investigator;ci-analysisskill unavailable in this environment; confidence capped low.
Findings
❌ Error — iOS fix changes Keyboard.Password behavior for non-Entry controls
src/Core/src/Platform/iOS/KeyboardExtensions.cs:43-46 removes SetSecureTextEntry(true) from the shared keyboard mapper. That fixes Entry only because Entry has a later UpdateIsPassword source of truth, but Editor and SearchBar also call this same ApplyKeyboard path and do not have IsPassword. For those controls, Keyboard.Password previously enabled secure text entry on iOS/MacCatalyst; after this PR it no longer does. The fix should be scoped to Entry, e.g. by reapplying entry.IsPassword after Entry keyboard mapping, rather than removing password behavior from the shared keyboard helper.
Failure-Mode Probing
Entry Keyboard=Password, IsPassword=false: fixed on iOS/Windows.Entry IsPasswordtoggle: existing mapper still updates native masking.Editor/SearchBar Keyboard=Passwordon iOS: now unmasked because no laterIsPasswordmapper exists.- Handler reconnect/subscriptions: Windows removes a callback; no new subscription accumulation.
Verdict: NEEDS_CHANGES
Confidence: low
Summary: The Entry-specific goal is sound, but the iOS implementation is overbroad and regresses other Keyboard.Password consumers. CI required-check status could not be verified due missing GitHub auth, and public checks are not fully green.
🛠️ Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix | Restore shared/native password behavior and reapply UpdateIsPassword from Entry MapKeyboard |
❌ FAIL | 4 files | Mapper ordering alone did not beat the Windows InputScope callback; both Entry tests failed initial false assertion. |
| 2 | try-fix | Preserve shared iOS secure-entry and Windows callback, but suppress callback only for mapper/internal InputScope assignments; reapply Entry IsPassword after keyboard mapping |
✅ PASS | 5 files | Windows Entry device tests passed; avoids PR's iOS Editor/SearchBar regression by restoring shared Keyboard.Password behavior. |
| PR | PR #36677 | Remove iOS shared SetSecureTextEntry(true) and remove Windows InputScope password callback |
✅ PASSED (Gate) | 2 implementation files + tests | Original PR passes gate but code review found iOS shared-helper blast radius. |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| code-review + maui-expert-reviewer | 1 | Yes | Found iOS blast-radius issue: shared KeyboardExtensions.ApplyKeyboard(Keyboard.Password) affects Editor/SearchBar, so alternatives should preserve shared behavior and scope Entry-specific override elsewhere. |
| try-fix loop | 1 | Yes | Candidate 1 proved mapper reordering alone is insufficient on Windows because the native InputScope callback still mutates IsPassword. |
| try-fix loop | 2 | Yes | Candidate 2 added scoped suppression for mapper-owned/internal InputScope assignments and passed Windows Entry tests. |
Exhausted: No — stopped because Candidate #2 passed the Windows gate criteria and is demonstrably better than the PR fix.
Selected Fix: Candidate #2 — preserves existing shared iOS Keyboard.Password behavior for non-Entry controls while keeping Entry IsPassword authoritative on Windows and iOS.
Candidate Narratives
try-fix-1
See CustomAgentLogsTmp/PRState/36677/PRAgent/try-fix-1/content.md for the full approach, diff, test output summary, and failure analysis.
try-fix-2
See CustomAgentLogsTmp/PRState/36677/PRAgent/try-fix-2/content.md for the full approach, diff, test output summary, and success analysis.
📝 Recommended PR Title & Description
Assessment: ✏️ Recommend updating — the current metadata accurately describes the submitted PR, but the winning fix is try-fix-2, which preserves shared iOS and Windows password-keyboard behavior instead of removing it.
Recommended title
[iOS and Windows] Entry: Respect IsPassword when Keyboard is Password
Recommended description
### Issue Details
- An Entry with Keyboard="Password" always renders text as masked, ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS/MacCatalyst and Windows when Keyboard="Password" is set.
### Root Cause
- On initial setup, Entry keyboard mapping can run after IsPassword mapping. The shared iOS Keyboard.Password path sets SecureTextEntry=true, and Windows MauiPasswordTextBox reacts to an InputScope=Password assignment by setting IsPassword=true. Both paths can overwrite an explicit IsPassword=false.
### Description of Change
- **iOS/MacCatalyst**: Preserve the shared Keyboard.Password behavior in KeyboardExtensions.ApplyKeyboard so non-Entry consumers such as Editor, SearchBar, alert prompt text fields, Shell search, and compatibility renderers continue to mask password keyboards. EntryHandler.iOS now reapplies UpdateIsPassword after UpdateKeyboard so Entry.IsPassword remains authoritative for Entry.
- **Windows**: Preserve the MauiPasswordTextBox InputScope password callback for non-mapper/native InputScope changes, but suppress that callback for MAUI-owned/internal InputScope assignments. EntryHandler.Windows now reapplies UpdateIsPassword after UpdateKeyboard so Entry.IsPassword remains authoritative for Entry.
- **Tests**: Added non-Android Entry device tests covering Keyboard.Password with IsPassword=false initially and IsPassword false -> true -> false toggling.
### What NOT to Do (for future agents)
- Do not remove SetSecureTextEntry(true) from the shared iOS KeyboardExtensions.ApplyKeyboard(Keyboard.Password) helper; it affects non-Entry controls that do not have an IsPassword mapper.
- Do not rely on Entry mapper ordering alone on Windows; the MauiPasswordTextBox InputScopeProperty callback can still flip IsPassword=true.
- Do not remove the Windows InputScope callback entirely when a scoped suppression is sufficient; preserving native/non-mapper behavior reduces compatibility risk.
**Note**: The Android fix for the same issue is tracked separately in PR #36280.
### Issues Fixed
Fixes #35650
### Validated the behaviour in the following platforms
- [x] Windows
- [ ] Android
- [x] iOS
- [x] Mac
### Output
| Platform | Before | After |
|----------|----------|----------|
| iOS | <video src="https://github.com/user-attachments/assets/1b249d36-8e83-434c-a7dc-b7a4b9c5a3f4"> | <video src="https://github.com/user-attachments/assets/1c917876-aa8f-4c39-93ca-22b6b592f213"> |
| Windows | <video src="https://github.com/user-attachments/assets/80ae3ff3-5c9b-4211-9451-eeb9fc13c126"> | <video src="https://github.com/user-attachments/assets/fdd830fe-8017-4b12-882d-bf118be4a9f1"> |
🏁 Report — Final Recommendation
Comparative Report — PR #36677
Candidate ranking
| Rank | Candidate | Regression tests | Assessment |
|---|---|---|---|
| 1 | try-fix-2 |
✅ PASS | Best fix. Preserves shared/native password behavior for non-Entry consumers while making Entry IsPassword authoritative through scoped mapper/internal overrides. |
| 2 | pr-plus-reviewer |
Not rerun; based on PR Windows gate + reviewer-applied iOS correction | Better than raw PR because it fixes the iOS shared-helper regression, but still removes the Windows MauiPasswordTextBox InputScope password callback entirely. |
| 3 | pr |
✅ PASSED gate | Passes the targeted Entry gate, but the expert reviewer found a major iOS/MacCatalyst blast-radius issue: shared Keyboard.Password no longer masks non-Entry consumers. |
| 4 | try-fix-1 |
❌ FAIL | Ranked below all passing candidates per rule. Mapper reapplication alone did not beat the Windows InputScope callback; both Entry tests failed their initial IsPassword=false assertion. |
Candidate details
pr
The submitted PR removes two platform-level forcing mechanisms: iOS shared KeyboardExtensions.ApplyKeyboard(Keyboard.Password) no longer calls SetSecureTextEntry(true), and Windows MauiPasswordTextBox no longer observes InputScopeProperty to set IsPassword=true. This passes the targeted Entry gate on Windows, and prior review evidence records iOS Entry gate success as well. However, the iOS change is not Entry-scoped: Editor, SearchBar, alert prompts, Shell search, and compatibility renderers all call the same shared helper and do not have an Entry.IsPassword mapper to restore password masking.
pr-plus-reviewer
The sandbox candidate applies the expert reviewer's feedback to the PR by restoring shared iOS Keyboard.Password masking and reapplying Entry UpdateIsPassword after Entry UpdateKeyboard. This resolves the major iOS blast-radius finding while keeping the PR's Windows deletion approach. It is a viable improvement over the raw PR, but it does not preserve the Windows native/InputScope behavior for non-mapper changes.
try-fix-1
This candidate restored shared iOS secure-entry behavior and the Windows InputScope callback, then re-applied UpdateIsPassword from Entry MapKeyboard. It failed the Windows regression tests: the native InputScope callback still flipped IsPassword=true before validation. Because candidates that failed regression tests must rank below passing candidates, it cannot win.
try-fix-2
This candidate preserves the shared iOS Keyboard.Password behavior and the Windows InputScope callback, but scopes suppression to MAUI-owned/internal InputScope assignments. It also reapplies Entry UpdateIsPassword after Entry UpdateKeyboard on iOS and Windows. The final Windows Entry device test run passed (Passed: 1979, Failed: 0, Skipped: 111), and the approach directly incorporates the learning from try-fix-1 by also routing cached InputScope restoration through the scoped setter.
Winning candidate
try-fix-2 wins. It is the only candidate that both passes the regression tests and avoids the PR's broad behavior regression by preserving existing shared/native password semantics outside the Entry mapper-owned update path.
🧭 Next Steps — alternative fix proposed (try-fix-2)
Automated review — alternative fix proposed
The expert-reviewer evaluation compared the PR fix against automatically generated candidates and selected try-fix-2 as the strongest fix.
Why: try-fix-2 passed the Windows Entry regression suite and is safer than the raw PR because it preserves shared iOS Keyboard.Password behavior and the Windows InputScope callback except during MAUI-owned/internal Entry updates. It avoids the expert reviewer's iOS blast-radius finding while making Entry IsPassword authoritative for the failing scenarios.
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-2)
diff --git a/src/Core/src/Handlers/Entry/EntryHandler.Windows.cs b/src/Core/src/Handlers/Entry/EntryHandler.Windows.cs
index 6b7ec0c2d8..7494c43588 100644
--- a/src/Core/src/Handlers/Entry/EntryHandler.Windows.cs
+++ b/src/Core/src/Handlers/Entry/EntryHandler.Windows.cs
@@ -97,8 +97,11 @@ namespace Microsoft.Maui.Handlers
public static void MapCharacterSpacing(IEntryHandler handler, IEntry entry) =>
handler.PlatformView?.UpdateCharacterSpacing(entry);
- public static void MapKeyboard(IEntryHandler handler, IEntry entry) =>
+ public static void MapKeyboard(IEntryHandler handler, IEntry entry)
+ {
handler.PlatformView?.UpdateKeyboard(entry);
+ handler.PlatformView?.UpdateIsPassword(entry);
+ }
public static void MapCursorPosition(IEntryHandler handler, IEntry entry) =>
handler.PlatformView?.UpdateCursorPosition(entry);
diff --git a/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs b/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs
index ec57791509..a6520caad5 100644
--- a/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs
+++ b/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs
@@ -108,8 +108,11 @@ namespace Microsoft.Maui.Handlers
public static void MapIsReadOnly(IEntryHandler handler, IEntry entry) =>
handler.PlatformView?.UpdateIsReadOnly(entry);
- public static void MapKeyboard(IEntryHandler handler, IEntry entry) =>
+ public static void MapKeyboard(IEntryHandler handler, IEntry entry)
+ {
handler.PlatformView?.UpdateKeyboard(entry);
+ handler.PlatformView?.UpdateIsPassword(entry);
+ }
public static void MapReturnType(IEntryHandler handler, IEntry entry) =>
handler.PlatformView?.UpdateReturnType(entry);
diff --git a/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs b/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs
index 4f0536eeb6..c782832fdd 100644
--- a/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs
+++ b/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs
@@ -56,11 +56,41 @@ namespace Microsoft.Maui.Platform
bool _internalChangeFlag;
int _cachedCursorPosition;
int _cachedTextLength;
+ bool _ignoreInputScopePasswordSync;
+ readonly long _token;
public MauiPasswordTextBox()
{
TextChanging += OnNativeTextChanging;
TextChanged += OnNativeTextChanged;
+ _token = RegisterPropertyChangedCallback(TextBox.InputScopeProperty, OnInputScopePropertyChanged);
+ Unloaded += (s, e) =>
+ {
+ UnregisterPropertyChangedCallback(TextBox.InputScopeProperty, _token);
+ };
+ }
+
+ static void OnInputScopePropertyChanged(DependencyObject sender, DependencyProperty dp)
+ {
+ if (sender is not MauiPasswordTextBox mauiTxtBox || mauiTxtBox.IsPassword || mauiTxtBox._ignoreInputScopePasswordSync)
+ {
+ return;
+ }
+
+ mauiTxtBox.IsPassword = mauiTxtBox.InputScope?.Names?.Any(x => x.NameValue == InputScopeNameValue.Password) ?? false;
+ }
+
+ internal void SetInputScopeFromMapper(InputScope? inputScope)
+ {
+ _ignoreInputScopePasswordSync = true;
+ try
+ {
+ InputScope = inputScope;
+ }
+ finally
+ {
+ _ignoreInputScopePasswordSync = false;
+ }
}
public bool IsPassword
@@ -206,7 +236,7 @@ namespace Microsoft.Maui.Platform
{
if (!IsPassword)
{
- InputScope = _cachedInputScope;
+ SetInputScopeFromMapper(_cachedInputScope);
IsSpellCheckEnabled = _cachedSpellCheckSetting;
IsTextPredictionEnabled = _cachedPredictionsSetting;
}
diff --git a/src/Core/src/Platform/Windows/TextBoxExtensions.cs b/src/Core/src/Platform/Windows/TextBoxExtensions.cs
index f57fb5b977..0d2af7a616 100644
--- a/src/Core/src/Platform/Windows/TextBoxExtensions.cs
+++ b/src/Core/src/Platform/Windows/TextBoxExtensions.cs
@@ -207,7 +207,10 @@ namespace Microsoft.Maui.Platform
inputScope.Names.Add(textInput.Keyboard?.ToInputScopeName() ?? new InputScopeName(InputScopeNameValue.Default));
- textBox.InputScope = inputScope;
+ if (textBox is MauiPasswordTextBox passwordTextBox)
+ passwordTextBox.SetInputScopeFromMapper(inputScope);
+ else
+ textBox.InputScope = inputScope;
}
public static void UpdateHorizontalTextAlignment(this TextBox textBox, ITextAlignment textAlignment)
diff --git a/src/Core/src/Platform/iOS/KeyboardExtensions.cs b/src/Core/src/Platform/iOS/KeyboardExtensions.cs
index 863810a4b3..9b7b72a3cc 100644
--- a/src/Core/src/Platform/iOS/KeyboardExtensions.cs
+++ b/src/Core/src/Platform/iOS/KeyboardExtensions.cs
@@ -43,6 +43,7 @@ namespace Microsoft.Maui.Platform
else if (keyboard == Keyboard.Password)
{
textInput.SetKeyboardType(UIKeyboardType.Default);
+ textInput.SetSecureTextEntry(true);
}
else if (keyboard is CustomKeyboard)
{
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
This pull request fixes a cross-platform inconsistency where Entry configured with Keyboard.Password could override IsPassword=false (initial load on iOS; initial load and runtime toggles on Windows). The change makes IsPassword the single source of truth for whether text is masked, while still allowing Keyboard.Password to influence keyboard/input-scope behavior.
Changes:
- iOS: Stop forcing
SecureTextEntry=trueinsideKeyboard.Passwordhandling soIsPassword=falseisn’t overwritten after mapping. - Windows: Remove the
InputScopeproperty-changed callback that forcedIsPassword=truewhenever the scope changed toPassword. - Device tests: Add coverage to ensure
Keyboard.PasswordrespectsIsPassword=falseinitially and when toggling (non-Android, since Android is tracked in #36280).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/Core/tests/DeviceTests/Handlers/Entry/EntryHandlerTests.cs | Adds device tests validating initial and toggled IsPassword behavior when Keyboard.Password is set (excluding Android). |
| src/Core/src/Platform/Windows/MauiPasswordTextBox.cs | Removes InputScope-driven forcing of IsPassword, preventing silent overrides of app intent. |
| src/Core/src/Platform/iOS/KeyboardExtensions.cs | Removes hardcoded secure-entry enabling from Keyboard.Password so masking follows IsPassword. |
…o Password (#36677) <!-- 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! ### Issue Details - An Entry with Keyboard="Password" always renders text as masked, ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS (initial load) and Windows (initial load and runtime toggle) when Keyboard="Password" is set. ### Root Cause - The MapIsPassword mapper runs before MapKeyboard in EntryHandler.cs on initial setup, so Keyboard.Password hardcodes masking behavior in ApplyKeyboard (iOS: SetSecureTextEntry(true)) and via an InputScope callback (Windows: OnInputScopePropertyChanged), both of which run after MapIsPassword and silently overwrite IsPassword=false. ### Description of Change - **iOS**: Removed the hardcoded SetSecureTextEntry(true) from the Keyboard.Password branch in KeyboardExtensions.cs. SecureTextEntry is now set exclusively by TextFieldExtensions.UpdateIsPassword, respecting the actual IsPassword value. - **Windows**: Removed the OnInputScopePropertyChanged callback from MauiPasswordTextBox that automatically forced IsPassword=true whenever InputScope changed to Password, allowing developers to set IsPassword=false even when Keyboard=Password is used. **Note**: The Android fix for the same issue is tracked separately in PR #36280. ### Issues Fixed Fixes #35650 ### Validated the behaviour in the following platforms - [x] Windows - [ ] Android - [x] iOS - [x] Mac ### Output | Platform | Before | After | |----------|----------|----------| | iOS | <video src="https://github.com/user-attachments/assets/1b249d36-8e83-434c-a7dc-b7a4b9c5a3f4"> | <video src="https://github.com/user-attachments/assets/1c917876-aa8f-4c39-93ca-22b6b592f213"> | | Windows | <video src="https://github.com/user-attachments/assets/80ae3ff3-5c9b-4211-9451-eeb9fc13c126"> | <video src="https://github.com/user-attachments/assets/fdd830fe-8017-4b12-882d-bf118be4a9f1"> |
…o Password (#36677) <!-- 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! ### Issue Details - An Entry with Keyboard="Password" always renders text as masked, ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS (initial load) and Windows (initial load and runtime toggle) when Keyboard="Password" is set. ### Root Cause - The MapIsPassword mapper runs before MapKeyboard in EntryHandler.cs on initial setup, so Keyboard.Password hardcodes masking behavior in ApplyKeyboard (iOS: SetSecureTextEntry(true)) and via an InputScope callback (Windows: OnInputScopePropertyChanged), both of which run after MapIsPassword and silently overwrite IsPassword=false. ### Description of Change - **iOS**: Removed the hardcoded SetSecureTextEntry(true) from the Keyboard.Password branch in KeyboardExtensions.cs. SecureTextEntry is now set exclusively by TextFieldExtensions.UpdateIsPassword, respecting the actual IsPassword value. - **Windows**: Removed the OnInputScopePropertyChanged callback from MauiPasswordTextBox that automatically forced IsPassword=true whenever InputScope changed to Password, allowing developers to set IsPassword=false even when Keyboard=Password is used. **Note**: The Android fix for the same issue is tracked separately in PR #36280. ### Issues Fixed Fixes #35650 ### Validated the behaviour in the following platforms - [x] Windows - [ ] Android - [x] iOS - [x] Mac ### Output | Platform | Before | After | |----------|----------|----------| | iOS | <video src="https://github.com/user-attachments/assets/1b249d36-8e83-434c-a7dc-b7a4b9c5a3f4"> | <video src="https://github.com/user-attachments/assets/1c917876-aa8f-4c39-93ca-22b6b592f213"> | | Windows | <video src="https://github.com/user-attachments/assets/80ae3ff3-5c9b-4211-9451-eeb9fc13c126"> | <video src="https://github.com/user-attachments/assets/fdd830fe-8017-4b12-882d-bf118be4a9f1"> |
…o Password (#36677) <!-- 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! ### Issue Details - An Entry with Keyboard="Password" always renders text as masked, ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS (initial load) and Windows (initial load and runtime toggle) when Keyboard="Password" is set. ### Root Cause - The MapIsPassword mapper runs before MapKeyboard in EntryHandler.cs on initial setup, so Keyboard.Password hardcodes masking behavior in ApplyKeyboard (iOS: SetSecureTextEntry(true)) and via an InputScope callback (Windows: OnInputScopePropertyChanged), both of which run after MapIsPassword and silently overwrite IsPassword=false. ### Description of Change - **iOS**: Removed the hardcoded SetSecureTextEntry(true) from the Keyboard.Password branch in KeyboardExtensions.cs. SecureTextEntry is now set exclusively by TextFieldExtensions.UpdateIsPassword, respecting the actual IsPassword value. - **Windows**: Removed the OnInputScopePropertyChanged callback from MauiPasswordTextBox that automatically forced IsPassword=true whenever InputScope changed to Password, allowing developers to set IsPassword=false even when Keyboard=Password is used. **Note**: The Android fix for the same issue is tracked separately in PR #36280. ### Issues Fixed Fixes #35650 ### Validated the behaviour in the following platforms - [x] Windows - [ ] Android - [x] iOS - [x] Mac ### Output | Platform | Before | After | |----------|----------|----------| | iOS | <video src="https://github.com/user-attachments/assets/1b249d36-8e83-434c-a7dc-b7a4b9c5a3f4"> | <video src="https://github.com/user-attachments/assets/1c917876-aa8f-4c39-93ca-22b6b592f213"> | | Windows | <video src="https://github.com/user-attachments/assets/80ae3ff3-5c9b-4211-9451-eeb9fc13c126"> | <video src="https://github.com/user-attachments/assets/fdd830fe-8017-4b12-882d-bf118be4a9f1"> |
…o Password (#36677) <!-- 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! ### Issue Details - An Entry with Keyboard="Password" always renders text as masked, ignoring IsPassword=false. Setting IsPassword=false has no effect on iOS (initial load) and Windows (initial load and runtime toggle) when Keyboard="Password" is set. ### Root Cause - The MapIsPassword mapper runs before MapKeyboard in EntryHandler.cs on initial setup, so Keyboard.Password hardcodes masking behavior in ApplyKeyboard (iOS: SetSecureTextEntry(true)) and via an InputScope callback (Windows: OnInputScopePropertyChanged), both of which run after MapIsPassword and silently overwrite IsPassword=false. ### Description of Change - **iOS**: Removed the hardcoded SetSecureTextEntry(true) from the Keyboard.Password branch in KeyboardExtensions.cs. SecureTextEntry is now set exclusively by TextFieldExtensions.UpdateIsPassword, respecting the actual IsPassword value. - **Windows**: Removed the OnInputScopePropertyChanged callback from MauiPasswordTextBox that automatically forced IsPassword=true whenever InputScope changed to Password, allowing developers to set IsPassword=false even when Keyboard=Password is used. **Note**: The Android fix for the same issue is tracked separately in PR #36280. ### Issues Fixed Fixes #35650 ### Validated the behaviour in the following platforms - [x] Windows - [ ] Android - [x] iOS - [x] Mac ### Output | Platform | Before | After | |----------|----------|----------| | iOS | <video src="https://github.com/user-attachments/assets/1b249d36-8e83-434c-a7dc-b7a4b9c5a3f4"> | <video src="https://github.com/user-attachments/assets/1c917876-aa8f-4c39-93ca-22b6b592f213"> | | Windows | <video src="https://github.com/user-attachments/assets/80ae3ff3-5c9b-4211-9451-eeb9fc13c126"> | <video src="https://github.com/user-attachments/assets/fdd830fe-8017-4b12-882d-bf118be4a9f1"> |
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
Note: The Android fix for the same issue is tracked separately in PR #36280.
Issues Fixed
Fixes #35650
Validated the behaviour in the following platforms
Output
iOS_Before.mov
iOS_After.mov
Windows_Before.mp4
Windows_After.mp4