From 90982580af0e2b9c37e5cd5feb93b54039db7ae4 Mon Sep 17 00:00:00 2001 From: TCFDONMEZ Date: Mon, 5 Oct 2026 00:28:28 +0300 Subject: [PATCH] Allow disabling ABRP uploads independently --- CHANGELOG.md | 8 ++++ FatihsMG4-unstable-2.2.34.apk.sha256 | 1 + app/build.gradle | 4 +- .../com/evsuite/abrp/AbrpUploadService.java | 22 +++++++++-- .../java/com/evsuite/abrp/BootReceiver.java | 4 +- .../java/com/evsuite/abrp/MainActivity.java | 38 ++++++++++++++++++- .../java/com/evsuite/abrp/UploadSettings.java | 12 +++++- .../main/res/layout-w1000dp/pane_service.xml | 2 + app/src/main/res/layout/pane_service.xml | 2 + app/src/main/res/values/strings.xml | 6 ++- 10 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 FatihsMG4-unstable-2.2.34.apk.sha256 diff --git a/CHANGELOG.md b/CHANGELOG.md index a0fab3c..6c7782d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.2.34] - 2026-10-05 + +### Added + +- Added a separate **Upload telemetry to ABRP** switch. Turning it off keeps background + vehicle sampling, consumption history and OTA support running, but stops ABRP network + uploads so DiPlay can be the sole live telemetry sender. + ## [2.2.33] - 2026-10-02 ### Fixed diff --git a/FatihsMG4-unstable-2.2.34.apk.sha256 b/FatihsMG4-unstable-2.2.34.apk.sha256 new file mode 100644 index 0000000..eaf8b5a --- /dev/null +++ b/FatihsMG4-unstable-2.2.34.apk.sha256 @@ -0,0 +1 @@ +dbd0fcb9579a1bc62c694133066a5b27856e1b46c5a123df4831a5fc75568c1c FatihsMG4-unstable-2.2.34.apk diff --git a/app/build.gradle b/app/build.gradle index ad4fe51..014d6e2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -34,8 +34,8 @@ android { applicationId "com.evsuite.abrp" minSdk 27 targetSdk 36 - versionCode 50 - versionName "2.2.33" + versionCode 51 + versionName "2.2.34" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/evsuite/abrp/AbrpUploadService.java b/app/src/main/java/com/evsuite/abrp/AbrpUploadService.java index 7904157..e923985 100644 --- a/app/src/main/java/com/evsuite/abrp/AbrpUploadService.java +++ b/app/src/main/java/com/evsuite/abrp/AbrpUploadService.java @@ -202,7 +202,7 @@ public class AbrpUploadService extends Service { // and something else has to. Idempotent, asynchronous, and absent on a car that does // not have the map stack — in which case ext_temp simply stays unreported. - requestLocationUpdates(); + if (settings.abrpUploadEnabled) requestLocationUpdates(); // Fire the first upload after a short warm-up, then every UPLOAD_INTERVAL_SEC. // scheduleWithFixedDelay ensures we always get at least UPLOAD_INTERVAL_SEC @@ -293,12 +293,13 @@ public class AbrpUploadService extends Service { mainHandler.post(this::requestLocationUpdates); Log.i(TAG, "Settings reloaded: interval=" + settings.intervalSec + "s" + " boostLowSoc=" + settings.boostLowSoc - + " lowSoc=" + settings.lowSocPercent + "%"); + + " lowSoc=" + settings.lowSocPercent + "%" + + " abrpUpload=" + settings.abrpUploadEnabled); } // Same watchdog for GPS: requestLocationUpdates used to run once in onCreate, // so a provider that was off at start-up — or dropped later — meant // position-less telemetry for the rest of the session. - if (!locationUpdatesActive + if (settings.abrpUploadEnabled && !locationUpdatesActive && System.currentTimeMillis() - lastLocationRequestMs > LOCATION_RETRY_INTERVAL_SEC * 1000) { Log.w(TAG, "Location updates inactive, re-arming"); @@ -306,7 +307,8 @@ public class AbrpUploadService extends Service { } // Before the upload, not after: an upload that fails for want of a network is // the thing this is here to prevent. Cheap and rate-limited when already on. - if (wifi != null && prefs.getBoolean(MainActivity.WIFI_AUTO_KEY, true)) { + if (settings.abrpUploadEnabled && wifi != null + && prefs.getBoolean(MainActivity.WIFI_AUTO_KEY, true)) { wifi.ensureConnected(false); } doUpload(); @@ -323,6 +325,12 @@ public class AbrpUploadService extends Service { EnergySnapshot vehicle = energyReader.read(sampleMs); consumptionTracker.sample(vehicle); + // Keep local consumption history alive while another app owns the ABRP feed. + if (!settings.abrpUploadEnabled) { + updateNotification(getString(R.string.notif_tracking_locally)); + return; + } + String token = securePrefs.getString(SecurePrefs.KEY_TOKEN, "").trim(); String apiKey = securePrefs.getString(SecurePrefs.KEY_API_KEY, "").trim(); @@ -663,6 +671,12 @@ public class AbrpUploadService extends Service { try { locationManager.removeUpdates(locationListener); } catch (Exception ignored) {} locationUpdatesActive = false; + if (!settings.abrpUploadEnabled) { + lastLocation = null; + Log.i(TAG, "GPS updates stopped while ABRP upload is disabled"); + return; + } + if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { // Match the upload cadence: a 10 s GPS subscription burned power for // fixes that were thrown away between uploads. diff --git a/app/src/main/java/com/evsuite/abrp/BootReceiver.java b/app/src/main/java/com/evsuite/abrp/BootReceiver.java index f884b01..ead84a5 100644 --- a/app/src/main/java/com/evsuite/abrp/BootReceiver.java +++ b/app/src/main/java/com/evsuite/abrp/BootReceiver.java @@ -50,8 +50,10 @@ public class BootReceiver extends BroadcastReceiver { SharedPreferences secure = SecurePrefs.get(context); boolean haveCreds = !secure.getString(SecurePrefs.KEY_TOKEN, "").trim().isEmpty() && !secure.getString(SecurePrefs.KEY_API_KEY, "").trim().isEmpty(); + boolean uploadEnabled = prefs.getBoolean(UploadSettings.KEY_ABRP_UPLOAD_ENABLED, + UploadSettings.DEFAULT_ABRP_UPLOAD_ENABLED); - if (!enabled || !autostart || !haveCreds) { + if (!enabled || !autostart || (uploadEnabled && !haveCreds)) { Log.i(TAG, action + " ignored (enabled=" + enabled + " autostart=" + autostart + " credentials=" + haveCreds + ")"); return; diff --git a/app/src/main/java/com/evsuite/abrp/MainActivity.java b/app/src/main/java/com/evsuite/abrp/MainActivity.java index 0db90e8..d9c8fbf 100644 --- a/app/src/main/java/com/evsuite/abrp/MainActivity.java +++ b/app/src/main/java/com/evsuite/abrp/MainActivity.java @@ -70,6 +70,7 @@ public class MainActivity extends AppCompatActivity { private TextInputLayout tokenLayout; private TextInputEditText tokenInput; private SwitchMaterial serviceSwitch; + private SwitchMaterial abrpUploadSwitch; private SwitchMaterial autostartSwitch; private TextView statusText; private Button testButton; @@ -250,6 +251,7 @@ public class MainActivity extends AppCompatActivity { tokenLayout = abrpPane.findViewById(R.id.token_layout); tokenInput = abrpPane.findViewById(R.id.token_input); serviceSwitch = servicePane.findViewById(R.id.service_switch); + abrpUploadSwitch = servicePane.findViewById(R.id.abrp_upload_switch); autostartSwitch = servicePane.findViewById(R.id.autostart_switch); statusText = servicePane.findViewById(R.id.status_text); testButton = abrpPane.findViewById(R.id.test_button); @@ -275,6 +277,9 @@ public class MainActivity extends AppCompatActivity { apiKeyInput.setText(savedApiKeyOrDefault()); tokenInput.setText(securePrefs.getString(SecurePrefs.KEY_TOKEN, "")); serviceSwitch.setChecked(prefs.getBoolean("service_enabled", false)); + abrpUploadSwitch.setChecked(prefs.getBoolean( + UploadSettings.KEY_ABRP_UPLOAD_ENABLED, + UploadSettings.DEFAULT_ABRP_UPLOAD_ENABLED)); autostartSwitch.setChecked( prefs.getBoolean(UploadSettings.KEY_AUTOSTART, UploadSettings.DEFAULT_AUTOSTART)); @@ -290,7 +295,9 @@ public class MainActivity extends AppCompatActivity { boolean enabled = prefs.getBoolean("service_enabled", false); boolean haveCreds = !securePrefs.getString(SecurePrefs.KEY_TOKEN, "").trim().isEmpty() && !securePrefs.getString(SecurePrefs.KEY_API_KEY, "").trim().isEmpty(); - if (enabled && haveCreds) { + boolean uploadEnabled = prefs.getBoolean(UploadSettings.KEY_ABRP_UPLOAD_ENABLED, + UploadSettings.DEFAULT_ABRP_UPLOAD_ENABLED); + if (enabled && (!uploadEnabled || haveCreds)) { // Asked for first, and deliberately: the service declares the `location` // foreground type, and since API 34 starting it without the permission behind // that type is a SecurityException in its own onCreate. Started this way round, @@ -308,7 +315,7 @@ public class MainActivity extends AppCompatActivity { if (checked) { String apiKey = textOf(apiKeyInput); String token = textOf(tokenInput); - if (apiKey.isEmpty() || token.isEmpty()) { + if (abrpUploadSwitch.isChecked() && (apiKey.isEmpty() || token.isEmpty())) { serviceSwitch.setChecked(false); if (apiKey.isEmpty()) apiKeyLayout.setError(getString(R.string.api_key_required)); if (token.isEmpty()) tokenLayout.setError(getString(R.string.token_required)); @@ -325,6 +332,22 @@ public class MainActivity extends AppCompatActivity { } refreshStatus(); }); + + abrpUploadSwitch.setOnCheckedChangeListener((btn, checked) -> { + if (checked) { + String apiKey = textOf(apiKeyInput); + String token = textOf(tokenInput); + if (apiKey.isEmpty() || token.isEmpty()) { + abrpUploadSwitch.setChecked(false); + if (apiKey.isEmpty()) apiKeyLayout.setError(getString(R.string.api_key_required)); + if (token.isEmpty()) tokenLayout.setError(getString(R.string.token_required)); + return; + } + } + prefs.edit().putBoolean(UploadSettings.KEY_ABRP_UPLOAD_ENABLED, checked).apply(); + AbrpUploadService.reloadSettings(); + refreshStatus(); + }); } private void showAbout() { @@ -362,6 +385,9 @@ public class MainActivity extends AppCompatActivity { apiKeyInput.setText(savedApiKeyOrDefault()); tokenInput.setText(securePrefs.getString(SecurePrefs.KEY_TOKEN, "")); serviceSwitch.setChecked(prefs.getBoolean("service_enabled", false)); + abrpUploadSwitch.setChecked(prefs.getBoolean( + UploadSettings.KEY_ABRP_UPLOAD_ENABLED, + UploadSettings.DEFAULT_ABRP_UPLOAD_ENABLED)); autostartSwitch.setChecked( prefs.getBoolean(UploadSettings.KEY_AUTOSTART, UploadSettings.DEFAULT_AUTOSTART)); // Poll state and log only while the screen is up; onPause cancels it. @@ -1070,6 +1096,14 @@ public class MainActivity extends AppCompatActivity { // force-kill because onDestroy never ran. UploadLog.State state = AbrpUploadService.state(); + if (AbrpUploadService.isRunning() && !prefs.getBoolean( + UploadSettings.KEY_ABRP_UPLOAD_ENABLED, + UploadSettings.DEFAULT_ABRP_UPLOAD_ENABLED)) { + statusText.setText(R.string.state_tracking_locally); + statusText.setTextColor(COLOR_OK); + return; + } + switch (state) { case ERROR: // Derived from the log, not from the last status alone: a single failed diff --git a/app/src/main/java/com/evsuite/abrp/UploadSettings.java b/app/src/main/java/com/evsuite/abrp/UploadSettings.java index 9634d7a..a30ec5a 100644 --- a/app/src/main/java/com/evsuite/abrp/UploadSettings.java +++ b/app/src/main/java/com/evsuite/abrp/UploadSettings.java @@ -15,6 +15,7 @@ final class UploadSettings { static final String KEY_BOOST_LOW_SOC = "boost_low_soc"; static final String KEY_LOW_SOC_PERCENT = "low_soc_percent"; static final String KEY_AUTOSTART = "autostart"; + static final String KEY_ABRP_UPLOAD_ENABLED = "abrp_upload_enabled"; /** * On by default: an ABRP plan is only useful if it is fed from the moment the drive @@ -22,6 +23,7 @@ final class UploadSettings { * service that starts itself must also be switchable off. */ static final boolean DEFAULT_AUTOSTART = true; + static final boolean DEFAULT_ABRP_UPLOAD_ENABLED = true; /** * Default cadence while driving. 60 s is roughly 1.5 km between points at motorway @@ -44,18 +46,26 @@ final class UploadSettings { final int intervalSec; final boolean boostLowSoc; final int lowSocPercent; + final boolean abrpUploadEnabled; UploadSettings(int intervalSec, boolean boostLowSoc, int lowSocPercent) { + this(intervalSec, boostLowSoc, lowSocPercent, DEFAULT_ABRP_UPLOAD_ENABLED); + } + + UploadSettings(int intervalSec, boolean boostLowSoc, int lowSocPercent, + boolean abrpUploadEnabled) { this.intervalSec = intervalSec; this.boostLowSoc = boostLowSoc; this.lowSocPercent = lowSocPercent; + this.abrpUploadEnabled = abrpUploadEnabled; } static UploadSettings from(SharedPreferences prefs) { return new UploadSettings( prefs.getInt(KEY_INTERVAL_SEC, DEFAULT_INTERVAL_SEC), prefs.getBoolean(KEY_BOOST_LOW_SOC, DEFAULT_BOOST_LOW_SOC), - prefs.getInt(KEY_LOW_SOC_PERCENT, DEFAULT_LOW_SOC_PERCENT)); + prefs.getInt(KEY_LOW_SOC_PERCENT, DEFAULT_LOW_SOC_PERCENT), + prefs.getBoolean(KEY_ABRP_UPLOAD_ENABLED, DEFAULT_ABRP_UPLOAD_ENABLED)); } static UploadSettings defaults() { diff --git a/app/src/main/res/layout-w1000dp/pane_service.xml b/app/src/main/res/layout-w1000dp/pane_service.xml index 5a6479b..9eced4d 100644 --- a/app/src/main/res/layout-w1000dp/pane_service.xml +++ b/app/src/main/res/layout-w1000dp/pane_service.xml @@ -5,6 +5,8 @@ + + diff --git a/app/src/main/res/layout/pane_service.xml b/app/src/main/res/layout/pane_service.xml index 2349cdd..9d8557f 100644 --- a/app/src/main/res/layout/pane_service.xml +++ b/app/src/main/res/layout/pane_service.xml @@ -5,6 +5,8 @@ + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6aefdd8..cc4dd0c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -74,7 +74,9 @@ Enter your ABRP token first Upload Service - Enable background uploading + Enable background telemetry + Upload telemetry to ABRP + Turn this off when DiPlay sends ABRP data. Local consumption tracking and background telemetry keep running. Start automatically with the car Uploading resumes on its own when the head unit powers up. Turn this off to start it by hand from this screen. @@ -98,6 +100,8 @@ Stopped Starting… Running + Tracking locally — ABRP upload off + Tracking locally — ABRP upload off In error — last %1$d uploads failed