fix(android): resolve prefetch scheduling and permission callback issues

- Add null safety check to permission callback to prevent NPE
- Fix fetch time calculation bug that caused double subtraction
  - scheduleFetch() now accepts pre-calculated fetchTime directly
  - Calculate scheduledTime back from fetchTime for worker data
- Add structured logging (DN|FETCH_SCHEDULING) for better traceability

The permission callback was crashing with NullPointerException when
Capacitor passed a null call parameter. The prefetch scheduling had a
logic error where fetchTime was calculated twice - once in the plugin
and once in the fetcher, causing 10-minute delays instead of 5-minute.

Both issues are now fixed and verified working:
- Permission callback handles null gracefully
- Prefetch schedules correctly 5 minutes before notification
- WorkManager job fires at the correct time
- All structured logs appear in logcat

Closes prefetch scheduling investigation.
This commit is contained in:
Matthew Raymer
2025-10-28 09:35:33 +00:00
parent 0e783a8a2d
commit 333c435b89
5 changed files with 491 additions and 13 deletions

View File

@@ -72,19 +72,23 @@ public class DailyNotificationFetcher {
/**
* Schedule a background fetch for content
*
* @param scheduledTime When the notification is scheduled for
* @param fetchTime When to fetch the content (already calculated, typically 5 minutes before notification)
*/
public void scheduleFetch(long scheduledTime) {
public void scheduleFetch(long fetchTime) {
try {
Log.d(TAG, "Scheduling background fetch for " + scheduledTime);
Log.d(TAG, "Scheduling background fetch for time: " + fetchTime);
// Calculate fetch time (5 minutes before notification)
long fetchTime = scheduledTime - TimeUnit.MINUTES.toMillis(5);
long currentTime = System.currentTimeMillis();
long delayMs = fetchTime - currentTime;
if (fetchTime > System.currentTimeMillis()) {
long delayMs = fetchTime - System.currentTimeMillis();
Log.d(TAG, "DN|FETCH_SCHEDULING fetch_time=" + fetchTime +
" current=" + currentTime +
" delay_ms=" + delayMs);
if (fetchTime > currentTime) {
// Create work data - we need to calculate the notification time (fetchTime + 5 minutes)
long scheduledTime = fetchTime + TimeUnit.MINUTES.toMillis(5);
// Create work data
Data inputData = new Data.Builder()
.putLong("scheduled_time", scheduledTime)
.putLong("fetch_time", fetchTime)
@@ -105,13 +109,13 @@ public class DailyNotificationFetcher {
Log.i(TAG, "DN|WORK_ENQUEUED work_id=" + fetchWork.getId().toString() +
" fetch_at=" + fetchTime +
" delay_ms=" + delayMs +
" delay_hours=" + (delayMs / 3600000.0));
" delay_minutes=" + (delayMs / 60000.0));
Log.i(TAG, "Background fetch scheduled successfully");
} else {
Log.w(TAG, "DN|FETCH_PAST_TIME fetch_time=" + fetchTime +
" current=" + System.currentTimeMillis() +
" past_by_ms=" + (System.currentTimeMillis() - fetchTime));
" current=" + currentTime +
" past_by_ms=" + (currentTime - fetchTime));
scheduleImmediateFetch();
}

View File

@@ -1243,6 +1243,13 @@ public class DailyNotificationPlugin extends Plugin {
private void onPermissionResult(PluginCall call) {
try {
Log.d(TAG, "DEBUG: onPermissionResult callback received");
// Guard against null call
if (call == null) {
Log.e(TAG, "Permission callback received null call - cannot process");
return;
}
Log.d(TAG, "Permission callback received");
// Check if POST_NOTIFICATIONS permission was granted
@@ -1262,7 +1269,9 @@ public class DailyNotificationPlugin extends Plugin {
} catch (Exception e) {
Log.e(TAG, "DEBUG: Exception in onPermissionResult callback", e);
Log.e(TAG, "Error in permission callback", e);
call.reject("Error processing permission result: " + e.getMessage());
if (call != null) {
call.reject("Error processing permission result: " + e.getMessage());
}
}
}