# Daily Notification Plugin - Android Receiver Not Triggered by AlarmManager

**Date**: 2026-02-02  
**Status**: ✅ Resolved (2026-02-06)  
**Plugin**: @timesafari/daily-notification-plugin  
**Platform**: Android  
**Issue**: AlarmManager fires alarms but DailyNotificationReceiver is not receiving broadcasts

---

## Resolution (2026-02-06)

The bug was fixed in the plugin repository. The plugin now:

- Creates the PendingIntent with the receiver component explicitly set (`setComponent(ComponentName(context, DailyNotificationReceiver::class.java))`), so AlarmManager delivers the broadcast to the receiver.
- Adds the schedule ID to the Intent extras (`intent.putExtra("id", scheduleId)`), resolving the `missing_id` error.

**In this app after pulling the fix:**

1. Run `npm install` to get the latest plugin from `#master`.
2. Run `npx cap sync` so the Android (and iOS) native projects get the updated plugin code.
3. Run `node scripts/restore-local-plugins.js` if you use local plugins (e.g. SafeArea, SharedImage).
4. Rebuild and run on Android, then verify using the [Testing Steps for Plugin Fix](#testing-steps-for-plugin-fix) below.
</think>

---

## Problem Summary

Alarms are being scheduled successfully and fire at the correct time, but the `DailyNotificationReceiver` is not being triggered when AlarmManager delivers the broadcast. Manual broadcasts to the receiver work correctly, indicating the receiver itself is functional.

---

## What Works ✅

1. **Receiver Registration**: The receiver is properly registered in AndroidManifest.xml with `exported="true"`
2. **Manual Broadcasts**: Manually triggering the receiver via `adb shell am broadcast` successfully triggers it
3. **Alarm Scheduling**: Alarms are successfully scheduled via `setAlarmClock()` and appear in `dumpsys alarm`
4. **Alarm Firing**: Alarms fire at the scheduled time (confirmed by alarm disappearing from dumpsys)

---

## What Doesn't Work ❌

1. **Automatic Receiver Triggering**: When AlarmManager fires the alarm, the broadcast PendingIntent does not reach the receiver
2. **No Logs on Alarm Fire**: No `DN|RECEIVE_START` logs appear when alarms fire automatically
3. **Missing ID in Intent**: When manually tested, receiver shows `DN|RECEIVE_ERR missing_id` (separate issue but related)

---

## Technical Details

### Receiver Configuration

**File**: `android/app/src/main/AndroidManifest.xml`

```xml
<receiver
    android:name="com.timesafari.dailynotification.DailyNotificationReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.timesafari.daily.NOTIFICATION" />
    </intent-filter>
</receiver>
```

- ✅ `exported="true"` is set (required for AlarmManager broadcasts)
- ✅ Intent action matches: `com.timesafari.daily.NOTIFICATION`
- ✅ Receiver is inside `<application>` tag

### Alarm Scheduling Evidence

From logs when scheduling (23:51:32):
```
I DNP-SCHEDULE: Scheduling OS alarm: variant=ALARM_CLOCK, action=com.timesafari.daily.NOTIFICATION, triggerTime=1770105300000, requestCode=44490, scheduleId=timesafari_daily_reminder
I DNP-NOTIFY: Alarm clock scheduled (setAlarmClock): triggerAt=1770105300000, requestCode=44490
```

From `dumpsys alarm` output:
```
RTC_WAKEUP #36: Alarm{7a8fb5e type 0 origWhen 1770148800000 whenElapsed 122488536 app.timesafari.app}
  tag=*walarm*:com.timesafari.daily.NOTIFICATION
  type=RTC_WAKEUP origWhen=2026-02-03 12:00:00.000 window=0 exactAllowReason=policy_permission
  operation=PendingIntent{6fce955: PendingIntentRecord{5856f6a app.timesafari.app broadcastIntent}}
```

### Alarm Firing Evidence

- Alarm scheduled for 23:55:00 (timestamp: 1770105300000)
- At 23:55:00, alarm is no longer in `dumpsys alarm` (confirmed it fired)
- **No `DN|RECEIVE_START` log at 23:55:00** (receiver was not triggered)

### Manual Broadcast Test (Works)

```bash
adb shell am broadcast -a com.timesafari.daily.NOTIFICATION -n app.timesafari.app/com.timesafari.dailynotification.DailyNotificationReceiver
```

**Result**: ✅ Receiver triggered successfully
```
02-02 23:46:07.505  DailyNotificationReceiver  D  DN|RECEIVE_START action=com.timesafari.daily.NOTIFICATION
02-02 23:46:07.506  DailyNotificationReceiver  W  DN|RECEIVE_ERR missing_id
```

---

## Root Cause Analysis

The issue appears to be in how the PendingIntent is created when scheduling alarms. Possible causes:

### Hypothesis 1: PendingIntent Not Targeting Receiver Correctly

The PendingIntent may be created without explicitly specifying the component, causing Android to not match it to the receiver when the alarm fires.

**Expected Fix**: When creating the PendingIntent for AlarmManager, explicitly set the component:

```kotlin
val intent = Intent("com.timesafari.daily.NOTIFICATION").apply {
    setComponent(ComponentName(context, DailyNotificationReceiver::class.java))
    putExtra("id", scheduleId) // Also fix missing_id issue
}
val pendingIntent = PendingIntent.getBroadcast(
    context,
    requestCode,
    intent,
    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
```

### Hypothesis 2: PendingIntent Flags Issue

The PendingIntent may be created with incorrect flags that prevent delivery when the app is in certain states.

**Check**: Ensure flags include:
- `FLAG_UPDATE_CURRENT` or `FLAG_CANCEL_CURRENT`
- `FLAG_IMMUTABLE` (required on Android 12+)

### Hypothesis 3: Package/Component Mismatch

The PendingIntent may be created with a different package name or component than what's registered in the manifest.

**Check**: Verify the package name in the Intent matches `app.timesafari.app` and the component matches the receiver class.

---

## Additional Issue: Missing ID in Intent

When the receiver IS triggered (manually), it shows:
```
DN|RECEIVE_ERR missing_id
```

This indicates the Intent extras don't include the `scheduleId`. The plugin should add the ID to the Intent when creating the PendingIntent:

```kotlin
intent.putExtra("id", scheduleId)
// or
intent.putExtra("scheduleId", scheduleId) // if receiver expects different key
```

---

## Testing Steps for Plugin Fix

1. **Verify PendingIntent Creation**:
   - Check the code that creates PendingIntent for AlarmManager
   - Ensure component is explicitly set
   - Ensure ID is added to Intent extras

2. **Test Alarm Delivery**:
   - Schedule an alarm for 1-2 minutes in the future
   - Monitor logs: `adb logcat | grep -E "DN|RECEIVE_START|DailyNotification"`
   - Verify `DN|RECEIVE_START` appears when alarm fires
   - Verify no `missing_id` error

3. **Test Different App States**:
   - App in foreground
   - App in background
   - App force-closed
   - Device in doze mode (if possible on emulator)

4. **Compare with Manual Broadcast**:
   - Manual broadcast works → receiver is fine
   - Alarm broadcast doesn't work → PendingIntent creation is the issue

---

## Files to Check in Plugin

1. **Alarm Scheduling Code**: Where `setAlarmClock()` or `setExact()` is called
2. **PendingIntent Creation**: Where `PendingIntent.getBroadcast()` is called
3. **Intent Creation**: Where the Intent for the alarm is created
4. **Receiver Code**: Verify what Intent extras it expects (for missing_id fix)

---

## Related Configuration

### AndroidManifest.xml (App Side)
- ✅ Receiver exported="true"
- ✅ Correct intent action
- ✅ Receiver inside application tag

### Permissions (App Side)
- ✅ POST_NOTIFICATIONS
- ✅ SCHEDULE_EXACT_ALARM
- ✅ USE_EXACT_ALARM
- ✅ RECEIVE_BOOT_COMPLETED
- ✅ WAKE_LOCK

---

## Expected Behavior After Fix

When an alarm fires:
1. AlarmManager delivers the broadcast
2. `DailyNotificationReceiver.onReceive()` is called
3. Log shows: `DN|RECEIVE_START action=com.timesafari.daily.NOTIFICATION`
4. Receiver finds the ID in Intent extras (no `missing_id` error)
5. Notification is displayed

---

## Notes

- The `exported="true"` change in the app's manifest was necessary and correct
- The issue is in the plugin's PendingIntent creation, not the app configuration
- Manual broadcasts work, proving the receiver registration is correct
- Alarms fire, proving AlarmManager scheduling is correct
- The gap is in the PendingIntent → Receiver delivery

---

## Quick Reference: Working Manual Test

```bash
# This works - receiver is triggered
adb shell am broadcast \
  -a com.timesafari.daily.NOTIFICATION \
  -n app.timesafari.app/com.timesafari.dailynotification.DailyNotificationReceiver \
  --es "id" "timesafari_daily_reminder"
```

The plugin's PendingIntent should create an equivalent broadcast that AlarmManager can deliver.
