Rename package and APKs to NilsMG4, credit Fatih, add SPECS.md

- applicationId com.evsuite.abrp -> com.stinnesbeck.nilsmg4 (the car
  build is .unstable); the Java namespace is unchanged. Installs next to
  upstream's app rather than over it.
- APK names NilsMG4-*.apk, debug builds included; build-car follows.
- OTA install-result action, cache/download names, User-Agent and log
  tags follow the new name.
- About credits fatihdonmezdev / FatihsMG4.
- SPECS.md journals what changed and what is still to do, starting
  with pointing the About link and QR code at git.stinnesbeck.com/nils/mg4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 13:08:09 +02:00
co-authored by Claude Opus 5.5
parent 3da3fa9f49
commit a707b590f7
11 changed files with 90 additions and 32 deletions
+7 -4
View File
@@ -31,7 +31,7 @@ android {
}
defaultConfig {
applicationId "com.evsuite.abrp"
applicationId "com.stinnesbeck.nilsmg4"
minSdk 27
targetSdk 36
versionCode 56
@@ -113,7 +113,7 @@ android {
}
// Version publiée par la CI pour composer le nom de l'asset APK : ce nom DOIT être
// comparable par l'updater ("FatihsMG4-unstable-1.0.42.apk"). Le tag de la
// comparable par l'updater ("NilsMG4-unstable-1.0.42.apk"). Le tag de la
// pré-release est la constante "unstable", écrasée à chaque build.
tasks.register('printUnstableVersion') {
doLast {
@@ -129,8 +129,11 @@ androidComponents {
// Le canal unstable garde un nom de fichier stable : l'updater identifie
// la version par le tag de la pré-release, jamais par le nom d'APK.
output.outputFileName.set(variant.flavorName == "unstable"
? "FatihsMG4-unstable.apk"
: "FatihsMG4-${variant.flavorName}-${output.versionName.get()}.apk")
? "NilsMG4-unstable.apk"
: "NilsMG4-${variant.flavorName}-${output.versionName.get()}.apk")
} else {
// Debug builds: NilsMG4-stable-debug.apk, NilsMG4-unstable-debug.apk.
output.outputFileName.set("NilsMG4-${variant.flavorName}-${variant.buildType}.apk")
}
}
}
@@ -28,7 +28,7 @@ import java.util.List;
* picks up right where the old one left off instead of showing zeroes.
*/
final class ConsumptionCloudClient {
private static final String TAG = "FatihsMG4.Mongo";
private static final String TAG = "NilsMG4.Mongo";
private static final long CONSUMPTION_SYNC_INTERVAL_MS = 2 * 60_000L;
private static final long CHARGE_RETRY_INTERVAL_MS = 5 * 60_000L;
private static final long HISTORY_FETCH_INTERVAL_MS = 5 * 60_000L;
@@ -216,7 +216,7 @@ final class ConsumptionTracker {
if (cloudLifetime.km > local.km) {
lifetime.set(cloudLifetime.km, cloudLifetime.kwh, cloudLifetime.hours, cloudLifetime.soc);
persist();
Log.i("FatihsMG4.Consumption", "Lifetime baseline synced from cloud: "
Log.i("NilsMG4.Consumption", "Lifetime baseline synced from cloud: "
+ cloudLifetime.km + " km (was " + local.km + " km)");
}
}
+1 -1
View File
@@ -128,7 +128,7 @@
<string name="about_action">About</string>
<string name="about_title">About Nils\' MG4</string>
<string name="about_version">Version %1$s</string>
<string name="about_attribution">Fork of malys / EVABRPUploader\nand Leon Kernan / ABRP_Uploader</string>
<string name="about_attribution">Fork of fatihdonmezdev / FatihsMG4,\nmalys / EVABRPUploader\nand Leon Kernan / ABRP_Uploader</string>
<string name="about_repository">github.com/fatihdonmezdev/FatihsMG4</string>
<string name="about_made_with_love">MG4 EH32 · SWI69</string>
<string name="about_logo_description">Nils\' MG4 logo</string>
@@ -102,13 +102,13 @@ public class OtaUpdaterTest {
@Test
public void versionIsReadFromTheAssetName() {
// The release tag is the constant "unstable", so the asset name carries the build.
assertEquals("1.0.42", OtaUpdater.versionFromAssetName("FatihsMG4-unstable-1.0.42.apk"));
assertEquals("1.0.100", OtaUpdater.versionFromAssetName("FatihsMG4-unstable-1.0.100.APK"));
assertEquals("1.0.42", OtaUpdater.versionFromAssetName("NilsMG4-unstable-1.0.42.apk"));
assertEquals("1.0.100", OtaUpdater.versionFromAssetName("NilsMG4-unstable-1.0.100.APK"));
}
@Test
public void assetNameWithoutAVersionIsIgnored() {
assertNull(OtaUpdater.versionFromAssetName("FatihsMG4-unstable.apk"));
assertNull(OtaUpdater.versionFromAssetName("NilsMG4-unstable.apk"));
assertNull(OtaUpdater.versionFromAssetName("unstable"));
}
@@ -125,14 +125,14 @@ public class OtaUpdaterTest {
public void sha256SidecarFormatsAreParsed() {
String hash = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
assertEquals(hash, OtaUpdater.parseExpectedSha256(hash,
"FatihsMG4-unstable-2.2.7.apk"));
"NilsMG4-unstable-2.2.7.apk"));
assertEquals(hash, OtaUpdater.parseExpectedSha256(
hash + " *FatihsMG4-unstable-2.2.7.apk\n",
"FatihsMG4-unstable-2.2.7.apk"));
hash + " *NilsMG4-unstable-2.2.7.apk\n",
"NilsMG4-unstable-2.2.7.apk"));
assertNull(OtaUpdater.parseExpectedSha256(hash + " another.apk",
"FatihsMG4-unstable-2.2.7.apk"));
"NilsMG4-unstable-2.2.7.apk"));
assertNull(OtaUpdater.parseExpectedSha256("not-a-hash",
"FatihsMG4-unstable-2.2.7.apk"));
"NilsMG4-unstable-2.2.7.apk"));
}
@Test
@@ -150,14 +150,14 @@ public class OtaUpdaterTest {
.put(release(true, asset("2.2.5")));
OtaUpdater.Update update = OtaUpdater.selectUpdate(releases, "2.2.2.0-unstable");
assertEquals("2.2.6", update.versionName);
assertTrue(update.apkUrl.endsWith("FatihsMG4-unstable-2.2.6.apk"));
assertTrue(update.apkUrl.endsWith("NilsMG4-unstable-2.2.6.apk"));
}
@Test
public void stableDraftForeignAndUnversionedAssetsCannotWin() throws Exception {
JSONObject foreign = asset("9.0.0").put("browser_download_url", "https://example.com/app.apk");
JSONObject unversioned = asset("9.0.0").put("name", "FatihsMG4-unstable.apk");
JSONObject stableName = asset("9.0.0").put("name", "FatihsMG4-stable-9.0.0.apk");
JSONObject unversioned = asset("9.0.0").put("name", "NilsMG4-unstable.apk");
JSONObject stableName = asset("9.0.0").put("name", "NilsMG4-stable-9.0.0.apk");
JSONArray releases = new JSONArray()
.put(release(false, asset("9.0.0")))
.put(release(true, asset("9.0.0")).put("draft", true))
@@ -216,7 +216,7 @@ public class OtaUpdaterTest {
}
private static JSONObject asset(String version) throws Exception {
String name = "FatihsMG4-unstable-" + version + ".apk";
String name = "NilsMG4-unstable-" + version + ".apk";
return new JSONObject().put("name", name).put("browser_download_url",
"https://github.com/fatihdonmezdev/FatihsMG4/releases/download/unstable/" + name);
}
+1 -1
View File
@@ -27,7 +27,7 @@
android:name=".OtaInstallResultReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.evsuite.abrp.OTA_INSTALL_RESULT" />
<action android:name="com.stinnesbeck.nilsmg4.OTA_INSTALL_RESULT" />
</intent-filter>
</receiver>
</application>
@@ -19,7 +19,7 @@ import android.widget.Toast;
*/
public final class OtaInstallResultReceiver extends BroadcastReceiver {
static final String ACTION_INSTALL_RESULT = "com.evsuite.abrp.OTA_INSTALL_RESULT";
static final String ACTION_INSTALL_RESULT = "com.stinnesbeck.nilsmg4.OTA_INSTALL_RESULT";
private static final String TAG = "EVABRP.Update";
@@ -53,7 +53,7 @@ import java.security.MessageDigest;
final class OtaUpdater {
private static final String TAG = "OtaUpdater";
private static final String CACHE_PREFIX = "FatihsMG4-ota-";
private static final String CACHE_PREFIX = "NilsMG4-ota-";
/**
* Pre-releases live here; the unstable channel tracks them.
@@ -167,7 +167,7 @@ final class OtaUpdater {
/**
* Version carried by an unstable asset name:
* "FatihsMG4-unstable-1.0.42.apk" -> "1.0.42".
* "NilsMG4-unstable-1.0.42.apk" -> "1.0.42".
*
* The release tag is the fixed string "unstable" (one rolling pre-release), so the asset
* name is what identifies a build. Returns null when the name carries no version.
@@ -203,7 +203,7 @@ final class OtaUpdater {
try {
conn.setInstanceFollowRedirects(false);
conn.setRequestProperty("Accept", "application/vnd.github.v3+json");
conn.setRequestProperty("User-Agent", "FatihsMG4-Android");
conn.setRequestProperty("User-Agent", "NilsMG4-Android");
conn.setConnectTimeout(TIMEOUT_MS);
conn.setReadTimeout(TIMEOUT_MS);
int status = conn.getResponseCode();
@@ -302,7 +302,7 @@ final class OtaUpdater {
connection.setInstanceFollowRedirects(false);
connection.setConnectTimeout(TIMEOUT_MS);
connection.setReadTimeout(TIMEOUT_MS);
connection.setRequestProperty("User-Agent", "FatihsMG4-Android");
connection.setRequestProperty("User-Agent", "NilsMG4-Android");
try {
int status = connection.getResponseCode();
if (status >= 300 && status <= 399) {
@@ -584,7 +584,7 @@ final class OtaUpdater {
if (downloads == null || (!downloads.isDirectory() && !downloads.mkdirs())) {
throw new IllegalStateException("Downloads directory unavailable");
}
File destination = new File(downloads, "FatihsMG4-OTA-update.apk");
File destination = new File(downloads, "NilsMG4-OTA-update.apk");
try (FileInputStream input = new FileInputStream(source);
FileOutputStream output = new FileOutputStream(destination, false)) {
byte[] buffer = new byte[64 * 1024];