From 470ec2f093c26cbc397c59f31a45c57eb5ee2dd2 Mon Sep 17 00:00:00 2001 From: Seb3thehacker Date: Tue, 13 Oct 2026 16:23:58 -0700 Subject: [PATCH] usage notes: say whether each drive was USB or wireless, and whether music went over USB or Bluetooth --- README.md | 3 ++- .../app/seb3thehacker/gearslip/GearslipRunner.kt | 2 +- .../app/seb3thehacker/gearslip/SessionReport.kt | 10 ++++++++-- .../seb3thehacker/gearslip/stats/UsageStats.kt | 15 +++++++++++++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4892e36..c448b8e 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,8 @@ turn them on, in setup or in Settings. - **What they carry.** The Gearslip version and which boxes you ticked, plus whatever those boxes cover: the Android version and whether the phone runs GrapheneOS, the phone model, whether a car connected that day, and each car's head unit, model, year, screen - size, and connection result. Settings shows the exact note. Untick a phone detail, and + size, and connection result, with whether that drive used the cable or wireless and + whether music went over USB or Bluetooth. Settings shows the exact note. Untick a phone detail, and the server drops the copy it kept. - **What they leave out.** Your name, accounts, location, contacts, messages, and anything you type or play. diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipRunner.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipRunner.kt index 57ebf92..0f63fa6 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipRunner.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipRunner.kt @@ -98,7 +98,7 @@ class GearslipRunner( fun run() { // This thread reads the car's acks; audio waits on them, so it can't be left at the back. android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO) - SessionReport.begin() + SessionReport.begin(wireless) log.i("--- session starting ---") SessionStatus.connecting("Connected to the head unit") log.i("device=${Build.MANUFACTURER} ${Build.MODEL} android=${Build.VERSION.RELEASE} (sdk ${Build.VERSION.SDK_INT})") diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/SessionReport.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/SessionReport.kt index 65737e4..9afca7d 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/SessionReport.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/SessionReport.kt @@ -76,8 +76,14 @@ object SessionReport { appCode = info?.longVersionCode ?: 0 } - fun begin() { + /** How this drive reached the car, and how its music did: "usb" or "wireless", "usb" or "bluetooth". */ + @Volatile var link = ""; private set + @Volatile var audioMode = ""; private set + + fun begin(wireless: Boolean) { startedAt = System.currentTimeMillis() + link = if (wireless) "wireless" else "usb" + audioMode = if (app.seb3thehacker.gearslip.car.CarSettings.pipeAudio.value) "usb" else "bluetooth" category = Category.NONE failure = ""; protocolVersion = ""; certSource = ""; certIssuer = "" stage = Stage.USB; failCode = ""; failedAfter = 0 @@ -218,7 +224,7 @@ object SessionReport { else -> category.label } runCatching { - UsageStats.recordSession(context, headUnitInfo, protocolVersion, outcome, carScreen, carDpi, sessionNote()) + UsageStats.recordSession(context, headUnitInfo, protocolVersion, outcome, carScreen, carDpi, sessionNote(), link, audioMode) } if (outcome == "connected") runCatching { app.seb3thehacker.gearslip.stats.WorkedPrompt.onDriveWorked(context, headUnitInfo, protocolVersion, carScreen, carDpi) diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/stats/UsageStats.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/stats/UsageStats.kt index 4c4855e..784d03c 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/stats/UsageStats.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/stats/UsageStats.kt @@ -156,12 +156,14 @@ object UsageStats { screen: String = "", dpi: Int = 0, session: JSONObject? = null, + link: String = "", + audio: String = "", ) { if (!enabled(context)) return val p = prefs(context) synchronized(carsLock) { - addCar(p, info, protocol, outcome, screen, dpi) - if (session != null && choices(context).failures) addSession(p, info, protocol, session) + addCar(p, info, protocol, outcome, screen, dpi, link, audio) + if (session != null && choices(context).failures) addSession(p, info, protocol, session, link, audio) } sendSoon(context) } @@ -171,6 +173,8 @@ object UsageStats { info: ServiceDiscovery.HeadUnitInfo?, protocol: String, session: JSONObject, + link: String, + audio: String, ) { val sessions = runCatching { JSONArray(p.getString(KEY_SESSIONS, "[]")) }.getOrDefault(JSONArray()) if (sessions.length() >= MAX_SESSIONS) return @@ -179,6 +183,7 @@ object UsageStats { .put("car", info?.carModel.orEmpty()) .put("year", info?.carYear.orEmpty()) .put("protocol", protocol) + if (link.isNotEmpty()) session.put("link", link).put("audio", audio) sessions.put(session) // Written at once: after a crash the app is about to die, and a deferred write would be lost. p.edit().putString(KEY_SESSIONS, sessions.toString()).commit() @@ -191,6 +196,8 @@ object UsageStats { outcome: String, screen: String, dpi: Int, + link: String, + audio: String, ) { val cars = runCatching { JSONArray(p.getString(KEY_CARS, "[]")) }.getOrDefault(JSONArray()) val car = JSONObject() @@ -202,6 +209,8 @@ object UsageStats { .put("protocol", protocol) .put("result", outcome) if (screen.isNotEmpty()) car.put("screen", screen).put("dpi", dpi) + // USB or wireless, and whether music went over USB or Bluetooth: settings, not the person. + if (link.isNotEmpty()) car.put("link", link).put("audio", audio) // The same car and outcome twice in a day is one fact, not two. val seen = (0 until cars.length()).any { cars.optJSONObject(it)?.toString() == car.toString() } if (!seen && cars.length() < MAX_CARS) cars.put(car) @@ -305,6 +314,8 @@ object UsageStats { .put("car", "Car model") .put("year", "2021") .put("protocol", "1.5") + .put("link", "usb") + .put("audio", "bluetooth") /** Sends the note now; false when it didn't get through. */ private fun send(context: Context): Boolean {