Skip to content

feat(android): foldable posture, fold regions, and fold-aware arrangements - #27

Merged
CAWRESTLER merged 5 commits into
mainfrom
feat/android-foldables
Oct 8, 2026
Merged

CAWRESTLER merged 5 commits into
mainfrom
feat/android-foldables

Conversation

@CAWRESTLER

Copy link
Copy Markdown
Owner

Summary

Adds real Android support for foldables (Pixel Fold, Galaxy Z Fold/Flip, and other devices Jetpack WindowManager supports). Before this, Android only got the JavaScript fallbacks.

Native (android/)

  • New RNDuoEnvironmentView and its view manager. They read FoldingFeature through androidx.window 1.3.0 (WindowInfoTrackerCallbackAdapter), plus the hinge-angle sensor (TYPE_HINGE_ANGLE, API 30+). They emit the same environment payload as iOS:
    • hinge.status: HALF_OPENED → partiallyOpen, FLAT → fullyOpen. When no fold is reported but there's a hinge sensor, the status comes from the angle, including closed.
    • hinge.angleDegrees/angleRadians come from the sensor.
    • The fold appears as a division reserved region (occlusion when the hinge hides content), active while it separates content, in provider-local dp. includeInactiveRegions also includes it while flat.
    • Geometry, window metrics, safe-area insets, and size classes (compact below 600 dp wide or 480 dp tall).
    • isDuo and supportsDuoApis stay false, since they describe iPhone Duo; foldable-aware code should check hinge.available. Cameras and accessories still use the fallbacks.

JavaScript

  • iOS and Android now share one native-backed DuoProvider (src/native/NativeDuoProvider.tsx). Web keeps the fallback.
  • The store exposes the provider's host view, so descendants can map provider-local region frames to their own position.
  • The fallback DuoArrangementView (Android and web) splits along an active fold: side by side around a vertical fold, stacked around a tabletop fold. It leaves the hinge's thickness empty and respects axes. The geometry lives in a pure resolveFoldSplit helper with unit tests.

Testing

  • Pixel Fold emulator (API 36, Release APK): the Hinge lab shows Partially open · 90.0° · Device hinge detected after adb emu sensor set hinge-angle0 90. The fold arrives as an active division region; the Duo Lab sidebar snaps to it. Unfolded flat, it correctly reports 0 active regions.
  • yarn validate passes: 77 Jest tests including the new fold-split.test.tsx, 59 tooling tests, lint with 0 errors, and pack:check.
  • Not tested: physical foldable hardware; the tabletop (horizontal-fold) orientation on the emulator; Galaxy Flip-style devices. Logcat shows a harmless legacy Could not find generated setter warning; Fabric props go through the codegen delegate.

🤖 Generated with Claude Code

CAWRESTLER and others added 5 commits October 7, 2026 17:35
- `@cawrestler/react-native-duo/jest`: components render with the JS
  fallbacks; setMockDuoEnvironment / resetMockDuoEnvironment /
  createMockDuoEnvironment simulate Duo environments and update mounted
  providers. Fallbacks moved to src/fallback/ so the mock imports them
  without platform resolution picking the native `.ios` files.
- docs/API_STABILITY.md: proposed stable/experimental classification
  and open naming questions for 0.1.0; @experimental JSDoc tags on the
  proposed experimental exports.
- example/.maestro: arrangement switching, toolbar rail placement, and
  scene accessory registration flows (`yarn example e2e`). Duo Lab
  toggles now give their switches an accessibility label.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ability

# Conflicts:
#	CHANGELOG.md
#	src/DuoSceneAccessory.tsx
…ments

- RNDuoEnvironmentView on Android reads Jetpack WindowManager's
  FoldingFeature and the hinge-angle sensor and emits the same
  environment payload as iOS: hinge status/angle, the fold as a
  division (or occlusion) reserved region, geometry, window metrics,
  and size classes. isDuo and supportsDuoApis stay false.
- DuoProvider uses the shared native provider on iOS and Android; the
  store exposes the provider host so descendants can map
  provider-local region frames.
- The fallback DuoArrangementView splits its panes along an active fold
  (resolveFoldSplit), honoring `axes` and the hinge thickness.

Verified on a Pixel Fold emulator (API 36): Hinge lab reports
"Partially open 90.0°" with the hinge detected, and the fold arrives as
an active division region.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	CHANGELOG.md
#	src/fallback/DuoArrangementView.tsx
@CAWRESTLER
CAWRESTLER enabled auto-merge (squash) October 8, 2026 03:15
@CAWRESTLER
CAWRESTLER merged commit 70ddab3 into main Oct 8, 2026
8 checks passed
@CAWRESTLER
CAWRESTLER deleted the feat/android-foldables branch October 8, 2026 03:36
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