ES-DE Overlay

Verified device facts

Device: Retroid Pocket Nova (kalama), checked over adb on 2026-10-28.

Device

Fact Value Evidence
Android 13 (SDK 33) adb shell getprop ro.build.version.release / ro.build.version.sdk
Screen 960x1280 physical, 320 dpi (used in landscape, 1280x960) adb shell wm size, wm density
ES-DE org.es_de.frontend, ES-DE 3.5.0-65 (r52), running as the home app pm list packages; first lines of es_log.txt
ES-DE data dir /storage/7BEF-E760/ES-DE (SD card) ls /storage/7BEF-E760/ES-DE
ROMs dir /storage/7BEF-E760/ROMs (SD card) ls /storage/7BEF-E760/ROMs; paths in es_log.txt
Media dir <ES-DE>/downloaded_media (MediaDirectory empty in es_settings.xml) grep MediaDirectory settings/es_settings.xml
Theme minui-menu-es-de-custom, variant gamelist-list-screenshot grep Theme settings/es_settings.xml
System screenshots /storage/emulated/0/Pictures/Screenshots/Screenshot_YYYYMMDD-HHMMSS.png ls Pictures/Screenshots
Log rotation ES-DE keeps one es_log.txt.bak, but after a device reboot it overwrote es_log.txt without rotating (see below) ls -la ES-DE/logs

Assumptions

ID Status Result Evidence
A1 Verified Every launch logs Launching game "<name>" from system "<Full Name> (<system>)"... plus same-second lines incl. Package: <pkg>. The ROM path appears only for some launch arguments: raw for RetroArch (%ROM% expanded: /storage/7BEF-E760/ROMs/snes/02) Hacks/Easyland.zip), percent-encoded for %ROMPROVIDER% (content://org.es_de.frontend.files/root/...). Android-app launches log no path. Debug mode is not needed. %ROMSAF% not yet seen in a real log, but ES-DE’s own code (classes.dex strings) logs it as %ROMSAF% expanded: content://com.android.externalstorage.documents/tree/<tree>/document/<docId>, which the parser handles encoded or not (unit-tested). fixtures/es_log/*.txt
A2 Verified The app reads es_log.txt through the SAF tree while ES-DE runs; a launch at ES-DE time 15:57:40 was logged by the app at 15:57:41.37 (1 s polling). adb logcat -s ESDEShot
A3 Verified Power + volume-down in a game creates Pictures/Screenshots/Screenshot_*.png; the ContentObserver filed it as screenshots/02) Hacks/Easyland.png within 1 s. Taken inside ES-DE, it is left alone with a notification. (KEYCODE_SYSRQ does not take a screenshot on this build; input keycombination KEYCODE_VOLUME_DOWN KEYCODE_POWER does.) stat on the media file; dumpsys notification
A4 Verified ES-DE showed the new screenshot (and played the video) for Easyland on returning to the gamelist, no reload or restart. Device screenshot; user observation
A5 Verified Theme variant gamelist-list-screenshot; existing scraped media under downloaded_media/<system>/screenshots/, mirroring ROM subfolders (e.g. snes/screenshots/01) All but the Best/) es_settings.xml; ls downloaded_media/snes/screenshots
A6 Verified One consent at service start covered several captures in a row across app switches. Reinstalling or restarting the service needs a new consent. Two back-to-back captures, no dialog
A7 Verified ES-DE plays the app’s H.264 MP4 from videos/. User observation
A8 Partly Clips now carry game audio (playback capture): an Easyland clip had AAC 48 kHz stereo, 14.89 s for 14.88 s of video, mean -23.3 dB. Whether the theme plays it in the gamelist is up to ES-DE’s video-audio settings. All installed games/emulators have ALLOW_AUDIO_PLAYBACK_CAPTURE. ffprobe, ffmpeg -af volumedetect, dumpsys package
A9 Superseded Gamepad combo through an AccessibilityService (the original plan’s Phase 4). The menu opened on Retroid’s Home message from 2026-10-29, and since 2026-11-03 opens on the controller’s Back through a key filter; see Back button menu. —

Game resolution

Because the log path is optional, the app resolves the game in this order:

  1. The ROM path from the launch-block lines (absolute /…/ROMs/<system>/…, or the SAF/document form 7BEF-E760:ROMs/<system>/…, percent-decoded).
  2. A unique <name> match in <ES-DE>/gamelists/<system>/gamelist.xml (its <path> is ./<relative path>; Android-app stubs such as ./Dead Cells.app are listed there too).
  3. Otherwise the app reports the raw launch line and saves nothing.

ES-DE’s bundled assets/systems/android/es_systems.xml (pulled from the installed APK) shows which launch arguments carry the ROM: %ROM% (RetroArch %EXTRA_ROM%), %ROMSAF%, %ROMPROVIDER%, among others.

Found while testing the app on the Nova

fixtures/es_log/retroarch_rom.txt was saved during testing as grep -n -A10 output from es_log.txt with only grep’s line-number prefix removed; the reboot then overwrote that log.

Emulators on this Nova (expected, not each tested)

Capture mirrors whatever is on screen, so it doesn’t depend on the emulator. What varies is how ES-DE passes the ROM (bundled es_systems.xml / es_find_rules.xml), which decides how the game is identified. Every emulator below keeps the game in the package ES-DE launched, which the foreground check needs.

Emulator Package ROM argument Status
RetroArch (all cores) com.retroarch.aarch64 %ROM% (raw path) Tested on device
Android games/apps the app itself none, resolved via gamelist Tested on device (Stuffy Frights)
Eden (Switch) dev.eden.eden_emulator %ROMPROVIDER% Real launch line parsed in tests
PPSSPP, Azahar, melonDS, Cemu, ARMSX2, Dolphin, NetherSX2 own packages %ROMSAF% Format confirmed from ES-DE code; parser unit-tested

If the path ever can’t be read, a unique <name> in the system’s gamelist.xml still identifies the game; failing both, nothing is saved and the notification shows the raw launch line. Not measured: any frame-rate cost of recording during the heaviest games (Switch, Wii U, PS2).

In-game menu

Checked on the Nova on 2026-10-29 with Easyland (snes/02) Hacks/Easyland.zip) in RetroArch.

Idle cost

dumpsys meminfo com.clintonium.es_de_overlay (TOTAL PSS) and top -b -n 3 -d 15 for the app process, with the menu closed and Easyland in front:

State PSS Graphics CPU (one core)
Baseline before the menu (earlier build, capture button) about 55 MB — about 0.2%
Fresh process, menu never opened 66–71 MB 2.6 MB 0.0–0.3%
After opening, zooming and closing the 8192x2048 map (software layer) 77–78 MB 8.0 MB 0.0–0.2%
The same, before the software layer 139–141 MB 70.5 MB 0.0–0.3%

The fresh process had also opened the settings screen for capture consent.

Acceptance (2026-10-29)

With test files for Easyland (a 3-page manual PDF; guides: a text file with ASCII art, an 8192x2048 PNG map, a PDF and a 3-page CBZ), removed afterwards:

Find guides and the HTML viewer

Checked on the Nova on 2026-10-30 with Shantae (gbc/Shantae.zip), Super Metroid (snes/Super Metroid.zip) and Easyland.

The guide browser

Checked on the Nova on 2026-10-30 (WebView 109, com.android.webview) in Shantae, with the browser in the :viewer process and the WebView’s own User-Agent and cookie settings.

In-game menu revamp

Checked on the Nova on 2026-11-02 with Shantae (gbc/Shantae.zip), Easyland and Easyland 2 (snes/02) Hacks/), side by side with ES-DE’s gamelist for Shantae.

Back button menu

Checked on the Nova on 2026-11-03 with a debug build of the back-button-menu branch (APK sha256 9d808a76…84e3): Easyland and Shantae in RetroArch, Prince of Persia: The Lost Crown in Eden. Retroid’s Prevent pressing Home accidentally was off (prevent_press_home_accidentally=0).

Back, Home and the viewer (2026-11-05)

Checked on the Nova with a debug build of the overlay-hardening branch (APK sha256 d5b59c69…a24e), Easyland in RetroArch, Retroid’s Prevent pressing Home accidentally off. Back and the other controller buttons were sent with sendevent on the Retroid Pocket Controller; Home was the user’s press. Window changes are timed from input_focus in the events log.

Text in the list pills (2026-11-05)

ES-DE centres a capital S in a list row, not the text’s line (its Font.cpp puts the baseline at half the line height plus half the S’s height). With VAG Rounded’s deep descent, a centred line left the capitals high: measured on the Nova from screenshots, the S in a guide’s contents pill (Wrecked Ship) had 9 px of pill above and 18 px below, and the G in the menu’s Quit Game 13 and 17. Both lists now move their text down by the font’s own difference, (ascent + descent - the S’s top) / 2, which is 0.092 em for VAG Rounded: 13 and 14 px in the contents, 15 and 15 in the menu, with the pills (56 and 60 px) and row pitch unchanged. The Nova’s WebView 109 has no CSS text-box trim, so the contents pill does it with padding.

Viewer zoom, map names, text sections and web saves (2026-11-05)

Checked on the Nova with a debug build of the viewer-navigation branch (APK sha256 a46b555b…a2e5), Shantae in RetroArch. The user gave capture consent, launched the game and opened the menu; everything else was sent with sendevent or tapped after a screenshot. A dry run on the build before found four of the points below, fixed before this pass.

Guide pictures and zoomed text (2026-11-05)

Checked on the Nova with debug builds of the viewer-navigation branch, Shantae in RetroArch, after a dry run. The user gave capture consent and opened the menu after each install; everything else was sent with sendevent or tapped after a screenshot.

Quitting games through Shizuku (2026-11-05)

Checked on the Nova with debug builds of the shizuku-quit branch, Shantae and Super Metroid in RetroArch and Super Mario Odyssey in Eden v0.2.1, after a dry run that found two bugs. The recorded pass ran after a reboot (APK sha256 73ca03a8…e017); a last build only adds the guard in the last bullet but one (b1e82940…f7a3). Shizuku-Next 14.0.33 (moe.shizuku.privileged.api, from rushiranpise/Shizuku-Next) with the client library dev.rikka.shizuku 13.1.5. The user launched the games and pressed the buttons.

Following the ES-DE theme (2026-11-06 and 07)

Checked on the Nova with debug builds of the public-release branch, Shantae in RetroArch, after a dry run whose fixes are below. The user switched themes in ES-DE, launched the game, gave capture consent and toggled Shizuku; the overlay was driven with sendevent. Each issue found in a pass was fixed before the next.

Security sweep (2026-11-08 and 09)

The code was reviewed for the ways an app with screen capture, a key-filtering accessibility service, overlay windows, Shizuku force-stop and two WebViews could be misused. Each finding was fixed or accepted with a reason. The fixes were checked on the Nova with a debug build of the public-release branch (APK sha256 3356ed52…1fdb), Shantae in RetroArch and Mario Kart 8 Deluxe in Eden, after a dry run that found one problem (the last bullet but one). The user launched the games and apps and gave capture consent; the overlay was driven with sendevent, the browser through WebView devtools.