Skip to content
View in the app

A better way to browse. Learn more.

Firmware, Software & Manuals for BYD Owners

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

DashCast — BYD Cluster Launcher & Mirror

DashCast — BYD Cluster Launcher & Mirror

Android application for BYD vehicles with DiLink 3.0 (Android 10) to push any installed app onto the instrument cluster display, control it via a real-time touch mirror, and diagnose BYD APIs.

изображение.png

Links:

Apk's:

Version

Link

v1.3.25-beta

Details

v1.3.24-beta

Details

v1.3.23-beta

Details

v1.3.22-beta

Details

v1.3.21-beta

Details

v1.3.20-beta

Details

v1.3.19-beta

Details

v1.3.18-beta

Details

v1.3.17-beta

Details

v1.3.16-beta

Details

v1.3.15-beta

Details

v1.3.14-beta

Details

v1.3.13-beta

Details

v1.3.12-beta

Details

v1.3.11-beta

Details

v1.3.10-beta

Details

v1.3.9-beta

Details

v1.3.8-beta

Details

v1.3.7-beta

Details

v1.3.6-beta

Details

v1.3.5-beta

Details

v1.3.4

Details

v1.3.3

Details

v1.3.3-beta

Details

v1.3.2

Details

v1.3.1

Details

v1.3.0

Details

v1.2.82-beta

Details

v1.2.81-beta

Details

v1.2.80-beta

Details

v1.2.79-beta

Details

v1.2.78-beta

Details

v1.2.77-beta

Details

v1.2.76-beta

Details

v1.2.75-beta

Details

v1.2.74-beta

Details

v1.2.73-beta

Details

v1.2.72-beta

Details

v1.2.71-beta

Details

v1.2.70-beta

Details

v1.2.69-beta

Details

v1.2.68-beta

Details

v1.2.67-beta

Details

v1.2.66-beta

Details

v1.2.65-beta

Details

v1.2.64-beta

Details

v1.2.63-beta

Details

v1.2.62-beta

Details

v1.2.61-beta

Details

v1.2.60-beta

Details

v1.2.58-beta-phase-A-step1

Details

v1.2.57-beta

Details

v1.2.56-beta

Details

v1.2.55-beta

Details

v1.2.54-beta

Details

v1.2.51-beta

Details

v1.2.49-beta

Details

v1.2.48-beta

Details

v1.2.47-beta

Details

v1.2.46-beta

Details

v1.2.45-beta

Details

v1.2.44-beta

Details

v1.2.43-beta

Details

v1.2.42-beta

Details

v1.2.40-beta

Details

v1.2.39-beta

Details

v1.2.38-beta

Details

v1.2.37-beta

Details

v1.2.36-beta

Details

v1.2.35-beta

Details

v1.2.34-beta

Details

v1.2.33-beta

Details

v1.2.32-beta

Details

v1.2.31-beta

Details

v1.2.28

Details

v1.2.27

Details

v1.2.26

Details

v1.2.25

Details

v1.2.24

Details

v1.2.23

Details

v1.2.22

Details

v1.2.21

Details

v1.2.20

Details

v1.2.19

Details

v1.2.18

Details

v1.2.17

Details

v1.2.16

Details

v1.2.15

Details

v1.2.14

Details

v1.2.13

Details

v1.2.12

Details

v1.2.11

Details

v1.2.10

Details

v1.2.9

Details

v1.2.8

Details

v1.2.7

Details

v1.2.6

Details

v1.2.5

Details

v1.2.4

Details

v1.2.3

Details

v1.2.2

Details

v1.2.1

Details

v1.2.0-build186

Details

v1.2.0-build185

Details

v1.2.0-build184

Details

v1.2.0-build183

Details

v1.2.0-build182

Details

v1.1.9-build180

Details

v1.1.9-build179

Details

v1.1.9-build178

Details

v1.1.9-build177

Details

v1.1.9-build176

Details

v1.1.9-build175

Details

v1.1.9-build174

Details

v1.1.9-build173

Details

v1.1.9-build172

Details

v1.1.9-build171

Details

v1.1.9-build170

Details

v1.1.9-build169

Details

v1.1.8

Details

v1.1.7

Details

v1.1.6

Details

v1.1.5

Details

v1.1.4

Details

v1.1.3

Details

v1.1.2

Details

v1.1.1

Details

v1.1.0-beta1

Details

v1.0.1

Details

v1.0.0

Details

v0.9.94

Details

v0.9.0

Details

v0.8.7

Details

v0.8.6

Details

v0.8.5

Details

v0.8.2

Details

v0.8.1

Details

v0.8.0

Details

v0.6.8-beta

Details

0.5.1

Details

v0.5.0-beta

Details

v0.2.1

Details

v0.2.0-beta

Details

  • Replies 143
  • Views 360
  • Created
  • Last Reply

Top Posters In This Topic

Posted Images

Featured Replies

  • Author

DashCast v1.2.67-beta


🚑 HOTFIX #3 — abandons PID-file detection for the bulletproof ps heuristic

Symptoms in v1.2.66: still ALREADY_BOOTSTRAPPING everywhere.

Root cause: every iteration of the PID-file fast-path had a
different subtle failure mode (PID file missing, /proc/comm = 'main',
toybox grep -a unreliable). Field logs from v1.2.66 confirm the fast-
path STILL never matched.

Fix

Drop the PID-file dependency entirely. Use EXACTLY the same heuristic
as the stale-kill (proven in production since 1.1.5):

ps -A | grep '[d]ashcast_proxy' | awk '{print $2}'

If any live daemon is found — INCLUDING the v1.2.63/64/65/66 ones
still stuck in the field with the FD-9 lock leak — we just touch the
trigger file. The FileObserver introduced in v1.2.63 lives in ALL
those daemons and will re-emit the binder broadcast.

Result

  • Recovery works without rebooting the tablet (the new fast-path
    reaches the stuck old daemons through the trigger file).
  • Same heuristic as stale-kill → the two identity checks can no
    longer disagree.
  • PID file is still written (useful for diagnostics) but no longer
    required.

Install v1.2.67 over v1.2.66 — should fix the issue immediately, no
reboot needed.

Links

APK download

GitHub release page

  • Author

DashCast v1.2.68-beta


🚑 HOTFIX #4 — TRUE root cause: flock is not on DiLink 3

After 4 iterations chasing increasingly subtle PID-file detection bugs,
the real culprit was much simpler: the flock binary doesn't exist on
DiLink 3
. It's part of util-linux, not toybox.

What was happening

if ! flock -n 9 2>/dev/null; then echo ALREADY_BOOTSTRAPPING; exit 0; fi

When flock is missing, the command returns 127 (not-found), so ! flock
is TRUE on EVERY call. Result:

  • Every bootstrap immediately returned ALREADY_BOOTSTRAPPING
  • The daemon was NEVER actually spawned since v1.2.63
  • The ps-based fast-path (v1.2.67) couldn't match either — no daemon to find
  • App stuck forever in a 15s broadcast-timeout loop

This single bug invalidated v1.2.63, v1.2.64, v1.2.65, v1.2.66 AND v1.2.67.

Fix

Gate the flock on its availability:

HAS_FLOCK=0; command -v flock >/dev/null 2>&1 && HAS_FLOCK=1
if [ "$HAS_FLOCK" = "1" ]; then exec 9>...; flock -n 9 || exit; fi

When flock is missing, just skip the lock. The stale-kill below already
prevents duplicate daemons, so losing the bootstrap-level lock is
acceptable degradation.

Bonus: diagnostics

  • ALREADY_BOOTSTRAPPING now includes the ps output (e.g.
    ALREADY_BOOTSTRAPPING ps=u0_a142 1234 ...)
  • A [diag] no_alive ps_lines=N has_flock=0|1 line is emitted on stderr

Install

Install v1.2.68 over v1.2.67 — should fix the issue immediately, no
reboot needed
. The ps fast-path will pick up any v1.2.63+ stuck daemon
through the trigger file.

Links

APK download

GitHub release page

  • Author

DashCast v1.2.69-beta


🚑 HOTFIX #5 — drop the flock entirely

v1.2.68 field logs confirm ALREADY_BOOTSTRAPPING ps= is still
returned with an empty ps output, even with the command -v flock
guard. So either:

  • flock is present but mis-behaves on DiLink 3 (returns non-zero
    even with no other holder)
  • exec 9>file silently fails (perms? mksh quirk?)

After 6 hotfixes chasing this lock, just drop it.

Race protection without flock

Already covered three ways:

  1. 10s RECONNECT_COOLDOWN_MS in attemptReconnect — app side, no shell needed
  2. Stale-kill below — kills any duplicate before spawning
  3. ps fast-path above — short-circuits when a daemon is already alive

Worst case: two near-simultaneous cold bootstraps spawn two daemons; the
second one's stale-kill kills the first; only one survives. Acceptable.

Install

Install v1.2.69 over v1.2.68. No reboot needed — the daemon will finally
actually spawn this time.

Links

APK download

GitHub release page

  • Author

DashCast v1.2.70-beta


✨ Phase A Step 4 — Layer 3: daemon hardening

First defence layer towards 100% availability. All daemon-side,
zero UX impact.

New

  1. OOM protection — the daemon writes -900 to
    /proc/self/oom_score_adj at startup. The Linux Low-Memory Killer
    will go after foreground apps before us.
  2. Atomic PID lock in JVM — replaces the broken flock shell
    cascade (v1.2.63→v1.2.69). At startup, reads dashcast_proxy.pid,
    checks that the PID is alive AND that its /proc/PID/cmdline
    contains dashcast_proxy. If yes → refuses to start (the canonical
    one keeps the field). Fail-open on I/O error.
  3. Self-heal heartbeat 10 s — daemon thread that:
    • recreates the trigger file if deleted
    • rearms the FileObserver (loses its inode binding on delete)
    • self-terminates if another daemon stole the lock (canonical survivor)

Compatibility

PROTOCOL_VERSION 7→8 (additive). Old clients keep working.

Next steps

  • v1.2.71 → permanent ForegroundService (Layer 2)
  • v1.2.72 → BOOT_COMPLETED + proactive spawn (Layer 1)
  • v1.2.73 → UX recovery + metrics (Layer 4)

Links

APK download

GitHub release page

  • Author

DashCast v1.2.71-beta


DL5 Fission test — F12E probe (AdbLocalClient only)

Field-driven follow-up to v1.2.60. The DL5 user-run log
log/byd_report_20260528_172327.log confirmed that the 3 hypotheses tested
in v1.2.60 (F12A/F12B/F12C) are all dead on this ROM, but F12A's verb
inventory revealed cmd activity task resizeable <TASK_ID> [0|1|2|3] is
still present in the binary — a fresh, never-tried avenue.

Why DIAG stays 100% on AdbLocalClient

The whole DL5 Fission battery (F01..F16) runs through AdbLocalClient
only — never the daemon. An earlier draft added an F12D that called
BetaProxyClient.moveAndResize (daemon-side AIDL reflection); it was
removed before shipping because the daemon path is reserved for production
runtime, not the in-app diagnostic surface. If the reflection path needs
validation it will be probed from production code under a feature flag,
not from DIAG.

What's new

  • F12E — shell task resizeable 2 then retry resize. Sets the task's
    resizeable mode to 2 (resizeable) via the still-present
    cmd activity task resizeable <taskId> 2, sleeps 1 s, retries
    cmd activity task resize <taskId> 100 80 1820 640, sleeps 2 s,
    dumpsys the bounds. Hypothesis: F11's silent no-op is caused by the
    task being in resizeable mode 0 at runtime.

Strictly additive

F01..F12C + F13..F16 are byte-identical to v1.2.60-beta. SKIP outside DL5.
No production runtime change.

Asset

DashCast-v1.2.71-beta-debug.apk (signed bydPlatform).

Links

APK download

GitHub release page

  • Author

DashCast v1.2.72-beta


DL5 Fission resize battery — refocused

7 scattered probes collapsed into 3 focused shots, with a novel "resize the
STACK, not the task" avenue that has never been tried on DL5 before.

Why refocus

Field reports v1.2.59 / v1.2.60 / v1.2.61 proved the per-verb exploration
approach had exhausted the obvious shell surface without finding a working
path:

  • set-task-windowing-mode → stripped on DL5
  • cmd activity task resize → silent no-op (exit=0, bounds unchanged)
  • cmd window set-display-windowing-mode → stripped
  • am start --activity-launch-bounds → unknown option

Rather than add a 13th nano-probe we collapse the F10..F12E block into 3
sharp probes that go straight at the remaining hole.

The 3 new probes (all via AdbLocalClient — DIAG rule)

  • F10 — Topology. Captures taskId of the target app, the stackId
    hosting it (parsed from dumpsys activity activities), current mBounds

    • mWindowingMode, plus a compact inventory of resize-relevant verbs
      (cmd activity stack, cmd activity task, am stack, wm).
  • F11 — DL3 chain via shell. One atomic shell script:

    1. cmd activity task resizeable <taskId> 2 (unlock)
    2. Try every stack-resize verb (the novel part):
      • am stack resize <stackId> 100 80 1820 640
      • cmd activity stack resize <stackId> 100 80 1820 640
      • cmd window stack resize <stackId> 100 80 1820 640
    3. Retry cmd activity task resize <taskId> 100 80 1820 640
    4. Dumpsys diff. Reports which verbs were accepted (accepted verbs: …).
  • F12 — Verify final bounds. Confirms whether the rect stuck.

Why this might finally work

All prior probes targeted IActivityTaskManager.resizeTask(taskId, …)
the shell verb for which (cmd activity task resize) is silent no-op on
DL5. The DL3 production code path actually calls
IActivityTaskManager.resizeStack(stackId, Rect) — a different AIDL
method on a different object. The shell verb for resizeStack has never
been tried on DL5. If any of the 3 variants in F11 step 2 is honoured,
we have a real shell resize path.

Strictly additive

F01..F09 + F13..F16 are byte-identical to v1.2.60-beta. SKIP outside DL5.
No production runtime change. Net: 20 → 16 probes.

Asset

DashCast-v1.2.72-beta-debug.apk (signed bydPlatform).

Links

APK download

GitHub release page

  • Author

DashCast v1.2.73-beta


✨ Phase A Step 4 — Layer 2: ProxyKeeperService 24/7

Permanent daemon watchdog, even when the app is closed.

What it brings

  • Foreground service with a heartbeat every 10 s on the daemon's binder
  • If binder dies → immediate proactive reconnect (10 s cooldown still honoured)
  • START_STICKY → Android restarts the service after an OOM kill
  • Persistent low-importance notification, no sound, no vibration (mandatory for an FG service)
  • Tap notification → opens MainActivity

Combined with Layer 3 (v1.2.70)

Layer Role Status
3 — Daemon hardening OOM -900, PID lock JVM, self-heal ✅ v1.2.70
2 — Keeper FG 24/7 Permanent 10 s watch ✅ v1.2.73
1 — Proactive triggers BOOT_COMPLETED, PACKAGE_REPLACED ⏭ v1.2.74
4 — UX recovery ADB notif, diag metrics ⏭ v1.2.75

New strings (12 locales)

proxy_keeper_channel_name, proxy_keeper_channel_desc,
proxy_keeper_notif_title, proxy_keeper_notif_text

Prerequisite

Gated on BetaConfig.isProxyDaemonEnabled — if you've never enabled
the daemon in Settings, no service and no notification ever start.

Installation

Install v1.2.73 on top of v1.2.72. A persistent "DashCast — proxy
active" notification will appear in the bar. That's normal and
mandatory (Android requires a notification for FG services).

Links

APK download

GitHub release page

  • Author

DashCast v1.2.74-beta


🐛 Fix — "Cluster mirror active" stays after stop

Symptom

A persistent DashCast — Cluster mirror active notification stayed
in the Android shade even when cluster projection was stopped and the
floating 📺 badge was invisible.

Cause

FloatingRemoteButton.hide() only hid the overlay view but never
demoted the service from its foreground state → the notification
stayed glued for as long as the DashCast process was alive.

Fix

  • hide()stopForeground(STOP_FOREGROUND_REMOVE): notif removed
  • show()startForeground() re-promotion with the same notif
  • startForegroundCompat() at startup: if no active projection
    (sShouldBeVisible == false), drop FG immediately → no ghost notif
    on app launch

Compatibility

None broken. The notification reappears automatically as soon as an
app is projected on the cluster.

Note

The persistent DashCast — proxy active notification (Layer 2,
v1.2.73) stays visible 24/7 when the proxy daemon is enabled — that's
normal and mandatory (Android requires a notification for an FG service).

Links

APK download

GitHub release page

  • Author

DashCast v1.2.75-beta


✨ Phase A Step 4 — Layer 1: proactive triggers (BOOT + OTA)

What it brings

The daemon and the KeeperService are woken up before the user
opens DashCast.

Trigger When Before Now
BOOT_COMPLETED Tablet power-on pre-warm daemon + ProxyKeeperService.ensureRunning()
MY_PACKAGE_REPLACED DashCast OTA install nothing full revive (daemon + Keeper)

Why MY_PACKAGE_REPLACED

Without this intent, after a DashCast update the daemon stayed dead
until you manually opened the app. Now Android fires the intent as
soon as the OTA install finishes, the receiver brings the whole
proxy stack back up automatically.

Defence-in-depth recap

Layer Role Status
3 — Daemon hardening OOM -900, PID lock JVM, self-heal ✅ v1.2.70
2 — KeeperService FG 24/7 Permanent 10 s watch ✅ v1.2.73
1 — Proactive triggers BOOT_COMPLETED, MY_PACKAGE_REPLACED ✅ v1.2.75
4 — UX recovery Adaptive cooldown, ADB notif, metrics ⏭ v1.2.76

Compatibility

None broken. Everything is gated on BetaConfig.isProxyDaemonEnabled
zero overhead if you haven't enabled the proxy daemon.

Test

Uninstall then reinstall DashCast on top, or wait for an OTA: the
daemon must be reachable immediately, without opening the app.

Links

APK download

GitHub release page

  • Author

DashCast v1.2.76-beta


✨ Reboot button in System panel

No need to hold the volume button for 10 s anymore to reboot the
tablet: a Reboot button now appears in the top bar of the
System panel, next to Regenerate.

Behaviour

  1. Tap → confirmation dialog ("All running apps will be closed")
  2. Confirm → reboot dispatched via local ADB (shell uid is whitelisted on DiLink)
  3. Toast "Rebooting…", then a clean Android shutdown

Why a dialog

A reboot kills the entire car session (HMI, GPS, audio…). We don't
want an accidental tap to trigger it.

i18n

6 new strings added across all 12 locales (fr+en+de+es+it+ru+uk+be+kk+uz+tr+ar).

Links

APK download

GitHub release page

  • Author

DashCast v1.2.77-beta


🐛 Fix — Ghost "Cluster: stopped" notification

Symptom

After stopping cluster projection, a persistent
DashCast — Cluster: stopped notification remained stuck in the
shade, impossible to swipe away.

Cause

ClusterService.stopProjectionNoAdb() was re-posting a
setOngoing(true) notification via NotificationManager.notify() just
before stopSelf(). Since that notification was no longer attached to
the service's foreground token (just posted via NM), it outlived the
service destruction and stayed non-dismissible forever.

Fix

On stop:

  1. stopForeground(STOP_FOREGROUND_REMOVE) → drops the FG notif
  2. NotificationManager.cancel(NOTIF_ID) → explicit cancel, belt + braces
  3. stopSelf()

No notification = nothing to dismiss.

Links

APK download

GitHub release page

  • Author

DashCast v1.2.78-beta


✨ Phase A close — Layer 4: adaptive cooldown + metrics

Closes the defence-in-depth (4/4 layers).

Adaptive cooldown (1 s → 2 s → 4 s → 8 s → 10 s)

Before: flat 10 s between reconnect attempts → KeeperService reacted
slowly when the daemon died. Now: first retry in ≤1 s, ramps up only
if failures accumulate. Resets to 0 as soon as a connect succeeds.

ERR_NO_APK fast-path

The PackageManager has a sub-second race window right after an OTA
during which it hasn't yet indexed our APK. When the bootstrap script
reports ERR_NO_APK, we bypass the cooldown → immediate retry on the
next attempt. No more "10 s of pointless waiting" right after an update.

Persistent metrics (BetaProxyMetrics)

6 counters stored in SharedPreferences (survive OOM kills):

Metric Meaning
cold_spawns Daemon spawned via app_process64 (heavy path ~2 s)
rebroadcasts Fast-path REBROADCAST (daemon already alive, ~3 ms)
fails_no_apk PM race post-OTA (recovered on next retry)
fails_timeout Bootstrap OK but no broadcast within 6 s
fails_other ADB transport error (ADB off, dex2oat, SELinux…)
binder_zombies Cached binder dead, cleared by DeathRecipient

Visible in the System report under "9. BETA PROXY METRICS" — useful
to spot long-term drift without scraping logs.

Phase A final recap

Layer Role Status
3 — Daemon hardening OOM -900, PID lock, self-heal ✅ v1.2.70
2 — KeeperService FG 24/7 Permanent 10 s watch ✅ v1.2.73
1 — Proactive triggers BOOT_COMPLETED, MY_PACKAGE_REPLACED ✅ v1.2.75
4 — UX recovery Adaptive cooldown + metrics ✅ v1.2.78

Next step

v1.2.79 / Phase C: flip DEFAULT_USE_PROXY_DAEMON=true after Phase A
field validation → the proxy daemon becomes the default path for all
new installs.

Links

APK download

GitHub release page

  • Author

DashCast v1.2.79-beta


🚀 Phase C — Flip default to proxy daemon

DEFAULT_USE_PROXY_DAEMON : falsetrue

Why now

Phase A (layers 1→4) locked down 24/7 daemon availability:

  • Layer 1 (v1.2.75) — BOOT_COMPLETED + MY_PACKAGE_REPLACED triggers
  • Layer 2 (v1.2.73) — ProxyKeeperService foreground 24/7
  • Layer 3 (v1.2.70) — daemon hardening (oom_score -900, PID lock, self-heal)
  • Layer 4 (v1.2.78) — adaptive cooldown + persistent metrics

The daemon is now the nominal path for every ADB operation.

User impact

Profile Behaviour
Fresh install ✅ Auto-switches to the proxy daemon
Existing install that never touched the Beta Engine toggle ✅ Auto-switch
Existing install that already toggled it 🔒 Choice preserved (SharedPreferences)

Safety net

BetaEngineGateway keeps the transparent fallback: any failure on the
proxy path falls back automatically to legacy AdbLocalClient. No UX
regression possible — worst case, legacy ADB latency.

How to verify the switch

System → "Generate report" → section "9. BETA PROXY METRICS":

  • cold_spawns or rebroadcasts climbing on each ADB action ⇒ proxy active
  • If only fails_* climb ⇒ legacy fallback in use

Next step

If everything stays stable for a week in the field → merge
phase-A-proxy-recovery into main + tag stable v1.3.0.

Links

APK download

GitHub release page

  • Author

DashCast v1.2.80-beta


🎤 Wake-word diag — see if "Hey Jarvis" reacts

Field problem

You shout "Hey Jarvis" → nothing happens → you assume it's broken.
In reality the model was probably scoring between 0.01 and 0.10 — i.e.
1% to 10% of the bar, invisible to the eye. The detection threshold
was at 0.5, basically unreachable in a car cabin.

Changes

  • Threshold 0.5 → 0.3 — the bar now trips at 30% (still well above
    HVAC/engine ambient noise according to the openWakeWord ROC).
  • Live score shown in plain text under the bar:
    score=0.034 · peak30s=0.087 (12s ago) · threshold=0.30
    → you can immediately tell whether the model reacts, even without
    crossing the threshold.
  • Auto log every 5 s in the Logs tab:
    WakeWordEngine: diag: score=0.087 max5s=0.142 peak30s=0.213 thr=0.30
    → diagnosable after the fact without watching Diag live.

How to test

  1. Diag → Voice tab → enable "Wake word" (auto-starts listening)
  2. Shout "HEY JARVIS" in English pronunciation ("hey djahr-viss")
  3. Watch the triple score=... · peak30s=... · threshold=0.30
    • If peak30s climbs to 0.20+ → the model perceives you, only the
      pronunciation needs tweaking
    • If peak30s stays at 0.0X → mic is OK but the model is deaf to
      your voice
    • If peak30s hits 0.30 → BEEP, detection confirmed
  4. Logs tab → filter "WakeWordEngine" to see the rolling 5 s history

Note

The hey_jarvis_v0.1 model is trained exclusively on US/UK English
voices. A French pronunciation ("hé jar-vis") scores 3-10× lower.
It's the placeholder until the custom "Ok DashCast" wake-word is
trained (Voice Phase 3, coming).

Links

APK download

GitHub release page

  • Author

DashCast v1.2.81-beta


Per-app DPI override on the cluster display

Long-pressing any app in the launcher now exposes a "Display density" row
in the bottom-sheet menu. Pick System default, one of the presets
(120 / 160 / 200 / 240 / 280 / 320 dpi) or Custom (96–480 dpi). The
override is stored persistently and applied automatically:

  • Before each launch on the cluster (wm density N -d <clusterDisplayId>)
  • Restored when projection is stopped (wm density reset)
  • Restored again on service destruction as a safety net

Useful for apps whose UI is sized for phones/tablets and ends up cropped
or oversized on the 1920×720 cluster (Waze map half-visible, Netflix
controls cut off, dashboard widgets too small, etc.).

Display 0 (head unit) — protected at three layers

This feature NEVER touches the main screen. The current density of
display 0 is left exactly as the ROM sets it. Three independent guards:

  1. ClusterDpiManager exits immediately when displayId <= 0
  2. ShellGateway.WM_DISPLAY_ZERO regex blocks any wm density … -d 0
    even via the proxy daemon
  3. AdbLocalClient.blockDiLink2Resize blocks all wm verbs when no
    cluster is present (DiLink 2 case)

Safety / no regression

  • Every DPI hook is wrapped in try/catch → a tweak never blocks the
    launch nor the stop sequence
  • Per-display cache: no-op shell call when the requested density is
    already in effect
  • 150 ms settle delay only when the density actually changes, before
    am start
  • Override editor is always visible — you can pre-configure a density
    before the first launch
  • onDestroy safety net: density is reset even if stopProjectionNoAdb
    was bypassed (e.g. process killed)

Diagnostics

A new "10. CLUSTER DPI OVERRIDES" section is added to the SysInfo
report, listing every configured package and the density currently
applied per display.

i18n

7 new user-facing strings, fully translated to all 12 supported locales
(fr, en, de, es, it, ru, uk, be, kk, uz, tr, ar).


APK: DashCast-v1.2.81-beta-debug.apk (46.5 MB)
Build: debug · signed with bydPlatform key

Links

APK download

GitHub release page

  • Author

DashCast v1.2.82-beta


Live preview — fixes & comfort

Bug fix — black preview after launching an app

Tapping an app to send it to the cluster left the local preview pane
stuck on a black frame. The only known workarounds were to open the
fullscreen mirror, or to go to the Android home screen and come back.

Root cause: startClusterMirror() was calling
attemptStartMirrorWithCurrentHolder() directly, which short-circuits
on isMirrorActive() == true. The previously-created SurfaceControl
token was still bound to the old cluster displayId / layerStack
(typically -1 or a stale value captured before activation), so frames
were composited onto the wrong layer stack → black surface.

Fix: apply the same stop + delayed surface rebind recipe already used
by enterFullscreenMirror() and exitFullscreenMirror(). The mirror
token is now recreated against the freshly-resolved cluster display on
every launch.

Enlarged compact preview (200dp → 320dp)

Cluster aspect ratio is 1920×720 ≈ 2.67:1, so the previous 200dp height
made the preview tiny and unreadable in the right pane. Bumped to
320dp (+60%): the preview is now actually usable for monitoring an
app on the cluster without entering fullscreen.

Notes

  • No display-0 (head unit) impact
  • No change to fullscreen / restart / lifecycle paths
  • 250 ms rebind delay covers am start latency on the cluster
  • Fallback path preserved if the SurfaceTexture is not yet ready at
    rebind time

APK: DashCast-v1.2.82-beta-debug.apk (46.5 MB)
Build: debug · signed with bydPlatform key

Links

APK download

GitHub release page

  • Author

DashCast v1.3.0


v1.3.0 — Stable release

First stable release of the Phase A line. Merges the full
phase-A-proxy-recovery branch (v1.2.61-beta → v1.2.83-beta) into
main after several weeks of in-car validation.

Highlights

🛡 Phase A — 24/7 daemon availability (4 layers)

The DashCast proxy daemon is now the default ADB path and is hardened
against every failure mode observed in the field.

Layer Role Shipped
Layer 1 — Proactive triggers BOOT_COMPLETED + MY_PACKAGE_REPLACED waking the daemon before the user opens DashCast v1.2.75
Layer 2ProxyKeeperService Foreground service watching the daemon binder every 10 s v1.2.73
Layer 3 — Daemon hardening oom_score_adj = -900, atomic PID lock in JVM, self-heal heartbeat v1.2.70
Layer 4 — UX recovery Adaptive cooldown (1 s → 10 s), ERR_NO_APK fast-path, persistent metrics v1.2.78
Phase C — Default ON DEFAULT_USE_PROXY_DAEMON = true for new installs v1.2.79

Result: ADB-backed operations are now resilient to OOM kills, OTA
updates, tablet reboots and bootstrap storms. Persistent metrics
(cold_spawns, rebroadcasts, fails_*, binder_zombies) are
visible in the System report for long-term drift analysis.

🎛 Cluster DPI overrides (v1.2.81)

Per-app DPI override on the cluster display (96-480 dpi). 3-layer
protection ensures display 0 (main screen) is never touched.

🖥 Live preview UX (v1.2.82, v1.2.83)

  • Fixed the black-preview bug after launching an app (mirror rebind).
  • Preview card enlarged from 200dp to 320dp.
  • Dashboard layout refocused: dashboard title and redundant cluster
    state card removed, apps column slimmed down to ~2-icon width,
    search bar compacted — the live preview now occupies the maximum
    possible width.

🐛 Notable fixes shipped during Phase A

  • HOTFIX flock FD leak (v1.2.65)
  • HOTFIX fast-path /proc/comm vs cmdline (v1.2.66)
  • Ghost "Cluster mirror active" notification (v1.2.74)
  • Ghost "Cluster: stopped" notification (v1.2.77)
  • Wake-word diag visibility (threshold 0.3 + live score, v1.2.80)

✨ Smaller features

  • Reboot button in the System panel (v1.2.76)
  • Daemon log export via Telegram (v1.2.64)
  • Foreground liveness watchdog (v1.2.62)
  • Fast PID-file + flock + trigger-file rebroadcast (v1.2.63)
  • DL5 fission resize stack-level battery (v1.2.72)

Compatibility

  • DiLink 3 (Android 10 / API 29) and DiLink 5 (Android 12 / API 32),
    both validated in-car.
  • Signed with the BYD platform key (mandatory for system permissions).
  • Existing users who never toggled the Beta Engine setting will
    auto-switch to the proxy daemon path.

Install

Install DashCast-v1.3.0-release.apk on top of any v1.2.x build.
No data migration. Notification "DashCast — proxy active" is normal
(mandatory for the foreground service guaranteeing 24/7 daemon
availability).

Links

APK download

GitHub release page

  • Author

DashCast v1.3.1


v1.3.1 — Polish locale + unified nav rail

New language

  • 🇵🇱 Polish (Polski) — full translation, 13th supported locale.

UI polish

  • Unified nav rail across Apps / Settings / Diag / SysInfo / Log / Hotspot.
    No more flash/size differences when switching activities — every screen now uses the same Material You Style A: same icon size, paddings, ripple, active pill and typography.
  • Tighter main layout (carried over from v1.3.1-beta): live preview gets every available pixel, favorites column aligned with the 2-col app grid, top bar and hero card removed.

Asset

  • DashCast-v1.3.1-release.apk — signed with BYD platform key.

versionCode 346 · versionName 1.3.1

Links

APK download

GitHub release page

  • Author

DashCast v1.3.2


Main screen layout — column alignment fix

The Main activity layout has been reworked to match the favorites strip
width and give the live cluster preview every available pixel on the right.

What changed

  • Left apps column locked to 160 dp (= width of 2 × 80 dp favorite tiles).
    The previous behaviour applied layout_weight=1.4 from code, which silently
    overrode the XML's 160dp declaration and let the search bar expand to
    roughly 400 px wide on DL5 — much wider than the favorites strip below it.
  • Apps grid forced to 2 columns so each app icon sits exactly under one
    favorite tile. The columns now line up vertically with the favorites strip:
    the left column (Centre multimédia, DAB+, Spotify …) is flush with the
    first favorite, the right column (Radio, Metrolist, NewPipe …) with the
    second one.
  • Live preview now fills the right pane. The cluster preview card has
    been switched from a fixed 320dp height to 0dp + weight=1 inside a
    match_parent right-pane container. It expands to occupy all the
    horizontal and vertical space freed by the narrower left column.
  • Mirror full / Stop projection buttons stay visible. They are placed
    right under the preview card inside the same vertical container, so
    they remain pinned at the bottom of the right pane regardless of how
    tall the preview is.

Root cause

MainActivity.applyCompactAppsPanelMode() assigned a non-zero layout_weight
to the left section without resetting its width. Android's LinearLayout
then computed a hybrid size that ignored the XML declaration. The fix:
write width = 160dp and weight = 0 explicitly, and pin the grid span
to 2 unconditionally. The "compact apps panel" preference is no longer
needed and is effectively absorbed into the default behaviour.

Compatibility

  • All 13 locales unchanged (no new user-visible strings).
  • Triple-display protection unchanged: display 0 is never touched.
  • BYD-platform signed; installs as an update over any previous 1.3.x.

versionCode 347 / versionName 1.3.2

Links

APK download

GitHub release page

  • Author

DashCast v1.3.3


v1.3.3 — Daemon reliability

Cure for "silent binder deaths" reported by DiLink 3 users on v1.3.x.
After a daemon process died, the app stayed convinced its binder was
alive and never reconnected, so every cluster action failed with
DeadObjectException or SecurityException launchDisplayId=-2 until
the user force-stopped DashCast.

Root cause

On DiLink 3 / Android 10 the kernel sometimes fails to deliver the
binderDied() callback to our DeathRecipient when the daemon
process is killed (LMK or shutdown path). The cached IBinder
reference then returns true from isBinderAlive() indefinitely
while every transact() throws. None of the existing recovery
layers reacted because:

  • BetaProxyClient.isConnected() was a local cache read only.
  • ProxyKeeperService heartbeat polled isConnected() and saw "OK".
  • Direct transact() call-sites (mirror start/stop, input injection)
    caught the exception but did not invalidate the cache.

Fix — defense in depth

  • New BetaProxyClient.invalidateBinder(reason) — public eager
    invalidator. Clears the cached binder, unhooks the (never-fired)
    death recipient, increments a new binder_deaths_silent metric.
  • Direct transact() call-sites now catch DeadObjectException
    explicitly and call invalidateBinder:
    • ClusterMirrorManager.startMirrorViaDaemon / stopMirrorViaDaemon
    • ClusterInputForwarder.injectTouchAt / injectKey / injectKeyEvent
  • ProxyKeeperService heartbeat hardened — uses
    IBinder.pingBinder() (real ~1 ms round-trip) every 10 s instead
    of the lock-free isBinderAlive() (local read). A silent death is
    now converted to a recoverable state within one heartbeat and the
    keeper re-bootstraps the daemon automatically.
  • Metric clarity — the existing binder_zombies counter is now
    displayed as binder_deaths_notif (kernel-notified, the normal
    case) and a new binder_deaths_silent is shown next to it. A
    non-zero silent counter on a user device is now a direct signal of
    the bug having been hit and recovered.

Compatibility

  • No new permissions, no new strings.
  • BYD-platform signed; installs as an update over any 1.3.x.
  • Three-layer display protection unchanged.

versionCode 348 / versionName 1.3.3

Links

APK download

GitHub release page

  • Author

DashCast v1.3.3-beta


DL5 Fission F10/F11 — Android 12 stackId fix

Field-driven fix from log/byd_report_20260529_082457.log: v1.2.72's novel "resize STACK not TASK" probes never actually ran because F10 couldn't extract a stackId (DL5 / Android 12 renamed Stack #rootTaskId), so F11 step 2 logged SKIPPED — no stackId from F10 instead of trying the three new shell verbs.

Fixes

  • F10 topology — grep filter now includes rootTaskId= / rootOfTask= / Task{; calls cmd activity stack help instead of no-arg (which throws); Android-12 fallback sets stackId = taskId when the dump confirms the task is its own root task; verb-inventory flags treat the Argument expected after "stack" exception itself as positive evidence the dispatcher exists.
  • F11 DL3 chain — step 2 (the 3 stack-resize verbs) is now ALWAYS executed; uses st.targetStackId if found, else taskId as fallback (correct on Android 12 for top-level launched tasks). Row detail annotates [fallback=taskId] when applicable.

Asset

DashCast-v1.3.3-beta-debug.apk (signed bydPlatform).

Links

APK download

GitHub release page

  • Author

DashCast v1.3.4


Compatibility fix

DashCast now works seamlessly with third-party launchers (e.g. com.dudu.autoui / DuDu AutoUI) that replace the BYD launcher.

Symptom (before)

  • Every tap on a cluster app triggered a 2 s "fallback launch" instead of the fast moveTaskToDisplay reparent.
  • App felt slower and racier to use, even with v1.3.3's daemon fix installed.

Root cause

Non-stock launchers manage the task stack outside the standard mRecentTasks, so live tasks never appear in dumpsys activity recents — our recents-based lookup always returned -1.

Fix

ClusterService.findRunningTaskId() now has a launcher-agnostic fallback: when the recents lookup returns no match, it re-queries dumpsys activity activities and parses the taskId out of the ActivityRecord{... pkg/class t<N>} line. This works regardless of which launcher manages home.

No behaviour change

Devices using the stock BYD launcher are unaffected — the original recents-based path still matches first.


versionCode 348 → 349 · versionName 1.3.3 → 1.3.4

Links

APK download

GitHub release page

  • Author

DashCast v1.3.5-beta


DL5 — Auto-keyboard on cluster mirror tap

New features

  • DL5 auto-keyboard: tapping an editable field in the cluster mirror now automatically triggers the keyboard bridge after 350ms (detected via AccessibilityService). The ⌨ button remains available as a manual fallback.
  • Prerequisite: ClusterImeWatcherService must be enabled (Settings → Accessibility). On dev device: adb shell settings put secure enabled_accessibility_services com.byd.dashcast/com.byd.dashcast.ime.ClusterImeWatcherService

Fixes

  • F10/F11 Android 12: fixed rootTaskId extraction for Android 12 (SKQ1.230128.001) — grep widened to rootTaskId=|rootOfTask=|Task{, taskId fallback when task is its own root, F11 step 2 always executed.

Architecture (additive — zero regression)

  • ClusterImeWatcherService.checkAndLaunchBridgeIfNeeded(): new static method, work dispatched on existing background thread, same debounce as the event-driven path.
  • MainActivity.forwardTouchFromMirror: ACTION_UP hook → postDelayed 350ms → bridge check.

Links

APK download

GitHub release page

  • Author

DashCast v1.3.6-beta


Pre-release — voice beta line back in sync with main

Brings the voice/beta line up to date with the latest stable fixes.

Includes everything from v1.3.5-beta

  • DL5: clavier auto on cluster mirror tap
  • DL5: F10/F11 fix (Android 12 rootTaskId-aware stack extraction)
  • Wake-word voice PoC

Plus (from main)

  • v1.3.3 — daemon: eager invalidateBinder + real pingBinder heartbeat. Catches silent binder deaths the kernel never notified (DiLink 3 Android 10).
  • v1.3.4 — launcher-agnostic findRunningTaskId fallback via dumpsys activity activities. Fixes the slow "fallback launch" path on devices with third-party launchers (e.g. com.dudu.autoui / DuDu AutoUI).

For DL3 testers who saw the field log warns

You should now see one of:

  • findRunningTaskId ... → taskId=N (via daemon dumpsys activities) — Path 2b working
  • findRunningTaskId ... → taskId=N (via AdbLocal dumpsys activities) — Path 3b working
  • Or a new not found in dumpsys activities warn — please send the log so the regex can be tuned to the API 29 DL3 output.

versionCode 350 → 351 · versionName 1.3.5-beta → 1.3.6-beta

Links

APK download

GitHub release page

  • Author

DashCast v1.3.7-beta


Pre-release — cleanup based on DL3 field log

Reduced log noise (findRunningTaskId)

The four intermediate not found in dumpsys recents/activities lines are part of a normal Path 1 \u2192 2 \u2192 3 cascade — only the final outcome matters. Downgraded all of them from WARN to DEBUG. The single no running task \u2192 fallback launch WARN at the call site stays.

DL3 ROM-strip handling (moveTaskToDisplay)

The BYD DiLink 3 API 29 ROM ships a stripped IActivityTaskManager that no longer exposes moveTaskToDisplay(int, int). v1.3.6-beta logged an ERROR with stack trace on every cluster-app tap.

Now: probe once per process, log a single WARN at first sight (moveTaskToDisplay: IActivityTaskManager.moveTaskToDisplay(int,int) stripped on this ROM — will use launcher fallback from now on), then skip the reflection entirely on subsequent calls and go straight to the launcher fallback (which was already working in practice).

Net effect on DL3 field logs: zero ERROR lines from moveTaskToDisplay, one informational WARN at startup, behaviour unchanged.


versionCode 351 → 352 \u00b7 versionName 1.3.6-beta \u2192 1.3.7-beta

Links

APK download

GitHub release page

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.