From c75a9f5eb7b2e3c7e5495d171a7ea0e29dbc3db6 Mon Sep 17 00:00:00 2001 From: mrambossek Date: Sat, 1 Aug 2026 10:03:03 +0200 Subject: [PATCH] =?UTF-8?q?app:=20accurate=20Shizuku=20handoff=20=E2=80=94?= =?UTF-8?q?=20name=20the=20steps,=20add=20developer-options=20shortcut?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- docs/build-status.md | 12 ++++++++ .../kotlin/app/echo_lot/app/MainActivity.kt | 19 ++++++++++++ .../echo_lot/shizuku/ShizukuAvailability.kt | 29 +++++++++++++++---- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/docs/build-status.md b/docs/build-status.md index a16379b..a64b0e5 100644 --- a/docs/build-status.md +++ b/docs/build-status.md @@ -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. diff --git a/echolot-app/app/src/main/kotlin/app/echo_lot/app/MainActivity.kt b/echolot-app/app/src/main/kotlin/app/echo_lot/app/MainActivity.kt index 86f45eb..9d6d32a 100644 --- a/echolot-app/app/src/main/kotlin/app/echo_lot/app/MainActivity.kt +++ b/echolot-app/app/src/main/kotlin/app/echo_lot/app/MainActivity.kt @@ -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), + ) + } } } } diff --git a/echolot-app/core-shizuku/src/main/kotlin/app/echo_lot/shizuku/ShizukuAvailability.kt b/echolot-app/core-shizuku/src/main/kotlin/app/echo_lot/shizuku/ShizukuAvailability.kt index 1a598a9..d634041 100644 --- a/echolot-app/core-shizuku/src/main/kotlin/app/echo_lot/shizuku/ShizukuAvailability.kt +++ b/echolot-app/core-shizuku/src/main/kotlin/app/echo_lot/shizuku/ShizukuAvailability.kt @@ -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).