phone: autonomous Shizuku revive over wireless-adb; glasses screen on/off buttons

AdbClient wraps the bundled libadb.so (useLegacyPackaging -> exec from nativeLibraryDir, HOME/TMPDIR overridden, adb key injected into BuildConfig from ~/.android at build time and never committed). ShizukuProvisioner: on each BLE+WiFi connect it enables ADB-over-WiFi via Mercury, connects with mDNS fallback, pushes the Shizuku starter and runs it; runs once per BLE session, does not relaunch GlassesApp when the WS channel is already up, and exposes runShell() for arbitrary commands. DebugReceiver (DUMP) + am start --ez provision for diagnostics.

Protocol: ShizukuStatus(running/granted) + RequestShizukuStatus; glasses push it on connect and on Shizuku state change, using a passive probe() that never shows a permission dialog. Glasses kill-guard now recreates its UserService when the Shizuku binder dies instead of spamming DeadObjectException. Mercury: brightness disables auto-brightness first (was silently ignored), BLE auto-connect loop retries every 6s (fixes 'searches then stops'). New phone section 'Экран очков' with wake/sleep via adb (input keyevent 224/223).
This commit is contained in:
2026-09-27 03:52:05 +03:00
parent 59069a741e
commit 8a0b7832c0
18 changed files with 1112 additions and 44 deletions
@@ -2,8 +2,17 @@ package pw.binom.rayneovm.phone
import android.app.Application
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import pw.binom.rayneovm.phone.bootstrap.ShizukuProvisioner
import pw.binom.rayneovm.phone.mercury.MercuryController
import pw.binom.rayneovm.phone.mercury.MercuryControllerProvider
import pw.binom.rayneovm.phone.mercury.MercuryState
import pw.binom.rayneovm.phone.protocol.ConnectionState
import pw.binom.rayneovm.phone.protocol.ControllerProvider
import pw.binom.rayneovm.phone.protocol.VmPhoneController
@@ -13,10 +22,15 @@ import pw.binom.rayneovm.phone.protocol.VmPhoneController
* При старте подготавливает контроллер [VmPhoneController] (auto-reconnect к очкам через mDNS)
* и [MercuryController] (второй канал — RayNeo Mercury BLE).
*/
class PhoneVmApp : Application(), ControllerProvider, MercuryControllerProvider {
class PhoneVmApp : Application(), ControllerProvider, MercuryControllerProvider, ShizukuProvisionerProvider {
private val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
private val controller: VmPhoneController by lazy { VmPhoneController(this) }
private val mercuryController: MercuryController by lazy { MercuryController(this) }
private val provisioner: ShizukuProvisioner by lazy {
ShizukuProvisioner(this, mercuryController, controller)
}
override fun onCreate() {
super.onCreate()
@@ -32,19 +46,58 @@ class PhoneVmApp : Application(), ControllerProvider, MercuryControllerProvider
// Запуск отложен до первого обращения — в lazy.
controller.start()
mercuryController.refresh()
// Автономный подъём Shizuku. Условие: есть и WiFi-канал (наша WebSocket-связь
// с очками), и BLE (Канал 2, через который очки включают ADB over WiFi).
// Проверяем при каждом появлении связи и периодически, пока BLE жив, —
// если Shizuku не запущен, поднимаем его.
appScope.launch {
controller.state.collect { st ->
if (st is ConnectionState.Connected && mercuryController.state.value is MercuryState.Connected) {
Log.i(TAG, "WiFi подключение к очкам — проверяю Shizuku")
provisioner.ensure()
}
}
}
// Периодический дешёвый дозвон, пока BLE жив. Полный adb-цикл гоняется не чаще
// одного раза за BLE-сессию (см. ShizukuProvisioner.provisionedInSession), поэтому
// это не дёргает очки; зато так мы подхватываем случай, когда Shizuku упал и очки
// прислали явный статус running=false.
appScope.launch {
while (true) {
delay(PROVISION_RETRY_MS)
if (mercuryController.state.value is MercuryState.Connected) {
provisioner.ensure()
}
}
}
// Разрыв BLE — новая сессия: при следующем подключении проверяем Shizuku заново.
appScope.launch {
mercuryController.state.collect { st ->
if (st !is MercuryState.Connected) provisioner.onBleDisconnected()
}
}
}
override fun onTerminate() {
super.onTerminate()
ConnectionKeepAliveService.stop(this)
provisioner.close()
controller.stop()
mercuryController.close()
}
override fun provideController(): VmPhoneController = controller
override fun provideMercuryController(): MercuryController = mercuryController
override fun provideShizukuProvisioner(): ShizukuProvisioner = provisioner
companion object {
private const val TAG = "PhoneVmApp"
private const val PROVISION_RETRY_MS = 30_000L
}
}
/** Провайдер автономного бутстрапа Shizuku для UI. */
interface ShizukuProvisionerProvider {
fun provideShizukuProvisioner(): ShizukuProvisioner
}