Skip to content

Add iPhone Duo support and fold controls - #179

Merged
krystofwoldrich merged 17 commits into
expo:expofrom
krystofwoldrich-agent:codex/iphone-duo-support
Sep 21, 2026
Merged

krystofwoldrich merged 17 commits into
expo:expofrom
krystofwoldrich-agent:codex/iphone-duo-support

Conversation

@krystofwoldrich-agent

@krystofwoldrich-agent krystofwoldrich-agent commented Sep 19, 2026 •

Copy link
Copy Markdown

Adds iPhone Duo streaming, fold controls, and the correct frames and corner radii. Keeps the bezel and hardware buttons aligned during rotation.

Uses per-display Universal HID reports for Duo touch input. Verified corner taps, drags, wheel input, and two-finger input at 0°, 90°, and 180°, in portrait and both landscape directions. Build, focused tests, typecheck, and lint pass.

Closed — 0°
Closed Duo, whole serve-sim UI

Half-fold — 90°, landscape
Half-fold Duo, whole serve-sim UI

Fully open — 180°, opposite landscape
Fully open Duo, whole serve-sim UI

Streaming and rotation video

duo-correct-frames-rotation.mp4

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>
Read per-display corner geometry from the simulator profile and scale it to
DeviceKit artwork. Keep asymmetric corners through clipping, resizing and
rotation, and select the matching geometry when the active display changes.

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>
Rotate DeviceKit bezels and screen cutouts with native display readback,
honor PDF page rotation for inner-display buttons, and use the Duo vendor
orientation control. Preserve the toolbar request cycle when an app
rejects a pose. Guard disconnected inner digitizers that crash backboardd.

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>

@krystofwoldrich-agent krystofwoldrich-agent left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🤖 This is an automated review. Addressing it doesn't guarantee a merge.

Review: Add iPhone Duo support and fold controls

Verdict: REQUEST_CHANGES (posted as a comment: GitHub blocks request-changes from the PR author account)
Findings: 0 critical · 3 design · 4 suggestion · 4 nit

The PR adds a CoreDevice bridge for fold and orientation control, per-display Universal HID touch reports, active-display framebuffer selection, rotated DeviceKit chrome with per-corner radii, a hinge WebSocket command, and a hinge CLI. The Duo-specific work is careful and well tested. The main concern is that three changes alter the input path for every non-foldable device, and the PR only reports verification on the Duo.

I could not verify the non-foldable path live: on a booted iPhone 17 (iOS 27.2), taps failed with both this build and the released 0.2.3 build, so that simulator instance was not a usable oracle. Focused TypeScript tests pass locally.

Check Result
Focused bun tests (10 files) 90 pass, 0 fail
iPhone 17 pushed config screenId: 1 present
iPhone 17 tap, PR build no effect, HID log confirms begin and end sent
iPhone 17 tap, 0.2.3 build no effect

Findings (details inline)

  • [design] Legacy Indigo target changes for every non-foldable device — Sources/StreamingPolicy/HIDTargetPolicy.swift:14
  • [design] Legacy move events switch from Down to Dragged for all devices — Sources/SimNative/HIDInjector.swift:257, :284
  • [design] Private CoreDevice framework is loaded for every device session — Sources/SimNative/HIDInjector.swift:91, Sources/SimNative/CoreDeviceBridge.swift:145
  • [suggestion] A failed setScreen makes the session start fail silently — src/device-session.ts:1073, src/native.ts:184
  • [suggestion] Fixed 16-byte buffers for resilient Swift structs — Sources/CoreDeviceShim/CoreDeviceDigitizerShim.m:90
  • [suggestion] Motion shim re-resolves symbols on every call — Sources/CoreDeviceShim/CoreDeviceMotionShim.c:8
  • [suggestion] readState argument differs from the other subcommands — src/index.ts:892
  • [nit] Asset cache key reads the whole PDF per request — src/devicekit-chrome.ts:844
  • [nit] Unused asset — src/client/assets/hinge-half-open-portrait.svg
  • [nit] Rotation cursor can ignore external rotation indefinitely — src/client/simulator/rotation-cursor.ts:15
  • [nit] Manager readiness poll blocks the bridge actor — Sources/SimNative/CoreDeviceBridge.swift:40

One observation, not a finding: the iPhone 17 simulator shut down about one minute after a PR-build server attached and Settings was launched via simctl, with a splashboardd crash in BKSHIDEventDeliveryManager. No input had been sent. After a reboot the same server attached without incident. Cause undetermined.

Comment thread packages/serve-sim/src/index.ts Resolved
Restore the original Indigo target and move encoding for non-foldables. Gate CoreDevice setup, controls, and display tracking on exactly two integrated displays.

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>
Log native HID setup errors once and disable input for the affected session without rejecting capture startup. Cover failed setup with and without screen metadata, continued video delivery, and subsequent display updates.

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>
Check both runtime value sizes before enabling the digitizer. Reject layouts that differ from the two-word buffers and Swift call signatures, preventing incompatible constructors or setters from running.

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>
Cache successful and failed initialization with dispatch_once so repeated capability checks do not resolve symbols or rewrite the async descriptor.

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>
Read the supplied device state directly, matching rotate, tap, gesture, and the other existing input commands.

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>
Version the rotation-aware PNG cache and parse PDF rotation only on a cache miss. Verify cached asset requests preserve the correct dimensions without rereading PDFs.

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>
Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>
Limit protection from delayed acknowledgements to 1.5 seconds per request. A declined pose no longer blocks later external rotations, while subsequent clicks can still cycle past unsupported poses.

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>
Coalesce concurrent readiness checks into one task with a monotonic five-second polling deadline. Fail explicitly before device enumeration on timeout and allow later retries without one caller's cancellation affecting other waiters.

Co-authored-by: Krystof Woldrich <[email protected]>
Co-authored-by: Codex <[email protected]>

@gwdp gwdp left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Automated review of ea913e60 against the expo base. Approving; the comments are follow-ups, not blockers.

Comment thread packages/serve-sim/src/native.ts Resolved
krystofwoldrich and others added 4 commits September 21, 2026 23:26
Gate every SimHID operation on the shared setup task, preserving setup failures instead of calling a partially initialized injector. Test pending foldable setup and cached failures.

Co-authored-by: Codex <[email protected]>
Handle rejected acknowledgements independently of the requested angle so the control clears pending state immediately and displays the server error. Cover timeout cancellation and successful-reply matching.

Co-authored-by: Codex <[email protected]>
Extend the existing child suite to verify the setup-failure latch across every input method, per-handle recovery, and non-latching malformed-input errors. Retain the MJPEG streaming and screen-metadata checks during setup failure.

Co-authored-by: Codex <[email protected]>
Preserve Duo display readiness and active-panel metadata alongside upstream capture timing diagnostics.

Co-authored-by: Codex <[email protected]>
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.

3 participants