Skip to content

Use role API when setting the default launcher#17

Merged
bryanroscoe merged 1 commit into
mainfrom
fix/launcher-set-default-role-api
May 8, 2026
Merged

Use role API when setting the default launcher#17
bryanroscoe merged 1 commit into
mainfrom
fix/launcher-set-default-role-api

Conversation

@bryanroscoe
Copy link
Copy Markdown
Owner

`Set-DefaultLauncher` only called `cmd package set-home-activity`, which is the legacy Android API. On Android 10+ the canonical mechanism is the role API (`cmd role add-role-holder android.app.role.HOME `); on Android 11+ the legacy command frequently no-ops silently. Reproduced on a real Shield running Android 11 — wizard reported "Could not set default programmatically" even after Projectivy was installed and the user clicked through the wizard.

The codebase already has `Set-HomeRoleHolder` (used by `Disable-AllStockLaunchers`). Try it first in `Set-DefaultLauncher`; fall through to the legacy command + activity-name fallbacks only if the role API rejects the package.

Verification

  • `make lint` — Syntax OK
  • `make test` — 121 passed / 4 skipped / 0 failed
  • On-device verification pending — open this PR for the user to retry the wizard.

Set-DefaultLauncher only called `cmd package set-home-activity`, which
is the legacy Android API. On Android 10+ the canonical mechanism is
the role API (`cmd role add-role-holder android.app.role.HOME <pkg>`)
and on Android 11+ the legacy command often no-ops silently — leaving
the launcher installed but not active.

The codebase already has Set-HomeRoleHolder used by the
Disable-AllStockLaunchers path. Try that first in Set-DefaultLauncher
and fall through to the legacy command (with the existing common-name
fallback) if the role API rejects the package. Reproduced on a Shield
running Android 11 where the wizard reported "Could not set default
programmatically" even after Projectivy was installed.
@bryanroscoe bryanroscoe merged commit c9c7b3d into main May 8, 2026
4 checks passed
bryanroscoe added a commit that referenced this pull request May 27, 2026
User feedback was that v2 was read-only — just data with no way to
change anything. This commit wires up the write surface:

Backend commands
----------------
- commands/launcher.rs::set_default_launcher — ports v1's full multi-
  strategy promotion (PR #17/#18). Order: `pm enable` → role API
  (skips on "Unknown command") → `cmd package query-activities` to
  discover the HOME activity, then set-home-activity via cmd package
  and pm aliases with --user 0 → HOME-intent kick fallback. Each
  attempt is verified by re-resolving the active launcher. Returns
  a structured SetLauncherResult { ok, strategy, current_launcher,
  last_error } so the UI can show which strategy worked / failed.
- commands/apps.rs — disable_package / enable_package /
  uninstall_package / reinstall_existing. Each runs the matching
  `pm` subcommand with --user 0, inspects stdout/stderr for Failure
  markers (pm's exit codes are unreliable across Android versions),
  returns ActionResult { ok, message }.
- commands/sideload.rs::install_apk — `adb -s <serial> install -r
  <path>`, with `decode_install_error` translating known
  INSTALL_FAILED_* / DELETE_FAILED_* codes into user-readable hints
  (insufficient storage, version downgrade, no matching ABIs, etc.).
- tauri-plugin-dialog added so the frontend can show a native file
  picker for APKs.

Frontend
--------
- Health tab gained a "Live refresh" checkbox + last-refreshed
  relative-time label (`Updated 5s ago`, ticks every second when
  live). Auto-polls every 3s while on. Cleans up timers on destroy.
- Top Memory Users now shows up to 20 entries (was 10) and each
  row gets a "Disable" button that calls disable_package and writes
  the result inline.
- Launcher tab — each installed launcher row now has a "Set as
  default" button that calls set_default_launcher and reloads the
  list. The currently-active launcher is tagged ACTIVE.
- App List tab — each row has Disable/Enable/Uninstall buttons
  (Uninstall only for entries marked UNINSTALL method). Uninstall
  asks for confirmation. Result message renders above the table.
- New "Install APK" tab — opens the native file picker via
  tauri-plugin-dialog, runs install_apk against the device, surfaces
  the verbatim adb output and decoded hint if the install failed.

Capabilities
------------
- dialog:allow-open added to capabilities/default.json so the file
  picker works.

Tests
-----
56 passing (same as before — no new parser logic, just commands and
UI). cargo fmt / clippy -D warnings / svelte-check all clean.
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