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
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);
|
|
}
|
|
}
|
|
}
|
|
|