Skip to content

Disable Setup Wraith with the stock launcher on Google TV, and show its state on the Launcher tab (#122) - #156

Merged
bryanroscoe merged 11 commits into
mainfrom
fix-122-setup-wraith-takeover
Oct 3, 2026
Merged

bryanroscoe merged 11 commits into
mainfrom
fix-122-setup-wraith-takeover

Conversation

@bryanroscoe

Copy link
Copy Markdown
Owner

Setup Wraith is Google TV's fallback Home: with the stock launcher disabled it takes the Home button back, and every launcher guide disables it along with stock. The takeover now does the same once the chosen launcher is confirmed as Home, re-verifies, and re-enables both on any failure. Re-enabling stock, Emergency Recovery and the Launcher tab's Re-enable button all bring it back. The tab always shows its state, with a one-click Turn it off.

Known costs: it must be re-enabled briefly for Google sign-in or remote pairing. The Shield has no Setup Wraith and is unaffected.

🤖 Generated with Claude Code

@bryanroscoe

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-03T04:35:59.389208Z fad558d Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fcff8ae05a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +147 to +150
let transient_installed: Vec<String> = catalog
.transient_home_holders
.iter()
.filter(|pkg| installed_pkgs.iter().any(|p| p == *pkg))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Gate setup-helper rows on Google TV evidence

Do not treat every installation of this package as evidence of Google TV. The checked-in Shield capture lists com.google.android.tungsten.setupwraith as installed and disabled (v2/crates/core/tests/fixtures/devices/shield-tv-pro/pm-list-packages-d.txt:4), so chaining every installed transient holder here now gives Shield users the Google-TV-specific callout and a button that can re-enable this normally disabled package. Require the paired Google TV stock launcher or confirmed device type before exposing this row/action.

AGENTS.md reference: AGENTS.md:L50-L54

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in 50bfa1c: the transient-holder row now needs an installed stock launcher that pairs with it, so the Shield's installed-but-disabled package gets no row or callout. The e2e Shield scenario now uses the captured Shield as is.

Comment on lines +1482 to +1486
: !setupHelper.enabled
? "off"
: stockEnabled || customIsCurrent
? "on"
: "risk",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat an enabled helper with stock off as risky

When upgrading a TV already affected by #122, stock can be disabled while the HOME role still names the chosen custom launcher and Setup Wraith actually wins Home by priority—the new StockThenPriority simulator explicitly models that state. current_launcher prefers the role holder, so customIsCurrent is true and this branch reports "on" rather than "risk", hiding the new verified Turn it off action exactly for that recovery case. The risk state should not be suppressed merely because the role-derived current launcher is custom.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in 50bfa1c: the state is now risk whenever the helper is enabled and stock is off, regardless of the role-derived current launcher, so Turn it off shows for that case.

@bryanroscoe

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 50bfa1c14a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

serial: String,
package: String,
) -> Result<crate::commands::apps::ActionResult, String> {
let result = disable_setup_helper_impl(state.inner(), &serial, &package).await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Enforce the launcher entitlement before disabling

When a free-entitlement user sees the risk callout and clicks Turn it off, this command invokes the mutating implementation without state.require_pro(Feature::LauncherTakeover). Unlike set_default_launcher and disable_stock_launcher, the normal UI path therefore disables the helper successfully without the paid launcher-takeover entitlement; apply the entitlement check before calling the implementation.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in c8cd6c9.

Comment on lines +1431 to +1433
for (const helper of pairedOff) {
launcherProgress = "Re-enabling Google TV's setup helper";
await api.enablePackage(serial, helper);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle setup-helper re-enable failures

When re-enabling stock succeeds but pm enable for its paired helper is rejected, enablePackage resolves to an ActionResult with ok: false; it does not throw. Ignoring that result lets the loop continue and report the stock-enable action as successful while Setup Wraith remains disabled, breaking the stated behavior that re-enabling stock restores its paired helper. Check each result and surface or retry the failure.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in c8cd6c9.

@bryanroscoe

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c8cd6c97b1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread v2/crates/core/src/commands/launcher.rs Outdated
Comment on lines +1090 to +1091
diagnostics.push("query-activities HOME (setup helper) -> unavailable".to_string());
return Ok(());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Roll back when the setup-helper query is unavailable

If this second HOME-handler query fails after the stock launcher has already been disabled, returning Ok(()) makes both takeover callers report success without disabling Setup Wraith. On the affected Google TV configuration, that leaves stock off while Setup Wraith can reclaim the Home button—the exact state this change is intended to prevent. Treat the unavailable query as a failure that restores stock, or reuse the handler inventory collected before disabling it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in bd338c9: the takeover now reads the Home-handler list before stock is disabled and reuses it, so there is no second query. If that read is unavailable, the takeover fails and stock is restored. Test: unreadable_home_apps_never_leave_stock_off_with_the_helper_on.

Comment thread v2/crates/core/src/commands/launcher.rs Outdated
Comment on lines +1240 to +1241
let restore = adb.shell(serial, &format!("pm enable {package}")).await;
let _ = restore;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Report a failed setup-helper rollback

When the disable command may have landed but verification fails, the rollback's pm enable result is discarded. If that enable also fails, the response still says the helper “was left enabled” or “was re-enabled,” even though it can remain disabled after a failed safety recovery. Check command_failure(&restore) and surface the incomplete rollback instead of claiming recovery succeeded.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in bd338c9: the rollback's pm enable result is checked. If it fails, the message says Setup Wraith may still be off and points to Re-enable Setup Wraith or Emergency Recovery, instead of claiming it was re-enabled. Test: a_failed_helper_rollback_is_reported_not_called_re_enabled.

Comment on lines +284 to +286
let installed = shield_optimizer_core::adb::parse_installed_packages_output(&sections[0]);
let disabled = shield_optimizer_core::adb::parse_disabled_packages_output(&sections[1]);
Some(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat an empty package inventory as unreadable

A zero-exit pm list packages response with an empty body is accepted here, so installed becomes empty and the diagnostics formatter reports “Setup helper: not installed.” Other package-state readers explicitly reject an empty installed list because an Android device always has packages; without the same guard, a transient blank response produces a false absence claim in the bug-report data added to diagnose this issue. Return None when installed is empty so the report says the state is unknown.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in e58dcbe: an empty installed list now returns None (unknown), so the report no longer says not installed. Test: an_empty_installed_list_is_unknown_not_absent.

@bryanroscoe

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bd338c908b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1314 to +1317
match adb.shell(serial, HOME_HANDLER_QUERY).await {
Ok(out) if out.success() && !out.shell_reported_failure() => {
Some(parse_home_handler_packages(&out.stdout))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat an empty HOME inventory as unreadable

When HOME_HANDLER_QUERY exits successfully but returns an empty or unparseable body, this constructs Some([]). After the target verifies, disable_paired_holders then returns success without disabling Setup Wraith, leaving Google TV stock off while the helper remains enabled and reporting the takeover as successful. Fresh evidence after bd338c9 is that its unavailable-query rollback does not cover successful empty output. Reject an empty parsed inventory or use package-state data to establish whether the paired helper is enabled.

AGENTS.md reference: AGENTS.md:L50-L54

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in fad558d: an empty parsed Home-handler list is now treated as unreadable, so the takeover fails and restores stock. Test: an_empty_home_inventory_never_leaves_stock_off_with_the_helper_on.

diagnostics,
});
}
Err(reason) => failure = Some(reason),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Report failed stock restoration after helper errors

When the target already holds Home and disabling or verifying the paired helper fails, this new error path enters the stock rollback loop. If pm enable <stock> also fails, that failure is recorded only in diagnostics and the returned message still says the stock launcher “was re-enabled”; meanwhile the helper rollback may have re-enabled Setup Wraith while stock remains off, recreating the risky state while telling the user recovery succeeded. Propagate the stock-restore failure and state that stock may remain disabled.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in fad558d: the stock rollback now checks pm enable. If it fails, the message says the stock launcher may still be off and points to Emergency Recovery, instead of claiming it was re-enabled. Test: a_failed_stock_restore_after_a_helper_error_is_reported.

@bryanroscoe

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fad558d239

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1359 to +1363
match disable_paired_holders(
adb,
serial,
package,
&[active.to_string()],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pair setup-helper shutdown with generic stock disables

When Google TV Home is disabled from the App List through disable_package (or through the launcher row's generic disable_launcher action), neither path reaches this new paired-holder logic. With another real launcher enabled, those guards allow the action, leaving Setup Wraith enabled after stock is turned off and recreating the exact state where it can take the Home button. Route every stock-launcher disable entry point through the paired-holder operation, not only the takeover commands.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Not changed here. This is the stock-off, helper-on state reached through the generic disable paths this PR doesn't touch. The review-fix round limit was reached, so it is filed as #157.

Comment on lines +1428 to +1430
const pairedOff = (launchers.find((l) => l.entry.package === pkg && l.stock)?.entry.disable_with ?? []).filter(
(h) => launchers.some((l) => l.entry.package === h && l.installed && !l.enabled),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore paired helpers when setting stock as default

After a takeover disables both packages, the stock row offers both Enable and Enable & set default, but this helper restoration runs only in enableLauncher; the latter button calls setDefaultLauncher, whose backend enables the stock package without its paired helper. The mobile launcher also restores disabled stock through that setter. In either flow Setup Wraith remains off even though stock was restored, so later Google sign-in or remote pairing can remain broken; restore paired helpers in the shared stock-enable/default path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Not changed here. Home is not lost in this case, since stock is back on. Filed as #158.

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