app: accurate Shizuku handoff — name the steps, add developer-options shortcut
Verified against Shizuku 13.6's manifest (pulled APK, aapt2 xmltree): its
wireless-debugging entry points (AdbPairingTutorialActivity,
AdbPairingService, StarterActivity) have no intent filters, so they are
not exported and cannot be launched externally; MainActivity answers only
MAIN/LAUNCHER with no deep link. Starting wireless debugging from another
app is therefore not possible, which is why the handoff lands on the
root-start screen.
Instead the hint now names the exact steps inside Shizuku ("Pairing", then
"Start"), and a second tap opens Developer options — that action IS public
and exported, and Wireless debugging has to be on before Shizuku's
wireless start works.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1d9e2063bf
commit
c75a9f5eb7
@@ -531,3 +531,15 @@ Verified on-device in one screenshot: progress bar at "test 4 of 8 · icmp.ping6
|
||||
Cancel button beside the disabled Run button, title clear of the status bar/cutout, and the banner
|
||||
having live-switched from "installed but not running" to "running but not authorised" via the
|
||||
binder listener when Shizuku was started mid-session.
|
||||
|
||||
### Why the Shizuku banner can't start wireless debugging directly (verified, 2026-08-01)
|
||||
Checked against Shizuku 13.6's own manifest (pulled the APK, `aapt2 dump xmltree`): the
|
||||
wireless-debugging entry points — `moe.shizuku.manager.adb.AdbPairingTutorialActivity`,
|
||||
`moe.shizuku.manager.adb.AdbPairingService`, `moe.shizuku.manager.starter.StarterActivity` —
|
||||
declare **no intent filters**, so they are not exported and a third-party app cannot launch them.
|
||||
`MainActivity` is the only reachable entry and answers MAIN/LAUNCHER only (no deep link), which is
|
||||
why the handoff lands on the screen whose primary action is the root start.
|
||||
Best available behavior, now implemented: the banner still opens Shizuku, but the hint names the
|
||||
exact steps there ("Pairing", then "Start"), and a second tap target opens **Developer options**
|
||||
(`Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS` — public and exported) since Wireless
|
||||
debugging must be enabled first for Shizuku's wireless start to work at all.
|
||||
|
||||
@@ -65,6 +65,13 @@ class MainActivity : ComponentActivity() {
|
||||
state = vm.state,
|
||||
onRun = { vm.run() },
|
||||
onCancel = vm::cancel,
|
||||
onDeveloperOptions = {
|
||||
runCatching {
|
||||
startActivity(
|
||||
app.echo_lot.shizuku.ShizukuAvailability.developerOptionsIntent()
|
||||
)
|
||||
}
|
||||
},
|
||||
onShizukuAction = {
|
||||
// Shizuku can only be started from its own app (the pairing flow lives
|
||||
// there), so send the user straight to it; if it is already running we
|
||||
@@ -114,6 +121,7 @@ private fun EcholotScreen(
|
||||
onRun: () -> Unit,
|
||||
onCancel: () -> Unit,
|
||||
onShizukuAction: () -> Unit,
|
||||
onDeveloperOptions: () -> Unit,
|
||||
onExport: (MeasurementDocument) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
@@ -150,6 +158,17 @@ private fun EcholotScreen(
|
||||
Text(it, fontSize = 11.sp, fontWeight = FontWeight.SemiBold,
|
||||
color = Color(0xFFFFB454))
|
||||
}
|
||||
// Wireless debugging must be ON before Shizuku's wireless start works, and
|
||||
// that screen (unlike Shizuku's pairing activity) is publicly launchable.
|
||||
if (state.shizukuState ==
|
||||
app.echo_lot.shizuku.ShizukuAvailability.State.INSTALLED_NOT_RUNNING
|
||||
) {
|
||||
Text(
|
||||
"Wireless debugging settings →",
|
||||
Modifier.padding(top = 6.dp).clickable { onDeveloperOptions() },
|
||||
fontSize = 11.sp, color = Color(0xFF35E0C4),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
-6
@@ -59,10 +59,14 @@ object ShizukuAvailability {
|
||||
}
|
||||
|
||||
/**
|
||||
* Intent that opens the Shizuku manager, where the user starts the service ("Start with
|
||||
* wireless debugging" / root). A third-party app cannot start Shizuku itself — the pairing
|
||||
* flow lives inside that app — so the best we can do is take the user straight there.
|
||||
* Null when Shizuku isn't installed or exposes no launcher activity.
|
||||
* Intent that opens the Shizuku manager.
|
||||
*
|
||||
* Only `MainActivity` is reachable: verified against Shizuku 13.6's own manifest, the
|
||||
* wireless-debugging entry points — `moe.shizuku.manager.adb.AdbPairingTutorialActivity`,
|
||||
* `moe.shizuku.manager.adb.AdbPairingService` and `moe.shizuku.manager.starter.StarterActivity`
|
||||
* — declare no intent filters, so they are NOT exported and a third-party app cannot launch
|
||||
* them (MainActivity itself only answers MAIN/LAUNCHER, no deep link). Landing on the main
|
||||
* screen and telling the user which button to press is therefore the best available handoff.
|
||||
*/
|
||||
fun launchIntent(context: Context): android.content.Intent? =
|
||||
context.packageManager.getLaunchIntentForPackage(SHIZUKU_PACKAGE)
|
||||
@@ -73,13 +77,26 @@ object ShizukuAvailability {
|
||||
runCatching { Shizuku.requestPermission(requestCode) }
|
||||
}
|
||||
|
||||
/** What tapping the notice should do, so the UI can label it honestly. */
|
||||
/**
|
||||
* What tapping the notice does. For the stopped case the label names the exact steps inside
|
||||
* Shizuku, because we can only hand the user to its main screen (see [launchIntent]).
|
||||
*/
|
||||
fun actionHint(s: State): String? = when (s) {
|
||||
State.INSTALLED_NOT_RUNNING -> "Tap to open Shizuku and start it"
|
||||
State.INSTALLED_NOT_RUNNING ->
|
||||
"Tap to open Shizuku → \"Pairing\" to pair, then \"Start\" (wireless debugging)"
|
||||
State.NEEDS_PERMISSION -> "Tap to grant permission"
|
||||
else -> null
|
||||
}
|
||||
|
||||
/**
|
||||
* Developer-options screen, where Wireless debugging is enabled — the prerequisite Shizuku's
|
||||
* wireless start depends on. This action IS public and exported, unlike Shizuku's own
|
||||
* pairing screen.
|
||||
*/
|
||||
fun developerOptionsIntent(): android.content.Intent =
|
||||
android.content.Intent(android.provider.Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)
|
||||
.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
/**
|
||||
* Reports the state now and on every binder transition. Returns a function that removes the
|
||||
* listeners again (call it from onCleared).
|
||||
|
||||
Reference in New Issue
Block a user