diff --git a/docs/android-app-analysis.md b/docs/android-app-analysis.md index 3b73bee..719a2ab 100644 --- a/docs/android-app-analysis.md +++ b/docs/android-app-analysis.md @@ -126,6 +126,8 @@ public class MainActivity extends BridgeActivity { +> **Note:** Set `android:name` only if you provide a custom `Application` class; otherwise remove to avoid ClassNotFound at runtime. + + +> **Note:** `android:priority` has no practical effect for `BOOT_COMPLETED`; safe to omit. @@ -162,7 +166,7 @@ public class MainActivity extends BridgeActivity { - `POST_NOTIFICATIONS`: Required for Android 13+ notification posting - `SCHEDULE_EXACT_ALARM`: Required for precise notification timing -- `WAKE_LOCK`: Required for background processing +- `WAKE_LOCK` **not required** unless you explicitly acquire/release your own wakelocks (AlarmManager & WorkManager handle theirs) - `INTERNET`: Required for content fetching - `RECEIVE_BOOT_COMPLETED`: Required for reboot recovery @@ -391,6 +395,8 @@ dependencies { // Cordova compatibility (include ONLY if using Cordova plugins) debugImplementation(project(':capacitor-cordova-android-plugins')) { transitive = false } releaseImplementation(project(':capacitor-cordova-android-plugins')) { transitive = false } + +> **Note:** Include `capacitor-cordova-android-plugins` **only** when using Cordova plugins. } ``` @@ -619,6 +625,8 @@ If **denied or quota-limited** → schedule via WorkManager (exp backoff + jitte | Battery optimization kills | App not whitelisted | Guide user to battery optimization settings | | Boot reschedule fails | `RECEIVE_BOOT_COMPLETED` denied | Check manifest receiver registration | +> **Test UI Integration:** Use "Open Channel Settings" and "Open Exact Alarm Settings" buttons in the test interface to resolve channel and exact alarm issues. + ## Runtime Flow Diagram ```mermaid @@ -635,8 +643,8 @@ graph TD I --> J[UI Update] %% Error paths - C -->|Validation Error| K[Canonical Error] - D -->|Use-case Error| K + C -->|Validation Error → Canonical Error| K[Canonical Error] + D -->|Use-case Error → Canonical Error| K K --> L[JavaScript Promise Rejection] ``` diff --git a/docs/android-app-improvement-plan.md b/docs/android-app-improvement-plan.md index 1bbe3e1..28d77ad 100644 --- a/docs/android-app-improvement-plan.md +++ b/docs/android-app-improvement-plan.md @@ -496,12 +496,26 @@ public class SecureNetworkClient { connection.setConnectTimeout(TIMEOUT_SECONDS * 1000); connection.setReadTimeout(TIMEOUT_SECONDS * 1000); - // Limit response size + // Limit response size (handle unknown Content-Length) long contentLength = connection.getContentLengthLong(); if (contentLength > MAX_RESPONSE_SIZE) { throw new NetworkException("E_RESPONSE_TOO_LARGE", "Response too large"); } + // Stream with size guard for unknown Content-Length + long read = 0; + try (InputStream in = connection.getInputStream()) { + byte[] buf = new byte[8192]; + int n; + while ((n = in.read(buf)) != -1) { + read += n; + if (read > MAX_RESPONSE_SIZE) { + throw new NetworkException("E_RESPONSE_TOO_LARGE", "Response too large"); + } + // process / buffer as needed + } + } + return readResponse(connection); } } @@ -671,6 +685,7 @@ public class DatabaseMaintenance { - **Index Optimization**: Maintain database performance - **Data Retention**: Configurable retention policies - **Performance Monitoring**: Track maintenance impact +- **Migration Safety**: Add a **no-op migration** for current schema version and a test that app boots with `fallbackToDestructiveMigration(false)` ## Documentation Updates @@ -870,6 +885,7 @@ interface ScheduleResponse { - [ ] Shows live channel state - [ ] Provides actionable buttons for issues - [ ] Exports diagnostics as JSON +- [ ] When fallback is active, matrix shows **"Degraded timing (Doze)"** and last event includes `EVT_DOZE_FALLBACK_TAKEN` ### Error Handling - [ ] All @PluginMethod calls validate inputs @@ -879,6 +895,7 @@ interface ScheduleResponse { - [ ] 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` +- [ ] Validation failures return **one joined message** surfaced to UI ### Reliability - [ ] Reboot scenarios reliably deliver notifications @@ -886,6 +903,7 @@ interface ScheduleResponse { - [ ] 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)` +- [ ] Only `BootReceiver` is exported; all other receivers remain `exported="false"` ### Testing - [ ] Test UI modularized into scenarios @@ -936,7 +954,7 @@ 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. +**Diagnostics MUST include:** appId, versionName/code, manufacturer/model, API level, timezone, `capacitor.config.json` plugin section echo, five status fields, last 50 event IDs, `webDir` effective path echo, `isDeviceIdleMode` boolean. - If exact alarm is denied/quota-limited, UI surfaces **"Degraded timing (Doze)"** and logs `EVT_DOZE_FALLBACK_TAKEN`. ### Phase 2 DoD @@ -973,7 +991,7 @@ By following this plan, the test app will become more maintainable, reliable, an |---|---|---| | Immediate notify | scheduleDailyNotification | Channel ON, perms granted | Success + toast seen | | Channel disabled path | isChannelEnabled/openChannelSettings | Disable channel | Canonical `E_CHANNEL_DISABLED` | -| Exact alarm denied path | openExactAlarmSettings | Revoke exact alarm | Fallback path taken; logged `DOZE_FALLBACK` | +| Exact alarm denied path | openExactAlarmSettings | Revoke exact alarm | Fallback path taken; logged `EVT_DOZE_FALLBACK_TAKEN` | | 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 |