package com.wigwamlabs.veckify;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.support.v4.app.NotificationCompat;
import android.text.format.DateFormat;
import com.wigwamlabs.veckify.db.AlarmsCursor;
import java.util.Calendar;
public final class AlarmUtils {
public static final int DAY_MONDAY = 0x01;
public static final int DAY_TUESDAY = 0x02;
public static final int DAY_WEDNESDAY = 0x04;
public static final int DAY_THURSDAY = 0x08;
public static final int DAY_FRIDAY = 0x10;
public static final int DAY_SATURDAY = 0x20;
public static final int DAY_SUNDAY = 0x40;
public static final int DAYS_NONE = 0x00;
public static final int DAYS_ALL = DAY_MONDAY | DAY_TUESDAY | DAY_WEDNESDAY | DAY_THURSDAY | DAY_FRIDAY | DAY_SATURDAY | DAY_SUNDAY;
private static final long MINIMUM_TIME_TO_ALARM_MS = 0;
private final Context mContext;
private final AlarmManager mAlarmManager;
private final NotificationManager mNotificationManager;
private final PendingIntent mAlarmPendingIntent;
private final String mDateFormatYear;
private final String mDateFormatNoYear;
public AlarmUtils(Context context) {
mContext = context;
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mAlarmPendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, MainActivity.class), 0);
// TODO am/pm
final char[] formatOrder = DateFormat.getDateFormatOrder(mContext);
mDateFormatYear = String.format("%s/%s/%s k:mm", formatOrder[0], formatOrder[1], formatOrder[2]);
final StringBuilder sb = new StringBuilder();
for (char c : formatOrder) {
if (c == 'y') { // year
continue;
}
if (sb.length() > 0) {
sb.append('/');
}
sb.append(c);
}
mDateFormatNoYear = sb.toString() + " k:mm";
}
public static Calendar getNextAlarmTime(boolean enabled, int hour, int minute, int repeatDays, long oneOffTimeMs, long nowMs) {
if (!enabled) {
return null;
}
if (repeatDays == DAYS_NONE && oneOffTimeMs > 0) { // one-off and we like to check that it's still valid
// check if in past
if (oneOffTimeMs < nowMs) {
return null;
}
}
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(nowMs);
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
final long timeToAlarmMs = cal.getTimeInMillis() - nowMs;
if (timeToAlarmMs < MINIMUM_TIME_TO_ALARM_MS) {
cal.add(Calendar.DAY_OF_YEAR, 1);
}
if (repeatDays != DAYS_NONE) {
for (int i = 0; i < 7; i++) {
final int day = cal.get(Calendar.DAY_OF_WEEK);
if (day == Calendar.MONDAY && (repeatDays & DAY_MONDAY) != 0) {
break;
}
if (day == Calendar.TUESDAY && (repeatDays & DAY_TUESDAY) != 0) {
break;
}
if (day == Calendar.WEDNESDAY && (repeatDays & DAY_WEDNESDAY) != 0) {
break;
}
if (day == Calendar.THURSDAY && (repeatDays & DAY_THURSDAY) != 0) {
break;
}
if (day == Calendar.FRIDAY && (repeatDays & DAY_FRIDAY) != 0) {
break;
}
if (day == Calendar.SATURDAY && (repeatDays & DAY_SATURDAY) != 0) {
break;
}
if (day == Calendar.SUNDAY && (repeatDays & DAY_SUNDAY) != 0) {
break;
}
cal.add(Calendar.DAY_OF_YEAR, 1);
}
}
return cal;
}
public static String repeatDaysText(Context context, int repeatDays) {
if (repeatDays == DAYS_NONE) {
return context.getString(R.string.repeatdays_none);
} else if (repeatDays == DAYS_ALL) {
return context.getString(R.string.repeatdays_all);
}
//TODO ensure follow locale's first weekday: Calendar.getFirstDayOfWeek()
final String[] dayNames = context.getResources().getStringArray(R.array.repeatdays_shortday);
final StringBuilder sb = new StringBuilder();
int day = 1;
for (final String dayName : dayNames) {
if ((repeatDays & day) != 0) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(dayName);
}
day <<= 1;
}
return sb.toString();
}
public static int getVolumeDrawable(Integer volume) {
if (volume == null) {
return R.drawable.ic_button_volume_1_inverse;
}
switch (3 * volume.intValue() / 100) {
case 0:
return R.drawable.ic_button_volume_1_inverse;
case 1:
return R.drawable.ic_button_volume_2_inverse;
default:
case 2:
return R.drawable.ic_button_volume_3_inverse;
}
}
static String getTimeToNextAlarmText(Context context, boolean enabled, int hour, int minute, int repeatDays, long oneOffTimeMs, long nowMs) {
final Resources res = context.getResources();
final Calendar nextAlarmTime = getNextAlarmTime(enabled, hour, minute, repeatDays, oneOffTimeMs, nowMs);
if (nextAlarmTime == null) {
return null;
}
int timeToNextAlarmMins = (int) ((nextAlarmTime.getTimeInMillis() - nowMs) / (1000 * 60));
if (timeToNextAlarmMins == 0) {
return res.getString(R.string.alarmscheduled_soon);
}
final int timeToNextAlarmDays = timeToNextAlarmMins / (60 * 24);
timeToNextAlarmMins -= timeToNextAlarmDays * 60 * 24;
final int timeToNextAlarmHours = timeToNextAlarmMins / 60;
timeToNextAlarmMins -= timeToNextAlarmHours * 60;
final StringBuilder sb = new StringBuilder();
if (timeToNextAlarmDays > 0) {
sb.append(res.getQuantityString(R.plurals.alarmscheduled_days, timeToNextAlarmDays, timeToNextAlarmDays));
}
if (timeToNextAlarmHours > 0) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(res.getQuantityString(R.plurals.alarmscheduled_hours, timeToNextAlarmHours, timeToNextAlarmHours));
}
if (timeToNextAlarmMins > 0) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(res.getQuantityString(R.plurals.alarmscheduled_mins, timeToNextAlarmMins, timeToNextAlarmMins));
}
sb.append(' ');
sb.append(context.getString(R.string.alarmscheduled_suffix));
return sb.toString();
}
public void reschedule(Context context, AlarmsCursor alarm) {
final long nowMs = System.currentTimeMillis();
Calendar nextTime = null;
long nextAlarmId = 0;
String nextPlaylistName = null;
String nextPlaylistLink = null;
for (boolean hasItem = alarm.moveToFirst(); hasItem; hasItem = alarm.moveToNext()) {
final Calendar alarmTime = getNextAlarmTime(alarm.enabled(), alarm.hour(), alarm.minute(), alarm.repeatDays(), alarm.oneoffTimeMs(), nowMs);
if (alarmTime != null) {
if (nextTime == null || alarmTime.before(nextTime)) {
nextTime = alarmTime;
nextAlarmId = alarm._id();
nextPlaylistName = alarm.playlistName();
nextPlaylistLink = alarm.playlistLink();
}
}
}
final Intent intent = new Intent(BroadcastReceiver.ACTION_ALARM);
if (nextTime != null) {
intent.putExtra(BroadcastReceiver.EXTRA_EVENT_TIME_MS, nextTime.getTimeInMillis());
intent.putExtra(BroadcastReceiver.EXTRA_ALARM_ID, nextAlarmId);
intent.putExtra(BroadcastReceiver.EXTRA_PLAYLIST_LINK, nextPlaylistLink);
}
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
if (nextTime != null) {
Debug.logAlarmScheduling("Scheduling alarm at " + DateFormat.format("yyyy-MM-dd kk:mm", nextTime));
mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextTime.getTimeInMillis(), pendingIntent);
mNotificationManager.notify(R.id.notificationAlarm, getNotification(nextPlaylistName, nextTime));
} else {
Debug.logAlarmScheduling("No next alarm, cancel any existing");
mAlarmManager.cancel(pendingIntent);
mNotificationManager.cancel(R.id.notificationAlarm);
}
}
private Notification getNotification(String playlistName, Calendar calendar) {
final Calendar now = Calendar.getInstance();
final String format = (now.get(Calendar.YEAR) == calendar.get(Calendar.YEAR)) ? mDateFormatNoYear : mDateFormatYear;
final String description = String.format(mContext.getString(R.string.notification_alarm_description),
DateFormat.format(format, calendar),
playlistName);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
.setSmallIcon(R.drawable.ic_stat_alarm)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setContentIntent(mAlarmPendingIntent)
.setContentTitle(mContext.getString(R.string.notification_alarm_title))
.setContentText(description)
.setOngoing(true);
return builder.build();
}
}