phone: dynamic app list from glasses + two-channel GlassesStatusScreen

Phone app:
- VmPhoneController: collect appsOnGlasses from glasses (state flow), and
  requestAppList() sends VmMessage.GetAppList over WebSocket.
- AppsListScreen: rename to dynamic list from glasses, verticalScroll,
  tap → LaunchAppCommand(packageName). Tap calls onAppClick for parent
  nav (Glasses tab on the bottom NavigationBar).
- Shared VM message types (VmMessage.GetAppList / AppListResponse /
  AppEntry) move into :shared module so both phone and glasses can
  serialize/deserialize them through the existing VmMessage.Json

Glasses app:
- VmService handles GetAppList by listing installed launchable apps
  via PackageManager.queryIntentActivities (combined with Android 11+
  <queries> fix in the previous commit so 3rd-party apps appear) and
  replies with AppListResponse.
- GlassesScreen drives state from controller.state; no longer hardcodes
  any apps in the UI.

Tested end-to-end on A06B4AB933C4103: phone taps app on
AppsListScreen → glasses' VmService receives LaunchAppCommand →
controller.launchGuest(pkg) launches the activity via
PackageManager.getLaunchIntentForPackage + FLAG_ACTIVITY_NEW_TASK.
This commit is contained in:
2026-09-25 15:21:14 +03:00
parent cc5866b373
commit 86bffed6ec
4 changed files with 96 additions and 48 deletions
@@ -39,6 +39,7 @@ import pw.binom.rayneovm.glasses.vm.GlassesScreenState
fun GlassesScreen(
controller: VmGlassesController,
modifier: Modifier = Modifier,
onRequestShizukuPermission: (() -> Unit)? = null,
) {
val state by controller.state.collectAsState()
val frameSource = remember { mutableStateOf<FrameSource>(NoOpFrameSource()) }
@@ -55,8 +56,9 @@ fun GlassesScreen(
is GlassesScreenState.Starting -> StatusOverlay("Подготавливаем очки...")
is GlassesScreenState.ShizukuMissing -> StatusOverlay(
title = "Shizuku не активен",
subtitle = "Запустите Shizuku на этом устройстве.\n" +
"Без него приложение не сможет создать виртуальный экран."
subtitle = "Без Shizuku приложение не может создать виртуальный экран.\n" +
"Тапните здесь, чтобы дать разрешение.",
onClick = onRequestShizukuPermission,
)
is GlassesScreenState.NoConnection -> StatusOverlay(
title = "Нет связи с телефоном",