|
@@ -96,7 +96,7 @@ notifyListeners();
|
|
|
- Screen-space is deliberately finite: test the 16-button grid at 1280×800, 1280×720 and 1024×600. The shortcut grid is bottom-anchored so a short row sits on the bottom edge; keep that behavior when changing layouts. The grid includes All apps; Settings sits in `StatusCluster` and does not consume a slot. Avoid unbounded `ListView`s inside `Column`s.
|
|
- Screen-space is deliberately finite: test the 16-button grid at 1280×800, 1280×720 and 1024×600. The shortcut grid is bottom-anchored so a short row sits on the bottom edge; keep that behavior when changing layouts. The grid includes All apps; Settings sits in `StatusCluster` and does not consume a slot. Avoid unbounded `ListView`s inside `Column`s.
|
|
|
- `tool/emulator.sh` starts a headless AVD with the **host GPU**; SwiftShader segfaulted on this machine's API 35 image. Use `CARDASH_GPU=swiftshader_indirect` only as a fallback. Use `adb exec-out screencap -p` for screenshots; there may be multiple `adb` binaries on PATH, so use the absolute one.
|
|
- `tool/emulator.sh` starts a headless AVD with the **host GPU**; SwiftShader segfaulted on this machine's API 35 image. Use `CARDASH_GPU=swiftshader_indirect` only as a fallback. Use `adb exec-out screencap -p` for screenshots; there may be multiple `adb` binaries on PATH, so use the absolute one.
|
|
|
- While CarDash is foreground, `MainActivity` consumes hardware volume keys and adjusts `STREAM_MUSIC` so they match the dashboard, unless `AudioManager.isVolumeFixed` is true; on fixed-volume car units the keys pass through to the vehicle amplifier and the on-screen slider is disabled with an explanation. `SystemBridge.setVolume` falls back to relative `adjustStreamVolume` steps when a unit ignores absolute `setStreamVolume`, then to a `FLAG_SHOW_UI` write that may reach the vendor's own volume panel. Long-pressing **Media volume** toggles `SystemController.volumeDiagnostics`, which shows the raw `index/max`/`min`, fixed flag, control source, vendor state, all stream levels and the last write result; the native side logs the same data under `CarDashVolume`. Do not remove this path without providing another sync path; otherwise Android controls the ring stream when no media is playing.
|
|
- While CarDash is foreground, `MainActivity` consumes hardware volume keys and adjusts `STREAM_MUSIC` so they match the dashboard, unless `AudioManager.isVolumeFixed` is true; on fixed-volume car units the keys pass through to the vehicle amplifier and the on-screen slider is disabled with an explanation. `SystemBridge.setVolume` falls back to relative `adjustStreamVolume` steps when a unit ignores absolute `setStreamVolume`, then to a `FLAG_SHOW_UI` write that may reach the vendor's own volume panel. Long-pressing **Media volume** toggles `SystemController.volumeDiagnostics`, which shows the raw `index/max`/`min`, fixed flag, control source, vendor state, all stream levels and the last write result; the native side logs the same data under `CarDashVolume`. Do not remove this path without providing another sync path; otherwise Android controls the ring stream when no media is playing.
|
|
|
-- FYT/Syu head units (Joying, Junsun, Teyes, Atoto and similar Chinese firmware) own the amplifier in the MCU, so the Android media stream is not what the driver hears. `SyuVolumeBridge` binds `com.syu.ms` (`app.ToolkitService`, action `com.syu.ms.toolkit`), fetches module 4 (`getRemoteModule`, transaction 1) and sends `cmd(0, [level])` for the absolute master volume (command 0 = `FinalSound.C_VOL`, range 0–36); it also subscribes to update 2 (level) and 3 (mute), so knob changes and slider changes stay in sync. `SystemBridge.readVolume` reports `source = syu` while that bridge is connected. `MainActivity`'s hardware-key path is unchanged: the car's own knob and steering-wheel volume are handled by the MCU, not by injecting extra steps. No permission, root or manifest change is needed; if the package, service or module is missing the bridge stays disconnected and the `AudioManager` path is used. Never make the vendor bind a hard dependency, and never let a failed binder call crash the app.
|
|
|
|
|
|
|
+- FYT/Syu head units (Joying, Junsun, Teyes, Atoto and similar Chinese firmware) own the amplifier in the MCU, so the Android media stream is not what the driver hears. `SyuVolumeBridge` binds `com.syu.ms` (`app.ToolkitService`, action `com.syu.ms.toolkit`), fetches module 4 (`getRemoteModule`, transaction 1) and sends `cmd(0, [level])` for the absolute master volume (command 0 = `FinalSound.C_VOL`, range 0–36); it also subscribes to update 2 (level) and 3 (mute), so knob changes and slider changes stay in sync. `SystemBridge.readVolume` reports `source = syu` while that bridge is connected. This path is verified on a real Android 13 FYT/Syu unit: the on-screen slider and the car's own volume control agree. `MainActivity`'s hardware-key path is unchanged: the car's own knob and steering-wheel volume are handled by the MCU, not by injecting extra steps. No permission, root or manifest change is needed; if the package, service or module is missing the bridge stays disconnected and the `AudioManager` path is used. Never make the vendor bind a hard dependency, and never let a failed binder call crash the app.
|
|
|
- A write that the car does not confirm must not snap the slider back to the old value: `SystemController` keeps the requested level for a 1.6 s settle window, then marks it unconfirmed (the card shows `25%?`) until the read changes. Do not restore the old immediate read-back revert; that is the "it always goes back" bug on units whose read does not follow writes.
|
|
- A write that the car does not confirm must not snap the slider back to the old value: `SystemController` keeps the requested level for a 1.6 s settle window, then marks it unconfirmed (the card shows `25%?`) until the read changes. Do not restore the old immediate read-back revert; that is the "it always goes back" bug on units whose read does not follow writes.
|
|
|
- `FLAG_KEEP_SCREEN_ON` is controlled by `DisplayController` from `display.keepScreenOn` (default on) through `SystemBridge`; do not hard-code it in `MainActivity` or move it to a wake lock.
|
|
- `FLAG_KEEP_SCREEN_ON` is controlled by `DisplayController` from `display.keepScreenOn` (default on) through `SystemBridge`; do not hard-code it in `MainActivity` or move it to a wake lock.
|
|
|
- The Music and Jellyfin equalizers are exclusive. The Jellyfin tile animates only while `JellyfinPlaybackController.playing`; the Music tile animates only when the system reports media playing, Jellyfin is not playing, and the active system session is not CarDash itself (`system.media.packageName != appPackageName`). The package guard prevents the Music tile flashing while a Jellyfin pause propagates through the 900 ms system poll. Jellyfin title/progress come from the native playback controller even without notification access; other apps use the notification-listener component and active MediaSession. Never read or store notification content.
|
|
- The Music and Jellyfin equalizers are exclusive. The Jellyfin tile animates only while `JellyfinPlaybackController.playing`; the Music tile animates only when the system reports media playing, Jellyfin is not playing, and the active system session is not CarDash itself (`system.media.packageName != appPackageName`). The package guard prevents the Music tile flashing while a Jellyfin pause propagates through the 900 ms system poll. Jellyfin title/progress come from the native playback controller even without notification access; other apps use the notification-listener component and active MediaSession. Never read or store notification content.
|