[Android][BLITZ] Native Login WebView fallback does not show back button - #2994
Conversation
Generated by 🚫 Danger |
3d41cfe to
6c45d2c
Compare
| * login activity, so show the back affordance to match — even with | ||
| * no authenticated users yet. | ||
| */ | ||
| nativeLoginActivity != null -> true |
There was a problem hiding this comment.
This doesn't seem right. The screen should not show a back button unconditionally for native login. What if there are 0 users logged in?
There was a problem hiding this comment.
Good question — I checked the 0-users case specifically, and it's not a dead-end.
The reason it's safe to show unconditionally for native login is that the back handler is already unconditional in that mode. LoginActivity.handleBackBehavior() finishes and returns to the native login activity whenever nativeLoginActivity != null — it never consults the user count:
// LoginActivity.handleBackBehavior()
if (nativeLoginActivity != null) {
setResult(RESULT_CANCELED)
finish()
return
}So with native login enabled, hardware/gesture back already dismisses this WebView fallback back to the native screen — including with 0 users. Before this change the visible ← button was gated on authenticated users, so it was hidden even though the navigation behind it worked, leaving no visible affordance to escape the fallback. This change just makes the button match the behavior that already ships.
I verified the 0-users path end-to-end on-device (native login enabled, no accounts): the fallback shows ←, and both the button and the gesture return to the native login screen — no dead-end. Happy to attach screenshots if useful.
Note this is scoped to LoginViewModel.shouldShowBackButton (the WebView fallback); NativeLoginManager.shouldShowBackButton — the app's own native screen — is untouched and still gates on users.
This response was generated by an AI agent on behalf of @JohnsonEricAtSalesforce.
There was a problem hiding this comment.
I forgot we have a separate shouldShowBack for native login.
brandonpage
left a comment
There was a problem hiding this comment.
This does not fix the issue of showing the back button when appropriate, it just always shows it for native login.
…rue from LoginViewModel.shouldShowBackButton when nativeLoginActivity is set so the dismissible WebView fallback shows the affordance; add tests)
6c45d2c to
4b45a1e
Compare
e773b29
into
forcedotcom:dev
Summary
When an app uses Native Login, the WebView-based
LoginActivityacts as a dismissible fallback loginsurface. Hardware/gesture back already worked there —
LoginActivity.handleBackBehavior()finishes the activityand returns to the native login activity when
nativeLoginActivity != null. But the visible top-bar backaffordance never appeared, so a user who reached the fallback WebView had no on-screen way back and could get
stranded.
The visible affordance is bound to
LoginViewModel.shouldShowBackButton, which previously gated only onwhether there were authenticated users. This change makes the visible button match the already-correct back
behavior in the Native Login fallback case.
Root cause
LoginViewModel.shouldShowBackButtonreturned!(authenticatedUsers.isNullOrEmpty() || biometricAuthenticationManager?.locked). In Native Login fallbackmode there are typically no authenticated users yet, so the button was suppressed — even though
handleBackBehavior()would have dismissed the screen.Fix
libs/SalesforceSDK/src/com/salesforce/androidsdk/ui/LoginViewModel.kt— rewrote the property as awhen:Behavior preserved:
moveTaskToBack) is unchanged.NativeLoginManager.shouldShowBackButton(the app's own native login screen) is a different surface and isintentionally not touched — it correctly continues to gate on authenticated users.
Tests
libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/auth/LoginViewModelTest.kt— 2 new tests:test_shouldShowBackButton_isTrueForNativeLoginFallbackWithNoUsers— asserts the button shows whennativeLoginActivity != nulland there are no authenticated users. Fails on the pre-fix code (failing-test-first).test_shouldShowBackButton_isFalseForNativeLoginFallbackWhenBiometricLocked— asserts biometric-locked still suppresses the button even in fallback mode. Pins the no-authenticated-users precondition so the biometric branch is the only thing that could show the button, proving the lock takes precedence.Both tests share a small
withNativeLoginFallbackViewModel { … }helper that spiesSalesforceSDKManagerto report Native Login is enabled and always tears the object mock down in afinally.Verification
1. Instrumented unit tests (API 36 emulator)
devtipc6fa97b03(no drift).test_shouldShowBackButton_isTrueForNativeLoginFallbackWithNoUsersFAILS ("Back button must be shown for the Native Login WebView fallback") — confirms the bug is real and still
present on latest dev.
NativeLoginManagerTest21/0.LoginViewModelTestrunsshow occasional order-dependent failures in unrelated tests (
generateAuthorizationUrl_*,codeVerifier_UpdatesOn_WebViewRefresh). The pristinedevsuite flakes at the same ~10% rate and on adifferent unrelated test, so this is pre-existing suite instability, not caused by this change. All such
tests pass in isolation. Out of scope for this bugfix.
2. End-to-end feature verification against the real Native Login feature (API 36 emulator)
The unit tests above exercise the
LoginViewModelin isolation with mocks. To prove the actual user-facingbehavior, I also ran the
AndroidNativeLoginTemplate(from the MSDK Templates repo) against a realExperience Cloud org with Headless Identity, wired to this branch via a Gradle composite build, and drove the
exact repro on-device: launch → native login screen → tap "Looking for Salesforce Log In?" → WebView
fallback
com.salesforce.androidsdk.ui.LoginActivity, with zero authenticated users (the reported brokenscenario). I captured both the screenshot and the
uiautomatorview hierarchy for each side:LoginActivitytoolbarcontent-desc="Back"nodedev)[43,181][106,244]The before/after difference is exactly the affordance this PR restores, confirmed both visually and in the
uiautomatoraccessibility hierarchy. The template clone used real test-org credentials that are notcommitted anywhere.
Before — WebView fallback
LoginActivity, no authenticated users (tip ofdev, without this fix)Toolbar shows only the ⋮ overflow; there is no back affordance, so the user is stranded.
BEFORE screenshot: no back button in the top-left of the WebView fallback toolbar.
After — same screen, same conditions, with this fix
The ← back affordance is present in the top-left and returns the user to the native login screen.
AFTER screenshot: ← back button present in the top-left of the WebView fallback toolbar.
Regression risk
Low, and bounded to Native-Login apps. The rewrite is behavior-preserving for every path except the one
being fixed. Reasoning, per input:
whenadds exactly one arm keyed onnativeLoginActivity != null. That condition is true only when an app has opted into Native Login viauseNativeLogin(...); apps that don't are completely unaffected.false— a locked user can never be shown theaffordance. Equivalent to the old expression's
biometricAuthenticationManager?.lockedterm, and covered bytest_shouldShowBackButton_isFalseForNativeLoginFallbackWhenBiometricLocked.elsearm is the original predicate!userAccountManager.authenticatedUsers.isNullOrEmpty(), so the standard host-picker / login-without-accountsflow (which relies on
moveTaskToBack) behaves exactly as before.LoginActivity.handleBackBehavior()alreadyfinished the activity and returned to the native login activity in this case; hardware/gesture back already
worked. This PR only makes the visible affordance agree with behavior that already shipped — it does not add
a new navigation path.
NativeLoginManager.shouldShowBackButton(the app's own native login screen) is a different surface and isnot touched — it continues to gate on authenticated users.
(Make login server picker non-dismissable (W-23731759) #2983) added a pre-existing guard test,
test_shouldShowBackButton_isFlagIndependent, asserting the property does not depend on the deprecatedforceAdvancedAuthenticationflag. This change keeps that test green — the flag never enters the newwhen.shouldShowBackButtonremains anopen valof the same type; only itscomputed value changes in the fallback case. No semver/deprecation impact.
Checklist
isFlagIndependentguard still green.nativeLoginActivity, orthogonal to account count.This response was generated by an AI agent on behalf of @JohnsonEricAtSalesforce.