diff --git a/SPECS.md b/SPECS.md
index 0ec7454..d5fa8e9 100644
--- a/SPECS.md
+++ b/SPECS.md
@@ -114,6 +114,9 @@ tyre pressures, GPS (lat, lon, elevation, heading) and the is_* flags. It does *
INGEST_TOKEN) into git and pushed it. Commit amended and force-pushed; both values regenerated in
the now gitignored `k8s/secrets.yaml` (since moved to `k8s/secrets/secrets.yaml`, outside
`kubectl apply -f k8s/`). Filled-in secrets live only there from now on.
+- 2026-10-17 — App 2.8.0: immersive full screen (switch in the Upload tab, default on). Hides the
+ system bars on the emulator; whether SAIC's own bars on the MG4 can be hidden is only known once
+ tried on the car.
- 2026-10-17 — App 2.7.1: the voice key works. The car's key report, read off the on-screen log:
`android.intent.extra.hardkey.keycode` (Integer), `.down` (Boolean, a report per press and per
release), `.longpress` (Boolean). 2.7.0 looked only for short names and never found the code.
diff --git a/app/build.gradle b/app/build.gradle
index f38b18d..a050f40 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -34,8 +34,8 @@ android {
applicationId "com.stinnesbeck.nilsmg4"
minSdk 27
targetSdk 36
- versionCode 65
- versionName "2.7.1"
+ versionCode 66
+ versionName "2.8.0"
// Nothing about the server ships in the APK: its URL and ingest token are entered in
// the app's Server tab (ServerConfig), and the database is only reachable by the server.
diff --git a/app/src/main/java/com/evsuite/abrp/MainActivity.java b/app/src/main/java/com/evsuite/abrp/MainActivity.java
index fae8d78..44fa0b0 100644
--- a/app/src/main/java/com/evsuite/abrp/MainActivity.java
+++ b/app/src/main/java/com/evsuite/abrp/MainActivity.java
@@ -120,7 +120,7 @@ public class MainActivity extends AppCompatActivity {
private TextView connectionStatusText;
/** Upload page: live telemetry switch and cadence. */
- private SwitchMaterial liveTelemetrySwitch, boostSwitch, voiceKeySwitch;
+ private SwitchMaterial liveTelemetrySwitch, boostSwitch, voiceKeySwitch, fullScreenSwitch;
private TextView steeringKeysText;
private android.widget.Spinner intervalSpinner;
private TextInputLayout lowSocLayout;
@@ -308,6 +308,35 @@ public class MainActivity extends AppCompatActivity {
uiHandler.post(uiRefresh);
}
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ // The system shows its bars again when focus moves (a dialog, the bars swiped in);
+ // re-applying on regaining focus keeps the app full screen.
+ if (hasFocus) applyFullScreen();
+ }
+
+ /**
+ * Immersive full screen: the head unit's top and bottom bars are hidden while the app is
+ * in front, and a swipe from the edge shows them briefly. On the MG4 those bars are SAIC's
+ * own (climate strip, hazard and home shortcuts); if the platform keeps them, these flags
+ * simply have no effect.
+ */
+ @SuppressWarnings("deprecation") // the WindowInsetsController API starts at 30; this is 28
+ private void applyFullScreen() {
+ View decor = getWindow().getDecorView();
+ if (UploadSettings.fullScreen(prefs)) {
+ decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN);
+ } else {
+ decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+ }
+ }
+
@Override
protected void onPause() {
super.onPause();
@@ -798,6 +827,12 @@ public class MainActivity extends AppCompatActivity {
voiceKeySwitch.setChecked(UploadSettings.voiceKeyOpensApp(prefs));
voiceKeySwitch.setOnCheckedChangeListener((btn, checked) ->
prefs.edit().putBoolean(UploadSettings.KEY_VOICE_KEY_OPENS, checked).apply());
+ fullScreenSwitch = servicePane.findViewById(R.id.full_screen_switch);
+ fullScreenSwitch.setChecked(UploadSettings.fullScreen(prefs));
+ fullScreenSwitch.setOnCheckedChangeListener((btn, checked) -> {
+ prefs.edit().putBoolean(UploadSettings.KEY_FULL_SCREEN, checked).apply();
+ applyFullScreen();
+ });
liveTelemetrySwitch = servicePane.findViewById(R.id.abrp_upload_switch);
intervalSpinner = servicePane.findViewById(R.id.interval_spinner);
boostSwitch = servicePane.findViewById(R.id.boost_switch);
diff --git a/app/src/main/java/com/evsuite/abrp/UploadSettings.java b/app/src/main/java/com/evsuite/abrp/UploadSettings.java
index fd3d717..7a867a3 100644
--- a/app/src/main/java/com/evsuite/abrp/UploadSettings.java
+++ b/app/src/main/java/com/evsuite/abrp/UploadSettings.java
@@ -16,6 +16,13 @@ final class UploadSettings {
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";
+ /** Hide the head unit's system bars while the app is open. */
+ static final String KEY_FULL_SCREEN = "full_screen";
+
+ static boolean fullScreen(SharedPreferences prefs) {
+ return prefs.getBoolean(KEY_FULL_SCREEN, true);
+ }
+
/** A double press of the steering wheel's voice key opens the app. */
static final String KEY_VOICE_KEY_OPENS = "voice_key_opens_app";
diff --git a/app/src/main/res/layout-w1000dp/pane_service.xml b/app/src/main/res/layout-w1000dp/pane_service.xml
index ea2863f..2ed63fd 100644
--- a/app/src/main/res/layout-w1000dp/pane_service.xml
+++ b/app/src/main/res/layout-w1000dp/pane_service.xml
@@ -6,6 +6,8 @@
+
+
diff --git a/app/src/main/res/layout/pane_service.xml b/app/src/main/res/layout/pane_service.xml
index b14540c..fbe693c 100644
--- a/app/src/main/res/layout/pane_service.xml
+++ b/app/src/main/res/layout/pane_service.xml
@@ -6,6 +6,8 @@
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 9f7431d..6d4d5ab 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -107,6 +107,8 @@
Connection timed out
Server error (HTTP %1$d)
+ Full screen
+ Hides the car\'s top and bottom bars while this app is open. Swipe in from the top or bottom edge to show them briefly, e.g. for the climate controls.
Double-press the voice key to open this app
Press the voice key on the steering wheel twice quickly. The voice assistant may still react to the presses.
Steering-wheel keys