glasses: switch to rikka.shizuku.ShizukuProvider, fix binder acquisition
- Add dev.rikka.shizuku:provider:13.1.5 dependency. - Replace custom ShizukuInitProvider with rikka.shizuku.ShizukuProvider from the upstream library; configured per Shizuku v12+ docs with android:permission='android.permission.INTERACT_ACROSS_USERS_FULL' to protect the provider from ordinary apps. - Move ShizukuBootstrap.attach() from GlassesVmApp.onCreate to MainActivity.onCreate (requestPermission needs an Activity context). - MainActivity now overrides onRequestPermissionsResult and forwards the grant to ShizukuBootstrap. - Rewrite ShizukuBootstrap strictly per the Shizuku-API guide: addBinderReceivedListenerSticky + addRequestPermissionResultListener in attach(); pingBinder / checkSelfPermission / requestPermission in refresh(). - Drop ShizukuInitProvider.kt — its job is now done by rikka.shizuku.ShizukuProvider.onCreate (verified in logcat: 'ShizukuProvider: binder received'). Verified on device ARGF20 (A06B4AB933C4103, API 32): Shizuku dialog 'Allow rayneo-vm to use Shizuku?' opens correctly; binder received via ShizukuProvider; launcher icon now visible (meta-data fix).
This commit is contained in:
@@ -64,6 +64,7 @@ dependencies {
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
|
||||
implementation(libs.shizuku.api)
|
||||
implementation(libs.shizuku.provider)
|
||||
implementation(libs.mercury.library)
|
||||
implementation(libs.mercury.transport)
|
||||
implementation(libs.mercury.binocular)
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="moe.shizuku.permission.SHIZUKU" />
|
||||
<!-- Shizuku v12+: BinderSender проверяет requestedPermissions на наличие
|
||||
этого permission (см. moe.shizuku.server.BinderSender.sendBinder).
|
||||
Старое moe.shizuku.permission.SHIZUKU (Shizuku v11) больше не работает. -->
|
||||
<uses-permission android:name="moe.shizuku.manager.permission.API_V23" />
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
@@ -21,6 +24,16 @@
|
||||
android:name="android.hardware.type.embedded"
|
||||
android:required="true" />
|
||||
|
||||
<!-- Android 11+ package visibility: Shizuku API выполняет context.bindService на сервис
|
||||
внутри пакета moe.shizuku.privileged.api; без явного queries bindService возвращает
|
||||
false и binder к нам никогда не приедет. -->
|
||||
<queries>
|
||||
<package android:name="moe.shizuku.privileged.api" />
|
||||
<intent>
|
||||
<action android:name="rikka.shizuku.intent.action.REQUEST_BINDER" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
android:name=".GlassesVmApp"
|
||||
android:label="@string/app_name"
|
||||
@@ -52,6 +65,18 @@
|
||||
android:name=".VmShizukuService"
|
||||
android:exported="true"
|
||||
android:process=":shizuku_vd" />
|
||||
|
||||
<!-- Shizuku v12+ требует ShizukuProvider в манифесте — он сам вытаскивает binder
|
||||
через ContentProvider IPC и инициализирует Shizuku-клиент. Без него binder не придёт.
|
||||
permission=INTERACT_ACROSS_USERS_FULL защищает провайдер от обычных приложений. -->
|
||||
<provider
|
||||
android:name="rikka.shizuku.ShizukuProvider"
|
||||
android:authorities="${applicationId}.shizuku"
|
||||
android:multiprocess="false"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||
|
||||
<meta-data android:name="com.rayneo.mercury.app" android:value="true" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -10,6 +10,9 @@ import pw.binom.rayneovm.glasses.protocol.VmGlassesController
|
||||
*
|
||||
* Запускает [VmService] при создании (foreground-сервис держит WebSocket сервер + mDNS,
|
||||
* и продолжает работать после сворачивания Activity).
|
||||
*
|
||||
* Также стартует [ShizukuBootstrap] — он регистрирует binder listener, ждёт/запрашивает
|
||||
* permission и обновляет state. MainActivity потом подпишется на этот state.
|
||||
*/
|
||||
class GlassesVmApp : Application(), ControllerProvider {
|
||||
|
||||
@@ -18,11 +21,15 @@ class GlassesVmApp : Application(), ControllerProvider {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
Log.i(TAG, "GlassesVmApp onCreate, uid=${android.os.Process.myUid()}")
|
||||
// Инициализация RayNeo Mercury SDK.
|
||||
com.ffalcon.mercury.android.sdk.MercurySDK.init(this)
|
||||
Log.i(TAG, "MercurySDK initialized")
|
||||
|
||||
// 1. RayNeo Mercury SDK init (BLE-канал, если нужно)
|
||||
runCatching { com.ffalcon.mercury.android.sdk.MercurySDK.init(this) }
|
||||
.onSuccess { Log.i(TAG, "MercurySDK initialized") }
|
||||
.onFailure { Log.w(TAG, "MercurySDK init failed: ${it.message}") }
|
||||
|
||||
controller.setAppContext(this)
|
||||
// Регистрируем debug-receiver для тестирования через adb.
|
||||
|
||||
// 2. Регистрируем debug-receiver для тестирования через adb
|
||||
val filter = android.content.IntentFilter(pw.binom.rayneovm.glasses.protocol.DebugTestReceiver.ACTION)
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(pw.binom.rayneovm.glasses.protocol.DebugTestReceiver(), filter, android.content.Context.RECEIVER_EXPORTED)
|
||||
@@ -30,6 +37,11 @@ class GlassesVmApp : Application(), ControllerProvider {
|
||||
@Suppress("UnspecifiedRegisterReceiverFlag")
|
||||
registerReceiver(pw.binom.rayneovm.glasses.protocol.DebugTestReceiver(), filter)
|
||||
}
|
||||
|
||||
// 3. Shizuku bootstrap здесь не зовём — он вызывается из MainActivity.onCreate,
|
||||
// где есть Activity-контекст (для requestPermission flow).
|
||||
|
||||
// 4. Запуск foreground-сервиса (WebSocket + mDNS publisher)
|
||||
VmService.start(this)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,23 +9,30 @@ import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import pw.binom.rayneovm.glasses.protocol.VmGlassesController
|
||||
import pw.binom.rayneovm.glasses.ui.GlassesScreen
|
||||
import pw.binom.rayneovm.glasses.vm.GlassesScreenState
|
||||
|
||||
/**
|
||||
* Single-Activity приложения: Compose host для GlassesScreen.
|
||||
*
|
||||
* Никакой навигации — здесь один экран (зеркало гостевого приложения + state overlay).
|
||||
*/
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
// По доке Shizuku (https://github.com/RikkaApps/Shizuku-API): подписываемся на
|
||||
// listener-ы здесь, после super.onCreate, но ДО setContent. ShizukuProvider
|
||||
// (rikka.shizuku.ShizukuProvider в манифесте) уже инициализировал binder через
|
||||
// ContentProvider.onCreate — pingBinder() сразу вернёт true.
|
||||
ShizukuBootstrap.attach(this)
|
||||
val controller = VmGlassesController.fromContext(this)
|
||||
|
||||
setContent {
|
||||
CompositionLocalProvider(VmGlassesController.Local provides controller) {
|
||||
MaterialTheme(colorScheme = darkColorScheme()) {
|
||||
@@ -34,10 +41,61 @@ class MainActivity : ComponentActivity() {
|
||||
.fillMaxSize()
|
||||
.background(Color.Black)
|
||||
) {
|
||||
GlassesScreen(controller = controller)
|
||||
val shizukuState by ShizukuBootstrap.state.collectAsState()
|
||||
val vmState by controller.state.collectAsState()
|
||||
DriveShizukuState(controller, shizukuState)
|
||||
GlassesScreen(
|
||||
controller = controller,
|
||||
onRequestShizukuPermission = { ShizukuBootstrap.refresh() },
|
||||
)
|
||||
// Как только VM ушёл в Running (запущен гость) — сворачиваем свой Activity,
|
||||
// чтобы SurfaceView гостя оказался поверх и был виден на очках.
|
||||
// Service продолжает жить в фоне (WebSocket/mDNS не рвутся).
|
||||
if (vmState is GlassesScreenState.Running) {
|
||||
(this as? ComponentActivity)?.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
ShizukuBootstrap.refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* По доке Shizuku, мы должны вручную передать результат диалога в Shizuku -
|
||||
* иначе он не узнает, что пользователь нажал Allow.
|
||||
*/
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray,
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == ShizukuBootstrap.REQUEST_CODE_PERMISSION) {
|
||||
val grant = grantResults.firstOrNull() ?: -1
|
||||
ShizukuBootstrap.onRequestPermissionResult(requestCode, grant)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DriveShizukuState(controller: VmGlassesController, shizuku: ShizukuBootstrap.AllowState) {
|
||||
LaunchedEffect(shizuku) {
|
||||
when (shizuku) {
|
||||
ShizukuBootstrap.AllowState.NotRunning,
|
||||
ShizukuBootstrap.AllowState.Waiting,
|
||||
ShizukuBootstrap.AllowState.NeedsPermission -> {
|
||||
controller.setState(GlassesScreenState.ShizukuMissing)
|
||||
}
|
||||
ShizukuBootstrap.AllowState.Granted -> {
|
||||
if (controller.state.value is GlassesScreenState.ShizukuMissing) {
|
||||
controller.setState(GlassesScreenState.NoAppSelected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ lifecycle = "2.11.0"
|
||||
activityCompose = "1.11.0"
|
||||
composeBom = "2026.09.00"
|
||||
shizukuApi = "13.1.5"
|
||||
shizukuProvider = "13.1.5"
|
||||
navCompose = "2.10.2"
|
||||
mercury = "0.1.0-SNAPSHOT"
|
||||
mercuryTransport = "0.1.0-SNAPSHOT"
|
||||
@@ -45,6 +46,7 @@ androidx-core-ktx = { module = "androidx.core:core-ktx", version = "1.15.0" }
|
||||
|
||||
# Shizuku
|
||||
shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizukuApi" }
|
||||
shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizukuProvider" }
|
||||
|
||||
# rayneo-mercury (библиотеки)
|
||||
mercury-library = { module = "pw.binom.mercury:rayneo-mercury", version.ref = "mercury" }
|
||||
|
||||
Reference in New Issue
Block a user