diff --git a/app/build.gradle b/app/build.gradle
index c54e60a..396a0e6 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -34,8 +34,8 @@ android {
applicationId "com.stinnesbeck.nilsmg4"
minSdk 27
targetSdk 36
- versionCode 93
- versionName "2.17.4"
+ versionCode 94
+ versionName "2.17.5"
// 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 00efca0..afffebc 100644
--- a/app/src/main/java/com/evsuite/abrp/MainActivity.java
+++ b/app/src/main/java/com/evsuite/abrp/MainActivity.java
@@ -114,8 +114,10 @@ public class MainActivity extends AppCompatActivity {
private ChargingGraphView chargeGraph;
/** Server page. */
- private TextInputLayout serverUrlLayout, serverTokenLayout, installationIdLayout;
- private TextInputEditText serverUrlInput, serverTokenInput, installationIdInput;
+ private TextInputLayout serverUrlLayout, serverTokenLayout;
+ private TextInputEditText serverUrlInput, serverTokenInput;
+ /** Shown, not edited: derived from the head unit (ServerConfig.installationIdFor). */
+ private TextView installationIdText;
private View connectionStatusRow, connectionIndicator;
private TextView connectionStatusText;
@@ -460,19 +462,17 @@ public class MainActivity extends AppCompatActivity {
private void bindServerPane() {
serverUrlLayout = serverPane.findViewById(R.id.server_url_layout);
serverTokenLayout = serverPane.findViewById(R.id.server_token_layout);
- installationIdLayout = serverPane.findViewById(R.id.installation_id_layout);
serverUrlInput = serverPane.findViewById(R.id.server_url_input);
serverTokenInput = serverPane.findViewById(R.id.server_token_input);
- installationIdInput = serverPane.findViewById(R.id.installation_id_input);
+ installationIdText = serverPane.findViewById(R.id.installation_id_text);
connectionStatusRow = serverPane.findViewById(R.id.connection_status_row);
connectionIndicator = serverPane.findViewById(R.id.connection_indicator);
connectionStatusText = serverPane.findViewById(R.id.connection_status_text);
showServerConfig();
- ((TextView) serverPane.findViewById(R.id.import_hint))
- .setText(getString(R.string.import_hint, configDirHint()));
serverPane.findViewById(R.id.server_save_button).setOnClickListener(v -> {
- if (saveServerConfig(textOf(serverUrlInput), textOf(serverTokenInput), textOf(installationIdInput))) {
+ if (saveServerConfig(textOf(serverUrlInput), textOf(serverTokenInput),
+ ServerConfig.get(this).installationId)) {
setConnectionStatus(COLOR_OK, getString(R.string.server_saved));
}
});
@@ -485,7 +485,7 @@ public class MainActivity extends AppCompatActivity {
ServerConfig config = ServerConfig.get(this);
serverUrlInput.setText(config.url);
serverTokenInput.setText(config.token);
- installationIdInput.setText(config.installationId);
+ installationIdText.setText(getString(R.string.installation_id_info, config.installationId));
}
/** Validates, marks the bad fields, and saves only when all three are good. */
@@ -495,9 +495,12 @@ public class MainActivity extends AppCompatActivity {
String id = rawId == null ? "" : rawId.trim().toLowerCase(java.util.Locale.US);
serverUrlLayout.setError(url == null ? getString(R.string.server_err_url) : null);
serverTokenLayout.setError(ServerConfig.isValidToken(token) ? null : getString(R.string.server_err_token));
- installationIdLayout.setError(ServerConfig.isValidInstallationId(id)
- ? null : getString(R.string.server_err_installation_id));
- if (url == null || !ServerConfig.isValidToken(token) || !ServerConfig.isValidInstallationId(id)) return false;
+ // Only an imported config file can bring a different id; the field is not editable.
+ if (!ServerConfig.isValidInstallationId(id)) {
+ setConnectionStatus(COLOR_ERROR, getString(R.string.server_err_installation_id));
+ return false;
+ }
+ if (url == null || !ServerConfig.isValidToken(token)) return false;
ServerConfig.save(this, url, token, id);
if (consumptionCloudClient != null) consumptionCloudClient.invalidateHistory();
showServerConfig();
@@ -513,15 +516,11 @@ public class MainActivity extends AppCompatActivity {
private void testConnection() {
String url = ServerConfig.normalizeUrl(textOf(serverUrlInput));
String token = textOf(serverTokenInput);
- String id = textOf(installationIdInput).toLowerCase(java.util.Locale.US);
+ String id = ServerConfig.get(this).installationId;
if (url == null) {
serverUrlLayout.setError(getString(R.string.server_err_url));
return;
}
- if (!ServerConfig.isValidInstallationId(id)) {
- installationIdLayout.setError(getString(R.string.server_err_installation_id));
- return;
- }
setConnectionStatus(COLOR_PENDING, getString(R.string.conn_testing));
new Thread(() -> {
String message;
@@ -563,9 +562,7 @@ public class MainActivity extends AppCompatActivity {
return;
}
serverUrlLayout.setError(null);
- String typedId = textOf(installationIdInput).toLowerCase(java.util.Locale.US);
- String installationId = ServerConfig.isValidInstallationId(typedId)
- ? typedId : ServerConfig.get(this).installationId;
+ String installationId = ServerConfig.get(this).installationId;
PhoneQrDialog ui = new PhoneQrDialog(R.string.pair_title, R.string.pair_starting);
final boolean[] cancelled = ui.cancelled;
@@ -973,7 +970,6 @@ public class MainActivity extends AppCompatActivity {
// Show what the file said, so the marked field is the one to fix in the file.
if (config.serverUrl != null) serverUrlInput.setText(config.serverUrl);
if (config.token != null) serverTokenInput.setText(config.token);
- if (config.installationId != null) installationIdInput.setText(config.installationId);
return false;
}
}
diff --git a/app/src/main/res/layout/pane_server.xml b/app/src/main/res/layout/pane_server.xml
index 850ed83..51b5762 100644
--- a/app/src/main/res/layout/pane_server.xml
+++ b/app/src/main/res/layout/pane_server.xml
@@ -1,6 +1,6 @@
-
+
@@ -11,22 +11,16 @@
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6380df6..0bf61cb 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -60,6 +60,7 @@
Save
Test connection
Import from file
+ Installation ID %1$s · derived from the head unit; your data is stored under it
Car server
@@ -67,8 +68,6 @@
For example https://car.k8s.stinnesbeck.com
Ingest token
The server\'s INGEST_TOKEN, at least 24 characters
- Installation ID
- Your data is stored under this ID. Keep it when reinstalling.
Enter an https:// URL
Pair with phone
Shows a QR code: scan it with your phone and approve with the approval password. The token below is then filled in for you.
@@ -92,7 +91,6 @@
Not a valid ID (UUID)
Server settings saved
Server not configured — open the Server tab
- Put a text file with server_url and token in %1$s (on the head unit or a USB stick in the same folder), then press Import.
Config imported and saved — press Test to verify
diff --git a/app/src/main/res/values/strings_design.xml b/app/src/main/res/values/strings_design.xml
index 9f4d9e0..1c8dc16 100644
--- a/app/src/main/res/values/strings_design.xml
+++ b/app/src/main/res/values/strings_design.xml
@@ -8,7 +8,7 @@
Your drive at a glance.
Data from your car, all in one place.
Where your data goes.
- Your own server stores it and passes it on to ABRP.
+ Your own server stores it; the car sends live data to ABRP itself.
Live data.
Where your car\'s live data goes, and how often.
Settings.
@@ -19,8 +19,6 @@
VEHICLE INFO
TIRE PRESSURES
SERVER LINK
- Your private connection.
- The token lets the car write to your server. It is stored encrypted on this device; your ABRP credentials stay on the server.
Values that cannot be read are shown as —.
LIVE DATA
ABRP, DIRECTLY FROM THE CAR