Documentation
Code Quality & Test Coverage Audit Report
Project: Drive Assist (com.geely.drivemem)
Target Platform: Geely EX2 / Geometry E (IHU629G Head Unit, Android 9 / API 28)
Date: 2026-09-10 (Section 2 refreshed 2026-09-24 — see its own note on the methodology change; Sections 3+ are unchanged from the original audit and predate the test/coverage growth below)
Status: Integrated & Verified Baseline
1. Executive Summary
This report documents the implementation and results of the automated code quality and test coverage pipeline established for the Drive Assist automotive application.
Key milestones achieved:
- JaCoCo Unit Test Coverage: Fully integrated into the Gradle build system (
jacocoTestReport), producing unified XML and HTML reports for the debug variant while ensuring the production release build (:drivemem:assembleRelease) remains completely unmodified. - Android Lint Tuning: Custom-tuned for Android 9 / API 28 automotive environment, suppressing irrelevant Play Store policy errors (
ExpiredTargetSdkVersion,MissingTranslation,MissingPermission,ObsoleteSdkInt) while elevating critical string format errors (StringFormatMatches,StringFormatInvalid). - Basque Localization Fix: Resolved a critical runtime format crash in Basque translation (
values-eu/strings.xml:222) where unescaped%100resulted in argument count mismatch. - Checkstyle Integration: Configured with a dedicated rule set (
config/checkstyle/checkstyle.xml) tuned for Java 8/11 Android development, establishing an automated style baseline. - SpotBugs Integration: Configured with custom exclude filters (
config/spotbugs/exclude.xml) ignoring generated Android artifacts (R.class,BuildConfig.class) and intentional singletons while surfacing real multithreading and I/O hazards. - Code Quality Catalog: Detailed analysis of 12 deprecated APIs, 10 cyclomatic complexity hotspots, and critical lifecycle management gaps across activities and background services.
2. Test Execution & Coverage Metrics
2.1 Test Execution Summary
The unit test suite consists of pure JUnit 4 tests executed against mock environments and data models:
| Metric | Value |
|---|---|
| Total Test Suites | 35 suites |
| Total Tests Executed | 325 tests |
| Failures | 0 |
| Errors | 0 |
| Skipped | 0 |
| Pass Rate | 100.0% |
| Execution Duration | ~1.0s (test task only) |
Test Suite Breakdown
| Test Suite | Tests | Failures | Time | Primary Focus |
|—|—|—|—|—|
| com.geely.drivemem.EffortTableTest | 39 | 0 | 0.014s | HVAC comfort ruler interpolation and effort lookup tables |
| com.geely.drivemem.ComfortCardVisibilityTest | 36 | 0 | 0.017s | Comfort-screen card visibility rules (gate, turbo, charging, journey, HA panel) |
| com.geely.drivemem.ChargeSessionTest | 19 | 0 | 0.013s | Battery charging session start/stop, energy tracking, crash recovery |
| com.geely.drivemem.ClipsTest | 18 | 0 | 0.030s | Media clip index parsing and timestamp math |
| com.geely.drivemem.TripSessionTest | 16 | 0 | 0.007s | Trip park/drive edge detection, grace periods, segment stitching |
| com.geely.drivemem.sensors.DrivingConsumptionTest | 16 | 0 | 0.003s | Driving energy/speed-bucket accumulation, measured-vs-estimated tally |
| com.geely.drivemem.DailyStatsProviderTest | 16 | 0 | 0.033s | Daily/weekly/monthly statistics aggregation |
| com.geely.drivemem.sensors.EnergySourceTest | 11 | 0 | 0.001s | Measured/estimated/mixed energy-source classification and combine() |
| com.geely.drivemem.CarDataHubApplyTest | 11 | 0 | 0.017s | Car property updates and VHAL property mapping |
| com.geely.drivemem.GateStateTest | 10 | 0 | 0.008s | Gate open/closed state, connected/sender consistency, press() gating |
| com.geely.drivemem.EnergyIntegratorTest | 10 | 0 | 0.002s | Trapezoidal power integration, trip/window energy accumulators |
| com.geely.drivemem.CarDataHubTest | 10 | 0 | 0.005s | Signal bus dispatch and listener registration |
| com.geely.drivemem.CarDbSqliteTest | 9 | 0 | 0.266s | Real SQLite schema creation, migration, and query correctness against CarDb |
| com.geely.drivemem.ModesTest | 8 | 0 | 0.002s | Vehicle drive mode (Eco/Sport) and regen state machines |
| com.geely.drivemem.CertImporterTest | 7 | 0 | 0.292s | TLS PKCS12 / PEM certificate import and validation |
| com.geely.drivemem.UpdaterInstallGateTest | 6 | 0 | 0.000s | OTA install-blocked gate: charging/session/grace-period checks |
| com.geely.drivemem.TelemetryTest | 6 | 0 | 0.004s | Telemetry number formatting and rounding rules |
| com.geely.drivemem.OdoStatsTest | 6 | 0 | 0.005s | Odometer math, delta calculations, and daily counters |
| com.geely.drivemem.MusicStateTest | 6 | 0 | 0.005s | Media session metadata and playback state |
| com.geely.drivemem.DailyStatsProviderSqliteTest | 6 | 0 | 0.021s | Real SQL query tests for daily/period energy-balance aggregation |
| com.geely.drivemem.ChargeSessionLogTest | 6 | 0 | 0.019s | Charging session CSV export and log rotation |
| com.geely.drivemem.sensors.Obd2ReaderTest | 5 | 0 | 0.001s | Regression coverage for the single-dropped-packet “shown as estimated” bug |
| com.geely.drivemem.controls.PurgeTest | 5 | 0 | 0.002s | Per-window crack-open target regulator math |
| com.geely.drivemem.CarTraceTest | 5 | 0 | 0.005s | Car property change tracing/logging |
| com.geely.drivemem.CarActorHarnessScenarioTest | 5 | 0 | 0.049s | Deterministic CarActor scenarios via the synchronous test harness |
| com.geely.drivemem.AbrpUploaderTest | 5 | 0 | 0.041s | ABRP telemetry JSON payload serialization |
| com.geely.drivemem.TelemetryChargingSourceTest | 4 | 0 | 0.001s | car.is_charging derivation from charge_a + plug_connected |
| com.geely.drivemem.PanelStateTest | 4 | 0 | 0.002s | Comfort panel UI display state |
| com.geely.drivemem.MqttDiscoveryTest | 4 | 0 | 0.001s | Home Assistant MQTT discovery JSON payloads |
| com.geely.drivemem.UpdaterCacheBustTest | 3 | 0 | 0.007s | OTA URL cache-busting shared by check()/update() |
| com.geely.drivemem.ui.ChargeCostDialogTest | 3 | 0 | 0.031s | Charge-cost entry dialog input parsing |
| com.geely.drivemem.MqttTlsTest | 3 | 0 | 0.110s | MQTT TLS handshake/config |
| com.geely.drivemem.net.AbrpSamplerTest | 2 | 0 | 0.001s | ABRP sampler poll-delay cadence (active vs. idle) |
| com.geely.drivemem.EntityBusTest | 2 | 0 | 0.001s | Pub/sub bus change-only delivery and duplicate-listener semantics |
| com.geely.drivemem.CarActorDeriveTest | 2 | 0 | 0.027s | deriveFrom() computed-property recomputation on every ingest |
| com.geely.drivemem.sensors.CarTraceConsumptionTest | 1 | 0 | 0.003s | Car trace consumption helper |
2.2 JaCoCo Code Coverage Metrics
Methodology unchanged since the 2026-09-14 refresh (see git history for that note); numbers below are a straight refresh of the same scoped measurement, run 2026-09-24 after this session’s test additions (typed Prefs, real-SQLite tests, the CarActor test harness, ComfortCardVisibility, and the energy-source/gate fixes). The jacocoTestReport task excludes ui/, art/, services/, and controls/ from the coverage ratio — those packages have no unit-test harness (no Robolectric; they’re exercised on a real device instead), so folding their all-zero instruction counts into the denominator measured “how much of the app is UI” rather than “how much of the tested logic is tested.” The excluded code is still compiled and shipped, and still covered — just by on-device testing instead of this report.
JaCoCo code coverage was captured during testDebugUnitTest, scoped to the testable packages (hvac, state, car, sensors, net, util, plus the top-level package):
| Counter Type | Total | Covered | Missed | Coverage % |
|---|---|---|---|---|
| Instructions | 42,315 | 8,395 | 33,920 | 19.84% |
| Branches | 4,460 | 950 | 3,510 | 21.30% |
| Lines | 7,231 | 1,633 | 5,598 | 22.58% |
| Cyclomatic Complexity | 3,443 | 642 | 2,801 | 18.65% |
| Methods | 1,191 | 289 | 902 | 24.27% |
| Classes | 123 | 53 | 70 | 43.09% |
Package Coverage Breakdown (testable packages only)
| Package | Instructions Covered | Instruction % | Lines Covered | Line % | Branches Covered | Branch % |
|—|—|—|—|—|—|—|
| com.geely.drivemem.car | 2,221 / 5,908 | 37.6% | 346 / 904 | 38.3% | 181 / 495 | 36.6% |
| com.geely.drivemem.state | 1,805 / 5,202 | 34.7% | 493 / 1,097 | 44.9% | 207 / 708 | 29.2% |
| com.geely.drivemem.hvac | 726 / 2,625 | 27.7% | 105 / 431 | 24.4% | 137 / 402 | 34.1% |
| com.geely.drivemem.sensors | 2,112 / 8,517 | 24.8% | 402 / 1,503 | 26.7% | 237 / 996 | 23.8% |
| com.geely.drivemem.net | 1,118 / 10,341 | 10.8% | 225 / 1,732 | 13.0% | 151 / 1,111 | 13.6% |
| com.geely.drivemem.util | 413 / 9,683 | 4.3% | 62 / 1,545 | 4.0% | 37 / 748 | 4.9% |
| com.geely.drivemem (root) | 0 / 39 | 0.0% | 0 / 19 | 0.0% | — | — |
car and state overtook hvac as the best-covered packages this session — the CarActor test harness, EntityBus/CarDataHub tests, ChargeSession/TripSession/GateState growth, and ComfortCardVisibility (extracted specifically to make it unit-testable) all landed there.
Excluded from the ratio (compiled and shipped; exercised on a real device instead of a JVM unit test — sizes below are from the 2026-09-14 baseline, not re-measured this pass, and have likely grown given this session’s TelemetryActivity split into per-section ui/ classes):
| Package | Instructions | Why excluded |
|—|—|—|
| com.geely.drivemem.ui | ~20,700 | Activities/custom Views — need a real window manager |
| com.geely.drivemem.art | ~5,300 | Canvas art renderers — visual output, checked by eye on-device |
| com.geely.drivemem.services | ~2,000 | Background services — need NotificationManager/system state |
| com.geely.drivemem.controls | ~1,700 | Physical car-control widgets — need a live VHAL connection |
Key Classes Coverage Analysis
- High Coverage Models & Logic (≥50 instructions, top-level classes):
com.geely.drivemem.state.GateState: 100.0% instruction coveragecom.geely.drivemem.sensors.EnergySource: 100.0% instruction coveragecom.geely.drivemem.hvac.EffortTable: 97.9% instruction coveragecom.geely.drivemem.util.Modes: 96.9% instruction coveragecom.geely.drivemem.sensors.DrivingConsumption: 95.8% instruction coveragecom.geely.drivemem.state.MusicState: 92.3% instruction coveragecom.geely.drivemem.car.CarDataHub: 91.6% instruction coveragecom.geely.drivemem.sensors.EnergyIntegrator: 86.6% instruction coveragecom.geely.drivemem.car.EntityBus: 77.8% instruction coveragecom.geely.drivemem.car.Telemetry: 69.2% instruction coverage
- Largest Untested Classes (0% coverage, by instruction count — the real next targets, distinct from the excluded packages above):
com.geely.drivemem.net.MqttReporter(4,497 instructions)com.geely.drivemem.util.Style(2,650 instructions)com.geely.drivemem.util.Diagnostics(2,067 instructions)com.geely.drivemem.hvac.ComfortRuler(1,160 instructions)com.geely.drivemem.sensors.TelemetryRollup(913 instructions)com.geely.drivemem.sensors.Obd2Reader(1,220 instructions)com.geely.drivemem.hvac.ComfortRuler(1,160 instructions)com.geely.drivemem.net.Updater(1,023 instructions)com.geely.drivemem.sensors.TelemetryRollup(898 instructions)com.geely.drivemem.car.CarActor(866 instructions)
- Coverage Gap Root Cause:
- Most of the remaining gap within the testable packages is integration-shaped code:
MqttReporter,Obd2Reader,CarActor, andUpdatertalk directly to a live broker, a Bluetooth OBD2 adapter, the VHAL, or the network — none of which exist in a JVM unit test without a fake/mocked transport layer, and none of those fakes have been built yet. Styleis almost entirely AndroidView/GradientDrawable/Canvasconstruction — the same shape as the excludedui/artpackages, it just hasn’t been moved out ofutilto join them.
- Most of the remaining gap within the testable packages is integration-shaped code:
3. Static Code Analysis: Android Lint
3.1 Configuration Rationale (Android 9 / API 28 Automotive Head Unit)
The application is deployed directly to the vehicle head unit (Geely IHU629G / ECARX 250060) as a sideloaded system utility. It is not distributed via Google Play. Standard Android Lint settings produce extensive false positives that obstruct build pipelines:
ExpiredTargetSdkVersion: Google Play requires API 33+, whereas the vehicle OS is Android 9 (API 28). Disabled to permit targeting API 28.MissingTranslation: Non-blocking partial localizations (e.g. Catalan, Basque, Hungarian). Suppressed to prevent translation gaps from breaking compilation.MissingPermission: FlaggedBluetoothAdapter.enable()for missingandroid.permission.BLUETOOTH_CONNECT.BLUETOOTH_CONNECTis an API 31+ runtime permission that does not exist in API 28. Suppressed as a false positive.ObsoleteSdkInt: Redundant backward compatibility guards (Build.VERSION.SDK_INT >= 26) retained intentionally for potential deployment across legacy ECARX variants. Suppressed.StringFormatMatches&StringFormatInvalid: Elevated to fatal errors to catch format string mismatch crashes at compile time.
3.2 String Formatting Defect Remediated
- Defect: In
ComfortActivity.java:1259:chargeRemainingView.setText(getString(R.string.charge_card_remaining, remainingMs / 60000));The Basque translation in
drivemem/src/main/res/values-eu/strings.xml:222contained:<!-- BEFORE: Format crash --> <string name="charge_card_remaining">~%1$d min %100era arte</string>Because
%100lacks escaping (%%),String.format()treats%10as a reference to a 10th argument or malformed conversion. At runtime, when the vehicle language was set to Basque during charging,getString()threwjava.util.UnknownFormatConversionException/MissingFormatArgumentException, crashing the launcher activity. - Fix Applied:
<!-- AFTER: Escaped percentage --> <string name="charge_card_remaining">~%1$d min %%100era arte</string>Verification confirmed
StringFormatMatchesis now 0 violations across all resource bundles.
3.3 Lint Summary Findings
- Total Warnings: 381
- Total Errors: 7 (Unescaped
%character incfg_bar_socacross 7 language files:values-ca,values-hu,values-eu,values-b+es+419,values-es-rUS,values-es,values-tl) - Key Warning Categories:
TypographyEllipsis(282 occurrences): Plain three-dot ellipsis...instead of Unicode….UnusedResources(39 occurrences): Unreferenced drawables and layout identifiers.SetTextI18n(13 occurrences): Hardcoded strings concatenated into TextViews.DefaultLocale(8 occurrences):String.format()ortoLowerCase()called without explicitLocale.ROOTorLocale.US.StaticFieldLeak(6 occurrences): StaticContextfields inAbrpUploader,CarActor,ComfortHub,Obd2Reader,SpotifyClient, andTurboMode.
4. Static Code Analysis: Checkstyle
4.1 Configuration
Checkstyle 10.12.7 was configured via config/checkstyle/checkstyle.xml with rules tailored for Android Java 8/11 development:
- Enforces curly braces on all control structures (
NeedBraces). - One statement per line (
OneStatementPerLine) and one variable declaration per line (MultipleVariableDeclarations). - Prohibits unused (
UnusedImports), redundant (RedundantImport), and wildcard imports (AvoidStarImport). - Requires whitespace after commas/typecasts and checks naming conventions.
4.2 Findings Summary
A total of 2,338 warnings across 68 files were recorded:
| Checkstyle Rule | Violations | Description |
|---|---|---|
NeedBracesCheck |
788 | Single-line if, for, while statements without braces |
LeftCurlyCheck |
624 | Inconsistent brace placement on method/class headers |
OneStatementPerLineCheck |
551 | Compact ternary or assignment chains on a single line |
MultipleVariableDeclarationsCheck |
145 | Multiple fields declared on a single line (e.g., int a = 1, b = 2;) |
UnusedImportsCheck |
118 | Leftover unused import statements across activities |
RightCurlyCheck |
72 | Closing brace formatting on else / catch blocks |
WhitespaceAfterCheck |
36 | Missing space after commas or cast operators |
MissingSwitchDefaultCheck |
2 | Switch statements lacking a default case branch |
ModifierOrderCheck |
1 | Non-standard modifier order (e.g. final static instead of static final) |
RedundantModifierCheck |
1 | Redundant public on interface method |
5. Static Code Analysis: SpotBugs
5.1 Configuration
SpotBugs 6.0.26 was integrated with Effort.MAX and Confidence.MEDIUM. Filter config/spotbugs/exclude.xml eliminates generated classes (R$*, BuildConfig) and intentional singleton context caches.
5.2 Findings Summary
A total of 117 SpotBugs issues were identified across 6 categories:
| Category | Count | Primary Implications |
|---|---|---|
| BAD_PRACTICE | 39 | Ignored return values, non-standard comparator contracts |
| MALICIOUS_CODE | 29 | Public static mutable fields and arrays |
| MT_CORRECTNESS | 20 | Static DateFormat instances invoked across threads |
| I18N | 18 | String.getBytes() or FileReader using default platform encoding |
| STYLE | 8 | Unread fields, non-short-circuit boolean evaluation |
| PERFORMANCE | 3 | Boxing in loops, suboptimal random usage |
Critical SpotBugs Patterns
STCAL_INVOKE_ON_STATIC_DATE_FORMAT_INSTANCE(18 occurrences):java.text.SimpleDateFormatis not thread-safe. Static formatters shared across threads inTelemetryActivity,MqttReporter, andChargeSessionLogcan corrupt date strings or throw exceptions during concurrent vehicle state updates.- Remediation: Replace with
java.time.format.DateTimeFormatter(thread-safe) or wrap inThreadLocal<SimpleDateFormat>.
DM_DEFAULT_ENCODING(18 occurrences):- Relying on the default platform charset when writing CSV logs or reading config files creates silent data corruption when moving between head unit firmware builds.
- Remediation: Explicitly pass
StandardCharsets.UTF_8.
RV_RETURN_VALUE_IGNORED_BAD_PRACTICE(12 occurrences):- Return values of
File.mkdirs()andFile.delete()are ignored inCertImporter,ChargeSessionLog, andAdbGate. If storage is full or read-only, failures occur silently. - Remediation: Check return boolean and log error conditions.
- Return values of
6. Catalog of Deprecated APIs
Direct compilation inspection with javac -Xlint:deprecation identified 12 distinct deprecated API patterns:
| # | Deprecated API | Deprecated In | Recommended Replacement | Project Locations |
|---|---|---|---|---|
| 1 | BluetoothAdapter.getDefaultAdapter() |
API 31 | BluetoothManager.getAdapter() |
Obd2Reader.java:291, 321, 439CarplayState.java:64 |
| 2 | BluetoothAdapter.enable() |
API 33 | User prompt via ACTION_REQUEST_ENABLE |
CarplayState.java:67 |
| 3 | BluetoothGattDescriptor.setValue(byte[])BluetoothGatt.writeDescriptor(desc) |
API 33 | BluetoothGatt.writeDescriptor(desc, value) |
Obd2Reader.java:580, 581 |
| 4 | BluetoothGattCallback.onCharacteristicChanged(gatt, char)BluetoothGattCharacteristic.getValue() |
API 33 | onCharacteristicChanged(gatt, char, byte[]) |
Obd2Reader.java:590, 591 |
| 5 | BluetoothGattCharacteristic.setValue(byte[])BluetoothGatt.writeCharacteristic(char) |
API 33 | BluetoothGatt.writeCharacteristic(char, byte[], writeType) |
Obd2Reader.java:676, 677 |
| 6 | WifiManager.setWifiEnabled(boolean) |
API 29 | Settings.Panel.ACTION_WIFI / Privileged API |
BootReceiver.java:123, 211OutTempService.java:55 |
| 7 | LayoutParams.FLAG_TRANSLUCENT_STATUSView.SYSTEM_UI_FLAG_*View.setSystemUiVisibility(int) |
API 30 | WindowInsetsController |
Style.java:242, 245, 249, 250 |
| 8 | WifiManager.getConnectionInfo()WifiManager.getDhcpInfo() |
API 31 | ConnectivityManager.getNetworkCapabilities() |
AdbGate.java:64, 120WifiIconService.java:76, 85 |
| 9 | WifiManager.calculateSignalLevel(int, int) |
API 30 | WifiManager.calculateSignalLevel(int) |
WifiIconService.java:78 |
| 10 | PackageInfo.versionCode |
API 28 | PackageInfo.getLongVersionCode() |
Updater.java:117 |
| 11 | X509Certificate.getSubjectDN() |
Java 16 | X509Certificate.getSubjectX500Principal() |
MqttTls.java:105 |
| 12 | LocationListener.onStatusChanged(String, int, Bundle) |
API 29 | Removed / default no-op in API 29+ | TelemetryService.java:169 |
7. Cyclomatic Complexity Hotspots
7.1 Top 10 Most Complex Classes
Branch token analysis (if, for, while, case, catch, &&, ||, ?):
| Rank | Class / File | Total Lines | Total Complexity | Key Responsibilities & Architectural Burden |
|---|---|---|---|---|
| 1 | com.geely.drivemem.ui.TelemetryActivity |
2,456 | 274 | Monolithic activity: MQTT UI, live logs, diagnostic series, certificate importation |
| 2 | com.geely.drivemem.ui.ComfortActivity |
1,685 | 265 | Main launcher UI: column layout, climate ruler, gate card, modal dialogs |
| 3 | com.geely.drivemem.net.MqttReporter |
1,404 | 260 | MQTT discovery JSON serialization, payload dispatch, connection state machine |
| 4 | com.geely.drivemem.sensors.Obd2Reader |
746 | 171 | BLE scanner, GATT characteristics parser, ELM327 protocol engine |
| 5 | com.geely.drivemem.net.CertImporter |
753 | 166 | PKCS12 / PEM extraction, KeyStore installation, TLS socket validation |
| 6 | com.geely.drivemem.util.Diagnostics |
559 | 148 | ADB broadcast debug action dispatcher (FANTEST, AUDIOPROBE, MEMDUMP) |
| 7 | com.geely.drivemem.car.CarAccess |
633 | 138 | CarPropertyManager abstraction, property ID reflection, vendor adaptors |
| 8 | com.geely.drivemem.net.AbrpUploader |
539 | 128 | ABRP HTTP payload generator, upload state machine, file audit logger |
| 9 | com.geely.drivemem.hvac.ComfortRuler |
455 | 121 | Temperature target blending, AC/fan calculations, debounce rules |
| 10 | com.geely.drivemem.art.VaporArtView |
857 | 106 | Canvas rendering, starfield animation, Konami code particle animations |
7.2 Top 10 Most Complex Methods
| Rank | Class & Method | Line | Complexity | Method Description & Refactoring Priority |
|---|---|---|---|---|
| 1 | Obd2Reader.scanRecordName |
512 | 64 | Low-level BLE PDU record parser traversing raw advertising byte arrays. Refactor to separate binary parser. |
| 2 | ClipPlayerActivity.tick |
324 | 45 | Media player timer loop managing UI timeline, video sync, and state transitions. |
| 3 | AbrpUploader.buildTlm |
367 | 39 | Giant JSON telemetry builder mapping vehicle signals and GPS coordinates. |
| 4 | ComfortRuler.apply |
279 | 38 | Main climate control decision tree mapping target temp to physical HVAC actions. |
| 5 | ComfortActivity.stopCarActorPolls |
1,481 | 35 | Teardown and sensor poll unregistration sequence. |
| 6 | CertImporter.testTls |
620 | 34 | Multi-fallback TLS handshake testing custom SSLSocket factories. |
| 7 | Updater.check |
64 | 34 | Remote update checker parsing APK archive headers and version queries. |
| 8 | Telemetry.roundFor |
61 | 30 | Formatting and scale truncation rules across dozens of data channels. |
| 9 | DailyStatsProvider.getDayOverview |
204 | 29 | SQLite aggregation query over daily trip sessions. |
| 10 | Style.darken |
466 | 29 | Color arithmetic and theme palette shading. |
8. Unhandled Lifecycle States & Architectural Risks
8.1 Activity Lifecycle Deficiencies
TelemetryActivity.java:- Missing
onPauseandonStop: Event listeners (EntityBus,Obd2Reader,AbrpUploader) registered inonCreateremain active when the user switches to another app or the head unit screen sleeps. This leaks CPU cycles and battery. - Remediation: Unregister bus listeners in
onPause()/onStop()and re-register inonResume().
- Missing
ComfortActivity.java:- Missing
onSaveInstanceState/onRestoreInstanceState: If the system terminates the process while parked or during deep sleep, UI state (active card selections, ruler positions) resets to default values. - Remediation: Store active tab index and temporary settings in the saved instance state bundle.
- Missing
ClipPlayerActivity.java:- Missing
onStopandonSaveInstanceState. Media playback threads can remain active in background.
- Missing
8.2 Service Lifecycle Gaps
OutTempService,SocIconService,WifiIconService:- Pack all setup into
onStartCommand()without implementingonCreate(). - Lack
onTrimMemory()andonLowMemory()handlers. Under system memory pressure, Android may kill the services without cleanup, leaving orphan status bar notification icons.
- Pack all setup into
8.3 Ineffective Lifecycle Broadcasts
BootReceiver.java:101-112:- Registers manifest intent-filters for
Intent.ACTION_SCREEN_ONandIntent.ACTION_USER_PRESENT. In Android 8.0+ (API 26+), broadcast receivers registered in the manifest cannot receiveSCREEN_ONbroadcasts. - The application relies on
AlarmManager.ELAPSED_REALTIME_WAKEUPto wake periodically; the manifest receiver entries forSCREEN_ONare dead code and should be removed.
- Registers manifest intent-filters for
8.4 Static Context References
- Static references holding
Contextexist in:AbrpUploader.appCtxCarActor.appContextComfortHub.instanceObd2Reader.appCtxSpotifyClient.appCtxTurboMode.appContext
- While initialized via
getApplicationContext(), static references hinder unit testing and risk memory leaks during hot reload or instrumentation test cycles.
9. Verification & Pipeline Commands
All code quality and test coverage tasks are fully verified via Gradle:
# 1. Run unit tests and generate JaCoCo coverage reports
./gradlew test jacocoTestReport
# Artifacts:
# drivemem/build/reports/jacoco/test/jacocoTestReport.xml
# drivemem/build/reports/jacoco/test/html/index.html
# drivemem/build/reports/tests/testDebugUnitTest/index.html
# 2. Verify clean production release build (uninstrumented)
./gradlew :drivemem:assembleRelease
# Artifact:
# drivemem/build/outputs/apk/release/drive_assist.apk
# 3. Run all static analysis checks
./gradlew lint checkstyle spotbugs
# Artifacts:
# drivemem/build/reports/lint-results.html (.xml, .txt)
# drivemem/build/reports/checkstyle/checkstyle.html (.xml)
# drivemem/build/reports/spotbugs/spotbugs.html (.xml)