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)