Skip to content

fix: improve offline indicator accuracy with HTTP probe#387

Merged
dcalhoun merged 4 commits intotrunkfrom
fix/offline-indicator-accuracy
Mar 18, 2026
Merged

fix: improve offline indicator accuracy with HTTP probe#387
dcalhoun merged 4 commits intotrunkfrom
fix/offline-indicator-accuracy

Conversation

@dcalhoun
Copy link
Copy Markdown
Member

@dcalhoun dcalhoun commented Mar 18, 2026

What?

Fixes the offline indicator not appearing in Android WebView, and improves its accuracy across all platforms.

Why?

Two issues:

  1. Android WebView never fires online/offline events — a known long-standing WebView limitation. Unlike Chrome (a full browser with its own network stack), Android WebView does not synthesize these events when OS network state changes, so the offline banner never appeared.
  2. navigator.onLine and browser online/offline events are unreliable on other platforms — they only confirm a network interface is active, not that the internet is reachable. Chrome is also known to not fire the offline event in all network loss scenarios.

Fix CMM-1945. Follow up on #366 (comment).

How?

Android native polyfill

Adds a ConnectivityManager.NetworkCallback inside GutenbergView that monitors OS network state and synthesizes window.dispatchEvent(new Event('online'|'offline')) into the WebView — a transparent polyfill requiring no host app changes. The callback is registered in onAttachedToWindow and unregistered in onDetachedFromWindow. Also adds the required ACCESS_NETWORK_STATE permission to the library manifest (a normal permission; no runtime grant needed).

JS probe-based connectivity strategy

Replaces the simple event listener approach with an asymmetric strategy:

  • Initial state reads navigator.onLine. A false value is trusted immediately (definitive signal the device has no interface). A true value triggers a mount-time probe to catch misreported online status before any event fires.
  • offline event: trusted immediately — this signal is reliable.
  • online event: verified by a lightweight HEAD probe before clearing the indicator, guarding against false positives.

The probe targets siteApiRoot from the GBKit config, testing actual WordPress API reachability. Falls back to /favicon.ico in local dev environments.

Testing Instructions

  1. If set, remove GUTENBERG_EDITOR_URL from local.properties.
  2. Run make build to build the latest JavaScript.
  3. Open the Android demo app editor on a device or emulator.
  4. Toggle airplane mode on — verify the offline banner appears.
  5. Toggle airplane mode off — verify the banner disappears.

Accessibility Testing Instructions

The offline indicator uses wp.a11y.speak() to announce connectivity loss to screen readers. Verify the announcement is made when going offline.

Screenshots or screencast

Screen recording

android-working-offline.mp4

Screenshot

android-working-offline

@dcalhoun dcalhoun added the [Type] Bug An existing feature does not function as intended label Mar 18, 2026
@dcalhoun dcalhoun force-pushed the fix/offline-indicator-accuracy branch 2 times, most recently from f9b8186 to 2e8c892 Compare March 18, 2026 15:47
dcalhoun and others added 2 commits March 18, 2026 10:49
Replaces the simple event listener approach with an asymmetric strategy:

- Initial state reads navigator.onLine. A false value is trusted immediately.
  A true value triggers a mount-time probe to catch misreported online status.
- offline event: trusted immediately — this signal is reliable.
- online event: verified by a lightweight HEAD probe before clearing the
  indicator, guarding against false positives.

The probe targets siteApiRoot from the GBKit config, testing actual WordPress
API reachability. Falls back to /favicon.ico in local dev environments.

An AbortController guards in-flight probe callbacks against calls to
setIsConnected after the component unmounts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ffline events in WebView

Android WebView does not fire online/offline events when OS network state
changes, unlike a full browser. Adds a ConnectivityManager.NetworkCallback
inside GutenbergView that monitors OS network state and dispatches
window.dispatchEvent(new Event('online'|'offline')) into the WebView —
a transparent polyfill requiring no host app changes.

Tracks the set of available networks so that onLost (which fires per-network,
not when all connectivity is gone) only signals offline when no networks
remain, preventing false offline flashes on devices with WiFi and cellular.

The callback is registered in onAttachedToWindow and unregistered in
onDetachedFromWindow. Adds the required ACCESS_NETWORK_STATE permission
to the library manifest (a normal permission; no runtime grant needed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dcalhoun dcalhoun force-pushed the fix/offline-indicator-accuracy branch from 2e8c892 to 84d32a2 Compare March 18, 2026 15:49
dcalhoun and others added 2 commits March 18, 2026 11:00
…st data races

`availableNetworks` is mutated from `ConnectivityManager.NetworkCallback`
threads; wrap it in `Collections.synchronizedSet` to prevent
`ConcurrentModificationException`. Mark `lastKnownConnectivity` as
`@Volatile` so the main thread always reads the latest value written by
the callback thread.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The siteApiRoot may be on a different origin without CORS headers. Using
`mode: 'no-cors'` skips preflight for HEAD requests so a missing
`Access-Control-Allow-Origin` header does not cause the probe to report
offline incorrectly. The response is opaque, but only reachability (not
the body) is needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dcalhoun dcalhoun marked this pull request as ready for review March 18, 2026 16:19
@dcalhoun dcalhoun requested a review from adalpari March 18, 2026 16:20
Copy link
Copy Markdown

@adalpari adalpari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works great!! 🚢 it!

@dcalhoun dcalhoun merged commit a052f11 into trunk Mar 18, 2026
14 checks passed
@dcalhoun dcalhoun deleted the fix/offline-indicator-accuracy branch March 18, 2026 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants