Skip to content

feat(android): detect Fire OS devices as Android TV targets and document Fire TV support - #3923

Merged
thymikee merged 1 commit into
mainfrom
fireos-docs
Oct 23, 2026
Merged

thymikee merged 1 commit into
mainfrom
fireos-docs

Conversation

@thymikee

@thymikee thymikee commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Summary

Fire TV devices running Fire OS are Android-based and automate over ADB, but the docs framed TV support as Android TV / tvOS / Vega VVD only, and TV detection missed them: detection read only the AOSP leanback/television features, while Fire OS declares amazon.hardware.fire_tv (Amazon, "Identify Fire TV Devices") and may declare no leanback feature. App launch and listing on a TV target queried LEANBACK_LAUNCHER only, while Fire OS apps can register under either launcher category.

  • launcher-categories.ts (new): one shared TV/mobile launcher-category resolver; app-lifecycle.ts and app-helpers.ts both read launch, fallback, and listing categories from it. TV listing is the union of LEANBACK_LAUNCHER and LAUNCHER; launch prefers LEANBACK_LAUNCHER and falls back to LAUNCHER, launching under the category the component resolved under.
  • inventory.ts: amazon.hardware.fire_tv counts as a TV feature signal, so a Fire TV is discovered with target=tv.
  • Docs + versioned help tv: Fire TV (Fire OS) = Android TV backend over ADB (adb connect <ip>:5555, ADB debugging); Vega OS remains a different, VVD-only OS. Docs state only the Android 6.0 (API 23) helper requirement; no per-command enumeration beyond what the Android TV backend runs.
  • Electron/Chromium macOS docs moved to docs(macos): document Electron app automation through the accessibility tree #3932.
adb connect 192.168.1.20:5555
agent-device open com.example.app --platform android --target tv
agent-device tv-remote press down --platform android --target tv

Validation

  • Head df2f9120ce66426d384a228b4cb813f7b68fe67a: rebased onto main after test(capture-kit): encode solid test PNGs unfiltered to stay inside the unit budget #3933 (coverage timeout fix) and docs(macos): document Electron app automation through the accessibility tree #3932 (Electron docs) merged; conflicts resolved by keeping main's Electron sentences and only adding the Fire OS wording, so no Electron text is re-added or duplicated. The one post-467e134 change is the review's single-spelling note: androidLaunchCategory now returns androidLauncherCategories(target)[0]!. pnpm check:affected --run --head df2f9120ce66426d384a228b4cb813f7b68fe67a: all runnable checks passed, exactCommit=true (receipt .tmp/validation/run-05ZPGb/receipt.json).
  • Head 467e13402ed220e58fdac45d42a53f179a7f1303 adds only the review's naming/dedup/assertion refactor in launcher-categories.ts/app-lifecycle.ts/app-helpers.ts; the emitted adb argv is byte-identical to the bbcc604 runs quoted below (the argv unit tests re-ran green at the new head). pnpm check:affected --run --head 467e13402ed220e58fdac45d42a53f179a7f1303: all runnable checks passed, exactCommit=true (receipt .tmp/validation/run-VsQOlP/receipt.json). Unit tests: Fire OS detection on the pm list features path and the cmd package has-feature path (device that fails ro.build.characteristics, answers no AOSP leanback/television feature, and answers amazon.hardware.fire_tv true — decided tv before the feature-list probe, asserted); TV fallback argv; TV listing queries both categories on the daemon and executor-helper paths. Each new production behavior fails on base for the intended reason.
  • Live, at head bbcc604599, on emulators created for this run: Android TV fireos_docs_tv (android-tv API 34, arm64, emulator-5554) and phone fireos_docs_phone (google_apis API 35, emulator-5556), both removed after. Two purpose-built APKs installed: com.example.fireosdocs (LAUNCHER-only activity) and com.example.fireosdocslb (LEANBACK_LAUNCHER-only). adb argv captured with a forwarding wrapper that logs each invocation, then execs the real platform-tools 37.0.1 adb; CLI built from the head sha.

1. apps --target tv lists the LAUNCHER-only package next to the leanback app:

$ agent-device apps --platform android --target tv --serial emulator-5554 --session head-tv
Fireosdocs (com.example.fireosdocs)
Fireosdocslb (com.example.fireosdocslb)

wrapper log — both category queries ran:

adb -s emulator-5554 shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LEANBACK_LAUNCHER
adb -s emulator-5554 shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER

2. open com.example.fireosdocs --target tv runs the fallback and the app resumes:

$ agent-device open com.example.fireosdocs --platform android --target tv --serial emulator-5554 --session head-tv
Opened: com.example.fireosdocs

wrapper log — primary -c LEANBACK_LAUNCHER -p start (which fails on the device with raw adb's Error: Activity not started, unable to resolve Intent { ... cat=[android.intent.category.LEANBACK_LAUNCHER,android.intent.category.DEFAULT] ... pkg=com.example.fireosdocs }), then resolve-activity for LEANBACK_LAUNCHER (misses), then resolve-activity for LAUNCHER (resolves), then the second am start -n with -c LAUNCHER:

adb -s emulator-5554 shell am start -W -a android.intent.action.MAIN -c android.intent.category.DEFAULT -c android.intent.category.LEANBACK_LAUNCHER -p com.example.fireosdocs
adb -s emulator-5554 shell cmd package resolve-activity --brief -a android.intent.action.MAIN -c android.intent.category.LEANBACK_LAUNCHER com.example.fireosdocs
adb -s emulator-5554 shell cmd package resolve-activity --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER com.example.fireosdocs
adb -s emulator-5554 shell am start -W -a android.intent.action.MAIN -c android.intent.category.DEFAULT -c android.intent.category.LAUNCHER -n com.example.fireosdocs/.LauncherActivity
$ agent-device appstate --platform android --target tv --serial emulator-5554 --session head-tv
Foreground app: com.example.fireosdocs
Activity: com.example.fireosdocs.LauncherActivity

3. Mobile-target open on the phone emulator still runs one am start -c LAUNCHER (zero LEANBACK occurrences in the whole request log):

$ agent-device open com.example.fireosdocs --platform android --target mobile --serial emulator-5556 --session head-phone
Opened: com.example.fireosdocs
adb -s emulator-5556 shell am start -W -a android.intent.action.MAIN -c android.intent.category.DEFAULT -c android.intent.category.LAUNCHER -p com.example.fireosdocs
  • Earlier live run at e9250ed (pre-amend): devices target=tv, snapshot -i on the helper backend (helperVersion 0.21.32-dev), tv-remote down/select/volume-down/home/back/android-keycode, screenshot 1920x1080, logs, network dump, is visible/is focused selectors, close.
  • Not tested: Fire OS hardware — no Fire TV device available. Detection of amazon.hardware.fire_tv rests on unit tests against the documented feature format plus the live Android TV runs above, not on Fire TV firmware.
  • CI owns coverage, device lanes, and integration.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-23 15:15 UTC

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.58 MB 5.58 MB +401 B
Package (unpacked) 5.58 MB 5.58 MB +401 B
Package (download) 1.69 MB 1.69 MB +141 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 40.2 ms 41.3 ms +1.1 ms
CLI --help 81.5 ms 79.8 ms -1.7 ms

@thymikee

Copy link
Copy Markdown
Member Author

The Fire OS detection looks right at fb6a58a, and the 19 checks are green, but I could not find live evidence for the changed Android TV routes yet. I only read the code; I did not re-run the tests or the checks, and I had no Fire OS hardware or image, so the claim that real Fire TV firmware omits the leanback, television and ro.build.characteristics signals rests on your note and Amazon's docs. The existing live run was at e9250ed, before the amend, and the diff since then touches app-helpers.ts and app-lifecycle.ts.

That run listed no apps on a TV target and opened a package that resolves under LEANBACK, so the new LAUNCHER fallback never ran. The union listing (LEANBACK_LAUNCHER plus LAUNCHER) and the fallback launch only have fixture-adb unit tests. Can you run this on an Android TV emulator at fb6a58a? First, run agent-device apps --platform android --target tv --session s and show a LAUNCHER-only package in the list next to the leanback apps. Second, run agent-device open <that package> --platform android --target tv and show the log with the primary am start -c LEANBACK_LAUNCHER -p failing, resolve-activity for LEANBACK_LAUNCHER then LAUNCHER, and a second am start -n <component> with -c LAUNCHER that opens the app. Third, show that a mobile-target open on a phone emulator still does one am start -c LAUNCHER. Please quote the output in the PR body with the exact sha. Merge needs this run; no conflicts are known.

Not blocking, take or leave: the TV category order now lives in two places, app-helpers.ts and app-lifecycle.ts, so a follow-up could share one resolver; commands.md:319 calls the LAUNCHER listing a fallback, but it is a union on every TV target (and for listAndroidAppsWithAdb with target tv), while launch is the fallback; commands.md:320 says Fire OS 5 falls back to the uiautomator snapshot path, but I found no such code in packages/platform-android/src, and it lists perf and replay as supported without Fire OS evidence, so state only the minSdk 23 requirement; the Electron/Chromium macOS accessibility docs (README.md, commands.md:337 and :359) are unrelated to Fire OS and could go in their own PR; and the automotive negative case in inventory.test.ts reads as mobile on base and head, so it guards nothing, while nothing covers a device that fails the ro.build.characteristics check but passes cmd package has-feature amazon.hardware.fire_tv.

@thymikee

Copy link
Copy Markdown
Member Author

All items applied at bbcc60459991b1f28b3616806b3b875dd95a41cd; the PR body now quotes the live runs at that sha.

  • One TV category resolver. launcher-categories.ts (new) owns the category constants and the probe order; app-lifecycle.ts and app-helpers.ts both read launch, fallback, and listing categories from it. The per-file copies are gone.
  • commands.md wording. Now: "app listing reads LEANBACK_LAUNCHER and LAUNCHER activities together; app launch prefers LEANBACK_LAUNCHER and falls back to LAUNCHER when the app declares no leanback activity" — union for listing, fallback for launch.
  • Fire OS 5 / uiautomator claim dropped; perf/replay claims dropped. I checked: there is no uiautomator fallback path in the code — the helper is the only Android snapshot backend. The bullet now states only the detection behavior, the Android TV backend, and the Android 6.0 (API 23) helper requirement. No command enumeration.
  • Electron/macOS docs moved out to docs(macos): document Electron app automation through the accessibility tree #3932, branched from current main. Claims there are scoped to what SnapshotTraversal.swift does (snapshot enables the Chromium tree, warns when it did not populate).
  • Automotive negative removed (you were right that it read mobile at both base and head). Added the has-feature test you asked for: characteristics returns a non-tv value, all three AOSP leanback/television cmd package has-feature probes answer false, only amazon.hardware.fire_tv answers true — asserts target: tv and that pm list features was never called, so the case is decided on the has-feature path, not the feature-list fallback.

Live evidence, at bbcc604599, on emulators created for this run (fireos_docs_tv, android-tv API 34; fireos_docs_phone, google_apis API 35; both removed after) with two purpose-built APKs — com.example.fireosdocs (LAUNCHER-only) and com.example.fireosdocslb (LEANBACK_LAUNCHER-only) — and a forwarding adb wrapper logging each argv; exact output is in the PR body:

  1. apps --target tv lists the LAUNCHER-only package next to the leanback app; the log shows both query-activities category queries.
  2. open com.example.fireosdocs --target tv: primary am start ... -c LEANBACK_LAUNCHER -p (fails on-device with unable to resolve Intent), resolve-activity LEANBACK (miss), resolve-activity LAUNCHER (resolves), second am start -n com.example.fireosdocs/.LauncherActivity with -c LAUNCHER; appstate shows the activity resumed.
  3. open ... --target mobile on the phone emulator: exactly one am start -c LAUNCHER, zero LEANBACK lines in the request log.

pnpm check:affected --run --head bbcc604599...: all runnable checks passed, exactCommit=true (receipt .tmp/validation/run-AlrpLj/receipt.json).

@thymikee

Copy link
Copy Markdown
Member Author

This PR is ready at bbcc604, and the Fire OS detection and the launcher category route now match the live output in the PR body. The earlier request for live evidence is satisfied, and I found no code problems. The Coverage job fails in the "Run coverage" step without printing a failing test, which matches the screenshot-diff.test.ts timeout described in #3933 (this PR is listed there as hit twice). This diff only touches the Android launcher and inventory code plus docs, so the failure looks unrelated, but that is attribution by signature, not proof. Merge waits only on that job, which should pass once the #3933 fix lands or the job is re-run. Not blocking, and you can take or leave these: includeLauncherCategory in launcher-categories.ts is named for the tv branch only, since for auto and desktop it adds LEANBACK_LAUNCHER, so a target-neutral name such as includeFallbackCategories would read better; and the Array.from(new Set(...)) wrapper at app-lifecycle.ts:510 cannot dedupe anything because the resolver never returns duplicates, so it can go, and exporting a launch-category function would also remove the [0]! at app-lifecycle.ts:83. I did not re-run the emulator sessions or the unit tests, and no Fire OS hardware was tested, as the PR body states, so amazon.hardware.fire_tv detection rests on unit tests and Amazon's documented feature name.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 23, 2026
@thymikee

Copy link
Copy Markdown
Member Author

Applied all three notes at 467e13402ed220e58fdac45d42a53f179a7f1303 (behavior-preserving refactor on top of bbcc604; the live evidence above was captured at bbcc604 and stands, since the argv these functions produce is byte-identical — the unit argv tests re-ran green at the new head):

  • Option renamed to includeFallbackCategories, and the docblock now describes the first entry as the launch category and the rest as the secondary categories, so the name reads for the auto/unknown branch too.
  • Dropped the Array.from(new Set(...)) wrapper in resolveAndroidLaunchComponent; it iterates the resolver's list directly.
  • launcher-categories.ts now exports androidLaunchCategory(target) — LEANBACK_LAUNCHER for tv, LAUNCHER otherwise — so the [0]! and the resolveAndroidLauncherCategory wrapper are gone.

Unit tests: 46/46 green (inventory.test.ts, app-lifecycle-open.test.ts, app-helpers.test.ts). pnpm check:affected --run --head 467e13402ed220e58fdac45d42a53f179a7f1303: all runnable checks passed, exactCommit=true (receipt .tmp/validation/run-VsQOlP/receipt.json). Leaving the Coverage job alone per the #3933 attribution.

@thymikee

Copy link
Copy Markdown
Member Author

The PR is ready at 467e134. The rename, the removed private helper and the added export in platform-android keep the launch category lists unchanged, so the clean result from the earlier review (bbcc604) still applies. I did not re-run unit tests, and the live Android TV evidence was captured at bbcc604. Fire OS detection through amazon.hardware.fire_tv is covered by unit tests and Android TV emulator runs, not Fire OS hardware.

Not blocking, take or leave: androidLaunchCategory repeats the tv ? LEANBACK : LAUNCHER rule that androidLauncherCategories(target)[0] already returns, so the rule now has two spellings in one file. You could return androidLauncherCategories(target)[0]! from it, or leave it as is.

The Coverage check is the only one not passing. This PR does not touch packages/capture-kit, and the failure looks like the screenshot-diff.test.ts timeout under coverage described in #3933. I could not read the failing test line from the log, so that match rests on the #3933 description. Once #3933 merges, rerun Coverage (or rebase onto it) and this PR can merge. I know of no conflicts.

…ent Fire TV support

Fire TV devices running Fire OS are Android-based and automate over ADB, but TV
detection only read the AOSP leanback/television features and app launch used the
LEANBACK_LAUNCHER category alone. Fire OS devices declare amazon.hardware.fire_tv
and may declare no leanback feature, and Fire OS apps can register under either
launcher category.

- Inventory: treat amazon.hardware.fire_tv as a TV feature signal.
- App launch and listing on a TV target: query LEANBACK_LAUNCHER first, fall back
  to LAUNCHER, and launch the resolved component under the category it resolved
  under.
- Docs and versioned help: Fire TV (Fire OS) connects as an Android TV device;
  Vega OS remains VVD-only and is a different OS; Electron/Chromium macOS apps
  automate through the accessibility tree.
@thymikee

Copy link
Copy Markdown
Member Author

Rebased onto main (c266126422 #3933 + ce85ac8d37 #3932) and applied the final note. Head is now df2f9120ce66426d384a228b4cb813f7b68fe67a.

  • Single spelling applied: androidLaunchCategory returns androidLauncherCategories(target)[0]!; the duplicated tv ? LEANBACK : LAUNCHER rule is gone. Behavior and emitted argv are unchanged (46/46 unit tests green, argv tests included).
  • Conflicts resolved toward main: the two doc conflicts (README "How it works", introduction platform list) now keep main's Electron sentences from docs(macos): document Electron app automation through the accessibility tree #3932 verbatim and only add the Fire OS wording ("Android, Android TV, and Fire OS" / "Fire TV devices running Fire OS"). git diff origin/main..HEAD adds no Electron text — no duplication from the split.
  • Coverage: the rebase picks up the test(capture-kit): encode solid test PNGs unfiltered to stay inside the unit budget #3933 timeout fix; this push reruns the job.
  • pnpm check:affected --run --head df2f9120ce66426d384a228b4cb813f7b68fe67a: all runnable checks passed, exactCommit=true (receipt .tmp/validation/run-05ZPGb/receipt.json).

The live Android TV evidence in the body stands from bbcc604 — the code path that produced that argv is unchanged since.

@thymikee
thymikee merged commit c48d27a into main Oct 23, 2026
18 of 19 checks passed
@thymikee
thymikee deleted the fireos-docs branch October 23, 2026 15:15
thymikee added a commit that referenced this pull request Oct 24, 2026
* origin/main:
  fix(android): bound the dumpsys reads behind dialog and foreground checks (#3936)
  feat(android): detect Fire OS devices as Android TV targets and document Fire TV support (#3923)
  docs(macos): document Electron/Chromium app automation through the accessibility tree (#3932)
  test(capture-kit): encode solid test PNGs unfiltered to stay inside the unit budget (#3933)
  fix: guard bounded lifecycle and claim recovery (#3911)
  fix(ios): clear a long text value wherever the caret lands (#3908)
  fix(snapshot): stop iOS 27 floating-bar containers from covering content (#3912)
  ci: cache and bound the Linux desktop dependency install (#3919)
  fix: refuse resource operations in bounded composites (#3910)
  refactor(ios): decide bridge-failure scope and warning once (#3914)
  refactor(capture-kit): encode post-gesture stabilization baseline provenance (#3915)
  perf: expect the persistent session on Android snapshot-raw (#3913)
  test(ios): hold the fill read-count pin to the route it measures (#3909)
  perf(ios): admit tap text-input probes from fresh target evidence (#3881)
  feat(perf): time every Android command against the fixture app (#3902)
  chore: mark 0.21.31 as released
thymikee added a commit that referenced this pull request Oct 24, 2026
* origin/main:
  fix(android): bound the dumpsys reads behind dialog and foreground checks (#3936)
  feat(android): detect Fire OS devices as Android TV targets and document Fire TV support (#3923)
  docs(macos): document Electron/Chromium app automation through the accessibility tree (#3932)
  test(capture-kit): encode solid test PNGs unfiltered to stay inside the unit budget (#3933)
  fix: guard bounded lifecycle and claim recovery (#3911)
  fix(ios): clear a long text value wherever the caret lands (#3908)
  fix(snapshot): stop iOS 27 floating-bar containers from covering content (#3912)
  ci: cache and bound the Linux desktop dependency install (#3919)
thymikee added a commit that referenced this pull request Oct 24, 2026
* origin/main:
  fix(android): bound the dumpsys reads behind dialog and foreground checks (#3936)
  feat(android): detect Fire OS devices as Android TV targets and document Fire TV support (#3923)
  docs(macos): document Electron/Chromium app automation through the accessibility tree (#3932)
  test(capture-kit): encode solid test PNGs unfiltered to stay inside the unit budget (#3933)
  fix: guard bounded lifecycle and claim recovery (#3911)
  fix(ios): clear a long text value wherever the caret lands (#3908)
  fix(snapshot): stop iOS 27 floating-bar containers from covering content (#3912)
  ci: cache and bound the Linux desktop dependency install (#3919)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant