mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
704 lines
41 KiB
Markdown
704 lines
41 KiB
Markdown
# Unified input validation
|
||
|
||
Recorded on 2026-10-24. These results distinguish the device-tested candidate from
|
||
the later upstream rebase and host regression fixes. They do not establish zero
|
||
latency or complete coverage of every controller and session mode.
|
||
|
||
## UI publication candidate, 2026-11-06
|
||
|
||
The implementation was updated through upstream `a1bc8467f` (merge `aa3757eff`).
|
||
The generic action selector now says **Scroll**; binding summaries still state
|
||
the configured direction. Closing the docked session drawer now invokes its
|
||
ordinary close action instead of disabling the second-screen presentation.
|
||
The global-reset regression compares against a pristine compiled library, which
|
||
includes the editable gamepad's keyboard element.
|
||
|
||
- All **944 input/UI tests in 125 suites passed**. The final full JVM run completed
|
||
**3,598 tests in 493 suites: 3,573 passed, 25 failed, no errors or skips**.
|
||
The failures are the same unchanged upstream log-export tests (24) and
|
||
case-sensitive WoW add-on import test (1) described below. Input/UI and global
|
||
settings reset passed in this full run.
|
||
- Initial full runs exhausted this Mac's free disk and produced secondary native
|
||
runtime/idle failures. Obsolete local test APKs were removed. The completed run
|
||
used a local Gradle init script with one worker and a fresh test JVM every 25
|
||
classes to bound temporary-file use. No repository test configuration was
|
||
weakened and no tests were excluded from the completed run.
|
||
- The APK passed runtime-input, session-asset, native dependency, alignment and
|
||
v1/v2/v3 signature checks. SHA-256:
|
||
`611814f11cbac4bab7f97dac5c0b0657d85d8dfbd6b40b741bda1fc13efa6f83`.
|
||
It was installed over the separate Input Test app with its environment intact;
|
||
as with earlier local candidates, Rust store engines were omitted.
|
||
- On AYN Thor, closing the lower-screen menu with its X restored the existing
|
||
controls instead of revealing Android. The live Steam editor, separate lower
|
||
canvas and upper tools/properties, profile previews, saved layouts, and action
|
||
pages were exercised. A single Trigger selection added a centered, selected
|
||
element; the reported occasional extra tap was not reproduced. The temporary
|
||
editor change was discarded.
|
||
- The user also verified native controls, profile switching, trackpad/pointer
|
||
and scrolling behavior on the immediately preceding UI candidate. This is
|
||
distinct from automated UI navigation and the historical latency measurements.
|
||
|
||
Actual display captures and test reports are retained locally under
|
||
`app/build/reports/input-publish/`. Screenshot publication is subject to the
|
||
user's review. No new latency measurement was made for this UI revision.
|
||
|
||
The follow-up router-ownership fix passed **47 tests** in `InputSourceOwnershipTest`,
|
||
`InputSurfaceSourceTest`, and `InputRouterTest`, including two new regressions.
|
||
An obsolete activity (or one without a router) cannot detach the replacement
|
||
activity's Deck routes; the current owner still releases its held keys on cleanup.
|
||
GitHub's complete Build APK workflow passed for `7b7722bd2`.
|
||
|
||
### Review follow-up
|
||
|
||
- Upgrade binding IDs are deterministic across unsuccessful reads. Editor lookup
|
||
from an earlier read remains valid when legacy screen-key import fails.
|
||
- An edit of malformed supported-version data commits both the restored library
|
||
and a recovery copy of the original text. Reads alone preserve the original;
|
||
newer unsupported versions remain protected against overwrite. Settings show
|
||
that recovery data was retained.
|
||
- Focus/capture loss releases hardware, Android keyboard and PC-keyboard owners
|
||
without releasing another source's hold. Secondary settings handle an invalid
|
||
presentation display at initial show and resume.
|
||
- Physical-button capture waits for release before confirmation/navigation.
|
||
Back and B remain assignable; another Back/B press cancels, A confirms, and
|
||
Retry starts a new capture. The existing dialog-window key hook is reused.
|
||
- Steam Controller BLE teardown synchronously closes its routed source and
|
||
gates state/feature publication. Queued callbacks and starts cannot reactivate
|
||
it after stop returns; disconnect work remains on the existing BLE thread.
|
||
|
||
The input/UI/global-reset run passed **959 tests in 127 suites**. After the
|
||
additional BLE finding, **5 BLE/routing tests passed**, including two regressions
|
||
for queued callbacks, synchronous release, source detachment and shared holds.
|
||
The final APK passed packaging, runtime/native dependency and signature checks:
|
||
`a5ec9120be120b829748f8489782a0c7158360d7f8deb61777fe75d601708d20`.
|
||
It was installed over Input Test; saved profile preferences remained byte-for-byte
|
||
identical and the existing environment was retained.
|
||
The button-capture dialog opened and cancelled on Thor without a crash. No
|
||
physical BLE-controller check or new latency measurement was made for these
|
||
follow-ups.
|
||
|
||
### Replacement-controller and mouse-backend follow-up
|
||
|
||
The Triton slot now has a single owner across activity instances. Late reports,
|
||
subscription callbacks, feature replies and teardown from a replaced controller
|
||
cannot overwrite the current controller's report or connection flag. Every
|
||
instance still closes its own routed source. Claiming the slot happens once at
|
||
start; a queued or repeated old start cannot take it back.
|
||
|
||
Legacy Select-to-Steam also migrates to the Desktop physical profile when there
|
||
is no saved Desktop profile. An existing Desktop assignment is preserved.
|
||
Mouse backend selection and publication share the button-owner lock with raw
|
||
channel open, soft release and destruction. Horizontal and vertical scrolling
|
||
use the same path and fall back to Wayland after leaving raw mode.
|
||
|
||
The complete input/UI/global-reset run passed **967 tests in 128 suites**.
|
||
The focused run passed **28 tests**, including replacement subscription before
|
||
old teardown, unstarted-instance teardown, saved/default Desktop migration, and
|
||
concurrent scroll versus raw-channel release/destruction. These changes add no
|
||
input queue or timer. Physical BLE hardware and latency remain unmeasured for
|
||
this follow-up.
|
||
|
||
### Upstream integration, 2026-11-07
|
||
|
||
Merged upstream through `542bbf89c`. The shared stick renderer retains the new
|
||
fast-double-tap rule from #2173, including cancelled, dragged, long-held and slow
|
||
second taps; the six upstream regressions were adapted to the profile-backed
|
||
renderer. WoW chat uses the existing custom lower-screen presentation and shared
|
||
key ownership, preserving Ctrl held by another input source. The new platform
|
||
pointer, PiP, component-update and store-launch changes are retained.
|
||
|
||
The merged candidate passed **1017 tests in 133 suites**, with no failures,
|
||
errors or skips: all input/UI tests, global reset, component updates, PiP policy,
|
||
runtime auto-update and Proton menu auto-selection. The gamescope p22 archive
|
||
was downloaded from the newly pinned component repository and verified against
|
||
upstream's SHA-256 before refreshing the local runtime inputs.
|
||
|
||
### Second-screen refresh follow-up, 2026-11-07
|
||
|
||
Refreshing a profile now updates the existing custom control surface in place.
|
||
Terminal and dashboard modes are untouched, and the custom surface keeps its
|
||
keyboard host, field-keyboard state and WoW chat panel. Actual mode changes
|
||
continue to use the existing full teardown/rebuild path.
|
||
|
||
All **35 tests in 5 suites passed** across `SessionSecondScreenTest`, the
|
||
surface UI suites and `InputSurfaceSourceTest`. Three new regressions cover
|
||
terminal/dashboard identity, changed elements/style with an open field keyboard,
|
||
and preservation of the lower-screen chat view and its dismissal callback.
|
||
|
||
## Input settings polish, 2026-11-06
|
||
|
||
The final input/UI host run passed **941 tests in 124 suites, zero failures**.
|
||
New coverage includes retained route/action drafts, centered element creation
|
||
without a placement tap, collapsed quick-profile settings, schema-4 migration
|
||
with a layout shared across both screens, target/scroll serialization, and
|
||
horizontal scrolling through both guest mouse backends. Existing physical native
|
||
fast-path and ownership tests remain green.
|
||
|
||
The settings use stable DroidDeck Input labels, contextual axis/contact hints,
|
||
color swatches, opacity sliders and rendered layout thumbnails. Diagnostics now
|
||
open a result dialog and explain how to record a sample and what it measures.
|
||
Shortcut rows show the actual assignment and offer Restore to default.
|
||
|
||
No new latency comparison was taken for this UI revision. The normal native
|
||
controller path is unchanged. New horizontal wheel work happens only for a local
|
||
scroll action. The user's environment installation is retained. Device verification is recorded below.
|
||
|
||
### Screen-key removal and Thor verification
|
||
|
||
The old screen-key overlay, standalone editor, layout panel and separate runtime
|
||
key sender are removed. Schema 6 imports the old active set and every named set
|
||
as editable profiles. Current defaults and selections are kept. Tests cover
|
||
idempotent import, chords, normalized geometry, per-element opacity, shapes,
|
||
image references, symbols, custom diagonals, and retaining the original data
|
||
when migration cannot complete. A backup and the converted library are committed
|
||
together before the old preferences are removed.
|
||
|
||
New shared element tests exercise latched keyboard and native controller buttons,
|
||
shared ownership, cancellation, menu suspension and profile replacement. Separate
|
||
diagonal bindings release previous keys and preserve neighboring-direction
|
||
fallbacks. No additional input queue or thread is used.
|
||
|
||
Final APK installed over `com.droiddeck.launcher.inputtest` on AYN Thor:
|
||
`6618be55c28a52746b6504656a480845d25d8a34114daa1829aad5dbb5b5e729`.
|
||
Packaging checked runtime inputs, session assets, native library dependencies and
|
||
v1/v2/v3 signatures. As with the earlier test packages, Rust store engines are
|
||
omitted; the Steam/Desktop environment is retained.
|
||
|
||
On-device checks:
|
||
|
||
- The expanded Profile has readable text and one visibly grouped block.
|
||
- Profile source rows and saved-layout rows show bounded thumbnails. The previous
|
||
black rectangle overflowing the list no longer appears.
|
||
- The original anchored color menu shows its color swatches.
|
||
- Steam → Controller → Edit opens settings on the spare display.
|
||
- Main-screen editing opens on the activity display over live Steam. A second
|
||
on-device crash was found and fixed: returning from lower-display settings must
|
||
use the existing activity dialog, not a Presentation on the default display.
|
||
- Adding a button immediately centers and selects it. Its properties and symbol
|
||
picker open on the main display.
|
||
- Secondary-screen editing leaves only the canvas below and tools above. Adding
|
||
a trackpad centers and selects it without requiring another placement touch.
|
||
- Temporary edits were discarded. Comparing the before/after saved libraries,
|
||
excluding new default schema fields, found no changes to the user's profiles,
|
||
geometry, bindings or selections. Schema changed from 5 to 6.
|
||
- Steam remained READY after closing the editors; the final device log contained
|
||
no new fatal exception.
|
||
|
||
The test device had no old screen-key sets to import. Legacy content migration
|
||
and toggle ownership were verified by host regression tests, not by a new
|
||
physical-input latency or end-to-end game test. Evidence is under
|
||
`app/build/reports/input-polish/`; the final installable copy is
|
||
`app/build/input-ui/DroidDeck-Input-Test-unified-screenkeys-2026-11-06.apk`.
|
||
|
||
## Unified editor and session profile composition, 2026-11-06
|
||
|
||
The fixed gamepad and its separate editor are replaced with a saved editable
|
||
layout rendered by `InputSurfaceView` on either display. The old fixed lower
|
||
panel, tab switches and separate mouse trackpad view are removed. Deck pads,
|
||
grips, single pads, the mouse trackpad and a compact gamepad are editable presets;
|
||
their menu, keyboard and click buttons are normal elements. The compact preset
|
||
reuses the previous panel geometry calculation.
|
||
|
||
Schema 4 migrates version-2 overlay references, mappings, saved positions,
|
||
appearance and stick-click preferences, and version-3 fixed lower layouts.
|
||
Other resolution-specific positions remain saved layouts. Future or invalid
|
||
libraries are not overwritten. Physical mappings retain their identities and
|
||
assignments. Existing custom layouts remain intact.
|
||
|
||
On two displays, the activity hosts Add, Undo, Snap, Done and full-size properties;
|
||
the other display contains only the canvas, without a reserved toolbar strip.
|
||
On the main display a draggable Tools bubble expands into the same tools,
|
||
including Properties. The editor snaps centers and edges while moving and
|
||
resizing. Both source pages list their actual elements. Device settings are
|
||
inline below the profiles.
|
||
|
||
The quick menu selects a whole profile or overrides Physical controller, Main
|
||
screen and Second screen independently. Game and Desktop selections are separate.
|
||
Changes do not mutate the source profiles; saving a combination creates independent
|
||
copies. Returning to Auto clears the overrides. Tests cover serialization,
|
||
reference validation, deletion protection and preservation of source profiles.
|
||
|
||
The complete input/UI host run passed **931 tests in 124 suites, zero failures**.
|
||
Coverage includes full-size shared editing, floating tools, display removal,
|
||
geometry migration, source ownership during detach/layout replacement, quick-menu
|
||
composition and saving, native Deck clicks and mouse gestures. Tap and hold use
|
||
the configured element click; ordinary taps do not reposition the cursor. Profile
|
||
changes and menu suspension suppress delayed gesture presses until neutral.
|
||
The neutral-stick/physical-input regression remains covered.
|
||
|
||
No new end-to-end latency measurement was performed for this revision. The
|
||
physical controller path remains unchanged. Touch output uses the existing
|
||
owned router and guest transports without an additional event queue. Mouse
|
||
movement is delivered synchronously; tap/hold recognition reuses the existing
|
||
`TouchpadGestures` timings. The local APK omits the Rust store engines and uses
|
||
the separate Input Test application ID.
|
||
|
||
Device verification on AYN Thor confirmed the four quick selectors and saved
|
||
second-screen presets, draggable/expandable tools, full-screen properties and a
|
||
canvas-only secondary display. WindowManager reports the main editor at
|
||
`[0,0][1920,1080]`; the secondary canvas uses the full `1240×1080` display.
|
||
The installed library migrated to schema 4 with existing profile references,
|
||
bindings and custom layouts preserved. A previous test migration's unchanged
|
||
main overlay geometry was corrected from its window-size copy to its saved
|
||
1920×1080 version. No user-edited geometry was replaced.
|
||
|
||
Final APK SHA-256: `c13326d11f5e8de3b878d83b296ba2f77495baf5c35d1d00dbb0327333c0277d`.
|
||
Runtime assets, native library dependencies and v1/v2/v3 APK signatures passed
|
||
verification. Focused editor/input checks passed again after fixing Compose 1.6
|
||
fullscreen dialog sizing. Live game/desktop input and perceived latency with this
|
||
final build still need user testing; the device checks above cover UI and migration.
|
||
|
||
## Controller integration and upstream update, 2026-11-06
|
||
|
||
Merged upstream `bf693d7f7` into the working branch as `ba5876bf6` before the UI
|
||
integration. This includes 90 upstream commits, including radial stick dead zones
|
||
and mouse-button handling. The merge keeps routed source ownership and the new
|
||
upstream raw-stick behavior; the targeted input merge checks passed.
|
||
|
||
Controller now contains two default-profile selectors, one profile list and a
|
||
Device settings entry. Source-specific action editing and saved layouts are
|
||
inside each profile. New profiles are independent by default, with an explicit
|
||
option to share physical controls. Direct editing and Hide tools / Show tools
|
||
are retained. No input-event queue or preference lookup was added by this UI
|
||
reorganization.
|
||
|
||
The first full host run executed 3,580 tests in 490 suites: 3,555 passed and 25
|
||
failed, with no skips. All 926 input and UI tests in that run passed. The failures
|
||
are in unchanged upstream log-export tests (24) and WoW add-on import tests (1).
|
||
The log fixtures require `SecureDirectoryStream`, unavailable in this macOS JDK;
|
||
the WoW test assumes `Foo` and `foo` refer to different paths, while this host
|
||
filesystem is case insensitive. A direct Java filesystem probe confirmed both
|
||
conditions. The log-export failures also reproduce when run separately. The
|
||
affected production and test sources match `origin/main`. These host limitations
|
||
have not been hidden by disabling tests or changing production code.
|
||
|
||
The final input/UI-only run passed all 927 tests in 122 suites.
|
||
|
||
Additional final checks cover integration in the existing Setup tabs, the lack
|
||
of duplicate Layout/Configure entries, back navigation, independent creation,
|
||
explicit physical sharing, and preserving elements while hiding editor tools.
|
||
Rendered UI checks cover 360×800, 640×360 and 960×600 dp. Earlier latency results
|
||
below are not a fresh measurement of this revision.
|
||
|
||
The final 26 profile/library/editor checks passed again after the source-specific
|
||
control lists and sharing labels were finalized. The APK passed session-asset
|
||
matching, runtime-input attestation, native dependency/export checks, alignment
|
||
and signing validation. It uses the same local HTTPS/direct-release download
|
||
adaptations as the previous build and still omits the store Rust engines.
|
||
|
||
Installed the update over `com.droiddeck.launcher.inputtest` on AYN Thor without
|
||
clearing data. Verified Setup → Controller → Desktop → Second screen → Edit on
|
||
screen; the canvas opened on the lower display, Hide tools / Show tools worked,
|
||
and selecting the right trackpad opened large properties on the main display.
|
||
Returned without saving; the stored input-profile preferences matched the backup
|
||
exactly. Device settings had no persisted overrides before or after this check.
|
||
No fresh gameplay or latency measurement was performed in this UI pass.
|
||
|
||
Final APK SHA-256:
|
||
`f1d16a503661055a0abe8cc954d3fc94f6b9a1c1c626ac38b6c88dba478810d1`.
|
||
|
||
## Local UI revision, 2026-11-05
|
||
|
||
This revision adds the Profiles / Layouts / Bindings libraries, migration of the
|
||
previous settings, independently identified touch elements, and a direct editor
|
||
on either display with properties on the activity display.
|
||
|
||
- The complete JVM/Compose run passed 3,306 tests across 467 suites, with no
|
||
failures, errors or skipped tests. The native identity fast-path checks remain
|
||
in that suite. After the final editor-window adjustment, all nine editor and
|
||
adaptive-layout UI tests passed again.
|
||
- New coverage includes legacy mapping/geometry/selection migration, shared
|
||
physical presets with separate touch actions, explicit private copies, safe
|
||
deletion/reset, unsupported schema preservation, independent element actions,
|
||
overlapping held outputs, suppression across profile/menu changes, and inert
|
||
editor previews, independent stick/trackpad click bindings, same-view
|
||
detach/reattach, and saving a draft after the auxiliary display disappears.
|
||
- Both Steam and Desktop quick settings expose the same input library entry.
|
||
- Compose navigation was exercised at 360×800, 640×360 and 960×600 dp. Rendered
|
||
images are generated under `app/build/reports/input-ui/`. The properties Save
|
||
control stays outside the scrollable content on the short landscape screen.
|
||
- Updated the existing `com.droiddeck.launcher.inputtest` installation on AYN
|
||
Thor from 0.6.0 to the local 0.6.9 build without clearing its data. The official
|
||
package was not replaced. A local backup of the two input preference files was
|
||
taken before migration; all 61 saved Desktop bindings matched after migration.
|
||
- On Thor, exercised the quick-settings entry, library navigation, full-size
|
||
editing on both displays, selection on the lower display with properties on
|
||
the main display, moving an element, Undo and Done. After undoing the move and
|
||
saving, the complete stored library matched the pre-edit data.
|
||
- The earlier Thor latency measurements below apply to the earlier candidate,
|
||
not to this library/editor revision. No new end-to-end or dispatch latency
|
||
claim is made.
|
||
|
||
The complete local runtime build passed session-asset matching, runtime-input
|
||
attestation, native export/dependency validation, alignment and signature checks.
|
||
The local build-script copy used HTTPS for the Debian archive and direct GitHub
|
||
release downloads when the unauthenticated API was rate limited; checksum and
|
||
revocation checks remained enabled. No build-script changes are included in the
|
||
source diff. As before, the test APK excludes the Epic/GOG/Amazon Rust engines.
|
||
The installed APK SHA-256 is
|
||
`3e3f41589d45b70294f2d59404f591ae76f2ceba8488657e8821aab1bca224b3`.
|
||
|
||
Before publishing, also test on Thor: create two Desktop profiles sharing physical
|
||
bindings; give them different touch actions; edit and resize on the actual lower
|
||
display; open properties on the top display; save/cancel; swap screens; return
|
||
from Android Home; disconnect/reconnect the auxiliary display; and repeat the
|
||
paired physical-button latency measurement. Verify primary custom overlays with
|
||
on-screen controls enabled and secondary layouts in Custom controls mode.
|
||
|
||
## Revisions and environment
|
||
|
||
The Thor candidate was `5021e7ac` on base `ac0909ea`, with the local temporary-file,
|
||
cursor visibility/handoff/frame cadence, scroll direction and button label fixes
|
||
subsequently committed on this branch. Its final APK SHA-256 was
|
||
`bb211095d6443e9f85ed1f5d8c5674f527df2937ac6b0efe7d6fc4adcb9dcf62`.
|
||
|
||
The branch was then rebased onto upstream `906e0d1f`. Review added regressions and
|
||
fixes for final touch-source release, concurrent native trackpad contact ownership,
|
||
and resetting the new preferences. Those final changes and the rebase have host
|
||
test coverage; the installed Thor APK was not silently replaced and those exact
|
||
changes have not yet been revalidated on the device.
|
||
|
||
Local Android builds use Java 17 and NDK `28.2.13676358`. The Thor test APK used a
|
||
local Gradle init script to install alongside the official app; no application ID
|
||
or app-name changes are part of this PR. Local builds use `-PskipRust=true`, so
|
||
Steam/Desktop checks do not establish the behavior of the Epic/GOG/Amazon store
|
||
engines in a complete release build.
|
||
|
||
## Automated checks
|
||
|
||
On the rebased implementation, the complete `:app:testDebugUnitTest` run passed:
|
||
**2,230 tests across 333 suites, zero failures/errors/skips**.
|
||
|
||
The supported `tools/build_local.sh` debug build also passed, including session
|
||
asset matching, runtime-input attestation, native export/dependency validation,
|
||
ZIP alignment and signature verification. The APK SHA-256 was
|
||
`a7d440b4029f9ad67ca6f44c92ccdd6b9eba9e9a758b28ab0e432256697d49b9`.
|
||
The only local environment repair was moving a Finder `.DS_Store` file out of the
|
||
NDK's host-toolchain directory; the upstream script counted it as another host.
|
||
No build checks were disabled to get past the stale-runtime check after rebasing.
|
||
|
||
Commands, with Java/SDK paths configured for the local machine:
|
||
|
||
```sh
|
||
./gradlew :app:testDebugUnitTest -PskipRust=true -PndkVersion=28.2.13676358
|
||
DROIDDECK_BUILD_VARIANT=debug DROIDDECK_SKIP_RUST=1 \
|
||
DROIDDECK_NDK_VERSION=28.2.13676358 bash tools/build_local.sh
|
||
# Linux with gcc and g++ available:
|
||
python3 -m unittest tools.tests.test_fakeinput_open -v
|
||
```
|
||
|
||
Coverage includes profile persistence and migration, invalid bindings, shared
|
||
holds, key order, trigger/direction hysteresis, neutral gating on profile changes,
|
||
source disposal, raw BLE report preservation, physical key capture, global reset,
|
||
existing controller/gesture/keyboard paths, pointer handoff, and Compose settings
|
||
and layout editor behavior.
|
||
|
||
Two additional ownership regressions were demonstrated failing before their
|
||
fixes, then passed in the full suite:
|
||
|
||
- Removing the last local touch surface must send the final release to the legacy
|
||
Epic mouse route, while removing only one of two holds must preserve the other.
|
||
- Concurrent native Deck pad surfaces must retain the first contact's coordinates
|
||
until it ends, then transfer ownership and release correctly.
|
||
|
||
The native preload regression probe compiles the actual library and compares
|
||
`open`, `openat`, `open64` and `openat64` with libc. It covers ordinary file
|
||
creation, `O_TMPFILE` permissions, and opening a directory without a mode argument
|
||
(12 combinations). The temporary-file fix addresses the KDE cache permissions
|
||
problem encountered during the Desktop test; it does not change controller
|
||
transport or publication ordering.
|
||
|
||
All three test methods passed on Linux x86-64 after rebasing. The same 12
|
||
combinations also passed in the earlier i386 probe.
|
||
|
||
Earlier native testing also exposed three i386 ring-test failures, reproduced on
|
||
the unmodified pre-feature baseline. These are not presented as passing or fixed
|
||
by this PR. Physical BLE coverage is likewise not implied by synthetic tests.
|
||
|
||
### PR review follow-up
|
||
|
||
After the first CodeRabbit review of PR #1439, nine regression tests were added
|
||
for deferred pad-ring opening, releases to an already-open ring, system-owned
|
||
Steam/VR actions, and retained input when replacing a router. Seven of the new
|
||
scenarios reproduced failures before the fixes. The retained-input tests cover
|
||
physical and touch button ownership, native sticks, Deck grips and trackpad
|
||
contacts; a separate regression verifies return to the native identity fast path
|
||
without scheduling output after held controls reach neutral.
|
||
|
||
The full `:app:testDebugUnitTest` run now passes **2,239 tests across 334 suites,
|
||
zero failures/errors/skips**. `:app:assembleDebug` also passes with the existing
|
||
verified native inputs and the same Java/SDK/NDK and `-PskipRust=true` settings.
|
||
The resulting APK passes `check_session_assets.py` and `runtime_inputs.py apk`;
|
||
its SHA-256 is
|
||
`1c77c85d5d08c4a054db0528ade33d60eaf8755c09a56a598f342207b27c85d4`.
|
||
|
||
These follow-up changes have not been installed on Thor or benchmarked on the
|
||
device. Retained-state initialization runs when sources attach; ordinary input
|
||
keeps its existing synchronous routing and native identity path. The VR command
|
||
uses the existing chord handler for its release, retaining the 120 ms pulse.
|
||
|
||
### SELECT and panel ownership follow-up
|
||
|
||
The next review covered SELECT-to-GUIDE routing and child-view ownership. The
|
||
existing one-time Select-as-Steam migration is exercised through real controller
|
||
key events, including simultaneous physical GUIDE ownership. Explicit native,
|
||
disabled and local SELECT assignments, and resetting the Game profile, remain
|
||
authoritative. Removing the obsolete bridge flag keeps raw SELECT state stable
|
||
when a router is attached or removed while the button is held.
|
||
|
||
Panel regressions use an attached Android view hierarchy and a two-finger
|
||
trackpad contact. Switching the other stick to a trackpad, or removing the D-pad
|
||
or face buttons, must release only that child's controls and preserve the other
|
||
trackpad's contact, coordinates and click. Whole-panel removal still releases
|
||
the shared source. These three panel scenarios and the retained SELECT scenario
|
||
failed before the fixes; all seven new tests pass after them.
|
||
|
||
The complete JVM run passes **2,246 tests across 336 suites, zero failures/errors/
|
||
skips**. The debug APK build, session-asset check and runtime-input verification
|
||
pass with the same local build settings. APK SHA-256:
|
||
`0d85b4003cd6b31084e50d603e8b00f239775c9c97f3ec17327264db5dd50612`.
|
||
These changes have host coverage only; Thor validation and new latency
|
||
measurements remain pending.
|
||
|
||
### Panel tab teardown follow-up
|
||
|
||
Tab changes now remove the old child views before releasing the panel's touch
|
||
source. Child detach callbacks can publish button releases, so source cleanup
|
||
must run after those callbacks to avoid retaining a neutral source.
|
||
|
||
The new tab-switch regression fails before this fix and passes after it. It
|
||
checks held-button release, removal of the old source before later physical
|
||
input, and touch input after returning to the Gamepad tab. A second regression
|
||
confirms that whole-panel removal already releases the source correctly.
|
||
All **22 targeted tests** in the panel ownership, input ownership and second-screen
|
||
suites pass. The debug APK build, session-asset check and runtime-input
|
||
verification also pass. This follow-up has not been tested on Thor or benchmarked
|
||
on the device.
|
||
|
||
### Upstream integration (2026-10-27)
|
||
|
||
Merged upstream `43a0ce93` while preserving the published PR history. The merge
|
||
retains upstream screen keys, portrait controls and Home/Back shortcuts alongside
|
||
the input profiles and custom second-screen layouts. Screen keys have their own
|
||
held-key owner, and explicit physical Back bindings take precedence over the
|
||
default QAM shortcut.
|
||
|
||
Queued Home/Back chord reports now use current routed axes, including touch
|
||
sources, rather than raw physical axes. Router/profile changes and disabled
|
||
routing discard queued reports. Cancelling a chord or releasing all input keeps
|
||
held controls blocked until neutral, including Deck grips. Ordinary routed input
|
||
still publishes synchronously without waiting for the chord queue.
|
||
|
||
Eleven integration regressions cover these interactions. Four routed-axis and
|
||
cancellation scenarios failed before their fixes. The existing panel ownership
|
||
fixture now explicitly selects a Deck controller, matching upstream's restriction
|
||
of native trackpad controls to that controller type.
|
||
|
||
The complete `:app:testDebugUnitTest` run passes **2,632 tests across 385 suites,
|
||
zero failures/errors/skips**, using Java 17, NDK `28.2.13676358` and
|
||
`-PskipRust=true`. This compiles the Android Java/Kotlin code and resources; a new
|
||
APK build, Thor validation and device latency measurements were not performed
|
||
for this merge.
|
||
|
||
### QAM and repeated enable-state review (2026-10-27)
|
||
|
||
A routed QAM press during an existing emulated chord now publishes simultaneous
|
||
button and stick changes immediately. Repeated enable/disable requests no longer
|
||
republish unchanged pad or Deck reports; the router reports whether its state
|
||
changed, so the bridge does not keep a second copy of that state.
|
||
|
||
Both regressions failed before the fixes. Two additional tests cover replacing a
|
||
disabled router and enabling a router that was disabled before attachment. The
|
||
complete `:app:testDebugUnitTest` run passes **2,636 tests across 385 suites, zero
|
||
failures/errors/skips**, with the same Java/SDK/NDK settings and `-PskipRust=true`.
|
||
These fixes have not been tested or benchmarked on Thor.
|
||
|
||
### Upstream Home/player-slot integration (2026-10-28)
|
||
|
||
Merged upstream `213c2da5` without rewriting the published branch. Home/Guide now
|
||
follows upstream's primary-player slot selection when the built-in pad is off,
|
||
while its report retains routed buttons and axes. The input-settings overlay
|
||
continues to gate Home shortcuts and now also gates upstream's Steam volume-key
|
||
handling.
|
||
|
||
A new regression combines Home on player slot 1 with button/stick remapping and
|
||
disabled routing. The complete `:app:testDebugUnitTest` run passes **2,707 tests
|
||
across 389 suites, zero failures/errors/skips**, using the same Java/SDK/NDK
|
||
settings and `-PskipRust=true`. A new APK build, Thor validation and latency
|
||
measurement were not performed for this merge.
|
||
|
||
### Upstream shortcuts and dual-screen integration (2026-10-30)
|
||
|
||
Merged upstream `6ffe675a` without rewriting the published branch. The merge
|
||
preserves upstream's docked second-screen menu, keyboard routing, remembered
|
||
panel selection, touch routing and physical shortcuts from #1202, together with
|
||
the active input profiles and custom lower-screen layouts.
|
||
|
||
Captured profile keys take precedence over global physical shortcuts, which in
|
||
turn precede default Back/QAM handling. Both use the original device/key identity
|
||
before Joy-Con normalization. Input-profile editing blocks shortcut execution;
|
||
consumed releases remain consumed when a shortcut opens or closes the menu.
|
||
The upstream shortcut configuration remains accessible from the input settings.
|
||
|
||
Mapped mouse output uses upstream's existing Wayland/raw-mouse helpers, retaining
|
||
shared button ownership. Changing the raw-mouse backend releases held buttons on
|
||
the outgoing backend. Touchpad zoom has an independent Ctrl owner, so it cannot
|
||
release Ctrl held by the profile or screen keys. Mapped pointer movement retains
|
||
the frame-callback rendering update and cursor visibility behavior.
|
||
|
||
Eight new regressions cover these interactions and reopening a custom panel with
|
||
either controller type. The upstream shortcut-page UI test now exercises the
|
||
replacement Input profiles page. The complete `:app:testDebugUnitTest` run passes
|
||
**2,918 tests across 413 suites, zero failures/errors/skips**, using Java 17,
|
||
NDK `28.2.13676358` and `-PskipRust=true`. The PR diff against upstream also passes
|
||
`git diff --check origin/main`.
|
||
|
||
This run compiles Android Java/Kotlin and resources. A new APK build, Thor test
|
||
and latency measurement were not performed for this merge; the full release
|
||
build remains an upstream CI check.
|
||
|
||
### Upstream PC input and bottom-screen integration (2026-11-04 UTC)
|
||
|
||
Merged upstream `f0052415` without rewriting the published branch. The merge
|
||
retains the common bottom-screen bar, dashboard, KDE desktop panel, game-screen
|
||
swap, hardware mouse/keyboard fixes and on-screen stick redraw optimization.
|
||
Custom controls use the same bar and preserve their secondary-source bindings
|
||
when the game and panel swap displays. Pointer handoff now lives in upstream's
|
||
shared `SessionTrackpadView`, used in either display arrangement.
|
||
|
||
Physical/IME key translation reuses `GuestKeys`, including keyboard Escape scan
|
||
codes and the Desktop right-Ctrl alias, while preserving shared key ownership.
|
||
The input-profile editor releases upstream's hardware mouse capture. Routed
|
||
on-screen stick movement uses the same redraw throttling as the native overlay;
|
||
pad publication remains synchronous, and mapped cursor frame updates keep their
|
||
existing cadence mechanism.
|
||
|
||
The pointer-handoff regression now exercises the extracted trackpad view. Menu
|
||
tests cover the custom panel alongside upstream's panel choices. A new ownership
|
||
regression checks that releasing a hardware right-Ctrl alias cannot release Ctrl
|
||
still held by the active profile. Panel teardown tests now use `ComponentActivity`
|
||
to supply the lifecycle required by upstream's Compose bar.
|
||
|
||
The complete `:app:testDebugUnitTest` run passes **3,281 tests across 464 suites,
|
||
zero failures/errors/skips**, using Java 17, NDK `28.2.13676358` and
|
||
`-PskipRust=true`. Upstream's pinned MaliBridge submodule is initialized and its
|
||
required Android server build also succeeds. The PR diff passes
|
||
`git diff --check origin/main`.
|
||
|
||
No new APK installation, Thor regression pass or latency measurement was performed
|
||
for this merge. The earlier device measurements do not validate this exact tree.
|
||
|
||
## Manual AYN Thor results
|
||
|
||
The user performed the following checks in the installed candidate. The desktop
|
||
application was KWrite; native gamepad input was checked in Steam's controller
|
||
input test. A loaded game's input-to-display response was not measured.
|
||
|
||
| Area | Observed result |
|
||
| --- | --- |
|
||
| Native Game profile | Physical buttons, D-pad, both sticks/clicks and triggers work without observed missed input or stuck controls |
|
||
| Desktop defaults | Left stick moves pointer; A/B click; X/Y provide Enter/Escape; D-pad supplies arrows; right stick scrolls and stops at neutral |
|
||
| Scroll direction | Stick down advances to higher line numbers; stick up returns to earlier lines |
|
||
| Cursor visibility | Controller buttons and stick movement no longer hide the mapped pointer |
|
||
| Pointer handoff | Lower trackpad and stick can alternate without a jump; click position matches cursor |
|
||
| Cursor cadence | User confirmed smooth movement after the frame update fix; measurements below |
|
||
| Android keyboard | Text entry works on the lower screen, including while moving the pointer; controls continue after hiding the keyboard |
|
||
| Configured shortcut | R3 assigned to Ctrl+F through the settings UI repeatedly opens search; Y/Escape closes it; subsequent typing has no stuck Ctrl |
|
||
| Combined keyboard input | Physical modifier with Android keyboard supports Ctrl+A, Ctrl+X, Ctrl+V and Ctrl+S |
|
||
| Custom lower screen | Right pad moves pointer, left pad scrolls, A/B click, and View/Select opens the keyboard |
|
||
| Shared mouse hold | Physical A and screen A can hold together; releasing the physical button preserves selection until the screen button is released |
|
||
| Menu/held input | User reported successful menu/Ctrl release and ordinary typing afterward |
|
||
| Android Home/resume | Physical stick, lower trackpad, clicks and keyboard shortcuts work after returning |
|
||
| Layout persistence | Removing/readding a button through the editor persists across APK update and restart; defaults restored through the editor |
|
||
| Label rendering | Long View/Select and Menu/Start labels fit within their buttons |
|
||
| Native Deck lower screen | Both trackpads, clicks, L4/L5/R4/R5 and physical controls work in Steam's input test |
|
||
|
||
The editor's individual compatible-native and disabled options are host-tested,
|
||
not an exhaustive manual hardware matrix. Menu is currently an open command;
|
||
Back/B closes it. Multi-button activation chords are not implemented.
|
||
|
||
## Relative latency measurement
|
||
|
||
### What was measured
|
||
|
||
On the same Thor, timestamps from the built-in controller's evdev stream using
|
||
`CLOCK_MONOTONIC` were matched to a read-only guest observer of the published
|
||
controller ring. The observer polled with a requested 250 microsecond sleep,
|
||
roughly 0.31 ms in practice. Each observation bounds receipt between polls; the
|
||
table reports the **upper bound**, not an exact physical latency.
|
||
|
||
This path includes Android dispatch and publication. It excludes controller
|
||
firmware, Steam Input/game processing, rendering and display scanout. USB was
|
||
used for control and collection, not as the timed input transport. This is not a
|
||
button-to-photon test.
|
||
|
||
The public 0.6.0 build (`22eac083`) was sampled first. A locally instrumented
|
||
baseline at `ac0909ea` was then compared with the feature candidate; their relevant
|
||
baseline Java/native input implementation matched. Both used Steam Deck emulation,
|
||
1280×720 at 60 Hz, Steam's main screen, and the same disabled low-latency options.
|
||
|
||
The manual samples used physical B presses. Automatic samples injected B edges
|
||
into the built-in controller's evdev path, continuing through normal Android
|
||
input dispatch. Settled paired runs used a 150-press warmup before 150 measured
|
||
presses (300 edges) at approximately 33°C battery temperature. Earlier preliminary
|
||
runs were affected by background preparation and are kept separate.
|
||
|
||
### Results
|
||
|
||
All values below are milliseconds, kernel event to observer upper bound.
|
||
|
||
| Run | Matched edges | p50 | p95 | p99 | Max |
|
||
| --- | ---: | ---: | ---: | ---: | ---: |
|
||
| Public 0.6.0, manual | 84 | 4.379 | 8.155 | 9.334 | 9.729 |
|
||
| Local baseline, manual | 82 | 3.876 | 8.322 | 10.667 | 12.447 |
|
||
| Baseline automatic, preliminary | 300 | 3.213 | 6.774 | 7.960 | 8.688 |
|
||
| Candidate automatic, preliminary | 300 | 2.694 | 5.197 | 6.725 | 8.164 |
|
||
| Candidate automatic, settled 1 | 300 | 3.403 | 6.503 | 9.114 | 10.167 |
|
||
| Baseline automatic, settled | 300 | 3.061 | 6.269 | 7.160 | 7.850 |
|
||
| Candidate automatic, settled 2 | 300 | 2.999 | 5.620 | 8.171 | 13.653 |
|
||
| Final installed candidate, extra check | 300 | 3.039 | 5.905 | 7.470 | 11.684 |
|
||
|
||
The extra final-APK check matched all 300 edges without an observed overrun or
|
||
extra/missing edge. Its p50 interval was 2.692–3.039 ms. It ran at 32°C with internal
|
||
timing disabled, without another paired baseline or the explicit 150-press warmup;
|
||
it is supporting regression evidence, not a controlled speed comparison.
|
||
|
||
A separate internal sample of 600 dispatch-to-publication observations reported:
|
||
|
||
| Build | p50 (µs) | p95 (µs) | p99 (µs) |
|
||
| --- | ---: | ---: | ---: |
|
||
| Baseline | 112.6 | 274.2 | 442.2 |
|
||
| Candidate | 116.9 | 315.2 | 561.7 |
|
||
|
||
The 4.3 µs median difference is the difference between those runs, **not an
|
||
isolated measurement of router cost**. The tested typical native path remained
|
||
within baseline variation. Candidate tail values were higher in some runs and
|
||
were not isolated to a cause. No claim of a speedup, zero cost, or unchanged worst
|
||
case is supported by these samples.
|
||
|
||
### Cursor frame cadence
|
||
|
||
The initial stick-driven cursor updated at a median 33.333 ms interval, while
|
||
the lower trackpad updated at 16.667 ms. Publishing pending Compose snapshot
|
||
notifications before the frame's draw traversal changed the stick median to
|
||
16.667 ms. Of 119 intervals, 115 were 14–20 ms and none were 30–37 ms. The remaining
|
||
four included longer start/stop gaps, so these are not a continuous-load frame-time
|
||
distribution. The user confirmed the visible improvement. Speed, sensitivity and
|
||
the stick response curve were unchanged.
|
||
|
||
This is a rendering cadence check, separate from event propagation latency.
|
||
|
||
## Remaining validation
|
||
|
||
- Repeat the short Thor regression pass on the rebased final branch.
|
||
- Measure simultaneous BLE and touch input, contention and allocations on hardware.
|
||
- Compare Desktop key/pointer and native Deck touch latency quantitatively.
|
||
- Repeat under a loaded game/rendering workload and, if needed, measure display
|
||
response with high-speed video.
|
||
- Exercise physical Bluetooth devices and other device-specific adapters.
|
||
- Let upstream CI build and test the complete release configuration, including
|
||
store engines omitted from the local Steam/Desktop APK.
|
||
|
||
These limits should remain visible in the PR while maintainers review the
|
||
architecture. Host tests and a successful APK build do not replace those checks.
|