Skip to content

Fix #5163: status-bar tap scrolls to top only once per Form#5164

Merged
shai-almog merged 2 commits into
masterfrom
fix-5163-statusbar-tap-rearm
Jun 4, 2026
Merged

Fix #5163: status-bar tap scrolls to top only once per Form#5164
shai-almog merged 2 commits into
masterfrom
fix-5163-statusbar-tap-rearm

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Problem

Reported in #5163: on device (iPhone 15 Pro Max, iOS 26.5), tapping the status bar scrolls the Form to the top, but only once after the Form is shown. Scroll down again and the next tap does nothing; switching to another Form and back re-enables exactly one more working tap. The simulator's "iOS Status Bar Tap" menu can't reproduce it because that path bypasses the proxy.

Root cause

The "tap status bar → scroll to top" feature uses a synthetic UIScrollView proxy (CN1StatusBarTapProxyView) pinned to the status-bar strip at the UIWindow level. iOS only routes UIStatusBarTapAction to a scroll view whose contentOffset.y > 0 (i.e. it looks "scrolled away from top"), so the proxy is kept at contentOffset = (0,1) to stay eligible.

cn1FireStatusBarTap() re-armed that offset synchronously — but it runs from inside scrollViewShouldScrollToTop: while UIKit is still mid-tap. UIKit settles the proxy back toward the top after the delegate returns, clobbering our reset, so the proxy ends up at offset 0 and is no longer eligible. iOS then stops delivering taps until the next viewDidAppear re-pins the offset — hence "works exactly once per Form appearance."

The Java half (Form.findScrollableChild + scrollRectToVisible) is stateless and would scroll on every invocation, which is what localizes the bug to the native re-arm.

Fix

Bounce the (0,1) re-arm to the next main-queue turn via dispatch_async, so UIKit finishes processing the gesture before we restore the offset. The re-arm then sticks and the proxy stays eligible for every subsequent tap. Low-risk: it only changes when the existing one-line reset runs, and dispatch_async to the main queue is safe regardless of which thread cn1FireStatusBarTap is invoked from (including the instrumented test path).

Verification

This is device-only (the simulator status-bar menu bypasses the proxy). The exposed diagnostic counter can confirm before/after:

Display.getInstance().getProperty("cn1.iosStatusBarTap.count", "0")

Before the fix the count stops incrementing on the second tap; after the fix it increments on every tap.

🤖 Generated with Claude Code

The iOS "tap status bar to scroll to top" proxy (CN1StatusBarTapProxyView)
is only eligible for UIStatusBarTapAction routing while its contentOffset.y
is > 0. cn1FireStatusBarTap reset that offset back to (0,1) synchronously,
but it runs from inside scrollViewShouldScrollToTop: while UIKit is still
processing the tap, so the reset was clobbered and the proxy settled at
offset 0. iOS then stopped delivering further taps until the next
viewDidAppear re-pinned the offset -- producing the reported "scroll to top
only works once after showing a Form" behavior.

Bounce the re-arm to the next main-queue turn so UIKit finishes the gesture
first and the (0,1) offset actually sticks, keeping the proxy eligible for
every subsequent tap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented Jun 4, 2026

Compared 122 screenshots: 122 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 153 seconds

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 688.000 ms
Base64 CN1 encode 1343.000 ms
Base64 encode ratio (CN1/native) 1.952x (95.2% slower)
Base64 native decode 430.000 ms
Base64 CN1 decode 1136.000 ms
Base64 decode ratio (CN1/native) 2.642x (164.2% slower)
Base64 SIMD encode 499.000 ms
Base64 encode ratio (SIMD/native) 0.725x (27.5% faster)
Base64 encode ratio (SIMD/CN1) 0.372x (62.8% faster)
Base64 SIMD decode 449.000 ms
Base64 decode ratio (SIMD/native) 1.044x (4.4% slower)
Base64 decode ratio (SIMD/CN1) 0.395x (60.5% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 65.000 ms
Image createMask (SIMD on) 15.000 ms
Image createMask ratio (SIMD on/off) 0.231x (76.9% faster)
Image applyMask (SIMD off) 184.000 ms
Image applyMask (SIMD on) 122.000 ms
Image applyMask ratio (SIMD on/off) 0.663x (33.7% faster)
Image modifyAlpha (SIMD off) 156.000 ms
Image modifyAlpha (SIMD on) 89.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.571x (42.9% faster)
Image modifyAlpha removeColor (SIMD off) 177.000 ms
Image modifyAlpha removeColor (SIMD on) 125.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.706x (29.4% faster)
Image PNG encode (SIMD off) 1275.000 ms
Image PNG encode (SIMD on) 1145.000 ms
Image PNG encode ratio (SIMD on/off) 0.898x (10.2% faster)
Image JPEG encode 616.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented Jun 4, 2026

Compared 103 screenshots: 103 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 264 seconds

Build and Run Timing

Metric Duration
Simulator Boot 93000 ms
Simulator Boot (Run) 1000 ms
App Install 13000 ms
App Launch 8000 ms
Test Execution 1504000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented Jun 4, 2026

Compared 122 screenshots: 122 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 206 seconds

Build and Run Timing

Metric Duration
Simulator Boot 72000 ms
Simulator Boot (Run) 0 ms
App Install 20000 ms
App Launch 6000 ms
Test Execution 351000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1296.000 ms
Base64 CN1 encode 1521.000 ms
Base64 encode ratio (CN1/native) 1.174x (17.4% slower)
Base64 native decode 520.000 ms
Base64 CN1 decode 1920.000 ms
Base64 decode ratio (CN1/native) 3.692x (269.2% slower)
Base64 SIMD encode 509.000 ms
Base64 encode ratio (SIMD/native) 0.393x (60.7% faster)
Base64 encode ratio (SIMD/CN1) 0.335x (66.5% faster)
Base64 SIMD decode 605.000 ms
Base64 decode ratio (SIMD/native) 1.163x (16.3% slower)
Base64 decode ratio (SIMD/CN1) 0.315x (68.5% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 73.000 ms
Image createMask (SIMD on) 13.000 ms
Image createMask ratio (SIMD on/off) 0.178x (82.2% faster)
Image applyMask (SIMD off) 215.000 ms
Image applyMask (SIMD on) 88.000 ms
Image applyMask ratio (SIMD on/off) 0.409x (59.1% faster)
Image modifyAlpha (SIMD off) 200.000 ms
Image modifyAlpha (SIMD on) 110.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.550x (45.0% faster)
Image modifyAlpha removeColor (SIMD off) 323.000 ms
Image modifyAlpha removeColor (SIMD on) 188.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.582x (41.8% faster)
Image PNG encode (SIMD off) 1386.000 ms
Image PNG encode (SIMD on) 1202.000 ms
Image PNG encode ratio (SIMD on/off) 0.867x (13.3% faster)
Image JPEG encode 619.000 ms

Refresh the 34 Mac native (Catalyst/Metal) goldens that the
build-mac-native job reported as "different", adopting the images
generated by the scripts-mac-native run on this branch. These are all
theme/rendering drift (ButtonTheme, DialogTheme, ToolbarTheme, etc.) on
the maturing Mac slice; the 88 other tests still match and no test is
newly missing.

Generated by: scripts-mac-native run 26923979109.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog merged commit 3af3c17 into master Jun 4, 2026
18 checks passed
@shai-almog shai-almog deleted the fix-5163-statusbar-tap-rearm branch June 4, 2026 02:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant