App 2.17.1: tidier Settings and Logs
- Settings: the Wi-Fi and saved-networks cards are gone, and the rest sits in three columns (display and steering wheel | battery | charging price and app) instead of one tall column. The background Wi-Fi auto-connect stays on, without a switch. - Logs: only the upload log. The steering-key reports, the car-colour probe and the screen line answered their questions and are removed, with their code (CarColorProbe, the key-report log) and strings. - README lists the current tabs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@ development. It must not be treated as a vendor specification.
|
|||||||
| Android | 9 (Pie) — **API 28** |
|
| Android | 9 (Pie) — **API 28** |
|
||||||
| Chipset | MediaTek **MT2712** |
|
| Chipset | MediaTek **MT2712** |
|
||||||
| Device | `mt2712_saic_eh32` (eh32 = MG4) |
|
| Device | `mt2712_saic_eh32` (eh32 = MG4) |
|
||||||
| Display | **1920×720 px @ 160 dpi**; the app window is **1778×720 px** (≈1778×640 dp for layouts), the car's own sidebar taking the rest. Confirmed on the car 2026-10-18 (Logs → SCREEN, `SWI68`). |
|
| Display | **1920×720 px @ 160 dpi**; the app window is **1778×720 px** (≈1778×640 dp for layouts), the car's own sidebar taking the rest. Confirmed on the car 2026-10-18 (read with app 2.16.2, `SWI68`). |
|
||||||
| Emulator display profile | **1920×720 @ 160 dpi** |
|
| Emulator display profile | **1920×720 @ 160 dpi** |
|
||||||
| `ro.build.mtk2712.vehicle_type` | `AS28` (a vehicle type code; the paint colour is not among the system properties) |
|
| `ro.build.mtk2712.vehicle_type` | `AS28` (a vehicle type code; the paint colour is not among the system properties) |
|
||||||
|
|
||||||
|
|||||||
@@ -63,13 +63,13 @@ with the server using a token of its own, obtained by pairing with a phone (belo
|
|||||||
|
|
||||||
| Tab | What it shows |
|
| Tab | What it shows |
|
||||||
|---|---|
|
|---|---|
|
||||||
| **Overview** | Battery, range, range since start and at the 5-minute average with their usage, power, speed; odometer, climate setpoint and tyre pressures |
|
| **Overview** | Battery, range, range since start and at the 5-minute average with their usage, energy since start, power and speed with their 5-minute averages; odometer, climate setpoint and tyre pressures |
|
||||||
| **Consumption** | Daily and period consumption, efficiency |
|
| **Consumption** | Daily and period consumption, efficiency |
|
||||||
| **Charging** | Charging sessions and curves, cost in euro |
|
| **Charging** | Charging sessions and curves, cost in euro |
|
||||||
| **Live data** | Live data on/off, ABRP credentials for sending directly from the car, upload frequency |
|
| **Live data** | Live data on/off, ABRP credentials for sending directly from the car, upload frequency |
|
||||||
| **Server** | Server URL, pairing by QR code, ingest token, installation ID, config import |
|
| **Server** | Server URL, pairing by QR code, ingest token, installation ID, config import |
|
||||||
| **Settings** | Full screen, voice key, battery (usable capacity, manual SoH), charging price, Wi-Fi |
|
| **Settings** | Full screen, voice key, tyre pressure unit, accent colour, battery (usable capacity, manual SoH), charging price, version, update check, About |
|
||||||
| **Logs** | Upload log and the last steering-wheel key reports |
|
| **Logs** | Upload log |
|
||||||
|
|
||||||
- **Opening the app:** the MG4 launcher does not list third-party apps. **Double-press the
|
- **Opening the app:** the MG4 launcher does not list third-party apps. **Double-press the
|
||||||
voice key** on the steering wheel and the app comes to the front (switch on the Settings
|
voice key** on the steering wheel and the app comes to the front (switch on the Settings
|
||||||
|
|||||||
@@ -112,6 +112,10 @@ 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
|
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
|
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.
|
`kubectl apply -f k8s/`). Filled-in secrets live only there from now on.
|
||||||
|
- 2026-10-18 — App 2.17.1: Settings without the Wi-Fi and saved-networks cards, in three columns
|
||||||
|
(display and steering wheel | battery | charging price and app). The background Wi-Fi
|
||||||
|
auto-connect stays on, now without a switch. Logs keeps only the upload log: the steering-key
|
||||||
|
reports, the car-colour probe and the screen line are gone, their questions answered.
|
||||||
- 2026-10-18 — App 2.17.0: "Speed, 5-min average" card under Speed. The top bar is one compact line
|
- 2026-10-18 — App 2.17.0: "Speed, 5-min average" card under Speed. The top bar is one compact line
|
||||||
(title and subtitle); version, update check and About moved to an App card on the Settings tab.
|
(title and subtitle); version, update check and About moved to an App card on the Settings tab.
|
||||||
The Overview fits the car's window without scrolling: checked on the emulator at 1778×640, the
|
The Overview fits the car's window without scrolling: checked on the emulator at 1778×640, the
|
||||||
|
|||||||
+2
-2
@@ -34,8 +34,8 @@ android {
|
|||||||
applicationId "com.stinnesbeck.nilsmg4"
|
applicationId "com.stinnesbeck.nilsmg4"
|
||||||
minSdk 27
|
minSdk 27
|
||||||
targetSdk 36
|
targetSdk 36
|
||||||
versionCode 89
|
versionCode 90
|
||||||
versionName "2.17.0"
|
versionName "2.17.1"
|
||||||
|
|
||||||
// Nothing about the server ships in the APK: its URL and ingest token are entered in
|
// 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.
|
// the app's Server tab (ServerConfig), and the database is only reachable by the server.
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
package com.evsuite.abrp;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Looks for the car's paint colour among the head unit's system properties, for the Logs tab.
|
|
||||||
*
|
|
||||||
* The MG launcher draws the car in its own colour, so the head unit knows it somewhere; where is
|
|
||||||
* not documented. This lists every property whose name or value mentions a colour or paint, so
|
|
||||||
* a photo of the Logs tab shows whether (and how) it can be read. Read-only: it runs the
|
|
||||||
* platform's own getprop, which only reads.
|
|
||||||
*/
|
|
||||||
final class CarColorProbe {
|
|
||||||
|
|
||||||
private static final Pattern LINE = Pattern.compile("^\\[([^\\]]*)\\]: \\[(.*)\\]$");
|
|
||||||
private static final Pattern INTERESTING = Pattern.compile(
|
|
||||||
"(?i)colou?r|paint|body_?col|exterior|car_?model|vehicle_?(config|type|model)");
|
|
||||||
|
|
||||||
private CarColorProbe() { }
|
|
||||||
|
|
||||||
/** getprop's output, filtered; at most {@code max} lines. Never throws. */
|
|
||||||
static List<String> run(int max) {
|
|
||||||
try {
|
|
||||||
Process p = new ProcessBuilder("getprop").redirectErrorStream(true).start();
|
|
||||||
StringBuilder out = new StringBuilder();
|
|
||||||
try (BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8))) {
|
|
||||||
String line;
|
|
||||||
while ((line = r.readLine()) != null && out.length() < 512 * 1024) out.append(line).append('\n');
|
|
||||||
}
|
|
||||||
p.waitFor();
|
|
||||||
return filter(out.toString(), max);
|
|
||||||
} catch (Exception e) {
|
|
||||||
List<String> failed = new ArrayList<>();
|
|
||||||
failed.add("getprop failed: " + e.getClass().getSimpleName());
|
|
||||||
return failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The "name = value" lines whose name or value looks colour- or model-related. Pure. */
|
|
||||||
static List<String> filter(String getpropOutput, int max) {
|
|
||||||
List<String> found = new ArrayList<>();
|
|
||||||
for (String line : getpropOutput.split("\n")) {
|
|
||||||
Matcher m = LINE.matcher(line.trim());
|
|
||||||
if (!m.matches()) continue;
|
|
||||||
String name = m.group(1), value = m.group(2);
|
|
||||||
if (INTERESTING.matcher(name).find() || INTERESTING.matcher(value).find()) {
|
|
||||||
found.add(name + " = " + value);
|
|
||||||
if (found.size() >= max) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -35,7 +35,11 @@ import com.evsuite.hardware.telemetry.EnergyTelemetryReader;
|
|||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
/** Shared with {@link AbrpUploadService}, which reads it on every tick. */
|
/**
|
||||||
|
* Rejoin a saved network (the phone hotspot) in the background; read by
|
||||||
|
* {@link AbrpUploadService} on every tick. On by default; the Wi-Fi card with its switch was
|
||||||
|
* removed from Settings (2.17.1), so it now stays on.
|
||||||
|
*/
|
||||||
static final String WIFI_AUTO_KEY = "wifi_auto_connect";
|
static final String WIFI_AUTO_KEY = "wifi_auto_connect";
|
||||||
private static final String REPOSITORY_URL = "https://git.stinnesbeck.com/nils/mg4";
|
private static final String REPOSITORY_URL = "https://git.stinnesbeck.com/nils/mg4";
|
||||||
|
|
||||||
@@ -76,9 +80,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
/** The pages in navigation order. Parallel to {@link #TAB_IDS}. */
|
/** The pages in navigation order. Parallel to {@link #TAB_IDS}. */
|
||||||
private View[] panes;
|
private View[] panes;
|
||||||
|
|
||||||
/** Wi-Fi page. The helper is the same one the upload service uses on its own tick. */
|
|
||||||
private WifiAutoConnect wifi;
|
|
||||||
private TextView wifiSsid, wifiState, wifiSavedList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value cells of the Vehicle page, looked up once and refreshed on the UI tick.
|
* Value cells of the Vehicle page, looked up once and refreshed on the UI tick.
|
||||||
@@ -126,7 +127,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
/** Upload page: live telemetry switch and cadence. */
|
/** Upload page: live telemetry switch and cadence. */
|
||||||
private SwitchMaterial liveTelemetrySwitch, boostSwitch, voiceKeySwitch, fullScreenSwitch;
|
private SwitchMaterial liveTelemetrySwitch, boostSwitch, voiceKeySwitch, fullScreenSwitch;
|
||||||
private TextView steeringKeysText;
|
|
||||||
private com.google.android.material.textfield.MaterialAutoCompleteTextView intervalChoices;
|
private com.google.android.material.textfield.MaterialAutoCompleteTextView intervalChoices;
|
||||||
private TextInputLayout lowSocLayout;
|
private TextInputLayout lowSocLayout;
|
||||||
private TextInputEditText lowSocInput;
|
private TextInputEditText lowSocInput;
|
||||||
@@ -215,10 +215,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
refreshStatus();
|
refreshStatus();
|
||||||
refreshCallLog();
|
refreshCallLog();
|
||||||
refreshSteeringKeys();
|
|
||||||
sampleTrackers();
|
sampleTrackers();
|
||||||
refreshConsumption();
|
refreshConsumption();
|
||||||
refreshWifi();
|
|
||||||
uiHandler.postDelayed(this, 2_000L);
|
uiHandler.postDelayed(this, 2_000L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -254,22 +252,12 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
bindVehiclePane();
|
bindVehiclePane();
|
||||||
bindConsumptionPane();
|
bindConsumptionPane();
|
||||||
bindChargingPane();
|
bindChargingPane();
|
||||||
bindWifiPane();
|
|
||||||
bindServerPane();
|
bindServerPane();
|
||||||
bindServicePane();
|
bindServicePane();
|
||||||
requestLocationPermissionIfNeeded();
|
requestLocationPermissionIfNeeded();
|
||||||
|
|
||||||
statusText = servicePane.findViewById(R.id.status_text);
|
statusText = servicePane.findViewById(R.id.status_text);
|
||||||
callLogText = logPane.findViewById(R.id.call_log_text);
|
callLogText = logPane.findViewById(R.id.call_log_text);
|
||||||
steeringKeysText = logPane.findViewById(R.id.steering_keys_text);
|
|
||||||
TextView carColorText = logPane.findViewById(R.id.car_color_text);
|
|
||||||
showScreenInfo(logPane.findViewById(R.id.screen_text));
|
|
||||||
logPane.findViewById(R.id.car_color_button).setOnClickListener(v -> new Thread(() -> {
|
|
||||||
java.util.List<String> found = CarColorProbe.run(60);
|
|
||||||
String shown = found.isEmpty() ? getString(R.string.car_color_none)
|
|
||||||
: android.text.TextUtils.join("\n", found);
|
|
||||||
runOnUiThread(() -> carColorText.setText(shown));
|
|
||||||
}, "car-color-probe").start());
|
|
||||||
logPane.findViewById(R.id.flush_now_button).setOnClickListener(v -> manualFlush());
|
logPane.findViewById(R.id.flush_now_button).setOnClickListener(v -> manualFlush());
|
||||||
|
|
||||||
setUpPager();
|
setUpPager();
|
||||||
@@ -292,21 +280,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
startForegroundService(new Intent(this, AbrpUploadService.class));
|
startForegroundService(new Intent(this, AbrpUploadService.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* What the head unit reports about its screen, for the Logs tab: the panel in pixels and its
|
|
||||||
* density, and this app's window in pixels and in dp, which is what layouts are chosen by.
|
|
||||||
* Sources disagree on the MG4's numbers (1920×720, 1280×480, a 1778×720 window).
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation") // getRealMetrics: the WindowMetrics API starts at 30; this is 28
|
|
||||||
private void showScreenInfo(TextView view) {
|
|
||||||
android.util.DisplayMetrics panel = new android.util.DisplayMetrics();
|
|
||||||
getWindowManager().getDefaultDisplay().getRealMetrics(panel);
|
|
||||||
android.util.DisplayMetrics window = getResources().getDisplayMetrics();
|
|
||||||
android.content.res.Configuration config = getResources().getConfiguration();
|
|
||||||
view.setText(getString(R.string.screen_info, panel.widthPixels, panel.heightPixels, panel.densityDpi,
|
|
||||||
window.widthPixels, window.heightPixels, config.screenWidthDp, config.screenHeightDp));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a dialog without bringing the car's bars back. A dialog is a window of its own, and
|
* Shows a dialog without bringing the car's bars back. A dialog is a window of its own, and
|
||||||
* the system shows the bars when a window without the full-screen flags takes focus. So it
|
* the system shows the bars when a window without the full-screen flags takes focus. So it
|
||||||
@@ -1224,45 +1197,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- Wi-Fi page ----------
|
|
||||||
|
|
||||||
private void bindWifiPane() {
|
|
||||||
wifi = new WifiAutoConnect(getApplicationContext());
|
|
||||||
wifiSsid = settingsPane.findViewById(R.id.wifi_ssid);
|
|
||||||
wifiState = settingsPane.findViewById(R.id.wifi_state);
|
|
||||||
wifiSavedList = settingsPane.findViewById(R.id.wifi_saved_list);
|
|
||||||
|
|
||||||
SwitchMaterial auto = settingsPane.findViewById(R.id.wifi_auto_switch);
|
|
||||||
auto.setChecked(prefs.getBoolean(WIFI_AUTO_KEY, true));
|
|
||||||
auto.setOnCheckedChangeListener((btn, checked) ->
|
|
||||||
prefs.edit().putBoolean(WIFI_AUTO_KEY, checked).apply());
|
|
||||||
|
|
||||||
settingsPane.findViewById(R.id.wifi_connect_button).setOnClickListener(v -> {
|
|
||||||
// force: the driver is asking now, so the rate limit does not apply.
|
|
||||||
WifiAutoConnect.Result r = wifi.ensureConnected(true);
|
|
||||||
wifiState.setText(r.message);
|
|
||||||
refreshWifi();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshWifi() {
|
|
||||||
if (wifi == null) return;
|
|
||||||
String ssid = wifi.currentSsid();
|
|
||||||
wifiSsid.setText(ssid == null ? getString(R.string.wifi_not_connected) : ssid);
|
|
||||||
if (ssid != null) {
|
|
||||||
wifiState.setText(R.string.wifi_connected);
|
|
||||||
} else if (!wifi.isWifiEnabled()) {
|
|
||||||
wifiState.setText(R.string.wifi_off);
|
|
||||||
}
|
|
||||||
// Left alone otherwise: a message the button just set says more about what is
|
|
||||||
// happening than "not connected" would.
|
|
||||||
|
|
||||||
java.util.List<String> saved = wifi.savedNetworkNames();
|
|
||||||
wifiSavedList.setText(saved.isEmpty()
|
|
||||||
? getString(R.string.wifi_saved_empty)
|
|
||||||
: android.text.TextUtils.join("\n", saved));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------- Vehicle page ----------
|
// ---------- Vehicle page ----------
|
||||||
|
|
||||||
/** Looks up the value cells once; the labels are static and never touched from code. */
|
/** Looks up the value cells once; the labels are static and never touched from code. */
|
||||||
@@ -1752,15 +1686,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}, "cloud-refresh").start();
|
}, "cloud-refresh").start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** What the car's steering-wheel key broadcasts looked like, newest first. */
|
|
||||||
private void refreshSteeringKeys() {
|
|
||||||
if (steeringKeysText == null) return;
|
|
||||||
java.util.List<String> keys = SteeringKeyListener.recent();
|
|
||||||
String text = keys.isEmpty() ? getString(R.string.steering_keys_empty)
|
|
||||||
: android.text.TextUtils.join("\n", keys);
|
|
||||||
if (!text.contentEquals(steeringKeysText.getText())) steeringKeysText.setText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshCallLog() {
|
private void refreshCallLog() {
|
||||||
java.util.List<UploadLog.Entry> entries = AbrpUploadService.log().recent();
|
java.util.List<UploadLog.Entry> entries = AbrpUploadService.log().recent();
|
||||||
if (entries.isEmpty()) {
|
if (entries.isEmpty()) {
|
||||||
|
|||||||
@@ -9,20 +9,12 @@ import android.os.Bundle;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the app on a double press of the steering wheel's voice key.
|
* Opens the app on a double press of the steering wheel's voice key.
|
||||||
*
|
*
|
||||||
* The head unit reports steering-wheel keys as the broadcast {@link #ACTION}; code 287 is the
|
* The head unit reports steering-wheel keys as the broadcast {@link #ACTION}; code 287 is the
|
||||||
* voice key (see EVHardware's PhysicalButtonEventDecoder). The extras' format was read off the
|
* voice key (see EVHardware's PhysicalButtonEventDecoder). The extras' format was read off the
|
||||||
* car (see {@link SteeringKeyReport}); every report is still kept raw for the Logs tab, in case
|
* car (see {@link SteeringKeyReport}).
|
||||||
* another firmware sends them differently.
|
|
||||||
*
|
*
|
||||||
* Registered by the always-on service on the main thread; never throws into the head unit.
|
* Registered by the always-on service on the main thread; never throws into the head unit.
|
||||||
*/
|
*/
|
||||||
@@ -31,9 +23,6 @@ final class SteeringKeyListener {
|
|||||||
static final String ACTION = "com.saic.keyevent.hardkey.report";
|
static final String ACTION = "com.saic.keyevent.hardkey.report";
|
||||||
static final int VOICE_KEY = 287;
|
static final int VOICE_KEY = 287;
|
||||||
private static final String TAG = "NilsMG4.SteeringKey";
|
private static final String TAG = "NilsMG4.SteeringKey";
|
||||||
private static final int MAX_LOG = 20;
|
|
||||||
|
|
||||||
private static final ArrayDeque<String> RECENT = new ArrayDeque<>();
|
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final SharedPreferences prefs;
|
private final SharedPreferences prefs;
|
||||||
@@ -79,18 +68,6 @@ final class SteeringKeyListener {
|
|||||||
registered = false;
|
registered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The last broadcasts, newest first, for the Logs tab. */
|
|
||||||
static synchronized List<String> recent() {
|
|
||||||
List<String> out = new ArrayList<>(RECENT);
|
|
||||||
java.util.Collections.reverse(out);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static synchronized void remember(String line) {
|
|
||||||
if (RECENT.size() >= MAX_LOG) RECENT.removeFirst();
|
|
||||||
RECENT.addLast(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handle(Intent intent) {
|
private void handle(Intent intent) {
|
||||||
Bundle extras = intent.getExtras();
|
Bundle extras = intent.getExtras();
|
||||||
SteeringKeyReport key = read(extras);
|
SteeringKeyReport key = read(extras);
|
||||||
@@ -98,11 +75,6 @@ final class SteeringKeyListener {
|
|||||||
if (key.code != null && UploadSettings.voiceKeyOpensApp(prefs)) {
|
if (key.code != null && UploadSettings.voiceKeyOpensApp(prefs)) {
|
||||||
opens = detector.accept(key.code, key.down, key.longPress, android.os.SystemClock.elapsedRealtime());
|
opens = detector.accept(key.code, key.down, key.longPress, android.os.SystemClock.elapsedRealtime());
|
||||||
}
|
}
|
||||||
remember(new SimpleDateFormat("HH:mm:ss.SSS", Locale.US).format(new Date())
|
|
||||||
+ " " + describe(extras)
|
|
||||||
+ "\n -> code " + (key.code == null ? "?" : key.code)
|
|
||||||
+ ", down " + (key.down == null ? "?" : key.down)
|
|
||||||
+ ", long " + key.longPress + (opens ? " OPENS APP" : ""));
|
|
||||||
if (opens) {
|
if (opens) {
|
||||||
try {
|
try {
|
||||||
context.startActivity(new Intent(context, MainActivity.class)
|
context.startActivity(new Intent(context, MainActivity.class)
|
||||||
@@ -129,17 +101,4 @@ final class SteeringKeyListener {
|
|||||||
}
|
}
|
||||||
return SteeringKeyReport.parse(values);
|
return SteeringKeyReport.parse(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** All extras as name=value(type), so the Logs tab shows the real format. */
|
|
||||||
static String describe(Bundle extras) {
|
|
||||||
if (extras == null || extras.isEmpty()) return "(no extras)";
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (String k : extras.keySet()) {
|
|
||||||
Object v = extras.get(k);
|
|
||||||
if (sb.length() > 0) sb.append(", ");
|
|
||||||
sb.append(k).append('=').append(v).append(" (")
|
|
||||||
.append(v == null ? "null" : v.getClass().getSimpleName()).append(')');
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,34 +58,6 @@ final class WifiAutoConnect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isWifiEnabled() {
|
|
||||||
try {
|
|
||||||
return wifi != null && wifi.isWifiEnabled();
|
|
||||||
} catch (Throwable t) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Saved network names, for the UI to show what it can reach. Empty if the OS refuses. */
|
|
||||||
List<String> savedNetworkNames() {
|
|
||||||
java.util.List<String> names = new java.util.ArrayList<>();
|
|
||||||
try {
|
|
||||||
if (wifi == null) return names;
|
|
||||||
List<WifiConfiguration> saved = wifi.getConfiguredNetworks();
|
|
||||||
if (saved == null) return names;
|
|
||||||
for (WifiConfiguration c : saved) {
|
|
||||||
if (c == null || c.SSID == null) continue;
|
|
||||||
String name = c.SSID.replace("\"", "").trim();
|
|
||||||
if (!name.isEmpty() && !names.contains(name)) names.add(name);
|
|
||||||
}
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
Log.w(TAG, "Saved networks unavailable: permission denied");
|
|
||||||
} catch (Throwable t) {
|
|
||||||
Log.w(TAG, "getConfiguredNetworks refused: " + t.getMessage());
|
|
||||||
}
|
|
||||||
return names;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One attempt to get onto a saved network, rate-limited.
|
* One attempt to get onto a saved network, rate-limited.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<com.evsuite.abrp.StableScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:clipToPadding="false">
|
<com.evsuite.abrp.StableScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:clipToPadding="false">
|
||||||
|
<!-- Three columns: display and steering wheel | battery | charging price and the app. -->
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="24dp" android:baselineAligned="false">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="24dp" android:baselineAligned="false">
|
||||||
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:layout_marginEnd="16dp">
|
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:layout_marginEnd="16dp">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass">
|
||||||
@@ -17,7 +18,9 @@
|
|||||||
<com.google.android.material.textfield.MaterialAutoCompleteTextView android:id="@+id/accent_choices" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="72dp" android:inputType="none" android:textSize="20sp" app:simpleItemLayout="@layout/dropdown_item" />
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView android:id="@+id/accent_choices" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="72dp" android:inputType="none" android:textSize="20sp" app:simpleItemLayout="@layout/dropdown_item" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
</LinearLayout>
|
||||||
|
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:layout_marginEnd="16dp">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_battery_settings_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_battery_settings_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
<com.google.android.material.textfield.TextInputLayout android:id="@+id/consumption_soh_layout" style="@style/Widget.Material3.TextInputLayout.OutlinedBox" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:hint="@string/settings_manual_soh" app:suffixText="@string/unit_percent">
|
<com.google.android.material.textfield.TextInputLayout android:id="@+id/consumption_soh_layout" style="@style/Widget.Material3.TextInputLayout.OutlinedBox" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:hint="@string/settings_manual_soh" app:suffixText="@string/unit_percent">
|
||||||
<com.google.android.material.textfield.TextInputEditText android:id="@+id/consumption_soh_input" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="numberDecimal" android:maxLength="5" android:minHeight="72dp"/>
|
<com.google.android.material.textfield.TextInputEditText android:id="@+id/consumption_soh_input" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="numberDecimal" android:maxLength="5" android:minHeight="72dp"/>
|
||||||
@@ -30,7 +33,9 @@
|
|||||||
<com.google.android.material.button.MaterialButton android:id="@+id/usable_capacity_save" style="@style/Widget.EV.Button" android:layout_width="match_parent" android:layout_height="72dp" android:layout_marginTop="8dp" android:text="@string/btn_save_capacity"/>
|
<com.google.android.material.button.MaterialButton android:id="@+id/usable_capacity_save" style="@style/Widget.EV.Button" android:layout_width="match_parent" android:layout_height="72dp" android:layout_marginTop="8dp" android:text="@string/btn_save_capacity"/>
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/helper_usable_capacity" android:textAppearance="@style/Text.EV.Secondary"/>
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/helper_usable_capacity" android:textAppearance="@style/Text.EV.Secondary"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
</LinearLayout>
|
||||||
|
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_price_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_price_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
<com.google.android.material.textfield.TextInputLayout android:id="@+id/charge_price_layout" style="@style/Widget.Material3.TextInputLayout.OutlinedBox" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:hint="@string/settings_unit_price" app:suffixText="@string/unit_eur_per_kwh">
|
<com.google.android.material.textfield.TextInputLayout android:id="@+id/charge_price_layout" style="@style/Widget.Material3.TextInputLayout.OutlinedBox" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:hint="@string/settings_unit_price" app:suffixText="@string/unit_eur_per_kwh">
|
||||||
<com.google.android.material.textfield.TextInputEditText android:id="@+id/charge_price_input" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="numberDecimal" android:maxLength="10" android:minHeight="72dp"/>
|
<com.google.android.material.textfield.TextInputEditText android:id="@+id/charge_price_input" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="numberDecimal" android:maxLength="10" android:minHeight="72dp"/>
|
||||||
@@ -39,20 +44,6 @@
|
|||||||
<com.google.android.material.button.MaterialButton android:id="@+id/settings_phone_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/btn_phone_settings" android:layout_marginTop="8dp" />
|
<com.google.android.material.button.MaterialButton android:id="@+id/settings_phone_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/btn_phone_settings" android:layout_marginTop="8dp" />
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/hint_phone_settings" android:textAppearance="@style/Text.EV.Secondary" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/hint_phone_settings" android:textAppearance="@style/Text.EV.Secondary" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
|
||||||
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical">
|
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass">
|
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_card_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
|
||||||
<TextView android:id="@+id/wifi_ssid" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:textAppearance="@style/Text.EV.Metric" android:layout_marginTop="20dp" />
|
|
||||||
<TextView android:id="@+id/wifi_state" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:textAppearance="@style/Text.EV.Secondary" android:layout_marginTop="12dp" />
|
|
||||||
<com.google.android.material.button.MaterialButton android:id="@+id/wifi_connect_button" style="@style/Widget.EV.Button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_connect_now" android:layout_marginTop="24dp" />
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial android:id="@+id/wifi_auto_switch" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="72dp" android:text="@string/wifi_auto_label" android:textAppearance="@style/Text.EV.Body" android:paddingTop="8dp" android:paddingBottom="8dp" app:useMaterialThemeColors="true" app:thumbTint="@color/switch_thumb" app:trackTint="@color/switch_track" android:textColor="@color/ev_text_primary" />
|
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_auto_hint" android:textAppearance="@style/Text.EV.Secondary" />
|
|
||||||
</LinearLayout>
|
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_saved_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
|
||||||
<TextView android:id="@+id/wifi_saved_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:textAppearance="@style/Text.EV.Body" android:lineSpacingExtra="16dp" />
|
|
||||||
</LinearLayout>
|
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_app_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_app_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
<TextView android:id="@+id/settings_version" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:textAppearance="@style/Text.EV.Body" />
|
<TextView android:id="@+id/settings_version" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:textAppearance="@style/Text.EV.Body" />
|
||||||
|
|||||||
@@ -4,14 +4,5 @@
|
|||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/label_call_log" android:textAppearance="@style/Text.EV.Eyebrow" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/label_call_log" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
<com.google.android.material.button.MaterialButton android:id="@+id/flush_now_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="@string/btn_flush_now" app:icon="@drawable/ic_refresh" app:iconGravity="textStart" style="@style/Widget.EV.Button.Outlined" xmlns:app="http://schemas.android.com/apk/res-auto" />
|
<com.google.android.material.button.MaterialButton android:id="@+id/flush_now_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="@string/btn_flush_now" app:icon="@drawable/ic_refresh" app:iconGravity="textStart" style="@style/Widget.EV.Button.Outlined" xmlns:app="http://schemas.android.com/apk/res-auto" />
|
||||||
<TextView android:id="@+id/call_log_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:minHeight="180dp" android:text="@string/call_log_empty" android:textAppearance="@style/Text.EV.Body" android:fontFamily="monospace" android:textSize="17sp" android:lineSpacingExtra="12dp" android:textIsSelectable="true" />
|
<TextView android:id="@+id/call_log_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:minHeight="180dp" android:text="@string/call_log_empty" android:textAppearance="@style/Text.EV.Body" android:fontFamily="monospace" android:textSize="17sp" android:lineSpacingExtra="12dp" android:textIsSelectable="true" />
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="32dp" android:text="@string/label_steering_keys" android:textAppearance="@style/Text.EV.Eyebrow" />
|
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/hint_steering_keys" android:textAppearance="@style/Text.EV.Secondary" />
|
|
||||||
<TextView android:id="@+id/steering_keys_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:text="@string/steering_keys_empty" android:textAppearance="@style/Text.EV.Body" android:fontFamily="monospace" android:textSize="14sp" android:lineSpacingExtra="4dp" />
|
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="32dp" android:text="@string/label_car_color" android:textAppearance="@style/Text.EV.Eyebrow" />
|
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/hint_car_color" android:textAppearance="@style/Text.EV.Secondary" />
|
|
||||||
<com.google.android.material.button.MaterialButton android:id="@+id/car_color_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:text="@string/btn_car_color" />
|
|
||||||
<TextView android:id="@+id/car_color_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:textAppearance="@style/Text.EV.Body" android:fontFamily="monospace" android:textSize="14sp" android:lineSpacingExtra="4dp" android:textIsSelectable="true" />
|
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="32dp" android:text="@string/label_screen" android:textAppearance="@style/Text.EV.Eyebrow" />
|
|
||||||
<TextView android:id="@+id/screen_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/no_value" android:textAppearance="@style/Text.EV.Body" android:fontFamily="monospace" android:textSize="14sp" android:textIsSelectable="true" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</com.evsuite.abrp.StableScrollView>
|
</com.evsuite.abrp.StableScrollView>
|
||||||
|
|||||||
@@ -38,18 +38,6 @@
|
|||||||
<com.google.android.material.button.MaterialButton android:id="@+id/settings_phone_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/btn_phone_settings" android:layout_marginTop="8dp" />
|
<com.google.android.material.button.MaterialButton android:id="@+id/settings_phone_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/btn_phone_settings" android:layout_marginTop="8dp" />
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/hint_phone_settings" android:textAppearance="@style/Text.EV.Secondary" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/hint_phone_settings" android:textAppearance="@style/Text.EV.Secondary" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_card_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
|
||||||
<TextView android:id="@+id/wifi_ssid" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:textAppearance="@style/Text.EV.Metric" android:layout_marginTop="20dp" />
|
|
||||||
<TextView android:id="@+id/wifi_state" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:textAppearance="@style/Text.EV.Secondary" android:layout_marginTop="12dp" />
|
|
||||||
<com.google.android.material.button.MaterialButton android:id="@+id/wifi_connect_button" style="@style/Widget.EV.Button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_connect_now" android:layout_marginTop="24dp" />
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial android:id="@+id/wifi_auto_switch" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="72dp" android:text="@string/wifi_auto_label" android:textAppearance="@style/Text.EV.Body" android:paddingTop="8dp" android:paddingBottom="8dp" app:useMaterialThemeColors="true" app:thumbTint="@color/switch_thumb" app:trackTint="@color/switch_track" android:textColor="@color/ev_text_primary" />
|
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_auto_hint" android:textAppearance="@style/Text.EV.Secondary" />
|
|
||||||
</LinearLayout>
|
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_saved_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
|
||||||
<TextView android:id="@+id/wifi_saved_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:textAppearance="@style/Text.EV.Body" android:lineSpacingExtra="16dp" />
|
|
||||||
</LinearLayout>
|
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_app_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_app_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
<TextView android:id="@+id/settings_version" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:textAppearance="@style/Text.EV.Body" />
|
<TextView android:id="@+id/settings_version" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:textAppearance="@style/Text.EV.Body" />
|
||||||
|
|||||||
@@ -14,16 +14,6 @@
|
|||||||
<string name="tab_settings">Settings</string>
|
<string name="tab_settings">Settings</string>
|
||||||
<string name="tab_log">Logs</string>
|
<string name="tab_log">Logs</string>
|
||||||
|
|
||||||
<!-- Wi-Fi page -->
|
|
||||||
<string name="wifi_card_title">WI-FI</string>
|
|
||||||
<string name="wifi_current">Connected network</string>
|
|
||||||
<string name="wifi_state">Status</string>
|
|
||||||
<string name="wifi_connect_now">Connect Now</string>
|
|
||||||
<string name="wifi_auto_label">Auto-connect in the background</string>
|
|
||||||
<string name="wifi_auto_hint">While the upload service is running, it tries to reconnect to saved networks on its own when the connection drops.</string>
|
|
||||||
<string name="wifi_saved_title">SAVED NETWORKS</string>
|
|
||||||
<string name="wifi_saved_empty">Could not read saved networks</string>
|
|
||||||
<string name="wifi_not_connected">Not connected</string>
|
|
||||||
|
|
||||||
<!-- Vehicle page -->
|
<!-- Vehicle page -->
|
||||||
<string name="vehicle_live_data">Live Vehicle Data</string>
|
<string name="vehicle_live_data">Live Vehicle Data</string>
|
||||||
@@ -40,12 +30,6 @@
|
|||||||
<string name="power_waiting">needs a minute of data</string>
|
<string name="power_waiting">needs a minute of data</string>
|
||||||
<string name="label_tire_unit">Tyre pressure unit</string>
|
<string name="label_tire_unit">Tyre pressure unit</string>
|
||||||
<string name="label_accent">Accent colour</string>
|
<string name="label_accent">Accent colour</string>
|
||||||
<string name="label_screen">SCREEN</string>
|
|
||||||
<string name="screen_info">Panel %1$d × %2$d px at %3$d dpi\nApp window %4$d × %5$d px = %6$d × %7$d dp</string>
|
|
||||||
<string name="label_car_color">CAR COLOUR</string>
|
|
||||||
<string name="hint_car_color">Lists the head unit\'s settings that mention a colour, paint or car model, to find out whether the car\'s colour can be read. A photo of this list helps.</string>
|
|
||||||
<string name="btn_car_color">Look for the car colour</string>
|
|
||||||
<string name="car_color_none">Nothing colour-related found</string>
|
|
||||||
<string name="energy_kwh">%1$.1f kWh</string>
|
<string name="energy_kwh">%1$.1f kWh</string>
|
||||||
<string name="energy_trip_note">net, after recuperation</string>
|
<string name="energy_trip_note">net, after recuperation</string>
|
||||||
<string name="energy_trip_waiting">once the car is on</string>
|
<string name="energy_trip_waiting">once the car is on</string>
|
||||||
@@ -134,9 +118,6 @@
|
|||||||
<string name="hint_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.</string>
|
<string name="hint_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.</string>
|
||||||
<string name="label_voice_key">Double-press the voice key to open this app</string>
|
<string name="label_voice_key">Double-press the voice key to open this app</string>
|
||||||
<string name="hint_voice_key">Press the voice key on the steering wheel twice quickly. The voice assistant may still react to the presses.</string>
|
<string name="hint_voice_key">Press the voice key on the steering wheel twice quickly. The voice assistant may still react to the presses.</string>
|
||||||
<string name="label_steering_keys">Steering-wheel keys</string>
|
|
||||||
<string name="hint_steering_keys">The last key reports the car sent, newest first. If double-pressing the voice key does not open the app, a photo of this list shows how the car reports it.</string>
|
|
||||||
<string name="steering_keys_empty">No key reports received yet. Press a steering-wheel key.</string>
|
|
||||||
<string name="label_abrp_upload_enabled">Send live data</string>
|
<string name="label_abrp_upload_enabled">Send live data</string>
|
||||||
<string name="hint_abrp_upload_enabled">To your server, which stores it, and straight to ABRP when the ABRP credentials below are set. Consumption and charging tracking keep running when this is off.</string>
|
<string name="hint_abrp_upload_enabled">To your server, which stores it, and straight to ABRP when the ABRP credentials below are set. Consumption and charging tracking keep running when this is off.</string>
|
||||||
<string name="hint_abrp_direct">The car sends live data to ABRP itself with your ABRP API key and user token. Without them, ABRP gets no live data; your server only stores it.</string>
|
<string name="hint_abrp_direct">The car sends live data to ABRP itself with your ABRP API key and user token. Without them, ABRP gets no live data; your server only stores it.</string>
|
||||||
@@ -260,8 +241,6 @@
|
|||||||
<string name="settings_unit_price">Unit price</string>
|
<string name="settings_unit_price">Unit price</string>
|
||||||
<string name="unit_eur_per_kwh">€/kWh</string>
|
<string name="unit_eur_per_kwh">€/kWh</string>
|
||||||
<string name="settings_save_price">Save price</string>
|
<string name="settings_save_price">Save price</string>
|
||||||
<string name="wifi_connected">Connected ♥</string>
|
|
||||||
<string name="wifi_off">Wi-Fi off</string>
|
|
||||||
<string name="trip_reset_title">Reset %1$s?</string>
|
<string name="trip_reset_title">Reset %1$s?</string>
|
||||||
<string name="trip_reset_message">This counter\'s recorded consumption history will be permanently deleted.</string>
|
<string name="trip_reset_message">This counter\'s recorded consumption history will be permanently deleted.</string>
|
||||||
<string name="trip_reset_confirm">Reset</string>
|
<string name="trip_reset_confirm">Reset</string>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<string name="design_service_title">Live data.</string>
|
<string name="design_service_title">Live data.</string>
|
||||||
<string name="design_service_subtitle">Where your car\'s live data goes, and how often.</string>
|
<string name="design_service_subtitle">Where your car\'s live data goes, and how often.</string>
|
||||||
<string name="design_settings_title">Settings.</string>
|
<string name="design_settings_title">Settings.</string>
|
||||||
<string name="design_settings_subtitle">Display, battery, charging price, Wi-Fi and updates.</string>
|
<string name="design_settings_subtitle">Display, battery, charging price and updates.</string>
|
||||||
<string name="design_log_title">Every upload, right here.</string>
|
<string name="design_log_title">Every upload, right here.</string>
|
||||||
<string name="design_log_subtitle">Status and details of recent uploads.</string>
|
<string name="design_log_subtitle">Status and details of recent uploads.</string>
|
||||||
<string name="design_battery">BATTERY</string>
|
<string name="design_battery">BATTERY</string>
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.evsuite.abrp;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/** Picking colour-related system properties out of getprop's output — pure JVM. */
|
|
||||||
public class CarColorProbeTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onlyColourOrModelRelatedPropertiesAreListed() {
|
|
||||||
String getprop = "[ro.build.version.sdk]: [28]\n"
|
|
||||||
+ "[persist.saic.vehicle.color]: [3]\n"
|
|
||||||
+ "[ro.product.model]: [EH32]\n"
|
|
||||||
+ "[persist.car.bodyCol]: [RED]\n"
|
|
||||||
+ "[sys.launcher.car_model]: [mg4_red.glb]\n"
|
|
||||||
+ "garbage line\n";
|
|
||||||
assertEquals(Arrays.asList("persist.saic.vehicle.color = 3", "persist.car.bodyCol = RED",
|
|
||||||
"sys.launcher.car_model = mg4_red.glb"), CarColorProbe.filter(getprop, 50));
|
|
||||||
assertEquals(1, CarColorProbe.filter(getprop, 1).size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user