package com.realtrackandroid.reminderalarms; import java.util.ArrayList; import java.util.Calendar; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; import com.realtrackandroid.backend.activities.ActivitiesDAO; import com.realtrackandroid.backend.activities.ParticipationDAO; import com.realtrackandroid.backend.reminders.RemindersDAO; import com.realtrackandroid.models.activities.Activities; import com.realtrackandroid.models.activities.Participation; import com.realtrackandroid.models.reminders.Reminders; /** * This class receives the boot completed event whenever the phone is started up Its job is to * schedule an alarm for this app's notifications */ public class NotificationReceiver extends BroadcastReceiver { private static ArrayList<Reminders> reminders_data; private static ArrayList<Participation> participation_data; public void onReceive(Context context, Intent intent) { // in our case intent will always be BOOT_COMPLETED, so we can just set // the alarm // Note that a BroadcastReceiver is *NOT* a Context. Thus, we can't use // "this" whenever we need to pass a reference to the current context. // Thankfully, Android will supply a valid Context as the first parameter // schedule an alarm // we separate this code because it's also called from WelcomeActivity scheduleAlarm(context); } public static void scheduleAlarm(Context context) { handleReminders(context); } private static void handleReminders(Context context) { // read in ALL reminders from the reminder table and set alarms for each one RemindersDAO rDao = new RemindersDAO(context); reminders_data = rDao.getAllReminders(); ParticipationDAO pDao = new ParticipationDAO(context); for (Reminders r : reminders_data) { Calendar c = Calendar.getInstance(); c.setTimeInMillis(r.getRemindTime()); // delete any participation events for this reminder scheduled in the future (from now) and // also cancel the associated // alarms for those events participation_data = pDao.getAllParticipationsForReminderId(r.getId()); for (Participation p : participation_data) { Calendar unservicedCalendar = Calendar.getInstance(); unservicedCalendar.setTimeInMillis(p.getDate()); if (Calendar.getInstance().compareTo(unservicedCalendar) == -1) { Log.e("burra", "deleting " + p.getId() + " and its associated alarms"); deleteParticipationAndAlarm(context, pDao, p.getId()); } } ActivitiesDAO aDao = new ActivitiesDAO(context); Activities a = aDao.getActivityWithId(r.getActivityid()); // if the activity has ended, delete the reminder and do not create any alarms // also cancel any existing alarms // note that if the activity's end date was 9/9/2013, reminders up to (but not including) // 9/10/2013 00:00 will // show up // we do NOT kill pending unserviced participations so that the user can still fill them in // from the pending // screen; he will just never get to see them via a notification Calendar activityCalendar = Calendar.getInstance(); activityCalendar.setTimeInMillis(a.getEndDate()); activityCalendar.add(Calendar.DAY_OF_WEEK, 1); // roll over to the start of the next day if (c.compareTo(activityCalendar) == 1) { Log.e("burra", "this activity is over. deleting reminder " + r.getId() + " and its associated alarms."); deleteReminderAndAlarm(context, rDao, r.getId()); return; } // if we're already past the time we want in this week, schedule it for the same time next // week if (r.getRemindTime() < System.currentTimeMillis()) { // set the reminder for the same day and time next week c.add(Calendar.DAY_OF_WEEK, 7); // update the reminder time in the Reminders table, which in turn, schedules this new // participation event // by calling this same NotificationReceiver function r.setRemindTime(c.getTimeInMillis()); // if the activity ends within the next 7 days, delete the reminder since it would have been // shown after 7 days // and do not create any alarms // note that if the activity's end date was 9/9/2013, reminders up to (but not including) // 9/10/2013 00:00 will // show up // we do NOT kill pending unserviced participations so that the user can still fill them in // from the pending // screen; he will just never get to see them via a notification if (c.compareTo(activityCalendar) == 1) { Log.e("burra", "this activity will be over within the week. deleting reminder " + r.getId() + " and its associated alarms."); deleteReminderAndAlarm(context, rDao, r.getId()); return; } rDao.updateReminders(r, context); Log.e("burra", "already passed this week, scheduling for next week " + c.get(Calendar.MONTH) + "/" + c.get(Calendar.DAY_OF_MONTH)); return; } Intent notifIntent = new Intent(context, NotificationService.class); notifIntent.putExtra("reminderid", r.getId()); notifIntent.setAction(Intent.ACTION_VIEW); // unpredictable android crap again. without an // action, the extras will NOT be sent!! PendingIntent pendingIntent = PendingIntent.getService(context, r.getId(), notifIntent, PendingIntent.FLAG_UPDATE_CURRENT); // remember to distinguish between pendingintents // using Reminders.id as the request code Log.e("burra", "scheduling for " + c.get(Calendar.MONTH) + "/" + c.get(Calendar.DAY_OF_MONTH) + ", " + c.get(Calendar.HOUR) + ":" + c.get(Calendar.MINUTE)); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, pendingIntent); c.clear(); } } private static void deleteParticipationAndAlarm(Context context, ParticipationDAO pDao, int participationId) { pDao.deleteParticipation(participationId); Intent notifIntent = new Intent(context, NotificationService.class); notifIntent.putExtra("participationid", participationId); notifIntent.setAction(Intent.ACTION_VIEW); // unpredictable android crap again. without an // action, the extras will NOT be sent!! PendingIntent pendingIntent = PendingIntent.getService(context, participationId, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT); // remember to distinguish between pendingintents // using Participation.id as the request code AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(pendingIntent); pendingIntent.cancel(); } private static void deleteReminderAndAlarm(Context context, RemindersDAO rDao, int reminderId) { rDao.deleteReminders(reminderId, context); Intent notifIntent = new Intent(context, NotificationService.class); notifIntent.putExtra("reminderid", reminderId); notifIntent.setAction(Intent.ACTION_VIEW); // unpredictable android crap again. without an // action, the extras will NOT be sent!! PendingIntent pendingIntent = PendingIntent.getService(context, reminderId, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT); // remember to distinguish between pendingintents // using Participation.id as the request code AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(pendingIntent); pendingIntent.cancel(); } }