mise.toml, the comments in app/build.gradle (corrected where they no longer described the build: the car build is signed by build-car, and the updater reads the version from build-car's file name), OTA.md's message table (now the updater's current English messages), the Turkish messages quoted in CHANGELOG.md and OTA.md (glossed in English), two test assertion messages, an icon comment, and the ignition-state comment in EVHardware.kt. The vendored EVHardware library still has about 120 half-French comment lines; noted in SPECS.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
219 lines
9.0 KiB
TOML
219 lines
9.0 KiB
TOML
# Development environment with mise (the Nix flake, `nix develop`, is the other way in).
|
|
#
|
|
# Committed on purpose: it describes how to build the project, not someone's machine. Paths
|
|
# go through {{env.HOME}} / JAVA_HOME, never hard-coded. For a local override (keystore path,
|
|
# SDK elsewhere), create a mise.local.toml — that one stays ignored by git.
|
|
#
|
|
# mise install installs the JDK
|
|
# mise run bootstrap installs the Android SDK if missing
|
|
# mise run test unit tests
|
|
# mise tasks lists everything
|
|
#
|
|
# Why the JDK is pinned: the machine's default JDK (26) is not supported by AGP and fails the
|
|
# build with an unhelpful class-version error.
|
|
|
|
[tools]
|
|
java = "17"
|
|
|
|
[env]
|
|
ANDROID_HOME = "{{env.HOME}}/Android/Sdk"
|
|
ANDROID_SDK_ROOT = "{{env.HOME}}/Android/Sdk"
|
|
_.path = [
|
|
"{{env.HOME}}/Android/Sdk/platform-tools",
|
|
"{{env.HOME}}/Android/Sdk/cmdline-tools/latest/bin",
|
|
]
|
|
|
|
# SDK version app/build.gradle needs (compileSdk = 36).
|
|
COMPILE_SDK = "36"
|
|
BUILD_TOOLS = "36.0.0"
|
|
|
|
# APK SIGNING secrets — nothing to do with the ABRP API key, which is entered in the app.
|
|
# Set them outside the repository: uncomment in a mise.local.toml (ignored by git) and point
|
|
# at a local keystore, NEVER at a file in the repository. The car build is signed by
|
|
# `build-car` (flake.nix) instead.
|
|
# SIGNING_KEYSTORE = "{{env.HOME}}/.keystores/signing.keystore"
|
|
# SIGNING_STORE_PASSWORD = "…"
|
|
# SIGNING_KEY_ALIAS = "platform"
|
|
# SIGNING_KEY_PASSWORD = "…"
|
|
|
|
# Gradle must run on the JDK mise just installed. Without -Dorg.gradle.java.home, Gradle may
|
|
# reuse a daemon started by another JDK — typically the one bundled with VS Code's Java
|
|
# extension, a JRE 21 without jlink: the build then fails in JdkImageTransform, with a message
|
|
# that has nothing to do with the code. JAVA_HOME is set by [tools] above; $JAVA_HOME is
|
|
# resolved by the shell at run time, so this stays portable between machines.
|
|
# ── Emulator ─────────────────────────────────────────────────────────────────────
|
|
#
|
|
# A WORD on fidelity: the car runs AAOS 9 (API 28). Google publishes NO Automotive system
|
|
# image below API 33 — checked with sdkmanager --list. So no emulator reproduces both the OS
|
|
# and the car API of the MG4. Hence two profiles, each faithful on one axis:
|
|
#
|
|
# emulator-car API 33 Automotive — has a CarPropertyManager, wrong OS version. For the
|
|
# service lifecycle and the car path. SAIC VENDOR properties (0x216xxxxx:
|
|
# SOC, range) do not exist in the emulator: those reads fail, as expected.
|
|
# emulator-screen API 28 tablet — right OS version and right screen (1920x720 @ 160 dpi,
|
|
# 12.8" HD like the MG4), but NO car services. For the UI, layouts and
|
|
# density. (The AOSP API 28 image also shares the car's platform key, so the
|
|
# car build installs there as the system user.)
|
|
#
|
|
# None of this replaces a test on the car.
|
|
# Target density: 160 dpi. Screen 12.8" 1920x720. Reference firmware: SWI68-29958-1300R69.
|
|
|
|
EMU_CAR_AVD = "evabrp-car"
|
|
EMU_CAR_IMAGE = "system-images;android-33;android-automotive;x86_64"
|
|
EMU_SCREEN_AVD = "evabrp-screen"
|
|
EMU_SCREEN_IMAGE = "system-images;android-28;google_apis;x86_64"
|
|
EMU_WIDTH = "1920"
|
|
EMU_HEIGHT = "720"
|
|
EMU_DENSITY = "160"
|
|
|
|
[tasks.bootstrap]
|
|
description = "Installs the Android SDK (platform + build-tools) if missing"
|
|
run = """
|
|
set -e
|
|
if [ -d "$ANDROID_HOME/platforms/android-$COMPILE_SDK" ]; then
|
|
echo "SDK $COMPILE_SDK already present, nothing to do"
|
|
exit 0
|
|
fi
|
|
mkdir -p "$ANDROID_HOME"
|
|
if [ ! -x "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" ]; then
|
|
echo "Downloading the command-line tools…"
|
|
tmp=$(mktemp -d)
|
|
curl -sSL -o "$tmp/tools.zip" \
|
|
https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
|
|
unzip -q "$tmp/tools.zip" -d "$tmp"
|
|
mkdir -p "$ANDROID_HOME/cmdline-tools"
|
|
mv "$tmp/cmdline-tools" "$ANDROID_HOME/cmdline-tools/latest"
|
|
rm -rf "$tmp"
|
|
fi
|
|
yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --sdk_root="$ANDROID_HOME" --licenses > /dev/null
|
|
"$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --sdk_root="$ANDROID_HOME" \
|
|
"platform-tools" "platforms;android-$COMPILE_SDK" "build-tools;$BUILD_TOOLS"
|
|
echo "sdk.dir=$ANDROID_HOME" > local.properties
|
|
echo "SDK installed, local.properties written"
|
|
"""
|
|
|
|
[tasks.build]
|
|
description = "Builds the debug APK"
|
|
run = './gradlew -Dorg.gradle.java.home=$JAVA_HOME assembleStableDebug'
|
|
|
|
[tasks.test]
|
|
description = "JVM unit tests"
|
|
run = './gradlew -Dorg.gradle.java.home=$JAVA_HOME testStableDebugUnitTest testUnstableDebugUnitTest'
|
|
|
|
[tasks.lint]
|
|
description = "Android lint"
|
|
run = './gradlew -Dorg.gradle.java.home=$JAVA_HOME lintStableDebug lintUnstableDebug'
|
|
|
|
[tasks.permissions]
|
|
description = "Permission drift check (the same as CI)"
|
|
run = "bash .github/security/check-permissions.sh"
|
|
|
|
[tasks.check]
|
|
description = "What CI runs: permissions + lint + tests"
|
|
depends = ["permissions", "lint", "test"]
|
|
|
|
[tasks.install]
|
|
description = "Installs the debug APK on the car connected over ADB"
|
|
run = './gradlew -Dorg.gradle.java.home=$JAVA_HOME installStableDebug'
|
|
|
|
[tasks.logs]
|
|
description = "Follows the app's logs on the car"
|
|
run = "adb logcat -s AbrpUploadService:V CarPropertyAdapter:V VhalProbe:V SecurePrefs:V OtaUpdater:V UpdateHook:V NilsMG4.Telemetry:V NilsMG4.Mongo:V NilsMG4.SteeringKey:V EVABRP.Boot:V EVABRP.Wifi:V"
|
|
|
|
[tasks.release]
|
|
description = "Release APKs of both channels (stable without OTA, unstable with OTA)"
|
|
run = './gradlew -Dorg.gradle.java.home=$JAVA_HOME assembleStableRelease assembleUnstableRelease'
|
|
|
|
[tasks.clean]
|
|
run = './gradlew -Dorg.gradle.java.home=$JAVA_HOME clean'
|
|
|
|
[tasks.emulator-setup]
|
|
description = "Installs the emulator and system images and creates both AVDs"
|
|
run = '''
|
|
set -e
|
|
SDK="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
|
|
AVDM="$ANDROID_HOME/cmdline-tools/latest/bin/avdmanager"
|
|
|
|
if [ ! -e /dev/kvm ]; then
|
|
echo "ERROR: /dev/kvm missing — no hardware acceleration, the emulator would be unusable." >&2
|
|
echo "On WSL2: enable nested virtualisation on the Windows side." >&2
|
|
exit 1
|
|
fi
|
|
if ! id -nG | tr ' ' '\n' | grep -qx kvm; then
|
|
echo "WARNING: user is not in the kvm group. Fix with:" >&2
|
|
echo " sudo usermod -aG kvm $USER # then log in again" >&2
|
|
fi
|
|
|
|
yes | "$SDK" --sdk_root="$ANDROID_HOME" --licenses > /dev/null
|
|
"$SDK" --sdk_root="$ANDROID_HOME" "emulator" "platform-tools" "$EMU_CAR_IMAGE" "$EMU_SCREEN_IMAGE"
|
|
|
|
create_avd() {
|
|
name="$1"; image="$2"; device="$3"
|
|
if "$AVDM" list avd 2>/dev/null | grep -q "Name: $name"; then
|
|
echo "AVD $name already exists"
|
|
else
|
|
echo no | "$AVDM" create avd -n "$name" -k "$image" -d "$device" --force
|
|
fi
|
|
cfg="$HOME/.android/avd/$name.avd/config.ini"
|
|
# The MG4's screen. Without this the AVD keeps the generic profile's density and the
|
|
# layouts do not look like what the driver sees.
|
|
sed -i '/^hw.lcd/d;/^disk.dataPartition.size/d' "$cfg"
|
|
{
|
|
echo "hw.lcd.width=$EMU_WIDTH"
|
|
echo "hw.lcd.height=$EMU_HEIGHT"
|
|
echo "hw.lcd.density=$EMU_DENSITY"
|
|
echo "disk.dataPartition.size=4G"
|
|
} >> "$cfg"
|
|
echo "AVD $name set to ${EMU_WIDTH}x${EMU_HEIGHT} @ ${EMU_DENSITY}dpi"
|
|
}
|
|
|
|
create_avd "$EMU_CAR_AVD" "$EMU_CAR_IMAGE" "automotive_1024p_landscape"
|
|
create_avd "$EMU_SCREEN_AVD" "$EMU_SCREEN_IMAGE" "pixel_c"
|
|
'''
|
|
|
|
# swiftshader_indirect, not "host": WSL2 exposes no real GPU (only Mesa llvmpipe). With
|
|
# -gpu host the emulator dies at start-up on "Your GPU cannot be used for hardware
|
|
# rendering", before any window appears — hence a tray icon and no visible emulator.
|
|
# Software rendering is slower, but it starts.
|
|
[tasks.emulator-car]
|
|
description = "Starts the Automotive emulator (API 33 — has a CarPropertyManager)"
|
|
run = '''
|
|
set -e
|
|
"$ANDROID_HOME/emulator/emulator" -avd "$EMU_CAR_AVD" \
|
|
-gpu swiftshader_indirect -no-snapshot-save -no-boot-anim &
|
|
"$ANDROID_HOME/platform-tools/adb" wait-for-device
|
|
echo "Car emulator ready."
|
|
'''
|
|
|
|
[tasks.emulator-screen]
|
|
description = "Starts the MG4 screen emulator (API 28, 1920x720 @ 160dpi — no car services)"
|
|
run = '''
|
|
set -e
|
|
"$ANDROID_HOME/emulator/emulator" -avd "$EMU_SCREEN_AVD" \
|
|
-gpu swiftshader_indirect -no-snapshot-save -no-boot-anim &
|
|
"$ANDROID_HOME/platform-tools/adb" wait-for-device
|
|
echo "Screen emulator ready."
|
|
'''
|
|
|
|
[tasks.emulator-stop]
|
|
description = "Stops the running emulator"
|
|
run = '"$ANDROID_HOME/platform-tools/adb" emu kill || true'
|
|
|
|
[tasks.run]
|
|
description = "Builds, installs and starts the APK on the emulator or the connected car"
|
|
depends = ["build"]
|
|
run = '''
|
|
set -e
|
|
ADB="$ANDROID_HOME/platform-tools/adb"
|
|
if [ -z "$($ADB devices | sed '1d' | grep -w device || true)" ]; then
|
|
echo "No device connected. Start 'mise run emulator-car' or 'mise run emulator-screen' first," >&2
|
|
echo "or connect the car over ADB." >&2
|
|
exit 1
|
|
fi
|
|
APK=$(ls -t app/build/outputs/apk/stable/debug/*.apk | head -1)
|
|
echo "Installing $APK"
|
|
$ADB install -r -g "$APK"
|
|
$ADB shell am start -n "com.stinnesbeck.nilsmg4/com.evsuite.abrp.MainActivity"
|
|
echo "Started. Logs: mise run logs"
|
|
'''
|