diff --git a/SPECS.md b/SPECS.md index b067264..aa56f6f 100644 --- a/SPECS.md +++ b/SPECS.md @@ -42,8 +42,6 @@ what has been changed, and what is still to do. - 2026-10-17 — Renamed to "Nils' MG4": package ID `com.stinnesbeck.nilsmg4` (`.unstable` for the car build), APK names `NilsMG4-*.apk`. It installs next to the old FatihsMG4 app instead of replacing it, and starts with empty settings and history. -- 2026-10-17 — Diagnostics section on the Logs tab: UID, signer, car permissions, last vehicle - read and its error, and the vehicle library's in-app log. For debugging without adb. ## Installing on the car diff --git a/app/src/main/java/com/evsuite/abrp/MainActivity.java b/app/src/main/java/com/evsuite/abrp/MainActivity.java index 8d96209..475686c 100644 --- a/app/src/main/java/com/evsuite/abrp/MainActivity.java +++ b/app/src/main/java/com/evsuite/abrp/MainActivity.java @@ -102,16 +102,6 @@ public class MainActivity extends AppCompatActivity { private ChargeSessionTracker chargeSessionTracker; private ChargingGraphView chargeGraph; - /** - * What the vehicle reads last did, for the diagnostics section of the Logs page. A failed - * read leaves the cells showing a dash, which looks the same as a signal the car does not - * publish; this is the only on-screen trace of why. - */ - private TextView diagnosticsText; - private volatile EnergySnapshot lastVehicleSnapshot; - private volatile long lastVehicleReadOkMs; - private volatile String lastVehicleReadError; - /** * Inflates a page with no parent, then gives it the MATCH_PARENT/MATCH_PARENT layout * params ViewPager2 requires of its items — inflating detached leaves them null, and @@ -178,7 +168,6 @@ public class MainActivity extends AppCompatActivity { } ((TextView) findViewById(R.id.header_title)).setText(PAGE_TITLES[position]); ((TextView) findViewById(R.id.header_subtitle)).setText(PAGE_SUBTITLES[position]); - if (panes[position] == logPane) refreshDiagnostics(); } /** Refreshes state + call log while the screen is visible. */ @@ -227,9 +216,6 @@ public class MainActivity extends AppCompatActivity { statusText = servicePane.findViewById(R.id.status_text); callLogText = logPane.findViewById(R.id.call_log_text); logPane.findViewById(R.id.flush_now_button).setOnClickListener(v -> manualFlush()); - diagnosticsText = logPane.findViewById(R.id.diagnostics_text); - logPane.findViewById(R.id.diagnostics_refresh_button) - .setOnClickListener(v -> refreshDiagnostics()); setUpPager(); findViewById(R.id.about_button).setOnClickListener(v -> showAbout()); @@ -421,8 +407,6 @@ public class MainActivity extends AppCompatActivity { } // The timestamp is passed explicitly: its Kotlin default is not visible from Java. EnergySnapshot s = vehicleReader.read(System.currentTimeMillis()); - lastVehicleSnapshot = s; - lastVehicleReadOkMs = System.currentTimeMillis(); ConsumptionTracker.get(this).sample(s); refreshCharging(s); @@ -439,12 +423,8 @@ public class MainActivity extends AppCompatActivity { vehTireFr.setText(fmt(s.getTirePressures().getFrontRightKpa(), "%.0f kPa")); vehTireRl.setText(fmt(s.getTirePressures().getRearLeftKpa(), "%.0f kPa")); vehTireRr.setText(fmt(s.getTirePressures().getRearRightKpa(), "%.0f kPa")); - } catch (Throwable t) { - // Leave the last good reading on screen, but keep the reason for the diagnostics. - String trace = android.util.Log.getStackTraceString(t); - lastVehicleReadError = new java.text.SimpleDateFormat("HH:mm:ss", java.util.Locale.US) - .format(new java.util.Date()) + " " - + (trace.length() > 2000 ? trace.substring(0, 2000) + "…" : trace); + } catch (Throwable ignored) { + // Leave the last good reading on screen. } } @@ -769,84 +749,6 @@ public class MainActivity extends AppCompatActivity { callLogText.setText(sb.toString()); } - // ---------- Diagnostics ---------- - - /** - * Fills the diagnostics section: who the app runs as, how it is signed, which car - * permissions it holds, what the last vehicle read returned, and the in-app log of the - * vehicle library. On the head unit there is no adb, so this is what can be photographed. - */ - private void refreshDiagnostics() { - if (diagnosticsText == null) return; - java.text.SimpleDateFormat time = new java.text.SimpleDateFormat("HH:mm:ss", java.util.Locale.US); - StringBuilder sb = new StringBuilder(); - int uid = android.os.Process.myUid(); - sb.append("Package ").append(getPackageName()).append('\n'); - sb.append("Version ").append(BuildConfig.VERSION_NAME).append('\n'); - sb.append("UID ").append(uid) - .append(uid == android.os.Process.SYSTEM_UID ? " (system — OK)" : " (NOT system)").append('\n'); - sb.append("Firmware ").append(safe(() -> com.evsuite.hardware.FirmwareInfo.INSTANCE.getDetectedString())) - .append('\n'); - PackageManager pm = getPackageManager(); - try { - @SuppressWarnings("deprecation") - android.content.pm.PackageInfo info = pm.getPackageInfo(getPackageName(), - PackageManager.GET_SIGNATURES | PackageManager.GET_PERMISSIONS); - if (info.signatures != null && info.signatures.length > 0) { - byte[] digest = java.security.MessageDigest.getInstance("SHA-256") - .digest(info.signatures[0].toByteArray()); - StringBuilder hex = new StringBuilder(); - for (byte b : digest) hex.append(String.format(java.util.Locale.US, "%02x", b)); - sb.append("Signer ").append(hex).append('\n'); - } - if (info.requestedPermissions != null) { - sb.append("Permissions\n"); - for (String p : info.requestedPermissions) { - if (!p.startsWith("android.car.")) continue; - boolean granted = checkSelfPermission(p) == PackageManager.PERMISSION_GRANTED; - sb.append(" ").append(granted ? "granted " : "DENIED ") - .append(p.substring(p.lastIndexOf('.') + 1)).append('\n'); - } - } - } catch (Exception e) { - sb.append("Package info unavailable: ").append(e).append('\n'); - } - - sb.append('\n').append("Last vehicle read ") - .append(lastVehicleReadOkMs > 0 ? time.format(new java.util.Date(lastVehicleReadOkMs)) : "never") - .append('\n'); - EnergySnapshot s = lastVehicleSnapshot; - if (s != null) { - sb.append(" SOC ").append(s.getSocPercent()) - .append(" range ").append(s.getRangeKm()) - .append(" speed ").append(s.getSpeedKmh()) - .append(" power ").append(s.getBatteryPowerKw()).append('\n') - .append(" odometer ").append(s.getOdometerKm()) - .append(" charge status ").append(s.getChargingStatus()) - .append(" port ").append(s.getChargePortConnected()).append('\n'); - } - String error = lastVehicleReadError; - if (error != null) sb.append("Last read error ").append(error).append('\n'); - - java.util.List entries = - com.evsuite.hardware.AppLogger.INSTANCE.getEntries(); - int shown = Math.min(entries.size(), 200); - sb.append('\n').append("Vehicle library log (newest first, ").append(shown) - .append(" of ").append(entries.size()).append(")\n"); - for (int i = entries.size() - 1; i >= entries.size() - shown; i--) { - com.evsuite.hardware.AppLogger.Entry e = entries.get(i); - sb.append(e.getTime()).append(' ').append(e.getLevel().name().charAt(0)).append('/') - .append(e.getTag()).append(": ").append(e.getMsg()).append('\n'); - } - diagnosticsText.setText(sb.toString()); - } - - private interface StringSupplier { String get() throws Exception; } - - private static String safe(StringSupplier supplier) { - try { return supplier.get(); } catch (Throwable t) { return "unavailable (" + t + ")"; } - } - // ---------- Service status ---------- private void refreshStatus() { diff --git a/app/src/main/res/layout/pane_log.xml b/app/src/main/res/layout/pane_log.xml index 7049563..31ea5d8 100644 --- a/app/src/main/res/layout/pane_log.xml +++ b/app/src/main/res/layout/pane_log.xml @@ -4,8 +4,5 @@ - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 11039fa..341259d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -107,8 +107,6 @@ Recent uploads No upload attempted yet. - Diagnostics - Refresh diagnostics Upload now Starting… Running — waiting for first upload