← All projects

eOr Dual-Screen Extension

In development

A paired-media layer for dual-screen Android handhelds, with the game on the top panel and an offline-capable companion below.

KotlinAndroidHandheld HardwareOpen SourceDual-Screen

At a glance

  • Outcome: Adds persisted Sessions, panel routing, lower-panel deck, and device authorization. Preserves single-screen behavior; targets general parts upstream without a polished release.
  • Status: Adds 11,165 lines across 91 files in about one week to older upstream work. Tests self-hosted RoMM authorization with JVM and MockWebServer fixtures; the last gate passed all 195 tests. Still requires browser approval and authenticated real-library Thor pass.
  • Role: Solo atop existing open-source base. eOr is not my project. It supplies the controller-first Android launcher; my work supplies the dual-screen paired-media layer.
  • Stack & libraries: Uses Kotlin, Android, and Gradle. Targets AYN Thor and Anbernic RG DS hardware.
  • Source: Private during development.
  • Limitations: Provides AYN Thor and Anbernic RG DS profiles; unknown devices use a layout that never relaunches the Activity. Only the Thor has a hardware record. Tests and fakes, not devices, cover RG DS, offer acceptance, Companion routing and independent stop, and lower-display detach and recovery.

Research and ownership

Reviewed eight dual-screen and handheld-companion products; found macro pads crowded and solved. Pulled two closed-source competitor APKs from the test device with ADB, decompiled with JADX, and verified behavior live. Made the first local build an unchanged upstream APK and recorded its real-hardware behavior before product changes.

eOr supplies Android home-app support, controller navigation, ROM discovery and metadata, artwork scraping, emulator launch adapters, and baseline dual-screen detection. My layer adds focus, recovery, and the Catlg companion client; its server remains unbuilt.

The explicit design rule is prefer changes that can be contributed upstream over maintaining an unnecessary hard fork.

Session and routing model

Replaces eOr’s artwork-hiding top-panel Boolean with a typed Session. Keeps launches pending until Android reports success. Ignores stale replaced-Session events and rejects illegal transitions. Recovers interrupted Companion routes without inventing game state. Persists no live Android object or authorization value.

Replaces eOr’s 181-line manager with a 417-line orchestrator and 245-line Android implementation. Separates the lifecycle-defining Primary, optional Companion, presenting Endpoint, and executed Route. Companion failures, stops, or display loss do not end or relaunch the game.

Represents phones, televisions, speakers, provider-native routes, and cast targets without offering unimplemented types. Renders authenticated ROM-library metadata below, with same-device fallback without a lower panel. Unsupported Android routes fail and can be added without rewriting the model.

Hardware behavior

Detects dual screens from hardware, not configuration. Handles unexpected emulator behavior during launch. Uses device authorization, not a configuration-file secret; this is the author’s closest consumer-device work beyond firmware.