Harden WebView nav + add test suite + fix lint for production
Build APK / build (push) Successful in 1m29s
Build APK / build (push) Successful in 1m29s
Security: - LoginActivity WebView now enforces a host allow-list in shouldOverrideUrlLoading: only claude.ai + required SSO/CDN hosts (Google, Apple, Cloudflare, gstatic, recaptcha) can navigate; everything else is blocked. market://intent:// still blocked; about:/data: allowed. Device-verified: claude.ai login + Cloudflare challenge still load. Tests (33, pure-JVM JUnit4, no device needed): - Extracted shouldRecordHistory() pure throttle decision (regression guard for the empty-history-chart bug) + HistoryThrottleTest. - UsageDataTest (mergedWith last-good/partial-union, computed props), PaceCalcTest, PeakHoursTest. - Added junit:junit:4.13.2 as testImplementation only. Build quality: - widget_layout.xml: suppress false-positive UseAppTint lint on the widget refresh button (app:tint doesn't work in RemoteViews; android:tint is correct here) so lintDebug is clean. Verified locally: 33 unit tests pass, lintDebug 0 errors, signed assembleRelease OK (apksigner verified, signer identity unchanged), emulator smoke test launches + renders without crash.
This commit is contained in:
@@ -107,7 +107,7 @@ class PreferencesManager(context: Context) {
|
||||
// (Previously we deleted the last point and re-added in place — but the foreground loop
|
||||
// refreshes every 30s, well inside this 2-min window, so history could never grow past a
|
||||
// single point while the app was open and the chart stayed on "Collecting history…".)
|
||||
if (history.isNotEmpty() && now - history.last().epochMs < MIN_HISTORY_GAP_MS) return
|
||||
if (!shouldRecordHistory(history.lastOrNull()?.epochMs, now, MIN_HISTORY_GAP_MS)) return
|
||||
history.add(
|
||||
UsageSnapshot(
|
||||
epochMs = now,
|
||||
@@ -153,10 +153,21 @@ class PreferencesManager(context: Context) {
|
||||
private const val KEY_NOTIFY_ENABLED = "notify_enabled"
|
||||
private const val KEY_AUTH_FAILS = "auth_fail_count"
|
||||
|
||||
private const val MIN_HISTORY_GAP_MS = 2 * 60 * 1000L // collapse readings <2 min apart
|
||||
internal const val MIN_HISTORY_GAP_MS = 2 * 60 * 1000L // collapse readings <2 min apart
|
||||
private const val HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1000L // keep 7 days
|
||||
private const val MAX_HISTORY_POINTS = 600
|
||||
|
||||
/**
|
||||
* Pure throttle decision for [recordHistory]: should a new point be appended?
|
||||
* Returns false only when a previous point exists ([lastEpochMs] != null) AND the gap to
|
||||
* [now] is below [minGapMs]; true otherwise (including the first-ever point, lastEpochMs == null).
|
||||
* No Android dependencies — kept separate so the throttle rule is unit-testable.
|
||||
*/
|
||||
internal fun shouldRecordHistory(lastEpochMs: Long?, now: Long, minGapMs: Long): Boolean {
|
||||
if (lastEpochMs == null) return true
|
||||
return now - lastEpochMs >= minGapMs
|
||||
}
|
||||
|
||||
fun createSecurePrefs(context: Context, onFallback: (() -> Unit)? = null): android.content.SharedPreferences {
|
||||
return try {
|
||||
buildEncryptedPrefs(context)
|
||||
|
||||
Reference in New Issue
Block a user