package fr.paug.androidmakers.service;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.text.format.DateUtils;
import android.util.Log;
import java.util.Date;
import java.util.Formatter;
import java.util.List;
import java.util.Locale;
import fr.paug.androidmakers.R;
import fr.paug.androidmakers.manager.AgendaRepository;
import fr.paug.androidmakers.model.Room;
import fr.paug.androidmakers.model.ScheduleSlot;
import fr.paug.androidmakers.model.Session;
import fr.paug.androidmakers.ui.activity.MainActivity;
import fr.paug.androidmakers.util.SessionSelector;
public class SessionAlarmService extends IntentService {
private static final String TAG = "sessionAlarm";
public static final String ACTION_NOTIFY_SESSION = "NOTIFY_SESSION";
public static final String ACTION_SCHEDULE_STARRED_BLOCK = "SCHEDULE_STARRED_BLOCK";
public static final String ACTION_UNSCHEDULE_UNSTARRED_BLOCK = "ACTION_UNSCHEDULE_UNSTARRED_BLOCK";
public static final String ACTION_SCHEDULE_ALL_STARRED_BLOCKS = "SCHEDULE_ALL_STARRED_BLOCKS";
public static final String EXTRA_SESSION_ID = "SESSION_ID";
public static final String EXTRA_SESSION_START = "SESSION_START";
public static final String EXTRA_SESSION_END = "SESSION_END";
public static final String EXTRA_NOTIF_TITLE = "NOTIF_TITLE";
public static final String EXTRA_NOTIF_CONTENT = "NOTIF_CONTENT";
private static final int NOTIFICATION_LED_ON_MS = 100;
private static final int NOTIFICATION_LED_OFF_MS = 1000;
private static final int NOTIFICATION_ARGB_COLOR = 0xff1EB6E1;
private static final long MILLI_FIVE_MINUTES = 300000;
private static final long UNDEFINED_VALUE = -1;
public SessionAlarmService() {
super("SessionAlarmService");
}
@Override
protected void onHandleIntent(Intent intent) {
final String action = intent.getAction();
LOGD(TAG, "Session alarm : " + action);
if (ACTION_SCHEDULE_ALL_STARRED_BLOCKS.equals(action)) {
//Scheduling all starred blocks.
scheduleAllStarredSessions();
return;
}
final long sessionEnd = intent.getLongExtra(SessionAlarmService.EXTRA_SESSION_END, UNDEFINED_VALUE);
final long sessionStart = intent.getLongExtra(SessionAlarmService.EXTRA_SESSION_START, UNDEFINED_VALUE);
final int sessionId = intent.getIntExtra(SessionAlarmService.EXTRA_SESSION_ID, 0);
if (ACTION_NOTIFY_SESSION.equals(action)) {
final String notifTitle = intent.getStringExtra(SessionAlarmService.EXTRA_NOTIF_TITLE);
final String notifContent = intent.getStringExtra(SessionAlarmService.EXTRA_NOTIF_CONTENT);
if (notifTitle == null || notifContent == null) {
Log.w(TAG, "Title or content of the notification is null.");
return;
}
LOGD(TAG, "Notifying about sessions starting at " +
sessionStart + " = " + (new Date(sessionStart)).toString());
notifySession(sessionId, notifTitle, notifContent);
} else if (ACTION_SCHEDULE_STARRED_BLOCK.equals(action)) {
LOGD(TAG, "Scheduling session alarm.");
LOGD(TAG, "-> Session start: " + sessionStart + " = " + (new Date(sessionStart))
.toString());
LOGD(TAG, "-> Session end: " + sessionEnd + " = " + (new Date(sessionEnd)).toString());
scheduleAlarm(sessionStart, sessionEnd, sessionId, true);
} else if (ACTION_UNSCHEDULE_UNSTARRED_BLOCK.equals(action)) {
LOGD(TAG, "Unscheduling session alarm for id " + sessionId);
unscheduleAlarm(sessionId);
}
}
void scheduleAllStarredSessions() {
// need to be sure that the AngendaRepository is loaded in order to schedule all starred sessions
final Runnable runnable = new Runnable() {
@Override
public void run() {
final List<ScheduleSlot> scheduleSlots = AgendaRepository.getInstance()
.getScheduleSlots();
// first unschedule all sessions
// this is done in case the session slot has changed
for (ScheduleSlot scheduleSlot : scheduleSlots) {
unscheduleAlarm(scheduleSlot.sessionId);
}
for (String id : SessionSelector.getInstance().getSessionsSelected()) {
ScheduleSlot scheduleSlot = AgendaRepository.getInstance().getScheduleSlot(id);
if (scheduleSlot != null) {
Log.i("SessionAlarmService", scheduleSlot.toString());
scheduleAlarm(scheduleSlot.startDate, scheduleSlot.endDate,
scheduleSlot.sessionId, false);
}
}
}
};
AgendaRepository.getInstance().load(new AgendaLoadListener(runnable));
}
/**
* Schedule an alarm for a given session that begins at a given time
* @param sessionStart start time of the slot. The alarm will be fired before this time
* @param sessionEnd end time of the slot
* @param sessionId id of the session
* @param allowLastMinute allow or not the alarm to be set if the delay between the alarm and
* the session start is over.
*/
private void scheduleAlarm(final long sessionStart, final long sessionEnd, int sessionId,
boolean allowLastMinute) {
final long currentTime = System.currentTimeMillis();
Log.i("Time", "current: " + currentTime + ", session start: " + sessionStart);
final long alarmTime = sessionStart - MILLI_FIVE_MINUTES;
if (allowLastMinute) {
// If the session is already started, do not schedule system notification.
if (currentTime > sessionStart) {
LOGD(TAG, "Not scheduling alarm because target time is in the past: " + sessionStart);
return;
}
} else {
if (currentTime > alarmTime) {
LOGD(TAG, "Not scheduling alarm because alarm time is in the past: " + alarmTime);
return;
}
}
final Session sessionToNotify = AgendaRepository.getInstance().getSession(sessionId);
final ScheduleSlot slotToNotify = AgendaRepository.getInstance().getScheduleSlot(sessionId);
if (sessionToNotify == null || slotToNotify == null) {
Log.w(TAG, "Cannot find session " + sessionId + " either in sessions or in slots");
return;
}
final String sessionDate = DateUtils.formatDateRange(this,
new Formatter(Locale.getDefault()),
slotToNotify.startDate,
slotToNotify.endDate,
DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_WEEKDAY | DateUtils.FORMAT_SHOW_TIME,
null).toString();
final Room room = AgendaRepository.getInstance().getRoom(slotToNotify.room);
final String roomName = ((room != null) ? room.name : "") + " - ";
LOGD(TAG, "Scheduling alarm for " + alarmTime + " = " + (new Date(alarmTime)).toString());
final Intent notifIntent = new Intent(
ACTION_NOTIFY_SESSION,
null,
this,
SessionAlarmService.class);
notifIntent.putExtra(EXTRA_SESSION_START, sessionStart);
LOGD(TAG, "-> Intent extra: session start " + sessionStart);
notifIntent.putExtra(EXTRA_SESSION_END, sessionEnd);
LOGD(TAG, "-> Intent extra: session end " + sessionEnd);
notifIntent.putExtra(EXTRA_SESSION_ID, sessionId);
notifIntent.putExtra(EXTRA_NOTIF_TITLE, sessionToNotify.title);
notifIntent.putExtra(EXTRA_NOTIF_CONTENT, roomName + sessionDate);
PendingIntent pi = PendingIntent.getService(this, sessionId, notifIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
// Schedule an alarm to be fired to notify user of added sessions are about to begin.
LOGD(TAG, "-> Scheduling RTC_WAKEUP alarm at " + alarmTime);
am.set(AlarmManager.RTC_WAKEUP, alarmTime, pi);
}
/**
* Remove the scheduled alarm for a given session
* @param sessionId the id of the session
*/
private void unscheduleAlarm(int sessionId) {
final AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
final Intent notifIntent = new Intent(
ACTION_NOTIFY_SESSION,
null,
this,
SessionAlarmService.class);
PendingIntent pi = PendingIntent.getService(this, sessionId, notifIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pi);
}
// Starred sessions are about to begin. Constructs and triggers system notification.
private void notifySession(int sessionId, @NonNull String notifTitle,
@NonNull String notifContent) {
// Generates the pending intent which gets fired when the user taps on the notification.
Intent baseIntent = new Intent(this, MainActivity.class);
baseIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
Intent resultIntent = new Intent(this, MainActivity.class);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setContentTitle(notifTitle)
.setContentText(notifContent)
.setColor(getResources().getColor(R.color.colorPrimary))
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
.setLights(
SessionAlarmService.NOTIFICATION_ARGB_COLOR,
SessionAlarmService.NOTIFICATION_LED_ON_MS,
SessionAlarmService.NOTIFICATION_LED_OFF_MS)
.setSmallIcon(R.drawable.ic_event_note_white_24dp)
.setContentIntent(resultPendingIntent)
.setPriority(Notification.PRIORITY_MAX)
.setAutoCancel(true);
NotificationManager notificationManager = (NotificationManager) getSystemService(
Context.NOTIFICATION_SERVICE);
LOGD(TAG, "Now showing notification.");
notificationManager.notify(sessionId, notificationBuilder.build());
}
public static void LOGD(final String tag, String message) {
Log.d(tag, message);
}
private static class AgendaLoadListener implements AgendaRepository.OnLoadListener {
@NonNull
private final Runnable runnable;
private AgendaLoadListener(@NonNull Runnable runnable) {
this.runnable = runnable;
}
@Override
public void onAgendaLoaded() {
runnable.run();
AgendaRepository.getInstance().removeListener(this);
}
}
}