From eb2ab62a585a88ddcd08569c5c4d8a1cb3a9eb3d Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Fri, 24 Oct 2025 10:52:01 +0000 Subject: [PATCH] docs: apply pin-point delta edits for correctness and polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Analysis doc improvements: - Add exact-alarm clarifier box: SCHEDULE_EXACT_ALARM is special app-op, not runtime permission - Add WAKE_LOCK usage tip: typically unnecessary with AlarmManager/WorkManager - Guard Cordova compat dependency: use debug/releaseImplementation with transitive=false - Add exported defaults reminder to manifest excerpt - Add asset path wording clarification: webDir → src/main/assets/public/ - Clarify POST_NOTIFICATIONS scope: required on Android 13+, ignored on lower APIs Implementation plan improvements: - Add Doze/Idle acceptance signal to Phase 1 DoD: UI surfaces 'Degraded timing (Doze)' - Add receiver export policy to PR checklist: only BootReceiver exported - Add ProGuard/R8 keep rules: prevent Capacitor annotations from being stripped - Enhance diagnostics payload: include appId, version, device info, API level, timezone, config, status fields, event IDs - Add negative schema case to Test Matrix: catches drift at JS boundary - Add channel invariants to acceptance criteria: missing/disabled channel returns proper errors - Add boot reschedule duplicate shield: unique key with UPSERT semantics - Add network client hard limits to AC: HTTPS-only, timeouts ≤ 30s, content ≤ 1MB All changes maintain existing structure with surgical precision edits. --- docs/android-app-analysis.md | 13 +++++++++++-- docs/android-app-improvement-plan.md | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/docs/android-app-analysis.md b/docs/android-app-analysis.md index a1e5205..3b73bee 100644 --- a/docs/android-app-analysis.md +++ b/docs/android-app-analysis.md @@ -127,6 +127,7 @@ public class MainActivity extends BridgeActivity { + + +> **Tip:** `WAKE_LOCK` is typically unnecessary with AlarmManager/WorkManager; remove unless you explicitly acquire/release your own wakelocks. +> **Note:** `POST_NOTIFICATIONS` is required **on Android 13+**; lower API levels ignore it gracefully. ``` **Critical Permissions**: @@ -207,6 +211,8 @@ public class MainActivity extends BridgeActivity { The `/www` directory (mapped to `assets/public/`) contains the web application that runs inside the Capacitor WebView: +> Capacitor builds copy your `webDir` (e.g., `www/`) to `src/main/assets/public/` on Android; the WebView serves from that `public/` folder. + ``` assets/public/ ├── index.html # Main test interface (549 lines) @@ -382,8 +388,9 @@ dependencies { implementation "androidx.work:work-runtime-ktx:2.9.0" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" - // Cordova Compatibility (only if shipping Cordova shims) - implementation project(':capacitor-cordova-android-plugins') + // Cordova compatibility (include ONLY if using Cordova plugins) + debugImplementation(project(':capacitor-cordova-android-plugins')) { transitive = false } + releaseImplementation(project(':capacitor-cordova-android-plugins')) { transitive = false } } ``` @@ -600,6 +607,8 @@ This architecture serves as both a practical testing tool and a reference implem If `SCHEDULE_EXACT_ALARM` is **granted** → schedule with `setExactAndAllowWhileIdle`. If **denied or quota-limited** → schedule via WorkManager (exp backoff + jitter) and surface `E_EXACT_ALARM_DENIED` (with "Degraded timing — Doze may delay" hint). +> **Exact Alarm note:** `SCHEDULE_EXACT_ALARM` is a **special app-op**, not a runtime permission prompt. Users grant it via Settings; your UI should deep-link there and reflect denial by degrading to WorkManager. + ## Permission & Settings Truth Table | Symptom | Likely Cause | Action | diff --git a/docs/android-app-improvement-plan.md b/docs/android-app-improvement-plan.md index c1d5af3..1bbe3e1 100644 --- a/docs/android-app-improvement-plan.md +++ b/docs/android-app-improvement-plan.md @@ -400,6 +400,20 @@ public class ScheduleDailyTest { ## Security Hardening +### 0. ProGuard/R8 Keep Rules (minify-safe plugin) + +**Purpose**: Prevent Capacitor annotations and plugin methods from being stripped +**Implementation**: Add keep rules to proguard-rules.pro + +```pro +# Keep Capacitor Plugin annotations & your plugin facade +-keep class com.getcapacitor.** { *; } +-keep @com.getcapacitor.annotation.CapacitorPlugin class * { *; } +-keepclassmembers class ** { + @com.getcapacitor.annotation.PluginMethod *; +} +``` + ### 1. Bridge Input Validation **Purpose**: Validate all inputs before native processing @@ -863,12 +877,15 @@ interface ScheduleResponse { - [ ] Maps native exceptions to canonical errors - [ ] Provides user-friendly error messages - [ ] Rejects unknown keys with single joined message +- [ ] Channel policy enforced: missing/disabled channel returns `E_CHANNEL_MISSING` or `E_CHANNEL_DISABLED` with "Open Channel Settings" CTA +- [ ] HTTPS-only; connect/read timeouts ≤ 30s; content-length hard cap ≤ 1 MB; oversize → `E_RESPONSE_TOO_LARGE` ### Reliability - [ ] Reboot scenarios reliably deliver notifications - [ ] Doze scenarios degrade gracefully - [ ] Clear logs explain system behavior - [ ] User-visible reasoning for failures +- [ ] Rescheduler uses unique key `(requestCode|channelId|time)` and **UPSERT** semantics; log `EVT_BOOT_REHYDRATE_DONE(count=n)` ### Testing - [ ] Test UI modularized into scenarios @@ -919,6 +936,9 @@ By following this plan, the test app will become more maintainable, reliable, an - @PluginMethod bodies ≤ 25 LOC, delegate to use-cases. - "Copy Diagnostics (JSON)" button functional. +**Diagnostics MUST include:** appId, versionName/code, manufacturer/model, API level, timezone, `capacitor.config.json` plugin section echo, five status fields, last 50 event IDs. +- If exact alarm is denied/quota-limited, UI surfaces **"Degraded timing (Doze)"** and logs `EVT_DOZE_FALLBACK_TAKEN`. + ### Phase 2 DoD - Test UI split into modular scenarios with fixtures. - Instrumentation tests cover channel disabled and exact alarm denied paths. @@ -945,6 +965,7 @@ By following this plan, the test app will become more maintainable, reliable, an - [ ] Status Matrix field(s) updated if capability changed - [ ] Runbooks section touched if behavior changed - [ ] No new events without ID (keeps logs grep-able) +- [ ] AndroidManifest receivers reviewed: only BootReceiver is exported; others remain `exported="false"`. ## Test Matrix @@ -955,6 +976,7 @@ By following this plan, the test app will become more maintainable, reliable, an | Exact alarm denied path | openExactAlarmSettings | Revoke exact alarm | Fallback path taken; logged `DOZE_FALLBACK` | | Boot reschedule | BootReceiver | Reboot emulator | One (not duplicate) schedule restored | | Doze idle window | scheduleDailyNotification | Device in idle | Fallback path taken; logged `EVT_DOZE_FALLBACK_TAKEN`; no crash | +| Bad schema rejects | bridge.ts + schema-validation.ts | Add unknown key / oversize title | Canonical `E_BAD_CONFIG` with single joined message | ## Error Codes (canonical)