You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

153 lines
5.5 KiB

package com.timesafari.dailynotification
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
/**
* Boot recovery receiver to reschedule notifications after device reboot
* Implements RECEIVE_BOOT_COMPLETED functionality
*
* @author Matthew Raymer
* @version 1.1.0
*/
class BootReceiver : BroadcastReceiver() {
companion object {
private const val TAG = "DNP-BOOT"
}
override fun onReceive(context: Context, intent: Intent?) {
if (intent?.action == Intent.ACTION_BOOT_COMPLETED) {
Log.i(TAG, "Boot completed, rescheduling notifications")
CoroutineScope(Dispatchers.IO).launch {
try {
rescheduleNotifications(context)
} catch (e: Exception) {
Log.e(TAG, "Failed to reschedule notifications after boot", e)
}
}
}
}
private suspend fun rescheduleNotifications(context: Context) {
val db = DailyNotificationDatabase.getDatabase(context)
val enabledSchedules = db.scheduleDao().getEnabled()
Log.i(TAG, "Found ${enabledSchedules.size} enabled schedules to reschedule")
enabledSchedules.forEach { schedule ->
try {
when (schedule.kind) {
"fetch" -> {
// Reschedule WorkManager fetch
val config = ContentFetchConfig(
enabled = schedule.enabled,
schedule = schedule.cron ?: schedule.clockTime ?: "0 9 * * *",
url = null, // Will use mock content
timeout = 30000,
retryAttempts = 3,
retryDelay = 1000,
callbacks = CallbackConfig()
)
FetchWorker.scheduleFetch(context, config)
Log.i(TAG, "Rescheduled fetch for schedule: ${schedule.id}")
}
"notify" -> {
// Reschedule AlarmManager notification
val nextRunTime = calculateNextRunTime(schedule)
if (nextRunTime > System.currentTimeMillis()) {
val config = UserNotificationConfig(
enabled = schedule.enabled,
schedule = schedule.cron ?: schedule.clockTime ?: "0 9 * * *",
title = "Daily Notification",
body = "Your daily update is ready",
sound = true,
vibration = true,
priority = "normal"
)
NotifyReceiver.scheduleExactNotification(context, nextRunTime, config)
Log.i(TAG, "Rescheduled notification for schedule: ${schedule.id}")
}
}
else -> {
Log.w(TAG, "Unknown schedule kind: ${schedule.kind}")
}
}
} catch (e: Exception) {
Log.e(TAG, "Failed to reschedule ${schedule.kind} for ${schedule.id}", e)
}
}
// Record boot recovery in history
try {
db.historyDao().insert(
History(
refId = "boot_recovery_${System.currentTimeMillis()}",
kind = "boot_recovery",
occurredAt = System.currentTimeMillis(),
outcome = "success",
diagJson = "{\"schedules_rescheduled\": ${enabledSchedules.size}}"
)
)
} catch (e: Exception) {
Log.e(TAG, "Failed to record boot recovery", e)
}
}
private fun calculateNextRunTime(schedule: Schedule): Long {
val now = System.currentTimeMillis()
// Simple implementation - for production, use proper cron parsing
return when {
schedule.cron != null -> {
// Parse cron expression and calculate next run
// For now, return next day at 9 AM
now + (24 * 60 * 60 * 1000L)
}
schedule.clockTime != null -> {
// Parse HH:mm and calculate next run
// For now, return next day at specified time
now + (24 * 60 * 60 * 1000L)
}
else -> {
// Default to next day at 9 AM
now + (24 * 60 * 60 * 1000L)
}
}
}
}
/**
* Data classes for configuration (simplified versions)
*/
data class ContentFetchConfig(
val enabled: Boolean,
val schedule: String,
val url: String? = null,
val timeout: Int? = null,
val retryAttempts: Int? = null,
val retryDelay: Int? = null,
val callbacks: CallbackConfig
)
data class UserNotificationConfig(
val enabled: Boolean,
val schedule: String,
val title: String? = null,
val body: String? = null,
val sound: Boolean? = null,
val vibration: Boolean? = null,
val priority: String? = null
)
data class CallbackConfig(
val apiService: String? = null,
val database: String? = null,
val reporting: String? = null
)