Skip to content

android: Use Android's scroll physics, and let hosts register an AssetSource - #13

Merged
huacnlee merged 1 commit into
mainfrom
tuyc/android-host-fixes
Sep 16, 2026
Merged

huacnlee merged 1 commit into
mainfrom
tuyc/android-host-fixes

Conversation

@tuyc

@tuyc tuyc commented Sep 16, 2026

Copy link
Copy Markdown

Two gaps a host app hits on the android::host path. Both are Android-only:
everything here lives under src/android/, which lib.rs gates behind
#[cfg(target_os = "android")], so iOS does not compile it. Verified by
building the crate for aarch64-apple-ios with these changes applied.

Flings used iOS physics

AndroidPlatform never implemented Platform::gestures, so GPUI fell back to
GestureTuning::default() — whose scroll_physics is UIScrollView's
exponential decay. Every Android app built on gpui-mobile has therefore been
flinging with iOS physics: the content coasts much further than the platform's
own scroll views, which reads as the list not stopping where you expect.

This returns ScrollPhysics::android() instead, the AOSP OverScroller
friction spline that already lives in gestures.rs. GPUI flings in logical
pixels and a window's scale factor is Android's display density, so logical
pixels are density-independent pixels and the constructor's nominal 160 dpi
pairing is the right one.

Measured on a Huawei P40 (1080x2340 @3x), same conversation and gesture script,
counting frames for 2.5s after release:

fling iOS physics Android physics
swipe 80ms 71 frames 58 frames
swipe 300ms 60 frames 41 frames

Fewer frames because the spline sheds speed faster and the fling travels a
shorter distance — the point of the change, not a regression. Frame pacing is
unchanged: 16ms intervals throughout, droppedFrames = 0 in both.

The rest of ViewConfiguration (touch slop, tap timeouts) stays on GPUI's
defaults; reading the real values over JNI is a separate change.

A host could not install an asset source

host::start hands the launch closure a &mut App, which is one step too late
to install an asset source: Application::with_assets consumes the builder, and
the builder is created inside on_surface_created where the host cannot reach
it.

The failure is silent. AssetSource::load returning None is a valid answer,
so nothing logs and anything resolved through the asset source — icons, SVGs —
simply does not appear.

start_with_assets stores the configuration step in a static that
on_surface_created consumes when it builds the Application, right before
run_embedded. start keeps its current shape for hosts that do not need one.

Testing

  • Huawei P40, android::host path, release build: flings and scrolling as
    above, no panics, droppedFrames/lateAcquireFrames both 0.
  • cargo check --target aarch64-linux-android and
    cargo check --target aarch64-apple-ios both clean.

…tSource

Two gaps a host app hits on the `android::host` path.

**Flings used iOS physics.** `AndroidPlatform` never implemented
`Platform::gestures`, so GPUI fell back to `GestureTuning::default()` — whose
`scroll_physics` is `UIScrollView`'s exponential decay. Every Android app built
on gpui-mobile has therefore been flinging with iOS physics: the content coasts
much further than the platform's own scroll views, which reads as the list not
stopping where you expect. Return `ScrollPhysics::android()` instead, the AOSP
`OverScroller` friction spline that already lives in `gestures.rs`. GPUI flings
in logical pixels and a window's scale factor is Android's display density, so
logical pixels are density-independent pixels and the constructor's nominal
160 dpi pairing is the right one.

Measured on a Huawei P40 (1080x2340 @3x), same conversation and gesture script,
2.5s after release:

    fling 80ms    iOS physics: 71 frames    Android physics: 58 frames
    fling 300ms   iOS physics: 60 frames    Android physics: 41 frames

Fewer frames because the spline sheds speed faster and the fling travels a
shorter distance — the point of the change, not a regression. Frame pacing is
unchanged (16ms intervals throughout, no dropped frames). The rest of
`ViewConfiguration` (touch slop, tap timeouts) stays on GPUI's defaults;
reading the real values over JNI is a separate change.

**A host could not install an asset source.** `host::start` hands the launch
closure a `&mut App`, which is one step too late: `Application::with_assets`
consumes the builder, and the builder is created inside `on_surface_created`
where the host cannot reach it. A host that renders SVGs or icons through the
asset source gets empty results with no error — `AssetSource::load` returning
`None` is a valid answer, so nothing logs and the icons simply do not appear.
`start_with_assets` stores the configuration step in a static that
`on_surface_created` consumes when it builds the `Application`, right before
`run_embedded`; `start` keeps its current shape for hosts that do not need one.
@tuyc
tuyc force-pushed the tuyc/android-host-fixes branch from 132ef3d to 32c3ea1 Compare September 16, 2026 11:31
@huacnlee
huacnlee merged commit 4e4668d into main Sep 16, 2026
5 checks passed
@huacnlee
huacnlee deleted the tuyc/android-host-fixes branch September 16, 2026 12:28
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.

2 participants