/* ── Android Auto's front door, as the PackageManager resolved it ───── * Two of the three fields FAIL the walk, and they are the only automated * proof this project has that Auto can see the app at all. * * What they catch is the `TAURI_ANDROID_PROJECT_PATH` trap. The service, * its intent filter and the `com.google.android.gms.car.application` * meta-data all live in the media-session plugin's own library manifest; * tauri-build only rewrites `gen/android/tauri.settings.gradle` when the * CLI's variable names the generated project, and without it the whole * module compiles fine and never reaches the APK. That has already cost * this project a start-up `ClassNotFoundException` once. Read out of * `pm dump` the filters are simply absent, which is a red line rather than * a crash in a car. * * `pm dump ` is `dumpsys package `: resolver tables, permissions * and package state. It prints NO application meta-data, so the * `automotive_app_desc` half cannot be asserted from here — `desc` is the * prober's own `{"ev":"desc"}` line echoed back, advisory, and the * meta-data's real proofs are aapt2 at link time (`@xml/automotive_app_desc` * is a compile-time reference; a missing resource fails the build) and * `tools/auto-prober/`, which resolves the int through * `PackageManager.GET_META_DATA` and parses the XML out of the app's own * Resources. * * `table` is in the JSON on purpose: a zero there says the Service Resolver * Table was not where this looked — a format surprise, not a missing * filter — which is the one thing that could turn these two into a false * red. */ function autoManifest() { const out = { browse: "", library: "", table: 0, desc: "no prober line" }; try { const dump = adb("shell", "pm", "dump", "com.soulstream.app").toString(); const at = dump.indexOf("Service Resolver Table:"); /* the section, and no further: the tables are printed one after another and an action name must not be found in the wrong one */ let table = ""; if (at >= 0) { const rest = dump.slice(at, at + 200000); const next = rest.indexOf("Resolver Table:", 23); table = next < 0 ? rest : rest.slice(0, next); } out.table = table.length; /* each action heads a block of the components that declare it; the window keeps a match from wandering into the next action's */ const resolves = (action) => { const i = table.indexOf(action + ":"); if (i < 0) return "no filter"; return /com\.soulstream\.mediasession\.MediaService/.test(table.slice(i, i + 600)) ? "MediaService" : "elsewhere"; }; out.browse = resolves("android.media.browse.MediaBrowserService"); out.library = resolves("androidx.media3.session.MediaLibraryService"); } catch (e) { out.browse = "ERR " + e.message; out.library = "ERR " + e.message; } try { const log = adb("logcat", "-d", "-s", "SoulAutoProbe:I").toString(); const lines = log.split(/\r?\n/).filter((l) => l.includes('"ev":"desc"')); const m = (lines[lines.length - 1] || "").match(/\{.*\}$/); if (m) out.desc = m[0]; } catch (e) { out.desc = "ERR " + e.message; } return out; }