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.
 
 
 
 
 
 

283 lines
10 KiB

/**
* DailyNotificationReceiver.java
*
* Broadcast receiver for handling scheduled notification alarms
* Displays notifications when scheduled time is reached
*
* @author Matthew Raymer
* @version 1.0.0
*/
package com.timesafari.dailynotification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import androidx.core.app.NotificationCompat;
/**
* Broadcast receiver for daily notification alarms
*
* This receiver is triggered by AlarmManager when it's time to display
* a notification. It retrieves the notification content from storage
* and displays it to the user.
*/
public class DailyNotificationReceiver extends BroadcastReceiver {
private static final String TAG = "DailyNotificationReceiver";
private static final String CHANNEL_ID = "timesafari.daily";
private static final String EXTRA_NOTIFICATION_ID = "notification_id";
/**
* Handle broadcast intent when alarm triggers
*
* @param context Application context
* @param intent Broadcast intent
*/
@Override
public void onReceive(Context context, Intent intent) {
try {
Log.d(TAG, "Received notification broadcast");
String action = intent.getAction();
if (action == null) {
Log.w(TAG, "Received intent with null action");
return;
}
if ("com.timesafari.daily.NOTIFICATION".equals(action)) {
handleNotificationIntent(context, intent);
} else {
Log.w(TAG, "Unknown action: " + action);
}
} catch (Exception e) {
Log.e(TAG, "Error handling broadcast", e);
}
}
/**
* Handle notification intent
*
* @param context Application context
* @param intent Intent containing notification data
*/
private void handleNotificationIntent(Context context, Intent intent) {
try {
String notificationId = intent.getStringExtra(EXTRA_NOTIFICATION_ID);
if (notificationId == null) {
Log.w(TAG, "Notification ID not found in intent");
return;
}
Log.d(TAG, "Processing notification: " + notificationId);
// Get notification content from storage
DailyNotificationStorage storage = new DailyNotificationStorage(context);
NotificationContent content = storage.getNotificationContent(notificationId);
if (content == null) {
Log.w(TAG, "Notification content not found: " + notificationId);
return;
}
// Check if notification is ready to display
if (!content.isReadyToDisplay()) {
Log.d(TAG, "Notification not ready to display yet: " + notificationId);
return;
}
// Display the notification
displayNotification(context, content);
// Schedule next notification if this is a recurring daily notification
scheduleNextNotification(context, content);
Log.i(TAG, "Notification processed successfully: " + notificationId);
} catch (Exception e) {
Log.e(TAG, "Error handling notification intent", e);
}
}
/**
* Display the notification to the user
*
* @param context Application context
* @param content Notification content to display
*/
private void displayNotification(Context context, NotificationContent content) {
try {
Log.d(TAG, "Displaying notification: " + content.getId());
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null) {
Log.e(TAG, "NotificationManager not available");
return;
}
// Create notification builder
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle(content.getTitle())
.setContentText(content.getBody())
.setPriority(getNotificationPriority(content.getPriority()))
.setAutoCancel(true)
.setCategory(NotificationCompat.CATEGORY_REMINDER);
// Add sound if enabled
if (content.isSound()) {
builder.setDefaults(NotificationCompat.DEFAULT_SOUND);
}
// Add click action if URL is available
if (content.getUrl() != null && !content.getUrl().isEmpty()) {
Intent clickIntent = new Intent(Intent.ACTION_VIEW);
clickIntent.setData(android.net.Uri.parse(content.getUrl()));
PendingIntent clickPendingIntent = PendingIntent.getActivity(
context,
content.getId().hashCode(),
clickIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
builder.setContentIntent(clickPendingIntent);
}
// Add dismiss action
Intent dismissIntent = new Intent(context, DailyNotificationReceiver.class);
dismissIntent.setAction("com.timesafari.daily.DISMISS");
dismissIntent.putExtra(EXTRA_NOTIFICATION_ID, content.getId());
PendingIntent dismissPendingIntent = PendingIntent.getBroadcast(
context,
content.getId().hashCode() + 1000, // Different request code
dismissIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
builder.addAction(
android.R.drawable.ic_menu_close_clear_cancel,
"Dismiss",
dismissPendingIntent
);
// Build and display notification
int notificationId = content.getId().hashCode();
notificationManager.notify(notificationId, builder.build());
Log.i(TAG, "Notification displayed successfully: " + content.getId());
} catch (Exception e) {
Log.e(TAG, "Error displaying notification", e);
}
}
/**
* Schedule the next occurrence of this daily notification
*
* @param context Application context
* @param content Current notification content
*/
private void scheduleNextNotification(Context context, NotificationContent content) {
try {
Log.d(TAG, "Scheduling next notification for: " + content.getId());
// Calculate next occurrence (24 hours from now)
long nextScheduledTime = content.getScheduledTime() + (24 * 60 * 60 * 1000);
// Create new content for next occurrence
NotificationContent nextContent = new NotificationContent();
nextContent.setTitle(content.getTitle());
nextContent.setBody(content.getBody());
nextContent.setScheduledTime(nextScheduledTime);
nextContent.setSound(content.isSound());
nextContent.setPriority(content.getPriority());
nextContent.setUrl(content.getUrl());
nextContent.setFetchTime(System.currentTimeMillis());
// Save to storage
DailyNotificationStorage storage = new DailyNotificationStorage(context);
storage.saveNotificationContent(nextContent);
// Schedule the notification
DailyNotificationScheduler scheduler = new DailyNotificationScheduler(
context,
(android.app.AlarmManager) context.getSystemService(Context.ALARM_SERVICE)
);
boolean scheduled = scheduler.scheduleNotification(nextContent);
if (scheduled) {
Log.i(TAG, "Next notification scheduled successfully");
} else {
Log.e(TAG, "Failed to schedule next notification");
}
} catch (Exception e) {
Log.e(TAG, "Error scheduling next notification", e);
}
}
/**
* Get notification priority constant
*
* @param priority Priority string from content
* @return NotificationCompat priority constant
*/
private int getNotificationPriority(String priority) {
if (priority == null) {
return NotificationCompat.PRIORITY_DEFAULT;
}
switch (priority.toLowerCase()) {
case "high":
return NotificationCompat.PRIORITY_HIGH;
case "low":
return NotificationCompat.PRIORITY_LOW;
case "min":
return NotificationCompat.PRIORITY_MIN;
case "max":
return NotificationCompat.PRIORITY_MAX;
default:
return NotificationCompat.PRIORITY_DEFAULT;
}
}
/**
* Handle notification dismissal
*
* @param context Application context
* @param notificationId ID of dismissed notification
*/
private void handleNotificationDismissal(Context context, String notificationId) {
try {
Log.d(TAG, "Handling notification dismissal: " + notificationId);
// Remove from storage
DailyNotificationStorage storage = new DailyNotificationStorage(context);
storage.removeNotification(notificationId);
// Cancel any pending alarms
DailyNotificationScheduler scheduler = new DailyNotificationScheduler(
context,
(android.app.AlarmManager) context.getSystemService(Context.ALARM_SERVICE)
);
scheduler.cancelNotification(notificationId);
Log.i(TAG, "Notification dismissed successfully: " + notificationId);
} catch (Exception e) {
Log.e(TAG, "Error handling notification dismissal", e);
}
}
}